Bridge++  Version 1.4.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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(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(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  int Nprec = 14;
98 
99  double rk = sqrt(1.0 - 1.0 / (bmax * bmax));
100  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  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  int Nj = 10000;
156  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(double uu, 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, emmc: kc.
202 //
203 // This routine is based on GSL.
204 // Typed by S. UEDA June 19, 2013
205 
206 
207  // The accuracy
208  const double epsilon = DBL_EPSILON;
209  // Max number of iteration
210  const int N = 16;
211 
212  emmc = 1 - emmc;
213 
214  if (abs(emmc) > 1.0) {
215  sn = cn = dn = 0;
216  vout.crucial("Error at %s: parameter m = %f must be smaller then 1.\n", class_name.c_str(), emmc);
217  exit(EXIT_FAILURE);
218  } else if (abs(emmc) < 2.0 * epsilon) {
219  sn = sin(uu);
220  cn = cos(uu);
221  dn = 1.0;
222  } else if (abs(emmc - 1) < 2.0 * epsilon) {
223  sn = tanh(uu);
224  cn = 1.0 / cosh(uu);
225  dn = cn;
226  } else {
227  double mu[N];
228  double nu[N];
229 
230  int n = 0;
231 
232  mu[0] = 1.0;
233  nu[0] = sqrt(1.0 - emmc);
234 
235  while (abs(mu[n] - nu[n]) > epsilon * abs(mu[n] + nu[n]))
236  {
237  mu[n + 1] = 0.5 * (mu[n] + nu[n]);
238  nu[n + 1] = sqrt(mu[n] * nu[n]);
239  ++n;
240  if (n >= N - 1) {
241  vout.general(m_vl, "max iteration\n");
242  break;
243  }
244  }
245 
246  double sin_umu = sin(uu * mu[n]);
247  double cos_umu = cos(uu * mu[n]);
248 
249  /* Since sin(u*mu(n)) can be zero we switch to computing sn(K-u),
250  cn(K-u), dn(K-u) when |sin| < |cos| */
251  if (abs(sin_umu < cos_umu)) {
252  double cot = sin_umu / cos_umu;
253  double cs = mu[n] * cot;
254  dn = 1.0;
255 
256  while (n > 0)
257  {
258  --n;
259  double r = cs * cs / mu[n + 1];
260  cs *= dn;
261  dn = (r + nu[n]) / (r + mu[n]);
262  }
263 
264  double sqrtm1 = sqrt(1.0 - emmc);
265  dn = sqrtm1 / dn;
266  // Is hypot(1, cs) better sqrt(1 + cs * cs)?
267  cn = dn * (cos_umu > 0 ? 1 : -1) / sqrt(1 + cs * cs);
268  sn = cn * cs / sqrtm1;
269  } else {
270  double cot = cos_umu / sin_umu;
271  double cs = mu[n] * cot;
272  dn = 1.0;
273 
274  while (n > 0)
275  {
276  --n;
277  double r = cs * cs / mu[n + 1];
278  cs *= dn;
279  dn = (r + nu[n]) / (r + mu[n]);
280  }
281  // Is hypot(1, cs) better than sqrt(1 + cs * cs)
282  sn = (sin_umu > 0 ? 1 : -1) / sqrt(1 + cs * cs);
283  cn = cs * sn;
284  }
285  }
286 }
287 
288 
289 //====================================================================
290 //============================================================END=====
BridgeIO vout
Definition: bridgeIO.cpp:495
void detailed(const char *format,...)
Definition: bridgeIO.cpp:212
void get_sign_parameters(std::vector< double > &cl, std::vector< double > &bl)
void general(const char *format,...)
Definition: bridgeIO.cpp:195
void poly_Zolotarev(double bmax, double &UK)
void Jacobi_elliptic(double uu, double emmc, double &sn, double &cn, double &dn)
Bridge::VerboseLevel m_vl
static const std::string class_name
std::vector< double > m_bl
void crucial(const char *format,...)
Definition: bridgeIO.cpp:178
std::vector< double > m_cl