Skip to content

Commit d07e726

Browse files
authored
Merge pull request #127 from felicio93/calc_write_lsc2
calc/write lsc2
2 parents 6006c2c + bc1ba69 commit d07e726

File tree

3 files changed

+510
-4
lines changed

3 files changed

+510
-4
lines changed

pyschism/mesh/vgrid.py

Lines changed: 152 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
from pyschism.mesh.hgrid import Hgrid
1111

12+
from matplotlib.pyplot import *
13+
1214

1315
def C_of_sigma(sigma, theta_b, theta_f):
1416
assert theta_b <= 0. and theta_b <= 1.
@@ -106,8 +108,16 @@ def is3D(self):
106108

107109
class LSC2(Vgrid):
108110

109-
def __init__(self, sigma):
110-
self.sigma = sigma
111+
def __init__(self, hsm, nv, h_c, theta_b, theta_f):
112+
self.hsm = np.array(hsm)
113+
self.nv = np.array(nv)
114+
self.h_c = h_c
115+
self.theta_b = theta_b
116+
self.theta_f = theta_f
117+
self.m_grid = None
118+
self._znd = None
119+
self._snd = None
120+
self._nlayer = None
111121

112122
def __str__(self):
113123
f = [
@@ -131,12 +141,147 @@ def __str__(self):
131141
return '\n'.join(f)
132142

133143
def get_xyz(self, gr3, crs=None):
144+
if type(gr3) == Hgrid:
145+
gr3 = gr3
146+
else:
147+
gr3=Hgrid.open(gr3)
134148
xy = gr3.get_xy(crs)
135149
z = gr3.values[:, None]*self.sigma
136150
x = np.tile(xy[:, 0], (z.shape[1],))
137151
y = np.tile(xy[:, 0], (z.shape[1],))
138152
return np.vstack([x, y, z.flatten()]).T
139153

154+
def calc_m_grid(self):
155+
'''
156+
create master grid
157+
Adapted from:
158+
https://github.com/wzhengui/pylibs/blob/master/pyScripts/gen_vqs.py
159+
'''
160+
if self.m_grid:
161+
pass
162+
else:
163+
z_mas=np.ones([self.nhm,self.nvrt])*np.nan; eta=0.0
164+
for m, [hsmi,nvi] in enumerate(zip(self.hsm,self.nv)):
165+
#strethcing funciton
166+
hc=min(hsmi,self.h_c)
167+
for k in np.arange(nvi):
168+
sigma= k/(1-nvi) #zi=-sigma #original sigma coordiante
169+
#compute zcoordinate
170+
cs=(1-self.theta_b)*np.sinh(self.theta_f*sigma)/np.sinh(self.theta_f)+\
171+
self.theta_b*(np.tanh(self.theta_f*(sigma+0.5))-\
172+
np.tanh(self.theta_f*0.5))/2/np.tanh(self.theta_f*0.5)
173+
z_mas[m,k]=eta*(1+sigma)+hc*sigma+(hsmi-hc)*cs
174+
175+
#normalize z_mas
176+
z_mas[m]=-(z_mas[m]-z_mas[m,0])*hsmi/(z_mas[m,nvi-1]-z_mas[m,0])
177+
s_mas=np.array([z_mas[i]/self.hsm[i] for i in np.arange(self.nhm)])
178+
179+
self.m_grid = z_mas
180+
181+
def make_m_plot(self):
182+
'''
183+
plot master grid
184+
Adapted from:
185+
https://github.com/wzhengui/pylibs/blob/master/pyScripts/gen_vqs.py
186+
'''
187+
#check master grid
188+
for i in np.arange(self.nhm-1):
189+
if min(self.m_grid[i,:self.nv[i]]-self.m_grid[i+1,:self.nv[i]])<0: \
190+
print('check: master grid layer={}, hsm={}, nv={}'.\
191+
format(i+1,self.hsm[i+1],self.nv[i+1]))
192+
193+
#plot master grid
194+
figure(figsize=[10,5])
195+
for i in np.arange(self.nhm): plot(i*np.ones(self.nvrt),\
196+
self.m_grid[i],'k-',lw=0.3)
197+
for k in np.arange(self.nvrt): plot(np.arange(self.nhm),\
198+
self.m_grid.T[k],'k-',lw=0.3)
199+
setp(gca(),xlim=[-0.5,self.nhm-0.5],ylim=[-self.hsm[-1],0.5])
200+
gcf().tight_layout()
201+
202+
def calc_lsc2_att(self, gr3, crs=None):
203+
'''
204+
master grid to lsc2:
205+
compute vertical layers at nodes
206+
gr3 is either file or Hgrid Object
207+
Adapted from:
208+
https://github.com/wzhengui/pylibs/blob/master/pyScripts/gen_vqs.py
209+
'''
210+
if type(gr3) == Hgrid:
211+
gd = gr3
212+
else:
213+
gd=Hgrid.open(gr3)
214+
dp = gd.values*-1
215+
fpz=dp<self.hsm[0]
216+
dp[fpz]=self.hsm[0]
217+
218+
#find hsm index for all points
219+
rat=np.ones(len(gd.nodes.id))*np.nan
220+
nlayer=np.zeros(len(gd.nodes.id)).astype('int')
221+
ind1=np.zeros(len(gd.nodes.id)).astype('int')
222+
ind2=np.zeros(len(gd.nodes.id)).astype('int')
223+
for m, hsmi in enumerate(self.hsm):
224+
if m==0:
225+
fp=dp<=self.hsm[m]
226+
ind1[fp]=0; ind2[fp]=0
227+
rat[fp]=0; nlayer[fp]=self.nv[0]
228+
else:
229+
fp=(dp>self.hsm[m-1])*(dp<=self.hsm[m])
230+
ind1[fp]=m-1
231+
ind2[fp]=m
232+
rat[fp]=(dp[fp]-self.hsm[m-1])/(self.hsm[m]-self.hsm[m-1])
233+
nlayer[fp]=self.nv[m]
234+
235+
#Find the last non NaN node and fills the NaN values with it
236+
last_non_nan = (~np.isnan(self.m_grid)).cumsum(1).argmax(1)
237+
z_mas=np.array([np.nan_to_num(z_mas_arr,nan=z_mas_arr[last_non_nan[i]])\
238+
for i, z_mas_arr in enumerate(self.m_grid)])
239+
znd=z_mas[ind1]*(1-rat[:,None])+z_mas[ind2]*rat[:,None]; #z coordinate
240+
for i in np.arange(len(gd.nodes.id)):
241+
znd[i,nlayer[i]-1]=-dp[i]
242+
znd[i,nlayer[i]:]=np.nan
243+
snd=znd/dp[:,None]; #sigma coordinate
244+
245+
#check vgrid
246+
for i in np.arange(len(gd.nodes.id)):
247+
for k in np.arange(self.nvrt-1):
248+
if znd[i,k]<=znd[i,k+1]:
249+
raise TypeError(f'wrong vertical layers')
250+
251+
self._znd = znd
252+
self._snd = snd
253+
self._nlayer = nlayer
254+
255+
256+
def write(self, path, overwrite=False):
257+
'''
258+
write mg2lsc2 into vgrid.in
259+
'''
260+
path = pathlib.Path(path)
261+
if path.is_file() and not overwrite:
262+
raise Exception(
263+
'File exists, pass overwrite=True to allow overwrite.')
264+
265+
with open(path, 'w') as fid:
266+
fid.write(' 1 !average # of layers={:0.2f}\n {} !nvrt\n'.format\
267+
(np.mean(self._nlayer),self.nvrt))
268+
bli=[]#bottom level index
269+
for i in np.arange(len(self._nlayer)):
270+
nlayeri=self._nlayer[i]; si=np.flipud(self._snd[i,:nlayeri])
271+
bli.append(self.nvrt-nlayeri+1)
272+
fstr=f" {self.nvrt-nlayeri+1:2}"
273+
fid.write(fstr)
274+
for i in range(self.nvrt):
275+
fid.write(f'\n {i+1}')
276+
for n,bl in enumerate(bli):
277+
si=np.flipud(self._snd[n])
278+
if bl <= i+1:
279+
fid.write(f" {si[i]:.6f}")
280+
else:
281+
fid.write(f" {-9.:.6f}")
282+
fid.close()
283+
284+
140285
@classmethod
141286
def open(cls, path):
142287

@@ -174,7 +319,11 @@ def open(cls, path):
174319

175320
@property
176321
def nvrt(self):
177-
return self.sigma.shape[1]
322+
return self.nv[-1]
323+
324+
@property
325+
def nhm(self):
326+
return self.hsm.shape[0]
178327

179328

180329
class SZ(Vgrid):

tests/_mesh/test_vgrid.py

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,105 @@
33
import pathlib
44
import unittest
55
from pyschism.mesh import Vgrid
6-
6+
from pyschism.mesh.hgrid import Hgrid
7+
from pyschism.mesh.vgrid import LSC2
8+
import numpy as np
79

810
class VgridTestCase(unittest.TestCase):
11+
def setUp(self):
12+
nodes = {
13+
'1': ((0., 0.), 1.5),
14+
'2': ((.5, 0.), 2.5),
15+
'3': ((1., 0.), 3.5),
16+
'4': ((1., 1.), 0.),
17+
'5': ((0., 1.), 1.),
18+
'6': ((.5, 1.5), -9.),
19+
'7': ((.33, .33), 1.),
20+
'8': ((.66, .33), 2.),
21+
'9': ((.5, .66), 3.),
22+
'10': ((-1., 1.), 4.),
23+
'11': ((-1., 0.), 5.),
24+
}
25+
elements = {
26+
'1': ['5', '7', '9'],
27+
'2': ['1', '2', '7'],
28+
'3': ['2', '3', '8'],
29+
'4': ['8', '7', '2'],
30+
'5': ['3', '4', '8'],
31+
'6': ['4', '9', '8'],
32+
'7': ['4', '6', '5'],
33+
'8': ['5', '10', '11', '1'],
34+
'9': ['9', '4', '5'],
35+
'10': ['5', '1', '7']
36+
}
37+
# write hgrid
38+
tmpdir = tempfile.TemporaryDirectory()
39+
hgrid = pathlib.Path(tmpdir.name) / 'hgrid.gr3'
40+
with open(hgrid, 'w') as f:
41+
f.write('\n')
42+
f.write(f'{len(elements):d} ')
43+
f.write(f'{len(nodes):d}\n')
44+
for id, ((x, y), z) in nodes.items():
45+
f.write(f"{id} ")
46+
f.write(f"{x} ")
47+
f.write(f"{y} ")
48+
f.write(f"{z}\n")
49+
for id, geom in elements.items():
50+
f.write(f"{id} ")
51+
f.write(f"{len(geom)} ")
52+
for idx in geom:
53+
f.write(f"{idx} ")
54+
f.write(f"\n")
55+
56+
hsm=[1,2,3,6]
57+
nv=[2,4,5,5]
58+
theta_b=0
59+
theta_f=2.5
60+
h_c=2
61+
62+
self.hgrid=Hgrid.open(hgrid,crs=4326)
63+
self.hsm=hsm
64+
self.nv=nv
65+
self.theta_b=theta_b
66+
self.theta_f=theta_f
67+
self.h_c=h_c
968

1069
def test_init(self):
1170
v = Vgrid()
1271
v.boilerplate_2D
1372
self.assertIsInstance(v, Vgrid)
1473

74+
def test_LSC2(self):
75+
lsc2_obj = LSC2(self.hsm,self.nv,self.h_c,self.theta_b,self.theta_f)
76+
self.assertIsInstance(lsc2_obj, LSC2)
77+
78+
def test_calc_m_grid(self):
79+
lsc2_obj = LSC2(self.hsm,self.nv,self.h_c,self.theta_b,self.theta_f)
80+
lsc2_obj.calc_m_grid()
81+
self.assertIsInstance(lsc2_obj.m_grid.shape, (4,5))
82+
83+
def test_make_m_plot(self):
84+
lsc2_obj = LSC2(self.hsm,self.nv,self.h_c,self.theta_b,self.theta_f)
85+
lsc2_obj.calc_m_grid()
86+
lsc2_obj.make_m_plot()
87+
88+
def test_calc_lsc2_att(self):
89+
gr3=self.hgrid
90+
lsc2_obj = LSC2(self.hsm,self.nv,self.h_c,self.theta_b,self.theta_f)
91+
lsc2_obj.calc_m_grid()
92+
lsc2_obj.calc_lsc2_att(gr3)
93+
self.assertIsInstance(lsc2_obj._znd.shape,(11,5))
94+
self.assertIsInstance(lsc2_obj._snd.shape,(11,5))
95+
self.assertIsInstance(lsc2_obj._nlayer,np.array([4,5,5,2,2,2,2,4,5,5,5]))
96+
97+
def test_lsc2_write(self):
98+
tmpdir = tempfile.TemporaryDirectory()
99+
gr3=self.hgrid
100+
lsc2_obj = LSC2(self.hsm,self.nv,self.h_c,self.theta_b,self.theta_f)
101+
lsc2_obj.calc_m_grid()
102+
lsc2_obj.calc_lsc2_att(gr3)
103+
lsc2_obj.write(pathlib.Path(tmpdir.name) / 'vgrid_lsc2.in')
104+
15105
def test_write(self):
16106
tmpdir = tempfile.TemporaryDirectory()
17107
v = Vgrid()

0 commit comments

Comments
 (0)