Skip to content

Commit

Permalink
Merge pull request #1103 from OceanParcels/explanation_syncedtime_out…
Browse files Browse the repository at this point in the history
…putfile

Explanation on synced time in outputfile
  • Loading branch information
erikvansebille authored Nov 10, 2021
2 parents 202ef08 + 1e9dec9 commit 280de52
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 9 deletions.
146 changes: 137 additions & 9 deletions parcels/examples/tutorial_delaystart.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In many applications, it is needed to 'delay' the start of particle advection. For example because particles need to be released at different times throughout an experiment. Or because particles need to be released at a conatant rate from the same set of locations.\n",
"In many applications, it is needed to 'delay' the start of particle advection. For example because particles need to be released at different times throughout an experiment. Or because particles need to be released at a constant rate from the same set of locations.\n",
"\n",
"This tutorial will show how this can be done. We start with importing the relevant modules."
]
Expand All @@ -26,6 +26,7 @@
"from parcels import FieldSet, ParticleSet, JITParticle, plotTrajectoriesFile\n",
"from parcels import AdvectionRK4\n",
"import numpy as np\n",
"import xarray as xr\n",
"from datetime import timedelta as delta"
]
},
Expand Down Expand Up @@ -96,8 +97,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: Compiled JITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/5fba5501ea36ea205605260b5254062f.so\n",
"100% (86400.0 of 86400.0) |##############| Elapsed Time: 0:00:00 Time: 0:00:00\n"
"INFO: Compiled ArrayJITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/lib15ab640308c954e580b6f93be742baae_0.so\n"
]
}
],
Expand Down Expand Up @@ -596,8 +596,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: Compiled JITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/694933c823154d73a884aab64a89b625.so\n",
"100% (86400.0 of 86400.0) |##############| Elapsed Time: 0:00:02 Time: 0:00:02\n"
"INFO: Compiled ArrayJITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/libcbcec39cf73cfa7671e8798abaac733b_0.so\n"
]
}
],
Expand Down Expand Up @@ -1183,9 +1182,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: Compiled JITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/aca27122514704372f3f6e56d1ca8af6.so\n",
"100% (28800.0 of 28800.0) |##############| Elapsed Time: 0:00:00 Time: 0:00:00\n",
"100% (54000.0 of 54000.0) |##############| Elapsed Time: 0:00:00 Time: 0:00:00\n"
"INFO: Compiled ArrayJITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/libd1c17d6554e6d39a5c989beb50bcc2d3_0.so\n"
]
},
{
Expand Down Expand Up @@ -1724,6 +1721,137 @@
"plotTrajectoriesFile('DelayParticle_releasedt_9hrs.nc', mode='movie2d_notebook')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Synced `time` in the output file\n",
"\n",
"Note that, because the `outputdt` variable controls the JIT-loop, all particles are written _at the same time_, even when they start at a non-multiple of `outputdt`. \n",
"\n",
"For example, if your particles start at `time=[0, 1, 2]` and `outputdt=2`, then the times written (for `dt=1` and `endtime=4`) will be "
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 0 2 4]\n",
" [ 2 4 'NaT']\n",
" [ 2 4 'NaT']]\n"
]
}
],
"source": [
"outtime_expected = np.array([[0, 2, 4], [2, 4, np.datetime64(\"NaT\")], [2, 4, np.datetime64(\"NaT\")]], dtype=\"timedelta64[s]\")\n",
"print(outtime_expected)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: Compiled ArrayJITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/lib73f1058452aa339434e56df780d0ba46_0.so\n"
]
}
],
"source": [
"outfilepath = \"DelayParticle_nonmatchingtime.nc\"\n",
"\n",
"pset = ParticleSet(fieldset=fieldset, pclass=JITParticle,\n",
" lat=[3e3]*3, lon=[3e3]*3, time=[0, 1, 2])\n",
"pset.execute(AdvectionRK4, endtime=4, dt=1, output_file=pset.ParticleFile(name=outfilepath, outputdt=2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And indeed, the `time` values in the NetCDF output file are as expected"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 0 2 4]\n",
" [ 2 4 'NaT']\n",
" [ 2 4 'NaT']]\n"
]
}
],
"source": [
"outtime_infile = xr.open_dataset(outfilepath).time.values[:]\n",
"print(outtime_infile.astype('timedelta64[s]'))\n",
"\n",
"assert (outtime_expected[np.isfinite(outtime_expected)] == outtime_infile[np.isfinite(outtime_infile)]).all()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, for some applications, this behavior may be undesirable; for example when particles need to be analyzed at a same age (instead of at a same time). In that case, we recommend either changing `outputdt` so that it is a common divisor of all start times; or doing multiple Parcels runs with subsets of the original `ParticleSet` (e.g., in the example above, one run with the Particles that start at `time=[0, 2]` and one with the Particle at `time=[1]`). In that case, you will get two files:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: Compiled ArrayJITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/lib4a9283c7ab81279666f072b74de9d644_0.so\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 0 2 4]\n",
" [ 2 4 'NaT']]\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: Compiled ArrayJITParticleAdvectionRK4 ==> /var/folders/r2/8593q8z93kd7t4j9kbb_f7p00000gr/T/parcels-504/libef5ef37165aa5febcc2e916a89504269_0.so\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1 3 4]]\n"
]
}
],
"source": [
"for times in [[0,2], [1]]:\n",
" pset = ParticleSet(fieldset=fieldset, pclass=JITParticle,\n",
" lat=[3e3]*len(times), lon=[3e3]*len(times), time=times)\n",
" pset.execute(AdvectionRK4, endtime=4, dt=1, output_file=pset.ParticleFile(name=outfilepath, outputdt=2))\n",
" print(xr.open_dataset(outfilepath).time.values[:].astype('timedelta64[s]'))"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -1748,7 +1876,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
"version": "3.8.10"
}
},
"nbformat": 4,
Expand Down
13 changes: 13 additions & 0 deletions tests/test_particle_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ def test_pset_create_with_time(fieldset, pset_mode, mode, npart=100):
assert np.allclose([p.time for p in pset], time, rtol=1e-12)


@pytest.mark.parametrize('pset_mode', pset_modes)
@pytest.mark.parametrize('mode', ['scipy', 'jit'])
def test_pset_not_multipldt_time(fieldset, pset_mode, mode):
times = [0, 1.1]
pset = pset_type[pset_mode]['pset'](fieldset, lon=[0]*2, lat=[0]*2, pclass=ptype[mode], time=times)

def Addlon(particle, fieldset, time):
particle.lon += particle.dt

pset.execute(Addlon, dt=1, runtime=2)
assert np.allclose([p.lon for p in pset], [2 - t for t in times])


@pytest.mark.parametrize('pset_mode', pset_modes)
@pytest.mark.parametrize('mode', ['scipy', 'jit'])
def test_pset_repeated_release(fieldset, pset_mode, mode, npart=10):
Expand Down

0 comments on commit 280de52

Please sign in to comment.