Skip to content

Commit

Permalink
Merge branch 'release-v1.1.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
mraspaud committed Dec 10, 2014
2 parents 6ccecea + ad3269c commit bb95750
Show file tree
Hide file tree
Showing 20 changed files with 229 additions and 184 deletions.
13 changes: 13 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
language: python
python:
- '2.6'
- '2.7'
- '3.2'
- '3.3'
- '3.4'
install:
- pip install .
- pip install coveralls
- pip install pykdtree
script: python setup.py nosetests --with-coverage --cover-package pyresample
after_success: coveralls
2 changes: 2 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Look at http://code.google.com/p/pyresample/ and http://pytroll.org/ for more in


===News===
* *2014-12-10*: Pyresample-1.1.1 released. Wrapping of longitudes and latitudes is now implemented.

* *2013-10-23*: Pyresample-1.1.0 released. Added option for calculating uncertainties for weighted kd-tree resampling. From now on pyresample will adhere to [http://semver.org/ semantic versioning].

* *2013-07-03*: Pyresample-1.0.0 released. Minor API change to the geometry.py module as the boundary variable is removed and replaced by proj_x_coords and proj_y_coords. Caching scheme removed from projection coordinate calculation in geometry.py as it introduced excessive complications. The numexpr package is now used for minor bottleneck optimization if available. Version number bumped to 1.0.0 as pyresample has been running stable in production environments for several years now.
Expand Down
43 changes: 23 additions & 20 deletions pyresample/__init__.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
#pyresample, Resampling of remote sensing image data in python
#
#Copyright (C) 2010 Esben S. Nielsen
# pyresample, Resampling of remote sensing image data in python
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
# Copyright (C) 2010, 2014 Esben S. Nielsen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import grid
import image
import kd_tree
import utils
import version
import plot
from __future__ import absolute_import

from pyresample import grid
from pyresample import image
from pyresample import kd_tree
from pyresample import utils
from pyresample import version
from pyresample import plot

__version__ = version.__version__


def get_capabilities():
cap = {}

try:
from pykdtree.kdtree import KDTree
cap['pykdtree'] = True
cap['pykdtree'] = True
except ImportError:
cap['pykdtree'] = False

try:
import numexpr
cap['numexpr'] = True
cap['numexpr'] = True
except ImportError:
cap['numexpr'] = False
cap['numexpr'] = False

return cap
104 changes: 49 additions & 55 deletions pyresample/_multi_proc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@
#You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import ctypes
from __future__ import absolute_import

import ctypes
import multiprocessing as mp

import numpy as np


class Scheduler(object):

def __init__(self, ndata, nprocs, chunk=None, schedule='guided'):
if not schedule in ['guided','dynamic', 'static']:
raise ValueError, 'unknown scheduling strategy'
raise ValueError('unknown scheduling strategy')
self._ndata = mp.RawValue(ctypes.c_int, ndata)
self._start = mp.RawValue(ctypes.c_int, 0)
self._lock = mp.Lock()
Expand All @@ -44,61 +47,52 @@ def __init__(self, ndata, nprocs, chunk=None, schedule='guided'):
self._chunk = min_chunk

def __iter__(self):
return self

def next(self):
self._lock.acquire()
ndata = self._ndata.value
nprocs = self._nprocs
start = self._start.value
if self._schedule == 'guided':
_chunk = ndata // nprocs
chunk = max(self._chunk, _chunk)
else:
chunk = self._chunk
if ndata:
if chunk > ndata:
s0 = start
s1 = start + ndata
self._ndata.value = 0
while True:
self._lock.acquire()
ndata = self._ndata.value
nprocs = self._nprocs
start = self._start.value
if self._schedule == 'guided':
_chunk = ndata // nprocs
chunk = max(self._chunk, _chunk)
else:
s0 = start
s1 = start + chunk
self._ndata.value = ndata - chunk
self._start.value = start + chunk
self._lock.release()
return slice(s0, s1)
else:
self._lock.release()
raise StopIteration

chunk = self._chunk
if ndata:
if chunk > ndata:
s0 = start
s1 = start + ndata
self._ndata.value = 0
else:
s0 = start
s1 = start + chunk
self._ndata.value = ndata - chunk
self._start.value = start + chunk
self._lock.release()
yield slice(s0, s1)
else:
self._lock.release()
raise StopIteration

def shmem_as_ndarray(raw_array):
_ctypes_to_numpy = {
ctypes.c_char : np.int8,
ctypes.c_wchar : np.int16,
ctypes.c_byte : np.int8,
ctypes.c_ubyte : np.uint8,
ctypes.c_short : np.int16,
ctypes.c_ushort : np.uint16,
ctypes.c_int : np.int32,
ctypes.c_uint : np.int32,
ctypes.c_long : np.int32,
ctypes.c_ulong : np.int32,
ctypes.c_float : np.float32,
ctypes.c_double : np.float64
}
address = raw_array._wrapper.get_address()
size = raw_array._wrapper.get_size()
ctypes.c_char: np.int8,
ctypes.c_wchar: np.int16,
ctypes.c_byte: np.int8,
ctypes.c_ubyte: np.uint8,
ctypes.c_short: np.int16,
ctypes.c_ushort: np.uint16,
ctypes.c_int: np.int32,
ctypes.c_uint: np.int32,
ctypes.c_long: np.int32,
ctypes.c_ulong: np.int32,
ctypes.c_float: np.float32,
ctypes.c_double: np.float64
}
dtype = _ctypes_to_numpy[raw_array._type_]
class Dummy(object): pass
d = Dummy()
d.__array_interface__ = {
'data' : (address, False),
'typestr' : np.dtype(np.uint8).str,
'descr' : np.dtype(np.uint8).descr,
'shape' : (size,),
'strides' : None,
'version' : 3
}
return np.asarray(d).view(dtype=dtype)

# The following works too, but occasionally raises
# RuntimeWarning: Item size computed from the PEP 3118 buffer format string does not match the actual item size.
# and appears to be slower.
# return np.ctypeslib.as_array(raw_array)

return np.frombuffer(raw_array, dtype=dtype)
27 changes: 14 additions & 13 deletions pyresample/_spatial_mp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from __future__ import absolute_import

import ctypes

import numpy as np
Expand All @@ -27,7 +29,7 @@
except ImportError:
ne = None

from _multi_proc import shmem_as_ndarray, Scheduler
from ._multi_proc import shmem_as_ndarray, Scheduler

#Earth radius
R = 6370997.0
Expand Down Expand Up @@ -133,13 +135,13 @@ def __call__(self, data1, data2, inverse=False, radians=False,\
shmem_data2 = mp.RawArray(ctypes.c_double, n)
shmem_res1 = mp.RawArray(ctypes.c_double, n)
shmem_res2 = mp.RawArray(ctypes.c_double, n)

# view shared memory as ndarrays
_data1 = shmem_as_ndarray(shmem_data1)
_data2 = shmem_as_ndarray(shmem_data2)
_res1 = shmem_as_ndarray(shmem_res1)
_res2 = shmem_as_ndarray(shmem_res2)

# copy input data to shared memory
_data1[:] = data1.ravel()
_data2[:] = data2.ravel()
Expand Down Expand Up @@ -192,9 +194,8 @@ def _run_jobs(target, args, nprocs):
for p in pool: p.start()
for p in pool: p.join()
if ierr.value != 0:
raise RuntimeError,\
('%d errors in worker processes. Last one reported:\n%s'%\
(ierr.value, err_msg.value))
raise RuntimeError('%d errors in worker processes. Last one reported:\n%s'%\
(ierr.value, err_msg.value.decode()))

# This is executed in an external process:
def _parallel_query(scheduler, # scheduler for load balancing
Expand Down Expand Up @@ -229,9 +230,9 @@ def _parallel_query(scheduler, # scheduler for load balancing
distance_upper_bound=dub)
# An error occured, increment the return value ierr.
# Access to ierr is serialized by multiprocessing.
except Exception, e:
except Exception as e:
ierr.value += 1
err_msg.value = e.message
err_msg.value = str(e).encode()

def _parallel_proj(scheduler, data1, data2, res1, res2, proj_args, proj_kwargs,\
inverse, radians, errcheck, ierr, err_msg):
Expand All @@ -249,12 +250,12 @@ def _parallel_proj(scheduler, data1, data2, res1, res2, proj_args, proj_kwargs,\
for s in scheduler:
_res1[s], _res2[s] = proj(_data1[s], _data2[s], inverse=inverse,\
radians=radians, errcheck=errcheck)

# An error occured, increment the return value ierr.
# Access to ierr is serialized by multiprocessing.
except Exception, e:
except Exception as e:
ierr.value += 1
err_msg.value = e.message
err_msg.value = str(e).encode()

def _parallel_transform(scheduler, lons, lats, n, coords, ierr, err_msg):
try:
Expand All @@ -270,6 +271,6 @@ def _parallel_transform(scheduler, lons, lats, n, coords, ierr, err_msg):
_coords[s, 2] = R*np.sin(np.radians(_lats[s]))
# An error occured, increment the return value ierr.
# Access to ierr is serialized by multiprocessing.
except Exception, e:
except Exception as e:
ierr.value += 1
err_msg.value = e.message
err_msg.value = str(e).encode()
2 changes: 2 additions & 0 deletions pyresample/data_reduce.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

"""Reduce data sets based on geographical information"""

from __future__ import absolute_import

import numpy as np


Expand Down
6 changes: 4 additions & 2 deletions pyresample/geo_filter.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import absolute_import

import numpy as np

import _spatial_mp
import geometry
from . import _spatial_mp
from . import geometry

class GridFilter(object):
"""Geographic filter from a grid
Expand Down
5 changes: 3 additions & 2 deletions pyresample/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Classes for geometry operations"""
import weakref

from __future__ import absolute_import

import numpy as np

import _spatial_mp
from . import _spatial_mp


class DimensionError(Exception):
Expand Down
11 changes: 9 additions & 2 deletions pyresample/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@
"""Resample image from one projection to another
using nearest neighbour method in cartesian projection coordinate systems"""

from __future__ import absolute_import

import numpy as np

import geometry
import _spatial_mp
from . import geometry
from . import _spatial_mp

try:
range = xrange
except NameError:
pass


def get_image_from_linesample(row_indices, col_indices, source_image,
Expand Down
4 changes: 3 additions & 1 deletion pyresample/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@

"""Handles resampling of images with assigned geometry definitions"""

from __future__ import absolute_import

import numpy as np

import geometry, grid, kd_tree
from . import geometry, grid, kd_tree


class ImageContainer(object):
Expand Down
Loading

0 comments on commit bb95750

Please sign in to comment.