1   /* Copyright 2002-2021 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.propagation.analytical.tle;
18  
19  import org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.hipparchus.util.FastMath;
21  import org.hipparchus.util.MathUtils;
22  import org.hipparchus.util.SinCos;
23  import org.orekit.annotation.DefaultDataContext;
24  import org.orekit.attitudes.Attitude;
25  import org.orekit.attitudes.AttitudeProvider;
26  import org.orekit.attitudes.InertialProvider;
27  import org.orekit.data.DataContext;
28  import org.orekit.errors.OrekitException;
29  import org.orekit.errors.OrekitMessages;
30  import org.orekit.frames.Frame;
31  import org.orekit.frames.Frames;
32  import org.orekit.orbits.CartesianOrbit;
33  import org.orekit.orbits.Orbit;
34  import org.orekit.propagation.SpacecraftState;
35  import org.orekit.propagation.analytical.AbstractAnalyticalPropagator;
36  import org.orekit.time.AbsoluteDate;
37  import org.orekit.time.TimeScale;
38  import org.orekit.utils.PVCoordinates;
39  
40  
41  /** This class provides elements to propagate TLE's.
42   * <p>
43   * The models used are SGP4 and SDP4, initially proposed by NORAD as the unique convenient
44   * propagator for TLE's. Inputs and outputs of this propagator are only suited for
45   * NORAD two lines elements sets, since it uses estimations and mean values appropriate
46   * for TLE's only.
47   * </p>
48   * <p>
49   * Deep- or near- space propagator is selected internally according to NORAD recommendations
50   * so that the user has not to worry about the used computation methods. One instance is created
51   * for each TLE (this instance can only be get using {@link #selectExtrapolator(TLE)} method,
52   * and can compute {@link PVCoordinates position and velocity coordinates} at any
53   * time. Maximum accuracy is guaranteed in a 24h range period before and after the provided
54   * TLE epoch (of course this accuracy is not really measurable nor predictable: according to
55   * <a href="https://www.celestrak.com/">CelesTrak</a>, the precision is close to one kilometer
56   * and error won't probably rise above 2 km).
57   * </p>
58   * <p>This implementation is largely inspired from the paper and source code <a
59   * href="https://www.celestrak.com/publications/AIAA/2006-6753/">Revisiting Spacetrack
60   * Report #3</a> and is fully compliant with its results and tests cases.</p>
61   * @author Felix R. Hoots, Ronald L. Roehrich, December 1980 (original fortran)
62   * @author David A. Vallado, Paul Crawford, Richard Hujsak, T.S. Kelso (C++ translation and improvements)
63   * @author Fabien Maussion (java translation)
64   * @see TLE
65   */
66  public abstract class TLEPropagator extends AbstractAnalyticalPropagator {
67  
68      // CHECKSTYLE: stop VisibilityModifier check
69  
70      /** Initial state. */
71      protected TLE tle;
72  
73      /** UTC time scale. */
74      protected final TimeScale utc;
75  
76      /** final RAAN. */
77      protected double xnode;
78  
79      /** final semi major axis. */
80      protected double a;
81  
82      /** final eccentricity. */
83      protected double e;
84  
85      /** final inclination. */
86      protected double i;
87  
88      /** final perigee argument. */
89      protected double omega;
90  
91      /** L from SPTRCK #3. */
92      protected double xl;
93  
94      /** original recovered semi major axis. */
95      protected double a0dp;
96  
97      /** original recovered mean motion. */
98      protected double xn0dp;
99  
100     /** cosinus original inclination. */
101     protected double cosi0;
102 
103     /** cos io squared. */
104     protected double theta2;
105 
106     /** sinus original inclination. */
107     protected double sini0;
108 
109     /** common parameter for mean anomaly (M) computation. */
110     protected double xmdot;
111 
112     /** common parameter for perigee argument (omega) computation. */
113     protected double omgdot;
114 
115     /** common parameter for raan (OMEGA) computation. */
116     protected double xnodot;
117 
118     /** original eccentricity squared. */
119     protected double e0sq;
120     /** 1 - e2. */
121     protected double beta02;
122 
123     /** sqrt (1 - e2). */
124     protected double beta0;
125 
126     /** perigee, expressed in KM and ALTITUDE. */
127     protected double perige;
128 
129     /** eta squared. */
130     protected double etasq;
131 
132     /** original eccentricity * eta. */
133     protected double eeta;
134 
135     /** s* new value for the contant s. */
136     protected double s4;
137 
138     /** tsi from SPTRCK #3. */
139     protected double tsi;
140 
141     /** eta from SPTRCK #3. */
142     protected double eta;
143 
144     /** coef for SGP C3 computation. */
145     protected double coef;
146 
147     /** coef for SGP C5 computation. */
148     protected double coef1;
149 
150     /** C1 from SPTRCK #3. */
151     protected double c1;
152 
153     /** C2 from SPTRCK #3. */
154     protected double c2;
155 
156     /** C4 from SPTRCK #3. */
157     protected double c4;
158 
159     /** common parameter for raan (OMEGA) computation. */
160     protected double xnodcf;
161 
162     /** 3/2 * C1. */
163     protected double t2cof;
164 
165     // CHECKSTYLE: resume VisibilityModifier check
166 
167     /** TLE frame. */
168     private final Frame teme;
169 
170     /** Spacecraft mass (kg). */
171     private final double mass;
172 
173     /** Protected constructor for derived classes.
174      *
175      * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
176      *
177      * @param initialTLE the unique TLE to propagate
178      * @param attitudeProvider provider for attitude computation
179      * @param mass spacecraft mass (kg)
180      * @see #TLEPropagator(TLE, AttitudeProvider, double, Frame)
181      */
182     @DefaultDataContext
183     protected TLEPropagator(final TLE initialTLE, final AttitudeProvider attitudeProvider,
184                             final double mass) {
185         this(initialTLE, attitudeProvider, mass,
186                 DataContext.getDefault().getFrames().getTEME());
187     }
188 
189     /** Protected constructor for derived classes.
190      * @param initialTLE the unique TLE to propagate
191      * @param attitudeProvider provider for attitude computation
192      * @param mass spacecraft mass (kg)
193      * @param teme the TEME frame to use for propagation.
194      * @since 10.1
195      */
196     protected TLEPropagator(final TLE initialTLE,
197                             final AttitudeProvider attitudeProvider,
198                             final double mass,
199                             final Frame teme) {
200         super(attitudeProvider);
201         setStartDate(initialTLE.getDate());
202         this.tle  = initialTLE;
203         this.teme = teme;
204         this.mass = mass;
205         this.utc = initialTLE.getUtc();
206 
207         initializeCommons();
208         sxpInitialize();
209         // set the initial state
210         final Orbit orbit = propagateOrbit(initialTLE.getDate());
211         final Attitude attitude = attitudeProvider.getAttitude(orbit, orbit.getDate(), orbit.getFrame());
212         super.resetInitialState(new SpacecraftState(orbit, attitude, mass));
213     }
214 
215     /** Selects the extrapolator to use with the selected TLE.
216      *
217      * <p>This method uses the {@link DataContext#getDefault() default data context}.
218      *
219      * @param tle the TLE to propagate.
220      * @return the correct propagator.
221      * @see #selectExtrapolator(TLE, Frames)
222      */
223     @DefaultDataContext
224     public static TLEPropagator selectExtrapolator(final TLE tle) {
225         return selectExtrapolator(tle, DataContext.getDefault().getFrames());
226     }
227 
228     /** Selects the extrapolator to use with the selected TLE.
229      * @param tle the TLE to propagate.
230      * @param frames set of Frames to use in the propagator.
231      * @return the correct propagator.
232      * @since 10.1
233      */
234     public static TLEPropagator selectExtrapolator(final TLE tle, final Frames frames) {
235         return selectExtrapolator(
236                 tle,
237                 InertialProvider.of(frames.getTEME()),
238                 DEFAULT_MASS,
239                 frames.getTEME());
240     }
241 
242     /** Selects the extrapolator to use with the selected TLE.
243      *
244      * <p>This method uses the {@link DataContext#getDefault() default data context}.
245      *
246      * @param tle the TLE to propagate.
247      * @param attitudeProvider provider for attitude computation
248      * @param mass spacecraft mass (kg)
249      * @return the correct propagator.
250      * @see #selectExtrapolator(TLE, AttitudeProvider, double, Frame)
251      */
252     @DefaultDataContext
253     public static TLEPropagator selectExtrapolator(final TLE tle, final AttitudeProvider attitudeProvider,
254                                                    final double mass) {
255         return selectExtrapolator(tle, attitudeProvider, mass,
256                 DataContext.getDefault().getFrames().getTEME());
257     }
258 
259     /** Selects the extrapolator to use with the selected TLE.
260      * @param tle the TLE to propagate.
261      * @param attitudeProvider provider for attitude computation
262      * @param mass spacecraft mass (kg)
263      * @param teme the TEME frame to use for propagation.
264      * @return the correct propagator.
265      * @since 10.1
266      */
267     public static TLEPropagator selectExtrapolator(final TLE tle,
268                                                    final AttitudeProvider attitudeProvider,
269                                                    final double mass,
270                                                    final Frame teme) {
271 
272         final double a1 = FastMath.pow( TLEConstants.XKE / (tle.getMeanMotion() * 60.0), TLEConstants.TWO_THIRD);
273         final double cosi0 = FastMath.cos(tle.getI());
274         final double temp = TLEConstants.CK2 * 1.5 * (3 * cosi0 * cosi0 - 1.0) *
275                             FastMath.pow(1.0 - tle.getE() * tle.getE(), -1.5);
276         final double delta1 = temp / (a1 * a1);
277         final double a0 = a1 * (1.0 - delta1 * (TLEConstants.ONE_THIRD + delta1 * (delta1 * 134.0 / 81.0 + 1.0)));
278         final double delta0 = temp / (a0 * a0);
279 
280         // recover original mean motion :
281         final double xn0dp = tle.getMeanMotion() * 60.0 / (delta0 + 1.0);
282 
283         // Period >= 225 minutes is deep space
284         if (MathUtils.TWO_PI / (xn0dp * TLEConstants.MINUTES_PER_DAY) >= (1.0 / 6.4)) {
285             return new DeepSDP4(tle, attitudeProvider, mass, teme);
286         } else {
287             return new SGP4(tle, attitudeProvider, mass, teme);
288         }
289     }
290 
291     /** Get the Earth gravity coefficient used for TLE propagation.
292      * @return the Earth gravity coefficient.
293      */
294     public static double getMU() {
295         return TLEConstants.MU;
296     }
297 
298     /** Get the extrapolated position and velocity from an initial TLE.
299      * @param date the final date
300      * @return the final PVCoordinates
301      */
302     public PVCoordinates getPVCoordinates(final AbsoluteDate date) {
303 
304         sxpPropagate(date.durationFrom(tle.getDate()) / 60.0);
305 
306         // Compute PV with previous calculated parameters
307         return computePVCoordinates();
308     }
309 
310     /** Computation of the first commons parameters.
311      */
312     private void initializeCommons() {
313 
314         // Sine and cosine of inclination
315         final SinCos scI0 = FastMath.sinCos(tle.getI());
316 
317         final double a1 = FastMath.pow(TLEConstants.XKE / (tle.getMeanMotion() * 60.0), TLEConstants.TWO_THIRD);
318         cosi0 = scI0.cos();
319         theta2 = cosi0 * cosi0;
320         final double x3thm1 = 3.0 * theta2 - 1.0;
321         e0sq = tle.getE() * tle.getE();
322         beta02 = 1.0 - e0sq;
323         beta0 = FastMath.sqrt(beta02);
324         final double tval = TLEConstants.CK2 * 1.5 * x3thm1 / (beta0 * beta02);
325         final double delta1 = tval / (a1 * a1);
326         final double a0 = a1 * (1.0 - delta1 * (TLEConstants.ONE_THIRD + delta1 * (1.0 + 134.0 / 81.0 * delta1)));
327         final double delta0 = tval / (a0 * a0);
328 
329         // recover original mean motion and semi-major axis :
330         xn0dp = tle.getMeanMotion() * 60.0 / (delta0 + 1.0);
331         a0dp = a0 / (1.0 - delta0);
332 
333         // Values of s and qms2t :
334         s4 = TLEConstants.S;  // unmodified value for s
335         double q0ms24 = TLEConstants.QOMS2T; // unmodified value for q0ms2T
336 
337         perige = (a0dp * (1 - tle.getE()) - TLEConstants.NORMALIZED_EQUATORIAL_RADIUS) * TLEConstants.EARTH_RADIUS; // perige
338 
339         //  For perigee below 156 km, the values of s and qoms2t are changed :
340         if (perige < 156.0) {
341             if (perige <= 98.0) {
342                 s4 = 20.0;
343             } else {
344                 s4 = perige - 78.0;
345             }
346             final double temp_val = (120.0 - s4) * TLEConstants.NORMALIZED_EQUATORIAL_RADIUS / TLEConstants.EARTH_RADIUS;
347             final double temp_val_squared = temp_val * temp_val;
348             q0ms24 = temp_val_squared * temp_val_squared;
349             s4 = s4 / TLEConstants.EARTH_RADIUS + TLEConstants.NORMALIZED_EQUATORIAL_RADIUS; // new value for q0ms2T and s
350         }
351 
352         final double pinv = 1.0 / (a0dp * beta02);
353         final double pinvsq = pinv * pinv;
354         tsi = 1.0 / (a0dp - s4);
355         eta = a0dp * tle.getE() * tsi;
356         etasq = eta * eta;
357         eeta = tle.getE() * eta;
358 
359         final double psisq = FastMath.abs(1.0 - etasq); // abs because pow 3.5 needs positive value
360         final double tsi_squared = tsi * tsi;
361         coef = q0ms24 * tsi_squared * tsi_squared;
362         coef1 = coef / FastMath.pow(psisq, 3.5);
363 
364         // C2 and C1 coefficients computation :
365         c2 = coef1 * xn0dp * (a0dp * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) +
366              0.75 * TLEConstants.CK2 * tsi / psisq * x3thm1 * (8.0 + 3.0 * etasq * (8.0 + etasq)));
367         c1 = tle.getBStar() * c2;
368         sini0 = scI0.sin();
369 
370         final double x1mth2 = 1.0 - theta2;
371 
372         // C4 coefficient computation :
373         c4 = 2.0 * xn0dp * coef1 * a0dp * beta02 * (eta * (2.0 + 0.5 * etasq) +
374              tle.getE() * (0.5 + 2.0 * etasq) -
375              2 * TLEConstants.CK2 * tsi / (a0dp * psisq) *
376              (-3.0 * x3thm1 * (1.0 - 2.0 * eeta + etasq * (1.5 - 0.5 * eeta)) +
377               0.75 * x1mth2 * (2.0 * etasq - eeta * (1.0 + etasq)) * FastMath.cos(2.0 * tle.getPerigeeArgument())));
378 
379         final double theta4 = theta2 * theta2;
380         final double temp1 = 3 * TLEConstants.CK2 * pinvsq * xn0dp;
381         final double temp2 = temp1 * TLEConstants.CK2 * pinvsq;
382         final double temp3 = 1.25 * TLEConstants.CK4 * pinvsq * pinvsq * xn0dp;
383 
384         // atmospheric and gravitation coefs :(Mdf and OMEGAdf)
385         xmdot = xn0dp +
386                 0.5 * temp1 * beta0 * x3thm1 +
387                 0.0625 * temp2 * beta0 * (13.0 - 78.0 * theta2 + 137.0 * theta4);
388 
389         final double x1m5th = 1.0 - 5.0 * theta2;
390 
391         omgdot = -0.5 * temp1 * x1m5th +
392                  0.0625 * temp2 * (7.0 - 114.0 * theta2 + 395.0 * theta4) +
393                  temp3 * (3.0 - 36.0 * theta2 + 49.0 * theta4);
394 
395         final double xhdot1 = -temp1 * cosi0;
396 
397         xnodot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * theta2) + 2.0 * temp3 * (3.0 - 7.0 * theta2)) * cosi0;
398         xnodcf = 3.5 * beta02 * xhdot1 * c1;
399         t2cof = 1.5 * c1;
400 
401     }
402 
403     /** Retrieves the position and velocity.
404      * @return the computed PVCoordinates.
405      */
406     private PVCoordinates computePVCoordinates() {
407 
408         // Sine and cosine of final perigee argument
409         final SinCos scOmega = FastMath.sinCos(omega);
410 
411         // Long period periodics
412         final double axn = e * scOmega.cos();
413         double temp = 1.0 / (a * (1.0 - e * e));
414         final double xlcof = 0.125 * TLEConstants.A3OVK2 * sini0 * (3.0 + 5.0 * cosi0) / (1.0 + cosi0);
415         final double aycof = 0.25 * TLEConstants.A3OVK2 * sini0;
416         final double xll = temp * xlcof * axn;
417         final double aynl = temp * aycof;
418         final double xlt = xl + xll;
419         final double ayn = e * scOmega.sin() + aynl;
420         final double elsq = axn * axn + ayn * ayn;
421         final double capu = MathUtils.normalizeAngle(xlt - xnode, FastMath.PI);
422         double epw = capu;
423         double ecosE = 0;
424         double esinE = 0;
425         double sinEPW = 0;
426         double cosEPW = 0;
427 
428         // Dundee changes:  items dependent on cosio get recomputed:
429         final double cosi0Sq = cosi0 * cosi0;
430         final double x3thm1 = 3.0 * cosi0Sq - 1.0;
431         final double x1mth2 = 1.0 - cosi0Sq;
432         final double x7thm1 = 7.0 * cosi0Sq - 1.0;
433 
434         if (e > (1 - 1e-6)) {
435             throw new OrekitException(OrekitMessages.TOO_LARGE_ECCENTRICITY_FOR_PROPAGATION_MODEL, e);
436         }
437 
438         // Solve Kepler's' Equation.
439         final double newtonRaphsonEpsilon = 1e-12;
440         for (int j = 0; j < 10; j++) {
441 
442             boolean doSecondOrderNewtonRaphson = true;
443 
444             final SinCos scEPW = FastMath.sinCos(epw);
445             sinEPW = scEPW.sin();
446             cosEPW = scEPW.cos();
447             ecosE = axn * cosEPW + ayn * sinEPW;
448             esinE = axn * sinEPW - ayn * cosEPW;
449             final double f = capu - epw + esinE;
450             if (FastMath.abs(f) < newtonRaphsonEpsilon) {
451                 break;
452             }
453             final double fdot = 1.0 - ecosE;
454             double delta_epw = f / fdot;
455             if (j == 0) {
456                 final double maxNewtonRaphson = 1.25 * FastMath.abs(e);
457                 doSecondOrderNewtonRaphson = false;
458                 if (delta_epw > maxNewtonRaphson) {
459                     delta_epw = maxNewtonRaphson;
460                 } else if (delta_epw < -maxNewtonRaphson) {
461                     delta_epw = -maxNewtonRaphson;
462                 } else {
463                     doSecondOrderNewtonRaphson = true;
464                 }
465             }
466             if (doSecondOrderNewtonRaphson) {
467                 delta_epw = f / (fdot + 0.5 * esinE * delta_epw);
468             }
469             epw += delta_epw;
470         }
471 
472         // Short period preliminary quantities
473         temp = 1.0 - elsq;
474         final double pl = a * temp;
475         final double r = a * (1.0 - ecosE);
476         double temp2 = a / r;
477         final double betal = FastMath.sqrt(temp);
478         temp = esinE / (1.0 + betal);
479         final double cosu = temp2 * (cosEPW - axn + ayn * temp);
480         final double sinu = temp2 * (sinEPW - ayn - axn * temp);
481         final double u = FastMath.atan2(sinu, cosu);
482         final double sin2u = 2.0 * sinu * cosu;
483         final double cos2u = 2.0 * cosu * cosu - 1.0;
484         final double temp1 = TLEConstants.CK2 / pl;
485         temp2 = temp1 / pl;
486 
487         // Update for short periodics
488         final double rk = r * (1.0 - 1.5 * temp2 * betal * x3thm1) + 0.5 * temp1 * x1mth2 * cos2u;
489         final double uk = u - 0.25 * temp2 * x7thm1 * sin2u;
490         final double xnodek = xnode + 1.5 * temp2 * cosi0 * sin2u;
491         final double xinck = i + 1.5 * temp2 * cosi0 * sini0 * cos2u;
492 
493         // Orientation vectors
494         final SinCos scuk   = FastMath.sinCos(uk);
495         final SinCos scik   = FastMath.sinCos(xinck);
496         final SinCos scnok  = FastMath.sinCos(xnodek);
497         final double sinuk  = scuk.sin();
498         final double cosuk  = scuk.cos();
499         final double sinik  = scik.sin();
500         final double cosik  = scik.cos();
501         final double sinnok = scnok.sin();
502         final double cosnok = scnok.cos();
503         final double xmx = -sinnok * cosik;
504         final double xmy = cosnok * cosik;
505         final double ux  = xmx * sinuk + cosnok * cosuk;
506         final double uy  = xmy * sinuk + sinnok * cosuk;
507         final double uz  = sinik * sinuk;
508 
509         // Position and velocity
510         final double cr = 1000 * rk * TLEConstants.EARTH_RADIUS;
511         final Vector3D pos = new Vector3D(cr * ux, cr * uy, cr * uz);
512 
513         final double rdot   = TLEConstants.XKE * FastMath.sqrt(a) * esinE / r;
514         final double rfdot  = TLEConstants.XKE * FastMath.sqrt(pl) / r;
515         final double xn     = TLEConstants.XKE / (a * FastMath.sqrt(a));
516         final double rdotk  = rdot - xn * temp1 * x1mth2 * sin2u;
517         final double rfdotk = rfdot + xn * temp1 * (x1mth2 * cos2u + 1.5 * x3thm1);
518         final double vx     = xmx * cosuk - cosnok * sinuk;
519         final double vy     = xmy * cosuk - sinnok * sinuk;
520         final double vz     = sinik * cosuk;
521 
522         final double cv = 1000.0 * TLEConstants.EARTH_RADIUS / 60.0;
523         final Vector3D vel = new Vector3D(cv * (rdotk * ux + rfdotk * vx),
524                                           cv * (rdotk * uy + rfdotk * vy),
525                                           cv * (rdotk * uz + rfdotk * vz));
526 
527         return new PVCoordinates(pos, vel);
528 
529     }
530 
531     /** Initialization proper to each propagator (SGP or SDP).
532      */
533     protected abstract void sxpInitialize();
534 
535     /** Propagation proper to each propagator (SGP or SDP).
536      * @param t the offset from initial epoch (min)
537      */
538     protected abstract void sxpPropagate(double t);
539 
540     /** {@inheritDoc}
541      * <p>
542      * For TLE propagator, calling this method is only recommended
543      * for covariance propagation when the new <code>state</code>
544      * differs from the previous one by only adding the additional
545      * state containing the derivatives.
546      * </p>
547      */
548     public void resetInitialState(final SpacecraftState state) {
549         super.resetInitialState(state);
550         super.setStartDate(state.getDate());
551         final TLE newTLE = TLE.stateToTLE(state, tle, utc, teme);
552         this.tle = newTLE;
553         initializeCommons();
554         sxpInitialize();
555     }
556 
557     /** {@inheritDoc} */
558     protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
559         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
560     }
561 
562     /** {@inheritDoc} */
563     protected double getMass(final AbsoluteDate date) {
564         return mass;
565     }
566 
567     /** {@inheritDoc} */
568     protected Orbit propagateOrbit(final AbsoluteDate date) {
569         return new CartesianOrbit(getPVCoordinates(date), teme, date, TLEConstants.MU);
570     }
571 
572     /** Get the underlying TLE.
573      * @return underlying TLE
574      */
575     public TLE getTLE() {
576         return tle;
577     }
578 
579     /** {@inheritDoc} */
580     public Frame getFrame() {
581         return teme;
582     }
583 
584 }