File: EmbeddedTest.cpp

package info (click to toggle)
bornagain 23.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • 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 (162 lines) | stat: -rw-r--r-- 6,488 bytes parent folder | download | duplicates (3)
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
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Tests/Unit/PyBinding/EmbeddedTest.cpp
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "BABuild.h"
#include "Base/Const/Units.h"
#include "PyCore/Embed/PyInterpreter.h"
#include "PyCore/Embed/PyObjectPtr.h"
#include "Tests/GTestWrapper/google_test.h"
#include <cstdint>
#include <string>
#include <vector>

//! Importing numpy and accessing its version string.

TEST(Embedded, PyInterpreterTest)
{
    // initialize Python interpreter
    PyInterpreter::initialize();
    EXPECT_TRUE(PyInterpreter::isInitialized());

    // add Python path
    PyInterpreter::addPythonPath("/Some/Extra/Python/Path/");
    EXPECT_FALSE(PyInterpreter::checkError());

    // get runtime info
    std::string runtime_info = PyInterpreter::runtimeInfo();
    std::cout << "Python runtime info:\n" << runtime_info << std::endl;

    // set Python path
    PyInterpreter::setPythonPath("/Some/Extra/Python/Path/");
}


TEST(Embedded, PyInterpreterNumpyTest)
{
    // TODO: re-implement the Numpy Test

    // initialize Python interpreter
    PyInterpreter::initialize();
    EXPECT_TRUE(PyInterpreter::isInitialized());

    // import Numpy
    PyObjectPtr numpy_module = PyInterpreter::import("numpy");
    EXPECT_TRUE(numpy_module.valid());
}


TEST(Embedded, BornAgainPyFunctionTest)
{
    // Test importing a Python script which uses BornAgain Python package

    // initialize Python interpreter
    PyInterpreter::initialize();
    EXPECT_TRUE(PyInterpreter::isInitialized());

    const std::string script{"import bornagain as ba; from bornagain import deg;"
                             "d0 = ba.deg; d1 = deg; "
                             "get_sample = lambda: (d0 == d1 and 'BornAgain.deg = %.3f' % d1)"};
    const std::string functionName{"get_sample"};

    // locate the `get_sample` function (it is an attribute of the module)
    PyObjectPtr ret{PyInterpreter::BornAgain::callScriptFunction(functionName, script, "")};

    if (!ret.valid())
        throw std::runtime_error("Failed executing Python function '" + functionName + "'");

    const std::string return_str = PyInterpreter::pyStrtoString(ret.get());
    std::stringstream _stream;
    _stream << std::fixed << std::setprecision(3) << Units::deg;
    const std::string expected_str = "BornAgain.deg = " + _stream.str();

    // verify that the returned string starts with the expected string
    if (!(return_str == expected_str))
        throw std::runtime_error("Result '" + return_str + "' does not match the expected '"
                                 + expected_str + "'");
}


TEST(Embedded, BornAgainPyFabioTest)
{
    // Test importing a Python script which uses BornAgain Python package

    // initialize Python interpreter
    PyInterpreter::initialize();
    EXPECT_TRUE(PyInterpreter::isInitialized());

    // import Fabio
    PyObjectPtr fabio_module = PyInterpreter::Fabio::import();
    EXPECT_TRUE(fabio_module.valid());

    // mar format ([2300, 2300], dtype = uint32)
    const std::string datafile_mar{BABuild::testdataDir() + "/fabio/200mMmgso4_001.mar2300"};
    std::cout << "BornAgainPyFabioTest: datafile '" << datafile_mar << std::endl;

    NumpyArrayWrapper np_arr1 = PyInterpreter::Fabio::load(datafile_mar);
    const ArrayMetadata& metadata1 = np_arr1.metadata();
    const std::size_t num_pixels = std::stoi(std::get<std::string>(metadata1.at("NumPixels")));
    const std::size_t n_rows1 = np_arr1.dimensions()[0], n_columns1 = np_arr1.dimensions()[1];
    std::cout << "Numpy array size = " << np_arr1.size() << ", "
              << "n_dimensions = " << np_arr1.rank() << ", "
              << "dtype = " << np_arr1.dtype() << ", "
              << "nr of pixels = " << num_pixels << ", "
              << "rows = " << n_rows1 << ", "
              << "columns = " << n_columns1 << std::endl;

    // check the nominal and actual number of pixels
    EXPECT_TRUE(num_pixels == np_arr1.size());

    auto arr1 = reinterpret_cast<const std::uint32_t*>(np_arr1.arrayPtr());
    const std::uint32_t arr1_test[] = {38, 21, 24}; // expected result
    const std::size_t i_r = 249, offset_r = i_r * n_columns1;
    for (std::size_t i_c = 1095, idx = 0; i_c < 1098; ++i_c) {
        const std::size_t offset = offset_r + i_c;
        const std::uint32_t val = arr1[offset], val_expected = arr1_test[idx];
        ++idx;

        std::printf("data[%zu, %zu] = %u =?= %u\n", i_r, i_c, val, val_expected);
        EXPECT_TRUE(val == val_expected);
    }

    // tif format ([480, 640], dtype = uint8)
    const std::string datafile_tif{BABuild::testdataDir() + "/fabio/at3_1m4_01.tif"};
    std::cout << "BornAgainPyFabioTest: datafile '" << datafile_tif << std::endl;

    NumpyArrayWrapper np_arr2 = PyInterpreter::Fabio::load(datafile_tif);
    const ArrayMetadata& metadata2 = np_arr2.metadata();
    const unsigned long n_rows2 = std::get<long int>(metadata2.at("nRows")),
                        n_columns2 = std::get<long int>(metadata2.at("nColumns")),
                        n_pixels2 = n_rows2 * n_columns2;

    std::cout << "Numpy array size = " << np_arr2.size() << ", "
              << "n_dimensions = " << np_arr2.rank() << ", "
              << "dtype = " << np_arr2.dtype() << ", "
              << "nr of rows = " << n_rows2 << ", "
              << "nr of columns = " << n_columns2 << std::endl;

    EXPECT_TRUE(n_pixels2 == np_arr2.size());

    auto arr2 = reinterpret_cast<const std::uint8_t*>(np_arr2.arrayPtr());
    const std::uint8_t arr2_test[] = {70, 72, 69, 67, 66, 68, 65, 67, 68}; // expected result
    for (std::size_t i_r = 200, idx = 0; i_r < 203; ++i_r) {
        const std::size_t offset_r = i_r * n_columns2;
        for (std::size_t i_c = 300; i_c < 303; ++i_c) {
            const std::size_t offset = offset_r + i_c;
            const std::uint8_t val = arr2[offset], val_expected = arr2_test[idx];
            ++idx;

            std::printf("data[%zu, %zu] = %u =?= %u\n", i_r, i_c, val, val_expected);
            EXPECT_TRUE(val == val_expected);
        }
    }
}