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