gsl_ode-initval__cscal.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* ode-initval/cscal.c
  2. *
  3. * Copyright (C) 2002, 2007 Brian Gough
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. #include "gsl__config.h"
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <math.h>
  23. #include "gsl_errno.h"
  24. #include "gsl_math.h"
  25. #include "gsl_odeiv.h"
  26. typedef struct
  27. {
  28. double eps_abs;
  29. double eps_rel;
  30. double a_y;
  31. double a_dydt;
  32. double * scale_abs;
  33. }
  34. sc_control_state_t;
  35. static void *
  36. sc_control_alloc (void)
  37. {
  38. sc_control_state_t * s =
  39. (sc_control_state_t *) malloc (sizeof(sc_control_state_t));
  40. if (s == 0)
  41. {
  42. GSL_ERROR_NULL ("failed to allocate space for sc_control_state",
  43. GSL_ENOMEM);
  44. }
  45. return s;
  46. }
  47. static int
  48. sc_control_init (void * vstate,
  49. double eps_abs, double eps_rel, double a_y, double a_dydt)
  50. {
  51. sc_control_state_t * s = (sc_control_state_t *) vstate;
  52. if (eps_abs < 0)
  53. {
  54. GSL_ERROR ("eps_abs is negative", GSL_EINVAL);
  55. }
  56. else if (eps_rel < 0)
  57. {
  58. GSL_ERROR ("eps_rel is negative", GSL_EINVAL);
  59. }
  60. else if (a_y < 0)
  61. {
  62. GSL_ERROR ("a_y is negative", GSL_EINVAL);
  63. }
  64. else if (a_dydt < 0)
  65. {
  66. GSL_ERROR ("a_dydt is negative", GSL_EINVAL);
  67. }
  68. s->eps_rel = eps_rel;
  69. s->eps_abs = eps_abs;
  70. s->a_y = a_y;
  71. s->a_dydt = a_dydt;
  72. return GSL_SUCCESS;
  73. }
  74. static int
  75. sc_control_hadjust(void * vstate, size_t dim, unsigned int ord, const double y[], const double yerr[], const double yp[], double * h)
  76. {
  77. sc_control_state_t *state = (sc_control_state_t *) vstate;
  78. const double eps_abs = state->eps_abs;
  79. const double eps_rel = state->eps_rel;
  80. const double a_y = state->a_y;
  81. const double a_dydt = state->a_dydt;
  82. const double * scale_abs = state->scale_abs;
  83. const double S = 0.9;
  84. const double h_old = *h;
  85. double rmax = DBL_MIN;
  86. size_t i;
  87. for(i=0; i<dim; i++) {
  88. const double D0 =
  89. eps_rel * (a_y * fabs(y[i]) + a_dydt * fabs(h_old * yp[i]))
  90. + eps_abs * scale_abs[i];
  91. const double r = fabs(yerr[i]) / fabs(D0);
  92. rmax = GSL_MAX_DBL(r, rmax);
  93. }
  94. if(rmax > 1.1) {
  95. /* decrease step, no more than factor of 5, but a fraction S more
  96. than scaling suggests (for better accuracy) */
  97. double r = S / pow(rmax, 1.0/ord);
  98. if (r < 0.2)
  99. r = 0.2;
  100. *h = r * h_old;
  101. return GSL_ODEIV_HADJ_DEC;
  102. }
  103. else if(rmax < 0.5) {
  104. /* increase step, no more than factor of 5 */
  105. double r = S / pow(rmax, 1.0/(ord+1.0));
  106. if (r > 5.0)
  107. r = 5.0;
  108. if (r < 1.0) /* don't allow any decrease caused by S<1 */
  109. r = 1.0;
  110. *h = r * h_old;
  111. return GSL_ODEIV_HADJ_INC;
  112. }
  113. else {
  114. /* no change */
  115. return GSL_ODEIV_HADJ_NIL;
  116. }
  117. }
  118. static void
  119. sc_control_free (void * vstate)
  120. {
  121. sc_control_state_t *state = (sc_control_state_t *) vstate;
  122. free (state->scale_abs);
  123. free (state);
  124. }
  125. static const gsl_odeiv_control_type sc_control_type =
  126. {"scaled", /* name */
  127. &sc_control_alloc,
  128. &sc_control_init,
  129. &sc_control_hadjust,
  130. &sc_control_free};
  131. const gsl_odeiv_control_type *gsl_odeiv_control_scaled = &sc_control_type;
  132. gsl_odeiv_control *
  133. gsl_odeiv_control_scaled_new(double eps_abs, double eps_rel,
  134. double a_y, double a_dydt,
  135. const double scale_abs[],
  136. size_t dim)
  137. {
  138. gsl_odeiv_control * c =
  139. gsl_odeiv_control_alloc (gsl_odeiv_control_scaled);
  140. int status = gsl_odeiv_control_init (c, eps_abs, eps_rel, a_y, a_dydt);
  141. if (status != GSL_SUCCESS)
  142. {
  143. gsl_odeiv_control_free (c);
  144. GSL_ERROR_NULL ("error trying to initialize control", status);
  145. }
  146. {
  147. sc_control_state_t * s = (sc_control_state_t *) c->state;
  148. s->scale_abs = (double *)malloc(dim * sizeof(double));
  149. if (s->scale_abs == 0)
  150. {
  151. free (s);
  152. GSL_ERROR_NULL ("failed to allocate space for scale_abs",
  153. GSL_ENOMEM);
  154. }
  155. memcpy(s->scale_abs, scale_abs, dim * sizeof(double));
  156. }
  157. return c;
  158. }