pio_server.c 36.3 KB
Newer Older
Deike Kleberg's avatar
Deike Kleberg committed
1
2
/** @file ioServer.c
*/
3
4
5
6
7
8
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#ifdef USE_MPI

Deike Kleberg's avatar
Deike Kleberg committed
9
10
11
#include "pio_server.h"


12
#include <limits.h>
Deike Kleberg's avatar
Deike Kleberg committed
13
14
#include <stdlib.h>
#include <stdio.h>
15
16
17
18
19
20

#ifdef HAVE_PARALLEL_NC4
#include <core/ppm_combinatorics.h>
#include <core/ppm_rectilinear.h>
#include <ppm/ppm_uniform_partition.h>
#endif
21
#include <yaxt.h>
22

Deike Kleberg's avatar
Deike Kleberg committed
23
#include "cdi.h"
24
#include "namespace.h"
Deike Kleberg's avatar
Deike Kleberg committed
25
#include "pio.h"
Deike Kleberg's avatar
Deike Kleberg committed
26
#include "pio_comm.h"
27
#include "pio_interface.h"
Deike Kleberg's avatar
Deike Kleberg committed
28
#include "pio_rpc.h"
Deike Kleberg's avatar
Deike Kleberg committed
29
#include "pio_util.h"
30
#include "cdi_int.h"
31
#include "pio_cdf_int.h"
32
#include "resource_handle.h"
33
#include "resource_unpack.h"
Thomas Jahns's avatar
Thomas Jahns committed
34
#include "stream_cdf.h"
Deike Kleberg's avatar
Deike Kleberg committed
35
#include "vlist_var.h"
36

37

38
extern resOps streamOps;
39
extern void arrayDestroy ( void );
Deike Kleberg's avatar
Deike Kleberg committed
40

41
42
43
static struct
{
  size_t size;
Thomas Jahns's avatar
Thomas Jahns committed
44
  unsigned char *buffer;
45
  int dictSize;
46
47
} *rxWin = NULL;

Thomas Jahns's avatar
Thomas Jahns committed
48
static MPI_Win getWin = MPI_WIN_NULL;
Thomas Jahns's avatar
Thomas Jahns committed
49
static MPI_Group groupModel = MPI_GROUP_NULL;
Deike Kleberg's avatar
Deike Kleberg committed
50

51
52
53
54
55
#ifdef HAVE_PARALLEL_NC4
/* prime factorization of number of pio collectors */
static uint32_t *pioPrimes;
static int numPioPrimes;
#endif
Deike Kleberg's avatar
Deike Kleberg committed
56

Deike Kleberg's avatar
Deike Kleberg committed
57
58
/************************************************************************/

59
static
Deike Kleberg's avatar
Deike Kleberg committed
60
61
void serverWinCleanup ()
{
62
63
  if (getWin != MPI_WIN_NULL)
    xmpi(MPI_Win_free(&getWin));
64
65
  if (rxWin)
    {
66
      free(rxWin[0].buffer);
67
      free(rxWin);
Deike Kleberg's avatar
Deike Kleberg committed
68
    }
69

70
  xdebug("%s", "cleaned up mpi_win");
Deike Kleberg's avatar
Deike Kleberg committed
71
}
72

Deike Kleberg's avatar
Deike Kleberg committed
73
 /************************************************************************/
74

75
76
static size_t
collDefBufferSizes()
Deike Kleberg's avatar
Deike Kleberg committed
77
{
78
  int nstreams, * streamIndexList, streamNo, vlistID, nvars, varID, iorank;
79
80
  int modelID;
  size_t sumGetBufferSizes = 0;
81
  int rankGlob = commInqRankGlob ();
Deike Kleberg's avatar
Deike Kleberg committed
82
  int nProcsModel = commInqNProcsModel ();
83
  int root = commInqRootGlob ();
Deike Kleberg's avatar
Deike Kleberg committed
84

85
  xassert(rxWin != NULL);
Deike Kleberg's avatar
Deike Kleberg committed
86

Deike Kleberg's avatar
Deike Kleberg committed
87
  nstreams = reshCountType ( &streamOps );
88
89
  streamIndexList = xmalloc ( nstreams * sizeof ( streamIndexList[0] ));
  reshGetResHListOfType ( nstreams, streamIndexList, &streamOps );
Deike Kleberg's avatar
Deike Kleberg committed
90
91
  for ( streamNo = 0; streamNo < nstreams; streamNo++ )
    {
92
      // space required for data
93
      vlistID = streamInqVlist ( streamIndexList[streamNo] );
Deike Kleberg's avatar
Deike Kleberg committed
94
95
96
97
      nvars = vlistNvars ( vlistID );
      for ( varID = 0; varID < nvars; varID++ )
        {
          iorank = vlistInqVarIOrank ( vlistID, varID );
Deike Kleberg's avatar
Deike Kleberg committed
98
          xassert ( iorank != CDI_UNDEFID );
Deike Kleberg's avatar
Deike Kleberg committed
99
100
          if ( iorank == rankGlob )
            {
Deike Kleberg's avatar
Deike Kleberg committed
101
              for ( modelID = 0; modelID < nProcsModel; modelID++ )
102
                {
103
104
105
106
107
108
109
110
                  int decoChunk;
                  {
                    int varSize = vlistInqVarSize(vlistID, varID);
                    int nProcsModel = commInqNProcsModel();
                    decoChunk =
                      (int)ceilf(cdiPIOpartInflate_
                                 * (varSize + nProcsModel - 1)/nProcsModel);
                  }
Deike Kleberg's avatar
Deike Kleberg committed
111
                  xassert ( decoChunk > 0 );
112
                  rxWin[modelID].size += decoChunk * sizeof (double)
113
114
115
116
117
118
119
120
                    /* re-align chunks to multiple of double size */
                    + sizeof (double) - 1
                    /* one header for data record, one for
                     * corresponding part descriptor*/
                    + 2 * sizeof (union winHeaderEntry)
                    /* FIXME: heuristic for size of packed Xt_idxlist */
                    + sizeof (Xt_int) * decoChunk * 3;
                  rxWin[modelID].dictSize += 2;
121
                }
Deike Kleberg's avatar
Deike Kleberg committed
122
            }
123
        }
Deike Kleberg's avatar
Deike Kleberg committed
124
125
      // space required for the 3 function calls streamOpen, streamDefVlist, streamClose 
      // once per stream and timestep for all collprocs only on the modelproc root
126
127
      rxWin[root].size += 3 * sizeof (union winHeaderEntry)
        + MAXDATAFILENAME;
128
      rxWin[root].dictSize += 3;
Deike Kleberg's avatar
Deike Kleberg committed
129
    }
130
  free ( streamIndexList );
Deike Kleberg's avatar
Deike Kleberg committed
131
132

  for ( modelID = 0; modelID < nProcsModel; modelID++ )
133
    {
134
      /* account for size header */
135
      rxWin[modelID].dictSize += 1;
136
      rxWin[modelID].size += sizeof (union winHeaderEntry);
137
138
139
      rxWin[modelID].size = roundUpToMultiple(rxWin[modelID].size,
                                              PIO_WIN_ALIGN);
      sumGetBufferSizes += (size_t)rxWin[modelID].size;
140
    }
Deike Kleberg's avatar
Deike Kleberg committed
141
  xassert ( sumGetBufferSizes <= MAXWINBUFFERSIZE );
142
  return sumGetBufferSizes;
Deike Kleberg's avatar
Deike Kleberg committed
143
}
144

Deike Kleberg's avatar
Deike Kleberg committed
145
 /************************************************************************/
146
147

static 
Deike Kleberg's avatar
Deike Kleberg committed
148
149
 void serverWinCreate ()
{ 
Deike Kleberg's avatar
Deike Kleberg committed
150
  int ranks[1], modelID;
151
  MPI_Comm commCalc = commInqCommCalc ();
Deike Kleberg's avatar
Deike Kleberg committed
152
  MPI_Group groupCalc;
153
  int nProcsModel = commInqNProcsModel ();
Deike Kleberg's avatar
Deike Kleberg committed
154

Deike Kleberg's avatar
Deike Kleberg committed
155
  xmpi ( MPI_Win_create ( MPI_BOTTOM, 0, 1, MPI_INFO_NULL,
156
                          commCalc, &getWin ));
Deike Kleberg's avatar
Deike Kleberg committed
157
158

  /* target group */
159
160
  ranks[0] = nProcsModel;
  xmpi ( MPI_Comm_group ( commCalc, &groupCalc ));
Deike Kleberg's avatar
Deike Kleberg committed
161
162
  xmpi ( MPI_Group_excl ( groupCalc, 1, ranks, &groupModel ));

163
  rxWin = xcalloc(nProcsModel, sizeof (rxWin[0]));
164
165
166
167
168
169
170
171
  size_t totalBufferSize = collDefBufferSizes();
  rxWin[0].buffer = xmalloc(totalBufferSize);
  size_t ofs = 0;
  for ( modelID = 1; modelID < nProcsModel; modelID++ )
    {
      ofs += rxWin[modelID - 1].size;
      rxWin[modelID].buffer = rxWin[0].buffer + ofs;
    }
Deike Kleberg's avatar
Deike Kleberg committed
172

173
  xdebug("%s", "created mpi_win, allocated getBuffer");
Deike Kleberg's avatar
Deike Kleberg committed
174
175
}

Deike Kleberg's avatar
Deike Kleberg committed
176
177
/************************************************************************/

178
179
static void
readFuncCall(struct funcCallDesc *header)
Deike Kleberg's avatar
Deike Kleberg committed
180
181
{
  int root = commInqRootGlob ();
182
  int funcID = header->funcID;
Deike Kleberg's avatar
Deike Kleberg committed
183

184
  xassert(funcID >= MINFUNCID && funcID <= MAXFUNCID);
Deike Kleberg's avatar
Deike Kleberg committed
185
186
  switch ( funcID )
    {
187
188
    case STREAMCLOSE:
      {
189
190
        int streamID
          = namespaceAdaptKey2(header->funcArgs.streamChange.streamID);
191
192
193
194
        streamClose(streamID);
        xdebug("READ FUNCTION CALL FROM WIN:  %s, streamID=%d,"
               " closed stream",
               funcMap[(-1 - funcID)], streamID);
195
196
      }
      break;
Deike Kleberg's avatar
Deike Kleberg committed
197
    case STREAMOPEN:
198
      {
199
        size_t filenamesz = header->funcArgs.newFile.fnamelen;
Deike Kleberg's avatar
Deike Kleberg committed
200
        xassert ( filenamesz > 0 && filenamesz < MAXDATAFILENAME );
201
202
203
204
205
206
        const char *filename
          = (const char *)(rxWin[root].buffer
                           + header->funcArgs.newFile.offset);
        xassert(filename[filenamesz] == '\0');
        int filetype = header->funcArgs.newFile.filetype;
        int streamID = streamOpenWrite(filename, filetype);
207
        xassert(streamID != CDI_ELIBNAVAIL);
208
209
        xdebug("READ FUNCTION CALL FROM WIN:  %s, filenamesz=%zu,"
               " filename=%s, filetype=%d, OPENED STREAM %d",
210
               funcMap[(-1 - funcID)], filenamesz, filename,
211
               filetype, streamID);
212
      }
213
      break;
214
215
    case STREAMDEFVLIST:
      {
216
217
218
        int streamID
          = namespaceAdaptKey2(header->funcArgs.streamChange.streamID);
        int vlistID = namespaceAdaptKey2(header->funcArgs.streamChange.vlistID);
219
220
221
222
        streamDefVlist(streamID, vlistID);
        xdebug("READ FUNCTION CALL FROM WIN:  %s, streamID=%d,"
               " vlistID=%d, called streamDefVlist ().",
               funcMap[(-1 - funcID)], streamID, vlistID);
223
224
      }
      break;
Deike Kleberg's avatar
Deike Kleberg committed
225
    default:
226
      xabort ( "REMOTE FUNCTIONCALL NOT IMPLEMENTED!" );
Deike Kleberg's avatar
Deike Kleberg committed
227
228
229
230
231
    }
}

/************************************************************************/

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
static void
resizeVarGatherBuf(int vlistID, int varID, double **buf, int *bufSize)
{
  int size = vlistInqVarSize(vlistID, varID);
  if (size <= *bufSize) ; else
    *buf = xrealloc(*buf, (*bufSize = size) * sizeof (buf[0][0]));
}

static void
gatherArray(int root, int nProcsModel, int headerIdx,
            int vlistID,
            double *gatherBuf, int *nmiss)
{
  union winHeaderEntry *winDict
    = (union winHeaderEntry *)rxWin[root].buffer;
  int streamID = winDict[headerIdx].dataRecord.streamID;
  int varID = winDict[headerIdx].dataRecord.varID;
249
  int varShape[3] = { 0, 0, 0 };
250
  cdiPioQueryVarDims(varShape, vlistID, varID);
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  Xt_int varShapeXt[3];
  static const Xt_int origin[3] = { 0, 0, 0 };
  for (unsigned i = 0; i < 3; ++i)
    varShapeXt[i] = varShape[i];
  int varSize = varShape[0] * varShape[1] * varShape[2];
  int *partOfs = xmalloc(2 * varSize * sizeof (partOfs[0])),
    *gatherOfs = partOfs + varSize;
  Xt_idxlist *part = xmalloc(nProcsModel * sizeof (part[0]));
  MPI_Comm commCalc = commInqCommCalc();
  {
    int nmiss_ = 0, partOfsOfs = 0;
    for (int modelID = 0; modelID < nProcsModel; modelID++)
      {
        struct dataRecord *dataHeader
          = &((union winHeaderEntry *)
              rxWin[modelID].buffer)[headerIdx].dataRecord;
        struct partDescRecord *partHeader
          = &((union winHeaderEntry *)
              rxWin[modelID].buffer)[headerIdx + 1].partDesc;
        int position = partHeader->offset;
271
        xassert(namespaceAdaptKey2(dataHeader->streamID) == streamID
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
                && dataHeader->varID == varID
                && partHeader->partDescMarker == PARTDESCMARKER
                && position > 0
                && ((size_t)position
                    >= sizeof (union winHeaderEntry) * rxWin[modelID].dictSize)
                && ((size_t)position < rxWin[modelID].size));
        part[modelID] = xt_idxlist_unpack(rxWin[modelID].buffer,
                                          (int)rxWin[modelID].size,
                                          &position, commCalc);
        Xt_int partSize = xt_idxlist_get_num_indices(part[modelID]);
        size_t charOfs = (rxWin[modelID].buffer + dataHeader->offset)
          - rxWin[0].buffer;
        xassert(charOfs % sizeof (double) == 0
                && charOfs / sizeof (double) + partSize <= INT_MAX);
        int elemOfs = charOfs / sizeof (double);
        for (int i = 0; i < (int)partSize; ++i)
          partOfs[partOfsOfs + i] = elemOfs + i;
        partOfsOfs += partSize;
        nmiss_ += dataHeader->nmiss;
      }
    *nmiss = nmiss_;
  }
  Xt_idxlist srcList = xt_idxlist_collection_new(part, nProcsModel);
295
  for (int modelID = 0; modelID < nProcsModel; modelID++)
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
    xt_idxlist_delete(part[modelID]);
  free(part);
  Xt_xmap gatherXmap;
  {
    Xt_idxlist dstList
      = xt_idxsection_new(0, 3, varShapeXt, varShapeXt, origin);
    struct Xt_com_list full = { .list = dstList, .rank = 0 };
    gatherXmap = xt_xmap_intersection_new(1, &full, 1, &full, srcList, dstList,
                                        MPI_COMM_SELF);
    xt_idxlist_delete(dstList);
  }
  xt_idxlist_delete(srcList);
  for (int i = 0; i < varSize; ++i)
    gatherOfs[i] = i;

  Xt_redist gatherRedist
    = xt_redist_p2p_off_new(gatherXmap, partOfs, gatherOfs, MPI_DOUBLE);
  xt_xmap_delete(gatherXmap);
314
  xt_redist_s_exchange1(gatherRedist, rxWin[0].buffer, gatherBuf);
315
316
  free(partOfs);
  xt_redist_delete(gatherRedist);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
}

struct xyzDims
{
  int sizes[3];
};

static inline int
xyzGridSize(struct xyzDims dims)
{
  return dims.sizes[0] * dims.sizes[1] * dims.sizes[2];
}

#ifdef HAVE_PARALLEL_NC4
static void
332
queryVarBounds(struct PPM_extent varShape[3], int vlistID, int varID)
333
{
334
335
  varShape[0].first = 0;
  varShape[1].first = 0;
336
  varShape[2].first = 0;
337
  int sizes[3];
338
  cdiPioQueryVarDims(sizes, vlistID, varID);
339
340
  for (unsigned i = 0; i < 3; ++i)
    varShape[i].size = sizes[i];
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
}

/* compute distribution of collectors such that number of collectors
 * <= number of variable grid cells in each dimension */
static struct xyzDims
varDimsCollGridMatch(const struct PPM_extent varDims[3])
{
  xassert(PPM_extents_size(3, varDims) >= commInqSizeColl());
  struct xyzDims collGrid = { { 1, 1, 1 } };
  /* because of storage order, dividing dimension 3 first is preferred */
  for (int i = 0; i < numPioPrimes; ++i)
    {
      for (int dim = 2; dim >=0; --dim)
        if (collGrid.sizes[dim] * pioPrimes[i] <= varDims[dim].size)
          {
            collGrid.sizes[dim] *= pioPrimes[i];
            goto nextPrime;
          }
      /* no position found, retrack */
      xabort("Not yet implemented back-tracking needed.");
      nextPrime:
      ;
    }
  return collGrid;
}

static void
myVarPart(struct PPM_extent varShape[3], struct xyzDims collGrid,
          struct PPM_extent myPart[3])
{
  int32_t myCollGridCoord[3];
  {
    struct PPM_extent collGridShape[3];
    for (int i = 0; i < 3; ++i)
      {
        collGridShape[i].first = 0;
        collGridShape[i].size = collGrid.sizes[i];
      }
    PPM_lidx2rlcoord_e(3, collGridShape, commInqRankColl(), myCollGridCoord);
    xdebug("my coord: (%d, %d, %d)", myCollGridCoord[0], myCollGridCoord[1],
           myCollGridCoord[2]);
  }
  PPM_uniform_partition_nd(3, varShape, collGrid.sizes,
                           myCollGridCoord, myPart);
}
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
#elif defined (HAVE_LIBNETCDF)
/* needed for writing when some files are only written to by a single process */
/* cdiOpenFileMap(fileID) gives the writer process */
int cdiPioSerialOpenFileMap(int streamID)
{
  return stream_to_pointer(streamID)->ownerRank;
}
/* for load-balancing purposes, count number of files per process */
/* cdiOpenFileCounts[rank] gives number of open files rank has to himself */
static int *cdiSerialOpenFileCount = NULL;
int cdiPioNextOpenRank()
{
  xassert(cdiSerialOpenFileCount != NULL);
  int commCollSize = commInqSizeColl();
  int minRank = 0, minOpenCount = cdiSerialOpenFileCount[0];
  for (int i = 1; i < commCollSize; ++i)
    if (cdiSerialOpenFileCount[i] < minOpenCount)
      {
        minOpenCount = cdiSerialOpenFileCount[i];
        minRank = i;
      }
  return minRank;
}

void cdiPioOpenFileOnRank(int rank)
{
  xassert(cdiSerialOpenFileCount != NULL
          && rank >= 0 && rank < commInqSizeColl());
  ++(cdiSerialOpenFileCount[rank]);
}


void cdiPioCloseFileOnRank(int rank)
{
  xassert(cdiSerialOpenFileCount != NULL
          && rank >= 0 && rank < commInqSizeColl());
  xassert(cdiSerialOpenFileCount[rank] > 0);
  --(cdiSerialOpenFileCount[rank]);
}

426
427
#endif

Deike Kleberg's avatar
Deike Kleberg committed
428
429
430
static
void readGetBuffers ( int tsID, int vdate, int vtime )
{
431
  int nProcsModel = commInqNProcsModel ();
Deike Kleberg's avatar
Deike Kleberg committed
432
  int root        = commInqRootGlob ();
433
#ifdef HAVE_NETCDF4
434
  int myCollRank = commInqRankColl();
435
  MPI_Comm collComm = commInqCommColl();
436
#endif
437
  xdebug("%s", "START");
438

439
440
441
  union winHeaderEntry *winDict
    = (union winHeaderEntry *)rxWin[root].buffer;
  xassert(winDict[0].headerSize.sizeID == HEADERSIZEMARKER);
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  {
    int dictSize = rxWin[root].dictSize,
      firstNonRPCEntry = dictSize - winDict[0].headerSize.numRPCEntries - 1,
      headerIdx,
      numFuncCalls = 0;
    for (headerIdx = dictSize - 1;
         headerIdx > firstNonRPCEntry;
         --headerIdx)
      {
        struct funcCallDesc *header
          = &(winDict[headerIdx].funcCall);
        xassert(header->funcID >= MINFUNCID
                && header->funcID <= MAXFUNCID);
        ++numFuncCalls;
        readFuncCall(header);
      }
    xassert(numFuncCalls == winDict[0].headerSize.numRPCEntries);
  }
Thomas Jahns's avatar
Thomas Jahns committed
460
  /* build list of streams, data was transferred for */
461
462
  {
    int numDataEntries = winDict[0].headerSize.numDataEntries;
Thomas Jahns's avatar
Thomas Jahns committed
463
464
    int streamIdx;
    struct {
465
      int streamID, filetype;
Thomas Jahns's avatar
Thomas Jahns committed
466
      int firstHeaderIdx, lastHeaderIdx;
467
      int numVars, *varMap;
Thomas Jahns's avatar
Thomas Jahns committed
468
469
470
471
    } *streamMap;
    int numStreamIDs = 0, sizeStreamMap = 16;
    streamMap = xmalloc(sizeStreamMap * sizeof (streamMap[0]));
    int streamIDOld = CDI_UNDEFID;
472
    int oldStreamIdx = CDI_UNDEFID;
473
    int filetype = CDI_UNDEFID;
474
    for (int headerIdx = 1; headerIdx < numDataEntries; headerIdx += 2)
475
      {
476
477
478
        int streamID
          = winDict[headerIdx].dataRecord.streamID
          = namespaceAdaptKey2(winDict[headerIdx].dataRecord.streamID);
Thomas Jahns's avatar
Thomas Jahns committed
479
480
        xassert(streamID > 0);
        if (streamID != streamIDOld)
481
          {
482
            for (int i = numStreamIDs - 1; i >= 0; --i)
Thomas Jahns's avatar
Thomas Jahns committed
483
              if ((streamIDOld = streamMap[i].streamID) == streamID)
484
485
486
487
488
                {
                  filetype = streamMap[i].filetype;
                  oldStreamIdx = i;
                  goto streamIDInventorized;
                }
Thomas Jahns's avatar
Thomas Jahns committed
489
490
491
492
493
494
            if (numStreamIDs < sizeStreamMap) ; else
              streamMap = xrealloc(streamMap,
                                   (sizeStreamMap *= 2)
                                   * sizeof (streamMap[0]));
            streamMap[numStreamIDs].streamID = streamID;
            streamMap[numStreamIDs].firstHeaderIdx = headerIdx;
495
            streamMap[numStreamIDs].numVars = -1;
Thomas Jahns's avatar
Thomas Jahns committed
496
497
            oldStreamIdx = numStreamIDs;
            streamIDOld = streamID;
498
499
500
501
502
503
504
505
506
507
508
509
510
511
            filetype = streamInqFiletype(streamID);
            streamMap[numStreamIDs].filetype = filetype;
            if (filetype == FILETYPE_NC || filetype == FILETYPE_NC2
                || filetype == FILETYPE_NC4)
              {
                int vlistID = streamInqVlist(streamID);
                int nvars = vlistNvars(vlistID);
                streamMap[numStreamIDs].numVars = nvars;
                streamMap[numStreamIDs].varMap
                  = xmalloc(sizeof (streamMap[numStreamIDs].varMap[0])
                            * nvars);
                for (int i = 0; i < nvars; ++i)
                  streamMap[numStreamIDs].varMap[i] = -1;
              }
Thomas Jahns's avatar
Thomas Jahns committed
512
            ++numStreamIDs;
513
          }
Thomas Jahns's avatar
Thomas Jahns committed
514
515
        streamIDInventorized:
        streamMap[oldStreamIdx].lastHeaderIdx = headerIdx;
516
517
518
519
520
521
        if (filetype == FILETYPE_NC || filetype == FILETYPE_NC2
                || filetype == FILETYPE_NC4)
          {
            int varID = winDict[headerIdx].dataRecord.varID;
            streamMap[oldStreamIdx].varMap[varID] = headerIdx;
          }
Thomas Jahns's avatar
Thomas Jahns committed
522
      }
523
524
525
526
    double *data = NULL;
#if defined (HAVE_PARALLEL_NC4)
    double *writeBuf = NULL;
#endif
Thomas Jahns's avatar
Thomas Jahns committed
527
528
529
530
531
    int currentDataBufSize = 0;
    for (streamIdx = 0; streamIdx < numStreamIDs; ++streamIdx)
      {
        int streamID = streamMap[streamIdx].streamID;
        int vlistID = streamInqVlist(streamID);
532
        int fileType = streamMap[streamIdx].filetype;
Thomas Jahns's avatar
Thomas Jahns committed
533
534
535
536
537
        int taxisID = vlistInqTaxis(vlistID);
        taxisDefVdate(taxisID, vdate);
        taxisDefVtime(taxisID, vtime);
        streamDefTimestep(streamID, tsID);

538
539
540
541
        switch (fileType)
          {
          case FILETYPE_GRB:
          case FILETYPE_GRB2:
Thomas Jahns's avatar
Thomas Jahns committed
542
            {
543
544
545
              int headerIdx, lastHeaderIdx = streamMap[streamIdx].lastHeaderIdx;
              for (headerIdx = streamMap[streamIdx].firstHeaderIdx;
                   headerIdx <= lastHeaderIdx;
546
                   headerIdx += 2)
547
548
549
550
                if (streamID == winDict[headerIdx].dataRecord.streamID)
                  {
                    int varID = winDict[headerIdx].dataRecord.varID;
                    int size = vlistInqVarSize(vlistID, varID);
551
552
553
554
555
                    int nmiss;
                    resizeVarGatherBuf(vlistID, varID, &data,
                                       &currentDataBufSize);
                    gatherArray(root, nProcsModel, headerIdx,
                                vlistID, data, &nmiss);
556
557
558
559
560
561
562
563
564
                    streamWriteVar(streamID, varID, data, nmiss);
                    if ( ddebug > 2 )
                      {
                        char text[1024];
                        sprintf(text, "streamID=%d, var[%d], size=%d",
                                streamID, varID, size);
                        xprintArray(text, data, size, DATATYPE_FLT);
                      }
                  }
Thomas Jahns's avatar
Thomas Jahns committed
565
            }
566
            break;
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
#ifdef HAVE_NETCDF4
          case FILETYPE_NC:
          case FILETYPE_NC2:
          case FILETYPE_NC4:
#ifdef HAVE_PARALLEL_NC4
            /* HAVE_PARALLE_NC4 implies having ScalES-PPM and yaxt */
            {
              int nvars = streamMap[streamIdx].numVars;
              int *varMap = streamMap[streamIdx].varMap;
              int *varIsWritten = xmalloc(sizeof (varIsWritten[0]) * nvars);
              for (int varID = 0; varID < nvars; ++varID)
                varIsWritten[varID] = ((varMap[varID] != -1)
                                       ?myCollRank+1 : 0);
              xmpi(MPI_Allreduce(MPI_IN_PLACE, varIsWritten, nvars,
                                 MPI_INT, MPI_BOR, collComm));
              for (int varID = 0; varID < nvars; ++varID)
                if (varIsWritten[varID])
                  {
                    struct PPM_extent varShape[3];
586
                    queryVarBounds(varShape, vlistID, varID);
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
                    struct xyzDims collGrid = varDimsCollGridMatch(varShape);
                    xdebug("writing varID %d with dimensions: "
                           "x=%d, y=%d, z=%d,\n"
                           "found distribution with dimensions:"
                           " x=%d, y=%d, z=%d.", varID,
                           varShape[0].size, varShape[1].size, varShape[2].size,
                           collGrid.sizes[0], collGrid.sizes[1],
                           collGrid.sizes[2]);
                    struct PPM_extent varChunk[3];
                    myVarPart(varShape, collGrid, varChunk);
                    int myChunk[3][2];
                    for (int i = 0; i < 3; ++i)
                      {
                        myChunk[i][0] = PPM_extent_start(varChunk[i]);
                        myChunk[i][1] = PPM_extent_end(varChunk[i]);
                      }
                    xdebug("Writing chunk { { %d, %d }, { %d, %d },"
                           " { %d, %d } }", myChunk[0][0], myChunk[0][1],
                           myChunk[1][0], myChunk[1][1], myChunk[2][0],
                           myChunk[2][1]);
                    Xt_int varSize[3];
                    for (int i = 0; i < 3; ++i)
                      varSize[2 - i] = varShape[i].size;
                    Xt_idxlist preRedistChunk, preWriteChunk;
                    /* prepare yaxt descriptor for current data
                       distribution after collect */
                    int nmiss;
                    if (varMap[varID] == -1)
                      {
                        preRedistChunk = xt_idxempty_new();
                        xdebug("%s", "I got none\n");
                      }
                    else
                      {
                        Xt_int preRedistStart[3] = { 0, 0, 0 };
                        preRedistChunk
                          = xt_idxsection_new(0, 3, varSize, varSize,
                                              preRedistStart);
                        resizeVarGatherBuf(vlistID, varID, &data,
                                           &currentDataBufSize);
                        int headerIdx = varMap[varID];
                        gatherArray(root, nProcsModel, headerIdx,
                                    vlistID, data, &nmiss);
                        xdebug("%s", "I got all\n");
                      }
                    MPI_Bcast(&nmiss, 1, MPI_INT, varIsWritten[varID] - 1,
                              collComm);
                    /* prepare yaxt descriptor for write chunk */
                    {
                      Xt_int preWriteChunkStart[3], preWriteChunkSize[3];
                      for (int i = 0; i < 3; ++i)
                        {
                          preWriteChunkStart[2 - i] = varChunk[i].first;
                          preWriteChunkSize[2 - i] = varChunk[i].size;
                        }
                      preWriteChunk = xt_idxsection_new(0, 3, varSize,
                                                        preWriteChunkSize,
                                                        preWriteChunkStart);
                    }
                    /* prepare redistribution */
                    {
                      Xt_xmap xmap = xt_xmap_all2all_new(preRedistChunk,
                                                         preWriteChunk,
                                                         collComm);
                      Xt_redist redist = xt_redist_p2p_new(xmap, MPI_DOUBLE);
                      xt_idxlist_delete(preRedistChunk);
                      xt_idxlist_delete(preWriteChunk);
                      xt_xmap_delete(xmap);
                      writeBuf = xrealloc(writeBuf,
                                          sizeof (double)
                                          * PPM_extents_size(3, varChunk));
658
                      xt_redist_s_exchange1(redist, data, writeBuf);
659
660
661
662
663
664
665
666
667
668
                      xt_redist_delete(redist);
                    }
                    /* write chunk */
                    streamWriteVarChunk(streamID, varID,
                                        (const int (*)[2])myChunk, writeBuf,
                                        nmiss);
                  }
            }
#else
            /* determine process which has stream open (writer) and
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
             * which has data for which variable (var owner)
             * three cases need to be distinguished */
            {
              int nvars = streamMap[streamIdx].numVars;
              int *varMap = streamMap[streamIdx].varMap;
              int *varIsWritten = xmalloc(sizeof (varIsWritten[0]) * nvars);
              for (int varID = 0; varID < nvars; ++varID)
                varIsWritten[varID] = ((varMap[varID] != -1)
                                       ?myCollRank+1 : 0);
              xmpi(MPI_Allreduce(MPI_IN_PLACE, varIsWritten, nvars,
                                 MPI_INT, MPI_BOR, collComm));
              int writerRank;
              if ((writerRank = cdiPioSerialOpenFileMap(streamID))
                  == myCollRank)
                {
                  for (int varID = 0; varID < nvars; ++varID)
                    if (varIsWritten[varID])
                      {
                        int nmiss;
                        int size = vlistInqVarSize(vlistID, varID);
                        resizeVarGatherBuf(vlistID, varID, &data,
                                           &currentDataBufSize);
                        int headerIdx = varMap[varID];
                        if (varIsWritten[varID] == myCollRank + 1)
                          {
                            /* this process has the full array and will
                             * write it */
                            xdebug("gathering varID=%d for direct writing",
                                   varID);
                            gatherArray(root, nProcsModel, headerIdx,
                                        vlistID, data, &nmiss);
                          }
                        else
                          {
                            /* another process has the array and will
                             * send it over */
                            MPI_Status stat;
                            xdebug("receiving varID=%d for writing from"
                                   " process %d",
                                   varID, varIsWritten[varID] - 1);
                            xmpiStat(MPI_Recv(&nmiss, 1, MPI_INT,
                                              varIsWritten[varID] - 1,
                                              COLLBUFNMISS,
                                              collComm, &stat), &stat);
                            xmpiStat(MPI_Recv(data, size, MPI_DOUBLE,
                                              varIsWritten[varID] - 1,
                                              COLLBUFTX,
                                              collComm, &stat), &stat);
                          }
                        streamWriteVar(streamID, varID, data, nmiss);
                      }
                }
              else
                for (int varID = 0; varID < nvars; ++varID)
                  if (varIsWritten[varID] == myCollRank + 1)
                    {
                      /* this process has the full array and another
                       * will write it */
                      int nmiss;
                      int size = vlistInqVarSize(vlistID, varID);
                      resizeVarGatherBuf(vlistID, varID, &data,
                                         &currentDataBufSize);
                      int headerIdx = varMap[varID];
                      gatherArray(root, nProcsModel, headerIdx,
                                  vlistID, data, &nmiss);
                      MPI_Request req;
                      MPI_Status stat;
                      xdebug("sending varID=%d for writing to"
                             " process %d",
                             varID, writerRank);
                      xmpi(MPI_Isend(&nmiss, 1, MPI_INT,
                                     writerRank, COLLBUFNMISS,
                                     collComm, &req));
                      xmpi(MPI_Send(data, size, MPI_DOUBLE,
                                    writerRank, COLLBUFTX,
                                    collComm));
                      xmpiStat(MPI_Wait(&req, &stat), &stat);
                    }
            }
748
749
750
#endif
            break;
#endif
751
752
753
          default:
            xabort("unhandled filetype in parallel I/O.");
          }
754
      }
Thomas Jahns's avatar
Thomas Jahns committed
755
756
    free(streamMap);
    free(data);
757
  }
758
  xdebug("%s", "RETURN");
759
760
761
762
} 

/************************************************************************/

Deike Kleberg's avatar
Deike Kleberg committed
763

Thomas Jahns's avatar
Thomas Jahns committed
764
765
static
void clearModelWinBuffer(int modelID)
Deike Kleberg's avatar
Deike Kleberg committed
766
767
768
{
  int nProcsModel = commInqNProcsModel ();

Deike Kleberg's avatar
Deike Kleberg committed
769
770
  xassert ( modelID                >= 0           &&
            modelID                 < nProcsModel &&
771
            rxWin != NULL && rxWin[modelID].buffer != NULL &&
772
773
            rxWin[modelID].size > 0 &&
            rxWin[modelID].size <= MAXWINBUFFERSIZE );
774
  memset(rxWin[modelID].buffer, 0, rxWin[modelID].size);
Deike Kleberg's avatar
Deike Kleberg committed
775
776
777
778
779
780
}


/************************************************************************/


781
static
Thomas Jahns's avatar
Thomas Jahns committed
782
void getTimeStepData ( int tsID, int vdate, int vtime )
Deike Kleberg's avatar
Deike Kleberg committed
783
{
784
  int modelID;
785
  char text[1024];
786
  int nProcsModel = commInqNProcsModel ();
Thomas Jahns's avatar
Thomas Jahns committed
787
788
  void *getWinBaseAddr;
  int attrFound;
789
          
790
  xdebug("%s", "START");
Deike Kleberg's avatar
Deike Kleberg committed
791
792

  // todo put in correct lbs and ubs
Deike Kleberg's avatar
Deike Kleberg committed
793
  xassert ( tsID >= 0 && vdate >= 0 && vtime >= 0 );
794
  xmpi(MPI_Win_start(groupModel, 0, getWin));
795
796
  xmpi(MPI_Win_get_attr(getWin, MPI_WIN_BASE, &getWinBaseAddr, &attrFound));
  xassert(attrFound);
Deike Kleberg's avatar
Deike Kleberg committed
797
798
  for ( modelID = 0; modelID < nProcsModel; modelID++ )
    {
Thomas Jahns's avatar
Thomas Jahns committed
799
      clearModelWinBuffer(modelID);
800
      xdebug("modelID=%d, nProcsModel=%d, rxWin[%d].size=%zu,"
Thomas Jahns's avatar
Thomas Jahns committed
801
             " getWin=%p, sizeof(int)=%u",
802
             modelID, nProcsModel, modelID, rxWin[modelID].size,
Thomas Jahns's avatar
Thomas Jahns committed
803
             getWinBaseAddr, (unsigned)sizeof(int));
804
      /* FIXME: this needs to use MPI_PACK for portability */
805
806
807
      xmpi(MPI_Get(rxWin[modelID].buffer, rxWin[modelID].size,
                   MPI_UNSIGNED_CHAR, modelID, 0,
                   rxWin[modelID].size, MPI_UNSIGNED_CHAR, getWin));
Deike Kleberg's avatar
Deike Kleberg committed
808
    }
809
  xmpi ( MPI_Win_complete ( getWin ));
Deike Kleberg's avatar
Deike Kleberg committed
810

811
  if ( ddebug > 2 )
Deike Kleberg's avatar
Deike Kleberg committed
812
    for ( modelID = 0; modelID < nProcsModel; modelID++ )
813
      {
814
        sprintf(text, "rxWin[%d].size=%zu from PE%d rxWin[%d].buffer",
815
                modelID, rxWin[modelID].size, modelID, modelID);
816
        xprintArray(text, rxWin[modelID].buffer,
817
818
                    rxWin[modelID].size / sizeof (double),
                    DATATYPE_FLT);
819
      }
Deike Kleberg's avatar
Deike Kleberg committed
820
  readGetBuffers ( tsID, vdate, vtime );
821
          
822
  xdebug("%s", "RETURN");
Deike Kleberg's avatar
Deike Kleberg committed
823
}
Deike Kleberg's avatar
Deike Kleberg committed
824
825
826

/************************************************************************/

827
828
829
830
831
832
833
834
835
836
837
838
#if defined (HAVE_LIBNETCDF) && ! defined (HAVE_PARALLEL_NC4)
static int
cdiPioStreamCDFOpenWrap(const char *filename, const char *filemode,
                        int filetype, stream_t *streamptr,
                        int recordBufIsToBeCreated)
{
  switch (filetype)
    {
    case FILETYPE_NC4:
    case FILETYPE_NC4C:
      {
        int rank, fileID;
Thomas Jahns's avatar
Thomas Jahns committed
839
840
        int ioMode = commInqIOMode();
        if (ioMode == PIO_NONE
841
842
843
844
            || commInqRankColl() == (rank = cdiPioNextOpenRank()))
          fileID = cdiStreamOpenDefaultDelegate(filename, filemode, filetype,
                                                streamptr,
                                                recordBufIsToBeCreated);
Thomas Jahns's avatar
Thomas Jahns committed
845
        if (ioMode != PIO_NONE)
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
          xmpi(MPI_Bcast(&fileID, 1, MPI_INT, rank, commInqCommColl()));
        streamptr->ownerRank = rank;
        return fileID;
      }
    default:
      return cdiStreamOpenDefaultDelegate(filename, filemode, filetype,
                                          streamptr, recordBufIsToBeCreated);
    }
}

static void
cdiPioStreamCDFCloseWrap(stream_t *streamptr, int recordBufIsToBeDeleted)
{
  int fileID   = streamptr->fileID;
  int filetype = streamptr->filetype;
  if ( fileID == CDI_UNDEFID )
    Warning("File %s not open!", streamptr->filename);
  else
    switch (filetype)
      {
      case FILETYPE_NC:
      case FILETYPE_NC2:
      case FILETYPE_NC4:
      case FILETYPE_NC4C:
        {
          int rank, rankOpen;
          if (commInqIOMode() == PIO_NONE
              || ((rank = commInqRankColl())
                  == (rankOpen = cdiPioSerialOpenFileMap(streamptr->self))))
            cdiStreamCloseDefaultDelegate(streamptr, recordBufIsToBeDeleted);
          break;
        }
      default:
        cdiStreamCloseDefaultDelegate(streamptr, recordBufIsToBeDeleted);
      }
}
Thomas Jahns's avatar
Thomas Jahns committed
882
883
884
885
886
887
888
889
890
891
892

static void
cdiPioCdfDefTimestep(stream_t *streamptr, int tsID)
{
  int rank, rankOpen, streamID = streamptr->self;
  if (commInqIOMode() == PIO_NONE
      || ((rank = commInqRankColl())
          == (rankOpen = cdiPioSerialOpenFileMap(streamID))))
    cdfDefTimestep(streamptr, tsID);
}

893
894
#endif

Deike Kleberg's avatar
Deike Kleberg committed
895
896
897
898
899
900
901
902
/**
  @brief is encapsulated in CDI library and run on I/O PEs.

  @param

  @return
*/

903
void IOServer ()
Deike Kleberg's avatar
Deike Kleberg committed
904
{
905
  int source, tag, size, nProcsModel=commInqNProcsModel();
906
  static int nfinished = 0;
Deike Kleberg's avatar
Deike Kleberg committed
907
  char * buffer;
908
909
  MPI_Comm commCalc;
  MPI_Status status;
Deike Kleberg's avatar
Deike Kleberg committed
910

911
  xdebug("%s", "START");
Deike Kleberg's avatar
Deike Kleberg committed
912

913
  backendInit ();
914
915
  if ( commInqRankNode () == commInqSpecialRankNode ()) 
    backendFinalize ();
916
  commCalc = commInqCommCalc ();
917
#ifdef HAVE_PARALLEL_NC4
918
  cdiPioEnableNetCDFParAccess();
919
920
  numPioPrimes = PPM_prime_factorization_32((uint32_t)commInqSizeColl(),
                                            &pioPrimes);
921
922
923
#elif defined (HAVE_LIBNETCDF)
  cdiSerialOpenFileCount = xcalloc(sizeof (cdiSerialOpenFileCount[0]),
                                   commInqSizeColl());
924
925
  namespaceSwitchSet(NSSWITCH_STREAM_OPEN_BACKEND, cdiPioStreamCDFOpenWrap);
  namespaceSwitchSet(NSSWITCH_STREAM_CLOSE_BACKEND, cdiPioStreamCDFCloseWrap);
Thomas Jahns's avatar
Thomas Jahns committed
926
  namespaceSwitchSet(NSSWITCH_CDF_DEF_TIMESTEP, cdiPioCdfDefTimestep);
927
#endif
Thomas Jahns's avatar
Thomas Jahns committed
928
929
  namespaceSwitchSet(NSSWITCH_FILE_WRITE, cdiPioFileWrite);
  
Deike Kleberg's avatar
Deike Kleberg committed
930
  for ( ;; )
931
    {
Deike Kleberg's avatar
Deike Kleberg committed
932
      xmpi ( MPI_Probe ( MPI_ANY_SOURCE, MPI_ANY_TAG, commCalc, &status ));
933
      
Deike Kleberg's avatar
Deike Kleberg committed
934
935
      source = status.MPI_SOURCE;
      tag    = status.MPI_TAG;
936
      
Deike Kleberg's avatar
Deike Kleberg committed
937
      switch ( tag )
938
        {
939
940
941
942
943
944
945
        case FINALIZE:
          {
            int i;
            xdebugMsg(tag, source, nfinished);
            xmpi(MPI_Recv(&i, 1, MPI_INTEGER, source,
                          tag, commCalc, &status));
          }
946
          xdebug("%s", "RECEIVED MESSAGE WITH TAG \"FINALIZE\"");
947
          nfinished++;
Thomas Jahns's avatar
Thomas Jahns committed
948
949
950
          xdebug("nfinished=%d, nProcsModel=%d", nfinished, nProcsModel);
          if ( nfinished == nProcsModel )
            {
951
              {
Deike Kleberg's avatar
Deike Kleberg committed
952
                int nStreams = streamSize ();
Thomas Jahns's avatar
Thomas Jahns committed
953

Deike Kleberg's avatar
Deike Kleberg committed
954
955
956
957
                if ( nStreams > 0 )
                  {
                    int streamNo;
                    int * resHs;
Thomas Jahns's avatar
Thomas Jahns committed
958

Deike Kleberg's avatar
Deike Kleberg committed
959
                    resHs       = xmalloc ( nStreams * sizeof ( resHs[0] ));
960
                    streamGetIndexList ( nStreams, resHs );
Deike Kleberg's avatar
Deike Kleberg committed
961
962
963
964
                    for ( streamNo = 0; streamNo < nStreams; streamNo++ )
                      streamClose ( resHs[streamNo] );
                    free ( resHs );
                  }
Deike Kleberg's avatar
Deike Kleberg committed
965
              }
Thomas Jahns's avatar
Thomas Jahns committed
966
967
              backendCleanup();
              serverWinCleanup();
968
              /* listDestroy(); */
969
              xdebug("%s", "RETURN");
Deike Kleberg's avatar
Deike Kleberg committed
970
971
              return;
            }
972
	  
973
974
          break;
          
Deike Kleberg's avatar
Deike Kleberg committed
975
	case RESOURCES:
976
	  xdebugMsg (  tag, source, nfinished );
977
	  xmpi ( MPI_Get_count ( &status, MPI_CHAR, &size ));
Thomas Jahns's avatar
Thomas Jahns committed
978
	  buffer = xmalloc(size);
979
980
	  xmpi ( MPI_Recv ( buffer, size, MPI_PACKED, source,
                            tag, commCalc, &status ));
981
          xdebug("%s", "RECEIVED MESSAGE WITH TAG \"RESOURCES\"");
982
	  reshUnpackResources(buffer, size, &commCalc);
983
          xdebug("%s", "");
Deike Kleberg's avatar
Deike Kleberg committed
984
	  free ( buffer );
Thomas Jahns's avatar
Thomas Jahns committed
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
          {
            int rankGlob = commInqRankGlob();
            if ( ddebug > 0 && rankGlob == nProcsModel)
              {
                static const char baseName[] = "reshListIOServer.",
                  suffix[] = ".txt";
                /* 9 digits for rank at most */
                char buf[sizeof (baseName) + 9 + sizeof (suffix) + 1];
                snprintf(buf, sizeof (buf), "%s%d%s", baseName, rankGlob,
                         suffix);
                FILE *fp = fopen(buf, "w");
                xassert(fp);
                reshListPrint(fp);
                fclose(fp);
              }
          }
          serverWinCreate ();
1002
	  break;
Deike Kleberg's avatar
Deike Kleberg committed
1003

1004
	case WRITETS:
1005
1006
1007
1008
1009
1010
1011
1012
1013
          {
            int iBuffer[timestepSize];
            xdebugMsg(tag, source, nfinished);
            xmpi(MPI_Get_count(&status, MPI_INTEGER, &size));
            xassert(size == timestepSize);
            xmpi(MPI_Recv(iBuffer, size, MPI_INTEGER, source,
                          tag, commCalc, &status));
            xdebug("RECEIVED MESSAGE WITH TAG \"WRITETS\": "
                   "tsID=%d, vdate=%d, vtime=%d, source=%d",
Deike Kleberg's avatar
Deike Kleberg committed
1014
                   iBuffer[0], iBuffer[1], iBuffer[2], source );
Thomas Jahns's avatar
Thomas Jahns committed
1015
            getTimeStepData(iBuffer[0], iBuffer[1], iBuffer[2]);
1016
          }
Deike Kleberg's avatar
Deike Kleberg committed
1017
	  break;
Deike Kleberg's avatar
Deike Kleberg committed
1018

Deike Kleberg's avatar
Deike Kleberg committed
1019
	default:
Deike Kleberg's avatar
Deike Kleberg committed
1020
	  xabort ( "TAG NOT DEFINED!" );
1021
	}
Deike Kleberg's avatar
Deike Kleberg committed
1022
1023
    }
}
1024

1025
#endif
1026
1027
1028
1029
1030
1031
1032
1033
1034
/*
 * Local Variables:
 * c-file-style: "Java"
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * show-trailing-whitespace: t
 * require-trailing-newline: t
 * End:
 */