Repository: OceanParcels/parcels
Pull request #576 (2019-04-17 05:57:46)

Adding lonlatdepth_dtype argument to ParticleSet constructor methods too
This follows #552


Patch:
diff --git a/parcels/particleset.py b/parcels/particleset.py
index a8973414..58a3e40b 100644
--- a/parcels/particleset.py
+++ b/parcels/particleset.py
@@ -128,7 +128,7 @@ class ParticleSet(object):
             raise ValueError("Latitude and longitude required for generating ParticleSet")
 
     @classmethod
-    def from_list(cls, fieldset, pclass, lon, lat, depth=None, time=None, repeatdt=None, **kwargs):
+    def from_list(cls, fieldset, pclass, lon, lat, depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None, **kwargs):
         """Initialise the ParticleSet from lists of lon and lat
 
         :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
@@ -139,12 +139,15 @@ class ParticleSet(object):
         :param depth: Optional list of initial depth values for particles. Default is 0m
         :param time: Optional list of start time values for particles. Default is fieldset.U.time[0]
         :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
+        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
+               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+               and np.float64 if the interpolation method is 'cgrid_velocity'
         Other Variables can be initialised using further arguments (e.g. v=... for a Variable named 'v')
        """
-        return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, repeatdt=repeatdt, **kwargs)
+        return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, repeatdt=repeatdt, lonlatdepth_dtype=lonlatdepth_dtype, **kwargs)
 
     @classmethod
-    def from_line(cls, fieldset, pclass, start, finish, size, depth=None, time=None, repeatdt=None):
+    def from_line(cls, fieldset, pclass, start, finish, size, depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None):
         """Initialise the ParticleSet from start/finish coordinates with equidistant spacing
         Note that this method uses simple numpy.linspace calls and does not take into account
         great circles, so may not be a exact on a globe
@@ -158,17 +161,19 @@ class ParticleSet(object):
         :param depth: Optional list of initial depth values for particles. Default is 0m
         :param time: Optional start time value for particles. Default is fieldset.U.time[0]
         :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
+        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
+               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+               and np.float64 if the interpolation method is 'cgrid_velocity'
         """
 
-        lonlat_type = cls.lonlatdepth_dtype_from_field_interp_method(fieldset.U)
-        lon = np.linspace(start[0], finish[0], size, dtype=lonlat_type)
-        lat = np.linspace(start[1], finish[1], size, dtype=lonlat_type)
+        lon = np.linspace(start[0], finish[0], size)
+        lat = np.linspace(start[1], finish[1], size)
         if type(depth) in [int, float]:
             depth = [depth] * size
-        return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, repeatdt=repeatdt)
+        return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, repeatdt=repeatdt, lonlatdepth_dtype=lonlatdepth_dtype)
 
     @classmethod
-    def from_field(cls, fieldset, pclass, start_field, size, mode='monte_carlo', depth=None, time=None, repeatdt=None):
+    def from_field(cls, fieldset, pclass, start_field, size, mode='monte_carlo', depth=None, time=None, repeatdt=None, lonlatdepth_dtype=None):
         """Initialise the ParticleSet randomly drawn according to distribution from a field
 
         :param fieldset: :mod:`parcels.fieldset.FieldSet` object from which to sample velocity
@@ -180,6 +185,9 @@ class ParticleSet(object):
         :param depth: Optional list of initial depth values for particles. Default is 0m
         :param time: Optional start time value for particles. Default is fieldset.U.time[0]
         :param repeatdt: Optional interval (in seconds) on which to repeat the release of the ParticleSet
+        :param lonlatdepth_dtype: Floating precision for lon, lat, depth particle coordinates.
+               It is either np.float32 or np.float64. Default is np.float32 if fieldset.U.interp_method is 'linear'
+               and np.float64 if the interpolation method is 'cgrid_velocity'
         """
 
         if mode == 'monte_carlo':
@@ -217,7 +225,7 @@ class ParticleSet(object):
         else:
             raise NotImplementedError('Mode %s not implemented. Please use "monte carlo" algorithm instead.' % mode)
 
-        return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, repeatdt=repeatdt)
+        return cls(fieldset=fieldset, pclass=pclass, lon=lon, lat=lat, depth=depth, time=time, lonlatdepth_dtype=lonlatdepth_dtype, repeatdt=repeatdt)
 
     @staticmethod
     def lonlatdepth_dtype_from_field_interp_method(field):


Test patch:
diff --git a/tests/test_particle_sets.py b/tests/test_particle_sets.py
index 160f9c91..cb8e43a2 100644
--- a/tests/test_particle_sets.py
+++ b/tests/test_particle_sets.py
@@ -30,12 +30,15 @@ def test_pset_create_lon_lat(fieldset, mode, npart=100):
 
 
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
-def test_pset_create_line(fieldset, mode, npart=100):
-    lon = np.linspace(0, 1, npart, dtype=np.float32)
-    lat = np.linspace(1, 0, npart, dtype=np.float32)
-    pset = ParticleSet.from_line(fieldset, size=npart, start=(0, 1), finish=(1, 0), pclass=ptype[mode])
+@pytest.mark.parametrize('lonlatdepth_dtype', [np.float64, np.float32])
+def test_pset_create_line(fieldset, mode, lonlatdepth_dtype, npart=100):
+    lon = np.linspace(0, 1, npart, dtype=lonlatdepth_dtype)
+    lat = np.linspace(1, 0, npart, dtype=lonlatdepth_dtype)
+    pset = ParticleSet.from_line(fieldset, size=npart, start=(0, 1), finish=(1, 0),
+                                 pclass=ptype[mode], lonlatdepth_dtype=lonlatdepth_dtype)
     assert np.allclose([p.lon for p in pset], lon, rtol=1e-12)
     assert np.allclose([p.lat for p in pset], lat, rtol=1e-12)
+    assert isinstance(pset[0].lat, lonlatdepth_dtype)
 
 
 @pytest.mark.parametrize('mode', ['scipy', 'jit'])
@@ -54,16 +57,19 @@ def test_pset_create_list_with_customvariable(fieldset, mode, npart=100):
 
 
 @pytest.mark.parametrize('mode', ['scipy'])
-def test_pset_create_field(fieldset, mode, npart=100):
+@pytest.mark.parametrize('lonlatdepth_dtype', [np.float64, np.float32])
+def test_pset_create_field(fieldset, mode, lonlatdepth_dtype, npart=100):
     np.random.seed(123456)
     shape = (fieldset.U.lon.size, fieldset.U.lat.size)
     K = Field('K', lon=fieldset.U.lon, lat=fieldset.U.lat,
               data=np.ones(shape, dtype=np.float32), transpose=True)
-    pset = ParticleSet.from_field(fieldset, size=npart, pclass=ptype[mode], start_field=K)
+    pset = ParticleSet.from_field(fieldset, size=npart, pclass=ptype[mode],
+                                  start_field=K, lonlatdepth_dtype=lonlatdepth_dtype)
     assert (np.array([p.lon for p in pset]) <= K.lon[-1]).all()
     assert (np.array([p.lon for p in pset]) >= K.lon[0]).all()
     assert (np.array([p.lat for p in pset]) <= K.lat[-1]).all()
     assert (np.array([p.lat for p in pset]) >= K.lat[0]).all()
+    assert isinstance(pset[0].lat, lonlatdepth_dtype)
 
 
 def test_pset_create_field_curvi(npart=100):