BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
PyFmt.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Base/Py/PyFmt.cpp
6 //! @brief Implements functions from namespace pyfmt.
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 "Base/Py/PyFmt.h"
16 #include "Base/Const/Units.h" // printDegrees
17 #include "Base/Math/Constants.h"
18 #include "Base/Util/Algorithms.h"
19 #include "Base/Util/StringUtils.h"
20 #include <iomanip>
21 
22 namespace Py::Fmt {
23 
24 std::string printImportedSymbols(const std::string& code)
25 {
26  std::vector<std::string> to_declare;
27  for (const std::string key : {"angstrom", "deg", "nm", "nm2", "micrometer"})
28  if (code.find("*" + key) != std::string::npos)
29  to_declare.push_back(key);
30  for (const std::string key : {"R3"})
31  if (code.find(key) != std::string::npos)
32  to_declare.push_back(key);
33  return "from bornagain import " + BaseUtils::String::join(to_declare, ", ") + "\n";
34 }
35 
36 std::string printInt(int value)
37 {
38  return std::to_string(value);
39 }
40 
41 std::string printBool(double value)
42 {
43  return value ? "True" : "False";
44 }
45 
46 std::string printDouble(double input)
47 {
48  std::ostringstream inter;
49  inter << std::setprecision(12);
50  if (std::abs(input) < std::numeric_limits<double>::epsilon()) {
51  inter << "0.0";
52  return inter.str();
53  }
54  inter << input;
55  if (inter.str().find('e') == std::string::npos && inter.str().find('.') == std::string::npos)
56  inter << ".0";
57  return inter.str();
58 }
59 
60 //! prints double as an integer, if possible within standard accuracy
61 std::string printLightDouble(double input)
62 {
63  std::ostringstream inter;
64  int ival = std::lround(input);
65  if (std::abs(input - ival) < 1e-11)
66  inter << ival;
67  else {
68  inter << std::setprecision(12);
69  if (std::abs(input) < std::numeric_limits<double>::epsilon())
70  return "0.0";
71  inter << input;
72  if (inter.str().find('e') == std::string::npos
73  && inter.str().find('.') == std::string::npos)
74  inter << ".0";
75  }
76  return inter.str();
77 }
78 
79 std::string printNm(double input)
80 {
81  std::ostringstream inter;
82  inter << std::setprecision(12);
83  inter << printLightDouble(input) << "*nm";
84  return inter.str();
85 }
86 
87 std::string printNm2(double input)
88 {
89  std::ostringstream inter;
90  inter << std::setprecision(12);
91  inter << printLightDouble(input) << "*nm2";
92  return inter.str();
93 }
94 
95 // 1.000000e+07 -> 1.0e+07
96 std::string printScientificDouble(double input)
97 {
98  std::ostringstream inter;
99  inter << std::scientific;
100  inter << input;
101 
102  std::string::size_type pos = inter.str().find('e');
103  if (pos == std::string::npos)
104  return inter.str();
105 
106  std::string part1 = inter.str().substr(0, pos);
107  std::string part2 = inter.str().substr(pos, std::string::npos);
108 
109  part1.erase(part1.find_last_not_of('0') + 1, std::string::npos);
110  if (part1.back() == '.')
111  part1 += "0";
112 
113  return part1 + part2;
114 }
115 
116 std::string printDegrees(double input)
117 {
118  std::ostringstream inter;
119  inter << printLightDouble(Units::rad2deg(input)) << "*deg";
120  return inter.str();
121 }
122 
123 std::string printValue(double value, const std::string& units)
124 {
125  if (units == "rad")
126  return printDegrees(value);
127  if (units == "nm")
128  return printNm(value);
129  if (units.empty())
130  return printDouble(value);
131  ASSERT(0);
132 }
133 
134 std::string printValue(std::variant<double, int> value, const std::string& units /*= ""*/)
135 {
136  if (std::holds_alternative<int>(value)) {
137  ASSERT(units.empty()); // int with units is not supported. Implement when necessary.
138  return printInt(std::get<int>(value));
139  }
140 
141  return printValue(std::get<double>(value), units);
142 }
143 
144 std::string printString(const std::string& value)
145 {
146  std::ostringstream result;
147  result << "\"" << value << "\"";
148  return result.str();
149 }
150 
151 std::string printArguments(const std::vector<std::pair<double, std::string>>& arguments)
152 {
153  std::vector<std::string> args;
154  for (const auto& argument : arguments)
155  args.push_back(Py::Fmt::printValue(argument.first, argument.second));
156  return BaseUtils::String::join(args, ", ");
157 }
158 
159 std::string
160 printArguments(const std::vector<std::pair<std::variant<double, int>, std::string>>& arguments)
161 {
162  std::vector<std::string> args;
163  for (const auto& argument : arguments)
164  args.push_back(Py::Fmt::printValue(argument.first, argument.second));
165  return BaseUtils::String::join(args, ", ");
166 }
167 
168 std::string printFunction(const std::string& name,
169  const std::vector<std::pair<double, std::string>>& arguments)
170 {
171  return name + "(" + printArguments(arguments) + ")";
172 }
173 
174 std::string printFunction(const std::string& name, double value, const std::string& unit)
175 {
176  return printFunction(name, {{value, unit}});
177 }
178 
179 std::string printFunction(const std::string& name, double value1, const std::string& unit1,
180  double value2, const std::string& unit2)
181 {
182  return printFunction(name, {{value1, unit1}, {value2, unit2}});
183 }
184 
185 bool isSquare(double length1, double length2, double angle)
186 {
187  return length1 == length2 && BaseUtils::algo::almostEqual(angle, M_PI_2);
188 }
189 
190 bool isHexagonal(double length1, double length2, double angle)
191 {
192  return length1 == length2 && BaseUtils::algo::almostEqual(angle, M_TWOPI / 3.0);
193 }
194 
195 std::string printKvector(const R3 value)
196 {
197  std::ostringstream result;
198  result << "R3(" << printDouble(value.x()) << ", " << printDouble(value.y()) << ", "
199  << printDouble(value.z()) << ")";
200  return result.str();
201 }
202 
203 std::string indent(size_t width)
204 {
205  return std::string(width, ' ');
206 }
207 
208 } // namespace Py::Fmt
Defines and implements namespace BaseUtils::algo with some algorithms.
#define ASSERT(condition)
Definition: Assert.h:45
Defines a few helper functions.
Defines M_PI and some more mathematical constants.
#define M_TWOPI
Definition: Constants.h:54
#define M_PI_2
Definition: Constants.h:45
Defines namespace pyfmt.
Defines some unit conversion factors and other constants in namespace Units.
std::string scientific(T value, int n=10)
Returns scientific string representing given value of any numeric type.
Definition: StringUtils.h:75
std::string join(const std::vector< std::string > &joinable, const std::string &joint)
Returns string obtain by joining vector elements.
Definition: StringUtils.cpp:45
bool almostEqual(double a, double b)
Returns true if two doubles agree within machine epsilon.
Definition: Algorithms.h:33
Utility functions for writing Python code snippets.
Definition: PyFmt.cpp:22
std::string printDegrees(double input)
Definition: PyFmt.cpp:116
std::string printDouble(double input)
Definition: PyFmt.cpp:46
std::string printLightDouble(double input)
prints double as an integer, if possible within standard accuracy
Definition: PyFmt.cpp:61
std::string printString(const std::string &value)
Definition: PyFmt.cpp:144
std::string printKvector(const R3 value)
Definition: PyFmt.cpp:195
std::string printScientificDouble(double input)
Definition: PyFmt.cpp:96
std::string printNm(double input)
Definition: PyFmt.cpp:79
bool isHexagonal(double length1, double length2, double angle)
Definition: PyFmt.cpp:190
std::string printBool(double value)
Definition: PyFmt.cpp:41
std::string indent(size_t width)
Returns a string of blanks with given width. By default the width equals standard offset in python fi...
Definition: PyFmt.cpp:203
std::string printNm2(double input)
Definition: PyFmt.cpp:87
std::string printFunction(const std::string &name, const std::vector< std::pair< double, std::string >> &arguments)
Print a function in the form "<name>(<arguments>)". arguments will be processed by printArguments(),...
Definition: PyFmt.cpp:168
std::string printArguments(const std::vector< std::pair< double, std::string >> &arguments)
Takes pairs of value/unit and concatenates them for an argument list. Each pair's content will be pro...
Definition: PyFmt.cpp:151
std::string printValue(double value, const std::string &units)
Definition: PyFmt.cpp:123
bool isSquare(double length1, double length2, double angle)
Definition: PyFmt.cpp:185
std::string printImportedSymbols(const std::string &code)
Definition: PyFmt.cpp:24
std::string printInt(int value)
Definition: PyFmt.cpp:36
double rad2deg(double angle)
Definition: Units.h:54