Topic: Transient transport solvers

I have issues with nonstationarytransportproblem and nltransienttransportproblem, and I created replacement, just called "TransientTransport".
It was easier than trying to decipher what the other solvers were up to, so that the results could be compared.
Recently, I have fixed up various bugs, trying out the solver on every test.


First, there are tests that use both of them, tmquad.in and tmquadnl.in
These are completely linear models, they use the same time stepping, same initial conditions.. but still yield different results. The nonlinear solver also converges in 1 iteration, but still doesn't reduce to the linear response.
The root cause of this is the inconsistency of boundary conditions, initial conditions time stepping, and time discretization.
This caused me quite a lot of headache, and is the primary reason i opted on created a third solver seperately instead.

My main gripe with the transport solvers: awkward nonlinear setup

When setting up the FE-problem for transport problems, we should always have the interna forces computed as

R(u) = integral B^T * flux(grad(u), u) dV

(i call the unknown u here, i.e. temperature or concentration)
where the flux is defined as a, possible nonlinear, function in terms of the gradient and the field itself.
This is just like we do for the stress.

I see that the nonstationarytransportproblem and nltransienttransportproblem both handle this in a completely different way, (I've seen similar setups as these in transport problems before, so I suspect it's there for historical reasons).
It's just backwards for no tangible benefit whatsoever.
They start with linear problem, and tries to back on nonlinearity, which I find very backwards.
It forces one to add a "bc" RHS vector.
It can't handle models that are nonlinear in the gradient.
It requires around twice as much code compared to just the general nonlinear approach.

There are no benefits gained from this approach.


Inconsistent time discretization

The time discretization scheme should always decide VM_Total and VM_Velocity. This is the only way we have consistency of turning off/on b.c.s etc.
So, b.c.s and i.c.s should apply on a specific target time. If the VM_Velocity is requested, it should not go to the b.c and ask for the analytical dF/dt at the intrinsic time. That is inconsistent, and leads to obscure analysis bugs.
Take for example the heaviside function, which is frequently used. VM_Velocity is always zero, but the value changes.

To give a clear example, in pseudocode

Setup:
Initial condition:  u(t=0) = u0
Boundary condition: u(t>0) = u1     (using heaviside func.)
Using generalized midpoint, alpha, to define intrinsic time.

Currently, we get this:
u = u1
du/dt = 0

We should do this:
u = u0*(1-alpha) + uBC*alpha 
du/dt = (uBC-u0)/deltaT

I.e. we should do the same thing for all dofs, unknown or prescribed, initial condition or not.

Exactly how BC and IC should be applied is up for debate. Maybe the BC should override the IC, but either way, this is how it should work.


TransientTransport
This is the replacement i made for these. The code is much simpler, it's solves all the problems, however, it won't give the same results as the other solvers, because I believe those to be inconsistent and, well, wrong. So I choose not to do the same.
With initial time set in the old solvers, and with properly defined IC and BC, they all produce the same results.

The discrepencies come from
1. Slightly different time stepping setup: Starting from 0->deltaT, instead of going -deltaT->o for the first step. I think this is more sensible.

2. The other solvers are inconsistent in time discretization: the time vector set at the "state" vector of the models  (when calling updateInternalState)  are set to the values at the target time not the intrinsic time, i.e. it doesn't respect "alpha".
I consider this a bug, but it's one that can't be fixed easily. Which I why i made a new version.

3. Again, more inconsistencies with time discretization; The flux reported in the output from one time step is incorrect in nonstationary transport. It also doesn't respect the "alpha" parameter.
This is due to nonstationarytransport trying to handle alpha purely on the global FE-level, which can only ever be done if you assume linear material models. That won't work correctly for anything nonlinear, and gives misleading statevector and output.

4. It's slightly easier to use. Doesn't need "changingProblemSize" parameter. Uses the standard NRSolver input parameters. We could do all the mstep-steps as well.

Re: Transient transport solvers

Dear Mikael,
I have tested your TransientTransport solver and and I think this should indeed replace nonstationarytransportproblem and nltransienttransportproblem in a long-term view. I have just committed a few fixes:
- The solution of transient problem should always report variable at the end of the timeStep. Alpha is only for specifying intrinsic time, which is related to integration and solution. I changed output to be always at the end of timeStep, also in vtu export. If not doing so, coupled thermo-mechanical tasks would depend on alpha selection and time synchronization is broken.
- We need to support VM_Incremental. This applies for coupled tasks such as thermo-creep formulated in incremental form. With Borek, we reimplemented the original incremental calculation in DofDistributedPrimaryField :: giveUnknownValue() so we compute the increment when necessary instead of holding increment on DoFs.
- Several testing examples and benchmarks were updated to use this TransientTransport solver. I checked that results correspond to physics. TransientTransport supports all sets which is untrue for surface/edges in old solvers.

Re: Transient transport solvers

Hi Vit,

As far as I can tell at a glance, I agree with all changes, so this looks good. I'll try to merge in with oofem.org as soon as I can.

The addition of the VM_Intermediate is probably needed. It was unclear on what is what when just calling it all just "VM_Total", which made it difficult to be consistent.
Holding the "VM_Incremental" was also not pratical, so holding the actual solutions like this is much preferable. I had stayed off activating the "if" block that did this in giveUnknown() because of risk of breaking old code.

That is why i placed that that logic for computing the increment inside the engineering model to start with (but perhaps there are some calls directly to the field that bypass this logic).

----------------------------

Not quite specific to the transport solver itself, but very relevant to the discussion above about VM_Total and fields.

I believe it is very important that we let the (DofDistributed)PrimaryField handle the IC and BC values themselves. Three good reasons why is:
1. It's a lot simpler. "MasterDof" doesn't need to keep track of anything. It just fetches the value no matter where it comes from (whether it be solution vector, bc, ic).
2.  It's consistent. Dofs subjected to BCs will right now not respect the time discretization.
3. If you have some FE^2 code that manipulates the boundary conditions each step, then storing the total values from the old step is really the only way to compute the increment.