Bridge++  Ver. 2.0.2
math_Sign_Zolotarev.cpp
Go to the documentation of this file.
1 
14 #include "math_Sign_Zolotarev.h"
15 
16 #include <cstdlib>
17 #include <cfloat>
18 
19 using Bridge::vout;
20 using std::abs;
21 
22 const std::string Math_Sign_Zolotarev::class_name = "Math_Sign_Zolotarev";
23 
24 //====================================================================
25 void Math_Sign_Zolotarev::get_sign_parameters(std::vector<double>& cl,
26  std::vector<double>& bl)
27 {
28  //- Zolotarev coefficient defined
29 
30  if (cl.size() != 2 * m_Np) {
31  vout.crucial(m_vl, "Error at %s: size of cl is not correct\n", class_name.c_str());
32  exit(EXIT_FAILURE);
33  }
34 
35  if (bl.size() != m_Np) {
36  vout.crucial(m_vl, "Error at %s: size of bl is not correct\n", class_name.c_str());
37  exit(EXIT_FAILURE);
38  }
39 
40  for (int i = 0; i < 2 * m_Np; ++i) {
41  cl[i] = m_cl[i];
42  }
43 
44  for (int i = 0; i < m_Np; ++i) {
45  bl[i] = m_bl[i];
46  }
47 }
48 
49 
50 //====================================================================
52 {
53  // Zolotarev coefficient defined
54  m_cl.resize(2 * m_Np);
55  m_bl.resize(m_Np);
56 
57  double UK = 0.0;
58  vout.general(m_vl, " bmax = %12.4e\n", m_bmax);
59  vout.general(m_vl, " UK = %12.4e\n", UK);
60 
62 
63  // for(int i=0; i<m_Np; i++){
64  // vout.general(m_vl, " %3d %12.4e %12.4e %12.4e\n", i, m_cl[i],
65  // m_cl[i+m_Np], m_bl[i]);
66  // }
67 }
68 
69 
70 //====================================================================
71 double Math_Sign_Zolotarev::sign(const double x)
72 {
73  //- cl[2*Np], bl[Np]: coefficients of rational approx.
74 
75  double x2R = 0.0;
76 
77  for (int l = 0; l < m_Np; l++) {
78  x2R += m_bl[l] / (x * x + m_cl[2 * l]);
79  }
80  x2R = x2R * (x * x + m_cl[2 * m_Np - 1]);
81 
82  return x * x2R;
83 }
84 
85 
86 //====================================================================
87 void Math_Sign_Zolotarev::poly_Zolotarev(const double bmax, double& UK)
88 {
89 // Return the coefficients of Zolotarev's approximation
90 // of sign function to rational function.
91 //
92 // Np: number of poles (2*Np is number of cl)
93 // bmax: range of argument [1,bmax]
94 // UK: complete elliptic integral of the 1st kind
95 // cl[2*Np],bl[Np]: coefficients of Zolotarev rational approx.
96 
97  const int Nprec = 14;
98 
99  const double rk = sqrt(1.0 - 1.0 / (bmax * bmax));
100  const double emmc = 1.0 - rk * rk;
101 
102  vout.general(m_vl, "emmc = %22.14e\n", emmc);
103 
104  double sn, cn, dn;
105 
106  //- Determination of K
107  double Dsr = 10.0;
108  double u = 0.0;
109  for (int i_prec = 0; i_prec < Nprec + 1; i_prec++) {
110  Dsr = Dsr * 0.1;
111 
112  for (int i = 0; i < 20; i++) {
113  u = u + Dsr;
114  Jacobi_elliptic(u, emmc, sn, cn, dn);
115  vout.detailed(m_vl, " %22.14e %22.14e %22.14e\n", u, sn, cn);
116  if (cn < 0.0) goto succeeded;
117  }
118  vout.general(m_vl, "Something wrong in setting Zolotarev\n");
119  return;
120 
121 succeeded:
122  u = u - Dsr;
123  }
124 
125  UK = u;
126 
127  Jacobi_elliptic(UK, emmc, sn, cn, dn);
128  vout.general(m_vl, " %22.14e %22.14e %22.14e\n", UK, sn, cn);
129 
130 
131  //- Determination of c_l
132  const double FK = UK / (2.0 * m_Np + 1.0);
133 
134  for (int l = 0; l < 2 * m_Np; l++) {
135  u = FK * (l + 1.0);
136  Jacobi_elliptic(u, emmc, sn, cn, dn);
137  m_cl[l] = sn * sn / (1.0 - sn * sn);
138  }
139 
140  //- Determination of b_l
141  double d0 = 1.0;
142  for (int l = 0; l < m_Np; l++) {
143  d0 = d0 * (1.0 + m_cl[2 * l]) / (1.0 + m_cl[2 * l + 1]);
144  }
145 
146  for (int l = 0; l < m_Np; l++) {
147  m_bl[l] = d0;
148  for (int i = 0; i < m_Np; i++) {
149  if (i < m_Np - 1) m_bl[l] = m_bl[l] * (m_cl[2 * i + 1] - m_cl[2 * l]);
150  if (i != l) m_bl[l] = m_bl[l] / (m_cl[2 * i] - m_cl[2 * l]);
151  }
152  }
153 
154  //- Correction
155  const int Nj = 10000;
156  const double Dx = (bmax - 1.0) / Nj;
157 
158  double d1 = 0.0;
159  double d2 = 2.0;
160 
161  for (int jx = 0; jx <= Nj; jx++) {
162  double x = 1.0 + Dx * jx;
163  double sgnx = sign(x);
164  if (fabs(sgnx) > d1) d1 = sgnx;
165  if (fabs(sgnx) < d2) d2 = sgnx;
166  }
167  vout.general(m_vl, " |sgnx|_up = %8.4e \n", d1 - 1.0);
168  vout.general(m_vl, " |sgnx|_dn = %8.4e \n", 1.0 - d2);
169 
170  /*
171  double d0c = 0.5*(d1+d2);
172  for(int ip=0; ip<m_Np; ip++){
173  m_bl[ip] = m_bl[ip]/d0c;
174  };
175 
176  d1 = 0.0;
177  d2 = 2.0;
178  for(int jx=0; jx <= Nj; jx++){
179  double x = 1.0 + Dx*jx;
180  double sgnx = sign(x);
181  if(fabs(sgnx) > d1) d1 = sgnx;
182  if(fabs(sgnx) < d2) d2 = sgnx;
183  }
184  vout.general(m_vl, " |sgnx|_up = %8.4e \n", d1-1.0);
185  vout.general(m_vl, " |sgnx|_dn = %8.4e \n", 1.0-d2);
186  */
187 
188  double dmax = d1 - 1.0;
189  if (dmax < 1.0 - d2) dmax = 1.0 - d2;
190  vout.general(m_vl, " Amp(1-|sgn|) = %16.8e \n", dmax);
191 }
192 
193 
194 //====================================================================
195 void Math_Sign_Zolotarev::Jacobi_elliptic(const double uu, const double emmc,
196  double& sn, double& cn, double& dn)
197 {
198 // Return the Jacobi elliptic functions sn(u,kc),
199 // cn(u,kc), and dn(u,kc), where kc = 1 - k^2, and
200 // arguments:
201 // uu: u
202 // emmc: kc.
203 //
204 // This routine is based on GSL. [19 Jun 2013 S.Ueda]
205 
206  // The accuracy
207  const double epsilon = DBL_EPSILON;
208  // Max number of iteration
209  const int N = 16;
210 
211  const double emmc1 = 1 - emmc;
212 
213  if (abs(emmc1) > 1.0) {
214  sn = cn = dn = 0;
215  vout.crucial("Error at %s: parameter m = %f must be smaller than 1.\n", class_name.c_str(), emmc1);
216  exit(EXIT_FAILURE);
217  } else if (abs(emmc1) < 2.0 * epsilon) {
218  sn = sin(uu);
219  cn = cos(uu);
220  dn = 1.0;
221  } else if (abs(emmc1 - 1) < 2.0 * epsilon) {
222  sn = tanh(uu);
223  cn = 1.0 / cosh(uu);
224  dn = cn;
225  } else {
226  double mu[N];
227  double nu[N];
228 
229  int n = 0;
230 
231  mu[0] = 1.0;
232  nu[0] = sqrt(1.0 - emmc1);
233 
234  while (abs(mu[n] - nu[n]) > epsilon * abs(mu[n] + nu[n]))
235  {
236  mu[n + 1] = 0.5 * (mu[n] + nu[n]);
237  nu[n + 1] = sqrt(mu[n] * nu[n]);
238  ++n;
239  if (n >= N - 1) {
240  vout.general(m_vl, "max iteration\n");
241  break;
242  }
243  }
244 
245  double sin_umu = sin(uu * mu[n]);
246  double cos_umu = cos(uu * mu[n]);
247 
248  /* Since sin(u*mu(n)) can be zero we switch to computing sn(K-u),
249  cn(K-u), dn(K-u) when |sin| < |cos| */
250  if (fabs(sin_umu) < fabs(cos_umu)) {
251  double cot = sin_umu / cos_umu;
252  double cs = mu[n] * cot;
253  dn = 1.0;
254 
255  while (n > 0)
256  {
257  --n;
258  double r = cs * cs / mu[n + 1];
259  cs *= dn;
260  dn = (r + nu[n]) / (r + mu[n]);
261  }
262 
263  double sqrt_m1 = sqrt(1.0 - emmc1);
264  dn = sqrt_m1 / dn;
265  // Is hypot(1, cs) better sqrt(1 + cs * cs)?
266  cn = dn * (cos_umu > 0 ? 1 : -1) / sqrt(1 + cs * cs);
267  sn = cn * cs / sqrt_m1;
268  } else {
269  double cot = cos_umu / sin_umu;
270  double cs = mu[n] * cot;
271  dn = 1.0;
272 
273  while (n > 0)
274  {
275  --n;
276  double r = cs * cs / mu[n + 1];
277  cs *= dn;
278  dn = (r + nu[n]) / (r + mu[n]);
279  }
280  // Is hypot(1, cs) better than sqrt(1 + cs * cs)
281  sn = (sin_umu > 0 ? 1 : -1) / sqrt(1 + cs * cs);
282  cn = cs * sn;
283  }
284  }
285 }
286 
287 
288 //====================================================================
289 //============================================================END=====
Math_Sign_Zolotarev::m_bl
std::vector< double > m_bl
Definition: math_Sign_Zolotarev.h:48
Math_Sign_Zolotarev::get_sign_parameters
void get_sign_parameters(std::vector< double > &cl, std::vector< double > &bl)
Definition: math_Sign_Zolotarev.cpp:25
Math_Sign_Zolotarev::poly_Zolotarev
void poly_Zolotarev(const double bmax, double &UK)
Definition: math_Sign_Zolotarev.cpp:87
Math_Sign_Zolotarev::sign
double sign(const double x)
Definition: math_Sign_Zolotarev.cpp:71
Bridge::BridgeIO::detailed
void detailed(const char *format,...)
Definition: bridgeIO.cpp:219
Math_Sign_Zolotarev::Jacobi_elliptic
void Jacobi_elliptic(const double uu, const double emmc, double &sn, double &cn, double &dn)
Definition: math_Sign_Zolotarev.cpp:195
Math_Sign_Zolotarev::set_sign_parameters
void set_sign_parameters()
Definition: math_Sign_Zolotarev.cpp:51
Math_Sign_Zolotarev::m_cl
std::vector< double > m_cl
Definition: math_Sign_Zolotarev.h:47
math_Sign_Zolotarev.h
Math_Sign_Zolotarev::m_bmax
double m_bmax
Definition: math_Sign_Zolotarev.h:46
Math_Sign_Zolotarev::m_vl
Bridge::VerboseLevel m_vl
Definition: math_Sign_Zolotarev.h:42
Math_Sign_Zolotarev::class_name
static const std::string class_name
Definition: math_Sign_Zolotarev.h:39
Math_Sign_Zolotarev::m_Np
int m_Np
Definition: math_Sign_Zolotarev.h:45
Bridge::BridgeIO::crucial
void crucial(const char *format,...)
Definition: bridgeIO.cpp:180
Bridge::BridgeIO::general
void general(const char *format,...)
Definition: bridgeIO.cpp:200
Bridge::vout
BridgeIO vout
Definition: bridgeIO.cpp:512