BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
algebraic_potential.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of BubbleProfiler.
3  *
4  * BubbleProfiler is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * BubbleProfiler is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with BubbleProfiler. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "algebraic_potential.hpp"
19 #include "error.hpp"
20 
21 #include <sstream>
22 
23 namespace BubbleProfiler {
24 
25 // Potential constructor - from expression string
27  const std::vector<std::string>& fields_,
28  const std::string& expr)
29  : fields(fields_)
30 {
31  // Parse the field expression & get symbol table
32  GiNaC::parser reader;
33  v = reader(expr);
34  GiNaC::symtab table = reader.get_syms();
35 
36  // Match fields names to symbol table
37  // TODO this should have error handling
38  for(auto& field : fields_) {
39  syms.push_back(GiNaC::ex_to<GiNaC::symbol>(table.at(field)));
40  }
41 
43 
44  std::stringstream log_str;
45  log_str << "Input potential: " << v;
47 }
48 
50 {
51  first_partials.clear();
52  second_partials.clear();
53 
54  for (const auto& sym: syms) {
55  GiNaC::ex deriv = v.diff(sym);
56  first_partials.push_back(deriv);
57 
58  std::vector<GiNaC::ex> row_partials;
59 
60  for (const auto& col_sym: syms) {
61  GiNaC::ex deriv2 = v.diff(sym).diff(col_sym);
62  row_partials.push_back(deriv2);
63  }
64 
65  second_partials.push_back(row_partials);
66  }
67 }
68 
70  const Eigen::VectorXd& translation)
71 {
72  const std::size_t n_coords = translation.size();
73  if (n_coords != syms.size()) {
74  throw Setup_error(
75  "Algebraic_potential::translate_origin: "
76  "dimensions of translation do not match number of fields");
77  }
78 
79  // Create coordinate substitutions
80  GiNaC::lst l;
81  for (std::size_t i = 0; i < n_coords; ++i) {
82  l.append(syms[i] == syms[i] + translation[i]);
83  }
84 
85  // Apply them
86  v = v.subs(l);
87 
88  // Rebuild algebraic derivatives
90 
91  std::stringstream log_str;
92  log_str << "Potential after translation: " << v;
94 }
95 
96 void Algebraic_potential::apply_basis_change(const Eigen::MatrixXd &cob_matrix) {
97  Eigen::MatrixXd cob_matrix_t = cob_matrix.transpose();
98  int n_coords = syms.size();
99 
100  // Create basis transformation substitution map
101  GiNaC::exmap substitutions;
102 
103  for (int old_field_ix = 0; old_field_ix < n_coords; ++old_field_ix) {
104 
105  // Build the RHS of the substitution for this field.
106  GiNaC::ex rhs = 0;
107 
108  for (int new_field_ix = 0; new_field_ix < n_coords; ++new_field_ix) {
109  double coeff = cob_matrix(new_field_ix, old_field_ix);
110  rhs += coeff * syms[new_field_ix];
111  }
112 
113  // Add the substitution for this field to the transformation map
114  substitutions[syms[old_field_ix]] = rhs;
115  }
116 
117  std::stringstream subs_str;
118  subs_str << "Subs: " << substitutions;
120 
121  // Apply all of the transformations simultaneously
122  v = v.subs(substitutions);
123 
124  // Rebuild algebraic derivatives
126 
127  std::stringstream expr_str;
128  expr_str << "Potential after translation: " << v;
130 }
131 
133 {
134  v += offset;
135 
136  std::stringstream expr_str;
137  expr_str << "Potential after adding constant term: " << v;
139 }
140 
141 // Evaluate a GiNaC expression (i.e. potential, partial derivatives) on
142 // this potential.
144  const GiNaC::ex& expr, const Eigen::VectorXd& coords) const
145 {
146  const std::size_t n_coords = coords.size();
147  if (n_coords != syms.size()) {
148  throw Setup_error(
149  "Algebraic_potential::eval: "
150  "number of values does not match number of coordinates");
151  }
152 
153  // A list of substitutions
154  GiNaC::lst l;
155  for (std::size_t i = 0; i < n_coords; ++i) {
156  l.append(syms[i] == coords(i));
157  }
158 
159  // Make subs & eval
160  GiNaC::ex result = GiNaC::evalf(expr.subs(l));
161 
162  return GiNaC::ex_to<GiNaC::numeric>(result).to_double();
163 }
164 
165 // Evaluate potential at a coordinate
166 double Algebraic_potential::operator()(const Eigen::VectorXd& coords) const
167 {
168  return Algebraic_potential::eval(v, coords);
169 }
170 
171 // Partial derivative WRT coordinate i at a point
172 double Algebraic_potential::partial(const Eigen::VectorXd& coords, int i) const
173 {
174  return Algebraic_potential::eval(first_partials[i], coords);
175 }
176 
177 // Partial derivatives WRT coordinates i, j at a a point
178 double Algebraic_potential::partial(const Eigen::VectorXd& coords,
179  int i, int j) const
180 {
181  return Algebraic_potential::eval(second_partials[i][j], coords);
182 }
183 
184 } // namespace BubbleProfiler
virtual void add_constant_term(double) override
Add a constant offset to the potential.
virtual void apply_basis_change(const Eigen::MatrixXd &) override
Apply a change of basis matrix.
virtual double partial(const Eigen::VectorXd &coords, int i) const override
Partial derivative WRT coordinate i at a point.
void log_message(Log_level level, const std::string &msg) const
GiNaC::ex v
GiNaC expression to hold potential.
std::vector< GiNaC::symbol > syms
GiNaC symbols matched to fields vec.
Algebraic_potential(const std::vector< std::string > &fields, const std::string &expr)
Construct from list of fields and GiNaC potential string.
std::vector< std::vector< GiNaC::ex > > second_partials
Second partials.
virtual double operator()(const Eigen::VectorXd &coords) const override
Evaluate potential at point.
double eval(const GiNaC::ex &, const Eigen::VectorXd &) const
virtual void translate_origin(const Eigen::VectorXd &) override
Shift the location of the origin by a specified vector.
std::vector< GiNaC::ex > first_partials
First partials.
Exception indicating general setup error.
Definition: error.hpp:32