aboutsummaryrefslogtreecommitdiff
path: root/src/PostSendGA.c
blob: b462c5233d4c64c2000bd9b7075b6988c87f63ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
 /*@@
   @file      PostSendGA.c
   @date      Wed  Feb  2 11:58:14 2000
   @author    Gabrielle Allen
   @desc 
   The send of the three-way pugh communcations branch
   which is @seefile PostReceiveGA.c, @seefile PostSendGA.c
   and @seefile FinishReceiveGA.c. See the documentation for
   @seeroutine PostSendGA for details on this routine.
   @enddesc 
   @version $Header$
 @@*/

/* #define DEBUG_PUGH 1 */

#include <stdio.h>
#include <string.h>

#include "cctk.h"
#include "pugh.h"

static const char *rcsid = "$Header$";

CCTK_FILEVERSION(CactusPUGH_PUGH_PostSendGA_c);

#ifdef CCTK_MPI

void PostSendGA(pGH *pughGH, int dir, pComm *comm);

 /*@@
   @routine    PostSendGA
   @date       Thu Apr  3 11:58:59 1997
   @author     Paul Walker
   @desc 
   This routine posts an asyncronous MPI send of a buffer
   for a face (MPI_Isend). It does this by first packing up
   a send buffer (allocated in @seeroutine PUGH_SetupGArrayGroupComm) then
   sending it out on the pipe.
   <p>
   Since this is an asynchronous communications model we
   assume that a recieve has been posted for the send.
   thus the correct calling order for this is as in
   @seeroutine PUGH_Sync, eg, after a Recv.
   <p>
   Note this does <b>not</b> wait on the send buffer from previous
   communications. It is the users responsibility to wait on
   that buffer.
   @enddesc 
   @calledby   PUGH_Sync
   @history
   @hdate Nov 4 1998 @hauthor Gabrielle Allen
   @hdesc Allow for forced synchronization of all GFs with storage
   @endhistory
@@*/

void PostSendGA(pGH *pughGH, int dir, pComm *comm)
{
  pGA *GA;
  int stag, dircomp;
  int neighbour;
  int i, dim, copy_bytes, offset;
  char *copy_from, *copy_to;
  int *istart, *iend, *iterator;


  GA = (pGA *) pughGH->variables[comm->first_var][0];

  /* return if no storage assigned */
  if (! GA->storage)
  {
    return;
  }

  /* return if communication not required and no forced synchronisation */
  if (! (pughGH->forceSync || comm->docomm[dir]))
  {
    return;
  }

  /* return if there is no neighbour in the given direction */
  neighbour = GA->connectivity->neighbours[pughGH->myproc][dir];
  if (neighbour < 0)
  {
    return;
  }

  dircomp = dir+1;                /* Complementary direction */
  if (dircomp % 2 == 0) 
  {
    dircomp = dir-1;
  }

  /* note this is the complement of the rtag set in PostReceiveGA */
  stag = 1000 + dircomp + 2 * (neighbour + pughGH->nprocs * GA->id);
  /* mod the tag to force MPI compliance */
  stag = stag % 32768;

#ifdef DEBUG_PUGH
  printf ("PostSendGA: into direction %d to proc %d with stag %d size %d for "
          "%d vars starting with '%s'\n",
          dir, neighbour, stag, comm->buffer_sz[dir], comm->n_vars, GA->name);
#endif

  if (pughGH->commmodel == PUGH_ALLOCATEDBUFFERS) 
  {
    istart   = GA->extras->overlap[0][dir];
    iend     = GA->extras->overlap[1][dir];
    iterator = GA->extras->iterator;

    if (iend[0] > GA->extras->nsize[0])
    {
      CCTK_WARN (CCTK_WARN_ABORT, "Internal error in communication descriptor: Trying to send data that don't exist. (This may happen if a process has too few grid points.)");
    }

    /* set iterator to the start vector */
    for(dim = 0; dim < GA->extras->dim; dim++)
    {
      iterator[dim] = istart[dim];
    }

    /* get the source and the number of bytes to copy in the lowest dimension */
    copy_to    = comm->send_buffer[dir];
    copy_bytes = (iend[0] - istart[0]) * GA->varsize;

    /* now do the nested loops starting with the innermost */
    dim = 1;
    while (1)
    {
      /* check for end of current loop */
      if (GA->extras->dim > 1 && iterator[dim] >= iend[dim])
      {
        /* increment outermost loopers */
        for (dim++; dim < GA->extras->dim; dim++)
        {
          iterator[dim]++;
          if (iterator[dim] < iend[dim])
          {
            break;
          }
        }

        /* done if beyond outermost loop */
        if (dim >= GA->extras->dim)
        {
          break;
        }

        /* reset innermost loopers */
        for (dim--; dim > 0; dim--)
        {
          iterator[dim] = istart[dim];
        }
        dim = 1;
      }

      /* get the linear offset */
      offset = istart[0];
      for (i = 1; i < GA->extras->dim; i++)
      {
        offset += iterator[i] * GA->extras->hyper_volume[i];
      }
      offset *= GA->varsize;

      /* copy the data in dimension 0 */
      for (i = comm->first_var; i < comm->first_var + comm->n_vars; i++)
      {
        copy_from = ((pGA *) pughGH->variables[i][comm->sync_timelevel])->data;
        memcpy (copy_to, copy_from + offset, copy_bytes);
        copy_to += copy_bytes;
      }

      if (GA->extras->dim > 1)
      {
        /* increment current looper */ 
        iterator[dim]++;
      }
      else
      {
        /* exit loop if array dim is 1D */
        break;
      }

    } /* end of nested loops over all dimensions */

    /* now post send */
    CACTUS_MPI_ERROR (MPI_Isend (comm->send_buffer[dir],
                                 comm->buffer_sz[dir], comm->mpi_type,
                                 neighbour, stag,
                                 pughGH->PUGH_COMM_WORLD, &comm->sreq[dir]));
  }
#ifdef PUGH_WITH_DERIVED_DATATYPES
  else if (pughGH->commmodel == PUGH_DERIVEDTYPES)
  {
    int var;
    MPI_Datatype *send_dt;


    switch (GA->vtype) 
    {

      case CCTK_VARIABLE_BYTE:
        send_dt = pughGH->send_char_dt;
        break;

      case CCTK_VARIABLE_INT:
        send_dt = pughGH->send_int_dt;
        break;

      case CCTK_VARIABLE_REAL:
        send_dt = pughGH->send_real_dt;
        break;

      case CCTK_VARIABLE_COMPLEX:
        send_dt = pughGH->send_complex_dt;
        break;

      default:
        CCTK_WARN (1, "Unknown variable type in PostSendGA");
        return;

    }

    for (var = comm->first_var; var < comm->first_var + comm->n_vars; var++)
    {
      pGA *GA = (pGA *) pughGH->variables[var][comm->sync_timelevel];


      CACTUS_MPI_ERROR (MPI_Isend (GA->data,
                                   1, send_dt[dir],
                                   neighbour, (stag + var) % 32768,
                                   pughGH->PUGH_COMM_WORLD,
                                   &GA->comm->sreq[dir]));
      CACTUS_MPI_ERROR (MPI_Request_free (&comm->sreq[dir]));
    }
  }
#endif
}
#endif /* CCTK_MPI */