gsl_ode-initval__evolve.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /* ode-initval/evolve.c
  2. *
  3. * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
  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. /* Author: G. Jungman
  20. */
  21. #include "gsl__config.h"
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include "gsl_math.h"
  25. #include "gsl_errno.h"
  26. #include "gsl_odeiv.h"
  27. #include "gsl_ode-initval__odeiv_util.h"
  28. gsl_odeiv_evolve *
  29. gsl_odeiv_evolve_alloc (size_t dim)
  30. {
  31. gsl_odeiv_evolve *e =
  32. (gsl_odeiv_evolve *) malloc (sizeof (gsl_odeiv_evolve));
  33. if (e == 0)
  34. {
  35. GSL_ERROR_NULL ("failed to allocate space for evolve struct",
  36. GSL_ENOMEM);
  37. }
  38. e->y0 = (double *) malloc (dim * sizeof (double));
  39. if (e->y0 == 0)
  40. {
  41. free (e);
  42. GSL_ERROR_NULL ("failed to allocate space for y0", GSL_ENOMEM);
  43. }
  44. e->yerr = (double *) malloc (dim * sizeof (double));
  45. if (e->yerr == 0)
  46. {
  47. free (e->y0);
  48. free (e);
  49. GSL_ERROR_NULL ("failed to allocate space for yerr", GSL_ENOMEM);
  50. }
  51. e->dydt_in = (double *) malloc (dim * sizeof (double));
  52. if (e->dydt_in == 0)
  53. {
  54. free (e->yerr);
  55. free (e->y0);
  56. free (e);
  57. GSL_ERROR_NULL ("failed to allocate space for dydt_in", GSL_ENOMEM);
  58. }
  59. e->dydt_out = (double *) malloc (dim * sizeof (double));
  60. if (e->dydt_out == 0)
  61. {
  62. free (e->dydt_in);
  63. free (e->yerr);
  64. free (e->y0);
  65. free (e);
  66. GSL_ERROR_NULL ("failed to allocate space for dydt_out", GSL_ENOMEM);
  67. }
  68. e->dimension = dim;
  69. e->count = 0;
  70. e->failed_steps = 0;
  71. e->last_step = 0.0;
  72. return e;
  73. }
  74. int
  75. gsl_odeiv_evolve_reset (gsl_odeiv_evolve * e)
  76. {
  77. e->count = 0;
  78. e->failed_steps = 0;
  79. e->last_step = 0.0;
  80. return GSL_SUCCESS;
  81. }
  82. void
  83. gsl_odeiv_evolve_free (gsl_odeiv_evolve * e)
  84. {
  85. free (e->dydt_out);
  86. free (e->dydt_in);
  87. free (e->yerr);
  88. free (e->y0);
  89. free (e);
  90. }
  91. /* Evolution framework method.
  92. *
  93. * Uses an adaptive step control object
  94. */
  95. int
  96. gsl_odeiv_evolve_apply (gsl_odeiv_evolve * e,
  97. gsl_odeiv_control * con,
  98. gsl_odeiv_step * step,
  99. const gsl_odeiv_system * dydt,
  100. double *t, double t1, double *h, double y[])
  101. {
  102. const double t0 = *t;
  103. double h0 = *h;
  104. int step_status;
  105. int final_step = 0;
  106. double dt = t1 - t0; /* remaining time, possibly less than h */
  107. if (e->dimension != step->dimension)
  108. {
  109. GSL_ERROR ("step dimension must match evolution size", GSL_EINVAL);
  110. }
  111. if ((dt < 0.0 && h0 > 0.0) || (dt > 0.0 && h0 < 0.0))
  112. {
  113. GSL_ERROR ("step direction must match interval direction", GSL_EINVAL);
  114. }
  115. /* No need to copy if we cannot control the step size. */
  116. if (con != NULL)
  117. {
  118. DBL_MEMCPY (e->y0, y, e->dimension);
  119. }
  120. /* Calculate initial dydt once if the method can benefit. */
  121. if (step->type->can_use_dydt_in)
  122. {
  123. int status = GSL_ODEIV_FN_EVAL (dydt, t0, y, e->dydt_in);
  124. if (status)
  125. {
  126. return status;
  127. }
  128. }
  129. try_step:
  130. if ((dt >= 0.0 && h0 > dt) || (dt < 0.0 && h0 < dt))
  131. {
  132. h0 = dt;
  133. final_step = 1;
  134. }
  135. else
  136. {
  137. final_step = 0;
  138. }
  139. if (step->type->can_use_dydt_in)
  140. {
  141. step_status =
  142. gsl_odeiv_step_apply (step, t0, h0, y, e->yerr, e->dydt_in,
  143. e->dydt_out, dydt);
  144. }
  145. else
  146. {
  147. step_status =
  148. gsl_odeiv_step_apply (step, t0, h0, y, e->yerr, NULL, e->dydt_out,
  149. dydt);
  150. }
  151. /* Check for stepper internal failure */
  152. if (step_status != GSL_SUCCESS)
  153. {
  154. *h = h0; /* notify user of step-size which caused the failure */
  155. return step_status;
  156. }
  157. e->count++;
  158. e->last_step = h0;
  159. if (final_step)
  160. {
  161. *t = t1;
  162. }
  163. else
  164. {
  165. *t = t0 + h0;
  166. }
  167. if (con != NULL)
  168. {
  169. /* Check error and attempt to adjust the step. */
  170. const int hadjust_status
  171. = gsl_odeiv_control_hadjust (con, step, y, e->yerr, e->dydt_out, &h0);
  172. if (hadjust_status == GSL_ODEIV_HADJ_DEC)
  173. {
  174. /* Step was decreased. Undo and go back to try again. */
  175. DBL_MEMCPY (y, e->y0, dydt->dimension);
  176. e->failed_steps++;
  177. goto try_step;
  178. }
  179. }
  180. *h = h0; /* suggest step size for next time-step */
  181. return step_status;
  182. }