YAC 3.18.0
Yet Another Coupler
Loading...
Searching...
No Matches
component.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 <limits.h>
10#include <string.h>
11#include <stdlib.h>
12#include <stdio.h>
13#include <math.h>
14
15#include <mpi.h>
16
17#include "utils_mci.h"
18#include "utils_common.h"
19#include "yac_mpi_common.h"
20#include "component.h"
21#include "yac.h"
22
24
25 char const * name;
26 MPI_Group group;
28};
29
31
32 MPI_Comm comm;
33 size_t num_comps;
35};
36
37static int compare_component_data(void const * a, void const * b) {
38 return strcmp(((struct component_data const *)a)->name,
39 ((struct component_data const *)b)->name);
40}
41
43 struct yac_couple_config * couple_config, char const ** names,
44 size_t num_names, MPI_Comm comm_) {
45
46 // get number of globally defined components
49
50 // make a copy of the provided communicator to avoid interference
51 // with other communication
52 MPI_Comm comm;
53 yac_mpi_call(MPI_Comm_dup(comm_, &comm), comm_);
54
55 // allocate and initialise basic component configuration
56 struct yac_component_config * comp_config =
57 xmalloc(
58 1 * sizeof(*comp_config) +
59 num_global_components * sizeof(struct component_data));
60 comp_config->comm = comm;
61 comp_config->num_comps = num_global_components;
62 for (size_t i = 0; i < num_global_components; ++i)
63 comp_config->comps[i].name =
65
66 // sort global components by name --> ensure identical processing
67 // order on all processes
68 qsort(
69 comp_config->comps, num_global_components,
70 sizeof(*(comp_config->comps)), compare_component_data);
71
72 // get the MPI group of the provided communicator
73 MPI_Group world_group;
74 yac_mpi_call(MPI_Comm_group(comm, &world_group), comm);
75
76 // allocate temporary data
77 int comm_size;
78 yac_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
79 int * rank_mask = xmalloc(2 * (size_t)comm_size * sizeof(*rank_mask));
80 int * ranks = rank_mask + (size_t)comm_size;
81
82 // for all sorted global component
83 for (size_t i = 0; i < num_global_components; ++i) {
84
85 struct component_data * comp = &(comp_config->comps[i]);
86 char const * comp_name = comp->name;
87
88 // search for current component in list of locally defined components
89 int is_local = 0;
90 for (size_t j = 0; (j < num_names) && !is_local; ++j)
91 is_local = !strcmp(comp_name, names[j]);
92
93 // determine which ranks are part of the current component
95 MPI_Allgather(
96 &is_local, 1, MPI_INT, rank_mask, 1, MPI_INT, comm), comm);
97
98 // generate list of all ranks included in the current component
99 int rank_count = 0;
100 for (int rank = 0; rank < comm_size; ++rank) {
101 if (rank_mask[rank]) {
102 ranks[rank_count] = rank;
103 ++rank_count;
104 }
105 }
106
107 // generate group containing all ranks from the current component
108 MPI_Group comp_group;
110 MPI_Group_incl(
111 world_group, rank_count, ranks, &comp_group), comm);
112
113 comp->group = comp_group;
114 comp->is_local = is_local;
115 }
116
117 // cleanup
118 yac_mpi_call(MPI_Group_free(&world_group), comm);
119 free(rank_mask);
120
121 return comp_config;
122}
123
124static inline int compare_int(const void * a, const void * b) {
125
126 int const * a_ = a, * b_ = b;
127
128 return (*a_ > *b_) - (*b_ > *a_);
129}
130
131static size_t get_comp_idx(
132 char const * caller, struct yac_component_config * comp_config,
133 char const * comp_name) {
134
135 struct component_data * comps = comp_config->comps;
136 size_t num_comps = comp_config->num_comps;
137 size_t comp_idx = SIZE_MAX;
138 for (size_t i = 0; (i < num_comps) && (comp_idx == SIZE_MAX); ++i)
139 if (!strcmp(comps[i].name, comp_name)) comp_idx = i;
141 comp_idx != SIZE_MAX,
142 "ERROR(%s): invalid component name: \"%s\"", caller, comp_name)
143 return comp_idx;
144}
145
147 struct yac_component_config * comp_config,
148 const char ** names, size_t num_names) {
149
150 // if no component name was provided
151 if (num_names == 0) return MPI_COMM_NULL;
152
154 num_names < INT_MAX,
155 "ERROR(yac_component_config_get_comps_comm): too many components (%zu)",
156 num_names);
157
158 // get the index of each component
159 int * comp_idxs = xmalloc(num_names * sizeof(*comp_idxs));
160 for (size_t i = 0; i < num_names; ++i)
161 comp_idxs[i] =
162 (int)get_comp_idx(
163 "yac_component_config_get_comps_comm", comp_config, names[i]);
164
165 // sort and remove duplicated component indices
166 qsort(comp_idxs, num_names, sizeof(*comp_idxs), compare_int);
167 yac_remove_duplicates_int(comp_idxs, &num_names);
168
169 MPI_Group comps_group = MPI_GROUP_EMPTY;
170 for (size_t i = 0; i < num_names; ++i) {
171 int comp_idx = comp_idxs[i];
172 MPI_Group comp_group = comp_config->comps[comp_idx].group;
173 MPI_Group union_group;
175 MPI_Group_union(comps_group, comp_group, &union_group),
176 comp_config->comm);
177 if (comps_group != MPI_GROUP_EMPTY)
178 yac_mpi_call(MPI_Group_free(&comps_group), comp_config->comm);
179 comps_group = union_group;
180 }
181
182 int group_rank, group_size;
183 yac_mpi_call(MPI_Group_rank(comps_group, &group_rank), comp_config->comm);
184 yac_mpi_call(MPI_Group_size(comps_group, &group_size), comp_config->comm);
186 group_rank != MPI_UNDEFINED,
187 "ERROR(yac_component_config_get_comps_comm): "
188 "local process not included in any component provided to this routine");
189
190 // get rank (from comp_config->comm) of neighbouring ranks
191 int group_neigh_ranks[3], neigh_ranks[3];
192 group_neigh_ranks[0] = (group_rank + 1) % group_size;
193 group_neigh_ranks[1] = (group_rank + group_size - 1) % group_size;
194 group_neigh_ranks[2] = group_rank;
195 MPI_Group comp_config_group;
197 MPI_Comm_group(comp_config->comm, &comp_config_group), comp_config->comm);
199 MPI_Group_translate_ranks(
200 comps_group, 3, group_neigh_ranks, comp_config_group, neigh_ranks),
201 comp_config->comm);
202 MPI_Group_free(&comp_config_group);
203
204 // exchange number of names with neighbouring processes
205 int num_names_buffer = (int)num_names;
206 int const tag = 0;
208 MPI_Sendrecv_replace(
209 &num_names_buffer, 1, MPI_INT, neigh_ranks[0], tag,
210 neigh_ranks[1], tag, comp_config->comm, MPI_STATUS_IGNORE),
211 comp_config->comm);
213 num_names_buffer == (int)num_names,
214 "ERROR(yac_component_config_get_comps_comm): "
215 "processes do not agree on number of component names "
216 "(rank %d num_names %d != rank %d num_names %zu)",
217 neigh_ranks[1], num_names_buffer, neigh_ranks[2], num_names);
218
219 // exchange component indices with neighbouring processes
220 int * comp_idxs_recv_buffer = xmalloc(num_names * sizeof(*comp_idxs_recv_buffer));
222 MPI_Sendrecv(
223 comp_idxs, (int)num_names, MPI_INT, neigh_ranks[0], tag,
224 comp_idxs_recv_buffer, (int)num_names, MPI_INT, neigh_ranks[1], tag,
225 comp_config->comm, MPI_STATUS_IGNORE), comp_config->comm);
226 for (size_t i = 0; i < num_names; ++i) {
228 comp_idxs[i] == comp_idxs_recv_buffer[i],
229 "ERROR(yac_component_config_get_comps_comm): "
230 "processes do not agree on component indices "
231 "(rank %d comp_idx[%zu] %d != rank %d comp_idx[%zu] %d)",
232 neigh_ranks[1], i, comp_idxs[i],
233 neigh_ranks[2], i, comp_idxs_recv_buffer[i]);
234 }
235 free(comp_idxs_recv_buffer);
236 free(comp_idxs);
237
238 MPI_Comm comps_comm;
240 MPI_Comm_create_group(
241 comp_config->comm, comps_group, tag, &comps_comm), comp_config->comm);
242
243 yac_mpi_call(MPI_Group_free(&comps_group), comp_config->comm);
244
245 return comps_comm;
246}
247
249 struct yac_component_config * comp_config, char const * comp_name) {
250
251 struct component_data * global_comps = comp_config->comps;
252 size_t num_global_comps = comp_config->num_comps;
253
254 for (size_t i = 0; i < num_global_comps; ++i)
255 if (!strcmp(comp_name, global_comps[i].name))
256 return global_comps[i].is_local;
257 return 0;
258}
259
260static MPI_Group get_local_comp_group(
261 char const * caller, struct yac_component_config * comp_config,
262 char const * comp_name) {
263
264 size_t comp_idx =
265 get_comp_idx(caller, comp_config, comp_name);
266
268 comp_config->comps[comp_idx].is_local,
269 "ERROR(%s): component \"%s\" is defined but not on local process",
270 caller, comp_name);
271
272 return comp_config->comps[comp_idx].group;
273}
274
276 struct yac_component_config * comp_config, char const * comp_name){
277
278 int size;
279 MPI_Group_size(
281 "yac_component_config_comp_size", comp_config, comp_name), &size);
282 return size;
283}
284
286 struct yac_component_config * comp_config, char const * comp_name){
287
288 int rank;
289 MPI_Group_rank(
291 "yac_component_config_comp_rank", comp_config, comp_name), &rank);
292 return rank;
293}
294
296
297 if (comp_config == NULL) return;
298
299 for (size_t i = 0; i < comp_config->num_comps; ++i) {
300 free((void*)comp_config->comps[i].name);
302 MPI_Group_free(&(comp_config->comps[i].group)), comp_config->comm);
303 }
304
305 yac_mpi_call(MPI_Comm_free(&(comp_config->comm)), MPI_COMM_WORLD);
306 free(comp_config);
307}
#define YAC_ASSERT(exp, msg)
static MPI_Group get_local_comp_group(char const *caller, struct yac_component_config *comp_config, char const *comp_name)
Definition component.c:260
int yac_component_config_comp_size(struct yac_component_config *comp_config, char const *comp_name)
Definition component.c:275
int yac_component_config_comp_rank(struct yac_component_config *comp_config, char const *comp_name)
Definition component.c:285
void yac_component_config_delete(struct yac_component_config *comp_config)
Definition component.c:295
MPI_Comm yac_component_config_get_comps_comm(struct yac_component_config *comp_config, const char **names, size_t num_names)
Definition component.c:146
static int compare_component_data(void const *a, void const *b)
Definition component.c:37
static size_t get_comp_idx(char const *caller, struct yac_component_config *comp_config, char const *comp_name)
Definition component.c:131
int yac_component_config_contains_component(struct yac_component_config *comp_config, char const *comp_name)
Definition component.c:248
static int compare_int(const void *a, const void *b)
Definition component.c:124
struct yac_component_config * yac_component_config_new(struct yac_couple_config *couple_config, char const **names, size_t num_names, MPI_Comm comm_)
Definition component.c:42
size_t yac_couple_config_get_num_components(struct yac_couple_config const *couple_config)
char const * yac_couple_config_get_component_name(struct yac_couple_config const *couple_config, size_t component_idx)
#define xstrdup(s)
Definition ppm_xfuncs.h:84
#define xmalloc(size)
Definition ppm_xfuncs.h:66
char const * name
Definition component.c:25
MPI_Group group
Definition component.c:26
struct component_data comps[]
Definition component.c:34
char const * name
Definition toy_scrip.c:114
static void yac_remove_duplicates_int(int *array, size_t *n)
static size_t num_global_components
Definition yac.c:182
#define YAC_ASSERT_F(exp, format,...)
Definition yac_assert.h:30
#define yac_mpi_call(call, comm)