1- from __future__ import absolute_import , division , print_function , \
2- unicode_literals
1+ import argparse
32
43import numpy as np
4+ import xarray as xr
55
6- from netCDF4 import Dataset as NetCDFFile
6+ from mpas_tools . io import write_netcdf
77from mpas_tools .mesh .creation .open_msh import readmsh
88from mpas_tools .mesh .creation .util import circumcenter
99
10- import argparse
11-
1210
1311def jigsaw_to_netcdf (msh_filename , output_name , on_sphere , sphere_radius = None ):
1412 """
@@ -18,150 +16,123 @@ def jigsaw_to_netcdf(msh_filename, output_name, on_sphere, sphere_radius=None):
1816 ----------
1917 msh_filename : str
2018 A JIGSAW mesh file name
19+
2120 output_name: str
2221 The name of the output file
22+
2323 on_sphere : bool
2424 Whether the mesh is spherical or planar
25+
2526 sphere_radius : float, optional
26- The radius of the sphere in meters. If ``on_sphere=True`` this argument
27- is required, otherwise it is ignored.
27+ The radius of the sphere in meters. If ``on_sphere=True`` this
28+ argument is required, otherwise it is ignored.
2829 """
29- # Authors: Phillip J. Wolfram, Matthew Hoffman and Xylar Asay-Davis
30-
31- grid = NetCDFFile (output_name , 'w' , format = 'NETCDF3_CLASSIC' )
3230
3331 # Get dimensions
3432 # Get nCells
3533 msh = readmsh (msh_filename )
3634 nCells = msh ['POINT' ].shape [0 ]
37-
38- # Get vertexDegree and nVertices
39- vertexDegree = 3 # always triangles with JIGSAW output
35+ # always triangles with JIGSAW output
36+ vertexDegree = 3
4037 nVertices = msh ['TRIA3' ].shape [0 ]
4138
4239 if vertexDegree != 3 :
43- ValueError ("This script can only compute vertices with triangular "
44- "dual meshes currently." )
45-
46- grid .createDimension ('nCells' , nCells )
47- grid .createDimension ('nVertices' , nVertices )
48- grid .createDimension ('vertexDegree' , vertexDegree )
40+ raise ValueError (
41+ 'This script can only compute vertices with triangular '
42+ 'dual meshes currently.' )
4943
5044 # Create cell variables and sphere_radius
5145 xCell_full = msh ['POINT' ][:, 0 ]
5246 yCell_full = msh ['POINT' ][:, 1 ]
53- zCell_full = []
5447 if msh ['NDIMS' ] == 2 :
5548 zCell_full = np .zeros (yCell_full .shape )
5649 elif msh ['NDIMS' ] == 3 :
5750 zCell_full = msh ['POINT' ][:, 2 ]
5851 else :
59- raise ValueError ("NDIMS must be 2 or 3; input mesh has NDIMS={}"
60- .format (msh ['NDIMS' ]))
52+ raise ValueError (
53+ f'NDIMS must be 2 or 3; input mesh has NDIMS={ msh ["NDIMS" ]} '
54+ )
6155 for cells in [xCell_full , yCell_full , zCell_full ]:
62- assert cells .shape [0 ] == nCells , 'Number of anticipated nodes is' \
63- ' not correct!'
56+ assert cells .shape [0 ] == nCells , \
57+ 'Number of anticipated nodes is not correct!'
58+
59+ attrs = {}
6460 if on_sphere :
65- grid . on_a_sphere = " YES"
66- grid . sphere_radius = sphere_radius
61+ attrs [ ' on_a_sphere' ] = ' YES'
62+ attrs [ ' sphere_radius' ] = sphere_radius
6763 # convert from km to meters
68- xCell_full *= 1e3
69- yCell_full *= 1e3
70- zCell_full *= 1e3
64+ xCell_full = xCell_full * 1e3
65+ yCell_full = yCell_full * 1e3
66+ zCell_full = zCell_full * 1e3
7167 else :
72- grid . on_a_sphere = "NO"
73- grid . sphere_radius = 0.0
68+ attrs [ ' on_a_sphere' ] = 'NO'
69+ attrs [ ' sphere_radius' ] = 0.0
7470
7571 # Create cellsOnVertex
7672 cellsOnVertex_full = msh ['TRIA3' ][:, :3 ] + 1
7773 assert cellsOnVertex_full .shape == (nVertices , vertexDegree ), \
7874 'cellsOnVertex_full is not the right shape!'
7975
80- # Create vertex variables
81- xVertex_full = np .zeros ((nVertices ,))
82- yVertex_full = np .zeros ((nVertices ,))
83- zVertex_full = np .zeros ((nVertices ,))
84-
85- for iVertex in np .arange (0 , nVertices ):
86- cell1 = cellsOnVertex_full [iVertex , 0 ]
87- cell2 = cellsOnVertex_full [iVertex , 1 ]
88- cell3 = cellsOnVertex_full [iVertex , 2 ]
89-
90- x1 = xCell_full [cell1 - 1 ]
91- y1 = yCell_full [cell1 - 1 ]
92- z1 = zCell_full [cell1 - 1 ]
93- x2 = xCell_full [cell2 - 1 ]
94- y2 = yCell_full [cell2 - 1 ]
95- z2 = zCell_full [cell2 - 1 ]
96- x3 = xCell_full [cell3 - 1 ]
97- y3 = yCell_full [cell3 - 1 ]
98- z3 = zCell_full [cell3 - 1 ]
99-
100- pv = circumcenter (on_sphere , x1 , y1 , z1 , x2 , y2 , z2 , x3 , y3 , z3 )
101- xVertex_full [iVertex ] = pv .x
102- yVertex_full [iVertex ] = pv .y
103- zVertex_full [iVertex ] = pv .z
104-
105- meshDensity_full = grid .createVariable (
106- 'meshDensity' , 'f8' , ('nCells' ,))
107-
108- for iCell in np .arange (0 , nCells ):
109- meshDensity_full [iCell ] = 1.0
110-
111- del meshDensity_full
112-
113- var = grid .createVariable ('xCell' , 'f8' , ('nCells' ,))
114- var [:] = xCell_full
115- var = grid .createVariable ('yCell' , 'f8' , ('nCells' ,))
116- var [:] = yCell_full
117- var = grid .createVariable ('zCell' , 'f8' , ('nCells' ,))
118- var [:] = zCell_full
119- var = grid .createVariable ('xVertex' , 'f8' , ('nVertices' ,))
120- var [:] = xVertex_full
121- var = grid .createVariable ('yVertex' , 'f8' , ('nVertices' ,))
122- var [:] = yVertex_full
123- var = grid .createVariable ('zVertex' , 'f8' , ('nVertices' ,))
124- var [:] = zVertex_full
125- var = grid .createVariable (
126- 'cellsOnVertex' , 'i4' , ('nVertices' , 'vertexDegree' ,))
127- var [:] = cellsOnVertex_full
128-
129- grid .sync ()
130- grid .close ()
131-
76+ # Vectorized circumcenter calculation
77+ # shape (nVertices, vertexDegree)
78+ cell_indices = cellsOnVertex_full - 1
79+ x_cells = xCell_full [cell_indices ]
80+ y_cells = yCell_full [cell_indices ]
81+ z_cells = zCell_full [cell_indices ]
82+
83+ # Vectorized circumcenter computation
84+ x1 , x2 , x3 = x_cells [:, 0 ], x_cells [:, 1 ], x_cells [:, 2 ]
85+ y1 , y2 , y3 = y_cells [:, 0 ], y_cells [:, 1 ], y_cells [:, 2 ]
86+ z1 , z2 , z3 = z_cells [:, 0 ], z_cells [:, 1 ], z_cells [:, 2 ]
87+ xVertex_full , yVertex_full , zVertex_full = circumcenter (
88+ on_sphere , x1 , y1 , z1 , x2 , y2 , z2 , x3 , y3 , z3
89+ )
90+
91+ meshDensity_full = np .ones ((nCells ,), dtype = np .float64 )
92+
93+ # Build xarray.Dataset
94+ ds = xr .Dataset (
95+ data_vars = dict (
96+ xCell = (('nCells' ,), xCell_full ),
97+ yCell = (('nCells' ,), yCell_full ),
98+ zCell = (('nCells' ,), zCell_full ),
99+ xVertex = (('nVertices' ,), xVertex_full ),
100+ yVertex = (('nVertices' ,), yVertex_full ),
101+ zVertex = (('nVertices' ,), zVertex_full ),
102+ cellsOnVertex = (('nVertices' , 'vertexDegree' ), cellsOnVertex_full ),
103+ meshDensity = (('nCells' ,), meshDensity_full ),
104+ ),
105+ attrs = attrs
106+ )
107+
108+ # Write to NetCDF using write_netcdf
109+ write_netcdf (ds , output_name )
132110
133111def main ():
112+ """
113+ Convert a JIGSAW mesh file to NetCDF format for MPAS-Tools.
114+ """
134115 parser = argparse .ArgumentParser (
135116 description = __doc__ ,
136117 formatter_class = argparse .RawTextHelpFormatter )
137118 parser .add_argument (
138- "-m" ,
139- "--msh" ,
140- dest = "msh" ,
141- required = True ,
142- help = "input .msh file generated by JIGSAW." ,
143- metavar = "FILE" )
119+ '-m' , '--msh' , dest = 'msh' , required = True ,
120+ help = 'input .msh file generated by JIGSAW.' , metavar = 'FILE' )
144121 parser .add_argument (
145- "-o" ,
146- "--output" ,
147- dest = "output" ,
148- default = "grid.nc" ,
149- help = "output file name." ,
150- metavar = "FILE" )
122+ '-o' , '--output' , dest = 'output' , default = 'grid.nc' ,
123+ help = 'output file name.' , metavar = 'FILE' )
151124 parser .add_argument (
152- "-s" ,
153- " --spherical" ,
154- dest = " spherical" ,
155- action = " store_true" ,
125+ '-s' ,
126+ ' --spherical' ,
127+ dest = ' spherical' ,
128+ action = ' store_true' ,
156129 default = False ,
157- help = " Determines if the input/output should be spherical or not." )
130+ help = ' Determines if the input/output should be spherical or not.' )
158131 parser .add_argument (
159- "-r" ,
160- "--sphere_radius" ,
161- dest = "sphere_radius" ,
162- type = float ,
163- help = "The radius of the sphere in meters" )
132+ '-r' ,
133+ '--sphere_radius' ,
134+ dest = 'sphere_radius' , type = float ,
135+ help = 'The radius of the sphere in meters' )
164136
165137 args = parser .parse_args ()
166-
167138 jigsaw_to_netcdf (args .msh , args .output , args .spherical , args .sphere_radius )
0 commit comments