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