daxiangxiang,
Similar to what I mentioned before, there are two object types within the OpenFOAM source code related to Lagrangian particles: Clouds and injectionModels. To properly checkpoint Lagrangian particles for implicit coupling we have to cache and restore information related to both.
Clouds contain information concerning the physics of particles that already exist in the domain. There are 5 main types of Clouds (found in /src/lagrangian/intermediate/clouds): basicKinematicCloud, basicThermoCloud, basicKinematicCollidingCloud, basicReactingCloud, basicReactingMultiphaseCloud. Depending on which Cloud one is using, these objects contain information like number of parcels, location of parcels, particle size distribution within a parcel, parcel velocity / momentum, parcel temperature / energy, parcel species mass / volume fraction, etc. Caching and restoring of Clouds is handled entirely within the Adapter.C and Adapter.H files in the preCICE OpenFOAM adatper. These files contain existing logic for setting up, writing, and reading checkpoints for all types of OpenFOAM objects present in the solver object registry (volScalarFields, volVectorFields, surfScalarFields, surfVectorFields, etc.). Adding the different Cloud types to these existing routines means all existing Lagrangian particles will be checkpointed alongside anything else the user requests via the preCICE adapter. At a very high level, the logic is such that at the beginning of a coupling time window the full definition of every parcel in every particle Cloud is cached in memory. At the end of the time window, if our implicit coupling is not converged the OpenFOAM solver will revert its time step back to the beginning of the time window (as controlled by preCICE). Any existing particle Clouds will be deleted and replaced in the domain with the particle Cloud that we cached at the beginning of the time window. The implementation caches, deletes, and replaces entire Cloud objects. Because these Cloud objects contain everything needed for their physics, the implicit coupling checkpointing is perfectly repeatable.
injectionModels contain information concerning how particles / parcels are added to existing Clouds. There are 6 main types of injectionModels (found in /src/lagrangian/intermediate/submodels/Kinematic/InjectionModel): patchInjection, coneNozzleInjection, manualInjection, cellZoneInjection, kinematicLookupTableInjection, surfaceFilmInjection. Depending on which injectionModel one is using in their simulation, these objects contain information like: initial position, initial velocity, initial size, initial mass (including fractional mass), initial temperature, etc. of the parcels being added to a Cloud. The different injectionModels are mostly different ways / places in which the user can inject parcels into the domain. For example, patchInjection lets the user inject parcels / particles into the domain at an existing boundary patch, but coneNozzleInjection asks the user to define a major and minor diameters of a cone within the domain volume from which parcels / particles will be injected into the domain. The fickle thing about the injectionModels is that they exist OUTSIDE the solvers object registry. This means the preCICE openFOAM adapter has no access to them. If we cannot cache and restore information about the injectionModel then when preCICE reverts the OpenFOAM solver time step within an implicit coupling loop the injectionModel will do one of three things: (1) not inject particles when it should, (2) inject particles when it shouldn’t, or (3) get confused about time going in reverse and crash the entire solver. So, in order to make sure new parcels / particles are injected into existing Clouds only when they should be, the implementation includes copies of native injectionModels that handle caching and restoring of important injecionModel parameters pertinent to implicit coupling loops. The same basic logic that applies to the Cloud objects applies to the new injectionModel objects. Their information is cached at the beginning of each implicit coupling time window. If preCICE reverts the solver time step, the injectionModel deletes the existing parameters and restores them from the cache. If the implicit coupling loop converges and the solver starts a new time window, the cache is cleared and a new set of parameters in put in the cache. These new injectionModels are built and installed alongside the preCICE OpenFOAM adapter as shared libraries, so in order for users to employ them they’ll have to load these libraries in their system/controlDict file and then modify the type of injectionModel they use in their Cloud properties file (constant/kinematicCloudProperties, constant/reactingCloud1Properties, etc.). The new injectionModel types are named after the native injectionModel from the OpenFOAM source code: patchingInjection → implicitPatchInjection, coneNozzleInjection → implicitConeNozzleInjection. No other modifications to the Cloud properties file are required by the user and everything supported by the native injectionModel is supported in the implicit copy (SOI, duration, parcelBasisType, flowRateProfile, etc.).
Please note that as of this comment only 2 implicit coupling injectionModels exist: implicitPatchInjection and implicitConeNozzleInjection.
No, the OpenFOAM solver used was never modified. I only had to make sure I used one of the new implicit injection models when running (by modifying system/controlDict and constant/kinematicCloudProperties).