OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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.
51template <unsigned Dim>
52DiscField<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 "."
63template <unsigned Dim>
64DiscField<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
75template <unsigned Dim>
76DiscField<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 "."
86template <unsigned Dim>
87DiscField<Dim>::DiscField(const char* base) {
88
89 initialize(base, 0, 0, 0);
90}
91
92
94// perform initialization based on the constuctor arguments
95template <unsigned Dim>
96void 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
141template <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.
159template <unsigned Dim>
160void 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.
178template <unsigned Dim>
179FILE* 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.
195template <unsigned Dim>
196int 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
222template <unsigned Dim>
223FILE* 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.
256template <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.
302template <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.
372template <unsigned Dim>
373bool 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
413template <unsigned Dim>
414void DiscField<Dim>::printDebug() { printDebug(std::cout); }
415
416template <unsigned Dim>
417void 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.
446template <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.
492template <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.
678template <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.
711template <unsigned Dim>
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
759template <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.
798template <unsigned Dim>
799int 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.
848template <unsigned Dim>
850 const NDIndex<Dim> &readDomain) {
851 int expected = 0;
852
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.
872template <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 PAssert(c)
Definition: PAssert.h:102
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
unsigned size() const
bool touches(const NDIndex< Dim > &) const
NDIndex< Dim > intersect(const NDIndex< Dim > &) const
iterator_iv end_iv()
Definition: FieldLayout.h:716
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
const NDIndex< Dim > & getDomain() const
Definition: FieldLayout.h:325
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