File: ReadWriteNicos.cpp

package info (click to toggle)
bornagain 23.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 103,936 kB
  • sloc: cpp: 423,131; python: 40,997; javascript: 11,167; awk: 630; sh: 318; ruby: 173; xml: 130; makefile: 51; ansic: 24
file content (166 lines) | stat: -rw-r--r-- 5,589 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Device/IO/ReadWriteNicos.cpp
//! @brief     Implements function Util::RW::readNicos.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "Device/IO/ReadWriteNicos.h"
#include "Base/Axis/Frame.h"
#include "Base/Axis/MakeScale.h"
#include "Base/Util/StringUtil.h"
#include "Device/Data/Datafield.h"
#include <memory>

namespace {

std::string lineRelatedError(const std::string& errorText, int lineNumber)
{
    return "Line " + std::to_string(lineNumber) + ": " + errorText;
}


unsigned int readAssignedPositiveIntValue(const std::string& line, int lineNumber)
{
    const auto parts = Base::String::split(line, "=");
    if (parts.size() != 2)
        throw std::runtime_error(lineRelatedError("Missing assigned value", lineNumber));

    int value = 0;
    if (!Base::String::to_int(parts[1], &value))
        throw std::runtime_error(
            lineRelatedError("Cannot parse assigned value '" + parts[1] + "'", lineNumber));

    if (value <= 0)
        throw std::runtime_error(
            lineRelatedError("Value of '" + parts[1] + "' is nonpositive", lineNumber));

    return value;
}

} // namespace


Datafield Util::RW::readNicos(std::istream& input_stream)
{
    std::string line;
    int lineNumber = 0;

    unsigned int width = 0;
    unsigned int height = 0;

    // -- read dimensions
    bool inFileSection = false;
    bool fileSectionFound = false;
    bool typeFound = false;
    while (std::getline(input_stream, line)) {
        lineNumber++;
        line = Base::String::trimFront(line, " ");

        if (!inFileSection) {
            if (Base::String::startsWith(line, "%File")) {
                inFileSection = true;
                fileSectionFound = true;
                continue;
            }
            continue;
        }

        if (Base::String::startsWith(line, "%"))
            break; // next section

        if (Base::String::startsWith(line, "Type=")) {
            const auto parts = Base::String::split(line, "=");
            if (parts[1] != "SANSDRaw")
                throw std::runtime_error(
                    lineRelatedError("Unsupported file type '" + parts[1] + "'", lineNumber));
            typeFound = true;
        }

        if (Base::String::startsWith(line, "DataSizeX"))
            width = readAssignedPositiveIntValue(line, lineNumber);
        else if (Base::String::startsWith(line, "DataSizeY"))
            height = readAssignedPositiveIntValue(line, lineNumber);
        if (width != 0 && height != 0)
            break;
    }

    if (!fileSectionFound)
        throw std::runtime_error("Could not find 'File' section");
    if (!typeFound)
        throw std::runtime_error("File type not found");
    if (width == 0)
        throw std::runtime_error("Could not find 'DataSizeX' value");
    if (height == 0)
        throw std::runtime_error("Could not find 'DataSizeY' value");

    std::vector<const Scale*> axes{newEquiDivision("u (bin)", width, 0.0, width),
                                   newEquiDivision("v (bin)", height, 0.0, height)};
    auto result = std::make_unique<Datafield>(axes);

    // -- read data
    bool inCountSection = false;
    bool countSectionFound = false;
    unsigned int dataRow = 0;

    while (std::getline(input_stream, line)) {
        lineNumber++;
        line = Base::String::trimFront(line, " ");

        if (!inCountSection) {
            if (Base::String::startsWith(line, "%Counts")) {
                inCountSection = true;
                countSectionFound = true;
                continue;
            }
            continue;
        }

        if (Base::String::startsWith(line, "%"))
            break; // next section

        // line is a data line
        line = Base::String::trim(line, " ");
        if (line.empty())
            continue;

        const auto valuesAsString = Base::String::split(line, ",");
        if (valuesAsString.size() != width)
            throw std::runtime_error(
                lineRelatedError("Number of found values (" + std::to_string(valuesAsString.size())
                                     + ") does not match DataSizeX (" + std::to_string(width) + ")",
                                 lineNumber));

        for (unsigned col = 0; col < width; ++col) {

            int value = 0;
            if (!Base::String::to_int(valuesAsString[col], &value))
                throw std::runtime_error(lineRelatedError(
                    "Value '" + valuesAsString[col] + "' could not be converted to integer",
                    lineNumber));

            // y-axis "0" is at bottom => invert y
            // to show first line at top of image
            (*result)[(height - 1 - dataRow) * width + col] = value;
        }
        dataRow++;

        if (dataRow == height)
            break;
    }

    if (!countSectionFound)
        throw std::runtime_error("Could not find 'Counts' section");
    if (dataRow != height)
        throw std::runtime_error("Number of found data rows (" + std::to_string(dataRow)
                                 + ") does not match DataSizeY (" + std::to_string(height) + ")");

    return *result;
}