OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
src/Sample/FromFile.cpp
Go to the documentation of this file.
1//
2// Class FromFile
3// This class parses a file that contains design variable values.
4// Each column belongs to a design variable.
5// The first line is considered as headerLine and consists of the
6// design variable name. The name has to agree with the string
7// in the input file.
8//
9// Copyright (c) 2018, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland
10// All rights reserved
11//
12// Implemented as part of the PhD thesis
13// "Precise Simulations of Multibunches in High Intensity Cyclotrons"
14//
15// This file is part of OPAL.
16//
17// OPAL is free software: you can redistribute it and/or modify
18// it under the terms of the GNU General Public License as published by
19// the Free Software Foundation, either version 3 of the License, or
20// (at your option) any later version.
21//
22// You should have received a copy of the GNU General Public License
23// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
24//
25#include "Sample/FromFile.h"
26
28
29#include <algorithm>
30#include <fstream>
31#include <iterator>
32#include <sstream>
33
34FromFile::FromFile(const std::string& filename, const std::string& dvarName, std::size_t modulo)
35 : mod_m(modulo), filename_m(filename), dvarName_m(dvarName), globalSize_m(0)
36{
37 // Open the input file
38 std::ifstream in(filename_m);
39 if (!in.is_open()) {
40 throw OpalException("FromFile()",
41 "Couldn't open file '" + filename_m + "'.");
42 }
43
44 // Count number of non-empty lines
45 std::string line;
46 std::size_t validLines = 0;
47 while (std::getline(in, line)) {
48 if (!line.empty()) ++validLines;
49 }
50 if (validLines == 0) {
51 throw OpalException("FromFile()", "Empty file '" + filename_m + "'.");
52 }
53
54 // Store the number of data rows (including header)
55 globalSize_m = static_cast<unsigned int>(validLines);
56
57 in.close();
58}
59
60void FromFile::create(std::shared_ptr<SampleIndividual>& ind, std::size_t i) {
61 ind->genes[i] = getNext(ind->id);
62}
63
64void FromFile::allocate(const CmdArguments_t& /*args*/, const Comm::Bundle_t& /*comm*/) {
65 std::ifstream file(filename_m);
66 if (!file.is_open()) {
67 throw OpalException("FromFile::allocate",
68 "Couldn't open file '" + filename_m + "'.");
69 }
70
71 // Read and parse the header line to identify the variable names
72 std::string headerLine;
73 if (!std::getline(file, headerLine)) {
74 throw OpalException("FromFile::allocate",
75 "Empty file or error reading header in '" + filename_m + "'.");
76 }
77
78 std::istringstream headerStream(headerLine);
79 std::vector<std::string> dvars{std::istream_iterator<std::string>{headerStream},
80 std::istream_iterator<std::string>{}};
81
82 // Find the column index of the requested design variable
83 auto it = std::find(dvars.begin(), dvars.end(), dvarName_m);
84 if (it == dvars.end()) {
85 throw OpalException("FromFile::allocate",
86 "Couldn't find dvar '" + dvarName_m +
87 "' in file '" + filename_m + "'");
88 }
89 const std::size_t columnIndex = std::distance(dvars.begin(), it);
90
91 // Reserve space for data values (excluding the header)
92 chain_m.reserve(globalSize_m - 1); // -1 for the header line
93 std::string line;
94 std::size_t lineNumber = 2; // Start at 2 because the header is line 1
95 while (std::getline(file, line)) {
96 if (line.empty()) {
97 ++lineNumber;
98 continue;
99 }
100
101 std::istringstream lineStream(line);
102 std::vector<std::string> tokens{std::istream_iterator<std::string>{lineStream},
103 std::istream_iterator<std::string>{}};
104
105 if (columnIndex >= tokens.size()) {
106 throw OpalException("FromFile::allocate",
107 "Line " + std::to_string(lineNumber) + " in file '" + filename_m +
108 "' has fewer columns (" + std::to_string(tokens.size()) +
109 ") than expected (index " + std::to_string(columnIndex) + ").");
110 }
111
112 try {
113 chain_m.push_back(std::stod(tokens[columnIndex]));
114 } catch (const std::exception& e) {
115 throw OpalException("FromFile::allocate",
116 "Conversion error at line " + std::to_string(lineNumber) +
117 " in file '" + filename_m + "': " + e.what());
118 }
119
120 ++lineNumber;
121 }
122
123 file.close();
124}
125
126double FromFile::getNext(unsigned int id) {
127 if (globalSize_m == 0 || chain_m.empty()) {
128 throw OpalException("FromFile::getNext",
129 "No valid numeric data found for DVAR '" + dvarName_m +
130 "' in file '" + filename_m + "'.");
131 }
132
133 std::size_t idx = (id / mod_m) % chain_m.size();
134 return chain_m[idx];
135}
136
137unsigned int FromFile::getSize() const {
138 return globalSize_m;
139}
std::shared_ptr< CmdArguments > CmdArguments_t
bundles all communicators for a specific role/pid
Definition types.h:32
void allocate(const CmdArguments_t &args, const Comm::Bundle_t &comm) override
Parses and loads the data from the file into memory.
std::size_t mod_m
Modulo used to wrap indices.
std::size_t globalSize_m
Number of lines in the file (including header).
unsigned int getSize() const
Get the number of lines in the file (including the header).
std::vector< double > chain_m
The values for the selected design variable loaded from the file.
std::string dvarName_m
Name of the design variable to extract.
void create(std::shared_ptr< SampleIndividual > &ind, std::size_t i) override
Assign a sampled value to an individual's gene.
std::string filename_m
File name where samples are read from.
double getNext(unsigned int id)
Returns the next value for the given individual ID.
FromFile(const std::string &filename, const std::string &dvarName, std::size_t modulo)
The base class for all OPAL exceptions.