Skip to content

Commit 2e602a9

Browse files
committed
More general coordinate handling
- logCoords and basis are now arrays to allow for multiple logarithmic coordinates instead of only one. - there are now additional inputs to LoadData (and thus also TransformCoords): reverseCoords and revCenter. These are arrays that tell pv_atmos which coordinates should be reversed (such as e.g. pressure), and around which value - The example files as well as the test_functions file now ask for the path to pv_atmos instead of assuming something. - Example and test files are modified to take into account the changes to pv_atmos mentioned above
1 parent b2d4056 commit 2e602a9

7 files changed

+68
-40
lines changed

basic.py

+28-9
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def ConvertLogCoordString(pString, basis=1e3):
3030
return expression
3131

3232
# do the coordinate conversion inside a Calculator
33-
def Cart2Log(src=GetActiveSource(), ratios=[1,1,1], logCoords=[2], basis=[1e3]):
33+
def Cart2Log(src=GetActiveSource(), ratios=[1,1,1], logCoords=[], basis=[]):
3434
"""Convert between logarithmic and linear coordinates. Also applies aspect ratio correction.
3535
3636
Adds a Calculator filter to the pipeline
@@ -86,16 +86,33 @@ def GridAspectRatio(ratios, src=GetActiveSource()):
8686
ratios -- 2- or 3-vector with multiplicative factors for each spatial coordinate
8787
"""
8888
calc=Calculator(src)
89-
try:
90-
calc.Function = 'iHat*'+str(ratios[0])+'*coordsX + jHat*'+str(ratios[1])+'*coordsY + kHat*'+str(ratios[2])+'*coordsZ'
91-
except:
92-
calc.Function = 'iHat*'+str(ratios[0])+'*coordsX + jHat*'+str(ratios[1])+'*coordsY'
89+
calc.Function = 'iHat*'+str(ratios[0])+'*coordsX + jHat*'+str(ratios[1])+'*coordsY + kHat*'+str(ratios[2])+'*coordsZ'
9390
calc.CoordinateResults = 1
9491
return calc
9592

9693
# transform coordinates: logarithmic, aspect ratio
97-
def TransformCoords(src=GetActiveSource(), aspectRatios=[1,1,1], logCoords=[2], basis=[1e3]):
94+
def TransformCoords(src=GetActiveSource(), aspectRatios=[1,1,1], logCoords=[], basis=[], reverseCoords=[], revCenter=[]):
9895
"""Transform the coordinates depending on whether or not there are logarithmic coordinates"""
96+
if len(reverseCoords)>0:
97+
nVec = ['iHat*','jHat*','kHat*']
98+
nCoor= ['X','Y','Z']
99+
revCoor = Calculator(src)
100+
rFun = ''
101+
for dim in range(3):
102+
if dim in reverseCoords or -dim in reverseCoords:
103+
for d in range(len(reverseCoords)):
104+
if dim == abs(reverseCoords[d]):
105+
rd = d
106+
if reverseCoords[rd]<0:
107+
coorSign = '+'
108+
else:
109+
coorSign = '-'
110+
rFun += ' +'+nVec[dim]+'('+str(revCenter[rd])+coorSign+'coords'+nCoor[dim]+')'
111+
else:
112+
rFun += ' +'+nVec[dim]+'coords'+nCoor[dim]
113+
revCoor.Function = rFun[2:]
114+
revCoor.CoordinateResults = 1
115+
src = revCoor
99116
if len(logCoords)>0 :
100117
transCoor = Cart2Log(src=src,ratios=aspectRatios,logCoords=logCoords,basis=basis)
101118
else:
@@ -111,7 +128,7 @@ def MakeSelectable(src=GetActiveSource()):
111128

112129
######### read in data, redefine pressure coordinates and change aspect ratio ###############
113130

114-
def LoadData( fileName, ncDims=['lon','lat','pfull'], aspectRatios=[1,1,1], logCoords=[2], basis=[1e3], replaceNaN=True ):
131+
def LoadData( fileName, ncDims=['lon','lat','pfull'], aspectRatios=[1,1,1], logCoords=[], basis=[], reverseCoords=[], revCenter=[], replaceNaN=True ):
115132
"""Load netCDF file, convert coordinates into useful aspect ratio.
116133
117134
Adds file output_nc, and Calculator LogP or Calculator AspRat to the pipeline
@@ -120,8 +137,10 @@ def LoadData( fileName, ncDims=['lon','lat','pfull'], aspectRatios=[1,1,1], logC
120137
fileName -- full path and file name of data to be read
121138
ncDims -- names of the dimensions within the netCDF file. Time should be excluded. Ordering [x,y,z]
122139
aspectRatios -- how to scale coordinates [xscale,yscale,zscale]. Z coordinate is scaled after applying log10 for logarithmic axes
123-
logCoords -- index/indices of dimension(s) to be logarithmic
140+
logCoords -- index/indices of dimension(s) to be logarithmic, set to [] if no log coordinates
124141
basis -- basis to normalize argument to logarithm (ie defines origin). List of same length as logCoords
142+
reverseCoords -- index/indices of dimension(s) to be reversed, set to [] if none to be reversed
143+
revCenter -- center of reversal if reverseCoords is not empty. List of same length as logCoords
125144
replaceNaN -- whether or not to replace the FillValue with NaNs
126145
OUTPUTS:
127146
output_nc -- netCDF reader object with the file data as read
@@ -144,7 +163,7 @@ def LoadData( fileName, ncDims=['lon','lat','pfull'], aspectRatios=[1,1,1], logC
144163
MakeSelectable()
145164
RenameSource(fileName,output_nc)
146165

147-
transCoor = TransformCoords(src=output_nc,aspectRatios=aspectRatios,logCoords=logCoords,basis=basis)
166+
transCoor = TransformCoords(src=output_nc,aspectRatios=aspectRatios,logCoords=logCoords,basis=basis,reverseCoords=reverseCoords,revCenter=revCenter)
148167
MakeSelectable()
149168

150169
if len(logCoords)>0 :

examples/example_flat.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
try:
1313
pvAtmosPath
1414
except:
15-
pvAtmosPath = '../'
15+
pvAtmosPath = raw_input("Please provide the path where pv_atmos lives: ")
16+
pvAtmosPath = pvAtmosPath+'/'
1617
try: #is pv_atmos installed?
1718
from pv_atmos.basic import *
1819
from pv_atmos.grids import *

examples/example_ocean.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
try:
1313
pvAtmosPath
1414
except:
15-
pvAtmosPath = '../'
15+
pvAtmosPath = raw_input("Please provide the path where pv_atmos lives: ")
16+
pvAtmosPath = pvAtmosPath+'/'
1617
try: #is pv_atmos installed?
1718
from pv_atmos.basic import *
1819
from pv_atmos.grids import *
@@ -52,7 +53,7 @@
5253

5354

5455
# bathymetry
55-
(depth_out,depth_coor)=LoadData(oceanPath+topoFile,ncDims=topoDims,logCoords=logCoord )
56+
(depth_out,depth_coor)=LoadData(oceanPath+topoFile,ncDims=topoDims,logCoords=logCoord,replaceNaN=False )
5657
# get the bounds of the topography. This is important if bathymetry and data files have different origins
5758
topoBds = depth_out.GetDataInformation().GetBounds()
5859

examples/example_pole.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
try:
1313
pvAtmosPath
1414
except:
15-
pvAtmosPath = '../'
15+
pvAtmosPath = raw_input("Please provide the path where pv_atmos lives: ")
16+
pvAtmosPath = pvAtmosPath+'/'
1617
try: #is pv_atmos installed?
1718
from pv_atmos.basic import *
1819
from pv_atmos.grids import *
@@ -45,7 +46,6 @@
4546

4647
# then, the file containing geopotential height data
4748
dataFile = 'ECMWF_19790223.nc'
48-
dataFile = 'tmp.nc'
4949
dataDims = ['longitude','latitude','level']
5050
# the values we will be interested in
5151
dataName = 'height'
@@ -68,7 +68,7 @@
6868
## Earth
6969

7070
# get bathymetry: this is exactly the same as in example_ocean.py
71-
(depth_out,depth_coor)=LoadData(topoFileName,ncDims=topoDims,logCoords=topoLogCoord )
71+
(depth_out,depth_coor)=LoadData(topoFileName,ncDims=topoDims,logCoords=topoLogCoord, replaceNaN = False )
7272
# the bathymetry file is in cell data, need to convert to point data
7373
c2p=CellDatatoPointData(depth_coor)
7474
MakeSelectable()

examples/example_sphere.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
try:
1313
pvAtmosPath
1414
except:
15-
pvAtmosPath = '../'
15+
pvAtmosPath = raw_input("Please provide the path where pv_atmos lives: ")
16+
pvAtmosPath = pvAtmosPath+'/'
1617
try: #is pv_atmos installed?
1718
from pv_atmos.basic import *
1819
from pv_atmos.grids import *

grids.py

+14-11
Original file line numberDiff line numberDiff line change
@@ -396,22 +396,25 @@ def SphericalShells(radius=1, ratios=[1,1,1], logCoord=[2], basis=[1e3], src=Get
396396
return Planes
397397

398398
###### add full set of grids and lables in rectangular geometry ############################
399-
def AddGrid(xlevels=[0,90,180,270], ylevels=[-60,-30,0,30,60], zlevels=[100,10,1,0.1], bounds=[0.0,360.0,-90.0,90.0,1e3,0.1], ratios=[1,1,1], logCoord=[2], basis=[1e3], AxisNames=["lon","lat","pressure [hPa]"], AxisColor=[0,0,0], AxisWidth=2.0,LabelSize=5.0):
399+
def AddGrid(xlevels=[0,90,180,270], ylevels=[-60,-30,0,30,60], zlevels=[100,10,1,0.1], bounds=[0.0,360.0,-90.0,90.0,1e3,0.1], ratios=[1,1,1], logCoord=[], basis=[], reverseCoords=[], revCenter=[], AxisNames=["lon","lat","pressure [hPa]"], AxisColor=[0,0,0], AxisWidth=2.0,LabelSize=5.0):
400400
"""Add a full grid with grid lines and labels.
401401
402402
Adds as many X,Y,Z grid lines as needed. This function adds a lot of objects and filters to the pipeline, and should probably only be used once the visualization itself is finished. This function can be called even if there is no data loaded.
403403
404404
INPUTS:
405-
xlevels -- vector with X grid positions
406-
ylevels -- vector with Y grid positions
407-
zlevels -- vector with Z grid levels
408-
bounds -- grid bounds
409-
ratios -- axes ratios
410-
basis -- basis (surface) pressure
411-
AxisNames -- names of x,y,z axis
412-
AxisColor -- color of lines in RGB
413-
AxisWidth -- width of lines
414-
LabelSize -- Size of the label text
405+
xlevels -- vector with X grid positions
406+
ylevels -- vector with Y grid positions
407+
zlevels -- vector with Z grid levels
408+
bounds -- grid bounds
409+
ratios -- axes ratios
410+
logCoord -- coordinate index/indices for logarithmic axes
411+
basis -- basis for logarithmic coordinates logCoords
412+
reverseCoords -- coordinate index/indices for axes to be reversed
413+
revCenter -- center around which to reverse reverseCoords
414+
AxisNames -- names of x,y,z axis
415+
AxisColor -- color of lines in RGB
416+
AxisWidth -- width of lines
417+
LabelSize -- Size of the label text
415418
"""
416419
(Xmin,Xmax,Ymin,Ymax,Zmin,Zmax) = BoundAspectRatio(bounds, ratios, logCoord, basis)
417420
absLsz = abs(LabelSize)

testing/test_functions.py

+16-13
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,25 @@
44
import numpy as np
55
import os
66

7-
#adjust the path to pv-atmos here:
8-
try:
9-
pvAtmosPath=os.path.dirname(__file__) + '/../'
10-
except: #if run in interactive mode
11-
pvAtmosPath='../'
127
try: from atmos_basic import *
13-
except: execfile(pvAtmosPath + 'atmos_basic.py')
8+
except:
9+
pvAtmosPath = raw_input("Please provide the path where pv_atmos lives: ")
10+
pvAtmosPath = pvAtmosPath+'/'
11+
print 'Using '+pvAtmosPath
12+
execfile(pvAtmosPath + 'basic.py')
1413
try: from atmos_grids import *
15-
except: execfile(pvAtmosPath + 'atmos_grids.py')
14+
except: execfile(pvAtmosPath + 'grids.py')
1615

1716

1817
class TestSequenceFunctions(unittest.TestCase):
1918
def setUp(self):
2019
self.p = random.uniform(1e-5,1e3) # choose pressure surface randomly
2120
self.rat = [random.uniform(0,1),random.uniform(0,1),random.uniform(0,1)] # choose box aspect ration randomly
22-
self.pCoord = round(random.uniform(0,1)) # choose whether or not data uses pressure coordinates
21+
# choose whether or not data uses pressure coordinates
22+
if round(random.uniform(0,1)) == 1:
23+
self.pCoord = [int(round(random.uniform(0,2)))] # which dimension is logarithmic?
24+
else:
25+
self.pCoord = []
2326
self.np = round(random.uniform(1,5)) # number of pressure levels for grid
2427
self.nx = round(random.uniform(1,5)) # number of lon gridlines for grid
2528
self.ny = round(random.uniform(1,5)) # number of lat gridlines for grid
@@ -35,21 +38,21 @@ def setUp(self):
3538
def test_basic(self):
3639
# load data
3740
fileName = pvAtmosPath+'examples/uv_daily.nc'
38-
(output_nc,CorrZ,Coor,AspRat) = loadData(fileName, ['pfull','lat','lon'], self.pCoord, self.rat, math.ceil(self.p))
41+
(output_nc,AspRat) = LoadData(fileName, ncDims=['lon','lat','pfull'], aspectRatios=self.rat, logCoords=self.pCoord, basis=[math.ceil(self.p)])
3942
self.assertEqual(output_nc.OutputType,'Unstructured')
40-
(W,norm,clipS,clipN)=CartWind2Atmos(src=AspRat,ratios=self.rat)
43+
(W,norm,clipS,clipN)=CartWind2Sphere(src=AspRat,ratios=self.rat)
4144
self.assertEqual(clipS.ClipType.Origin[1],-80.0*self.rat[1])
4245
self.assertEqual(clipN.ClipType.Origin[1], 80.0*self.rat[1])
4346

4447
def test_allGrids(self):
45-
AddGrid(press=np.arange(self.p,self.top,-self.p/self.np), lats=np.arange(self.mx[0],self.mx[1],(self.mx[1]-self.mx[0])/self.nx), lons=np.arange(self.my[0],self.my[1],(self.my[1]-self.my[0])/self.ny), bounds=[self.my[0],self.my[1],self.mx[0],self.mx[1],self.p,self.top], ratios=self.rat, basis=math.ceil(self.p), AxisColor=[0,0,0], AxisWidth=2.0,LabelSize=5.0)
48+
AddGrid(zlevels=np.arange(self.p,self.top,-self.p/self.np), ylevels=np.arange(self.mx[0],self.mx[1],(self.mx[1]-self.mx[0])/self.nx), xlevels=np.arange(self.my[0],self.my[1],(self.my[1]-self.my[0])/self.ny), bounds=[self.my[0],self.my[1],self.mx[0],self.mx[1],self.p,self.top], ratios=self.rat, basis=[math.ceil(self.p)], AxisColor=[0,0,0], AxisWidth=2.0,LabelSize=5.0)
4649
print 'Check pipeline for grid'
4750

4851
def test_shells(self):
4952
# load data
5053
fileName = pvAtmosPath+'examples/uv_daily.nc'
51-
(output_nc,CorrZ,Coor,AspRat) = loadData(fileName, ['pfull','lat','lon'], 1, self.rat, math.ceil(self.p))
52-
AtmosShells(radius=self.rad,ratios=self.rat,basis=math.ceil(self.p),src=AspRat,shellValues=np.arange(self.p,self.top,-self.p/self.np),labels=self.pCoord,labelPosition=[self.my[0],self.mx[0]],waterMark='WaterMark',markPosition=[self.my[1],self.mx[1]])
54+
(output_nc,AspRat) = LoadData(fileName, ['pfull','lat','lon'], self.rat, [1], [math.ceil(self.p)])
55+
SphericalShells(radius=self.rad,ratios=self.rat,basis=[math.ceil(self.p)],src=AspRat,shellValues=np.arange(self.p,self.top,-self.p/self.np),labels=self.pCoord,labelPosition=[self.my[0],self.mx[0]],waterMark='WaterMark',markPosition=[self.my[1],self.mx[1]])
5356
print 'Check pipeline for spherical shells'
5457

5558

0 commit comments

Comments
 (0)