File: SimulationWrapper.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 (99 lines) | stat: -rw-r--r-- 3,362 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
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sim/Fitting/SimulationWrapper.cpp
//! @brief     Implements family of PyFittingCallbacks classes.
//!
//! @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 "Sim/Fitting/SimulationWrapper.h"
#include "Device/Data/Datafield.h"
#include "Sim/Simulation/ISimulation.h"
#include <stdexcept>

SimulationWrapper::SimulationWrapper(const SimulationWrapper& other)
{
    cSimulationFn = other.cSimulationFn;
    pySimulationFn = other.pySimulationFn;
    pySimulate = other.pySimulate;
    pyFree = other.pyFree;
}

SimulationWrapper::~SimulationWrapper()
{
    discard();
}

void SimulationWrapper::check() const
{
    if (!(cSimulationFn || pySimulationFn))
        throw std::runtime_error("SimulationWrapper: "
                                 "simulation-builder function is not available");

    if (cSimulationFn && pySimulationFn)
        throw std::runtime_error("SimulationWrapper: Either C++ or a Python simulation-builder "
                                 "function must be given, not both");

    if (pySimulationFn && !(pySimulate && pyFree))
        throw std::runtime_error(
            "SimulationWrapper: Python simulation-builder "
            "function needs extra functions to execute a Python simulation, "
            "convert a Python simulation, and free the memory on Python side.");
}

Datafield SimulationWrapper::simulate(const mumufit::Parameters& prm)
{
    check();
    discard(); // discard any artifacts from a previous simulation

    if (pySimulationFn)
        return m_executePySimulation(prm);

    // it's a C++ simulation
    return m_executeSimulation(prm);
}

void SimulationWrapper::discard()
{
    if (pySimulationFn) { // Python case
#ifdef BORNAGAIN_PYTHON
        // Release here, as the generated ISimulation instance and its
        // Python wrapper are managed by the Python interpreter.
        simulation.release();
        pyFree(m_pythonObject);
#endif // BORNAGAIN_PYTHON
        m_pythonObject = nullptr;

    } else { // C++ case
        simulation.reset();
    }
}

Datafield SimulationWrapper::m_executePySimulation(const mumufit::Parameters& params)
{
#ifndef BORNAGAIN_PYTHON
    throw std::runtime_error("SimulationWrapper: Calling a Python simulation-builder"
                             "function needs interoperation with a Python interpreter");
#endif // BORNAGAIN_PYTHON

    // call a Python function with signature:
    // fn(Parameters:Python-dict) -> Python-Object which wraps an ISimulation instance
    ISimulation* sim;
    pySimulate(pySimulationFn, params, sim, m_pythonObject);
    simulation.reset(sim);
    return simulation->simulate();
}

Datafield SimulationWrapper::m_executeSimulation(const mumufit::Parameters& params)
{
    // call a C++ function with signature:
    // fn(Parameters) -> ISimulation instance
    simulation.reset(cSimulationFn(params).release());
    return simulation->simulate();
}