12 from mpi4py
import MPI
22 yac_weight_file_on_existing
28from argparse
import ArgumentParser
30from pathlib
import Path
37 case f
if m := re.match(
r"^healpix(\d{1,2})$", f):
38 return ux.Grid.from_healpix(zoom=int(m[1]))
39 case f
if m := re.match(
r"^reg((?P<lon_from>-?\d+\.?\d*):(?P<lon_to>-?\d+\.?\d*):)?(?P<lon_n>\d+),((?P<lat_from>-?\d+\.?\d*):(?P<lat_to>-?\d+\.?\d*):)?(?P<lat_n>\d+)$", f):
40 return ux.Grid.from_structured(lon=np.linspace(start=float(m[
"lon_from"]
or 0),
41 stop=float(m[
"lon_to"]
or 360),
43 lat=np.linspace(start=float(m[
"lat_from"]
or -90),
44 stop=float(m[
"lat_to"]
or 90),
48 if gridname
is not None:
49 return ux.open_multigrid(filename, gridnames=[gridname])[gridname]
50 return ux.open_grid(filename)
54 if loc == yac_location.YAC_LOC_CELL:
55 lon, lat = np.deg2rad([uxgrid.face_lon, uxgrid.face_lat])
56 elif loc == yac_location.YAC_LOC_CORNER:
58 elif loc == yac_location.YAC_LOC_EDGE:
59 lon, lat = np.deg2rad([uxgrid.edge_lon, uxgrid.edge_lat])
60 return yac_grid.add_coordinates(loc, lon, lat)
66 except Exception
as e:
67 logging.debug(f
"Cannot parse interpolation as json: {e}")
71yac_location.__str__ =
lambda loc: loc.name
74parser = ArgumentParser(prog=
"yac_generate_weights.py", description=
"Generate YAC weights files")
75parser.add_argument(
"src_grid_path", type=str,
77 "Path to the source grid file, or a shorthand: "
78 "'healpix<N>' for a HEALPix grid at zoom level N (e.g. 'healpix5'), "
79 "or 'reg[lon_from:lon_to:]<lon_n>,[lat_from:lat_to:]<lat_n>' for a "
80 "regular structured grid (e.g. 'reg360,180' or 'reg-180:180:360,-90:90:181')."
85 type=
lambda loc: yac_location[loc],
87 yac_location.YAC_LOC_CELL,
88 yac_location.YAC_LOC_CORNER,
89 yac_location.YAC_LOC_EDGE,
91 default=yac_location.YAC_LOC_CELL,
93parser.add_argument(
"--src-mask-var", type=str, help=
"Variable name of the mask")
95 "--src-mask-filename", type=str, help=
"Filename to read the mask from."
98 "--src-mask-valid-values",
102 help=
"Valid values for the mask",
104parser.add_argument(
"--src-grid-name", type=str, default=
None)
106parser.add_argument(
"tgt_grid_path", type=str,
108 "Path to the target grid file, or a shorthand: "
109 "'healpix<N>' for a HEALPix grid at zoom level N (e.g. 'healpix5'), "
110 "or 'reg[lon_from:lon_to:]<lon_n>,[lat_from:lat_to:]<lat_n>' for a "
111 "regular structured grid (e.g. 'reg360,180' or 'reg-180:180:360,-90:90:181')."
116 type=
lambda loc: yac_location[loc],
118 yac_location.YAC_LOC_CELL,
119 yac_location.YAC_LOC_CORNER,
120 yac_location.YAC_LOC_EDGE,
122 default=yac_location.YAC_LOC_CELL,
124parser.add_argument(
"--tgt-mask-var", type=str, help=
"Variable name of the mask")
126 "--tgt-mask-filename", type=str, help=
"Filename to read the mask from."
129 "--tgt-mask-valid-values",
133 help=
"Valid values for the mask",
135parser.add_argument(
"--tgt-grid-name",
"--tgt_grid_name", type=str, default=
None)
138 "interpolation_stack",
139 type=parse_interpolation,
141 help=
"format: method_name[,JSON mapping]",
143parser.add_argument(
"--output-file", type=Path, default=
"weights.nc")
144parser.add_argument(
"--output-grids-file",
147 help=
"Write the source and target grids to this file for debugging purposes.")
150 default=logging.INFO,
151 type=
lambda x: getattr(logging, x),
152 help=
"Configure the logging level.",
155args = parser.parse_args()
157logging.basicConfig(level=args.log_level)
159logging.info(
"Reading src grid")
160src_uxgrid = load_grid(args.src_grid_path, args.src_grid_name)
161src_grid = BasicGrid.from_uxgrid(args.src_grid_name
or "source_grid", src_uxgrid)
162src_coords =
get_coords(args.src_location, src_uxgrid, src_grid)
163if args.src_mask_var
is not None:
164 src_mask_file = args.src_mask_filename
or args.src_grid_path
165 with ux.open_dataset(args.src_grid_path, src_mask_file)
as ds:
166 m = np.isin(ds[args.src_mask_var], args.src_mask_valid_values)
167 src_mask = src_grid.add_mask(args.src_location, m)
170src_field = InterpField(src_coords, src_mask)
172logging.info(
"Reading tgt grid")
173tgt_uxgrid = load_grid(args.tgt_grid_path, args.tgt_grid_name)
174tgt_grid = BasicGrid.from_uxgrid(args.tgt_grid_name
or "target_grid", tgt_uxgrid)
175tgt_coords =
get_coords(args.tgt_location, tgt_uxgrid, tgt_grid)
176if args.tgt_mask_var
is not None:
177 tgt_mask_file = args.tgt_mask_filename
or args.tgt_grid_path
178 with netCDF4.Dataset(tgt_mask_file)
as ds:
179 m = np.isin(ds[args.tgt_mask_var], args.tgt_mask_valid_values)
180 tgt_mask = tgt_grid.add_mask(args.tgt_location, m)
183tgt_field = InterpField(tgt_coords, tgt_mask)
185interp_stack = InterpolationStack.from_list(args.interpolation_stack)
187logging.info(f
"Writing grid file {args.output_grids_file}")
188if args.output_grids_file.exists():
189 logging.info(f
"Overwriting existing file")
190 args.output_grids_file.unlink()
191src_grid.to_file(
str(args.output_grids_file))
192tgt_grid.to_file(
str(args.output_grids_file))
194logging.info(
"Computing weights")
195weights = compute_weights(interp_stack, src_field, tgt_field)
197logging.info(
"Write weights to file")
198weights.write_to_file(
199 str(args.output_file),
200 src_grid_name=args.src_grid_name
or "source_grid",
201 tgt_grid_name=args.tgt_grid_name
or "target_grid",
202 on_existing=yac_weight_file_on_existing.YAC_WEIGHT_FILE_OVERWRITE,
load_grid(filename, gridname=None)
get_coords(loc, uxgrid, yac_grid)