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