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

Explanation on synced time in outputfile #1103

Merged
merged 3 commits into from
Nov 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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