YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
read_icon_grid.c
Go to the documentation of this file.
1// Copyright (c) 2024 The YAC Authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#ifdef HAVE_CONFIG_H
6#include "config.h"
7#endif
8
9#include <stdlib.h>
10#include <stdio.h>
11#include <string.h>
12#include <assert.h>
13#include <math.h>
14#include <limits.h>
15
16#include <mpi.h>
17
18#include "read_icon_grid.h"
19#include "utils_common.h"
20#include "io_utils.h"
21#include "geometry.h"
22#include "read_grid.h"
23
24#ifdef YAC_NETCDF_ENABLED
25#include <netcdf.h>
26
27static int * get_icon_cell_mask( int ncid, size_t nbr_cells );
28static void get_icon_connect(
29 int ncid, size_t nbr_cells, int ** vertex_of_cell, size_t * nv);
30
32 const char * filename, int * nbr_vertices, int * nbr_cells,
33 int ** num_vertices_per_cell, int ** cell_to_vertex,
34 double ** x_vertices, double ** y_vertices,
35 double ** x_cells, double ** y_cells, int ** global_cell_id,
36 int ** cell_mask, int ** cell_core_mask,
37 int ** global_corner_id, int ** corner_core_mask, int rank, int size) {
38
39 // read the global grid
41 filename, nbr_vertices, nbr_cells, num_vertices_per_cell, cell_to_vertex,
42 x_vertices, y_vertices, x_cells, y_cells, cell_mask);
43
44 // determine local range
45 int local_start =
46 ((unsigned long)(*nbr_cells) * (unsigned long)rank) /
47 (unsigned long)size;
48 int num_local_cells =
49 ((unsigned long)(*nbr_cells) * ((unsigned long)rank+1)) /
50 (unsigned long)size - (unsigned long)local_start;
51
52 // mask for required vertices and cells
53 int * required_vertices = xcalloc(*nbr_vertices, sizeof(*required_vertices));
54 int * required_cells = xcalloc(*nbr_cells, sizeof(*required_cells));
55
56 int offset = 0;
57 for (int i = 0; i < local_start; ++i)
58 offset += (*num_vertices_per_cell)[i];
59
60 // mark all local cells and their vertices as required
61 for (int i = local_start; i < local_start + num_local_cells; ++i) {
62
63 required_cells[i] = 2;
64 for (int j = 0; j < (*num_vertices_per_cell)[i]; ++j)
65 required_vertices[(*cell_to_vertex)[offset+j]] = 2;
66
67 offset += (*num_vertices_per_cell)[i];
68 }
69
70 // mark all halo cells as required
71 offset = 0;
72 for (int i = 0; i < *nbr_cells; ++i) {
73
74 if (!required_cells[i]) {
75
76 for (int j = 0; j < (*num_vertices_per_cell)[i]; ++j) {
77
78 if (required_vertices[(*cell_to_vertex)[offset+j]]) {
79
80 required_cells[i] = 1;
81 break;
82 }
83 }
84
85 }
86
87 offset += (*num_vertices_per_cell)[i];
88 }
89
90 // mark all halo vertices as required
91 offset = 0;
92 for (int i = 0; i < *nbr_cells; ++i) {
93
94 if (required_cells[i] == 1) {
95
96 for (int j = 0; j < (*num_vertices_per_cell)[i]; ++j) {
97
98 if (!required_vertices[(*cell_to_vertex)[offset+j]]) {
99
100 required_vertices[(*cell_to_vertex)[offset+j]] = 1;
101 }
102 }
103 }
104
105 offset += (*num_vertices_per_cell)[i];
106 }
107
108 // count the number of cells and vertices
109 int part_num_vertices = 0;
110 int part_num_cells = 0;
111 for (int i = 0; i < *nbr_vertices; ++i)
112 if (required_vertices[i])
113 part_num_vertices++;
114 for (int i = 0; i < *nbr_cells; ++i)
115 if(required_cells[i])
116 part_num_cells++;
117
118 *global_cell_id = xmalloc(part_num_cells * sizeof(**global_cell_id));
119 *cell_core_mask = xmalloc(part_num_cells * sizeof(**cell_core_mask));
120 *global_corner_id = xmalloc(part_num_vertices * sizeof(**global_corner_id));
121 *corner_core_mask = xmalloc(part_num_vertices * sizeof(**corner_core_mask));
122
123 // generate final vertex data
124 part_num_vertices = 0;
125 int * global_to_local_vertex =
126 xmalloc(*nbr_vertices * sizeof(*global_to_local_vertex));
127 for (int i = 0; i < *nbr_vertices; ++i) {
128
129 if (required_vertices[i]) {
130
131 (*global_corner_id)[part_num_vertices] = i;
132 (*corner_core_mask)[part_num_vertices] = required_vertices[i] == 2;
133 (*x_vertices)[part_num_vertices] = (*x_vertices)[i];
134 (*y_vertices)[part_num_vertices] = (*y_vertices)[i];
135 global_to_local_vertex[i] = part_num_vertices;
136 part_num_vertices++;
137 }
138 }
139
140 *x_vertices = xrealloc(*x_vertices, part_num_vertices * sizeof(**x_vertices));
141 *y_vertices = xrealloc(*y_vertices, part_num_vertices * sizeof(**y_vertices));
142 *nbr_vertices = part_num_vertices;
143 free(required_vertices);
144
145 // generate final cell data
146 int num_cell_vertex_dependencies = 0;
147 part_num_cells = 0;
148 offset = 0;
149 for (int i = 0; i < *nbr_cells; ++i) {
150
151 if (required_cells[i]) {
152
153 (*global_cell_id)[part_num_cells] = i;
154 (*cell_core_mask)[part_num_cells] = required_cells[i] == 2;
155 (*x_cells)[part_num_cells] = (*x_cells)[i];
156 (*y_cells)[part_num_cells] = (*y_cells)[i];
157 (*cell_mask)[part_num_cells] = (*cell_mask)[i];
158
159 for (int j = 0; j < (*num_vertices_per_cell)[i]; ++j)
160 (*cell_to_vertex)[num_cell_vertex_dependencies++] =
161 global_to_local_vertex[(*cell_to_vertex)[offset+j]];
162
163 (*num_vertices_per_cell)[part_num_cells] = (*num_vertices_per_cell)[i];
164
165 part_num_cells++;
166 }
167
168 offset += (*num_vertices_per_cell)[i];
169 }
170
171 *x_cells = xrealloc(*x_cells, part_num_cells * sizeof(**x_cells));
172 *y_cells = xrealloc(*y_cells, part_num_cells * sizeof(**y_cells));
173 *cell_mask = xrealloc(*cell_mask, part_num_cells * sizeof(**cell_mask));
174
175 *num_vertices_per_cell = xrealloc(*num_vertices_per_cell, part_num_cells *
176 sizeof(**num_vertices_per_cell));
177 *cell_to_vertex = xrealloc(*cell_to_vertex, num_cell_vertex_dependencies *
178 sizeof(**cell_to_vertex));
179 *nbr_cells = part_num_cells;
180 free(required_cells);
181 free(global_to_local_vertex);
182}
183
184void yac_read_icon_grid_information(const char * filename, int * nbr_vertices,
185 int * nbr_cells, int ** num_vertices_per_cell,
186 int ** cell_to_vertex, double ** x_vertices,
187 double ** y_vertices, double ** x_cells,
188 double ** y_cells, int ** cell_mask) {
189
190 /* Open file */
191 int ncid;
192 yac_nc_open(filename, NC_NOWRITE, &ncid);
193
194 /* Get vertex longitudes and latitudes of cells */
195 size_t nbr_vertices_;
197 ncid, "vlon", "vlat", x_vertices, y_vertices, &nbr_vertices_);
198 *nbr_vertices = (int)nbr_vertices_;
199
200 /* Get cell center longitudes and latitudes of cells */
201 size_t nbr_cells_;
202 yac_read_coords(ncid, "clon", "clat", x_cells, y_cells, &nbr_cells_);
203 *nbr_cells = (int)nbr_cells_;
204
205 /* Get mask of cells */
206 *cell_mask = get_icon_cell_mask ( ncid, *nbr_cells );
207
208 /* Get relations between vertices and cells */
209 int * vertex_of_cell;
210 size_t nv;
211 get_icon_connect(ncid, *nbr_cells, &vertex_of_cell, &nv);
212
213 /* Close file */
214 YAC_HANDLE_ERROR(nc_close(ncid));
215
216 //-------------------------------------------------------------------------//
217
218 *num_vertices_per_cell = xmalloc(*nbr_cells * sizeof(**num_vertices_per_cell));
219 for (int i = 0; i < *nbr_cells; (*num_vertices_per_cell)[i++] = (int)nv);
220
221 *cell_to_vertex = xmalloc(*nbr_cells * nv * sizeof(**cell_to_vertex));
222
223 // Unfortunately the data is only available in Fortran order
224 for (int i = 0; i < *nbr_cells; ++i) {
225
226 for (size_t j = 0; j < nv; ++j)
227 (*cell_to_vertex)[nv * i + j] =
228 vertex_of_cell[i + j * (*nbr_cells)] - 1;
229 }
230
231 free(vertex_of_cell);
232}
233
234// taken from scales-ppm library
235// https://www.dkrz.de/redmine/projects/scales-ppm
236static inline int
237partition_idx_from_element_idx(unsigned element_idx, unsigned num_elements,
238 int num_partitions) {
239
240 return (int)((((unsigned long)element_idx) * ((unsigned long)num_partitions) +
241 (unsigned long)num_partitions - 1) /
242 ((unsigned long)num_elements));
243}
244
245static void convert_to_rad(int ncid, int varid, double * array, size_t count) {
246
247 if (yac_check_coord_units(ncid, varid))
248 for (size_t i = 0; i < count; ++i) array[i] *= YAC_RAD;
249}
250
252 const char * filename, MPI_Comm comm, int * nbr_vertices, int * nbr_cells,
253 int ** num_vertices_per_cell, int ** cell_to_vertex, int ** global_cell_ids,
254 int ** cell_owner, int ** global_vertex_ids, int ** vertex_owner,
255 double ** x_vertices, double ** y_vertices,
256 double ** x_cells, double ** y_cells, int ** cell_msk) {
257
259 ((x_cells == NULL) && (y_cells == NULL)) ||
260 ((x_cells != NULL) && (y_cells != NULL)),
261 "arguments x_cells and y_cells have to be either both NULL or "
262 "both different from NULL");
263
264 const int with_cell_coords = x_cells != NULL;
265 const int with_cell_mask = cell_msk != NULL;
266
267 int comm_rank, comm_size;
268
269 MPI_Comm_rank(comm, &comm_rank);
270 MPI_Comm_size(comm, &comm_size);
271
272 int local_is_io, * io_ranks, num_io_ranks;
273 yac_get_io_ranks(comm, &local_is_io, &io_ranks, &num_io_ranks);
274
275 size_t ncells, nvertices, nv, ne;
276
277 size_t read_local_start_cell = 0;
278 size_t read_num_local_cells = 0;
279 size_t read_local_start_vertex = 0;
280 size_t read_num_local_vertices = 0;
281 double * read_cell_lon = NULL;
282 double * read_cell_lat = NULL;
283 int * read_cell_mask = NULL;
284 double * read_vertex_lon = NULL;
285 double * read_vertex_lat = NULL;
286 int * read_dist_vertex_of_cell = NULL;
287 int * read_dist_cells_of_vertex = NULL;
288
289 if (local_is_io) {
290
291 unsigned long io_proc_idx = ULONG_MAX;
292 for (int i = 0; (i < num_io_ranks) && (io_proc_idx == ULONG_MAX); ++i)
293 if (io_ranks[i] == comm_rank)
294 io_proc_idx = (unsigned long)i;
295
296 // open file
297 int ncid;
298 yac_nc_open(filename, NC_NOWRITE, &ncid);
299
300 // get number of cells and vertices
301 int dim_id;
302 yac_nc_inq_dimid(ncid, "cell", &dim_id);
303 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &ncells));
304 yac_nc_inq_dimid(ncid, "vertex", &dim_id);
305 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &nvertices));
306 yac_nc_inq_dimid(ncid, "nv", &dim_id);
307 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &nv));
308 yac_nc_inq_dimid(ncid, "ne", &dim_id);
309 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &ne));
310
311 // determine local range for cell and vertex data
312 read_local_start_cell =
313 ((unsigned long)ncells * io_proc_idx) / (unsigned long)num_io_ranks;
314 read_num_local_cells =
315 ((unsigned long)ncells * (io_proc_idx+1)) / (unsigned long)num_io_ranks -
316 (unsigned long)read_local_start_cell;
317 read_local_start_vertex =
318 ((unsigned long)nvertices * io_proc_idx) / (unsigned long)num_io_ranks;
319 read_num_local_vertices =
320 ((unsigned long)nvertices * (io_proc_idx+1)) / (unsigned long)num_io_ranks -
321 (unsigned long)read_local_start_vertex;
322
323 // read basic grid data (each process its individual part)
324 read_cell_lon =
325 with_cell_coords?
326 xmalloc(read_num_local_cells * sizeof(*read_cell_lon)):NULL;
327 read_cell_lat =
328 with_cell_coords?
329 xmalloc(read_num_local_cells * sizeof(*read_cell_lat)):NULL;
330 read_cell_mask =
331 with_cell_mask?
332 xmalloc(read_num_local_cells * sizeof(*read_cell_mask)):NULL;
333 read_vertex_lon = xmalloc(read_num_local_vertices * sizeof(*read_vertex_lon));
334 read_vertex_lat = xmalloc(read_num_local_vertices * sizeof(*read_vertex_lat));
335 read_dist_vertex_of_cell =
336 xmalloc(read_num_local_cells * nv * sizeof(*read_dist_vertex_of_cell));
337 read_dist_cells_of_vertex =
338 xmalloc(read_num_local_vertices * ne * sizeof(*read_dist_cells_of_vertex));
339 int varid;
340 if (with_cell_coords) {
341 yac_nc_inq_varid(ncid, "clon", &varid);
342 YAC_HANDLE_ERROR(nc_get_vara_double(ncid, varid, &read_local_start_cell,
343 &read_num_local_cells, read_cell_lon));
344 convert_to_rad(ncid, varid, read_cell_lon, read_num_local_cells);
345 yac_nc_inq_varid(ncid, "clat", &varid);
346 YAC_HANDLE_ERROR(nc_get_vara_double(ncid, varid, &read_local_start_cell,
347 &read_num_local_cells, read_cell_lat));
348 convert_to_rad(ncid, varid, read_cell_lat, read_num_local_cells);
349 }
350 if (with_cell_mask) {
351 yac_nc_inq_varid(ncid, "cell_sea_land_mask", &varid);
352 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, varid, &read_local_start_cell,
353 &read_num_local_cells, read_cell_mask));
354 }
355 yac_nc_inq_varid(ncid, "vlon", &varid);
356 YAC_HANDLE_ERROR(nc_get_vara_double(ncid, varid, &read_local_start_vertex,
357 &read_num_local_vertices, read_vertex_lon));
358 convert_to_rad(ncid, varid, read_vertex_lon, read_num_local_vertices);
359 yac_nc_inq_varid(ncid, "vlat", &varid);
360 YAC_HANDLE_ERROR(nc_get_vara_double(ncid, varid, &read_local_start_vertex,
361 &read_num_local_vertices, read_vertex_lat));
362 convert_to_rad(ncid, varid, read_vertex_lat, read_num_local_vertices);
363 {
364 int * buffer = xmalloc(MAX(nv*read_num_local_cells,
365 ne*read_num_local_vertices) * sizeof(*buffer));
366 {
367 size_t tmp_start[2] = {0, read_local_start_cell};
368 size_t tmp_count[2] = {nv, read_num_local_cells};
369 yac_nc_inq_varid(ncid, "vertex_of_cell", &varid);
370 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, varid, tmp_start, tmp_count, buffer));
371 for (size_t i = 0; i < read_num_local_cells; ++i)
372 for (size_t j = 0; j < nv; ++j)
373 read_dist_vertex_of_cell[i * nv + j] =
374 buffer[i + j * read_num_local_cells];
375 }
376 {
377 size_t tmp_start[2] = {0, read_local_start_vertex};
378 size_t tmp_count[2] = {ne, read_num_local_vertices};
379 yac_nc_inq_varid(ncid, "cells_of_vertex", &varid);
380 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, varid, tmp_start, tmp_count, buffer));
381 for (size_t i = 0; i < read_num_local_vertices; ++i)
382 for (size_t j = 0; j < ne; ++j)
383 read_dist_cells_of_vertex[i * ne + j] =
384 buffer[i + j * read_num_local_vertices];
385 }
386 free(buffer);
387
388 // adjust for c indices
389 for (size_t i = 0; i < read_num_local_cells * nv; ++i)
390 if (read_dist_vertex_of_cell[i] > 0) read_dist_vertex_of_cell[i]--;
391 for (size_t i = 0; i < read_num_local_vertices * ne; ++i)
392 read_dist_cells_of_vertex[i]--;
393 }
394
395 YAC_HANDLE_ERROR(nc_close(ncid));
396 } else {
397 read_cell_lon =
398 with_cell_coords?xmalloc(1 * sizeof(*read_cell_lon)):NULL;
399 read_cell_lat =
400 with_cell_coords?xmalloc(1 * sizeof(*read_cell_lat)):NULL;
401 read_cell_mask =
402 with_cell_mask?xmalloc(1 * sizeof(*read_cell_mask)):NULL;
403 read_vertex_lon = xmalloc(1 * sizeof(*read_vertex_lon));
404 read_vertex_lat = xmalloc(1 * sizeof(*read_vertex_lat));
405 read_dist_vertex_of_cell = xmalloc(1 * sizeof(*read_dist_vertex_of_cell));
406 read_dist_cells_of_vertex = xmalloc(1 * sizeof(*read_dist_cells_of_vertex));
407 }
408
409 free(io_ranks);
410
411 {
412 int tmp;
413 if (comm_rank == 0) tmp = (int)ncells;
414 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
415 ncells = (size_t)tmp;
416 if (comm_rank == 0) tmp = (int)nvertices;
417 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
418 nvertices = (size_t)tmp;
419 if (comm_rank == 0) tmp = (int)nv;
420 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
421 nv = (size_t)tmp;
422 if (comm_rank == 0) tmp = (int)ne;
423 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
424 ne = (size_t)tmp;
425 }
426
427 // determine local range for cell and vertex data
428 size_t local_start_cell =
429 ((unsigned long)ncells * (unsigned long)comm_rank) /
430 (unsigned long)comm_size;
431 size_t num_local_cells =
432 ((unsigned long)ncells * ((unsigned long)comm_rank+1)) /
433 (unsigned long)comm_size - (unsigned long)local_start_cell;
434 size_t local_start_vertex =
435 ((unsigned long)nvertices * (unsigned long)comm_rank) /
436 (unsigned long)comm_size;
437 size_t num_local_vertices =
438 ((unsigned long)nvertices * ((unsigned long)comm_rank+1)) /
439 (unsigned long)comm_size - (unsigned long)local_start_vertex;
440
441 // redistribute basic cell data (from io decomposition)
442 double * cell_lon =
443 with_cell_coords?xmalloc(num_local_cells * sizeof(*cell_lon)):NULL;
444 double * cell_lat =
445 with_cell_coords?xmalloc(num_local_cells * sizeof(*cell_lat)):NULL;
446 int * cell_mask =
447 with_cell_mask?xmalloc(num_local_cells * sizeof(*cell_mask)):NULL;
448 int * dist_vertex_of_cell =
449 xmalloc(num_local_cells * nv * sizeof(*dist_vertex_of_cell));
450 {
451 int * send_count = xcalloc(comm_size, sizeof(*send_count));
452 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
453
454 for (size_t i = 0; i < read_num_local_cells; ++i)
455 send_count[
457 read_local_start_cell + i, ncells, comm_size)]++;
458
459 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
460
461 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
462 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
463 int send_accum = 0, recv_accum = 0;
464 for (int i = 0; i < comm_size; ++i) {
465 send_displ[i] = send_accum;
466 recv_displ[i] = recv_accum;
467 send_accum += send_count[i];
468 recv_accum += recv_count[i];
469 }
470
471 if (with_cell_coords) {
472 MPI_Alltoallv(read_cell_lon, send_count, send_displ, MPI_DOUBLE,
473 cell_lon, recv_count, recv_displ, MPI_DOUBLE, comm);
474 MPI_Alltoallv(read_cell_lat, send_count, send_displ, MPI_DOUBLE,
475 cell_lat, recv_count, recv_displ, MPI_DOUBLE, comm);
476 }
477 if (with_cell_mask) {
478 MPI_Alltoallv(read_cell_mask, send_count, send_displ, MPI_INT,
479 cell_mask, recv_count, recv_displ, MPI_INT, comm);
480 }
481
482 for (int i = 0; i < comm_size; ++i) {
483 send_count[i] *= nv;
484 send_displ[i] *= nv;
485 recv_count[i] *= nv;
486 recv_displ[i] *= nv;
487 }
488
489 MPI_Alltoallv(read_dist_vertex_of_cell, send_count, send_displ, MPI_INT,
490 dist_vertex_of_cell, recv_count, recv_displ, MPI_INT, comm);
491
492 free(recv_displ);
493 free(send_displ);
494 free(recv_count);
495 free(send_count);
496 free(read_cell_lon);
497 free(read_cell_lat);
498 free(read_cell_mask);
499 free(read_dist_vertex_of_cell);
500 }
501
502 // redistribute basic vertex data (from io decomposition)
503 double * vertex_lon = xmalloc(num_local_vertices * sizeof(*vertex_lon));
504 double * vertex_lat = xmalloc(num_local_vertices * sizeof(*vertex_lat));
505 int * dist_cells_of_vertex =
506 xmalloc(num_local_vertices * ne * sizeof(*dist_cells_of_vertex));
507 {
508 int * send_count = xcalloc(comm_size, sizeof(*send_count));
509 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
510
511 for (size_t i = 0; i < read_num_local_vertices; ++i)
512 send_count[
514 read_local_start_vertex + i, nvertices, comm_size)]++;
515
516 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
517
518 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
519 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
520 int send_accum = 0, recv_accum = 0;
521 for (int i = 0; i < comm_size; ++i) {
522 send_displ[i] = send_accum;
523 recv_displ[i] = recv_accum;
524 send_accum += send_count[i];
525 recv_accum += recv_count[i];
526 }
527
528 MPI_Alltoallv(read_vertex_lon, send_count, send_displ, MPI_DOUBLE,
529 vertex_lon, recv_count, recv_displ, MPI_DOUBLE, comm);
530 MPI_Alltoallv(read_vertex_lat, send_count, send_displ, MPI_DOUBLE,
531 vertex_lat, recv_count, recv_displ, MPI_DOUBLE, comm);
532
533 for (int i = 0; i < comm_size; ++i) {
534 send_count[i] *= ne;
535 send_displ[i] *= ne;
536 recv_count[i] *= ne;
537 recv_displ[i] *= ne;
538 }
539
540 MPI_Alltoallv(read_dist_cells_of_vertex, send_count, send_displ, MPI_INT,
541 dist_cells_of_vertex, recv_count, recv_displ, MPI_INT, comm);
542
543 free(recv_displ);
544 free(send_displ);
545 free(recv_count);
546 free(send_count);
547 free(read_vertex_lon);
548 free(read_vertex_lat);
549 free(read_dist_cells_of_vertex);
550 }
551
552 // determine required vertices for core cells
553 size_t num_core_vertices = num_local_cells * nv;
554 int * core_vertices = xmalloc(num_core_vertices * sizeof(*core_vertices));
555 {
556 memcpy(core_vertices, dist_vertex_of_cell,
557 num_core_vertices * sizeof(*core_vertices));
558 yac_quicksort_index(core_vertices, num_core_vertices, NULL);
559 yac_remove_duplicates_int(core_vertices, &num_core_vertices);
560 core_vertices =
561 xrealloc(core_vertices, num_core_vertices * sizeof(*core_vertices));
562 }
563
564 // get cells_of_vertex for core vertices and compute dist_vertex_owner
565 int * cells_of_vertex_core =
566 xmalloc(num_core_vertices * ne * sizeof(*cells_of_vertex_core));
567 int * dist_vertex_owner =
568 xmalloc(num_local_vertices * sizeof(*dist_vertex_owner));
569 {
570 int * send_count = xcalloc(comm_size, sizeof(*send_count));
571 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
572
573 for (size_t i = 0; i < num_core_vertices; ++i)
574 send_count[((unsigned long)(core_vertices[i]) *
575 (unsigned long)comm_size + (unsigned long)comm_size - 1) /
576 (unsigned long)nvertices]++;
577
578 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
579
580 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
581 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
582 int send_accum = 0, recv_accum = 0;
583 for (int i = 0; i < comm_size; ++i) {
584 send_displ[i] = send_accum;
585 recv_displ[i] = recv_accum;
586 send_accum += send_count[i];
587 recv_accum += recv_count[i];
588 }
589
590 int num_core_vertices_remote = 0;
591 for (int i = 0; i < comm_size; ++i)
592 num_core_vertices_remote += recv_count[i];
593
594 int * remote_vertex_buffer =
595 xmalloc(num_core_vertices_remote * sizeof(*remote_vertex_buffer));
596
597 MPI_Alltoallv(core_vertices, send_count, send_displ, MPI_INT,
598 remote_vertex_buffer, recv_count, recv_displ, MPI_INT, comm);
599
600 for (size_t i = 0; i < num_local_vertices; ++i) dist_vertex_owner[i] = -1;
601
602 for (int i = 0, j = 0; i < comm_size; ++i)
603 for (int k = 0; k < recv_count[i]; ++k, ++j)
604 dist_vertex_owner[remote_vertex_buffer[j] - local_start_vertex] = i;
605
606 int * send_cell_of_vertex =
607 xmalloc(num_core_vertices_remote * ne * sizeof(*send_cell_of_vertex));
608
609 for (int i = 0, l = 0, m = 0; i < comm_size; ++i) {
610 for (int j = 0; j < recv_count[i]; ++j, ++l) {
611 int idx = remote_vertex_buffer[l] - local_start_vertex;
612 for (size_t k = 0; k < ne; ++k, ++m)
613 send_cell_of_vertex[m] = dist_cells_of_vertex[idx * ne + k];
614 }
615 }
616 free(dist_cells_of_vertex);
617
618 for (int i = 0; i < comm_size; ++i) {
619 send_count[i] *= ne;
620 send_displ[i] *= ne;
621 recv_count[i] *= ne;
622 recv_displ[i] *= ne;
623 }
624
625 MPI_Alltoallv(send_cell_of_vertex, recv_count, recv_displ, MPI_INT,
626 cells_of_vertex_core, send_count, send_displ, MPI_INT, comm);
627
628 free(send_cell_of_vertex);
629 free(remote_vertex_buffer);
630 free(recv_displ);
631 free(send_displ);
632 free(recv_count);
633 free(send_count);
634 }
635
636 // determine halo cells
637 int * halo_cells;
638 size_t num_halo_cells = 0;
639 {
640 int * tmp_cells = cells_of_vertex_core;
641 size_t num_tmp_cells = num_core_vertices * ne;
642
643 yac_quicksort_index(tmp_cells, num_tmp_cells, NULL);
644 yac_remove_duplicates_int(tmp_cells, &num_tmp_cells);
645
646 if ((num_tmp_cells > 0) && (tmp_cells[0] == -1)) {
647 num_tmp_cells--;
648 tmp_cells++;
649 }
650
651 halo_cells = xmalloc((num_tmp_cells - num_local_cells) * sizeof(*halo_cells));
652
653 size_t i = 0;
654 for (; i < num_tmp_cells && tmp_cells[i] < (int)local_start_cell; ++i)
655 halo_cells[num_halo_cells++] = tmp_cells[i];
656 i += num_local_cells;
657 for (; i < num_tmp_cells; ++i) halo_cells[num_halo_cells++] = tmp_cells[i];
658
659 assert(num_halo_cells == num_tmp_cells - num_local_cells);
660
661 free(cells_of_vertex_core);
662 }
663
664 // determine all vertices and get coordinates of halo cells
665 size_t num_all_local_vertices = num_halo_cells * nv + num_core_vertices;
666 int * all_cell_to_vertex;
667 int * all_local_vertices = xrealloc(core_vertices, num_all_local_vertices *
668 sizeof(*all_local_vertices));
669 if (with_cell_coords) {
670 cell_lon = xrealloc(cell_lon, (num_local_cells + num_halo_cells) *
671 sizeof(*cell_lon));
672 cell_lat = xrealloc(cell_lat, (num_local_cells + num_halo_cells) *
673 sizeof(*cell_lat));
674 }
675 if (with_cell_mask) {
676 cell_mask = xrealloc(cell_mask, (num_local_cells + num_halo_cells) *
677 sizeof(*cell_mask));
678 }
679 {
680 int * send_count = xcalloc(comm_size, sizeof(*send_count));
681 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
682
683 for (size_t i = 0; i < num_halo_cells; ++i)
684 send_count[((unsigned long)(halo_cells[i]) *
685 (unsigned long)comm_size + (unsigned long)comm_size - 1) /
686 (unsigned long)ncells]++;
687
688 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
689
690 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
691 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
692 int send_accum = 0, recv_accum = 0;
693 for (int i = 0; i < comm_size; ++i) {
694 send_displ[i] = send_accum;
695 recv_displ[i] = recv_accum;
696 send_accum += send_count[i];
697 recv_accum += recv_count[i];
698 }
699
700 int num_halo_cells_remote = 0;
701 for (int i = 0; i < comm_size; ++i)
702 num_halo_cells_remote += recv_count[i];
703
704 int * remote_halo_cell_buffer =
705 xmalloc(num_halo_cells_remote * sizeof(*remote_halo_cell_buffer));
706
707 MPI_Alltoallv(halo_cells, send_count, send_displ, MPI_INT,
708 remote_halo_cell_buffer, recv_count, recv_displ, MPI_INT,
709 comm);
710
711 int * send_halo_cell_vertices =
712 xmalloc(num_halo_cells_remote * nv * sizeof(*send_halo_cell_vertices));
713 double * send_cell_lon =
714 with_cell_coords?
715 xmalloc(num_halo_cells_remote * sizeof(*send_cell_lon)):NULL;
716 double * send_cell_lat =
717 with_cell_coords?
718 xmalloc(num_halo_cells_remote * sizeof(*send_cell_lat)):NULL;
719 int * send_cell_mask =
720 with_cell_mask?
721 xmalloc(num_halo_cells_remote * sizeof(*send_cell_mask)):NULL;
722
723 for (int i = 0, l = 0, m = 0; i < comm_size; ++i) {
724 for (int j = 0; j < recv_count[i]; ++j, ++l) {
725 int idx = remote_halo_cell_buffer[l] - local_start_cell;
726 for (size_t k = 0; k < nv; ++k, ++m)
727 send_halo_cell_vertices[m] = dist_vertex_of_cell[idx * nv + k];
728 }
729 }
730 if (with_cell_coords) {
731 for (int i = 0, l = 0; i < comm_size; ++i) {
732 for (int j = 0; j < recv_count[i]; ++j, ++l) {
733 int idx = remote_halo_cell_buffer[l] - local_start_cell;
734 send_cell_lon[l] = cell_lon[idx];
735 send_cell_lat[l] = cell_lat[idx];
736 }
737 }
738 }
739 if (with_cell_mask) {
740 for (int i = 0, l = 0; i < comm_size; ++i) {
741 for (int j = 0; j < recv_count[i]; ++j, ++l) {
742 int idx = remote_halo_cell_buffer[l] - local_start_cell;
743 send_cell_mask[l] = cell_mask[idx];
744 }
745 }
746 }
747
748 if (with_cell_coords) {
749 MPI_Alltoallv(send_cell_lon, recv_count, recv_displ, MPI_DOUBLE,
750 cell_lon + num_local_cells, send_count, send_displ,
751 MPI_DOUBLE, comm);
752 MPI_Alltoallv(send_cell_lat, recv_count, recv_displ, MPI_DOUBLE,
753 cell_lat + num_local_cells, send_count, send_displ,
754 MPI_DOUBLE, comm);
755 }
756 if (with_cell_mask) {
757 MPI_Alltoallv(send_cell_mask, recv_count, recv_displ, MPI_INT,
758 cell_mask + num_local_cells, send_count, send_displ,
759 MPI_INT, comm);
760 }
761
762 for (int i = 0; i < comm_size; ++i) {
763 send_count[i] *= nv;
764 send_displ[i] *= nv;
765 recv_count[i] *= nv;
766 recv_displ[i] *= nv;
767 }
768
769 all_cell_to_vertex =
770 xrealloc(dist_vertex_of_cell, (num_local_cells + num_halo_cells) * nv *
771 sizeof(*all_cell_to_vertex));
772
773 MPI_Alltoallv(send_halo_cell_vertices, recv_count, recv_displ, MPI_INT,
774 all_cell_to_vertex + num_local_cells * nv, send_count,
775 send_displ, MPI_INT, comm);
776
777 memcpy(all_local_vertices + num_core_vertices,
778 all_cell_to_vertex + num_local_cells * nv,
779 num_halo_cells * nv * sizeof(*all_local_vertices));
780
781 free(send_cell_mask);
782 free(send_cell_lat);
783 free(send_cell_lon);
784 free(send_halo_cell_vertices);
785 free(remote_halo_cell_buffer);
786 free(recv_displ);
787 free(send_displ);
788 free(recv_count);
789 free(send_count);
790
792 all_local_vertices, num_all_local_vertices, NULL);
793 yac_remove_duplicates_int(all_local_vertices, &num_all_local_vertices);
794 }
795
796 // determine owner and coordinates for all vertices
797 double * all_vertex_lon =
798 xmalloc(num_all_local_vertices * sizeof(*all_vertex_lon));
799 double * all_vertex_lat =
800 xmalloc(num_all_local_vertices * sizeof(*all_vertex_lat));
801 int * all_local_vertices_owner =
802 xmalloc(num_all_local_vertices * sizeof(*all_local_vertices_owner));
803 {
804 int * send_count = xcalloc(comm_size, sizeof(*send_count));
805 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
806
807 for (size_t i = 0; i < num_all_local_vertices; ++i)
808 send_count[((unsigned long)(all_local_vertices[i]) *
809 (unsigned long)comm_size + (unsigned long)comm_size - 1) /
810 (unsigned long)nvertices]++;
811
812 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
813
814 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
815 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
816 int send_accum = 0, recv_accum = 0;
817 for (int i = 0; i < comm_size; ++i) {
818 send_displ[i] = send_accum;
819 recv_displ[i] = recv_accum;
820 send_accum += send_count[i];
821 recv_accum += recv_count[i];
822 }
823
824 int num_all_local_vertices_remote = 0;
825 for (int i = 0; i < comm_size; ++i)
826 num_all_local_vertices_remote += recv_count[i];
827
828 int * remote_vertex_buffer =
829 xmalloc(num_all_local_vertices_remote * sizeof(*remote_vertex_buffer));
830
831 MPI_Alltoallv(all_local_vertices, send_count, send_displ, MPI_INT,
832 remote_vertex_buffer, recv_count, recv_displ, MPI_INT, comm);
833
834 int * send_vertex_owner = remote_vertex_buffer;
835 double * send_vertex_lon =
836 xmalloc(num_all_local_vertices_remote * sizeof(*send_vertex_lon));
837 double * send_vertex_lat =
838 xmalloc(num_all_local_vertices_remote * sizeof(*send_vertex_lat));
839
840 for (int i = 0, l = 0; i < comm_size; ++i) {
841 for (int j = 0; j < recv_count[i]; ++j, ++l) {
842 int idx = remote_vertex_buffer[l] - local_start_vertex;
843 send_vertex_owner[l] = dist_vertex_owner[idx];
844 send_vertex_lon[l] = vertex_lon[idx];
845 send_vertex_lat[l] = vertex_lat[idx];
846 }
847 }
848
849 free(dist_vertex_owner);
850 free(vertex_lon);
851 free(vertex_lat);
852
853 MPI_Alltoallv(send_vertex_owner, recv_count, recv_displ, MPI_INT,
854 all_local_vertices_owner, send_count, send_displ, MPI_INT,
855 comm);
856 MPI_Alltoallv(send_vertex_lon, recv_count, recv_displ, MPI_DOUBLE,
857 all_vertex_lon, send_count, send_displ, MPI_DOUBLE, comm);
858 MPI_Alltoallv(send_vertex_lat, recv_count, recv_displ, MPI_DOUBLE,
859 all_vertex_lat, send_count, send_displ, MPI_DOUBLE, comm);
860
861 free(send_vertex_lat);
862 free(send_vertex_lon);
863 free(send_vertex_owner);
864 free(recv_displ);
865 free(send_displ);
866 free(recv_count);
867 free(send_count);
868 }
869
870 // convert global ids within all_cell_to_vertex into local ids
871 {
872 size_t vertex_count = nv * (num_local_cells + num_halo_cells);
873 int * permutation = xmalloc(vertex_count * sizeof(*permutation));
874 for (size_t i = 0; i < vertex_count; ++i) permutation[i] = (int)i;
875
876 yac_quicksort_index(all_cell_to_vertex, vertex_count, permutation);
877
878 for (size_t i = 0, j = 0; i < vertex_count; ++i) {
879 while (all_local_vertices[j] != all_cell_to_vertex[i]) ++j;
880 all_cell_to_vertex[i] = (int)j;
881 }
882
883 yac_quicksort_index(permutation, vertex_count, all_cell_to_vertex);
884 free(permutation);
885 }
886
887 *nbr_vertices = num_all_local_vertices;
888 *nbr_cells = num_local_cells + num_halo_cells;
889
890 *num_vertices_per_cell =
891 xmalloc((num_local_cells + num_halo_cells) * sizeof(**num_vertices_per_cell));
892 for (size_t i = 0; i < num_local_cells + num_halo_cells; ++i)
893 (*num_vertices_per_cell)[i] = nv;
894
895 *cell_to_vertex = all_cell_to_vertex;
896
897 *global_cell_ids =
898 xmalloc((num_local_cells + num_halo_cells) * sizeof(**global_cell_ids));
899 for (size_t i = 0; i < num_local_cells; ++i)
900 (*global_cell_ids)[i] = local_start_cell + i;
901 memcpy(*global_cell_ids + num_local_cells, halo_cells,
902 num_halo_cells * sizeof(*halo_cells));
903 *global_vertex_ids = xrealloc(all_local_vertices, num_all_local_vertices *
904 sizeof(*all_local_vertices));
905
906 *cell_owner =
907 xmalloc((num_local_cells + num_halo_cells) * sizeof(**cell_owner));
908 for (size_t i = 0; i < num_local_cells; ++i)
909 (*cell_owner)[i] = -1;
910 for (size_t i = 0; i < num_halo_cells; ++i)
911 (*cell_owner)[num_local_cells + i] =
912 ((unsigned long)(halo_cells[i]) * (unsigned long)comm_size +
913 (unsigned long)comm_size - 1) / (unsigned long)ncells;
914 free(halo_cells);
915
916 for (size_t i = 0; i < num_all_local_vertices; ++i)
917 if (all_local_vertices_owner[i] == comm_rank)
918 all_local_vertices_owner[i] = -1;
919 *vertex_owner = all_local_vertices_owner;
920
921 *x_vertices = all_vertex_lon;
922 *y_vertices = all_vertex_lat;
923 if (with_cell_coords) {
924 *x_cells = cell_lon;
925 *y_cells = cell_lat;
926 }
927 if (with_cell_mask) *cell_msk = cell_mask;
928}
929
931 const char * filename, MPI_Fint comm, int * nbr_vertices, int * nbr_cells,
932 int ** num_vertices_per_cell, int ** cell_to_vertex, int ** global_cell_ids,
933 int ** cell_owner, int ** global_vertex_ids, int ** vertex_owner,
934 double ** x_vertices, double ** y_vertices,
935 double ** x_cells, double ** y_cells, int ** cell_msk) {
936
938 filename, MPI_Comm_f2c(comm), nbr_vertices, nbr_cells,
939 num_vertices_per_cell, cell_to_vertex, global_cell_ids,
940 cell_owner, global_vertex_ids, vertex_owner,
941 x_vertices, y_vertices, x_cells, y_cells, cell_msk);
942}
943
944static int * generate_simple_core_mask(size_t N) {
945 int * mask = xmalloc(N * sizeof(*mask));
946 for (size_t i = 0; i < N; ++i) mask[i] = 1;
947 return mask;
948}
949
950static size_t * generate_offsets(size_t N, int * counts) {
951
952 size_t * offsets = xmalloc(N * sizeof(*offsets));
953 for (size_t i = 0, accu = 0; i < N; ++i) {
954 offsets[i] = accu;
955 accu += (size_t)(counts[i]);
956 }
957 return offsets;
958}
959
961 const char * filename, MPI_Comm comm,
962 double ** x_vertices, double ** y_vertices,
963 yac_int ** cell_ids, yac_int ** vertex_ids, yac_int ** edge_ids,
964 size_t * num_cells, size_t * num_vertices, size_t * num_edges,
965 int ** num_vertices_per_cell, int ** num_cells_per_vertex,
966 size_t ** cell_to_vertex, size_t ** cell_to_edge, size_t ** vertex_to_cell,
967 size_t ** edge_to_vertex, enum yac_edge_type ** edge_type,
968 double ** x_cells, double ** y_cells, int ** cell_msk) {
969
971 ((x_cells == NULL) && (y_cells == NULL)) ||
972 ((x_cells != NULL) && (y_cells != NULL)),
973 "arguments x_cells and y_cells have to be either both NULL or "
974 "both different from NULL");
975
976 const int with_cell_coords = x_cells != NULL;
977 const int with_cell_mask = cell_msk != NULL;
978
979 int comm_rank, comm_size;
980
981 MPI_Comm_rank(comm, &comm_rank);
982 MPI_Comm_size(comm, &comm_size);
983
984 int local_is_io, * io_ranks, num_io_ranks;
985 yac_get_io_ranks(comm, &local_is_io, &io_ranks, &num_io_ranks);
986
987 size_t ncells, nvertices, nedges, nv, ne;
988
989 size_t read_local_start_cell = 0;
990 size_t read_num_local_cells = 0;
991 size_t read_local_start_vertex = 0;
992 size_t read_num_local_vertices = 0;
993 size_t read_local_start_edge = 0;
994 size_t read_num_local_edges = 0;
995 double * read_cell_lon = NULL;
996 double * read_cell_lat = NULL;
997 int * read_cell_mask = NULL;
998 double * read_vertex_lon = NULL;
999 double * read_vertex_lat = NULL;
1000 int * read_dist_vertex_of_cell = NULL;
1001 int * read_dist_edge_of_cell = NULL;
1002 int * read_dist_edge_vertices = NULL;
1003
1004 if (local_is_io) {
1005
1006 unsigned long io_proc_idx = ULONG_MAX;
1007 for (int i = 0; (i < num_io_ranks) && (io_proc_idx == ULONG_MAX); ++i)
1008 if (io_ranks[i] == comm_rank)
1009 io_proc_idx = (unsigned long)i;
1010
1011 // open file
1012 int ncid;
1013 yac_nc_open(filename, NC_NOWRITE, &ncid);
1014
1015 // get number of cells and vertices
1016 int dim_id;
1017 yac_nc_inq_dimid(ncid, "cell", &dim_id);
1018 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &ncells));
1019 yac_nc_inq_dimid(ncid, "vertex", &dim_id);
1020 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &nvertices));
1021 yac_nc_inq_dimid(ncid, "edge", &dim_id);
1022 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &nedges));
1023 yac_nc_inq_dimid(ncid, "nv", &dim_id);
1024 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &nv));
1025 yac_nc_inq_dimid(ncid, "ne", &dim_id);
1026 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dim_id, &ne));
1027
1028 // determine local range for cell and vertex data
1029 read_local_start_cell =
1030 ((unsigned long)ncells * io_proc_idx) / (unsigned long)num_io_ranks;
1031 read_num_local_cells =
1032 ((unsigned long)ncells * (io_proc_idx+1)) / (unsigned long)num_io_ranks -
1033 (unsigned long)read_local_start_cell;
1034 read_local_start_vertex =
1035 ((unsigned long)nvertices * io_proc_idx) / (unsigned long)num_io_ranks;
1036 read_num_local_vertices =
1037 ((unsigned long)nvertices * (io_proc_idx+1)) / (unsigned long)num_io_ranks -
1038 (unsigned long)read_local_start_vertex;
1039 read_local_start_edge =
1040 ((unsigned long)nedges * io_proc_idx) / (unsigned long)num_io_ranks;
1041 read_num_local_edges =
1042 ((unsigned long)nedges * (io_proc_idx+1)) / (unsigned long)num_io_ranks -
1043 (unsigned long)read_local_start_edge;
1044
1045 // read basic grid data (each process its individual part)
1046 read_vertex_lon = xmalloc(read_num_local_vertices * sizeof(*read_vertex_lon));
1047 read_vertex_lat = xmalloc(read_num_local_vertices * sizeof(*read_vertex_lat));
1048 read_cell_lon =
1049 with_cell_coords?
1050 xmalloc(read_num_local_cells * sizeof(*read_cell_lon)):NULL;
1051 read_cell_lat =
1052 with_cell_coords?
1053 xmalloc(read_num_local_cells * sizeof(*read_cell_lat)):NULL;
1054 read_cell_mask =
1055 with_cell_mask?
1056 xmalloc(read_num_local_cells * sizeof(*read_cell_mask)):NULL;
1057 read_dist_vertex_of_cell =
1058 xmalloc(read_num_local_cells * nv * sizeof(*read_dist_vertex_of_cell));
1059 read_dist_edge_of_cell =
1060 xmalloc(read_num_local_cells * nv * sizeof(*read_dist_edge_of_cell));
1061 read_dist_edge_vertices =
1062 xmalloc(read_num_local_edges * 2 * sizeof(*read_dist_edge_vertices));
1063 int varid;
1064 yac_nc_inq_varid(ncid, "vlon", &varid);
1065 YAC_HANDLE_ERROR(nc_get_vara_double(ncid, varid, &read_local_start_vertex,
1066 &read_num_local_vertices, read_vertex_lon));
1067 convert_to_rad(ncid, varid, read_vertex_lon, read_num_local_vertices);
1068 yac_nc_inq_varid(ncid, "vlat", &varid);
1069 YAC_HANDLE_ERROR(nc_get_vara_double(ncid, varid, &read_local_start_vertex,
1070 &read_num_local_vertices, read_vertex_lat));
1071 convert_to_rad(ncid, varid, read_vertex_lat, read_num_local_vertices);
1072 if (with_cell_coords) {
1073 yac_nc_inq_varid(ncid, "clon", &varid);
1075 nc_get_vara_double(
1076 ncid, varid, &read_local_start_cell,
1077 &read_num_local_cells, read_cell_lon));
1078 convert_to_rad(ncid, varid, read_cell_lon, read_num_local_cells);
1079 yac_nc_inq_varid(ncid, "clat", &varid);
1081 nc_get_vara_double(
1082 ncid, varid, &read_local_start_cell,
1083 &read_num_local_cells, read_cell_lat));
1084 convert_to_rad(ncid, varid, read_cell_lat, read_num_local_cells);
1085 }
1086 if (read_cell_mask) {
1087 yac_nc_inq_varid(ncid, "cell_sea_land_mask", &varid);
1089 nc_get_vara_int(
1090 ncid, varid, &read_local_start_cell,
1091 &read_num_local_cells, read_cell_mask));
1092 }
1093 {
1094 int * buffer =
1095 xmalloc(
1096 MAX(nv*read_num_local_cells, 2*read_num_local_edges) *
1097 sizeof(*buffer));
1098 {
1099 size_t tmp_start[2] = {0, read_local_start_cell};
1100 size_t tmp_count[2] = {nv, read_num_local_cells};
1101 yac_nc_inq_varid(ncid, "vertex_of_cell", &varid);
1102 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, varid, tmp_start, tmp_count, buffer));
1103 for (size_t i = 0; i < read_num_local_cells; ++i)
1104 for (size_t j = 0; j < nv; ++j)
1105 read_dist_vertex_of_cell[i * nv + j] =
1106 buffer[i + j * read_num_local_cells];
1107 yac_nc_inq_varid(ncid, "edge_of_cell", &varid);
1108 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, varid, tmp_start, tmp_count, buffer));
1109 for (size_t i = 0; i < read_num_local_cells; ++i)
1110 for (size_t j = 0; j < nv; ++j)
1111 read_dist_edge_of_cell[i * nv + j] =
1112 buffer[i + j * read_num_local_cells];
1113 }
1114 {
1115 size_t tmp_start[2] = {0, read_local_start_edge};
1116 size_t tmp_count[2] = {2, read_num_local_edges};
1117 yac_nc_inq_varid(ncid, "edge_vertices", &varid);
1118 YAC_HANDLE_ERROR(nc_get_vara_int(ncid, varid, tmp_start, tmp_count, buffer));
1119 for (size_t i = 0; i < read_num_local_edges; ++i)
1120 for (int j = 0; j < 2; ++j)
1121 read_dist_edge_vertices[i * 2 + j] =
1122 buffer[i + j * read_num_local_edges];
1123 }
1124 free(buffer);
1125
1126 // adjust for c indices
1127 for (size_t i = 0; i < read_num_local_cells * nv; ++i)
1128 if (read_dist_vertex_of_cell[i] > 0) read_dist_vertex_of_cell[i]--;
1129 for (size_t i = 0; i < read_num_local_cells * nv; ++i)
1130 if (read_dist_edge_of_cell[i] > 0) read_dist_edge_of_cell[i]--;
1131 for (size_t i = 0; i < read_num_local_edges * 2; ++i)
1132 if (read_dist_edge_vertices[i] > 0) read_dist_edge_vertices[i]--;
1133 }
1134
1135 YAC_HANDLE_ERROR(nc_close(ncid));
1136 } else {
1137 read_cell_lon = with_cell_coords?xmalloc(1 * sizeof(*read_cell_lon)):NULL;
1138 read_cell_lat = with_cell_coords?xmalloc(1 * sizeof(*read_cell_lat)):NULL;
1139 read_cell_mask = with_cell_mask?xmalloc(1 * sizeof(*read_cell_mask)):NULL;
1140 read_vertex_lon = xmalloc(1 * sizeof(*read_vertex_lon));
1141 read_vertex_lat = xmalloc(1 * sizeof(*read_vertex_lat));
1142 read_dist_vertex_of_cell = xmalloc(1 * sizeof(*read_dist_vertex_of_cell));
1143 read_dist_edge_of_cell = xmalloc(1 * sizeof(*read_dist_edge_of_cell));
1144 read_dist_edge_vertices = xmalloc(1 * sizeof(*read_dist_edge_vertices));
1145 }
1146
1147 free(io_ranks);
1148
1149 {
1150 int tmp;
1151 if (comm_rank == 0) tmp = (int)ncells;
1152 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
1153 ncells = (size_t)tmp;
1154 if (comm_rank == 0) tmp = (int)nvertices;
1155 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
1156 nvertices = (size_t)tmp;
1157 if (comm_rank == 0) tmp = (int)nedges;
1158 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
1159 nedges = (size_t)tmp;
1160 if (comm_rank == 0) tmp = (int)nv;
1161 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
1162 nv = (size_t)tmp;
1163 if (comm_rank == 0) tmp = (int)ne;
1164 MPI_Bcast(&tmp, 1, MPI_INT, 0, comm);
1165 ne = (size_t)tmp;
1166 }
1167
1168 // determine local range for cell and vertex data
1169 size_t local_start_cell =
1170 ((unsigned long)ncells * (unsigned long)comm_rank) /
1171 (unsigned long)comm_size;
1172 size_t num_local_cells =
1173 ((unsigned long)ncells * ((unsigned long)comm_rank+1)) /
1174 (unsigned long)comm_size - (unsigned long)local_start_cell;
1175 size_t local_start_vertex =
1176 ((unsigned long)nvertices * (unsigned long)comm_rank) /
1177 (unsigned long)comm_size;
1178 size_t num_local_vertices =
1179 ((unsigned long)nvertices * ((unsigned long)comm_rank+1)) /
1180 (unsigned long)comm_size - (unsigned long)local_start_vertex;
1181 size_t local_start_edge =
1182 ((unsigned long)nedges * (unsigned long)comm_rank) /
1183 (unsigned long)comm_size;
1184 size_t num_local_edges =
1185 ((unsigned long)nedges * ((unsigned long)comm_rank+1)) /
1186 (unsigned long)comm_size - (unsigned long)local_start_edge;
1187
1188 // redistribute basic cell data (from io decomposition)
1189 if (with_cell_coords) {
1190 *x_cells = xmalloc(num_local_cells * sizeof(**x_cells));
1191 *y_cells = xmalloc(num_local_cells * sizeof(**y_cells));
1192 }
1193 if (with_cell_mask) {
1194 *cell_msk = xmalloc(num_local_cells * sizeof(**cell_msk));
1195 }
1196 int * dist_vertex_of_cell =
1197 xmalloc(num_local_cells * nv * sizeof(*dist_vertex_of_cell));
1198 int * dist_edge_of_cell =
1199 xmalloc(num_local_cells * nv * sizeof(*dist_edge_of_cell));
1200 {
1201 int * send_count = xcalloc(comm_size, sizeof(*send_count));
1202 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
1203
1204 for (unsigned i = 0; i < read_num_local_cells; ++i)
1205 send_count[
1207 read_local_start_cell + i, ncells, comm_size)]++;
1208
1209 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
1210
1211 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
1212 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
1213 int send_accum = 0, recv_accum = 0;
1214 for (int i = 0; i < comm_size; ++i) {
1215 send_displ[i] = send_accum;
1216 recv_displ[i] = recv_accum;
1217 send_accum += send_count[i];
1218 recv_accum += recv_count[i];
1219 }
1220
1221 if (with_cell_coords) {
1222 MPI_Alltoallv(read_cell_lon, send_count, send_displ, MPI_DOUBLE,
1223 *x_cells, recv_count, recv_displ, MPI_DOUBLE, comm);
1224 MPI_Alltoallv(read_cell_lat, send_count, send_displ, MPI_DOUBLE,
1225 *y_cells, recv_count, recv_displ, MPI_DOUBLE, comm);
1226 }
1227 if (with_cell_mask) {
1228 MPI_Alltoallv(read_cell_mask, send_count, send_displ, MPI_INT,
1229 *cell_msk, recv_count, recv_displ, MPI_INT, comm);
1230 }
1231
1232 for (int i = 0; i < comm_size; ++i) {
1233 send_count[i] *= nv;
1234 send_displ[i] *= nv;
1235 recv_count[i] *= nv;
1236 recv_displ[i] *= nv;
1237 }
1238
1239 MPI_Alltoallv(read_dist_vertex_of_cell, send_count, send_displ, MPI_INT,
1240 dist_vertex_of_cell, recv_count, recv_displ, MPI_INT, comm);
1241 MPI_Alltoallv(read_dist_edge_of_cell, send_count, send_displ, MPI_INT,
1242 dist_edge_of_cell, recv_count, recv_displ, MPI_INT, comm);
1243
1244 free(recv_displ);
1245 free(send_displ);
1246 free(recv_count);
1247 free(send_count);
1248 free(read_dist_vertex_of_cell);
1249 free(read_dist_edge_of_cell);
1250 free(read_cell_mask);
1251 free(read_cell_lat);
1252 free(read_cell_lon);
1253 }
1254
1255 // redistribute basic vertex data (from io decomposition)
1256 double * vertex_lon = xmalloc(num_local_vertices * sizeof(*vertex_lon));
1257 double * vertex_lat = xmalloc(num_local_vertices * sizeof(*vertex_lat));
1258 {
1259 int * send_count = xcalloc(comm_size, sizeof(*send_count));
1260 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
1261
1262 for (unsigned i = 0; i < read_num_local_vertices; ++i)
1263 send_count[
1265 read_local_start_vertex + i, nvertices, comm_size)]++;
1266
1267 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
1268
1269 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
1270 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
1271 int send_accum = 0, recv_accum = 0;
1272 for (int i = 0; i < comm_size; ++i) {
1273 send_displ[i] = send_accum;
1274 recv_displ[i] = recv_accum;
1275 send_accum += send_count[i];
1276 recv_accum += recv_count[i];
1277 }
1278
1279 MPI_Alltoallv(read_vertex_lon, send_count, send_displ, MPI_DOUBLE,
1280 vertex_lon, recv_count, recv_displ, MPI_DOUBLE, comm);
1281 MPI_Alltoallv(read_vertex_lat, send_count, send_displ, MPI_DOUBLE,
1282 vertex_lat, recv_count, recv_displ, MPI_DOUBLE, comm);
1283
1284 free(recv_displ);
1285 free(send_displ);
1286 free(recv_count);
1287 free(send_count);
1288 free(read_vertex_lon);
1289 free(read_vertex_lat);
1290 }
1291
1292 // redistribute basic edge data (from io decomposition)
1293 int * dist_edge_vertices =
1294 xmalloc(num_local_edges * 2 * sizeof(*dist_edge_vertices));
1295 {
1296 int * send_count = xcalloc(comm_size, sizeof(*send_count));
1297 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
1298
1299 for (unsigned i = 0; i < read_num_local_edges; ++i)
1300 send_count[
1302 read_local_start_edge + i, nedges, comm_size)] += 2;
1303
1304 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
1305
1306 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
1307 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
1308 int send_accum = 0, recv_accum = 0;
1309 for (int i = 0; i < comm_size; ++i) {
1310 send_displ[i] = send_accum;
1311 recv_displ[i] = recv_accum;
1312 send_accum += send_count[i];
1313 recv_accum += recv_count[i];
1314 }
1315
1316 MPI_Alltoallv(read_dist_edge_vertices, send_count, send_displ, MPI_INT,
1317 dist_edge_vertices, recv_count, recv_displ, MPI_INT, comm);
1318
1319 free(recv_displ);
1320 free(send_displ);
1321 free(recv_count);
1322 free(send_count);
1323 free(read_dist_edge_vertices);
1324 }
1325
1326 // determine required vertices for core cells
1327 // in additional compute num_cells_per_vertex, vertex_to_cell,
1328 // and cell_to_vertex
1329 size_t num_core_vertices;
1330 {
1331 size_t N = num_local_cells * nv;
1332 *vertex_ids = xmalloc(N * sizeof(**vertex_ids));
1333 *num_cells_per_vertex = xmalloc(N * sizeof(**num_cells_per_vertex));
1334 *vertex_to_cell = xmalloc(N * sizeof(**vertex_to_cell));
1335 *cell_to_vertex = xmalloc(N * sizeof(**cell_to_vertex));
1336 for (size_t i = 0; i < N; ++i)
1337 (*vertex_ids)[i] = (yac_int)dist_vertex_of_cell[i];
1338 size_t * permutation = *vertex_to_cell;
1339 for (size_t i = 0; i < N; ++i) permutation[i] = i;
1340 yac_quicksort_index_yac_int_size_t(*vertex_ids, N, permutation);
1341 // remove duplicated core vertices and count number of cells per vertex
1342 yac_int prev_vertex_id = YAC_INT_MAX;
1343 num_core_vertices = 0;
1344 for (size_t i = 0; i < N; ++i) {
1345 yac_int curr_vertex_id = (*vertex_ids)[i];
1346 if (prev_vertex_id == curr_vertex_id) {
1347 (*num_cells_per_vertex)[num_core_vertices-1]++;
1348 } else {
1349 (*num_cells_per_vertex)[num_core_vertices] = 1;
1350 (*vertex_ids)[num_core_vertices] = (prev_vertex_id = curr_vertex_id);
1351 ++num_core_vertices;
1352 }
1353 (*cell_to_vertex)[permutation[i]] = num_core_vertices-1;
1354 permutation[i] /= nv;
1355 }
1356 *vertex_ids =
1357 xrealloc(*vertex_ids, num_core_vertices * sizeof(**vertex_ids));
1358 *num_cells_per_vertex =
1359 xrealloc(*num_cells_per_vertex,
1360 num_core_vertices * sizeof(**num_cells_per_vertex));
1361 free(dist_vertex_of_cell);
1362 }
1363
1364 // determine required edges for core cells
1365 // in additional compute edge_to_cell and cell_to_edge
1366 size_t num_core_edges;
1367 {
1368 size_t N = num_local_cells * nv;
1369 *edge_ids = xmalloc(N * sizeof(**edge_ids));
1370 size_t * permutation = xmalloc(N * sizeof(*permutation));
1371 *cell_to_edge = xmalloc(N * sizeof(**cell_to_edge));
1372 for (size_t i = 0; i < N; ++i)
1373 (*edge_ids)[i] = (yac_int)dist_edge_of_cell[i];
1374 for (size_t i = 0; i < N; ++i) permutation[i] = i;
1375 yac_quicksort_index_yac_int_size_t(*edge_ids, N, permutation);
1376 // remove duplicated core edges and count number of cells per edge
1377 yac_int prev_edge_id = YAC_INT_MAX;
1378 num_core_edges = 0;
1379 for (size_t i = 0; i < N; ++i) {
1380 yac_int curr_edge_id = (*edge_ids)[i];
1381 if (prev_edge_id != curr_edge_id)
1382 (*edge_ids)[num_core_edges++] = (prev_edge_id = curr_edge_id);
1383 (*cell_to_edge)[permutation[i]] = num_core_edges-1;
1384 permutation[i] /= nv;
1385 }
1386 free(permutation);
1387 *edge_ids =
1388 xrealloc(*edge_ids, num_core_edges * sizeof(**edge_ids));
1389 free(dist_edge_of_cell);
1390 }
1391
1392 // generate vertex coordinate data
1393 {
1394 *x_vertices = xmalloc(num_core_vertices * sizeof(**x_vertices));
1395 *y_vertices = xmalloc(num_core_vertices * sizeof(**y_vertices));
1396 int * send_count = xcalloc(comm_size, sizeof(*send_count));
1397 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
1398
1399 for (size_t i = 0; i < num_core_vertices; ++i)
1400 send_count[((unsigned long)((*vertex_ids)[i]) *
1401 (unsigned long)comm_size + (unsigned long)comm_size - 1) /
1402 (unsigned long)nvertices]++;
1403
1404 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
1405
1406 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
1407 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
1408 int send_accum = 0, recv_accum = 0;
1409 for (int i = 0; i < comm_size; ++i) {
1410 send_displ[i] = send_accum;
1411 recv_displ[i] = recv_accum;
1412 send_accum += send_count[i];
1413 recv_accum += recv_count[i];
1414 }
1415
1416 int num_all_local_vertices_remote = 0;
1417 for (int i = 0; i < comm_size; ++i)
1418 num_all_local_vertices_remote += recv_count[i];
1419
1420 yac_int * remote_vertex_buffer =
1421 xmalloc(num_all_local_vertices_remote * sizeof(*remote_vertex_buffer));
1422
1423 MPI_Alltoallv(
1424 *vertex_ids, send_count, send_displ, yac_int_dt,
1425 remote_vertex_buffer, recv_count, recv_displ, yac_int_dt, comm);
1426
1427 double * send_vertex_lon =
1428 xmalloc(num_all_local_vertices_remote * sizeof(*send_vertex_lon));
1429 double * send_vertex_lat =
1430 xmalloc(num_all_local_vertices_remote * sizeof(*send_vertex_lat));
1431
1432 for (int i = 0, l = 0; i < comm_size; ++i) {
1433 for (int j = 0; j < recv_count[i]; ++j, ++l) {
1434 size_t idx = (size_t)(remote_vertex_buffer[l]) - local_start_vertex;
1435 send_vertex_lon[l] = vertex_lon[idx];
1436 send_vertex_lat[l] = vertex_lat[idx];
1437 }
1438 }
1439
1440 free(remote_vertex_buffer);
1441 free(vertex_lon);
1442 free(vertex_lat);
1443
1444 MPI_Alltoallv(send_vertex_lon, recv_count, recv_displ, MPI_DOUBLE,
1445 *x_vertices, send_count, send_displ, MPI_DOUBLE, comm);
1446 MPI_Alltoallv(send_vertex_lat, recv_count, recv_displ, MPI_DOUBLE,
1447 *y_vertices, send_count, send_displ, MPI_DOUBLE, comm);
1448
1449 free(send_vertex_lat);
1450 free(send_vertex_lon);
1451 free(recv_displ);
1452 free(send_displ);
1453 free(recv_count);
1454 free(send_count);
1455 }
1456
1457 // generate edge vertex data
1458 *edge_to_vertex =
1459 xmalloc(2 * num_core_edges * sizeof(**edge_to_vertex));
1460 {
1461 int * local_edge_to_vertex =
1462 xmalloc(2 * num_core_edges * sizeof(*local_edge_to_vertex));
1463 int * send_count = xcalloc(comm_size, sizeof(*send_count));
1464 int * recv_count = xcalloc(comm_size, sizeof(*recv_count));
1465
1466 for (size_t i = 0; i < num_core_edges; ++i)
1467 send_count[((unsigned long)((*edge_ids)[i]) *
1468 (unsigned long)comm_size + (unsigned long)comm_size - 1) /
1469 (unsigned long)nedges]++;
1470
1471 MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
1472
1473 int * send_displ = xmalloc(comm_size * sizeof(*send_displ));
1474 int * recv_displ = xmalloc(comm_size * sizeof(*recv_displ));
1475 int send_accum = 0, recv_accum = 0;
1476 for (int i = 0; i < comm_size; ++i) {
1477 send_displ[i] = send_accum;
1478 recv_displ[i] = recv_accum;
1479 send_accum += send_count[i];
1480 recv_accum += recv_count[i];
1481 }
1482
1483 int num_all_local_edges_remote = 0;
1484 for (int i = 0; i < comm_size; ++i)
1485 num_all_local_edges_remote += recv_count[i];
1486
1487 yac_int * remote_edge_buffer =
1488 xmalloc(num_all_local_edges_remote * sizeof(*remote_edge_buffer));
1489
1490 MPI_Alltoallv(
1491 *edge_ids, send_count, send_displ, yac_int_dt,
1492 remote_edge_buffer, recv_count, recv_displ, yac_int_dt, comm);
1493
1494 int * send_edge_vertices =
1495 xmalloc(2 * num_all_local_edges_remote * sizeof(*send_edge_vertices));
1496
1497 for (int i = 0, l = 0; i < comm_size; ++i) {
1498 for (int j = 0; j < recv_count[i]; ++j, ++l) {
1499 size_t idx = (size_t)(remote_edge_buffer[l]) - local_start_edge;
1500 send_edge_vertices[2*l+0] = dist_edge_vertices[2*idx+0];
1501 send_edge_vertices[2*l+1] = dist_edge_vertices[2*idx+1];
1502
1503 }
1504 send_count[i] *= 2;
1505 recv_count[i] *= 2;
1506 send_displ[i] *= 2;
1507 recv_displ[i] *= 2;
1508 }
1509
1510 free(remote_edge_buffer);
1511 free(dist_edge_vertices);
1512
1513 MPI_Alltoallv(send_edge_vertices, recv_count, recv_displ, MPI_INT,
1514 local_edge_to_vertex, send_count, send_displ, MPI_INT, comm);
1515
1516 size_t * permutation = xmalloc(2 * num_core_edges * sizeof(*permutation));
1517 for (size_t i = 0; i < 2 * num_core_edges; ++i) permutation[i] = i;
1518
1520 local_edge_to_vertex, 2 * num_core_edges, permutation);
1521
1522 for (size_t i = 0, j = 0; i < 2 * num_core_edges; ++i) {
1523 yac_int curr_vertex = (yac_int)(local_edge_to_vertex[i]);
1524 while ((j < nvertices) && ((*vertex_ids)[j] < curr_vertex)) ++j;
1525 YAC_ASSERT(
1526 (j < nvertices) && ((*vertex_ids)[j] == curr_vertex),
1527 "vertex id missmatch")
1528 (*edge_to_vertex)[permutation[i]] = j;
1529 }
1530
1531 free(permutation);
1532 free(send_edge_vertices);
1533 free(recv_displ);
1534 free(send_displ);
1535 free(recv_count);
1536 free(send_count);
1537 free(local_edge_to_vertex);
1538 }
1539
1540 // generate cell ids for local partition
1541 *cell_ids = xmalloc(num_local_cells * sizeof(**cell_ids));
1542 for (size_t i = 0; i < num_local_cells; ++i)
1543 (*cell_ids)[i] = (yac_int)(local_start_cell + i);
1544
1545 // generate num_vertices_per_cell
1546 *num_vertices_per_cell =
1547 xmalloc(num_local_cells * sizeof(**num_vertices_per_cell));
1548 for (size_t i = 0; i < num_local_cells; ++i) (*num_vertices_per_cell)[i] = nv;
1549
1550 // generate edge_type (for icon grids this is always YAC_GREAT_CIRCLE_EDGE)
1551 *edge_type = xmalloc(num_core_edges * sizeof(**edge_type));
1552 for (size_t i = 0; i < num_core_edges; ++i)
1553 (*edge_type)[i] = YAC_GREAT_CIRCLE_EDGE;
1554
1555 *num_cells = num_local_cells;
1556 *num_vertices = num_core_vertices;
1557 *num_edges = num_core_edges;
1558}
1559
1561 const char * filename, MPI_Comm comm) {
1562
1563 double * x_vertices;
1564 double * y_vertices;
1565 yac_int * cell_ids;
1567 yac_int * edge_ids;
1568 size_t num_cells;
1569 size_t num_vertices;
1570 size_t num_edges;
1573 size_t * cell_to_vertex;
1574 size_t * cell_to_edge;
1575 size_t * vertex_to_cell;
1576 size_t * edge_to_vertex;
1577 enum yac_edge_type * edge_type;
1578
1580 filename, comm, &x_vertices, &y_vertices, &cell_ids, &vertex_ids, &edge_ids,
1583 &edge_to_vertex, &edge_type, NULL, NULL, NULL);
1584
1587 for (size_t i = 0; i < num_vertices; ++i)
1588 LLtoXYZ(x_vertices[i], y_vertices[i], vertex_coordinates[i]);
1589 free(x_vertices);
1590 free(y_vertices);
1591
1593 grid_data.vertex_coordinates = vertex_coordinates;
1594 grid_data.cell_ids = cell_ids;
1595 grid_data.vertex_ids = vertex_ids;
1596 grid_data.edge_ids = edge_ids;
1597 grid_data.num_cells = num_cells;
1598 grid_data.num_vertices = num_vertices;
1599 grid_data.num_edges = num_edges;
1604 grid_data.num_cells_per_vertex = num_cells_per_vertex;
1606 grid_data.cell_to_vertex_offsets = generate_offsets(num_cells, num_vertices_per_cell);
1607 grid_data.cell_to_edge = cell_to_edge;
1608 grid_data.cell_to_edge_offsets = grid_data.cell_to_vertex_offsets;
1609 grid_data.vertex_to_cell = vertex_to_cell;
1611 grid_data.edge_to_vertex = (yac_size_t_2_pointer)&(edge_to_vertex[0]);
1612 grid_data.edge_type = edge_type;
1613 grid_data.num_total_cells = num_cells;
1614 grid_data.num_total_vertices = num_vertices;
1615 grid_data.num_total_edges = num_edges;
1616
1617 return grid_data;
1618}
1619
1621 char const * filename, char const * gridname, MPI_Comm comm,
1622 struct yac_basic_grid ** basic_grid, size_t * cell_coordinate_idx,
1623 int ** cell_mask) {
1624
1625 double * x_vertices;
1626 double * y_vertices;
1627 yac_int * cell_ids;
1629 yac_int * edge_ids;
1630 size_t num_cells;
1631 size_t num_vertices;
1632 size_t num_edges;
1635 size_t * cell_to_vertex;
1636 size_t * cell_to_edge;
1637 size_t * vertex_to_cell;
1638 size_t * edge_to_vertex;
1639 enum yac_edge_type * edge_type;
1640 double * x_cells;
1641 double * y_cells;
1642
1644 filename, comm, &x_vertices, &y_vertices, &cell_ids, &vertex_ids, &edge_ids,
1647 &edge_to_vertex, &edge_type, &x_cells, &y_cells, cell_mask);
1648
1651 for (size_t i = 0; i < num_vertices; ++i)
1652 LLtoXYZ(x_vertices[i], y_vertices[i], vertex_coordinates[i]);
1653 free(x_vertices);
1654 free(y_vertices);
1655
1656 struct yac_basic_grid_data basic_grid_data;
1657 basic_grid_data.vertex_coordinates = vertex_coordinates;
1658 basic_grid_data.cell_ids = cell_ids;
1659 basic_grid_data.vertex_ids = vertex_ids;
1660 basic_grid_data.edge_ids = edge_ids;
1661 basic_grid_data.num_cells = num_cells;
1662 basic_grid_data.num_vertices = num_vertices;
1663 basic_grid_data.num_edges = num_edges;
1669 basic_grid_data.cell_to_vertex = cell_to_vertex;
1671 basic_grid_data.cell_to_edge = cell_to_edge;
1672 basic_grid_data.cell_to_edge_offsets = basic_grid_data.cell_to_vertex_offsets;
1673 basic_grid_data.vertex_to_cell = vertex_to_cell;
1675 basic_grid_data.edge_to_vertex = (yac_size_t_2_pointer)&(edge_to_vertex[0]);
1676 basic_grid_data.edge_type = edge_type;
1677 basic_grid_data.num_total_cells = num_cells;
1678 basic_grid_data.num_total_vertices = num_vertices;
1679 basic_grid_data.num_total_edges = num_edges;
1680
1681 *basic_grid = yac_basic_grid_new(gridname, basic_grid_data);
1682
1683 yac_coordinate_pointer cell_coordinates =
1684 xmalloc(num_cells * sizeof(*cell_coordinates));
1685 for (size_t i = 0; i < num_cells; ++i)
1686 LLtoXYZ(x_cells[i], y_cells[i], cell_coordinates[i]);
1687 *cell_coordinate_idx =
1689 *basic_grid, YAC_LOC_CELL, cell_coordinates);
1690 free(x_cells);
1691 free(y_cells);
1692}
1693
1695 char const * filename, char const * gridname, MPI_Comm comm) {
1696
1697 return
1699 gridname,
1701}
1702
1704 char const * filename, char const * gridname, MPI_Fint comm) {
1705
1706 return
1708 filename, gridname, MPI_Comm_f2c(comm));
1709}
1710
1712 char const * filename) {
1713
1714 int nbr_vertices;
1715 int nbr_cells;
1716 int * num_vertices_per_cell = NULL;
1717 int * cell_to_vertex = NULL;
1718 int * cell_mask = NULL;
1719
1720 double * x_vertices = NULL;
1721 double * y_vertices = NULL;
1722 double * x_cells = NULL;
1723 double * y_cells = NULL;
1724
1725 yac_read_icon_grid_information(filename, &nbr_vertices, &nbr_cells,
1727 &x_vertices, &y_vertices,
1728 &x_cells, &y_cells,
1729 &cell_mask);
1730
1731 free(x_cells);
1732 free(y_cells);
1733 free(cell_mask);
1734
1735 struct yac_basic_grid_data grid =
1737 (size_t)nbr_vertices, (int)nbr_cells, num_vertices_per_cell,
1738 x_vertices, y_vertices, cell_to_vertex);
1740 free(x_vertices);
1741 free(y_vertices);
1742 free(cell_to_vertex);
1743
1744 return grid;
1745}
1746
1748 char const * filename, char const * gridname) {
1749
1750 return
1752 gridname, yac_read_icon_basic_grid_data(filename));
1753}
1754
1755/* ---------------------------------------------------------------- */
1756
1757static int * get_icon_cell_mask ( int ncid, size_t nbr_cells ) {
1758
1759 // get variable id
1760 int mask_id;
1761 yac_nc_inq_varid (ncid, "cell_sea_land_mask", &mask_id);
1762
1763 // check number of dimension (has to be 1)
1764 int ndims;
1765 YAC_HANDLE_ERROR(nc_inq_varndims(ncid, mask_id, &ndims));
1766 YAC_ASSERT( ndims == 1, "mask array has more than one dimension")
1767
1768 // get id of dimension
1769 int dimid;
1770 YAC_HANDLE_ERROR(nc_inq_vardimid(ncid, mask_id, &dimid));
1771
1772 // check size of mask (has to be equal to nbr_cells)
1773 size_t dimlen;
1774 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimid, &dimlen));
1775 YAC_ASSERT(dimlen == nbr_cells, "invalid size of mask array")
1776
1777 // check mask type (has to be NC_INT)
1778 nc_type mask_type;
1779 YAC_HANDLE_ERROR(nc_inq_vartype(ncid, mask_id, &mask_type));
1780 YAC_ASSERT(mask_type == NC_INT, "invalid mask type")
1781
1782 // get and return mask
1783 int * cell_mask = xmalloc(nbr_cells * sizeof(*cell_mask));
1784 YAC_HANDLE_ERROR(nc_get_var_int (ncid, mask_id, cell_mask));
1785 return cell_mask;
1786}
1787
1788/* ---------------------------------------------------------------- */
1789
1791 int ncid, size_t nbr_cells, int ** vertex_of_cell, size_t * nv) {
1792
1793 // get variable id
1794 int conn_id;
1795 yac_nc_inq_varid(ncid, "vertex_of_cell", &conn_id);
1796
1797 // check number of dimension (has to be 1)
1798 int ndims;
1799 YAC_HANDLE_ERROR(nc_inq_varndims(ncid, conn_id, &ndims));
1800 YAC_ASSERT(ndims == 2, "connectivity array has invalid number of dimensions")
1801
1802 // get ids of dimensions
1803 int dimids[2];
1804 YAC_HANDLE_ERROR(nc_inq_vardimid(ncid, conn_id, dimids));
1805
1806 // check size of dimensions
1807 size_t dimlen;
1808 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimids[0], nv));
1809 YAC_HANDLE_ERROR(nc_inq_dimlen(ncid, dimids[1], &dimlen));
1810 YAC_ASSERT(
1811 dimlen == nbr_cells,
1812 "invalid size of second dimension of connectivity array "
1813 "(has to be nbr_cells)")
1814
1815 // get and return connectivity array
1816 *vertex_of_cell = xmalloc(*nv * nbr_cells * sizeof(**vertex_of_cell));
1817 YAC_HANDLE_ERROR(nc_get_var_int (ncid, conn_id, *vertex_of_cell));
1818}
1819
1821 int ** global_cell_id,
1822 int ** global_cell_id_rank,
1823 int ** num_vertices_per_cell,
1824 int ** global_corner_id,
1825 int ** global_corner_id_rank,
1826 int ** cell_to_vertex,
1827 double ** x_cells,
1828 double ** y_cells,
1829 double ** x_vertices,
1830 double ** y_vertices) {
1831
1832 free (*cell_mask);
1833 free (*global_cell_id);
1834 free (*global_cell_id_rank);
1835 free (*num_vertices_per_cell);
1836 free (*global_corner_id);
1837 free (*global_corner_id_rank);
1838 free (*cell_to_vertex);
1839 free (*x_cells);
1840 free (*y_cells);
1841 free (*x_vertices);
1842 free (*y_vertices);
1843}
1844
1845#else
1846
1848 char const * filename) {
1849
1850 UNUSED(filename);
1851 die(
1852 "ERROR(yac_basic_grid_data): "
1853 "YAC is built without the NetCDF support");
1854
1855 return
1857 (size_t[]){0,0}, (int[]){0,0}, NULL, NULL);
1858}
1859
1861 char const * filename, char const * gridname) {
1862
1863 UNUSED(filename);
1864 UNUSED(gridname);
1865 die(
1866 "ERROR(yac_read_icon_basic_grid): "
1867 "YAC is built without the NetCDF support");
1868
1869 return NULL;
1870}
1871
1872void yac_read_icon_grid_information(const char * filename, int * nbr_vertices,
1873 int * nbr_cells, int ** num_vertices_per_cell,
1874 int ** cell_to_vertex, double ** x_vertices,
1875 double ** y_vertices, double ** x_cells,
1876 double ** y_cells, int ** cell_mask) {
1877
1878 UNUSED(filename);
1879 UNUSED(nbr_vertices);
1880 UNUSED(nbr_cells);
1881 UNUSED(num_vertices_per_cell);
1883 UNUSED(x_vertices);
1884 UNUSED(y_vertices);
1885 UNUSED(x_cells);
1886 UNUSED(y_cells);
1888 die(
1889 "ERROR(yac_read_icon_grid_information): "
1890 "YAC is built without the NetCDF support");
1891}
1892
1894 const char * filename, int * num_vertices, int * num_cells,
1895 int ** num_vertices_per_cell, int ** cell_to_vertex,
1896 double ** x_vertices, double ** y_vertices,
1897 double ** x_cells, double ** y_cells, int ** global_cell_id,
1898 int ** cell_mask, int ** cell_core_mask,
1899 int ** global_corner_id, int ** corner_core_mask, int rank, int size) {
1900
1901 UNUSED(filename);
1902 UNUSED(num_vertices);
1904 UNUSED(num_vertices_per_cell);
1906 UNUSED(x_vertices);
1907 UNUSED(y_vertices);
1908 UNUSED(x_cells);
1909 UNUSED(y_cells);
1910 UNUSED(global_cell_id);
1913 UNUSED(global_corner_id);
1914 UNUSED(corner_core_mask);
1915 UNUSED(rank);
1916 UNUSED(size);
1917 die(
1918 "ERROR(yac_read_part_icon_grid_information): "
1919 "YAC is built without the NetCDF support");
1920}
1921
1923 const char * filename, MPI_Comm comm, int * nbr_vertices, int * nbr_cells,
1924 int ** num_vertices_per_cell, int ** cell_to_vertex, int ** global_cell_ids,
1925 int ** cell_owner, int ** global_vertex_ids, int ** vertex_owner,
1926 double ** x_vertices, double ** y_vertices,
1927 double ** x_cells, double ** y_cells, int ** cell_msk) {
1928
1929 UNUSED(filename);
1930 UNUSED(comm);
1931 UNUSED(nbr_vertices);
1932 UNUSED(nbr_cells);
1933 UNUSED(num_vertices_per_cell);
1935 UNUSED(global_cell_ids);
1936 UNUSED(cell_owner);
1937 UNUSED(global_vertex_ids);
1938 UNUSED(vertex_owner);
1939 UNUSED(x_vertices);
1940 UNUSED(y_vertices);
1941 UNUSED(x_cells);
1942 UNUSED(y_cells);
1943 UNUSED(cell_msk);
1944 die(
1945 "ERROR(yac_read_icon_grid_information_parallel): "
1946 "YAC is built without the NetCDF support");
1947}
1948
1950 const char * filename, MPI_Fint comm, int * nbr_vertices, int * nbr_cells,
1951 int ** num_vertices_per_cell, int ** cell_to_vertex, int ** global_cell_ids,
1952 int ** cell_owner, int ** global_vertex_ids, int ** vertex_owner,
1953 double ** x_vertices, double ** y_vertices,
1954 double ** x_cells, double ** y_cells, int ** cell_msk) {
1955
1956 UNUSED(filename);
1957 UNUSED(comm);
1958 UNUSED(nbr_vertices);
1959 UNUSED(nbr_cells);
1960 UNUSED(num_vertices_per_cell);
1962 UNUSED(global_cell_ids);
1963 UNUSED(cell_owner);
1964 UNUSED(global_vertex_ids);
1965 UNUSED(vertex_owner);
1966 UNUSED(x_vertices);
1967 UNUSED(y_vertices);
1968 UNUSED(x_cells);
1969 UNUSED(y_cells);
1970 UNUSED(cell_msk);
1971 die(
1972 "ERROR(yac_read_icon_grid_information_parallel_f2c): "
1973 "YAC is built without the NetCDF support");
1974}
1975
1977 const char * filename, MPI_Comm comm,
1978 double ** x_vertices, double ** y_vertices,
1979 yac_int ** cell_ids, yac_int ** vertex_ids, yac_int ** edge_ids,
1980 size_t * num_cells, size_t * num_vertices, size_t * num_edges,
1981 int ** num_vertices_per_cell, int ** num_cells_per_vertex,
1982 size_t ** cell_to_vertex, size_t ** cell_to_edge, size_t ** vertex_to_cell,
1983 size_t ** edge_to_vertex, enum yac_edge_type ** edge_type,
1984 double ** x_cells, double ** y_cells, int ** cell_msk) {
1985
1986 UNUSED(filename);
1987 UNUSED(comm);
1988 UNUSED(x_vertices);
1989 UNUSED(y_vertices);
1990 UNUSED(cell_ids);
1991 UNUSED(vertex_ids);
1992 UNUSED(edge_ids);
1994 UNUSED(num_vertices);
1995 UNUSED(num_edges);
1996 UNUSED(num_vertices_per_cell);
1997 UNUSED(num_cells_per_vertex);
1999 UNUSED(cell_to_edge);
2000 UNUSED(vertex_to_cell);
2001 UNUSED(edge_to_vertex);
2002 UNUSED(edge_type);
2003 UNUSED(x_cells);
2004 UNUSED(y_cells);
2005 UNUSED(cell_msk);
2006 die(
2007 "ERROR(yac_read_icon_grid_information_parallel_2): "
2008 "YAC is built without the NetCDF support");
2009}
2010
2012 char const * filename, char const * gridname, MPI_Comm comm,
2013 struct yac_basic_grid ** basic_grid, size_t * cell_coordinate_idx,
2014 int ** cell_mask) {
2015
2016 UNUSED(filename);
2017 UNUSED(gridname);
2018 UNUSED(comm);
2019 UNUSED(basic_grid);
2020 UNUSED(cell_coordinate_idx);
2022 die(
2023 "ERROR(yac_read_icon_basic_grid_parallel_2): "
2024 "YAC is built without the NetCDF support");
2025}
2026
2028 const char * filename, MPI_Comm comm) {
2029
2030 UNUSED(filename);
2031 UNUSED(comm);
2032 die(
2033 "ERROR(yac_read_icon_basic_grid_data_parallel): "
2034 "YAC is built without the NetCDF support");
2035
2036 return
2038 (size_t[]){0,0}, (int[]){0,0}, NULL, NULL);
2039}
2040
2042 char const * filename, char const * gridname, MPI_Comm comm) {
2043
2044 UNUSED(filename);
2045 UNUSED(gridname);
2046 UNUSED(comm);
2047 die(
2048 "ERROR(yac_read_icon_basic_grid_parallel): "
2049 "YAC is built without the NetCDF support");
2050
2051 return NULL;
2052}
2053
2055 char const * filename, char const * gridname, MPI_Fint comm) {
2056
2057 UNUSED(filename);
2058 UNUSED(gridname);
2059 UNUSED(comm);
2060 die(
2061 "ERROR(yac_read_icon_basic_grid_parallel_f2c): "
2062 "YAC is built without the NetCDF support");
2063
2064 return NULL;
2065}
2066
2068 int ** global_cell_id,
2069 int ** cell_core_mask,
2070 int ** num_vertices_per_cell,
2071 int ** global_corner_id,
2072 int ** corner_core_mask,
2073 int ** cell_to_vertex,
2074 double ** x_cells,
2075 double ** y_cells,
2076 double ** x_vertices,
2077 double ** y_vertices) {
2078
2080 UNUSED(global_cell_id);
2082 UNUSED(num_vertices_per_cell);
2083 UNUSED(global_corner_id);
2084 UNUSED(corner_core_mask);
2086 UNUSED(x_vertices);
2087 UNUSED(y_vertices);
2088 UNUSED(x_cells);
2089 UNUSED(y_cells);
2090 die(
2091 "ERROR(yac_delete_icon_grid_data): "
2092 "YAC is built without the NetCDF support");
2093}
2094
2095#endif // YAC_NETCDF_ENABLED
#define YAC_ASSERT(exp, msg)
struct yac_basic_grid * yac_basic_grid_new(char const *name, struct yac_basic_grid_data grid_data)
Definition basic_grid.c:57
size_t yac_basic_grid_add_coordinates_nocpy(struct yac_basic_grid *grid, enum yac_location location, yac_coordinate_pointer coordinates)
Definition basic_grid.c:202
struct yac_basic_grid_data yac_generate_basic_grid_data_reg_2d(size_t nbr_vertices[2], int cyclic[2], double *lon_vertices, double *lat_vertices)
Definition grid_reg2d.c:62
struct yac_basic_grid_data yac_generate_basic_grid_data_unstruct(size_t nbr_vertices, size_t nbr_cells, int *num_vertices_per_cell, double *x_vertices, double *y_vertices, int *cell_to_vertex)
#define UNUSED(x)
Definition core.h:72
#define YAC_RAD
yac_edge_type
Definition grid_cell.h:12
@ YAC_GREAT_CIRCLE_EDGE
great circle
Definition grid_cell.h:13
void yac_get_io_ranks(MPI_Comm comm, int *local_is_io_, int **io_ranks_, int *num_io_ranks_)
Definition io_utils.c:271
void yac_nc_inq_varid(int ncid, char const *name, int *varidp)
Definition io_utils.c:369
void yac_nc_open(const char *path, int omode, int *ncidp)
Definition io_utils.c:311
void yac_nc_inq_dimid(int ncid, char const *name, int *dimidp)
Definition io_utils.c:344
@ YAC_LOC_CELL
Definition location.h:14
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:67
#define xcalloc(nmemb, size)
Definition ppm_xfuncs.h:64
#define xmalloc(size)
Definition ppm_xfuncs.h:66
int yac_check_coord_units(int ncid, int varid)
Definition read_grid.c:43
void yac_read_coords(int ncid, char const *lon_name, char const *lat_name, double **lon, double **lat, size_t *len)
Definition read_grid.c:90
struct yac_basic_grid * yac_read_icon_basic_grid_parallel_f2c(char const *filename, char const *gridname, MPI_Fint comm)
static void convert_to_rad(int ncid, int varid, double *array, size_t count)
void yac_delete_icon_grid_data(int **cell_mask, int **global_cell_id, int **global_cell_id_rank, int **num_vertices_per_cell, int **global_corner_id, int **global_corner_id_rank, int **cell_to_vertex, double **x_cells, double **y_cells, double **x_vertices, double **y_vertices)
struct yac_basic_grid * yac_read_icon_basic_grid(char const *filename, char const *gridname)
void yac_read_part_icon_grid_information(const char *filename, int *nbr_vertices, int *nbr_cells, int **num_vertices_per_cell, int **cell_to_vertex, double **x_vertices, double **y_vertices, double **x_cells, double **y_cells, int **global_cell_id, int **cell_mask, int **cell_core_mask, int **global_corner_id, int **corner_core_mask, int rank, int size)
struct yac_basic_grid_data yac_read_icon_basic_grid_data_parallel(const char *filename, MPI_Comm comm)
static int * get_icon_cell_mask(int ncid, size_t nbr_cells)
void yac_read_icon_grid_information_parallel(const char *filename, MPI_Comm comm, int *nbr_vertices, int *nbr_cells, int **num_vertices_per_cell, int **cell_to_vertex, int **global_cell_ids, int **cell_owner, int **global_vertex_ids, int **vertex_owner, double **x_vertices, double **y_vertices, double **x_cells, double **y_cells, int **cell_msk)
void yac_read_icon_basic_grid_parallel_2(char const *filename, char const *gridname, MPI_Comm comm, struct yac_basic_grid **basic_grid, size_t *cell_coordinate_idx, int **cell_mask)
void yac_read_icon_grid_information_parallel_f2c(const char *filename, MPI_Fint comm, int *nbr_vertices, int *nbr_cells, int **num_vertices_per_cell, int **cell_to_vertex, int **global_cell_ids, int **cell_owner, int **global_vertex_ids, int **vertex_owner, double **x_vertices, double **y_vertices, double **x_cells, double **y_cells, int **cell_msk)
static int partition_idx_from_element_idx(unsigned element_idx, unsigned num_elements, int num_partitions)
void yac_read_icon_grid_information_parallel_2(const char *filename, MPI_Comm comm, double **x_vertices, double **y_vertices, yac_int **cell_ids, yac_int **vertex_ids, yac_int **edge_ids, size_t *num_cells, size_t *num_vertices, size_t *num_edges, int **num_vertices_per_cell, int **num_cells_per_vertex, size_t **cell_to_vertex, size_t **cell_to_edge, size_t **vertex_to_cell, size_t **edge_to_vertex, enum yac_edge_type **edge_type, double **x_cells, double **y_cells, int **cell_msk)
static size_t * generate_offsets(size_t N, int *counts)
static int * generate_simple_core_mask(size_t N)
void yac_read_icon_grid_information(const char *filename, int *nbr_vertices, int *nbr_cells, int **num_vertices_per_cell, int **cell_to_vertex, double **x_vertices, double **y_vertices, double **x_cells, double **y_cells, int **cell_mask)
static void get_icon_connect(int ncid, size_t nbr_cells, int **vertex_of_cell, size_t *nv)
struct yac_basic_grid * yac_read_icon_basic_grid_parallel(char const *filename, char const *gridname, MPI_Comm comm)
struct yac_basic_grid_data yac_read_icon_basic_grid_data(char const *filename)
yac_coordinate_pointer vertex_coordinates
size_t * vertex_to_cell_offsets
yac_size_t_2_pointer edge_to_vertex
enum yac_edge_type * edge_type
size_t * cell_to_vertex_offsets
int * cell_to_vertex
int * cell_mask
double * cell_lat
double * cell_lon
#define N
size_t num_cells[2]
int vertex_of_cell[3][16]
static int mask[16]
int * cell_core_mask
double * buffer
#define YAC_HANDLE_ERROR(exp)
Definition toy_output.c:13
static void LLtoXYZ(double lon, double lat, double p_out[])
Definition toy_scrip.c:587
static void yac_remove_duplicates_int(int *array, size_t *n)
#define MAX(a, b)
void yac_quicksort_index_yac_int_size_t(yac_int *a, size_t n, size_t *idx)
void yac_quicksort_index_int_size_t(int *a, size_t n, size_t *idx)
void yac_quicksort_index(int *a, size_t n, int *idx)
#define die(msg)
Definition yac_assert.h:14
YAC_INT yac_int
Definition yac_types.h:15
size_t(* yac_size_t_2_pointer)[2]
Definition yac_types.h:25
#define yac_int_dt
Definition yac_types.h:18
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:21