OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
Enge.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017, Chris Rogers
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  * 1. Redistributions of source code must retain the above copyright notice,
7  * this list of conditions and the following disclaimer.
8  * 2. Redistributions in binary form must reproduce the above copyright notice,
9  * this list of conditions and the following disclaimer in the documentation
10  * and/or other materials provided with the distribution.
11  * 3. Neither the name of STFC nor the names of its contributors may be used to
12  * endorse or promote products derived from this software without specific
13  * prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <cmath>
29 
30 #include "gsl/gsl_sf_gamma.h"
31 #include "gsl/gsl_sf_pow_int.h"
32 
34 
35 namespace endfieldmodel {
36 
37 // Use
38 // d^n E/dx^n = a_n1m1 F(n1) g(m1) + a_n2m1m2 F(n2) g(m1)g(m2)+...
39 // where
40 double Enge::getEnge(double x, int n) const {
41  std::vector< std::vector<int> > qt = getQIndex(n);
42  std::vector<double> g;
43  double e(0.);
44  for (size_t i = 0; i < qt.size(); ++i) {
45  double ei(qt[i][0]);
46  for (size_t j = 1; j < qt[i].size(); ++j) {
47  if (j > g.size()) g.push_back(gN(x, j-1));
48  ei *= gsl_sf_pow_int(g[j-1], qt[i][j]);
49  }
50  if (ei != ei) ei = 0; // div 0, usually g == 0 and index < 0
51  e += ei;
52  }
53  return e;
54 }
55 
56 // h = a_0+a_1 (x/w)+a_2 (x/w)^2+a_3 (x/w)^3+...+a_m (x/w)^m
57 // h^(n) = d^nh/dx^n = sum^m_{i=n} a_i x^{i-n}/w^i i!/n!
58 double Enge::hN(double x, int n) const {
59  double hn = 0;
60  // optimise by precalculating factor
61  for (unsigned int i = n; i <_a.size(); i++)
62  hn += _a[i]/gsl_sf_pow_int(_lambda, i)*gsl_sf_pow_int(x, i-n)*
63  gsl_sf_fact(i)/gsl_sf_fact(i-n);
64  return hn;
65 }
66 
67 // g = 1+exp(h)
68 // g^(n) = d^ng/dx^n
69 double Enge::gN(double x, int n) const {
70  if (n == 0) return 1+exp(hN(x, 0)); // special case
71  std::vector<double> hn(n+1);
72  for (int i = 0; i <= n; i++) hn[i] = hN(x, i);
73  double exp_h0 = exp(hn[0]);
74  double gn = 0;
75  for (size_t i = 0; i < _h[n].size(); ++i) {
76  double gnj = _h[n][i][0]*exp_h0;
77  for (size_t j = 1; j < _h[n][i].size(); ++j)
78  gnj *= gsl_sf_pow_int(hn[j], _h[n][i][j]);
79  gn += gnj;
80  }
81  return gn;
82 }
83 
84 // _q[i][j][k]; urk, 3d vector
85 // i indexes the derivative of f;
86 // j indexes the element in f derivative
87 // k indexes the derivative of g
88 // this will quickly become grotesque
89 std::vector< std::vector< std::vector<int> > > Enge::_q;
90 std::vector< std::vector< std::vector<int> > > Enge::_h;
92  if (_q.size() == 0) {
93  _q.push_back(std::vector< std::vector<int> >(1, std::vector<int>(3)) );
94  _q[0][0][0] = +1; // f_0 = 1*g^(-1)
95  _q[0][0][1] = -1;
96  _q[0][0][2] = 0;
97  }
98 
99  for (size_t i = _q.size(); i < n+1; ++i) {
100  _q.push_back(std::vector< std::vector<int> >() );
101  for (size_t j = 0; j < _q[i-1].size(); ++j) {
102  size_t k_max = _q[i-1][j].size();
103  std::vector<int> new_vec(_q[i-1][j]);
104  // derivative of g^-n0 = -n0*g^(-n0-1)*g(1)
105  new_vec[0] *= new_vec[1]; // alpha *= g(0) power
106  new_vec[1] -= 1; // g(0) power -= 1
107  new_vec[2] += 1; // g(1) power += 1
108  _q[i].push_back(new_vec);
109  for (size_t k = 2; k < k_max; ++k) { // 0 is alpha; 1 is g(0)
110  // derivative of g(k)^nk = nk g(k+1) g(k)^(nk-1)
111  if (_q[i-1][j][k] > 0) {
112  std::vector<int> new_vec(_q[i-1][j]);
113  if ( k == k_max-1 ) new_vec.push_back(0); // need enough coefficients
114  new_vec[0] *= new_vec[k];
115  new_vec[k] -= 1;
116  new_vec[k+1] += 1;
117  _q[i].push_back(new_vec);
118  }
119  }
120  }
121  }
122 
123  if (_h.size() == 0) {
124  // first one is special case (1+e^h dealt with explicitly)
125  _h.push_back(std::vector< std::vector<int> >());
126  // second is (1*e^h h'^1)
127  _h.push_back(std::vector< std::vector<int> >());
128  _h[1].push_back(std::vector<int>(2, 1));
129  }
130  for (size_t i = _h.size(); i < n+1; ++i) {
131  _h.push_back(std::vector< std::vector<int> >());
132  for (size_t j = 0; j < _h[i-1].size(); ++j) {
133  // d/dx k0 e^g g(1)^k1 ... g(n)^kn ... = k0 e^g g(1)^(k1+1) ... g(n)^kn
134  // + SUM_n k0 kn e^g ... g(n)^(kn-1) g(n-1)
135  std::vector<int> new_vec(_h[i-1][j]);
136  new_vec[1] += 1;
137  _h[i].push_back(new_vec);
138  for (size_t k = 1; k <_h[i-1][j].size(); ++k) {
139  if (_h[i-1][j][k] > 0) {
140  std::vector<int> new_vec(_h[i-1][j]);
141  if (k == _h[i-1][j].size()-1) new_vec.push_back(0);
142  new_vec[0] *= new_vec[k];
143  new_vec[k] -= 1;
144  new_vec[k+1] += 1;
145  _h[i].push_back(new_vec);
146  }
147  }
148  }
149  _h[i] = CompactVector(_h[i]);
150  }
151 }
152 
153 Enge::Enge(const std::vector<double> a, double x0, double lambda)
154  : _a(a), _lambda(lambda), _x0(x0) {
155 }
156 
157 Enge* Enge::clone() const {
158  Enge* myclone = new Enge(_a, _x0, _lambda);
159  return myclone;
160 }
161 
162 void Enge::rescale(double scaleFactor) {
163  _x0 *= scaleFactor;
164  _lambda *= scaleFactor;
165 }
166 
167 std::ostream& Enge::print(std::ostream& out) const {
168  out << "Enge function l=" << _lambda << " x0=" << _x0 << " c=";
169  for (auto ai: _a) {
170  out << ai << " ";
171  }
172  return out;
173 }
174 }
175 
double getEnge(double x, int n) const
Definition: Enge.cpp:40
std::vector< std::vector< int > > CompactVector(std::vector< std::vector< int > > vec)
Tps< T > exp(const Tps< T > &x)
Exponential.
Definition: TpsMath.h:165
static std::vector< std::vector< int > > getQIndex(int n)
Definition: Enge.h:159
static std::vector< std::vector< std::vector< int > > > _h
Definition: Enge.h:148
std::ostream & print(std::ostream &out) const
Definition: Enge.cpp:167
static std::vector< std::vector< std::vector< int > > > _q
Definition: Enge.h:146
static void setEngeDiffIndices(size_t n)
Definition: Enge.cpp:91
std::vector< double > _a
Definition: Enge.h:142
double hN(double x, int n) const
Definition: Enge.cpp:58
constexpr double e
The value of .
Definition: Physics.h:39
double _lambda
Definition: Enge.h:143
Enge * clone() const
Definition: Enge.cpp:157
double gN(double x, int n) const
Definition: Enge.cpp:69
void rescale(double scaleFactor)
Definition: Enge.cpp:162