1 /*
2    ElmerGrid - A simple mesh generation and manipulation utility
3    Copyright (C) 1995- , CSC - IT Center for Science Ltd.
4 
5    Author: Peter Raback
6    Email: elmeradm@csc.fi
7    Address: CSC - IT Center for Science Ltd.
8             Keilaranta 14
9             02101 Espoo, Finland
10 
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License
13    as published by the Free Software Foundation; either version 2
14    of the License, or (at your option) any later version.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24 */
25 
26 #include <stdio.h>
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <math.h>
31 #include <sys/types.h>
32 #include <time.h>
33 
34 /* Possible monitoring of memory usage, if supported */
35 #define MEM_USAGE 0
36 #if MEM_USAGE
37 #include <sys/resource.h>
38 #endif
39 
40 #include "egutils.h"
41 
42 #define FREE_ARG char*
43 #define SHOWMEM 0
44 
45 #if SHOWMEM
46 static int nfloat=0, nint=0, cumnfloat=0, cumnint=0, locnint, locnfloat;
47 
MemoryUsage()48 int MemoryUsage()
49 {
50   if(locnint > 1000 || locnfloat > 1000)
51     printf("Memory used real %d %d %d int %d %d %d\n",
52 	   nfloat,cumnfloat,locnfloat,nint,cumnint,locnint);
53   locnfloat = locnint = 0;
54 }
55 #endif
56 
57 
58 /* The following routines are copied from the book
59    "Numerical Recipes in C, The art of scientific computing"
60    by Cambridge University Press and include the following
61 
62    Non-Copyright Notice: This appendix and its utility routines are
63    herewith placed into the public domain. Anyone may copy them freely
64    for any purpose. We of course accept no liability whatsoever for
65    any such use. */
66 
67 
68 
nrerror(const char error_text[])69 void nrerror(const char error_text[])
70 /* standerd error handler */
71 {
72   fprintf(stderr,"run-time error...\n");
73   fprintf(stderr,"%s\n",error_text);
74   fprintf(stderr,"...now exiting to system...\n");
75   exit(1);
76 }
77 
78 
79 /* Vector initialization */
80 
vector(int nl,int nh)81 float *vector(int nl,int nh)
82 /* allocate a float vector with subscript range v[nl..nh] */
83 {
84   float *v;
85 
86   v = (float*)malloc((size_t) (nh-nl+1+1)*sizeof(float));
87   if (!v) nrerror("allocation failure in vector()");
88   return(v-nl+1);
89 }
90 
91 
92 
ivector(int nl,int nh)93 int *ivector(int nl,int nh)
94 /* Allocate an int vector with subscript range v[nl..nh] */
95 {
96   int *v;
97 
98   if( nh < nl ) {
99     printf("Allocation impossible in ivector: %d %d\n",nl,nh);
100     exit(1);
101   }
102 
103   v=(int*) malloc((size_t) (nh-nl+1+1)*sizeof(int));
104   if (!v) nrerror("allocation failure in ivector()");
105 
106  #if SHOWMEM
107   locnint = (nh-nl+1+1);
108   nint += locnint;
109   cumnint += locnint;
110   MemoryUsage();
111 #endif
112 
113   return(v-nl+1);
114 }
115 
116 
cvector(int nl,int nh)117 unsigned char *cvector(int nl,int nh)
118 /* allocate an unsigned char vector with subscript range v[nl..nh] */
119 {
120   unsigned char *v;
121 
122   v=(unsigned char *)malloc((size_t) (nh-nl+1+1)*sizeof(unsigned char));
123   if (!v) nrerror("allocation failure in cvector()");
124   return(v-nl+1);
125 }
126 
127 
lvector(int nl,int nh)128 unsigned long *lvector(int nl,int nh)
129 /* allocate an unsigned long vector with subscript range v[nl..nh] */
130 {
131   unsigned long *v;
132 
133   v=(unsigned long *)malloc((size_t) (nh-nl+1+1)*sizeof(unsigned long));
134   if (!v) nrerror("allocation failure in lvector()");
135   return(v-nl+1);
136 }
137 
138 
139 
dvector(int nl,int nh)140 double *dvector(int nl,int nh)
141 /* allocate a double vector with subscript range v[nl..nh] */
142 {
143   double *v;
144 
145   if( nh < nl ) {
146     printf("Allocation impossible in dvector: %d %d\n",nl,nh);
147     exit(1);
148   }
149 
150   v=(double *)malloc((size_t) (nh-nl+1+1)*sizeof(double));
151   if (!v) nrerror("allocation failure in dvector()");
152 
153 #if SHOWMEM
154   locnfloat = nh-nl+1+1;
155   nfloat += locnfloat;
156   cumnfloat += locnfloat;
157   MemoryUsage();
158 #endif
159 
160   return(v-nl+1);
161 }
162 
163 
164 /* Matrix initialization */
165 
matrix(int nrl,int nrh,int ncl,int nch)166 float **matrix(int nrl,int nrh,int ncl,int nch)
167 /* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
168 {
169   int i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
170   float **m;
171 
172   /* allocate pointers to rows */
173   m=(float **) malloc((size_t) (nrow+1)*sizeof(float*));
174   if (!m) nrerror("allocation failure 1 in matrix()");
175   m += 1;
176   m -= nrl;
177 
178   /* allocate rows and set pointers to them */
179   m[nrl]=(float *) malloc((size_t)((nrow*ncol+1)*sizeof(float)));
180   if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
181   m[nrl] += 1;
182   m[nrl] -= ncl;
183 
184   for(i=nrl+1;i<=nrh;i++)
185     m[i]=m[i-1]+ncol;
186 
187   return(m);
188 }
189 
190 
dmatrix(int nrl,int nrh,int ncl,int nch)191 double **dmatrix(int nrl,int nrh,int ncl,int nch)
192 /* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */
193 {
194   int i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
195   double **m;
196 
197   if( nrh < nrl || nch < ncl ) {
198     printf("Allocation impossible in dmatrix: %d %d %d %d\n",nrl,nrh,ncl,nch);
199     exit(1);
200   }
201 
202 
203 
204   /* allocate pointers to rows */
205   m=(double **) malloc((size_t) (nrow+1)*sizeof(double*));
206   if (!m) nrerror("allocation failure 1 in dmatrix()");
207   m += 1;
208   m -= nrl;
209 
210 
211   /* allocate rows and set pointers to them */
212   m[nrl]=(double *) malloc((size_t)((nrow*ncol+1)*sizeof(double)));
213   if (!m[nrl]) nrerror("allocation failure 2 in dmatrix()");
214   m[nrl] += 1;
215   m[nrl] -= ncl;
216 
217   for(i=nrl+1;i<=nrh;i++)
218     m[i]=m[i-1]+ncol;
219 
220 #if SHOWMEM
221   locnfloat = (nrow+1 + (nrow*ncol+1));
222   nfloat += locnfloat;
223   cumnfloat += locnfloat;
224   MemoryUsage();
225 #endif
226 
227   return(m);
228 }
229 
230 
imatrix(int nrl,int nrh,int ncl,int nch)231 int **imatrix(int nrl,int nrh,int ncl,int nch)
232 /* allocate an int matrix with subscript range m[nrl..nrh][ncl..nch] */
233 {
234   int i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
235   int **m;
236 
237   if( nrh < nrl || nch < ncl ) {
238     printf("Allocation impossible in imatrix: %d %d %d %d\n",nrl,nrh,ncl,nch);
239     exit(1);
240   }
241 
242   /* allocate pointers to rows */
243   m=(int **) malloc((size_t) (nrow+1)*sizeof(int*));
244   if (!m) nrerror("allocation failure 1 in imatrix()");
245   m += 1;
246   m -= nrl;
247 
248   /* allocate rows and set pointers to them */
249   m[nrl]=(int *) malloc((size_t)((nrow*ncol+1)*sizeof(int)));
250   if (!m[nrl]) nrerror("allocation failure 2 in imatrix()");
251   m[nrl] += 1;
252   m[nrl] -= ncl;
253 
254   for(i=nrl+1;i<=nrh;i++)
255     m[i]=m[i-1]+ncol;
256 
257 #if SHOWMEM
258   locnint = (nrow+1 + (nrow*ncol+1));
259   nint += locnint;
260   cumnint += locnint;
261   MemoryUsage();
262 #endif
263 
264   return(m);
265 }
266 
267 
268 
submatrix(float ** a,int oldrl,int oldrh,int oldcl,int oldch,int newrl,int newcl)269 float **submatrix(float **a,int oldrl,int oldrh,int oldcl,int oldch,int newrl,int newcl)
270 /* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */
271 {
272   int i,j, nrow=oldrh-oldrl+1, ncol=oldcl-newcl;
273   float **m;
274 
275   /* allocate array of pointers to rows */
276   m=(float **) malloc((size_t) ((nrow+1)*sizeof(float*)));
277   if (!m) nrerror("allocation failure in submatrix()");
278   m += 1;
279   m -= newrl;
280 
281   /* set pointers to rows */
282   for(i=oldrl,j=newrl;i<=oldrh;i++,j++)
283     m[j]=a[i]+ncol;
284 
285   return(m);
286 }
287 
288 /* Tensor initialization */
289 
f3tensor(int nrl,int nrh,int ncl,int nch,int ndl,int ndh)290 double ***f3tensor(int nrl,int nrh,int ncl,int nch,int ndl,int ndh)
291 /* allocate a double 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */
292 {
293   int i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1;
294   double ***t;
295 
296   t=(double***) malloc((size_t)((nrow+1)*sizeof(double***)));
297   if (!t) nrerror("allocation failure 1 in f3tensor()");
298   t += 1;
299   t -= nrl;
300 
301   t[nrl]=(double**) malloc((size_t)((nrow*ncol+1)*sizeof(double*)));
302   if(!t[nrl]) nrerror("allocation failure 2 in f3tensor()");
303   t[nrl] += 1;
304   t[nrl] -= ncl;
305 
306   t[nrl][ncl]=(double*) malloc((size_t)((nrow*ncol*ndep+1)*sizeof(double)));
307   if(!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()");
308   t[nrl][ncl] += 1;
309   t[nrl][ncl] -= ndl;
310 
311   for(j=ncl+1;j<=nch;j++) t[nrl][j] = t[nrl][j-1]+ndep;
312   for(i=nrl+1;i<=nrh;i++) {
313     t[i] = t[i-1]+ncol;
314     t[i][ncl] = t[i-1][ncl]+ncol*ndep;
315     for(j=ncl+1;j<=nch;j++) t[i][j] = t[i][j-1]+ndep;
316   }
317   return(t);
318 }
319 
320 
321 /* Deallocation routines */
322 
free_vector(float * v,int nl,int nh)323 void free_vector(float *v,int nl,int nh)
324 {
325   free((FREE_ARG) (v+nl-1));
326 }
327 
free_ivector(int * v,int nl,int nh)328 void free_ivector(int *v,int nl,int nh)
329 {
330 #if SHOWMEM
331   cumnint -= (nh-nl+1+1);
332 #endif
333 
334   free((FREE_ARG) (v+nl-1));
335 }
336 
free_cvector(unsigned char * v,int nl,int nh)337 void free_cvector(unsigned char *v,int nl,int nh)
338 {
339   free((FREE_ARG) (v+nl-1));
340 }
341 
free_lvector(unsigned long * v,int nl,int nh)342 void free_lvector(unsigned long *v,int nl,int nh)
343 {
344   free((FREE_ARG) (v+nl-1));
345 }
346 
347 
free_dvector(double * v,int nl,int nh)348 void free_dvector(double *v,int nl,int nh)
349 {
350 #if SHOWMEM
351   cumnfloat -= (nh-nl+1+1);
352 #endif
353 
354   free((FREE_ARG) (v+nl-1));
355 }
356 
free_matrix(float ** m,int nrl,int nrh,int ncl,int nch)357 void free_matrix(float **m,int nrl,int nrh,int ncl,int nch)
358 {
359   free((FREE_ARG) (m[nrl]+ncl-1));
360   free((FREE_ARG) (m+nrl-1));
361 }
362 
free_dmatrix(double ** m,int nrl,int nrh,int ncl,int nch)363 void free_dmatrix(double **m,int nrl,int nrh,int ncl,int nch)
364 {
365 #if SHOWMEM
366   int nrow=nrh-nrl+1;
367   int ncol=nch-ncl+1;
368   cumnfloat -= (nrow+1 + (nrow*ncol+1));
369 #endif
370 
371   free((FREE_ARG) (m[nrl]+ncl-1));
372   free((FREE_ARG) (m+nrl-1));
373 }
374 
free_imatrix(int ** m,int nrl,int nrh,int ncl,int nch)375 void free_imatrix(int **m,int nrl,int nrh,int ncl,int nch)
376 {
377 #if SHOWMEM
378   int nrow=nrh-nrl+1;
379   int ncol=nch-ncl+1;
380   cumnint -= (nrow+1 + (nrow*ncol+1));
381 #endif
382 
383   free((FREE_ARG) (m[nrl]+ncl-1));
384   free((FREE_ARG) (m+nrl-1));
385 }
386 
free_submatrix(float ** b,int nrl,int nrh,int ncl,int nch)387 void free_submatrix(float **b,int nrl,int nrh,int ncl,int nch)
388 {
389   free((FREE_ARG) (b+nrl-1));
390 }
391 
free_f3tensor(double *** t,int nrl,int nrh,int ncl,int nch,int ndl,int ndh)392 void free_f3tensor(double ***t,int nrl,int nrh,int ncl,int nch,int ndl,int ndh)
393 {
394   free((FREE_ARG) (t[nrl][ncl]+ndl-1));
395   free((FREE_ARG) (t[nrl]+ncl-1));
396   free((FREE_ARG) (t+nrl-1));
397 }
398 
399 
400 /* -------------------------------:  common.c  :----------------------------
401    Includes common operations for operating vectors and such. */
402 
403 
404 static Real timer_t0, timer_dt;
405 static int timer_active = FALSE;
406 static char timer_filename[600];
407 
timer_init()408 void timer_init()
409 {
410   timer_active = FALSE;
411 }
412 
413 
timer_activate(const char * prefix)414 void timer_activate(const char *prefix)
415 {
416   Real time;
417   timer_active = TRUE;
418 
419   time = clock() / (double)CLOCKS_PER_SEC;
420 
421   AddExtension(prefix,timer_filename,"time");
422 
423   printf("Activating timer (s): %.2f\n",time);
424   printf("Saving timer info to file %s\n",timer_filename);
425 
426   timer_dt = time;
427   timer_t0 = time;
428 }
429 
430 
timer_show()431 void timer_show()
432 {
433   static int visited = 0;
434   Real time;
435   FILE *out;
436 #if MEM_USAGE
437   int who,ret;
438   Real memusage;
439   static struct rusage usage;
440 #endif
441 
442   if(!timer_active) return;
443 
444   time = clock() / (double)CLOCKS_PER_SEC;
445   printf("Elapsed time (s): %.2f %.2f\n",time-timer_t0,time-timer_dt);
446 
447 #if MEM_USAGE
448   who = RUSAGE_SELF;
449   ret = getrusage( who, &usage );
450   if( !ret ) {
451     printf("maxrss %ld\n",usage.ru_maxrss);
452     printf("ixrss %ld\n",usage.ru_ixrss);
453     printf("idrss %ld\n",usage.ru_idrss);
454     printf("isrss %ld\n",usage.ru_isrss);
455 
456     memusage = (double) 1.0 * usage.ru_maxrss;
457   }
458   else {
459     printf("Failed to obtain resource usage!\n");
460     memusage = 0.0;
461   }
462 #endif
463 
464   visited = visited + 1;
465   if( visited == 1 ) {
466     out = fopen(timer_filename,"w");
467   }
468   else {
469     out = fopen(timer_filename,"a");
470   }
471 
472 #if MEM_USAGE
473   fprintf(out,"%3d %12.4le %12.4le %12.4le\n",visited,time-timer_t0,time-timer_dt,memusage);
474 #else
475   fprintf(out,"%3d %12.4le %12.4le\n",visited,time-timer_t0,time-timer_dt);
476 #endif
477 
478   fclose(out);
479 
480   timer_dt = time;
481 }
482 
483 
484 
485 
bigerror(const char error_text[])486 void bigerror(const char error_text[])
487 {
488   fprintf(stderr,"The program encountered a major error...\n");
489   fprintf(stderr,"%s\n",error_text);
490   fprintf(stderr,"...now exiting to system...\n");
491   exit(1);
492 }
493 
494 
smallerror(const char error_text[])495 void smallerror(const char error_text[])
496 {
497   fprintf(stderr,"The program encountered a minor error...\n");
498   fprintf(stderr,"%s\n",error_text);
499   fprintf(stderr,"...we'll try to continue...\n");
500 }
501 
502 
503 
FileExists(char * filename)504 int FileExists(char *filename)
505 {
506   FILE *in;
507 
508   if((in = fopen(filename,"r")) == NULL)
509     return(FALSE);
510   else {
511     fclose(in);
512     return(TRUE);
513   }
514 }
515 
516 
Minimum(Real * vector,int first,int last)517 Real Minimum(Real *vector,int first,int last)
518 /* Returns the smallest value of vector in range [first,last]. */
519 {
520   Real min;
521   int i;
522 
523   min=vector[first];
524   for(i=first+1;i<=last;i++)
525     if(min>vector[i]) min=vector[i];
526 
527   return(min);
528 }
529 
530 
Minimi(Real * vector,int first,int last)531 int Minimi(Real *vector,int first,int last)
532 /* Returns the position of the smallest value of vector in range [first,last]. */
533 {
534   Real min;
535   int i,mini;
536 
537   mini=first;
538   min=vector[first];
539   for(i=first+1;i<=last;i++)
540     if(min>vector[i])
541       min=vector[(mini=i)];
542 
543   return(mini);
544 }
545 
546 
Maximum(Real * vector,int first,int last)547 Real Maximum(Real *vector,int first,int last)
548 /* Returns the largest value of vector in range [first,last]. */
549 {
550   Real max;
551   int i;
552 
553   max=vector[first];
554   for(i=first+1;i<=last;i++)
555     if(max<vector[i]) max=vector[i];
556 
557   return(max);
558 }
559 
560 
Maximi(Real * vector,int first,int last)561 int Maximi(Real *vector,int first,int last)
562 /* Returns the position of the largest value of vector in range [first,last]. */
563 {
564   Real max;
565   int i,maxi;
566 
567   maxi=-1;
568   max=vector[first];
569   for(i=first+1;i<=last;i++)
570     if(max<vector[i])
571       max=vector[(maxi=i)];
572 
573   return(maxi);
574 }
575 
576 
577 
AddExtension(const char * fname1,char * fname2,const char * newext)578 void AddExtension(const char *fname1,char *fname2,const char *newext)
579 /* Changes the extension of a filename.
580    'fname1' - the original filename
581    'fname2' - the new filename
582    'newext' - the new extension
583    If there is originally no extension it's appended. In this case
584    there has to be room for the extension.
585    */
586 {
587   char *ptr1,*ptr2;
588 
589   strcpy(fname2,fname1);
590   ptr1 = strrchr(fname2, '.');
591 
592   if (ptr1) {
593     int badpoint=FALSE;
594     ptr2 = strrchr(fname2, '/');
595     if(ptr2 && ptr2 > ptr1) badpoint = TRUE;
596     if(!badpoint) *ptr1 = '\0';
597   }
598   strcat(fname2, ".");
599   strcat(fname2,newext);
600 }
601 
602 
StringToStrings(const char * buf,char args[10][15],int maxcnt,char separator)603 int StringToStrings(const char *buf,char args[10][15],int maxcnt,char separator)
604 /*  Finds real numbers separated by a certain separator from a string.
605     'buf'       - input string ending to a EOF
606     'dest'      - a vector of real numbers
607     'maxcnt'    - maximum number of real numbers to be read
608     'separator'	- the separator of real numbers
609     The number of numbers found is returned in the function value.
610     */
611 {
612   int i,cnt,totlen,finish;
613   char *ptr1 = (char *)buf, *ptr2;
614 
615 
616   totlen = strlen(buf);
617   finish = 0;
618   cnt = 0;
619 
620   if (!buf[0]) return 0;
621 
622   do {
623     ptr2 = strchr(ptr1,separator);
624     if(ptr2) {
625       for(i=0;i<15;i++) {
626 	args[cnt][i] = ptr1[i];
627 	if(ptr1 + i >= ptr2) break;
628       }
629       args[cnt][i] = '\0';
630       ptr1 = ptr2+1;
631     }
632     else {
633       for(i=0;i<15;i++) {
634 	if(ptr1 + i >= buf+totlen) break;
635 	args[cnt][i] = ptr1[i];
636       }
637       args[cnt][i] = '\0';
638       finish = 1;
639     }
640 
641     cnt++;
642   } while (cnt < maxcnt && !finish);
643 
644   return cnt;
645 }
646 
647 
StringToReal(const char * buf,Real * dest,int maxcnt,char separator)648 int StringToReal(const char *buf,Real *dest,int maxcnt,char separator)
649 /*  Finds real numbers separated by a certain separator from a string.
650     'buf'       - input string ending to a EOF
651     'dest'      - a vector of real numbers
652     'maxcnt'    - maximum number of real numbers to be read
653     'separator'	- the separator of real numbers
654     The number of numbers found is returned in the function value.
655     */
656 {
657   int cnt = 0;
658   char *ptr1 = (char *)buf, *ptr2;
659 
660   if (!buf[0]) return 0;
661   do {
662     ptr2 = strchr(ptr1,separator);
663     if (ptr2) ptr2[0] = '\0';
664     dest[cnt++] = atof(ptr1);
665     if (ptr2) ptr1 = ptr2+1;
666   } while (cnt < maxcnt && ptr2 != NULL);
667 
668   return cnt;
669 }
670 
671 
StringToInteger(const char * buf,int * dest,int maxcnt,char separator)672 int StringToInteger(const char *buf,int *dest,int maxcnt,char separator)
673 {
674   int cnt = 0;
675   char *ptr1 = (char *)buf, *ptr2;
676   int ival;
677 
678   if (!buf[0]) return 0;
679   do {
680 
681     ptr2 = strchr(ptr1,separator);
682     if (ptr2) ptr2[0] = '\0';
683     ival = atoi(ptr1);
684 
685     dest[cnt++] = ival;
686 
687     if (ptr2) ptr1 = ptr2+1;
688   } while (cnt < maxcnt && ptr2 != NULL);
689 
690   return cnt;
691 }
692 
StringToIntegerNoZero(const char * buf,int * dest,int maxcnt,char separator)693 int StringToIntegerNoZero(const char *buf,int *dest,int maxcnt,char separator)
694 {
695   int cnt = 0;
696   char *ptr1 = (char *)buf, *ptr2;
697   int ival;
698 
699   if (!buf[0]) return 0;
700   do {
701 
702     ptr2 = strchr(ptr1,separator);
703     if (ptr2) ptr2[0] = '\0';
704     ival = atoi(ptr1);
705 
706     if(ival == 0) break;
707 
708     dest[cnt++] = ival;
709 
710     if (ptr2) ptr1 = ptr2+1;
711   } while (cnt < maxcnt && ptr2 != NULL);
712 
713   return cnt;
714 }
715 
716 
next_int(char ** start)717 int next_int(char **start)
718 {
719   int i;
720   char *end;
721 
722   i = strtol(*start,&end,10);
723   *start = end;
724   return(i);
725 }
726 
next_int_n(char ** start,int n)727 int next_int_n(char **start, int n)
728 {
729   int i;
730   char *end = *start+n;
731   char saved = *end;
732 
733   *end = '\0';
734   i = strtol(*start,NULL,10);
735   *end = saved;
736   *start = end;
737   return(i);
738 }
739 
next_real(char ** start)740 Real next_real(char **start)
741 {
742   Real r;
743   char *end;
744 
745   r = strtod(*start,&end);
746 
747   *start = end;
748   return(r);
749 }
750 
751 
752 /*
753  * sort: sort an (double) array to ascending order, and move the elements of
754  *       another (integer) array accordingly. the latter can be used as track
755  *       keeper of where an element in the sorted order at position (k) was in
756  *       in the original order (Ord[k]), if it is initialized to contain
757  *       numbers (0..N-1) before calling sort.
758  *
759  * Parameters:
760  *
761  * N:      int                  / number of entries in the arrays.
762  * Key:    double[N]             / array to be sorted.
763  * Ord:    int[N]               / change this accordingly.
764  */
SortIndex(int N,double * Key,int * Ord)765 void SortIndex( int N, double *Key, int *Ord )
766 {
767   double CurrentKey;
768 
769   int CurrentOrd;
770 
771   int CurLastPos;
772   int CurHalfPos;
773 
774   int i;
775   int j;
776 
777   /* Initialize order */
778   for(i=1;i<=N;i++)
779     Ord[i] = i;
780 
781   CurHalfPos = N / 2 + 1;
782   CurLastPos = N;
783   while( 1 ) {
784     if ( CurHalfPos > 1 ) {
785       CurHalfPos--;
786       CurrentKey = Key[CurHalfPos];
787       CurrentOrd = Ord[CurHalfPos];
788     } else {
789       CurrentKey = Key[CurLastPos];
790       CurrentOrd = Ord[CurLastPos];
791       Key[CurLastPos] = Key[1];
792       Ord[CurLastPos] = Ord[1];
793       CurLastPos--;
794       if ( CurLastPos == 1 ) {
795 	Key[1] = CurrentKey;
796 	Ord[1] = CurrentOrd;
797 	return;
798       }
799     }
800     i = CurHalfPos;
801     j = 2 * CurHalfPos;
802     while( j <= CurLastPos ) {
803       if ( j < CurLastPos && Key[j] < Key[j + 1] ) {
804 	j++;
805       }
806       if ( CurrentKey < Key[j] ) {
807 	Key[i] = Key[j];
808 	Ord[i] = Ord[j];
809 	i  = j;
810 	j += i;
811       } else {
812 	j = CurLastPos + 1;
813       }
814     }
815     Key[i] = CurrentKey;
816     Ord[i] = CurrentOrd;
817   }
818 
819 }
820 
821 
822 
823