Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing an inconsistency in vertical index search between JIT and Scipy #1834

Merged
merged 2 commits into from
Jan 30, 2025

Conversation

erikvansebille
Copy link
Member

While working on #1816, we found a small inconsistency between the JIT and Scipy implementation of the vertical index search. This meant that a particle that was exactly at the top of a cell in JIT (zi=k, zeta=1) would be located at the bottom of the overlying cell in Scipy (zi=k+1, zeta=0).

While this does not matter for linear or nearest interpolation (the particle will get the velocities at the cell interface anyways), it does matter for C-grid interpolation because the horizontal velocities are vertically uniform over a cell; so the horizontal velocities would be different in JIT and Scipy for a particle located exactly at a depth level.

This PR makes the Scipy index-search consistent with what was already the JIT version. I think(?) it's arbitrary whether the upper (k+1) or lower (k) cell is chosen when a particle is at a depth level, and because JIT is used much more widely and in production, I decided to use the JIT-implementation also for Scipy.

@VeckoTheGecko
Copy link
Contributor

Would you mind elaborating on 762d911 ? Does the first search get the wrong zi sometimes?

@erikvansebille
Copy link
Member Author

Would you mind elaborating on 762d911 ? Does the first search get the wrong zi sometimes?

In some very rare cases, the zeta<0 or zeta>1; and this catches them so that 0<=zeta<=1. This is the same as we do in JIT. So these while-loops are only very rarely entered

@erikvansebille
Copy link
Member Author

There's a failing mypy check; should I worry about that? Do you want to have a look for a fix, or can I merge?

@VeckoTheGecko
Copy link
Contributor

Feel free to merge. The mypy checks can be worried about another time

@erikvansebille erikvansebille merged commit e1043f3 into main Jan 30, 2025
15 of 16 checks passed
@erikvansebille erikvansebille deleted the scipy_vertical_indexsearch_inconsistency branch January 30, 2025 06:35
@VeckoTheGecko VeckoTheGecko restored the scipy_vertical_indexsearch_inconsistency branch January 30, 2025 11:58
@VeckoTheGecko
Copy link
Contributor

VeckoTheGecko commented Jan 30, 2025

I was doing some testing in #1816, and it looks like we're still getting failures on test_scipy_vs_jit[cgrid_velocity] on the line assert not np.isclose(pset_scipy[i].depth, z.flatten()[pset_scipy.pid[i]], atol=tol) where it doesn't look like the depth is updating for some particles.

I have pushed a commit to scipy_vertical_indexsearch_inconsistency with this modified test case

def test_scipy_vs_jit(interp_method):
    """Test that the scipy and JIT versions of the interpolation are the same."""
    variables = {"U": "U", "V": "V", "W": "W"}
    dimensions = {"time": "time", "lon": "lon", "lat": "lat", "depth": "depth"}
    fieldset = FieldSet.from_xarray_dataset(create_interpolation_data_with_land(), variables, dimensions, mesh="flat")

    for field in [fieldset.U, fieldset.V, fieldset.W]:  # Set a land point (for testing freeslip)
        field.interp_method = interp_method

    x, y, z = np.meshgrid(np.linspace(0, 1, 7), np.linspace(0, 1, 13), np.linspace(0, 1, 5))

    TestP = ScipyParticle.add_variable("pid", dtype=np.int32, initial=0)
    pset_scipy = ParticleSet(fieldset, pclass=TestP, lon=x, lat=y, depth=z, pid=np.arange(x.size))
    pset_jit = ParticleSet(fieldset, pclass=JITParticle, lon=x, lat=y, depth=z)

    def DeleteParticle(particle, fieldset, time):
        if particle.state >= 50:
            particle.delete()

    for pset in [pset_scipy, pset_jit]:
        pset.execute([AdvectionRK4_3D, DeleteParticle], runtime=4e-3, dt=1e-3)

    tol = 1e-6
+   count = 0
    for i in range(len(pset_scipy)):
        # Check that the Scipy and JIT particles are at the same location
        assert np.isclose(pset_scipy[i].lon, pset_jit[i].lon, atol=tol)
        assert np.isclose(pset_scipy[i].lat, pset_jit[i].lat, atol=tol)
        assert np.isclose(pset_scipy[i].depth, pset_jit[i].depth, atol=tol)
        # Check that the Scipy and JIT particles have moved
        assert not np.isclose(pset_scipy[i].lon, x.flatten()[pset_scipy.pid[i]], atol=tol)
        assert not np.isclose(pset_scipy[i].lat, y.flatten()[pset_scipy.pid[i]], atol=tol)
-      assert not np.isclose(pset_scipy[i].depth, z.flatten()[pset_scipy.pid[i]], atol=tol)
+      if np.isclose(pset_scipy[i].depth, z.flatten()[pset_scipy.pid[i]], atol=tol):
+            count += 1
+    print(f"{count}/{len(pset_scipy)} particles are at the same depth as the initial condition.")

And the outcome is 5/289 particles are at the same location. Initially I thought it was due to the grid geometry, and that some particles were initialized at the edges of the FieldSet, but changing those initialized positions doesn't fix things

- x, y, z = np.meshgrid(np.linspace(0, 1, 7), np.linspace(0, 1, 13), np.linspace(0, 1, 5))
+ dx = 0.2
+ x, y, z = np.meshgrid(
+     np.linspace(0 + dx, 1 - dx, 7), np.linspace(0 + dx, 1 - dx, 13), np.linspace(0 + dx, 1 - dx, 5)
+ )

Any thoughts as to what is going on here @erikvansebille ?

@erikvansebille
Copy link
Member Author

Hmm, not sure what is going on here. I'll investigate in the coming days!

@erikvansebille
Copy link
Member Author

I found the bug, just fixed it in bb275c3. The issue was with the 'land point' we created in the unit test. That set fieldset.W=0 for a whole column, and hence particle didn't move vertically.

@VeckoTheGecko
Copy link
Contributor

I found the bug, just fixed it in bb275c3. The issue was with the 'land point' we created in the unit test. That set fieldset.W=0 for a whole column, and hence particle didn't move vertically.

I see! I'm a bit surprised that that caused it (since we're not using "nearest" interpolation), but at the same time I don't have a feel like I have a great intuition for this scenario

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants