Repository: team-ocean/veros

Issue:
Compute initial streamfunction from initial velocity
Not knowing the numerics, and possibly not reading the docs carefully enough, it is unclear to me how to initialize the velocities in the model.  

For a channel run, re-entrant in x, with intial velocity 0.1 m/s everywhere, no forcing, I tried do in `set_initial_conditions`: `s.u = update(vs.u, at[...], 0.1 * vs.maskU[..., None])`.  

The velocity signal only lasts for one time step, and then it is gone.  It _does_ create a small pressure perturbations that drive internal waves, but the mean flow of 0.1 m/s is immediately gone.  Conversely, the initial conditions have psi=0 everywhere, and then immediately on the next time step there is a stream function, but if the units are really m^3/s it is far too small.  

Was I to initialize psi at the beginning instead of u, or in addition to u?  


Discussion:
I agree that this is counter-intuitive. It may take me some time to investigate what's going on. We have an experimental surface pressure solver where this doesn't happen, so it definitely seems connected to the stream function.
Cool, yes, I'm used to a surface pressure solver in the MITgcm.  Though that can be expensive and hard to parallelize.  

I'm not sure what I would do if I wanted to initialize a shear flow with non-zero barotropic flow.  Remove the barotropic and put that in as a stream function and just initialize u and v with the shear?  

Here, where I wanted a barotropic initial flow, the solution to a mean flow definitely seemed to be _not_ to specify `vs.u` and _only_ specify `vs.psi`.  
> I'm not sure what I would do if I wanted to initialize a shear flow with non-zero barotropic flow. Remove the barotropic and put that in as a stream function and just initialize u and v with the shear?

Yes that seems to be it. The streamfunction solver removes any barotropic mode from `u` and `v`, and adds it back based on `psi`.

That's a bit awkward of course. I think I will pull in the first version of the surface pressure solver with linear free surface soon (identical to the MITgcm implementation). That should make things easier for you. 
I think, even working within the confines of the stream function solver we might consider calculating the initial steam function from the initial velocity field as an initial step.   Most of your demos start from rest, but I would expect people to be more likely to know u, v rather than psi as an initial condition?  
Yes, that's a good suggestion.

Resolving patch:
diff --git a/veros/core/external/streamfunction_init.py b/veros/core/external/streamfunction_init.py
--- a/veros/core/external/streamfunction_init.py
+++ b/veros/core/external/streamfunction_init.py
@@ -3,7 +3,7 @@
 from veros.distributed import global_max
 from veros.core import utilities as mainutils
 from veros.core.operators import numpy as npx, update, at
-from veros.core.external import island, line_integrals
+from veros.core.external import island, line_integrals, solve_stream
 from veros.core.external.solvers import get_linear_solver
 
 
@@ -65,6 +65,29 @@ def streamfunction_init(state):
     line_psin_out = island_integrals(state)
     vs.update(line_psin_out)
 
+    """
+    take care of initial velocity
+    """
+
+    # transfer initial velocity to tendency
+    vs.du = update(vs.du, at[..., vs.tau], vs.u[..., vs.tau] / settings.dt_mom / (1.5 + settings.AB_eps))
+    vs.dv = update(vs.dv, at[..., vs.tau], vs.v[..., vs.tau] / settings.dt_mom / (1.5 + settings.AB_eps))
+    vs.u = update(vs.u, at[...], 0)
+    vs.v = update(vs.v, at[...], 0)
+
+    # run streamfunction solver to determine initial barotropic and baroclinic modes
+    solve_stream.solve_streamfunction(state)
+
+    vs.psi = update(vs.psi, at[...], vs.psi[..., vs.taup1, npx.newaxis])
+    vs.u = update(
+        vs.u, at[...], mainutils.enforce_boundaries(vs.u[..., vs.taup1, npx.newaxis], settings.enable_cyclic_x)
+    )
+    vs.v = update(
+        vs.v, at[...], mainutils.enforce_boundaries(vs.v[..., vs.taup1, npx.newaxis], settings.enable_cyclic_x)
+    )
+    vs.du = update(vs.du, at[..., vs.tau], 0)
+    vs.dv = update(vs.dv, at[..., vs.tau], 0)
+
 
 @veros_kernel
 def island_integrals(state):


Test patch:
diff --git a/test/pyom_consistency/acc_setup_test.py b/test/pyom_consistency/acc_setup_test.py
--- a/test/pyom_consistency/acc_setup_test.py
+++ b/test/pyom_consistency/acc_setup_test.py
@@ -302,5 +302,8 @@ def test_acc_setup(pyom2_lib):
     sim = ACCSetup()
     sim.setup()
 
+    # Veros runs a streamfunction solve during setup
+    allowed_failures = ("p_hydro",)
+
     # psin and line_psin don't quite meet the tolerance
-    compare_state(sim.state, pyom_obj, rtol=1e-6)
+    compare_state(sim.state, pyom_obj, rtol=1e-6, allowed_failures=allowed_failures)