1 /* zzgetelm.f -- translated by f2c (version 19980913).
2    You must link the resulting object file with the libraries:
3 	-lf2c -lm   (in that order)
4 */
5 
6 #include "f2c.h"
7 
8 /* Table of constant values */
9 
10 static integer c__3 = 3;
11 static integer c__2 = 2;
12 static integer c__4 = 4;
13 
14 /* $Procedure ZZGETELM ( Get the components from two-line elements) */
zzgetelm_(integer * frstyr,char * lines,doublereal * epoch,doublereal * elems,logical * ok,char * error,ftnlen lines_len,ftnlen error_len)15 /* Subroutine */ int zzgetelm_(integer *frstyr, char *lines, doublereal *
16 	epoch, doublereal *elems, logical *ok, char *error, ftnlen lines_len,
17 	ftnlen error_len)
18 {
19     /* Initialized data */
20 
21     static logical first = TRUE_;
22 
23     /* System generated locals */
24     address a__1[3], a__2[2];
25     integer i__1, i__2, i__3[3], i__4[2];
26 
27     /* Builtin functions */
28     /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
29     integer s_rnge(char *, integer, char *, integer), s_cmp(char *, char *,
30 	    ftnlen, ftnlen);
31     /* Subroutine */ int s_cat(char *, char **, integer *, integer *, ftnlen);
32 
33     /* Local variables */
34     static doublereal ndd60;
35     static char cday[32];
36     static doublereal incl, ndt20;
37     static integer bexp, year;
38     static doublereal tvec[8];
39     static char term[160*13];
40     static integer nexp;
41     static doublereal node0;
42     static integer i__, k;
43     static char cndd60[32], cincl[32];
44     static doublereal omega;
45     static char cndt20[32];
46     extern /* Subroutine */ int chkin_(char *, ftnlen);
47     static char cyear[32];
48     extern /* Subroutine */ int repmc_(char *, char *, char *, char *, ftnlen,
49 	     ftnlen, ftnlen, ftnlen), repmd_(char *, char *, doublereal *,
50 	    integer *, char *, ftnlen, ftnlen, ftnlen);
51     static char ciexp[32];
52     static integer begyr;
53     static doublereal bstar;
54     extern /* Subroutine */ int repmi_(char *, char *, integer *, char *,
55 	    ftnlen, ftnlen, ftnlen);
56     static doublereal power[75];
57     extern doublereal twopi_(void);
58     static char cnode0[32], comega[32];
59     static doublereal mo, no;
60     static char cibexp[32];
61     static integer yr;
62     static char cbstar[32];
63     extern integer lastnb_(char *, ftnlen);
64     extern /* Subroutine */ int nparsd_(char *, doublereal *, char *, integer
65 	    *, ftnlen, ftnlen), nparsi_(char *, integer *, char *, integer *,
66 	    ftnlen, ftnlen), chkout_(char *, ftnlen);
67     static doublereal d2r, pi2;
68     extern /* Subroutine */ int ttrans_(char *, char *, doublereal *, ftnlen,
69 	    ftnlen);
70     static char errprs[160*13];
71     extern logical return_(void);
72     static doublereal ecc, day;
73     static char cmo[32], cno[32];
74     extern doublereal rpd_(void);
75     static integer ptr;
76     static char cecc[32];
77 
78 /* $ Abstract */
79 
80 /*    Given a the "lines" of a two-line element set, parse the */
81 /*    lines and return the elements in units suitable for use */
82 /*    in SPICE software. */
83 
84 /* $ Disclaimer */
85 
86 /*     THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */
87 /*     CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */
88 /*     GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */
89 /*     ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */
90 /*     PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */
91 /*     TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */
92 /*     WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */
93 /*     PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */
94 /*     SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */
95 /*     SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */
96 
97 /*     IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */
98 /*     BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */
99 /*     LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
100 /*     INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */
101 /*     REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */
102 /*     REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */
103 
104 /*     RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */
105 /*     THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */
106 /*     CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */
107 /*     ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */
108 
109 /* $ Required_Reading */
110 
111 /*     None. */
112 
113 /* $ Keywords */
114 
115 /*     PARSING */
116 
117 /* $ Declarations */
118 /* $ Brief_I/O */
119 
120 /*     VARIABLE  I/O  DESCRIPTION */
121 /*     --------  ---  -------------------------------------------------- */
122 /*     FRSTYR     I   year of earliest representable two-line elements */
123 /*     LINES      I   a pair of "lines" containing two-line elements */
124 /*     EPOCH      O   The epoch of the elements in seconds past J2000 */
125 /*     ELEMS      O   The elements converted to SPICE units. */
126 /*     OK         O   Boolean indicating error state. */
127 /*     ERROR      O   String describing error. */
128 
129 /* $ Detailed_Input */
130 
131 /*     FRSTYR    is the first year possible for two line elements. */
132 /*               Since two line elements allow only two digits for */
133 /*               the year, some conventions must be followed concerning */
134 /*               which century the two digits refer to .  FRSTYR */
135 /*               is the year of the earliest representable elements. */
136 /*               The two-digit year is mapped to the year in */
137 /*               the interval from FRSTYR to FRSTYR + 99 that */
138 /*               has the same last two digits as the two digit */
139 /*               year in the element set.  For example if FRSTYR */
140 /*               is set to 1960  then the two digit years are mapped */
141 /*               as shown in the table below: */
142 
143 /*               Two-line         Maps to */
144 /*               element year */
145 /*                  00            2000 */
146 /*                  01            2001 */
147 /*                  02            2002 */
148 /*                   .              . */
149 /*                   .              . */
150 /*                   .              . */
151 /*                  58            2058 */
152 /*                  59            2059 */
153 /*                 -------------------- */
154 /*                  60            1960 */
155 /*                  61            1961 */
156 /*                  62            1962 */
157 /*                   .              . */
158 /*                   .              . */
159 /*                   .              . */
160 /*                  99            1999 */
161 
162 /*                Note that if Space Command should decide to represent */
163 /*                years in 21st century as 100 + the last two digits */
164 /*                of the year (for example: 2015 is represented as 115) */
165 /*                instead of simply dropping the first two digits of */
166 /*                the year, this routine will correctly map the year */
167 /*                as long as you set FRSTYR to some value between 1900 */
168 /*                and 1999. */
169 
170 /*     LINES      is a pair of lines of text that comprise a Space */
171 /*                command ``two-line element'' set.  These text lines */
172 /*                should be the same as they are presented in the */
173 /*                two-line element files available from Space Command */
174 /*                (formerly NORAD). Below is an example of a two-line */
175 /*                set for TOPEX. */
176 
177 /*  TOPEX */
178 /*  1 22076U 92052A   97173.53461370 -.00000038  00000-0  10000-3 0   594 */
179 /*  2 22076  66.0378 163.4372 0008359 278.7732  81.2337 12.80930736227550 */
180 
181 
182 /* $ Detailed_Output */
183 
184 /*     EPOCH      is the epoch of the two line elements supplied via */
185 /*                the input array LINES.  Epoch is returned in TDB */
186 /*                seconds past J2000. */
187 
188 /*     ELEMS      is an array containing the elements from the two line */
189 /*                set supplied via the array LINES.  The elements are */
190 /*                in units suitable for use by the SPICE routine */
191 /*                EV2LIN. */
192 
193 /*                Also note that the elements XNDD6O and BSTAR */
194 /*                incorporate the exponential factor present in the */
195 /*                input two line elements in LINES.  (See particulars */
196 /*                below. */
197 
198 /*                    ELEMS (  1 ) = XNDT2O in radians/minute**2 */
199 /*                    ELEMS (  2 ) = XNDD6O in radians/minute**3 */
200 /*                    ELEMS (  3 ) = BSTAR */
201 /*                    ELEMS (  4 ) = XINCL  in radians */
202 /*                    ELEMS (  5 ) = XNODEO in radians */
203 /*                    ELEMS (  6 ) = EO */
204 /*                    ELEMS (  7 ) = OMEGAO in radians */
205 /*                    ELEMS (  8 ) = XMO    in radians */
206 /*                    ELEMS (  9 ) = XNO    in radians/minute */
207 /*                    ELEMS ( 10 ) = EPOCH of the elements in seconds */
208 /*                                   past ephemeris epoch J2000. */
209 
210 /*     OK         a boolean flag indicating whether an error occured */
211 /*                while processing the TLE. Processing errors include */
212 /*                incorrect format for TLEs, angular values beyond */
213 /*                allowed range. */
214 
215 /*     ERROR      a string containing a description of any TLE */
216 /*                processing error. */
217 
218 /* $ Parameters */
219 
220 /*     None. */
221 
222 /* $ Files */
223 
224 /*     You must have loaded a SPICE leapseconds kernel into the */
225 /*     kernel pool prior to caling this routine. */
226 
227 /* $ Exceptions */
228 
229 /*     This routine does not signal errors, rather it returns an */
230 /*     error flag and description to the calling program. Errors */
231 /*     reported: */
232 
233 /*     1) TLE line has incorrect format. */
234 
235 /*     2) A TLE '2' line has a different vehicle tag than the */
236 /*         corresponding '1' line. */
237 
238 /*     3) TLE data length more than 69 characters, or less than 68 */
239 /*        characters. */
240 
241 /*     4) An NPARS* routine cannot parse a string to a numeric value. */
242 
243 /*     5) The value of an angular measure, NODE0, OMEGA, MO, or INCL */
244 /*        fails to lie within the expected numerical bounds. */
245 
246 /* $ Particulars */
247 
248 /*     This routine parses a Space Command Two-line element set and */
249 /*     returns the orbital elements properly scaled and in units */
250 /*     suitable for use by other SPICE software.  Input elements */
251 /*     have the form: */
252 
253 /*  1 22076U 92052A   97173.53461370 -.00000038  00000-0  10000-3 0   594 */
254 /*  2 22076  66.0378 163.4372 0008359 278.7732  81.2337 12.80930736227550 */
255 /*  ^ */
256 /*  123456789012345678901234567890123456789012345678901234567890123456789 */
257 /*           1         2         3         4         5         6 */
258 
259 /*     The ``raw'' elements in the first  and second lines are marked */
260 /*     below.  Note that in several instances exponents and decimal */
261 /*     points are implied.  Also note that */
262 /*     input units are degrees, degrees/day**n and revolutions/day. */
263 
264 
265 /*                      DAY OF YEAR             NDD60    BSTAR */
266 /*                      vvvvvvvvvvvv            vvvvvv   vvvvvv */
267 /*  --------------------------------------------------------------------- */
268 /*  1 22076U 92052A   97173.53461370 -.00000038  00000-0  10000-3 0   594 */
269 /*  --------------------------------------------------------------------- */
270 /*                    ^^             ^^^^^^^^^^       ^^       ^^ */
271 /*                    YEAR             NDT20          IEXP     IBEXP */
272 
273 
274 
275 /*     The ``raw'' elements in the second line are marked below */
276 /*                   NODE0            OMEGA             N0 */
277 /*                   vvvvvvvv         vvvvvvvv          vvvvvvvvvvv */
278 /*  --------------------------------------------------------------------- */
279 /*  2 22076  66.0378 163.4372 0008359 278.7732  81.2337 12.80930736227550 */
280 /*  --------------------------------------------------------------------- */
281 /*          ^^^^^^^^          ^^^^^^^          ^^^^^^^^ */
282 /*          Inclination       Eccentricity     M0 */
283 
284 /*     This routine extracts these values ``inserts'' the implied */
285 /*     decimal points and exponents and then converts the inputs */
286 /*     to units of radians, radians/minute, radians/minute**2, and */
287 /*     radians/minute**3 */
288 
289 /* $ Examples */
290 
291 /*     Suppose you have a set of two-line elements and an array */
292 /*     containing the related geophysical constants necessary */
293 /*     to evaluate a state.  The example below shows how you */
294 /*     can use this routine together with the routine EV2LIN to */
295 /*     propagate a state to an epoch of interest. */
296 
297 
298 /*        The parameters below will make it easier to make assignments */
299 /*        to the array GEOPHS required by EV2LIN. */
300 
301 /*        J2  --- location of J2 */
302 /*        J3  --- location of J3 */
303 /*        J4  --- location if J4 */
304 /*        KE  --- location of KE = sqrt(GM) in eart-radii**1.5/MIN */
305 /*        QO  --- location of upper bound of atmospheric model in KM */
306 /*        SO  --- location of lower bound of atmospheric model in KM */
307 /*        ER  --- location of earth equatorial radius in KM. */
308 /*        AE  --- location of distance units/earth radius */
309 
310 /*        PARAMETER           ( J2 = 1 ) */
311 /*        PARAMETER           ( J3 = 2 ) */
312 /*        PARAMETER           ( J4 = 3 ) */
313 /*        PARAMETER           ( KE = 4 ) */
314 /*        PARAMETER           ( QO = 5 ) */
315 /*        PARAMETER           ( SO = 6 ) */
316 /*        PARAMETER           ( ER = 7 ) */
317 /*        PARAMETER           ( AE = 8 ) */
318 
319 
320 /*        We set the lower bound for the years to be the beginning */
321 /*        of the space age. */
322 
323 /*        FRSTYR = 1957 */
324 
325 /*        Read in the next two lines from the text file that contains */
326 /*        the two-line elements.  We assume that file has been opened */
327 /*        properly and that we have set the ``file pointer'' to the */
328 /*        correct location for reading the next set of elements. */
329 
330 /*        READ  (UNIT,FMT='(A)' ) LINE(1) */
331 /*        READ  (UNIT,FMT='(A)' ) LINE(2) */
332 
333 /*        CALL ZZGETELM ( FRSTYR, LINE, EPOCH, ELEMS, OK, ERROR ) */
334 
335 /*        Set up the geophysical quantities.  At last check these */
336 /*        were the values used by Space Command. */
337 
338 /*        GEOPHS( J2 ) =    1.082616D-3 */
339 /*        GEOPHS( J3 ) =   -2.53881D-6 */
340 /*        GEOPHS( J4 ) =   -1.65597D-6 */
341 /*        GEOPHS( KE ) =    7.43669161D-2 */
342 /*        GEOPHS( QO ) =  120.0D0 */
343 /*        GEOPHS( SO ) =   78.0D0 */
344 /*        GEOPHS( ER ) = 6378.135D0 */
345 /*        GEOPHS( AE ) =    1.0D0 */
346 
347 /*        Now propagate the state using EV2LIN to the epoch of */
348 /*        interest. */
349 
350 /*        CALL EV2LIN ( ET, GEOPHS, ELEMS, STATE ) */
351 
352 
353 /* $ Restrictions */
354 
355 /*    The format of the two-line elements suffer from a "millenium" */
356 /*    problem---only two digits are used for the year of the elements. */
357 /*    It is not clear how Space Command will deal with this problem */
358 /*    as the year 2000 comes and goes.  We hope that by adjusting */
359 /*    the input FRSTYR you should be able to use this */
360 /*    routine well into the 21st century.  However, since we can't */
361 /*    predict how others will resolve the millenium problem we */
362 /*    can't be sure that our approach will be addequate to deal with */
363 /*    the problem. */
364 
365 /*    The approach taken to mapping the two-digit year to the */
366 /*    full year is given by the code below. Here, YR is the */
367 /*    integer obtained by parsing the two-digit year from the first */
368 /*    line of the elements. */
369 
370 /*        BEGYR = (FRSTYR/100)*100 */
371 /*        YEAR  = BEGYR + YR */
372 
373 /*        IF ( YEAR .LT. FRSTYR ) THEN */
374 /*           YEAR = YEAR + 100 */
375 /*        END IF */
376 
377 /*     This mapping will be changed if future two-line element */
378 /*     representations make this method of computing the full year */
379 /*     inaccurate. */
380 
381 /* $ Author_and_Institution */
382 
383 /*     W.L. Taber      (JPL) */
384 /*     E.D. Wright     (JPL) */
385 
386 /* $ Literature_References */
387 
388 /*     None. */
389 
390 /* $ Version */
391 
392 
393 /* -    SPICELIB Version 1.0.0, 26-APR-2004 (EDW) */
394 
395 /*        Modified routine GETELM to confirm */
396 /*        acceptable range for angular measures and exponents. */
397 /*        The routine does not signal errors,it returns an error */
398 /*        flag and error string to the calling program. */
399 
400 /*        Routine named ZZGETELM from GETELM. */
401 
402 /* -& */
403 /* $ Index_Entries */
404 
405 /*     Parse two-line elements */
406 
407 /* -& */
408 
409 /*     Spicelib functions */
410 
411 
412 /*     An enumeration of the various components of the */
413 /*     elements array---ELEMS */
414 
415 /*        KNDT20 */
416 /*        KNDD60 */
417 /*        KBSTAR */
418 /*        KINCL */
419 /*        KNODE0 */
420 /*        KECC */
421 /*        KOMEGA */
422 /*        KMO */
423 /*        KNO */
424 
425 
426 /*     Character string lengths */
427 
428 
429 /*     Maximum exponent (base 10) */
430 
431 
432 /*     Double precision constants. */
433 
434 
435 /*     Minutes/day */
436 
437 
438 /*     Local variables */
439 
440 
441 /*     Standard SPICE error handling. */
442 
443     if (return_()) {
444 	return 0;
445     }
446     chkin_("ZZGETELM", (ftnlen)8);
447 
448 /*     Initialize the error indicators and the elements to zero. */
449 
450     *ok = TRUE_;
451     s_copy(error, " ", error_len, (ftnlen)1);
452     elems[0] = 0.;
453     elems[1] = 0.;
454     elems[2] = 0.;
455     elems[3] = 0.;
456     elems[4] = 0.;
457     elems[5] = 0.;
458     elems[6] = 0.;
459     elems[7] = 0.;
460     elems[8] = 0.;
461     elems[9] = 0.;
462     *epoch = 0.;
463 
464 /*     First entry initialization. */
465 
466     if (first) {
467 
468 /*        Define two constants. This initialization proves the most */
469 /*        useful when processing thousands of TLE sets. */
470 
471 	d2r = rpd_();
472 	pi2 = twopi_();
473 	first = FALSE_;
474 	power[37] = 1.;
475 	for (i__ = 1; i__ <= 37; ++i__) {
476 	    power[(i__1 = i__ + 37) < 75 && 0 <= i__1 ? i__1 : s_rnge("power",
477 		     i__1, "zzgetelm_", (ftnlen)535)] = power[(i__2 = i__ +
478 		    36) < 75 && 0 <= i__2 ? i__2 : s_rnge("power", i__2,
479 		    "zzgetelm_", (ftnlen)535)] * 10.;
480 	    power[(i__1 = -i__ + 37) < 75 && 0 <= i__1 ? i__1 : s_rnge("power"
481 		    , i__1, "zzgetelm_", (ftnlen)536)] = 1. / power[(i__2 =
482 		    i__ + 37) < 75 && 0 <= i__2 ? i__2 : s_rnge("power", i__2,
483 		     "zzgetelm_", (ftnlen)536)];
484 	}
485 	s_copy(term, "\"YEAR\" (characters 19 to 20 of the first line of a t"
486 		"wo-line element set)", (ftnlen)160, (ftnlen)72);
487 	s_copy(term + 160, "\"DAY\" (characters 21 to 32 of the first line o"
488 		"f a two-line element set)", (ftnlen)160, (ftnlen)71);
489 	s_copy(term + 320, "\"NDT20\" (characters 34 to 43 of the first line"
490 		" of a two-line element set)", (ftnlen)160, (ftnlen)73);
491 	s_copy(term + 480, "\"NDD60\" (characters 45 to 45 of the first line"
492 		" of a two-line element set)", (ftnlen)160, (ftnlen)73);
493 	s_copy(term + 640, "\"IEXP\" (characters 51 to 52 of the first line "
494 		"of a two-line element set)", (ftnlen)160, (ftnlen)72);
495 	s_copy(term + 800, "\"BSTAR\" (characters 54 to 54 of the first line"
496 		" of a two-line element set)", (ftnlen)160, (ftnlen)73);
497 	s_copy(term + 960, "\"IBEXP\" (characters 60 to 61 of the first line"
498 		" of a two-line element set)", (ftnlen)160, (ftnlen)73);
499 	s_copy(term + 1120, "\"INCL\" (characters 9 to 16 of the second line"
500 		" of a two-line element set)", (ftnlen)160, (ftnlen)72);
501 	s_copy(term + 1280, "\"NODE0\" (characters 18 to 25 of the second li"
502 		"ne of a two-line element set)", (ftnlen)160, (ftnlen)74);
503 	s_copy(term + 1440, "\"ECC\" (characters 27 to 33 of the second line"
504 		" of a two-line element set)", (ftnlen)160, (ftnlen)72);
505 	s_copy(term + 1600, "\"OMEGA\" (characters 35 to 42 of the second li"
506 		"ne of a two-line element set)", (ftnlen)160, (ftnlen)74);
507 	s_copy(term + 1760, "\"MO\" (characters 44 to 51 of the second line "
508 		"of a two-line element set)", (ftnlen)160, (ftnlen)71);
509 	s_copy(term + 1920, "\"NO\" (characters 53 to 63 of the second line "
510 		"of a two-line element set)", (ftnlen)160, (ftnlen)71);
511     }
512 
513 /*     Ensure the vehicle IDs match in each line. */
514 
515     if (s_cmp(lines + 1, lines + (lines_len + 1), (ftnlen)6, (ftnlen)6) != 0)
516 	    {
517 
518 /*        Vehicle IDs do not match. Flag an error. */
519 
520 	s_copy(error, "Line 1 of the TLE pair tagged with vehicle ID #1,  li"
521 		"ne 2 of TLE pair tagged with vehicle ID #2", error_len, (
522 		ftnlen)95);
523 	repmc_(error, "#1", lines + 1, error, error_len, (ftnlen)2, (ftnlen)6,
524 		 error_len);
525 	repmc_(error, "#2", lines + (lines_len + 1), error, error_len, (
526 		ftnlen)2, (ftnlen)6, error_len);
527 	*ok = FALSE_;
528 	chkout_("ZZGETELM", (ftnlen)8);
529 	return 0;
530     }
531 
532 /*    Check line format and length. */
533 
534     for (k = 1; k <= 2; ++k) {
535 	if (lastnb_(lines + ((i__1 = k - 1) < 2 && 0 <= i__1 ? i__1 : s_rnge(
536 		"lines", i__1, "zzgetelm_", (ftnlen)604)) * lines_len,
537 		lines_len) != 68 && lastnb_(lines + ((i__2 = k - 1) < 2 && 0
538 		<= i__2 ? i__2 : s_rnge("lines", i__2, "zzgetelm_", (ftnlen)
539 		604)) * lines_len, lines_len) != 69) {
540 
541 /*          The TLE data line was not 68 or 69 characters long (ignoring */
542 /*          trailing whitespace). Flag an error. */
543 
544 	    s_copy(error, "Line #1 of the TLE has incorrect data length. Exp"
545 		    "ected length 68 or 69 elements, actual length: #2. TLE l"
546 		    "ine value: #3", error_len, (ftnlen)118);
547 	    repmi_(error, "#1", &k, error, error_len, (ftnlen)2, error_len);
548 	    i__2 = lastnb_(lines + ((i__1 = k - 1) < 2 && 0 <= i__1 ? i__1 :
549 		    s_rnge("lines", i__1, "zzgetelm_", (ftnlen)615)) *
550 		    lines_len, lines_len);
551 	    repmi_(error, "#2", &i__2, error, error_len, (ftnlen)2, error_len)
552 		    ;
553 	    repmc_(error, "#3", lines + ((i__1 = k - 1) < 2 && 0 <= i__1 ?
554 		    i__1 : s_rnge("lines", i__1, "zzgetelm_", (ftnlen)616)) *
555 		    lines_len, error, error_len, (ftnlen)2, lines_len,
556 		    error_len);
557 	    *ok = FALSE_;
558 	    chkout_("ZZGETELM", (ftnlen)8);
559 	    return 0;
560 	}
561     }
562 
563 /*     This isn't particularly pretty, but it is straight */
564 /*     forward.  According to the documentation on the two line */
565 /*     element sets, (as well as what's indicated by the program */
566 /*     driver that is documented in SPACETRACK REPORT NO.3 */
567 /*     we can simply pick out the various components of the */
568 /*     elements from the input lines 1 and 2. */
569 
570 /*     For the record we include the DECODE statement in DRIVER */
571 /*     for fetching the data out of lines one and two (after a bit */
572 /*     of pretty printing).  Note that some of these formats have */
573 /*     and implied decimal point.  In particular f6.5 and f7.7  in */
574 /*     all other cases the decimal points seem to be given explicitely. */
575 
576 /*     decode (abuf,702) epoch,     xndt20,                       ... */
577 /*                       xndd60,    iexp,        bstar,    ibexp, ... */
578 /*                       xincl,     xnodeo,                       ... */
579 /*                       eo,        omegao,     xmo,       xno */
580 /*     format(      18x, d14.8, 1x, f10.8, */
581 /*                   1x, f6.5,      i2,     1x, f6.5,      i2,    /, */
582 /*                   8x, f8.4,  1x, f8.4, */
583 /*                   1x, f7.7,  1x, f8.4,   1x, f8.4   1x, f11.8 ) */
584 
585 /*     Note that in the two-line element sets, the epoch is read */
586 /*     as a single number.  However the documentation that describes */
587 /*     this data (as well as the code in THETAG) show that it's a lot */
588 /*     easier to capture the year and day of year separately. */
589 
590     s_copy(cyear, lines + 18, (ftnlen)32, (ftnlen)2);
591     s_copy(cday, lines + 20, (ftnlen)32, (ftnlen)12);
592     s_copy(cndt20, lines + 33, (ftnlen)32, (ftnlen)10);
593 /* Writing concatenation */
594     i__3[0] = 1, a__1[0] = lines + 44;
595     i__3[1] = 1, a__1[1] = ".";
596     i__3[2] = 5, a__1[2] = lines + 45;
597     s_cat(cndd60, a__1, i__3, &c__3, (ftnlen)32);
598     s_copy(ciexp, lines + 50, (ftnlen)32, (ftnlen)2);
599 /* Writing concatenation */
600     i__3[0] = 1, a__1[0] = lines + 53;
601     i__3[1] = 1, a__1[1] = ".";
602     i__3[2] = 5, a__1[2] = lines + 54;
603     s_cat(cbstar, a__1, i__3, &c__3, (ftnlen)32);
604     s_copy(cibexp, lines + 59, (ftnlen)32, (ftnlen)2);
605     s_copy(cincl, lines + (lines_len + 8), (ftnlen)32, (ftnlen)8);
606     s_copy(cnode0, lines + (lines_len + 17), (ftnlen)32, (ftnlen)8);
607 /* Writing concatenation */
608     i__4[0] = 2, a__2[0] = "0.";
609     i__4[1] = 7, a__2[1] = lines + (lines_len + 26);
610     s_cat(cecc, a__2, i__4, &c__2, (ftnlen)32);
611     s_copy(comega, lines + (lines_len + 34), (ftnlen)32, (ftnlen)8);
612     s_copy(cmo, lines + (lines_len + 43), (ftnlen)32, (ftnlen)8);
613     s_copy(cno, lines + (lines_len + 52), (ftnlen)32, (ftnlen)11);
614 
615 /*     Parse the numerical values from the data string. */
616 
617     nparsi_(cyear, &yr, errprs, &ptr, (ftnlen)32, (ftnlen)160);
618     nparsd_(cday, &day, errprs + 160, &ptr, (ftnlen)32, (ftnlen)160);
619     nparsd_(cndt20, &ndt20, errprs + 320, &ptr, (ftnlen)32, (ftnlen)160);
620     nparsd_(cndd60, &ndd60, errprs + 480, &ptr, (ftnlen)32, (ftnlen)160);
621     nparsi_(ciexp, &nexp, errprs + 640, &ptr, (ftnlen)32, (ftnlen)160);
622     nparsd_(cbstar, &bstar, errprs + 800, &ptr, (ftnlen)32, (ftnlen)160);
623     nparsi_(cibexp, &bexp, errprs + 960, &ptr, (ftnlen)32, (ftnlen)160);
624     nparsd_(cincl, &incl, errprs + 1120, &ptr, (ftnlen)32, (ftnlen)160);
625     nparsd_(cnode0, &node0, errprs + 1280, &ptr, (ftnlen)32, (ftnlen)160);
626     nparsd_(cecc, &ecc, errprs + 1440, &ptr, (ftnlen)32, (ftnlen)160);
627     nparsd_(comega, &omega, errprs + 1600, &ptr, (ftnlen)32, (ftnlen)160);
628     nparsd_(cmo, &mo, errprs + 1760, &ptr, (ftnlen)32, (ftnlen)160);
629     nparsd_(cno, &no, errprs + 1920, &ptr, (ftnlen)32, (ftnlen)160);
630 
631 /*     Check for parse errors. */
632 
633     for (i__ = 1; i__ <= 13; ++i__) {
634 	if (s_cmp(errprs + ((i__1 = i__ - 1) < 13 && 0 <= i__1 ? i__1 :
635 		s_rnge("errprs", i__1, "zzgetelm_", (ftnlen)692)) * 160,
636 		" ", (ftnlen)160, (ftnlen)1) != 0) {
637 
638 /*           Something could not parse. Set the error message then */
639 /*           return. */
640 
641 	    s_copy(error, "An error occurred while trying to parse the term "
642 		    "#. The diagnostic was:  # ", error_len, (ftnlen)75);
643 	    repmc_(error, "#", term + ((i__1 = i__ - 1) < 13 && 0 <= i__1 ?
644 		    i__1 : s_rnge("term", i__1, "zzgetelm_", (ftnlen)700)) *
645 		    160, error, error_len, (ftnlen)1, (ftnlen)160, error_len);
646 	    repmc_(error, "#", errprs + ((i__1 = i__ - 1) < 13 && 0 <= i__1 ?
647 		    i__1 : s_rnge("errprs", i__1, "zzgetelm_", (ftnlen)701)) *
648 		     160, error, error_len, (ftnlen)1, (ftnlen)160, error_len)
649 		    ;
650 	    *ok = FALSE_;
651 	    chkout_("ZZGETELM", (ftnlen)8);
652 	    return 0;
653 	}
654     }
655 
656 /*     Check for reasonable exponets; a single digit. These should */
657 /*     probably be LE 0. */
658 
659     if (abs(nexp) > 9) {
660 	s_copy(error, "NEXP (exponent) not a single digit. Actual value #1",
661 		error_len, (ftnlen)51);
662 	repmi_(error, "#1", &nexp, error, error_len, (ftnlen)2, error_len);
663 	*ok = FALSE_;
664 	chkout_("ZZGETELM", (ftnlen)8);
665 	return 0;
666     }
667     if (abs(bexp) > 9) {
668 	s_copy(error, "BEXP (exponent) not a single digit. Actual value #1",
669 		error_len, (ftnlen)51);
670 	repmi_(error, "#1", &bexp, error, error_len, (ftnlen)2, error_len);
671 	*ok = FALSE_;
672 	chkout_("ZZGETELM", (ftnlen)8);
673 	return 0;
674     }
675 
676 /*     Confirm correct bounds on angular values. */
677 
678 /*     NODE0 - right ascension of the ascending node, [0,360) */
679 
680     if (node0 < 0. || node0 >= 360.) {
681 	s_copy(error, "NODE0 (RA acend node) expected bounds [0,360). Actual"
682 		" value #1", error_len, (ftnlen)62);
683 	repmd_(error, "#1", &node0, &c__4, error, error_len, (ftnlen)2,
684 		error_len);
685 	*ok = FALSE_;
686 	chkout_("ZZGETELM", (ftnlen)8);
687 	return 0;
688     }
689 
690 /*     OMEAGA - argument of the periapsis, [0,360) */
691 
692     if (omega < 0. || omega >= 360.) {
693 	s_copy(error, "OMEGA (arg periap) expected bounds [0,360). Actual va"
694 		"lue #1", error_len, (ftnlen)59);
695 	repmd_(error, "#1", &omega, &c__4, error, error_len, (ftnlen)2,
696 		error_len);
697 	*ok = FALSE_;
698 	chkout_("ZZGETELM", (ftnlen)8);
699 	return 0;
700     }
701 
702 /*     MO - mean anomoly, [0,360) */
703 
704     if (mo < 0. || mo >= 360.) {
705 	s_copy(error, "MO (mean anomoly) expected bounds [0,360). Actual val"
706 		"ue #1", error_len, (ftnlen)58);
707 	repmd_(error, "#1", &mo, &c__4, error, error_len, (ftnlen)2,
708 		error_len);
709 	*ok = FALSE_;
710 	chkout_("ZZGETELM", (ftnlen)8);
711 	return 0;
712     }
713 
714 /*     INCL - inclination, [0,180] */
715 
716     if (incl < 0. || incl > 180.) {
717 	s_copy(error, "INCL (inclination) expected bounds [0,180). Actual va"
718 		"lue #1", error_len, (ftnlen)59);
719 	repmd_(error, "#1", &incl, &c__4, error, error_len, (ftnlen)2,
720 		error_len);
721 	*ok = FALSE_;
722 	chkout_("ZZGETELM", (ftnlen)8);
723 	return 0;
724     }
725 
726 /*     NO - mean motion (0,20) (Earth orbiter). */
727 
728     if (no > 20. || no < 0.) {
729 	s_copy(error, "NO (mean motion) expected bounds (0,20). Actual value"
730 		" #1", error_len, (ftnlen)56);
731 	repmd_(error, "#1", &no, &c__4, error, error_len, (ftnlen)2,
732 		error_len);
733 	*ok = FALSE_;
734 	chkout_("ZZGETELM", (ftnlen)8);
735 	return 0;
736     }
737 
738 /*     Finish up the computation of NDD60 and BSTAR */
739 
740     ndd60 *= power[(i__1 = nexp + 37) < 75 && 0 <= i__1 ? i__1 : s_rnge("pow"
741 	    "er", i__1, "zzgetelm_", (ftnlen)827)];
742     bstar *= power[(i__1 = bexp + 37) < 75 && 0 <= i__1 ? i__1 : s_rnge("pow"
743 	    "er", i__1, "zzgetelm_", (ftnlen)828)];
744 
745 /*     Convert everything from degrees to radians ... */
746 
747     node0 *= d2r;
748     omega *= d2r;
749     mo *= d2r;
750     incl *= d2r;
751 
752 /*     ... and from revolutions/day**n to radians/minutes**n */
753 
754     no = no * pi2 / 1440.;
755     ndt20 = ndt20 * pi2 / 1440. / 1440.;
756     ndd60 = ndd60 * pi2 / 1440. / 1440. / 1440.;
757 
758 /*     Finally, we need to convert the input epoch to */
759 /*     seconds past 2000. First let's adjust the year. */
760 /*     Add to YR the largest multiple of 100 that is */
761 /*     less than or equal to FRSTYR */
762 
763     begyr = *frstyr / 100 * 100;
764     year = begyr + yr;
765     if (year < *frstyr) {
766 	year += 100;
767     }
768 
769 /*     Compute the epoch of the year and date. */
770 
771     tvec[0] = (doublereal) year;
772     tvec[1] = day;
773     ttrans_("YD.D", "TDB", tvec, (ftnlen)4, (ftnlen)3);
774     *epoch = tvec[0];
775 
776 /*     That's it.  Load ELEMS with the elements and ship them */
777 /*     back to the calling routine. */
778 
779     elems[0] = ndt20;
780     elems[1] = ndd60;
781     elems[2] = bstar;
782     elems[3] = incl;
783     elems[4] = node0;
784     elems[5] = ecc;
785     elems[6] = omega;
786     elems[7] = mo;
787     elems[8] = no;
788     elems[9] = *epoch;
789     chkout_("ZZGETELM", (ftnlen)8);
790     return 0;
791 } /* zzgetelm_ */
792 
793