OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
DiscField.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/DiscField.h"
28 #include "Utility/DiscConfig.h"
29 #include "Utility/DiscMeta.h"
30 #include "Message/Tags.h"
31 
32 #include "Utility/PAssert.h"
33 #include "Utility/IpplStats.h"
34 #include <cstring>
35 #include <cerrno>
36 
37 
39 // Constructor: make a DiscField for writing
40 // fname = name of file (without extensions)
41 // config = name of configuration file
42 // numFields = number of Fields in the file (for writing)
43 // typestr = string describing the 'type' of the Field to be written (this
44 // is ignored if the Field is being read). The string should be
45 // the same as the statement used to declare the Field object
46 // e.g., for a field of the form Field<double,2> the string
47 // should be "Field<double,2>". The string should be such that
48 // if read later into a variable F, you can use the string in
49 // a source code line as 'F A' to create an instance of the
50 // same type of data as is stored in the file.
51 template <unsigned Dim>
52 DiscField<Dim>::DiscField(const char* base, const char* config,
53  unsigned int numFields, const char* typestr) {
54 
55  initialize(base, config, typestr, numFields);
56 }
57 
58 
60 // Constructor: same as above, but without a config file specified. The
61 // default config file entry that will be used is "* .", which means, for
62 // each SMP machine, assume the directory to put data files in is "."
63 template <unsigned Dim>
64 DiscField<Dim>::DiscField(const char* base, unsigned int numFields,
65  const char* typestr) {
66 
67  initialize(base, 0, typestr, numFields);
68 }
69 
70 
72 // Constructor: make a DiscField for reading only.
73 // fname = name of file (without extensions
74 // config = name of configuration file
75 template <unsigned Dim>
76 DiscField<Dim>::DiscField(const char* base, const char* config) {
77 
78  initialize(base, config, 0, 0);
79 }
80 
81 
83 // Constructor: same as above, but without a config file specified. The
84 // default config file entry that will be used is "* .", which means, for
85 // each SMP machine, assume the directory to put data files in is "."
86 template <unsigned Dim>
87 DiscField<Dim>::DiscField(const char* base) {
88 
89  initialize(base, 0, 0, 0);
90 }
91 
92 
94 // perform initialization based on the constuctor arguments
95 template <unsigned Dim>
96 void DiscField<Dim>::initialize(const char *base, const char *config,
97  const char *typestr, unsigned int numFields) {
98 
99  // save string data
100  BaseFile = base;
101  DiscType = "";
102  if (typestr != 0)
103  TypeString = typestr;
104  else
105  TypeString = "unknown";
106 
107  // initialize member data
108  DataDimension = Dim;
109  CurrentOffset = 0;
110  NumRecords = 0;
111  NumWritten = 0;
112  NumVnodes = 0;
113  VnodeTally = 0;
114 
115  // save the number of fields, which indicates if this object is being
116  // opened for reading or writing
117  NumFields = numFields;
118  WritingFile = (NumFields > 0);
119  if (WritingFile)
120  NeedStartRecord = 1;
121  else
122  NeedStartRecord = -1;
123 
124  // initialize valid field flags
125  for (unsigned int i=0; i < NumFields; ++i)
126  ValidField.push_back(false);
127 
128  // parse the configuration file to find our SMP's, file directories, etc.
129  ConfigOK = parse_config(config, WritingFile);
130 
131  // figure out the number of fields, number of records, size, and
132  // typestring from the .meta file, and store it here. This is only done
133  // if we're reading the file
134  if (ConfigOK && !WritingFile)
135  ConfigOK = read_meta();
136 }
137 
138 
140 // Destructor
141 template <unsigned Dim>
143 
144  // delete per-record vnode information
145  if (NumVnodes != 0)
146  delete [] NumVnodes;
147  if (VnodeTally != 0)
148  delete [] VnodeTally;
149 
150  // delete the configuration file info
151  if (Config != 0)
152  delete Config;
153 }
154 
155 
157 // Obtain all the information about the file, including the number
158 // of records, fields, and number of vnodes stored in each record.
159 template <unsigned Dim>
160 void DiscField<Dim>::query(int& numRecords, int& numFields,
161  std::vector<int>& size) const {
162 
163  numRecords = NumRecords;
164  numFields = NumFields;
165  if (numFiles() > 0 && myBox0() == Ippl::myNode()) {
166  size = NumVnodes[0];
167  for (int i=1; i < numFiles(); ++i) {
168  for (int j=0; j < NumVnodes[i].size(); ++j)
169  size[j] += NumVnodes[i][j];
170  }
171  }
172 }
173 
174 
176 // open a file in the given mode. If an error occurs, print a message
177 // and return 0.
178 template <unsigned Dim>
179 FILE* DiscField<Dim>::open_df_file(const std::string& fnm, const std::string& mode) {
180 
181  FILE *f = fopen(fnm.c_str(), mode.c_str());
182  if (f == 0) {
183  ERRORMSG("DiscField: Could not open file '" << fnm.c_str());
184  ERRORMSG("' for mode '" << mode.c_str() << "' on node ");
185  ERRORMSG(Ippl::myNode() << "." << endl);
186  Ippl::abort("Exiting due to DiscField error.");
187  }
188  return f;
189 }
190 
191 
193 // open a file in the given mode. If an error occurs, print a message
194 // and return 0. This version is used for data files.
195 template <unsigned Dim>
196 int DiscField<Dim>::open_df_file_fd(const std::string& fnm, const std::string& suf,
197  int origflags) {
198 
199  // Form a string with the total filename
200  std::string fnamebuf("");
201  if (fnm.length() > 0)
202  fnamebuf += fnm;
203  if (suf.length() > 0)
204  fnamebuf += suf;
205 
206  // Form the open flags
207  int flags = origflags;
208 
209  // Try to open the file
210  int f = ::open(fnamebuf.c_str(), flags, 0644);
211  if (f < 0) {
212  ERRORMSG("DiscField: Could not open file '" << fnamebuf.c_str());
213  ERRORMSG("' on node " << Ippl::myNode() << ", f = " << f << "."<<endl);
214  return (-1);
215  }
216  return f;
217 }
218 
219 
221 // same as above, but also specifying a file suffix
222 template <unsigned Dim>
223 FILE* DiscField<Dim>::open_df_file(const std::string& fnm, const std::string& suf,
224  const std::string& mode) {
225 
226  std::string fnamebuf("");
227  if (fnm.length() > 0)
228  fnamebuf += fnm;
229  if (suf.length() > 0)
230  fnamebuf += suf;
231 
232  /*
233  char fnamebuf[1024];
234  fnamebuf[0] = '\0';
235  if (fnm.length() > 0)
236  strcat(fnamebuf, fnm.c_str());
237  if (suf.length() > 0)
238  strcat(fnamebuf, suf.c_str());
239  FILE *f = fopen(fnamebuf, mode.c_str());
240  */
241 
242  FILE *f = fopen(fnamebuf.c_str(), mode.c_str());
243 
244  if (f == 0) {
245  ERRORMSG("DiscField: Could not open file '" << fnamebuf);
246  ERRORMSG("' for mode '" << mode.c_str() << "' on node ");
247  ERRORMSG(Ippl::myNode() << "." << endl);
248  Ippl::abort("Exiting due to DiscField error.");
249  }
250  return f;
251 }
252 
253 
255 // create the data files used to store Field data. Return success.
256 template <unsigned Dim>
258 
259 
260  FILE *f;
261  std::string om("w");
262  std::string suff[4];
263  suff[0] = ".meta";
264  suff[1] = ".layout";
265  suff[2] = ".offset";
266  suff[3] = ".data";
267 
268  unsigned int nfiles = 3;
269 
270  // create the non-data files
271  for (unsigned int i=0; i < nfiles; ++i) {
272  std::string fname(Config->getFilename(0) + suff[i]);
273  if ((f = open_df_file(fname, om)) == 0) {
274  ERRORMSG("DiscField: Could not create file '" << fname.c_str());
275  ERRORMSG("'." << endl);
276  Ippl::abort("Exiting due to DiscField error.");
277  }
278  fclose(f);
279  }
280 
281  // create the data file
282  int fd = open_df_file_fd(Config->getFilename(0), suff[3],
283  O_RDWR|O_CREAT|O_TRUNC);
284  if (fd < 0) {
285  std::string fname(Config->getFilename(0) + suff[3]);
286  ERRORMSG("DiscField: Could not create data file '"<<fname.c_str());
287  ERRORMSG("'. errno = " << errno << endl);
288  Ippl::abort("Exiting due to DiscField error.");
289  } else {
290  close(fd);
291  }
292 
293  return true;
294 }
295 
296 
298 // Since the layout can be different every time write
299 // is called, the globalID container needs to be recalculated. The total
300 // domain of the Field should not change, though, just the layout. Return
301 // success.
302 template <unsigned Dim>
304 
305  // check layout to make sure it's valid
306  if (Size.size() != 0 && !(Size == layout.getDomain()))
307  return false;
308  else
309  Size = layout.getDomain();
310 
311  // get rid of the existing mapping
312  globalID.erase(globalID.begin(), globalID.end());
313 
314  // for each local vnode, get the NDIndex it has and store it along with
315  // the node that owns it.
316  typedef typename GlobalIDList_t::value_type vtype;
317  typename FieldLayout<Dim>::iterator_iv local;
318  for (local = layout.begin_iv() ; local != layout.end_iv(); ++local) {
319  // get the domain, and the node and SMP that holds that domain
320  NDIndex<Dim>& domain = (NDIndex<Dim>&) (*local).second.get()->getDomain();
321  int node = (*local).second.get()->getNode();
322  unsigned int nodesmp = Config->getNodeSMPIndex(node);
323 
324  // find out of any of our SMP's contain that node
325  bool foundsmp = (nodesmp == mySMP());
326  unsigned int checksmp = 0;
327  while (!foundsmp && checksmp < Config->getNumOtherSMP()) {
328  foundsmp = (nodesmp == Config->getOtherSMP(checksmp));
329  checksmp++;
330  }
331 
332  // if we are responsible for this vnode, save it
333  if (foundsmp) {
334  // WARNMSG(" ==> Found vnode " << domain << " on this SMP, from node ");
335  // WARNMSG(node << endl);
336  globalID.insert(vtype(domain, node));
337  }
338  }
339 
340  // for each remote vnode, get the NDIndex it has and store it along with
341  // the node that owns it.
342  typename FieldLayout<Dim>::iterator_dv remote;
343  for (remote = layout.begin_rdv() ; remote != layout.end_rdv(); ++remote) {
344  // get the domain, and the node and SMP that holds that domain
345  NDIndex<Dim>& domain = (NDIndex<Dim>&) (*remote).first;
346  int node = (*remote).second->getNode();
347  unsigned int nodesmp = Config->getNodeSMPIndex(node);
348 
349  // find out of any of our SMP's contain that node
350  bool foundsmp = (nodesmp == mySMP());
351  unsigned int checksmp = 0;
352  while (!foundsmp && checksmp < Config->getNumOtherSMP()) {
353  foundsmp = (nodesmp == Config->getOtherSMP(checksmp));
354  checksmp++;
355  }
356 
357  // if we are responsible for this vnode, save it
358  if (foundsmp) {
359  // WARNMSG(" ==> Found vnode " << domain << " on this SMP, from node ");
360  // WARNMSG(node << endl);
361  globalID.insert(vtype(domain, node));
362  }
363  }
364 
365  return true;
366 }
367 
368 
370 // read in from configuration file - an ascii file of token pairs.
371 // This is mostly handled by the DiscConfig class. Return success.
372 template <unsigned Dim>
373 bool DiscField<Dim>::parse_config(const char *fname, bool writing) {
374 
375  // create a DiscConfig instance, which will parse the file on some of
376  // the nodes and distribute the information to all the other nodes.
377  Config = new DiscConfig(fname, BaseFile.c_str(), writing);
378 
379  // need to set up a few things if the config file checked out OK
380  if (Config->ok()) {
381  // create vnode information storage for Box0 nodes
382  if (numFiles() > 0 && myBox0() == (unsigned int) Ippl::myNode()) {
383  NumVnodes = new std::vector<int>[numFiles()];
384  VnodeTally = new std::vector<int>[numFiles()];
385 
386  // if we need to, create the files
387  if (writing) {
388  if (!create_files())
389  return false;
390  }
391  }
392 
393  // indicate how many filesets we're reading or writing
394  /*
395  if (writing) {
396  ADDIPPLSTAT(incDiscFilesetWrites,numFiles());
397  } else {
398  ADDIPPLSTAT(incDiscFilesetReads,numFiles());
399  }
400  */
401  } else {
402  ERRORMSG("DiscField: A problem occurred reading the config file '");
403  ERRORMSG(fname << "'." << endl);
404  Ippl::abort("Exiting due to DiscField error.");
405  }
406 
407  return Config->ok();
408 }
409 
410 
412 // print out debugging information for this DiscField
413 template <unsigned Dim>
414 void DiscField<Dim>::printDebug() { printDebug(std::cout); }
415 
416 template <unsigned Dim>
417 void DiscField<Dim>::printDebug(std::ostream& outmsg) {
418 
419  Inform msg("DiscField", outmsg, INFORM_ALL_NODES);
420 
421  msg << "BaseFile = " << BaseFile << endl;
422  msg << "Field Type = " << TypeString << endl;
423  msg << "NumRecords = " << NumRecords << endl;
424  msg << "NumFields = " << NumFields << endl;
425 
426  msg << "Configuration file information:" << endl;
427  Config->printDebug(msg);
428 
429  msg << endl;
430 }
431 
432 
434 // write out a new .meta file. The .meta file contains the following
435 // information, on each line:
436 // String with type of data stored here, supplied by user
437 // Dimension
438 // For each dimension:
439 // Total domain of the Fields, as first last stride
440 // Number of Fields
441 // Number of Records
442 // Number of SMPs
443 // Vnodes/SMP for each record, on one line
444 // Vnodes/SMP tally for each record, on one line
445 // return success of operation.
446 template <unsigned Dim>
448 
449  unsigned int r, d;
450 
451  // no need to write anything if we have no files for this SMP
452  if (numFiles() == 0)
453  return true;
454 
455  // open the meta data file
456  FILE *outputMeta = open_df_file(Config->getFilename(0),".meta",std::string("w"));
457  if (outputMeta == 0)
458  return false;
459 
460  // write the initial header info
461  fprintf(outputMeta, "Type = %s\n", TypeString.c_str());
462  fprintf(outputMeta, "Dim = %u\n", Dim);
463  for (d=0; d < Dim; ++d)
464  fprintf(outputMeta, "Domain = %d %d %d\n",
465  Size[d].first(), Size[d].last(), Size[d].stride());
466  fprintf(outputMeta, "Fields = %u\n", NumFields);
467  fprintf(outputMeta, "Records = %u\n", NumRecords);
468  fprintf(outputMeta, "SMPs = %u\n", fileSMPs());
469 
470  // write information for each record. When writing, we will only
471  // write one file set per box, so we use '0' for the fileset number.
472  fprintf(outputMeta, "VnodesInRecord = ");
473  for (r=0; r < NumRecords; ++r)
474  fprintf(outputMeta, " %d", NumVnodes[0][r]);
475  fprintf(outputMeta, "\n");
476 
477  fprintf(outputMeta, "VnodeTally= ");
478  for (r=0; r < NumRecords; ++r)
479  fprintf(outputMeta, " %d", VnodeTally[0][r]);
480  fprintf(outputMeta, "\n");
481 
482  // close data file and return
483  fclose(outputMeta);
484  return true;
485 }
486 
487 
489 // read in data from .meta file, and replace current storage values.
490 // The format for a .meta file is described in the write_meta routine.
491 // return success of operation.
492 template <unsigned Dim>
494 
495  bool iserror = false;
497 
498  // on Box0 nodes, read in the meta data ... on others, wait for
499  // Box0 nodes to send info to them
500  if ((unsigned int) Ippl::myNode() == myBox0()) {
501  // loop over all the files on this Box0 node
502  for (unsigned int sf=0; sf < numFiles(); ++sf) {
503  // open and parse the meta data file
504  std::string filename = Config->getFilename(sf) + ".meta";
505  DiscMeta outputMeta(filename.c_str());
506  if (outputMeta.size() == 0) {
507  ERRORMSG("DiscField: The meta file '" << filename << "' is empty ");
508  ERRORMSG("or does not exist." << endl);
509  Ippl::abort("Exiting due to DiscField error.");
510  return false;
511  }
512 
513  // initialize data before reading .meta file
514  unsigned int dimread = 0;
515  TypeString = "unknown";
516  DataDimension = Dim;
517  NumFields = 0;
518  NumRecords = 0;
519  NumVnodes[sf].erase(NumVnodes[sf].begin(), NumVnodes[sf].end());
520  VnodeTally[sf].erase(VnodeTally[sf].begin(), VnodeTally[sf].end());
521 
522  // keep reading until we have all data
523  DiscMeta::iterator metaline, metaend = outputMeta.end();
524  for (metaline = outputMeta.begin(); metaline != metaend; ++metaline) {
525  // get number of tokens and list of tokens in the line
526  int linesread = (*metaline).first;
527  int numtokens = (*metaline).second.first;
528  std::string *tokens = (*metaline).second.second;
529 
530  // action is based on first keyword
531  if (tokens[0] == "Type") {
532  if (numtokens > 1)
533  TypeString = tokens[1];
534  }
535  else if (tokens[0] == "Dim" && numtokens == 2) {
536  DataDimension = atoi(tokens[1].c_str());
537  if (DataDimension < 1) {
538  ERRORMSG("DiscField: The meta file '" << filename << "' ");
539  ERRORMSG("contains a value for dimension < 1, '");
540  ERRORMSG(tokens[1] << "'." << endl);
541  Ippl::abort("Exiting due to DiscField error.");
542  iserror = true;
543  }
544  }
545  else if (tokens[0] == "Fields" && numtokens == 2) {
546  NumFields = atoi(tokens[1].c_str());
547  if (NumFields < 1) {
548  ERRORMSG("DiscField: The meta file '" << filename << "' ");
549  ERRORMSG("contains a value for Fields < 1, '");
550  ERRORMSG(tokens[1] << "'." << endl);
551  Ippl::abort("Exiting due to DiscField error.");
552  iserror = true;
553  }
554  }
555  else if (tokens[0] == "Records" && numtokens == 2) {
556  NumRecords = atoi(tokens[1].c_str());
557  }
558  else if (tokens[0] == "SMPs" && numtokens == 2) {
559  unsigned int checkfileSMPs = atoi(tokens[1].c_str());
560  if (fileSMPs() != checkfileSMPs) {
561  ERRORMSG("DiscField: The meta file '" << filename << "' ");
562  ERRORMSG("contains a value for the number of filesets that\n");
563  ERRORMSG("does not match the number of filesets in the config\n");
564  ERRORMSG("file: metafile filesets = " << tokens[1] << ", ");
565  ERRORMSG("config filesets = " << fileSMPs() << "." << endl);
566  Ippl::abort("Exiting due to DiscField error.");
567  iserror = true;
568  }
569  }
570  else if (tokens[0] == "Domain" && numtokens == 4) {
571  if (dimread < Dim) {
572  Size[dimread] = Index(atoi(tokens[1].c_str()),
573  atoi(tokens[2].c_str()),
574  atoi(tokens[3].c_str()));
575  }
576  dimread++;
577  }
578  else if (tokens[0] == "VnodesInRecord") {
579  for (int r=1; r < numtokens; ++r)
580  NumVnodes[sf].push_back(atoi(tokens[r].c_str()));
581  }
582  else if (tokens[0] == "VnodeTally") {
583  for (int r=1; r < numtokens; ++r)
584  VnodeTally[sf].push_back(atoi(tokens[r].c_str()));
585  }
586  else {
587  // error in line
588  ERRORMSG("DiscField: Format error on line " << linesread);
589  ERRORMSG(" in meta file '" << filename << "'." << endl);
590  Ippl::abort("Exiting due to DiscField error.");
591  iserror = true;
592  }
593 
594  if (iserror)
595  break;
596  }
597 
598  // do a little sanity checking
599  if (DataDimension != dimread) {
600  ERRORMSG("DiscField: Dim != # Domain lines in meta file '");
601  ERRORMSG(filename << "'. (" << DataDimension << " != " << dimread);
602  ERRORMSG(")" << endl);
603  Ippl::abort("Exiting due to DiscField error.");
604  iserror = true;
605  }
606  if (NumRecords != NumVnodes[sf].size()) {
607  ERRORMSG("DiscField: Records != VnodesInRecord items in meta file '");
608  ERRORMSG(filename << "'. (" << NumRecords << " != ");
609  ERRORMSG(NumVnodes[sf].size() << ")" << endl);
610  Ippl::abort("Exiting due to DiscField error.");
611  iserror = true;
612  }
613  if (NumRecords != VnodeTally[sf].size()) {
614  ERRORMSG("DiscField: Records != VnodeTally items in meta file '");
615  ERRORMSG(filename << "'. (" << NumRecords << " != ");
616  ERRORMSG(VnodeTally[sf].size() << ")" << endl);
617  Ippl::abort("Exiting due to DiscField error.");
618  iserror = true;
619  }
620 
621  // stop processing meta files is there was an error
622  if (iserror)
623  break;
624  }
625 
626  // now send meta info to all nodes which expect it
627  int numinform = Config->getNumOtherSMP();
628  for (int s=0; s <= numinform; ++s) {
629  int smp = mySMP();
630  if (s != numinform)
631  smp = Config->getOtherSMP(s);
632  for (unsigned int n=0; n < Config->getNumSMPNodes(smp); ++n) {
633  int node = Config->getSMPNode(smp, n);
634  if (node != Ippl::myNode()) {
635  // create a message with meta info
636  Message *msg = new Message;
637  int errint = iserror;
638  msg->put(errint);
639  msg->put(DataDimension);
640  msg->put(NumFields);
641  msg->put(NumRecords);
642  ::putMessage(*msg, Size);
643  ::putMessage(*msg, TypeString);
644 
645  // send the message to the intended node
646  Ippl::Comm->send(msg, node, tag);
647  }
648  }
649  }
650 
651  } else {
652  // all other nodes (which are not Box0 nodes) should get a message
653  // telling them the meta info
654  int node = myBox0();
655  Message *msg = Ippl::Comm->receive_block(node, tag);
656  PAssert(msg);
657 
658  // get info out of message
659  int errint = 0;
660  msg->get(errint);
661  iserror = (errint != 0);
662  msg->get(DataDimension);
663  msg->get(NumFields);
664  msg->get(NumRecords);
665  ::getMessage(*msg, Size);
666  ::getMessage(*msg, TypeString);
667 
668  // we're done with this message
669  delete msg;
670  }
671 
672  return (!iserror);
673 }
674 
675 
677 // Read the data for a single NDIndex from the given file. Return success.
678 template <unsigned Dim>
680  // an array of ints used to read the data
681  int ndidata[6*Dim];
682 
683  // OK, this is a mess, for the reasons described in write_NDIndex. This
684  // reads in 6 ints for each dimension, of which three are used for
685  // the first, stride, and length parameters. These are put in to the given
686  // NDIndex.
687 
688  // first read the data into the int array
689  if (fread(ndidata, sizeof(int), 6*Dim, f) != 6*Dim) {
690  ERRORMSG("DiscField: Error reading NDIndex line from data file." << endl);
691  Ippl::abort("Exiting due to DiscField error.");
692  return false;
693  }
694 
695  // now copy data int the NDIndex
696  int *dptr = ndidata + 1;
697  for (unsigned int d=0; d < Dim; ++d) {
698  int first = *dptr;
699  int stride = *(dptr + 1);
700  int length = *(dptr + 2);
701  ndi[d] = Index(first, first + (length - 1)*stride, stride);
702  dptr += 6;
703  }
704 
705  return true;
706 }
707 
708 
710 // Write the data for a single NDIndex to the given file. Return success.
711 template <unsigned Dim>
712 bool DiscField<Dim>::write_NDIndex(FILE *f, const NDIndex<Dim> &ndi) {
713  // OK, this is a mess ... originally, data was just written
714  // out from an NDIndex directly, which is just an array of Index objs.
715  // However, the contents of an Index are compiler-specific, since some
716  // compilers use the empty-base-class optimization, some put in an
717  // extra int in a base class, etc. So, this has been switched from
718  // writing out the NDIndex data using
719  // fwrite(&((*id).first), sizeof(NDIndex<Dim>), 1, outputLayout)
720  // to
721  // fwrite(ndidata, sizeof(int), 6*Dim, outputLayout)
722  // since the original, most-used version of DiscField did so with
723  // a compiler that constructed an Index object with this data:
724  // int = 0 (empty-base-class storage)
725  // int = first
726  // int = stride
727  // int = length
728  // int = base
729  // int = id
730  // With some compilers, the initial int = 0 is not included, since it
731  // is not necessary. But for backwards compatibility, we'll use this
732  // format of 6 ints, with the first, fifth, and sixth set to zero
733 
734  // first copy the data into the int array
735  int ndidata[6*Dim];
736  int *dptr = ndidata;
737  for (unsigned int d=0; d < Dim; ++d) {
738  *dptr++ = 0;
739  *dptr++ = ndi[d].first();
740  *dptr++ = ndi[d].stride();
741  *dptr++ = ndi[d].length();
742  *dptr++ = 0;
743  *dptr++ = 0;
744  }
745 
746  // now write the data, and report whether the result is OK
747  return (fwrite(ndidata, sizeof(int), 6*Dim, f) == 6*Dim);
748 }
749 
750 
752 // update the .layout file, which contains information on the layout
753 // of the Fields for each record. This file contains a set of NDIndex
754 // objects for each record. The format, for each record, is:
755 // Number of vnodes on this SMP box
756 // For each vnode on this SMP box:
757 // Vnode object, containing NDIndex(first last stride)
758 // return success of update
759 template <unsigned Dim>
761 
762  // no need to write anything if we have no files for this SMP
763  if (numFiles() == 0)
764  return true;
765 
766  // open the layout data file
767  FILE *outputLayout = open_df_file(Config->getFilename(0), ".layout",
768  std::string("a"));
769 
770  // write out the number of vnodes in this record for this file set
771  int numvnodes = globalID.size();
772  if (fwrite(&numvnodes, sizeof(int), 1, outputLayout) != 1) {
773  ERRORMSG("Error writing .layout file in DiscField::write_layout." << endl);
774  Ippl::abort("Exiting due to DiscField error.");
775  fclose(outputLayout);
776  return false;
777  }
778 
779  // write out the current vnode sizes from the provided FieldLayout
780  typename GlobalIDList_t::iterator id, idend = globalID.end();
781  for (id = globalID.begin(); id != idend; ++id) {
782  if (!write_NDIndex(outputLayout, (*id).first)) {
783  ERRORMSG("Error writing record " << NumRecords-1 << " to .layout file.");
784  Ippl::abort("Exiting due to DiscField error.");
785  fclose(outputLayout);
786  return false;
787  }
788  }
789 
790  // close the file, we're done
791  fclose(outputLayout);
792  return true;
793 }
794 
795 
797 // Read layout info for one file set in the given record.
798 template <unsigned Dim>
799 int DiscField<Dim>::read_layout(int record, int sf) {
800 
801  // open the layout data file
802  std::string filename = Config->getFilename(sf) + ".layout";
803  FILE *outputLayout = open_df_file(Config->getFilename(sf),
804  ".layout", std::string("r"));
805  if (outputLayout == 0)
806  return (-1);
807 
808  // seek to the proper location
809  Offset_t seekpos = record*sizeof(int) +
810  VnodeTally[sf][record]*6*Dim*sizeof(int);
811 
812  if (fseek(outputLayout, seekpos, SEEK_SET) != 0) {
813  ERRORMSG("Error seeking to position " << static_cast<long>(seekpos));
814  ERRORMSG(" in file '" << filename << "' for DiscField::read_layout.");
815  ERRORMSG(endl);
816  Ippl::abort("Exiting due to DiscField error.");
817  fclose(outputLayout);
818  return (-1);
819  }
820 
821  // read the number of vnodes stored here
822  int numvnodes = 0;
823  if (fread(&numvnodes, sizeof(int), 1, outputLayout) != 1) {
824  ERRORMSG("Error reading file '" << filename);
825  ERRORMSG("' in DiscField::read_layout.");
826  ERRORMSG(endl);
827  Ippl::abort("Exiting due to DiscField error.");
828  fclose(outputLayout);
829  return (-1);
830  }
831 
832  // we used to have to read the vnode domains, but now it is
833  // not necessary, we get that from the offset file. layout files
834  // will continue to store correct data for backwards compatibility,
835  // but we don't need it for reading any more. So, just return.
836 
837  fclose(outputLayout);
838  return numvnodes;
839 }
840 
841 
843 // Compute how many elements we should expect to store into the local
844 // node for the given FieldLayout. Just loop through the local vnodes
845 // and accumulate the sizes of the owned domains. This is modified
846 // by the second "read domain" argument, which might be a subset of
847 // the total domain.
848 template <unsigned Dim>
850  const NDIndex<Dim> &readDomain) {
851  int expected = 0;
852 
853  typename FieldLayout<Dim>::const_iterator_iv local = f.begin_iv();
854  for (; local != f.end_iv(); ++local) {
855  // Compute the size of the domain of this vnode, and add it to the
856  // amount we expect for this node.
857  NDIndex<Dim>& domain = (NDIndex<Dim>&)(*local).second.get()->getDomain();
858  if (domain.touches(readDomain)) {
859  NDIndex<Dim> newdomain = domain.intersect(readDomain);
860  // expected += domain.size();
861  expected += newdomain.size();
862  }
863  }
864 
865  return expected;
866 }
867 
868 
870 // Compute the size of a domain, zero-based, that has a total
871 // size <= chunkelems and has evenly chunked slices.
872 template <unsigned Dim>
874  int chunkelems,
875  int &msdim,
876  bool iscompressed)
877 {
878 
879  // Initialize result to the total block sizes
880  NDIndex<Dim> sliceblock;
881  for (unsigned int i=0; i < Dim; ++i)
882  sliceblock[i] = Index(currblock[i].length());
883 
884  // If this is compressed, or we are not chunking, just use the whole block
885  int currsize = currblock.size();
886  if (chunkelems < 1 || iscompressed)
887  chunkelems = currsize;
888 
889  // Find out actual size for each dimension, generally smaller than the
890  // total size
891  for (int d=(Dim-1); d >= 0; --d) {
892  // Size of this domain slice
893  int axislen = currblock[d].length();
894  currsize /= axislen;
895 
896  // Compute the number of lower-dim slices
897  int numslices = chunkelems / currsize;
898  if (numslices > axislen)
899  numslices = axislen;
900 
901  // If there are some slices, just use those and we're done
902  if (numslices > 0) {
903  sliceblock[d] = Index(numslices);
904  msdim = d;
905  break;
906  } else {
907  // No slices here, so change the length of this dimension to 1
908  sliceblock[d] = Index(1);
909  }
910  }
911 
912  // Return the newly computed block size; msdim is set to the maximum
913  // dimension of the chunk block
914  return sliceblock;
915 }
916 
917 
918 /***************************************************************************
919  * $RCSfile: DiscField.cpp,v $ $Author: adelmann $
920  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:33 $
921  * IPPL_VERSION_ID: $Id: DiscField.cpp,v 1.1.1.1 2003/01/23 07:40:33 adelmann Exp $
922  ***************************************************************************/
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
PartBunchBase< T, Dim >::ConstIterator begin(PartBunchBase< T, Dim > const &bunch)
const unsigned Dim
void putMessage(Message &m, const T &t)
Definition: Message.h:549
void getMessage(Message &m, T &t)
Definition: Message.h:572
#define DF_READ_META_TAG
Definition: Tags.h:73
#define DF_TAG_CYCLE
Definition: Tags.h:74
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define INFORM_ALL_NODES
Definition: Inform.h:39
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
#define PAssert(c)
Definition: PAssert.h:102
unsigned size() const
bool touches(const NDIndex< Dim > &) const
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
iterator_iv end_iv()
Definition: FieldLayout.h:716
const NDIndex< Dim > & getDomain() const
Definition: FieldLayout.h:325
iterator_dv begin_rdv(const GuardCellSizes< Dim > &gc=gc0())
Definition: FieldLayout.h:765
iterator_dv end_rdv(const GuardCellSizes< Dim > &gc=gc0())
Definition: FieldLayout.h:772
ac_id_vnodes::const_iterator const_iterator_iv
Definition: FieldLayout.h:74
ac_id_vnodes::iterator iterator_iv
Definition: FieldLayout.h:73
iterator_iv begin_iv()
Definition: FieldLayout.h:709
Definition: Index.h:237
bool send(Message *, int node, int tag, bool delmsg=true)
Message * receive_block(int &node, int &tag)
Message & put(const T &val)
Definition: Message.h:406
Message & get(const T &cval)
Definition: Message.h:476
int next_tag(int t, int s=1000)
Definition: TagMaker.h:39
bool write_layout()
Definition: DiscField.hpp:760
bool make_globalID(FieldLayout< Dim > &)
Definition: DiscField.hpp:303
int compute_expected(const FieldLayout< Dim > &, const NDIndex< Dim > &)
Definition: DiscField.hpp:849
void query(int &numRecords, int &numFields, std::vector< int > &size) const
Definition: DiscField.hpp:160
DiscField(const char *fname, const char *config, unsigned int numFields, const char *typestr=0)
Definition: DiscField.hpp:52
void initialize(const char *base, const char *config, const char *typestr, unsigned int numFields)
Definition: DiscField.hpp:96
NDIndex< Dim > chunk_domain(const NDIndex< Dim > &currblock, int chunkelems, int &msdim, bool iscompressed)
Definition: DiscField.hpp:873
void printDebug()
Definition: DiscField.hpp:414
bool read_meta()
Definition: DiscField.hpp:493
int read_layout(int record, int sf)
Definition: DiscField.hpp:799
bool parse_config(const char *, bool)
Definition: DiscField.hpp:373
bool write_NDIndex(FILE *, const NDIndex< Dim > &)
Definition: DiscField.hpp:712
int open_df_file_fd(const std::string &fnm, const std::string &suf, int flags)
Definition: DiscField.hpp:196
long long Offset_t
Definition: DiscField.h:849
bool read_NDIndex(FILE *, NDIndex< Dim > &)
Definition: DiscField.hpp:679
FILE * open_df_file(const std::string &fnm, const std::string &mode)
Definition: DiscField.hpp:179
bool create_files()
Definition: DiscField.hpp:257
bool write_meta()
Definition: DiscField.hpp:447
unsigned int size() const
Definition: DiscMeta.h:61
iterator begin()
Definition: DiscMeta.h:76
iterator end()
Definition: DiscMeta.h:77
container_t::iterator iterator
Definition: DiscMeta.h:41
Definition: Inform.h:42
static void abort(const char *=0)
Definition: IpplInfo.cpp:616
static int myNode()
Definition: IpplInfo.cpp:691
static Communicate * Comm
Definition: IpplInfo.h:84
rep_type::iterator iterator
Definition: vmap.h:98
std::pair< NDIndex< Dim >, int > value_type
Definition: vmap.h:64