Skip to content

Commit 48468df

Browse files
committed
add arbitrary ellipse for geofixedgrid, centers_to_edges
1 parent 7031649 commit 48468df

File tree

1 file changed

+120
-6
lines changed

1 file changed

+120
-6
lines changed

pyxlma/coords.py

Lines changed: 120 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,38 @@ class GeostationaryFixedGridSystem(CoordinateSystem):
207207

208208
def __init__(self, subsat_lon=0.0, subsat_lat=0.0, sweep_axis='y',
209209
sat_ecef_height=35785831.0,
210-
ellipse='WGS84', datum='WGS84'):
210+
ellipse='WGS84'):
211211
"""
212-
Satellite height is with respect to the ellipsoid. Fixed grid
213-
coordinates are in radians.
212+
Coordinate system representing a grid of scan angles from the perspective of a
213+
geostationary satellite above an arbitrary ellipsoid. Fixed grid coordinates are
214+
in radians.
215+
216+
Parameters
217+
----------
218+
subsat_lon : float
219+
Longitude of the subsatellite point in degrees.
220+
subsat_lat : float
221+
Latitude of the subsatellite point in degrees.
222+
sweep_axis : str
223+
Axis along which the satellite sweeps. 'x' or 'y'. Use 'x' for GOES
224+
and 'y' (default) for EUMETSAT.
225+
sat_ecef_height : float
226+
Height of the satellite in meters from the center of the Earth.
227+
ellipse : str or list
228+
A string representing a known ellipse to pyproj, or a list of [a, b] (semi-major
229+
and semi-minor axes) of the ellipse. Default is 'WGS84'.
214230
"""
215-
# self.ECEFxyz = proj4.Proj(proj='cart', ellps=ellipse)#, datum=datum)
216-
self.ECEFxyz = proj4.Proj(proj='geocent', ellps=ellipse)#, datum=datum)
231+
if type(ellipse) == list and len(ellipse) == 2:
232+
rf = semiaxes_to_invflattening(ellipse[0], ellipse[1])
233+
ellipse_args = {'a': ellipse[0], 'rf': rf}
234+
elif type(ellipse) == str:
235+
ellipse_args = {'ellps': ellipse}
236+
else:
237+
raise ValueError("Ellipse must be a string or list of [a, b].")
238+
self.ECEFxyz = proj4.Proj(proj='geocent', **ellipse_args)
217239
self.fixedgrid = proj4.Proj(proj='geos', lon_0=subsat_lon,
218240
lat_0=subsat_lat, h=sat_ecef_height, x_0=0.0, y_0=0.0,
219-
units='m', sweep=sweep_axis, ellps=ellipse)
241+
units='m', sweep=sweep_axis, **ellipse_args)
220242
self.h=sat_ecef_height
221243

222244
def toECEF(self, x, y, z):
@@ -473,3 +495,95 @@ def fromLocal(self, data):
473495
return array( [ (dot(self.TransformToLocal.transpose(), v) + self.centerECEF)
474496
for v in data[0:3,:].transpose()]
475497
).squeeze().transpose()
498+
499+
500+
def semiaxes_to_invflattening(semimajor, semiminor):
501+
""" Calculate the inverse flattening from the semi-major
502+
and semi-minor axes of an ellipse"""
503+
rf = semimajor/(semimajor-semiminor)
504+
return rf
505+
506+
507+
def centers_to_edges(x):
508+
"""
509+
Create an array of length N+1 edge locations from an
510+
array of lenght N grid center locations.
511+
512+
In the interior, the edge positions set to the midpoints
513+
of the values in x. For the outermost edges, half the
514+
closest dx is assumed to apply.
515+
516+
Parameters
517+
----------
518+
x : array, shape (N)
519+
Locations of the centers
520+
521+
Returns
522+
-------
523+
xedge : array, shape (N+1,M+1)
524+
525+
"""
526+
xedge=zeros(x.shape[0]+1)
527+
xedge[1:-1] = (x[:-1] + x[1:])/2.0
528+
xedge[0] = x[0] - (x[1] - x[0])/2.0
529+
xedge[-1] = x[-1] + (x[-1] - x[-2])/2.0
530+
return xedge
531+
532+
533+
def centers_to_edges_2d(x):
534+
"""
535+
Create a (N+1, M+1) array of edge locations from a
536+
(N, M) array of grid center locations.
537+
538+
In the interior, the edge positions set to the midpoints
539+
of the values in x. For the outermost edges, half the
540+
closest dx is assumed to apply. This matters for polar
541+
meshes, where one edge of the grid becomes a point at the
542+
polar coordinate origin; dx/2 is a half-hearted way of
543+
trying to prevent negative ranges.
544+
545+
Parameters
546+
----------
547+
x : array, shape (N,M)
548+
Locations of the centers
549+
550+
Returns
551+
-------
552+
xedge : array, shape (N+1,M+1)
553+
554+
"""
555+
xedge = zeros((x.shape[0]+1,x.shape[1]+1))
556+
# interior is a simple average of four adjacent centers
557+
xedge[1:-1,1:-1] = (x[:-1,:-1] + x[:-1,1:] + x[1:,:-1] + x[1:,1:])/4.0
558+
559+
# /\
560+
# /\/\
561+
# / /\ \
562+
# /\/ \/\
563+
# / /\ /\ \
564+
# /\/ \/ \/\
565+
# / /\ /\ /\ \
566+
# /\/ \/ \/ \/\
567+
#4 \/\ /\ /\ /\/ 4
568+
# 3 \ \/ \/ \/ / 3
569+
# \/\ /\ /\/
570+
# 2 \ \/ \/ / 2
571+
# \/\ /\/
572+
# 1 \ \/ / 1
573+
# \/\/
574+
# 0 \/ 0 = center ID of 0th dimension
575+
#
576+
577+
# calculate the deltas along each edge, excluding corners
578+
xedge[1:-1,0] = xedge[1:-1, 1] - (xedge[1:-1, 2] - xedge[1:-1, 1])/2.0
579+
xedge[1:-1,-1]= xedge[1:-1,-2] - (xedge[1:-1,-3] - xedge[1:-1,-2])/2.0
580+
xedge[0,1:-1] = xedge[1,1:-1] - (xedge[2,1:-1] - xedge[1,1:-1])/2.0
581+
xedge[-1,1:-1]= xedge[-2,1:-1] - (xedge[-3,1:-1] - xedge[-2,1:-1])/2.0
582+
583+
# now do the corners
584+
xedge[0,0] = xedge[1, 1] - (xedge[2, 2] - xedge[1, 1])/2.0
585+
xedge[0,-1] = xedge[1,-2] - (xedge[2,-3] - xedge[1,-2])/2.0
586+
xedge[-1,0] = xedge[-2,1] - (xedge[-3,2] - xedge[-2,1])/2.0
587+
xedge[-1,-1]= xedge[-2,-2]- (xedge[-3,-3]- xedge[-2,-2])/2.0
588+
589+
return xedge

0 commit comments

Comments
 (0)