BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
PyFmt2.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Core/Export/PyFmt2.cpp
6 //! @brief Implements functions from namespace pyfmt2.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
15 #include "Core/Export/PyFmt2.h"
16 #include "Base/Axis/FixedBinAxis.h"
18 #include "Base/Const/Units.h"
19 #include "Base/Math/Constants.h"
20 #include "Base/Utils/Algorithms.h"
21 #include "Base/Utils/StringUtils.h"
22 #include "Core/Export/PyFmt.h"
24 #include "Device/Mask/Ellipse.h"
26 #include "Device/Mask/Line.h"
27 #include "Device/Mask/Polygon.h"
28 #include "Device/Mask/Rectangle.h"
34 #include <iomanip>
35 
36 namespace pyfmt2 {
37 
38 //! Returns fixed Python code snippet that defines the function "runSimulation".
39 
40 std::string representShape2D(const std::string& indent, const IShape2D* ishape, bool mask_value,
41  std::function<std::string(double)> printValueFunc)
42 {
43  std::ostringstream result;
44  result << std::setprecision(12);
45 
46  if (const Polygon* shape = dynamic_cast<const Polygon*>(ishape)) {
47  std::vector<double> xpos, ypos;
48  shape->getPoints(xpos, ypos);
49  result << indent << "points = [";
50  for (size_t i = 0; i < xpos.size(); ++i) {
51  result << "[" << printValueFunc(xpos[i]) << ", " << printValueFunc(ypos[i]) << "]";
52  if (i != xpos.size() - 1)
53  result << ", ";
54  }
55  result << "]\n";
56  result << indent << "simulation.addMask("
57  << "ba.Polygon(points), " << pyfmt::printBool(mask_value) << ")\n";
58 
59  } else if (dynamic_cast<const InfinitePlane*>(ishape)) {
60  result << indent << "simulation.maskAll()\n";
61 
62  } else if (const Ellipse* shape = dynamic_cast<const Ellipse*>(ishape)) {
63  result << indent << "simulation.addMask(";
64  result << "ba.Ellipse(" << printValueFunc(shape->getCenterX()) << ", "
65  << printValueFunc(shape->getCenterY()) << ", " << printValueFunc(shape->getRadiusX())
66  << ", " << printValueFunc(shape->getRadiusY());
67  if (shape->getTheta() != 0.0)
68  result << ", " << pyfmt::printDegrees(shape->getTheta());
69  result << "), " << pyfmt::printBool(mask_value) << ")\n";
70  }
71 
72  else if (const Rectangle* shape = dynamic_cast<const Rectangle*>(ishape)) {
73  result << indent << "simulation.addMask(";
74  result << "ba.Rectangle(" << printValueFunc(shape->getXlow()) << ", "
75  << printValueFunc(shape->getYlow()) << ", " << printValueFunc(shape->getXup())
76  << ", " << printValueFunc(shape->getYup()) << "), " << pyfmt::printBool(mask_value)
77  << ")\n";
78  }
79 
80  else if (const VerticalLine* shape = dynamic_cast<const VerticalLine*>(ishape)) {
81  result << indent << "simulation.addMask(";
82  result << "ba.VerticalLine(" << printValueFunc(shape->getXpos()) << "), "
83  << pyfmt::printBool(mask_value) << ")\n";
84  }
85 
86  else if (const HorizontalLine* shape = dynamic_cast<const HorizontalLine*>(ishape)) {
87  result << indent << "simulation.addMask(";
88  result << "ba.HorizontalLine(" << printValueFunc(shape->getYpos()) << "), "
89  << pyfmt::printBool(mask_value) << ")\n";
90 
91  } else
92  throw std::runtime_error("representShape2D(const IShape2D*) -> Error. Unknown shape");
93 
94  return result.str();
95 }
96 
97 //! Returns parameter value, followed by its unit multiplicator (like "* nm").
98 
99 std::string valueTimesUnit(const RealParameter* par)
100 {
101  return pyfmt::printValue(par->value(), par->unit());
102 }
103 
104 //! Returns comma-separated list of parameter values, including unit multiplicator (like "* nm").
105 
106 std::string argumentList(const IParametricComponent* ip)
107 {
108  std::vector<std::string> args;
109  for (const auto* par : ip->parameterPool()->parameters())
110  args.push_back(valueTimesUnit(par));
111  return StringUtils::join(args, ", ");
112 }
113 
114 //! Prints an axis.
115 std::string printAxis(const IAxis* axis, const std::string& unit)
116 {
117  std::ostringstream result;
118  if (const auto* a = dynamic_cast<const FixedBinAxis*>(axis); a)
119  result << "ba.FixedBinAxis(" << pyfmt::printString(a->getName()) << ", " << a->size()
120  << ", " << pyfmt::printValue(a->lowerBound(), unit) << ", "
121  << pyfmt::printValue(a->upperBound(), unit) << ")";
122  else if (const auto* a = dynamic_cast<const PointwiseAxis*>(axis); a) {
123  result << "numpy.asarray([";
124  const std::vector<double>& points = a->binCenters();
125  for (auto iter = points.begin(); iter != points.end() - 1; ++iter) {
126  result << pyfmt::printValue(*iter, unit) << ",";
127  }
128  result << pyfmt::printValue(points.back(), unit) << "])\n";
129  } else
130  throw std::runtime_error("printAxis not implemented for current axis type");
131  return result.str();
132 }
133 
134 //! Prints distribution with constructor parameters in given units.
135 //! ba.DistributionGaussian(2.0*deg, 0.02*deg)
136 
137 std::string printDistribution(const IDistribution1D& par_distr, const std::string& units)
138 {
139  std::unique_ptr<IDistribution1D> distr(par_distr.clone());
140  distr->setUnits(units);
141 
142  std::ostringstream result;
143  result << "ba." << distr->getName() << "(" << argumentList(distr.get()) << ")";
144  return result.str();
145 }
146 
148  const std::string& distVarName, const std::string& units)
149 {
150  std::ostringstream result;
151 
152  result << "ba.ParameterDistribution("
153  << "\"" << par_distr.getMainParameterName() << "\""
154  << ", " << distVarName << ", " << par_distr.getNbrSamples() << ", "
155  << pyfmt::printDouble(par_distr.getSigmaFactor())
156  << pyfmt::printRealLimitsArg(par_distr.getLimits(), units) << ")";
157 
158  return result.str();
159 }
160 
162 {
163  std::ostringstream result;
164  result << pyfmt::indent() << "distribution = ba.";
165  result << distr.name();
166  result << "(" << distr.nSamples() << ", " << pyfmt::printDouble(distr.sigmaFactor());
167  if (!distr.limits().isLimitless())
168  result << pyfmt::printRealLimitsArg(distr.limits());
169  result << ")";
170  return result.str();
171 }
172 
173 } // namespace pyfmt2
Defines and implements namespace algo with some algorithms.
Defines a few helper functions.
Defines M_PI and some more mathematical constants.
Defines classes representing one-dimensional distributions.
Defines class Rectangle.
Defines class FixedBinAxis.
Defines class InfinitePlane.
Defines class Line.
Defines class ParameterDistribution.
Defines class ParameterPool.
Defines class PointwiseAxis.
Defines class Polygon.
Defines namespace pyfmt2.
Defines functions in namespace pyfmt.
Defines functions in namespace pyfmt.
Defines classes representing ranged one-dimensional distributions.
Defines class RealParameter.
Defines class Rectangle.
Defines some unit conversion factors and other constants in namespace Units.
An ellipse, for use in detector masks.
Definition: Ellipse.h:23
Axis with fixed bin size.
Definition: FixedBinAxis.h:23
An infinite horizontal line.
Definition: Line.h:55
Interface for one-dimensional axes.
Definition: IAxis.h:25
Interface for one-dimensional distributions.
Definition: Distributions.h:34
virtual IDistribution1D * clone() const =0
Manages a local parameter pool, and a tree of child pools.
ParameterPool * parameterPool() const
Returns pointer to the parameter pool.
Interface for one-dimensional ranged distributions.
double sigmaFactor() const
Returns sigma factor to use during sampling.
virtual std::string name() const =0
Returns distribution name for python-formatted text.
RealLimits limits() const
Returns current limits of the distribution.
size_t nSamples() const
Returns number of samples to generate.
Basic class for all shapes in 2D.
Definition: IShape2D.h:27
The infinite plane is used for masking the entire detector.
Definition: InfinitePlane.h:28
A parametric distribution function, for use with any model parameter.
size_t getNbrSamples() const
get number of samples for this distribution
double getSigmaFactor() const
get the sigma factor
RealLimits getLimits() const
std::string getMainParameterName() const
get the main parameter's name
const std::vector< RealParameter * > parameters() const
Returns full vector of parameters.
Definition: ParameterPool.h:51
Axis containing arbitrary (non-equidistant) coordinate values.
Definition: PointwiseAxis.h:37
A polygon, for use in detector masks.
Definition: Polygon.h:30
bool isLimitless() const
Definition: RealLimits.cpp:173
Wraps a parameter of type double.
Definition: RealParameter.h:31
double value() const
Returns value of wrapped parameter.
std::string unit() const
A rectangle, for use in detector masks.
Definition: Rectangle.h:25
An infinite vertical line.
Definition: Line.h:38
std::string join(const std::vector< std::string > &joinable, const std::string &joint)
Returns string obtain by joining vector elements.
Definition: StringUtils.cpp:71
Utility functions for writing Python code snippets.
Definition: PyFmt2.cpp:36
std::string printParameterDistribution(const ParameterDistribution &par_distr, const std::string &distVarName, const std::string &units)
Definition: PyFmt2.cpp:147
std::string printAxis(const IAxis *axis, const std::string &unit)
Prints an axis.
Definition: PyFmt2.cpp:115
std::string printDistribution(const IDistribution1D &par_distr, const std::string &units)
Prints distribution with constructor parameters in given units.
Definition: PyFmt2.cpp:137
std::string valueTimesUnit(const RealParameter *par)
Returns parameter value, followed by its unit multiplicator (like "* nm").
Definition: PyFmt2.cpp:99
std::string argumentList(const IParametricComponent *ip)
Returns comma-separated list of parameter values, including unit multiplicator (like "* nm").
Definition: PyFmt2.cpp:106
std::string representShape2D(const std::string &indent, const IShape2D *ishape, bool mask_value, std::function< std::string(double)> printValueFunc)
Returns fixed Python code snippet that defines the function "runSimulation".
Definition: PyFmt2.cpp:40
std::string printRangedDistribution(const IRangedDistribution &distr)
Definition: PyFmt2.cpp:161
std::string printDegrees(double input)
Definition: PyFmt.cpp:111
std::string printDouble(double input)
Definition: PyFmt.cpp:41
std::string printBool(double value)
Definition: PyFmt.cpp:36
std::string printString(const std::string &value)
Definition: PyFmt.cpp:130
std::string indent(size_t width)
Returns a string of blanks with given width.
Definition: PyFmt.cpp:155
std::string printRealLimitsArg(const RealLimits &limits, const std::string &units)
Prints RealLimits in the form of argument (in the context of ParameterDistribution and similar).
Definition: PyFmtLimits.cpp:60
std::string printValue(double value, const std::string &units)
Definition: PyFmt.cpp:118