Skip to content

Conversation

@jeremyfirst22
Copy link
Contributor

@jeremyfirst22 jeremyfirst22 commented Nov 11, 2025

Feature

  • Adds a new lbpm_color_unsteady_simulator module to address a common workflow type, where an unsteady state simulation is run at a density/pressure gradient until the water saturation converges.
  • Convergence criteria is read from tolerance database parameter and represents the relative change in water saturation per step. The default value is zero, and result in the simulation running all the way to timestepMax.

PS, I am not set on the name of this new module and welcome better ideas 😄

@JamesEMcClure
Copy link
Collaborator

My advice would be to add this as a simulation protocol, similar to how others are done

https://lbpm-sim.org/userGuide/models/color/index.html#simulation-protocols

The advantage to doing it this way is that you can configure the protocol to override any input values that are inconsistent with how the protocol is supposed to behave (e.g. setting periodic boundary conditions or a body force).

It should be straightforward to setup a switch to set the boundary conditions, e.g. at lines 141-190 in models/ColorModel.cpp and update ColorModel::Run() to handle the saturation-based exit criterion.

Some refactoring of ColorModel::Run() would make the logic easier to follow; much of the capillary number logic is built around the fractional flow protocol, and it would be more clear if this was explicit (this is my fault -- criticizing my own code here)

@jeremyfirst22 jeremyfirst22 force-pushed the feature-unsteady-sw-simulator branch from 72d9fef to 3957b9e Compare December 5, 2025 20:26
@jeremyfirst22 jeremyfirst22 changed the title lbpm_color_unsteady_simulator for sw convergence 'sw_steady' protocol for color model Dec 5, 2025
@jeremyfirst22
Copy link
Contributor Author

jeremyfirst22 commented Dec 5, 2025

@JamesEMcClure Thank you for this suggestion. I agree, this is a better way to do it. I've made the change so that this workflow is a new protocol called 'sw_steady' and added a page to document the protocol.

I am still hijacking the other ColorModel::Run() method (i.e., not ColorModel::Run(int returntime)) to avoid getting tangled with the logic around the capillary number. As far as refactoring Run(), IMO, perhaps each protocol could be implemented as a separate Run() function in order to clean up this logic, with the forward stepping logic conserved between protocols (I have a commit towards that here 7e060fc, but it is not cleanly separable from #109 and will need to be merged in afterwards). In this way, we would avoid all the awkward logic of trying to simultaneously account for all protocol types all within the same function.

Let me know what you think.

@JamesEMcClure
Copy link
Collaborator

JamesEMcClure commented Dec 7, 2025

The intent for the implementation of the protocols is that these would be separated out from the low-level lattice Boltzmann model that is implemented in the models directory. In other words, ideally everything under models/ColorModel.cpp would be generic and not specific to a particular application. Implementing a separate simulator would then make a lot of sense, because it could be done without relying on protocol-specific behavior (making ColorModel.cpp easier to re-use).

In an ideal world the protocol should not depend on the physical model. For example, there is also a free energy multiphase model in LBPM. This is just a basic lattice Boltzmann model without most of the the digital rock specific bells and whistles. If you want to simulate incompressible fluids (usually liquid -oil systems) the Color model tends to be the best choice because it minimizes the effects of compressibility and is a good fit for immiscible fluids. If you have liquid-gas systems the free energy models are a better choice. If you want to tune a capillary number, this implementation doesn't need to depend on the underlying lattice Boltzmann model that you choose. So the abstractions to work toward are then:

models/ - generic implementation of lattice Boltzmann models (including support for boundary conditions)
* inputs are fluid configurations, pressure boundary conditions, body forces, etc.
* outputs are simple things like density, pressure, velocity fields

protocols/ - methods to control the lattice Boltzmann models in a more sophisticated way to create a computational analog of a physical experiment (note there is no protocols/ directory -- If I was refactoring myself I would create one)
(inputs to protocols are LB outputs or averages computed by the analysis frameworks
(outputs of protocols are LB inputs)
* capillary number adjustment
* adaptive saturation control
* adjustment of pressure boundary conditions

analysis/ - analysis methods that compute averages from the lattice Boltzman outputs
* outputs are saturation, interfacial area, averaged pressures, etc.

These would then be building blocks to build new simulators. Ideally you could write a new simulator from these pieces without having to rewrite / refactor the underlying building blocks.

We were always trying to work toward having more modularity / composibility, but it is hard to find time to do this.

Look in tests/lbpm_nersnst_planck_simulator.cpp for an example. Those go in the direction where you are combining multiple LBM models to build a more sophisticated simulator (electro-diffusion in this case). A "good" design (my definition) would be one where you could build a version of this that took the ColorModel as input and all of the capillary number adjustments were done externally

@jeremyfirst22 jeremyfirst22 force-pushed the feature-unsteady-sw-simulator branch from 3957b9e to 5fb3d9a Compare December 17, 2025 19:22
@jeremyfirst22
Copy link
Contributor Author

Hi @JamesEMcClure Thank you for the comments. I agree with the vision, and think it would make things easier to completely decouple the 'protocol' logic from the 'model' logic. We would need to setup abstract model/protocol classes for this, and have each particular model/protocol be a polymorph.

But that will take some time, and I would consider that work outside the scope of this PR. Can we table this idea into a separate issue/feature request so that we can come back to it with another larger refactor PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants