OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
FieldBlock.hpp
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  * This program was prepared by PSI.
7  * All rights in the program are reserved by PSI.
8  * Neither PSI nor the author(s)
9  * makes any warranty, express or implied, or assumes any liability or
10  * responsibility for the use of this software
11  *
12  * Visit www.amas.web.psi for more details
13  *
14  ***************************************************************************/
15 
16 // -*- C++ -*-
17 /***************************************************************************
18  *
19  * The IPPL Framework
20  *
21  *
22  * Visit http://people.web.psi.ch/adelmann/ for more details
23  *
24  ***************************************************************************/
25 
26 // include files
27 #include "Utility/FieldBlock.h"
28 #include "Utility/IpplInfo.h"
29 #include "Utility/PAssert.h"
30 #include "Field/BrickExpression.h"
31 #include "Field/Field.h"
33 #include "Field/LField.h"
34 #include "Message/Message.h"
35 #include "Message/Communicate.h"
36 
37 
38 #include <cstring>
39 #include <cstdio>
40 
41 #ifdef IPPL_NETCDF
42 #include <netcdf.h>
43 #endif
44 
45 //------------------------------------------------------------------
46 // This constructor is used to create a block of fields in a netcdf
47 // record. There can be an unlimited number of records. Thus, a netcdf
48 // file is produced which will store numFields Fields with the layout
49 // given into a netcdf file named fname. A new netcdf file is
50 // created whenever this constructor is used.
51 template<class T, unsigned Dim, class Mesh, class Centering >
53  FieldLayout<Dim>& layout,
54  unsigned numFields) :
55  Layout(layout), NumFields(numFields)
56 {
57 
58  strcpy(FName, fname);
59  NumRecords = 0;
60 
61  // setup the file
62 #ifdef IPPL_NETCDF
63  int Parent = 0;
64  if( Ippl::Comm->myNode() == Parent ) {
65  int ncid; // NetCDF file ID
66  int rcode;
67 
68  // Create the NetCDF file, overwrite if already exists:
69  ncid = nccreate(FName, NC_CLOBBER);
70 
71  // Select no-fill mode, to avoid wasting time initializing values
72  // into variables with no UNLIMITED dimension upon creation:
73  int fillmode = ncsetfill(ncid,NC_NOFILL); //tjwdebug
74  // Initialize metadata:
75  // Dimensions:
76 
77  const NDIndex<Dim> &domain = Layout.getDomain();
78 
79  // Variables:
80  int dimids[4];
81  if ( Dim==1 ) {
82  dimids[0] = ncdimdef(ncid, "record", NC_UNLIMITED);
83  dimids[1] = ncdimdef(ncid, "nx", domain[0].length());
84  }
85  if ( Dim==2 ) {
86  dimids[0] = ncdimdef(ncid, "record", NC_UNLIMITED);
87  dimids[1] = ncdimdef(ncid, "nx", domain[0].length());
88  dimids[2] = ncdimdef(ncid, "ny", domain[1].length());
89  }
90  if ( Dim==3 ) {
91  dimids[0] = ncdimdef(ncid, "record", NC_UNLIMITED);
92  dimids[1] = ncdimdef(ncid, "nx", domain[0].length());
93  dimids[2] = ncdimdef(ncid, "ny", domain[1].length());
94  dimids[3] = ncdimdef(ncid, "nz", domain[2].length());
95  }
96  if ( Dim>3 ) {
97  ERRORMSG("FieldBlock: can't write more than 3 dimensions" << endl);
98  }
99  for( int i = 0 ; i < NumFields ; i++ ) {
100  char varName[256];
101  sprintf(varName, "var%d", i);
102  ncvardef(ncid, varName, NC_DOUBLE, Dim+1, dimids);
103  }
104  // End (metadata) definition mode and close file (par_io requires):
105  int errRet = ncendef(ncid);
106  rcode = ncclose(ncid); // Everybody/master closes file.
107  if ( rcode != 0) {
108  ERRORMSG("FieldBlock: ncclose() error, rcode=" << rcode << endl);
109  }
110  }
111 #endif // IPPL_NETCDF
112 }
113 //------------------------------------------------------------------
114 // This constructor is used to access a block of fields in a netcdf
115 // record. It assumes that the netcdf file fname already exists.
116 template<class T, unsigned Dim, class Mesh, class Centering >
118 FieldBlock(char* fname, FieldLayout<Dim>& layout)
119 : Layout(layout)
120 {
121 
122  strcpy(FName, fname);
123  // setup the file
124 #ifdef IPPL_NETCDF
125  int Parent = 0;
126  if( Ippl::Comm->myNode() == Parent ) {
127  int i; // loop variables
128  int ncid, ndims, nvars; // NetCDF file info
129  nc_type datatype; // variable Type
130  int rcode;
131  long netSize[Dim+1];
132 
133  // Create the NetCDF file, overwrite if already exists:
134  ncid = ncopen(FName, NC_NOWRITE);
135 
136  // Inquire the metadata
137  ncinquire(ncid, &ndims, &nvars, 0, 0);
138  if( ndims != Dim+1)
139  ERRORMSG("FieldBlock: bad number of dims on read of " << FName << endl);
140  NumFields = nvars;
141  for( i = 0; i < Dim+1 ; i++ ) {
142  ncdiminq(ncid, i, 0, &netSize[i]);
143  }
144  for( i = 0; i < Dim ; i++ ) {
145  if( netSize[i+1] != Layout.getDomain()[i].length() ) {
146  ERRORMSG("FieldBlock: encountered non-conforming size on axis ");
147  ERRORMSG(i << endl);
148  }
149  }
150 
151  for( i = 0; i < NumFields ; i++ ) {
152  ncvarinq(ncid, i, 0, &datatype, 0, 0, 0);
153  if( datatype != NC_DOUBLE)
154  ERRORMSG("FieldBlock: file must contain double precion data" << endl);
155  }
156  long numRecords; // how many records in this file?
157  ncdiminq(ncid, 0, 0, &numRecords);
158  NumRecords = numRecords;
159  rcode = ncclose(ncid); // Everybody/master closes file.
160  if ( rcode != 0) {
161  ERRORMSG("FieldBlock: ncclose() error, rcode=" << rcode << endl);
162  }
163  }
164 #endif // IPPL_NETCDF
165 }
166 //------------------------------------------------------------------
167 template< class T, unsigned Dim, class Mesh, class Centering >
169  unsigned varID,
170  unsigned record)
171 {
172 
173 #ifdef IPPL_NETCDF
174  Inform msg("FieldBlock::write");
175  msg.setPrintNode();
176 
177  if( varID >=NumFields ) {
178  ERRORMSG(varID << " is a bad variable ID in FieldBlock::write " << endl);
179  return;
180  }
181  int ncid; // NetCDF file ID
182  int Parent = 0; // send everything to node 0
183 
184  // Open netCDF file for reading
185  if( Ippl::Comm->myNode() == Parent ) {
186  ncid = ncopen(FName, NC_WRITE);
187 
188  // Select no-fill mode, to avoid wasting time initializing values
189  // into variables with no UNLIMITED dimension upon creation:
190  int fillmode = ncsetfill(ncid,NC_NOFILL); //tjwdebug
191  }
192  Ippl::Comm->barrier();
193 
194  long startIndex[Dim+1];
195  long countIndex[Dim+1];
196  int rcode;
197 
199  typedef LField<T,Dim>::iterator LFI;
200  // ----------------------------------------
201  // First loop over all the local nodes and send
203  // msg << "starting to send messages: " << endl;
204  for (local = f.begin_if(); local != f.end_if(); ++local) {
205  // Cache some information about this local field.
206  LField<T,Dim>& l = *(*local).second.get();
207  NDIndex<Dim>& lo = (NDIndex<Dim>&) l.getOwned();
209 
210  // Build a message containing the owned LocalField data
211  Message *mess = new Message();
212  ::putMessage(*mess, lo);
213  LFI msgval = l.begin();
214  msgval.TryCompress();
215  ::putMessage(*mess, msgval);
216 
217  // Send it.
218  // msg << "sending a message from node " << Ippl::Comm->myNode();
219  // msg << " to parent node " << Parent << " with tag " << tag << endl;
220  Ippl::Comm->send(mess, Parent, tag);
221  }
222  // ----------------------------------------
223  // Receive all the messages.
224  // write each one to the netCDF file as it is received
225  // only the Parent processor writes the data
226  if( Ippl::Comm->myNode() == Parent ) {
227  // we expect to receive one message from each vnode
228 
229  int numVnodes = Layout.size_iv() + Layout.size_rdv();
230  // msg << " numVnodes = " << numVnodes << endl;
231 
232  for (int remaining = numVnodes; remaining>0; --remaining) {
233  // Receive the generic message.
234  int any_node = COMM_ANY_NODE;
235  Message *mess = Ippl::Comm->receive_block(any_node, tag);
236  PAssert(mess);
237 
238  // msg << "received a message from node " << any_node;
239  // msg << " on parent node " << Parent << " with tag " << tag << endl;
240 
241  // Extract the rhs BrickIterator from it.
242  NDIndex<Dim> localBlock;
243  LFI rhs;
244  ::getMessage(*mess, localBlock);
245  ::getMessage(*mess, rhs);
246 
247  // Get pointer to the data so we can free it.
248  int size = 1;
249  for( int i = 0 ; i < Dim ; i++ ) {
250  startIndex[Dim - i] = localBlock[Dim - 1 - i].first();
251  countIndex[Dim - i] = localBlock[Dim - 1 - i].length();
252  size *= countIndex[Dim - i];
253  }
254 
255  // unlimited dimension
256  startIndex[0] = record;
257  countIndex[0] = 1;
258  double* buffer = new double[size];
259  // now write the data
260  int icount = 0;
261  int n0,n1,n2,i0,i1,i2;
262  if (rhs.IsCompressed()) {
263  for (i0=0; i0<size; ++i0) buffer[icount++] = *rhs;
264  // msg << " compressed value is: " << *rhs << endl;
265  } else {
266  switch(Dim) {
267  case 1:
268  n0 = rhs.size(0);
269  for (i0=0; i0<n0; ++i0)
270  buffer[icount++] = rhs.offset(i0);
271  break;
272  case 2:
273  n0 = rhs.size(0);
274  n1 = rhs.size(1);
275  for (i0=0; i0<n0; ++i0)
276  for (i1=0; i1<n1; ++i1)
277  buffer[icount++] = rhs.offset(i0,i1);
278  break;
279  case 3:
280  n0 = rhs.size(0);
281  n1 = rhs.size(1);
282  n2 = rhs.size(2);
283  for (i0=0; i0<n0; ++i0)
284  for (i1=0; i1<n1; ++i1)
285  for (i2=0; i2<n2; ++i2)
286  buffer[icount++] = rhs.offset(i0,i1,i2);
287  break;
288  default:
289  ERRORMSG("FieldBlock: bad Dimension in Field::write()" << endl);
290  break;
291  }
292  }
293  // msg << " before ncvarput " << endl;
294  rcode = ncvarput(ncid, varID, startIndex,countIndex, buffer);
295  // msg << " after ncvarput " << endl;
296  if ( rcode != 0) {
297  ERRORMSG("FieldBlock: ncvarput() error, rcode=" << rcode << endl);
298  }
299  delete [] buffer;
300  delete mess;
301  }
302  rcode = ncclose(ncid); // parent closes file.
303  if ( rcode != 0) {
304  ERRORMSG("FieldBlock: ncclose() error, rcode=" << rcode << endl);
305  }
306  }
307  NumRecords = NumRecords > record ? NumRecords : record;
308 #endif // IPPL_NETCDF
309 }
310 //--------------------------------------------------------------------
311 template< class T, unsigned Dim, class Mesh, class Centering >
313  unsigned varID,
314  unsigned record)
315 {
316 #ifdef IPPL_NETCDF
317  Inform msg("FieldBlock::read");
318  int i; // loop variables
319  int ncid; // NetCDF file info
320  int Parent = 0; // send everything to node 0
321 
322  // Create the NetCDF file, overwrite if already exists:
323  if( Ippl::Comm->myNode() == Parent ) {
324  ncid = ncopen(FName, NC_NOWRITE);
325  }
326 
327  if( record >= NumRecords )
328  ERRORMSG("invalid record on FieldBlock::read() " << endl);
329 
330  // Loop over all the Vnodes, creating an LField in each.
331  long startIndex[Dim+1];
332  long countIndex[Dim+1];
333  int rcode;
334 
336  typedef LField<T,Dim>::iterator LFI;
337 
338  // cycle through all the local vnodes and
339  // assign data to the corresponding localFields
340  // only the Parent reads
341  if( Ippl::Comm->myNode() == Parent ) {
342  // DomainMap<NDIndex,Vnode*>::iterator for Vnodes from FieldLayout
343  // this section can be reworked to straight BrickExpressions
344  // the messages are being used to shake down the communications
346  for (localVnode = Layout.begin_iv() ;
347  localVnode != Layout.end_iv(); ++localVnode) {
348  // Cache some information about this local vnode
349  Vnode<Dim>& vn = *(*localVnode).second;
350  NDIndex<Dim>& lo = (NDIndex<Dim>&) vn.getDomain();
351 
352  int size = 1;
353  for( i = 0 ; i < Dim ; i++ ) {
354  startIndex[Dim - i] = lo[Dim - 1 - i].first();
355  countIndex[Dim - i] = lo[Dim - 1 - i].length();
356  size *= countIndex[Dim - i];
357  }
358  // unlimited dimension
359  startIndex[0] = record;
360  countIndex[0] = 1;
361  double* buffer = new double[size];
362 
363  rcode = ncvarget(ncid, varID, startIndex, countIndex, buffer);
364  if ( rcode != 0) {
365  ERRORMSG("FieldBlock: ncvarget() error, rcode=" << rcode << endl);
366  }
367  // Build a message containing the owned LocalField data
368  Message *mess = new Message();
369  ::putMessage(*mess, lo);
370  LFI msgval(buffer, lo, lo);
371  ::putMessage(*mess, msgval);
372 
373 
374  // Send it to the physical node
375  Ippl::Comm->send(mess, vn.getNode(), tag);
376  delete [] buffer;
377  }
378  // cycle through all the remote vnodes and
379  // send a message to the corresponding pnode
380  FieldLayout<Dim>::iterator_dv remoteVnode;
381  for (remoteVnode = Layout.begin_rdv() ;
382  remoteVnode != Layout.end_rdv(); ++remoteVnode) {
383  // Cache some information about this remote vnode
384  NDIndex<Dim>& lo = (NDIndex<Dim>&) (*remoteVnode).first;
385  Vnode<Dim>& vn = *(*remoteVnode).second;
386 
387  int size = 1;
388  for( i = 0 ; i < Dim ; i++ ) {
389  startIndex[Dim - i] = lo[Dim - 1 - i].first();
390  countIndex[Dim - i] = lo[Dim - 1 - i].length();
391  size *= countIndex[Dim - i];
392  }
393  // unlimited dimension
394  startIndex[0] = record;
395  countIndex[0] = 1;
396  double* buffer = new double[size];
397 
398  rcode = ncvarget(ncid, varID, startIndex,countIndex, buffer);
399  if ( rcode != 0) {
400  ERRORMSG("FieldBlock: ncvarget() error, rcode=" << rcode << endl);
401  }
402 
403  // Build a message containing the owned LocalField data
404  Message *mess = new Message();
405  ::putMessage(*mess, lo);
406  LFI msgval(buffer, lo, lo);
407  ::putMessage(*mess, msgval);
408 
409  // Send it to the physica node
410  Ippl::Comm->send(mess, vn.getNode(), tag);
411  delete [] buffer;
412  }
413  rcode = ncclose(ncid); // Parent closes file.
414  if ( rcode != 0) {
415  ERRORMSG("FieldBlock: ncclose() error, rcode=" << rcode << endl);
416  }
417  }
418 
419  // receive the messages
420  int numLocalVnodes = Layout.size_iv();
421  for (int remaining = numLocalVnodes; remaining>0; --remaining) {
422  // Receive the generic message.
423  int any_node = COMM_ANY_NODE;
424  Message *mess = Ippl::Comm->receive_block(any_node, tag);
425  PAssert_NE(mess, 0);
426 
427  // Extract the rhs BrickIterator from it.
428  NDIndex<Dim> localBlock;
429  LFI rhs;
430  ::getMessage(*mess, localBlock);
431  ::getMessage(*mess, rhs);
432 
433  // to which local vnode does this correspond?
434  LField<T,Dim>* myLField;
435  bool flag = 1;
436  // DomainMap<NDIndex,LField*>::iterator for LocalFields
438  for (local = f.begin_if(); local != f.end_if(); ++local) {
439  myLField = (*local).second.get();
440  const NDIndex<Dim>& lo = myLField->getOwned();
441  if( lo == localBlock ) {
442  flag = 0;
443  break;
444  }
445  }
446  if(flag)
447  ERRORMSG("FieldBlock::read: did not match the local NDIndex" << endl);
448  // now read the data into the LocalFields
449  // Build the lhs brick iterator.
450  LFI lhs = myLField->begin();
451  int n0,n1,n2,i0,i1,i2;
452  if( lhs.IsCompressed() && rhs.IsCompressed() ) {
453  *lhs = *rhs;
454  }
455  if( !lhs.IsCompressed() && rhs.IsCompressed() ) {
456  for (i0=0; i0 < localBlock.size(); ++i0) {
457  *lhs = *rhs;
458  ++lhs;
459  }
460  }
461  if( !rhs.IsCompressed() ) {
462  if( lhs.IsCompressed() ) {
463  myLField->Uncompress();
464  lhs = myLField->begin();
465  }
466  switch(Dim) {
467  case 1:
468  n0 = rhs.size(0);
469  for (i0=0; i0<n0; ++i0) {
470  lhs.offset(i0) = *rhs;
471  ++rhs;
472  }
473  break;
474  case 2:
475  n0 = rhs.size(0);
476  n1 = rhs.size(1);
477  for (i0=0; i0<n0; ++i0)
478  for (i1=0; i1<n1; ++i1) {
479  lhs.offset(i0,i1) = *rhs;
480  ++rhs;
481  }
482  break;
483  case 3:
484  n0 = rhs.size(0);
485  n1 = rhs.size(1);
486  n2 = rhs.size(2);
487  for (i0=0; i0<n0; ++i0)
488  for (i1=0; i1<n1; ++i1)
489  for (i2=0; i2<n2; ++i2) {
490  lhs.offset(i0,i1,i2) = *rhs;
491  ++rhs;
492  }
493  break;
494  default:
495  ERRORMSG("FieldBlock: bad Dimension in write()" << endl);
496  break;
497  }
498  }
499  // Do the assignment.
500  // BrickExpression<Dim,BI,BI,AppAssign<T,T> > (lhs,rhs).apply();
501  // Free the memory.
502  delete mess;
503  } // loop over the vnodes
504 
505 #endif // IPPL_NETCDF
506 }
507 //--------------------------------------------------------------------
508 /***************************************************************************
509  * $RCSfile: FieldBlock.cpp,v $ $Author: adelmann $
510  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:33 $
511  * IPPL_VERSION_ID: $Id: FieldBlock.cpp,v 1.1.1.1 2003/01/23 07:40:33 adelmann Exp $
512  ***************************************************************************/
FieldBlock(char *fname, FieldLayout< Dim > &layout, unsigned numFields)
Definition: FieldBlock.hpp:52
ac_id_larray::iterator iterator_if
Definition: BareField.h:91
const NDIndex< Dim > & getOwned() const
Definition: LField.h:93
#define ERRORMSG(msg)
Definition: IpplInfo.h:399
void barrier(void)
const int COMM_ANY_NODE
Definition: Communicate.h:40
Definition: FFT.h:31
void Uncompress(bool fill_domain=true)
Definition: LField.h:166
unsigned size() const
char FName[30]
Definition: FieldBlock.h:61
int next_tag(int t, int s=1000)
Definition: TagMaker.h:43
const iterator & begin() const
Definition: LField.h:104
FieldLayout< Dim > & Layout
Definition: FieldBlock.h:62
int getNode() const
Definition: Vnode.h:69
iterator_if end_if()
Definition: BareField.h:100
iterator_iv end_iv()
Definition: FieldLayout.h:716
iterator_iv begin_iv()
Definition: FieldLayout.h:709
void setPrintNode(int n=(-1))
Definition: Inform.h:85
ac_id_vnodes::iterator iterator_iv
Definition: FieldLayout.h:73
unsigned NumRecords
Definition: FieldBlock.h:64
const NDIndex< Dim > & getAllocated() const
Definition: LField.h:92
unsigned NumFields
Definition: FieldBlock.h:63
int size(unsigned d) const
Definition: BrickIterator.h:48
const NDIndex< Dim > & getDomain() const
Definition: Vnode.h:71
void read(Field< T, Dim, Mesh, Centering > &f, unsigned varID, unsigned record=0)
Definition: FieldBlock.hpp:312
#define FB_TAG_CYCLE
Definition: Tags.h:62
#define PAssert_NE(a, b)
Definition: PAssert.h:120
Definition: Vnode.h:22
void write(Field< T, Dim, Mesh, Centering > &f, unsigned varID, unsigned record=0)
Definition: FieldBlock.hpp:168
void getMessage(Message &m, T &t)
Definition: Message.h:580
#define PAssert(c)
Definition: PAssert.h:117
#define FB_READ_TAG
Definition: Tags.h:61
const unsigned Dim
void putMessage(Message &m, const T &t)
Definition: Message.h:557
iterator_if begin_if()
Definition: BareField.h:99
Message * receive_block(int &node, int &tag)
Definition: Inform.h:41
static Communicate * Comm
Definition: IpplInfo.h:93
bool send(Message *, int node, int tag, bool delmsg=true)
#define FB_WRITE_TAG
Definition: Tags.h:60
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
datatype
Definition: ast.hpp:20