Bridge++  Ver. 1.2.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 const std::string Math_Sign_Zolotarev::class_name = "Math_Sign_Zolotarev";
22 
23 //====================================================================
24 void Math_Sign_Zolotarev::get_sign_parameters(std::valarray<double>& cl,
25  std::valarray<double>& bl)
26 {
27  //- Zolotarev coefficient defined
28 
29  if (cl.size() != 2 * m_Np) {
30  vout.crucial(m_vl, "size of cl is not correct\n");
31  abort();
32  }
33 
34  if (bl.size() != m_Np) {
35  vout.crucial(m_vl, "size of bl is not correct\n");
36  abort();
37  }
38 
39  for (int i = 0; i < 2 * m_Np; ++i) {
40  cl[i] = m_cl[i];
41  }
42 
43  for (int i = 0; i < m_Np; ++i) {
44  bl[i] = m_bl[i];
45  }
46 }
47 
48 
49 //====================================================================
51 {
52  // Zolotarev coefficient defined
53  m_cl.resize(2 * m_Np);
54  m_bl.resize(m_Np);
55 
56  double UK = 0.0;
57  vout.general(m_vl, " bmax = %12.4e\n", m_bmax);
58  vout.general(m_vl, " UK = %12.4e\n", UK);
59 
61 
62  // for(int i=0; i<m_Np; i++){
63  // vout.general(m_vl, " %3d %12.4e %12.4e %12.4e\n", i, m_cl[i],
64  // m_cl[i+m_Np], m_bl[i]);
65  // }
66 }
67 
68 
69 //====================================================================
70 double Math_Sign_Zolotarev::sign(double x)
71 {
72  //- cl[2*Np], bl[Np]: coefficients of rational approx.
73 
74  double x2R = 0.0;
75 
76  for (int l = 0; l < m_Np; l++) {
77  x2R += m_bl[l] / (x * x + m_cl[2 * l]);
78  }
79  x2R = x2R * (x * x + m_cl[2 * m_Np - 1]);
80 
81  return x * x2R;
82 }
83 
84 
85 //====================================================================
86 void Math_Sign_Zolotarev::poly_Zolotarev(double bmax, double& UK)
87 {
88 // Return the coefficients of Zolotarev's approximation
89 // of sign function to rational function.
90 //
91 // Np: number of poles (2*Np is number of cl)
92 // bmax: range of argument [1,bmax]
93 // UK: complete elliptic integral of the 1st kind
94 // cl[2*Np],bl[Np]: coefficients of Zolotarev rational approx.
95 
96  int Nprec = 14;
97 
98  double rk = sqrt(1.0 - 1.0 / (bmax * bmax));
99  double emmc = 1.0 - rk * rk;
100 
101  vout.general(m_vl, "emmc = %22.14e\n", emmc);
102 
103  double sn, cn, dn;
104 
105  //- Determination of K
106  double Dsr = 10.0;
107  double u = 0.0;
108  for (int i_prec = 0; i_prec < Nprec + 1; i_prec++) {
109  Dsr = Dsr * 0.1;
110 
111  for (int i = 0; i < 20; i++) {
112  u = u + Dsr;
113  Jacobi_elliptic(u, emmc, sn, cn, dn);
114  vout.detailed(m_vl, " %22.14e %22.14e %22.14e\n", u, sn, cn);
115  if (cn < 0.0) goto succeeded;
116  }
117  vout.general(m_vl, "Something wrong in setting Zolotarev\n");
118  return;
119 
120 succeeded:
121  u = u - Dsr;
122  }
123 
124  UK = u;
125 
126  Jacobi_elliptic(UK, emmc, sn, cn, dn);
127  vout.general(m_vl, " %22.14e %22.14e %22.14e\n", UK, sn, cn);
128 
129 
130  //- Determination of c_l
131  double FK = UK / (2.0 * m_Np + 1.0);
132 
133  for (int l = 0; l < 2 * m_Np; l++) {
134  u = FK * (l + 1.0);
135  Jacobi_elliptic(u, emmc, sn, cn, dn);
136  m_cl[l] = sn * sn / (1.0 - sn * sn);
137  }
138 
139  //- Determination of b_l
140  double d0 = 1.0;
141  for (int l = 0; l < m_Np; l++) {
142  d0 = d0 * (1.0 + m_cl[2 * l]) / (1.0 + m_cl[2 * l + 1]);
143  }
144 
145  for (int l = 0; l < m_Np; l++) {
146  m_bl[l] = d0;
147  for (int i = 0; i < m_Np; i++) {
148  if (i < m_Np - 1) m_bl[l] = m_bl[l] * (m_cl[2 * i + 1] - m_cl[2 * l]);
149  if (i != l) m_bl[l] = m_bl[l] / (m_cl[2 * i] - m_cl[2 * l]);
150  }
151  }
152 
153  //- Correction
154  int Nj = 10000;
155  double Dx = (bmax - 1.0) / Nj;
156 
157  double d1 = 0.0;
158  double d2 = 2.0;
159 
160  for (int jx = 0; jx <= Nj; jx++) {
161  double x = 1.0 + Dx * jx;
162  double sgnx = sign(x);
163  if (fabs(sgnx) > d1) d1 = sgnx;
164  if (fabs(sgnx) < d2) d2 = sgnx;
165  }
166  vout.general(m_vl, " |sgnx|_up = %8.4e \n", d1 - 1.0);
167  vout.general(m_vl, " |sgnx|_dn = %8.4e \n", 1.0 - d2);
168 
169  /*
170  double d0c = 0.5*(d1+d2);
171  for(int ip=0; ip<m_Np; ip++){
172  m_bl[ip] = m_bl[ip]/d0c;
173  };
174 
175  d1 = 0.0;
176  d2 = 2.0;
177  for(int jx=0; jx <= Nj; jx++){
178  double x = 1.0 + Dx*jx;
179  double sgnx = sign(x);
180  if(fabs(sgnx) > d1) d1 = sgnx;
181  if(fabs(sgnx) < d2) d2 = sgnx;
182  }
183  vout.general(m_vl, " |sgnx|_up = %8.4e \n", d1-1.0);
184  vout.general(m_vl, " |sgnx|_dn = %8.4e \n", 1.0-d2);
185  */
186 
187  double dmax = d1 - 1.0;
188  if (dmax < 1.0 - d2) dmax = 1.0 - d2;
189  vout.general(m_vl, " Amp(1-|sgn|) = %16.8e \n", dmax);
190 }
191 
192 
193 //====================================================================
194 void Math_Sign_Zolotarev::Jacobi_elliptic(double uu, double emmc,
195  double& sn, double& cn, double& dn)
196 {
197 // Return the Jacobi elliptic functions sn(u,kc),
198 // cn(u,kc), and dn(u,kc), where kc = 1 - k^2, and
199 // arguments:
200 // uu: u, emmc: kc.
201 //
202 // This routine is based on GSL.
203 // Typed by S. UEDA June 19, 2013
204 
205 
206  // The accuracy
207  const double epsilon = DBL_EPSILON;
208  // Max number of iteration
209  const int N = 16;
210 
211  emmc = 1 - emmc;
212 
213  if (abs(emmc) > 1.0) {
214  sn = cn = dn = 0;
215  vout.crucial("parameter m = %f must be smaller then 1.\n", emmc);
216  std::abort();
217  } else if (abs(emmc) < 2.0 * epsilon) {
218  sn = sin(uu);
219  cn = cos(uu);
220  dn = 1.0;
221  } else if (abs(emmc - 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 - emmc);
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 (abs(sin_umu < 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 sqrtm1 = sqrt(1.0 - emmc);
264  dn = sqrtm1 / 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 / sqrtm1;
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=====
BridgeIO vout
Definition: bridgeIO.cpp:207
void detailed(const char *format,...)
Definition: bridgeIO.cpp:50
void general(const char *format,...)
Definition: bridgeIO.cpp:38
void poly_Zolotarev(double bmax, double &UK)
void Jacobi_elliptic(double uu, double emmc, double &sn, double &cn, double &dn)
std::valarray< double > m_bl
Bridge::VerboseLevel m_vl
static const std::string class_name
void crucial(const char *format,...)
Definition: bridgeIO.cpp:26
void get_sign_parameters(std::valarray< double > &cl, std::valarray< double > &bl)
std::valarray< double > m_cl