~ubuntu-branches/ubuntu/trusty/nwchem/trusty-proposed

« back to all changes in this revision

Viewing changes to src/tools/ga-5-2/comex/src-ofa/groups.c

  • Committer: Package Import Robot
  • Author(s): Michael Banck, Daniel Leidert, Andreas Tille, Michael Banck
  • Date: 2013-07-04 12:14:55 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20130704121455-5tvsx2qabor3nrui
Tags: 6.3-1
* New upstream release.
* Fixes anisotropic properties (Closes: #696361).
* New features include:
  + Multi-reference coupled cluster (MRCC) approaches
  + Hybrid DFT calculations with short-range HF 
  + New density-functionals including Minnesota (M08, M11) and HSE hybrid
    functionals
  + X-ray absorption spectroscopy (XAS) with TDDFT
  + Analytical gradients for the COSMO solvation model
  + Transition densities from TDDFT 
  + DFT+U and Electron-Transfer (ET) methods for plane wave calculations
  + Exploitation of space group symmetry in plane wave geometry optimizations
  + Local density of states (LDOS) collective variable added to Metadynamics
  + Various new XC functionals added for plane wave calculations, including
    hybrid and range-corrected ones
  + Electric field gradients with relativistic corrections 
  + Nudged Elastic Band optimization method
  + Updated basis sets and ECPs 

[ Daniel Leidert ]
* debian/watch: Fixed.

[ Andreas Tille ]
* debian/upstream: References

[ Michael Banck ]
* debian/upstream (Name): New field.
* debian/patches/02_makefile_flags.patch: Refreshed.
* debian/patches/06_statfs_kfreebsd.patch: Likewise.
* debian/patches/07_ga_target_force_linux.patch: Likewise.
* debian/patches/05_avoid_inline_assembler.patch: Removed, no longer needed.
* debian/patches/09_backported_6.1.1_fixes.patch: Likewise.
* debian/control (Build-Depends): Added gfortran-4.7 and gcc-4.7.
* debian/patches/10_force_gcc-4.7.patch: New patch, explicitly sets
  gfortran-4.7 and gcc-4.7, fixes test suite hang with gcc-4.8 (Closes:
  #701328, #713262).
* debian/testsuite: Added tests for COSMO analytical gradients and MRCC.
* debian/rules (MRCC_METHODS): New variable, required to enable MRCC methods.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if HAVE_CONFIG_H
 
2
#   include "config.h"
 
3
#endif
 
4
 
 
5
#if HAVE_STDLIB_H
 
6
#   include <stdlib.h>
 
7
#endif
 
8
#if HAVE_ASSERT_H
 
9
#   include <assert.h>
 
10
#endif
 
11
 
 
12
#include "comex.h"
 
13
#include "comex_impl.h"
 
14
#include "groups.h"
 
15
 
 
16
/* COMEX has the notion of a default group and a world group. */
 
17
comex_group_t COMEX_Default_Proc_Group = 0;
 
18
comex_group_t COMEX_World_Proc_Group = 0;
 
19
 
 
20
/* the HEAD of the group linked list */
 
21
comex_igroup_t *group_list = NULL;
 
22
 
 
23
 
 
24
/**
 
25
 * Return the comex_igroup_t instance given the comex_group_t.
 
26
 *
 
27
 * The group linked list is searched sequentially until the given group
 
28
 * is found. It is an error if this function is called before
 
29
 * comex_group_init(). An error occurs if the given group is not found.
 
30
 */
 
31
comex_igroup_t* comex_get_igroup_from_group(comex_group_t id)
 
32
{
 
33
    comex_igroup_t *current_group_list_item = group_list;
 
34
 
 
35
    assert(group_list != NULL);
 
36
    while (current_group_list_item != NULL) {
 
37
        if (current_group_list_item->id == id) {
 
38
            return current_group_list_item;
 
39
        }
 
40
        current_group_list_item = current_group_list_item->next;
 
41
    }
 
42
    comex_error("comex_group_t lookup failed", -1);
 
43
 
 
44
    return NULL;
 
45
}
 
46
 
 
47
 
 
48
/**
 
49
 * Creates and associates an comex_group_t with an comex_igroup_t.
 
50
 *
 
51
 * This does *not* initialize the members of the comex_igroup_t.
 
52
 */
 
53
static void comex_create_group_and_igroup(
 
54
        comex_group_t *id, comex_igroup_t **igroup)
 
55
{
 
56
    comex_igroup_t *new_group_list_item = NULL;
 
57
    comex_igroup_t *last_group_list_item = NULL;
 
58
 
 
59
    /* find the last group in the group linked list */
 
60
    last_group_list_item = group_list;
 
61
    while (last_group_list_item->next != NULL) {
 
62
        last_group_list_item = last_group_list_item->next;
 
63
    }
 
64
 
 
65
    /* create, init, and insert the new node for the linked list */
 
66
    new_group_list_item = malloc(sizeof(comex_igroup_t));
 
67
    new_group_list_item->id = last_group_list_item->id + 1;
 
68
    new_group_list_item->next = NULL;
 
69
    last_group_list_item->next = new_group_list_item;
 
70
 
 
71
    /* return the group id and comex_igroup_t */
 
72
    *igroup = new_group_list_item;
 
73
    *id = new_group_list_item->id;
 
74
}
 
75
 
 
76
 
 
77
/**
 
78
 * Returns the rank of this process within the given group.
 
79
 */
 
80
int comex_group_rank(comex_group_t id, int *rank)
 
81
{
 
82
    int status;
 
83
 
 
84
    comex_igroup_t *igroup = comex_get_igroup_from_group(id);
 
85
    status = MPI_Group_rank(igroup->group, rank);
 
86
    if (status != MPI_SUCCESS) {
 
87
        comex_error("MPI_Group_rank: Failed ", status);
 
88
    }
 
89
 
 
90
    return COMEX_SUCCESS;
 
91
}
 
92
 
 
93
 
 
94
/**
 
95
 * Returns the size of a group.
 
96
 */
 
97
int comex_group_size(comex_group_t id, int *size)
 
98
{
 
99
    int status;
 
100
 
 
101
    comex_igroup_t *igroup = comex_get_igroup_from_group(id);
 
102
    status = MPI_Group_size(igroup->group, size);
 
103
    if (status != MPI_SUCCESS) {
 
104
        comex_error("MPI_Group_size: Failed ", status);
 
105
    }
 
106
 
 
107
    return COMEX_SUCCESS;
 
108
}
 
109
 
 
110
 
 
111
int comex_group_comm(comex_group_t group, MPI_Comm *comm)
 
112
{
 
113
    comex_igroup_t *igroup = comex_get_igroup_from_group(group);
 
114
    *comm = igroup->comm;
 
115
 
 
116
    return COMEX_SUCCESS;
 
117
}
 
118
 
 
119
 
 
120
/**
 
121
 * Translates the given rank from the given group into that of the world group.
 
122
 */
 
123
int comex_group_translate_world(comex_group_t id, int group_rank, int *world_rank)
 
124
{
 
125
    int status;
 
126
    MPI_Group world_group;
 
127
    comex_igroup_t *igroup = comex_get_igroup_from_group(id);
 
128
 
 
129
    status = MPI_Comm_group(l_state.world_comm, &world_group);
 
130
    if (status != MPI_SUCCESS) {
 
131
        comex_error("MPI_Comm_group: Failed ", status);
 
132
    }
 
133
    status = MPI_Group_translate_ranks(
 
134
            igroup->group, 1, &group_rank, world_group, world_rank);
 
135
    if (status != MPI_SUCCESS) {
 
136
        comex_error("MPI_Group_translate_ranks: Failed ", status);
 
137
    }
 
138
 
 
139
    return COMEX_SUCCESS;
 
140
}
 
141
 
 
142
 
 
143
/**
 
144
 * Sets the default comex_group_t.
 
145
 */
 
146
void comex_group_set_default(comex_group_t id) 
 
147
{
 
148
    /* sanity check that the group is valid */
 
149
    comex_igroup_t *igroup = comex_get_igroup_from_group(id);
 
150
    assert(NULL != igroup);
 
151
    COMEX_Default_Proc_Group = id;
 
152
}
 
153
 
 
154
 
 
155
/**
 
156
 * Gets the default comex_group_t.
 
157
 */
 
158
void comex_group_get_default(comex_group_t *group_out)
 
159
{
 
160
    *group_out = COMEX_Default_Proc_Group;
 
161
}
 
162
 
 
163
 
 
164
/**
 
165
 * Gets the world comex_group_t.
 
166
 */
 
167
void comex_group_get_world(comex_group_t *group_out)
 
168
{
 
169
    *group_out = COMEX_World_Proc_Group;
 
170
}
 
171
 
 
172
 
 
173
/**
 
174
 * Destroys the given comex_igroup_t.
 
175
 */
 
176
static void comex_igroup_finalize(comex_igroup_t *igroup)
 
177
{
 
178
    int status;
 
179
 
 
180
    assert(igroup);
 
181
 
 
182
    status = MPI_Group_free(&igroup->group);
 
183
    if (status != MPI_SUCCESS) {
 
184
        comex_error("MPI_Group_free: Failed ", status);
 
185
    }
 
186
    
 
187
    if (igroup->comm != MPI_COMM_NULL) {
 
188
      status = MPI_Comm_free(&igroup->comm);
 
189
      if (status != MPI_SUCCESS) {
 
190
          comex_error("MPI_Comm_free: Failed ", status);
 
191
      }
 
192
    }
 
193
}
 
194
 
 
195
 
 
196
/**
 
197
 * Removes and destroys the given comex_group_t from the group linked list.
 
198
 */
 
199
int comex_group_free(comex_group_t id)
 
200
{
 
201
    comex_igroup_t *current_group_list_item = group_list;
 
202
    comex_igroup_t *previous_group_list_item = NULL;
 
203
 
 
204
    /* find the group to free */
 
205
    while (current_group_list_item != NULL) {
 
206
        if (current_group_list_item->id == id) {
 
207
            break;
 
208
        }
 
209
        previous_group_list_item = current_group_list_item;
 
210
        current_group_list_item = current_group_list_item->next;
 
211
    }
 
212
    /* make sure we found a group */
 
213
    assert(current_group_list_item != NULL);
 
214
    /* remove the group from the linked list */
 
215
    if (previous_group_list_item != NULL) {
 
216
        previous_group_list_item->next = current_group_list_item->next;
 
217
    }
 
218
    /* free the group */
 
219
    comex_igroup_finalize(current_group_list_item);
 
220
    free(current_group_list_item);
 
221
 
 
222
    return COMEX_SUCCESS;
 
223
}
 
224
 
 
225
 
 
226
/**
 
227
 * Create a child group for to the given group.
 
228
 *
 
229
 * @param[in] n #procs in this group (<= that in group_parent)
 
230
 * @param[in] pid_list The list of proc ids (w.r.t. group_parent)
 
231
 * @param[out] id_child Handle to store the created group
 
232
 * @param[in] id_parent Parent group 
 
233
 */
 
234
int comex_group_create(
 
235
        int n, int *pid_list, comex_group_t id_parent, comex_group_t *id_child)
 
236
{
 
237
    int status;
 
238
    int grp_me;
 
239
    comex_igroup_t *igroup_child = NULL;
 
240
    MPI_Group    *group_child = NULL;
 
241
    MPI_Comm     *comm_child = NULL;
 
242
    comex_igroup_t *igroup_parent = NULL;
 
243
    MPI_Group    *group_parent = NULL;
 
244
    MPI_Comm     *comm_parent = NULL;
 
245
 
 
246
    /* create the node in the linked list of groups and */
 
247
    /* get the child's MPI_Group and MPI_Comm, to be populated shortly */
 
248
    comex_create_group_and_igroup(id_child, &igroup_child);
 
249
    group_child = &(igroup_child->group);
 
250
    comm_child  = &(igroup_child->comm);
 
251
 
 
252
    /* get the parent's MPI_Group and MPI_Comm */
 
253
    igroup_parent = comex_get_igroup_from_group(id_parent);
 
254
    group_parent = &(igroup_parent->group);
 
255
    comm_parent  = &(igroup_parent->comm);
 
256
 
 
257
    status = MPI_Group_incl(*group_parent, n, pid_list, group_child);
 
258
    if (status != MPI_SUCCESS) {
 
259
        comex_error("MPI_Group_incl: Failed ", status);
 
260
    }
 
261
 
 
262
    {
 
263
        MPI_Comm comm, comm1, comm2;
 
264
        int lvl=1, local_ldr_pos;
 
265
        MPI_Group_rank(*group_child, &grp_me);
 
266
        if (grp_me == MPI_UNDEFINED) {
 
267
            *comm_child = MPI_COMM_NULL;
 
268
            /* FIXME: keeping the group around for now */
 
269
            return COMEX_SUCCESS;
 
270
        }
 
271
        /* SK: sanity check for the following bitwise operations */
 
272
        assert(grp_me>=0);
 
273
        MPI_Comm_dup(MPI_COMM_SELF, &comm); /* FIXME: can be optimized away */
 
274
        local_ldr_pos = grp_me;
 
275
        while(n>lvl) {
 
276
            int tag=0;
 
277
            int remote_ldr_pos = local_ldr_pos^lvl;
 
278
            if (remote_ldr_pos < n) {
 
279
                int remote_leader = pid_list[remote_ldr_pos];
 
280
                MPI_Comm peer_comm = *comm_parent;
 
281
                int high = (local_ldr_pos<remote_ldr_pos)?0:1;
 
282
                MPI_Intercomm_create(
 
283
                        comm, 0, peer_comm, remote_leader, tag, &comm1);
 
284
                MPI_Comm_free(&comm);
 
285
                MPI_Intercomm_merge(comm1, high, &comm2);
 
286
                MPI_Comm_free(&comm1);
 
287
                comm = comm2;
 
288
            }
 
289
            local_ldr_pos &= ((~0)^lvl);
 
290
            lvl<<=1;
 
291
        }
 
292
        *comm_child = comm;
 
293
        /* cleanup temporary group (from MPI_Group_incl above) */
 
294
        MPI_Group_free(group_child);
 
295
        /* get the actual group associated with comm */
 
296
        MPI_Comm_group(*comm_child, group_child);
 
297
    }
 
298
 
 
299
    return COMEX_SUCCESS;
 
300
}
 
301
 
 
302
 
 
303
/**
 
304
 * Initialize group linked list. Prepopulate with world group.
 
305
 */
 
306
void comex_group_init() 
 
307
{
 
308
    /* Initially, World group is the default group */
 
309
    COMEX_World_Proc_Group = 0;
 
310
    COMEX_Default_Proc_Group = 0;
 
311
 
 
312
    /* create the head of the group linked list */
 
313
    assert(group_list == NULL);
 
314
    group_list = malloc(sizeof(comex_igroup_t));
 
315
    group_list->id = COMEX_World_Proc_Group;
 
316
    group_list->next = NULL;
 
317
 
 
318
    /* save MPI world group and communicatior in COMEX_World_Proc_Group */
 
319
    group_list->comm = l_state.world_comm;
 
320
    MPI_Comm_group(l_state.world_comm, &(group_list->group));
 
321
}
 
322
 
 
323
 
 
324
void comex_group_finalize()
 
325
{
 
326
    comex_igroup_t *current_group_list_item = group_list;
 
327
    comex_igroup_t *previous_group_list_item = NULL;
 
328
 
 
329
    /* don't free the world group (the list head) */
 
330
    current_group_list_item = current_group_list_item->next;
 
331
 
 
332
    while (current_group_list_item != NULL) {
 
333
        previous_group_list_item = current_group_list_item;
 
334
        current_group_list_item = current_group_list_item->next;
 
335
        comex_igroup_finalize(previous_group_list_item);
 
336
        free(previous_group_list_item);
 
337
    }
 
338
}