misc.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /* This file is part of the GNU plotutils package. */
  2. /*
  3. * Copyright (C) 1982-1994, Nicholas B. Tufillaro. All rights reserved.
  4. *
  5. * GNU enhancements Copyright (C) 1996, 1997, 1998, 1999, 2005, 2008, Free
  6. * Software Foundation, Inc.
  7. */
  8. /* stuff that doesn't go anywhere else in particular */
  9. #include "sys-defines.h"
  10. #include "ode.h"
  11. #include "extern.h"
  12. /*
  13. * check checks internal consistency prior to calling the
  14. * numerical routine. Tasks it performs include:
  15. * ensures one and only one independent variable
  16. * the symbol table is coherent
  17. * the print queue is coherent
  18. * the independent variable has a derivative == 1.
  19. * each dependent variable has an ODE and an initial value
  20. */
  21. bool
  22. check (void)
  23. {
  24. struct sym *sp, *ivp, *prevp;
  25. struct prt *pp;
  26. /*
  27. * discard any previous entry for "(indep)"
  28. */
  29. prevp = NULL;
  30. for (sp = symtab; sp != NULL; sp = sp->sy_link)
  31. {
  32. if (strncmp (sp->sy_name, "(indep)", NAMMAX) == 0)
  33. {
  34. if (prevp == NULL)
  35. symtab = sp->sy_link;
  36. else
  37. prevp->sy_link = sp->sy_link;
  38. sfree(sp);
  39. break;
  40. }
  41. prevp = sp;
  42. }
  43. /*
  44. * check for only one independent variable
  45. */
  46. ivp = prevp = NULL;
  47. for (sp = symtab; sp != NULL; sp = sp->sy_link)
  48. {
  49. if (!(sp->sy_flags & SF_DEPV))
  50. {
  51. if (ivp != NULL)
  52. {
  53. fprintf (stderr,
  54. "%s: both `%.*s' and `%.*s' are independent\n",
  55. progname,
  56. NAMMAX, sp->sy_name,
  57. NAMMAX, ivp->sy_name);
  58. return false;
  59. }
  60. ivp = sp;
  61. }
  62. if (ivp == NULL)
  63. prevp = sp;
  64. }
  65. /*
  66. * invent one if it's missing
  67. */
  68. if (ivp == NULL)
  69. {
  70. ivp = salloc();
  71. strncpy (ivp->sy_name, "(indep)", NAMMAX);
  72. }
  73. else if (prevp != NULL)
  74. {
  75. /*
  76. * link the independent var at the
  77. * head of the symtab queue
  78. */
  79. prevp->sy_link = ivp->sy_link;
  80. ivp->sy_link = symtab;
  81. symtab = ivp;
  82. }
  83. /*
  84. * now ivp points to the ind. var. entry
  85. * make sure the independent var gets
  86. * printed when there's no print statement
  87. */
  88. if (!sawprint)
  89. {
  90. for (pp = pqueue; pp != NULL; pp = pp->pr_link)
  91. if (pp->pr_sym == ivp)
  92. goto found;
  93. pp = palloc();
  94. pp->pr_link = pqueue;
  95. pqueue = pp;
  96. pp->pr_sym = ivp;
  97. }
  98. found:
  99. /*
  100. * indep var has a derivative of 1.0
  101. */
  102. ivp->sy_expr = &exprone;
  103. /*
  104. * ensure an expr and value for each dep var
  105. */
  106. for (sp = symtab; sp != NULL; sp = sp->sy_link)
  107. {
  108. switch (sp->sy_flags&SF_DEPV)
  109. {
  110. case SF_INIT:
  111. sp->sy_expr = &exprzero;
  112. sp->sy_flags |= SF_ISEQN;
  113. break;
  114. case SF_ISEQN:
  115. sp->sy_value = 0;
  116. sp->sy_flags |= SF_INIT;
  117. break;
  118. }
  119. }
  120. /*
  121. * dependent variables start here
  122. */
  123. dqueue = symtab->sy_link;
  124. return true;
  125. }
  126. /*
  127. * set default values
  128. * determine step direction (forgive confused users)
  129. * initialize values for printq() and numerical routines
  130. */
  131. void
  132. defalt (void)
  133. {
  134. if (!sawfrom)
  135. tfrom = tstart;
  136. if (!sawevery)
  137. tevery = 1;
  138. if (tstart>tstop && tstep>0)
  139. tstep = -tstep;
  140. else if (tstart<tstop && tstep<0)
  141. tstep = -tstep;
  142. printnum = false;
  143. }
  144. /*
  145. * evaluate all the derivatives
  146. */
  147. void
  148. field(void)
  149. {
  150. for (fsp = symtab->sy_link; fsp!=NULL; fsp = fsp->sy_link)
  151. fsp->sy_prime = eval(fsp->sy_expr);
  152. }
  153. /*
  154. * internal error (fatal)
  155. */
  156. void
  157. panic (const char *s)
  158. {
  159. fprintf (stderr, "%s panic: %s\n", progname, s);
  160. exit (EXIT_FAILURE);
  161. }
  162. void
  163. panicn (const char *fmt, int n)
  164. {
  165. fprintf (stderr, "%s panic: ", progname);
  166. fprintf (stderr, fmt, n);
  167. fprintf (stderr, "\n");
  168. exit (EXIT_FAILURE);
  169. }
  170. #define LASTVAL (tstep>0 ? t>=tstop-0.0625*tstep : t<=tstop-0.0625*tstep)
  171. #define TFROM (tfrom - 0.0625*tstep)
  172. #define PRFROM (tstep>0 ? t >= TFROM : t<= TFROM)
  173. void
  174. printq (void)
  175. {
  176. double f = 0.0;
  177. double t;
  178. struct prt *pp;
  179. t = symtab->sy_value;
  180. if (!printnum && PRFROM)
  181. printnum = true;
  182. if (((it % tevery == 0) && printnum) || LASTVAL)
  183. {
  184. pp = pqueue;
  185. if (pp != NULL)
  186. for (;;)
  187. {
  188. switch (pp->pr_which)
  189. {
  190. case P_VALUE:
  191. f = pp->pr_sym->sy_value;
  192. break;
  193. case P_PRIME:
  194. f = pp->pr_sym->sy_prime;
  195. break;
  196. case P_ACERR:
  197. f = pp->pr_sym->sy_acerr;
  198. break;
  199. case P_ABERR:
  200. f = pp->pr_sym->sy_aberr;
  201. break;
  202. case P_SSERR:
  203. f = pp->pr_sym->sy_sserr;
  204. break;
  205. default:
  206. panicn ("bad cell spec (%d) in printq()", (int)(pp->pr_which));
  207. break;
  208. }
  209. prval (f);
  210. pp = pp->pr_link;
  211. if (pp == NULL)
  212. break;
  213. putchar (' ');
  214. }
  215. putchar ('\n');
  216. fflush (stdout);
  217. }
  218. if (it == LONGMAX)
  219. it = 0;
  220. }
  221. /*
  222. * print a value to current precision
  223. * kludge for Pascal compatibility
  224. */
  225. void
  226. prval (double x)
  227. {
  228. if (prec < 0)
  229. {
  230. char outbuf[20];
  231. if (x < 0)
  232. {
  233. putchar ('-');
  234. x = -x;
  235. }
  236. sprintf (outbuf, "%.7g", x);
  237. if (*outbuf == '.')
  238. putchar ('0');
  239. printf ("%s", outbuf);
  240. }
  241. else
  242. printf ("%*.*e", fwd, prec, x);
  243. }
  244. /*
  245. * handler for math library exceptions (`rterrors' may or may not return)
  246. */
  247. #ifdef HAVE_MATHERR
  248. int
  249. # ifdef __cplusplus
  250. matherr (struct __exception *x)
  251. #else
  252. matherr (struct exception *x)
  253. #endif
  254. {
  255. switch (x->type)
  256. {
  257. case DOMAIN:
  258. rterrors ("domain error in %s", x->name);
  259. break;
  260. case SING:
  261. rterrors ("singularity error in %s", x->name);
  262. break;
  263. case OVERFLOW:
  264. rterrors ("range error (overflow) in %s", x->name);
  265. break;
  266. #ifdef TLOSS
  267. case TLOSS:
  268. rterrors ("range error (total loss of significance) in %s",
  269. x->name);
  270. break;
  271. #endif
  272. #ifdef PLOSS
  273. case PLOSS:
  274. rterrors ("range error (partial loss of significance) in %s",
  275. x->name);
  276. break;
  277. #endif
  278. case UNDERFLOW: /* treat as non-fatal */
  279. rtsquawks ("range error (underflow) in %s", x->name);
  280. break;
  281. default:
  282. rterrors ("unknown error in %s", x->name);
  283. break;
  284. }
  285. return 1; /* suppress system error message */
  286. }
  287. #endif
  288. /*
  289. * print a diagnostic for run-time errors.
  290. * uses fsp to decide which dependent variable was being worked
  291. */
  292. void
  293. rterror (const char *s)
  294. {
  295. if (fsp == NULL) /* no computation, just print message */
  296. fprintf (stderr, "%s: %s\n", progname, s);
  297. else
  298. {
  299. fprintf (stderr, "%s: %s while calculating %.*s'\n", progname, s,
  300. NAMMAX, fsp->sy_name);
  301. longjmp (mark, 1); /* interrupt computation */
  302. }
  303. }
  304. void
  305. rterrors (const char *fmt, const char *s)
  306. {
  307. if (fsp != NULL) /* interrupt computation */
  308. {
  309. fprintf (stderr, "%s: ", progname);
  310. fprintf (stderr, fmt, s);
  311. fprintf (stderr, " while calculating %.*s'\n", NAMMAX, fsp->sy_name);
  312. longjmp (mark, 1);
  313. }
  314. else /* just print error message */
  315. {
  316. fprintf (stderr, "%s: ", progname);
  317. fprintf (stderr, fmt, s);
  318. fprintf (stderr, "\n");
  319. }
  320. }
  321. /*
  322. * same, but doesn't do a longjmp.
  323. * computation continues
  324. */
  325. void
  326. rtsquawks (const char *fmt, const char *s)
  327. {
  328. fprintf (stderr, "%s: ", progname);
  329. fprintf (stderr, fmt, s);
  330. if (fsp != NULL)
  331. fprintf (stderr, " while calculating %.*s'", NAMMAX, fsp->sy_name);
  332. fprintf (stderr, "\n");
  333. return;
  334. }
  335. /*
  336. * Run the numerical stuff.
  337. * This gets called from the grammar
  338. * because we want to solve on each
  339. * 'step' statement.
  340. */
  341. void
  342. solve (void)
  343. {
  344. struct sym *sp;
  345. bool adapt;
  346. if (check() == false)
  347. return;
  348. defalt ();
  349. if (tflag)
  350. title ();
  351. fflush (stderr);
  352. setflt ();
  353. if (!setjmp (mark))
  354. {
  355. adapt = eflag|rflag|!conflag ? true : false;
  356. if (tstart == tstop)
  357. trivial();
  358. else switch (algorithm)
  359. {
  360. case A_EULER:
  361. eu();
  362. break;
  363. case A_ADAMS_MOULTON:
  364. if (adapt || prerr)
  365. ama();
  366. else
  367. am();
  368. break;
  369. case A_RUNGE_KUTTA_FEHLBERG:
  370. default:
  371. if (adapt || prerr)
  372. rka();
  373. else
  374. rk();
  375. break;
  376. }
  377. }
  378. resetflt();
  379. /* add final newline (to aid realtime postprocessing of dataset by graph) */
  380. putchar ('\n');
  381. fflush (stdout);
  382. for (sp = symtab; sp != NULL; sp = sp->sy_link)
  383. {
  384. sp->sy_prime = sp->sy_pri[0];
  385. sp->sy_value = sp->sy_val[0];
  386. }
  387. }
  388. /*
  389. * choose step size at tstart
  390. */
  391. void
  392. startstep (void)
  393. {
  394. if (!hflag)
  395. hmax = fabs ((tstop-tstart)/2);
  396. tstep = fabs ((tstop-tstart)/MESH);
  397. if (tstep > hmax)
  398. tstep = hmax;
  399. if (tstep < hmin)
  400. tstep = hmin;
  401. while (tstep >= HMAX)
  402. tstep *= HALF;
  403. while (tstart + tstep == tstart)
  404. tstep *= TWO;
  405. }
  406. /*
  407. * print a header
  408. * Try to center the headings over the columns
  409. */
  410. void
  411. title (void)
  412. {
  413. struct prt *pp;
  414. char tag = '\0';
  415. pp = pqueue;
  416. if (pp != NULL)
  417. for (;;)
  418. {
  419. switch (pp->pr_which)
  420. {
  421. case P_PRIME:
  422. tag = '\'';
  423. break;
  424. case P_VALUE:
  425. tag = ' ';
  426. break;
  427. case P_SSERR:
  428. tag = '?';
  429. break;
  430. case P_ABERR:
  431. tag = '!';
  432. break;
  433. case P_ACERR:
  434. tag = '~';
  435. break;
  436. default:
  437. panicn ("bad cell spec (%d) in title()", (int)(pp->pr_which));
  438. break;
  439. }
  440. printf (" %*.*s%c", fwd - 2, NAMMAX, pp->pr_sym->sy_name, tag);
  441. if ((pp=pp->pr_link) == NULL)
  442. break;
  443. putchar (' ');
  444. }
  445. putchar ('\n');
  446. fflush (stdout);
  447. }