1   /* Copyright 2002-2025 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.attitudes;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.complex.Complex;
22  import org.hipparchus.complex.ComplexField;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Rotation;
25  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
26  import org.hipparchus.geometry.euclidean.threed.Vector3D;
27  import org.hipparchus.util.Binary64Field;
28  import org.hipparchus.util.FastMath;
29  import org.junit.jupiter.api.AfterEach;
30  import org.junit.jupiter.api.Assertions;
31  import org.junit.jupiter.api.BeforeEach;
32  import org.junit.jupiter.api.Test;
33  import org.orekit.Utils;
34  import org.orekit.bodies.GeodeticPoint;
35  import org.orekit.bodies.OneAxisEllipsoid;
36  import org.orekit.errors.OrekitException;
37  import org.orekit.frames.Frame;
38  import org.orekit.frames.FramesFactory;
39  import org.orekit.orbits.*;
40  import org.orekit.propagation.FieldSpacecraftState;
41  import org.orekit.propagation.Propagator;
42  import org.orekit.propagation.SpacecraftState;
43  import org.orekit.propagation.analytical.KeplerianPropagator;
44  import org.orekit.time.AbsoluteDate;
45  import org.orekit.time.DateComponents;
46  import org.orekit.time.FieldAbsoluteDate;
47  import org.orekit.time.TimeComponents;
48  import org.orekit.time.TimeInterpolator;
49  import org.orekit.time.TimeScalesFactory;
50  import org.orekit.utils.*;
51  
52  import java.util.ArrayList;
53  import java.util.List;
54  
55  
56  class NadirPointingTest {
57  
58      // Computation date
59      private AbsoluteDate date;
60  
61      // Body mu
62      private double mu;
63  
64      // Reference frame = ITRF
65      private Frame itrf;
66  
67      @Test
68      void testGetTargetPV() {
69          // GIVEN
70          final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
71          final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
72          final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
73          final Frame frame = FramesFactory.getGCRF();
74          final PVCoordinatesProvider provider = (date1, frame1) -> {
75              final double duration = date1.durationFrom(AbsoluteDate.FIFTIES_EPOCH);
76              final Vector3D position = new Vector3D(duration * duration / 2, 0., 0.);
77              final Vector3D velocity = new Vector3D(duration, 0., 0.);
78              final Vector3D acceleration = new Vector3D(1, 0, 0);
79              return new TimeStampedPVCoordinates(date1, position, velocity, acceleration);
80          };
81          // WHEN
82          final TimeStampedPVCoordinates actualPV = nadirAttitudeLaw.getTargetPV(provider, date, frame);
83          // THEN
84          final PVCoordinatesProvider providerWithoutAcceleration = (date12, frame12) -> {
85              final TimeStampedPVCoordinates originalPV = provider.getPVCoordinates(date12, frame12);
86              return new TimeStampedPVCoordinates(date12, originalPV.getPosition(), originalPV.getVelocity());
87          };
88          final TimeStampedPVCoordinates pv = nadirAttitudeLaw.getTargetPV(providerWithoutAcceleration, date, frame);
89          Assertions.assertEquals(pv.getDate(), actualPV.getDate());
90          final PVCoordinates relativePV = new PVCoordinates(pv, actualPV);
91          Assertions.assertEquals(0., relativePV.getPosition().getNorm(), 2e-9);
92          Assertions.assertEquals(0., relativePV.getVelocity().getNorm(), 1e-7);
93      }
94  
95      @Test
96      void testGetTargetPVViaInterpolationField() {
97          // GIVEN
98          final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
99          final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
100         final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
101         final Frame frame = FramesFactory.getGCRF();
102         final PVCoordinatesProvider provider = (dateIn, frameIn) -> new TimeStampedPVCoordinates(dateIn,
103                 new Vector3D(dateIn.durationFrom(AbsoluteDate.FIFTIES_EPOCH), 0., 0.), Vector3D.PLUS_I);
104         final ComplexField field = ComplexField.getInstance();
105         final FieldAbsoluteDate<Complex> fieldDate = new FieldAbsoluteDate<>(field, date);
106         final FieldPVCoordinatesProvider<Complex> fieldProvider = (dateIn, frameIn) -> new TimeStampedFieldPVCoordinates<>(dateIn,
107                 new FieldVector3D<>(dateIn.durationFrom(AbsoluteDate.FIFTIES_EPOCH), field.getZero(), field.getZero()),
108                 FieldVector3D.getPlusI(field), FieldVector3D.getZero(field));
109         // WHEN
110         final TimeStampedFieldPVCoordinates<Complex> actualPV = nadirAttitudeLaw.getTargetPV(fieldProvider, fieldDate, frame);
111         // THEN
112         final TimeStampedPVCoordinates pv = nadirAttitudeLaw.getTargetPV(provider, date, frame);
113         Assertions.assertEquals(pv.getDate(), actualPV.getDate().toAbsoluteDate());
114         final PVCoordinates relativePV = new PVCoordinates(pv, actualPV.toPVCoordinates());
115         final Vector3D positionDifference = relativePV.getPosition();
116         Assertions.assertEquals(0., positionDifference.getNorm(), 2e-9);
117         final Vector3D velocityDifference = relativePV.getVelocity();
118         Assertions.assertEquals(0., velocityDifference.getNorm(), 1e-6);
119     }
120 
121     @Test
122     void testGetTargetPosition() {
123         // GIVEN
124         final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
125         final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
126         final CircularOrbit circ =
127                 new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(270.),
128                         FastMath.toRadians(5.300), PositionAngleType.MEAN,
129                         FramesFactory.getEME2000(), date, mu);
130         // WHEN
131         final Vector3D actualPosition = nadirAttitudeLaw.getTargetPosition(circ, circ.getDate(), circ.getFrame());
132         // THEN
133         final Vector3D expectedPosition = nadirAttitudeLaw.getTargetPV(circ, circ.getDate(), circ.getFrame()).getPosition();
134         Assertions.assertEquals(0., expectedPosition.subtract(actualPosition).getNorm(), 1e-9);
135     }
136 
137     @Test
138     void testGetTargetPositionField() {
139         // GIVEN
140         final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
141         final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
142         final CircularOrbit circ =
143                 new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(270.),
144                         FastMath.toRadians(5.300), PositionAngleType.MEAN,
145                         FramesFactory.getEME2000(), date, mu);
146         final FieldCircularOrbit<Complex> fieldOrbit = new FieldCircularOrbit<>(ComplexField.getInstance(), circ);
147         // WHEN
148         final FieldVector3D<Complex> actualPosition = nadirAttitudeLaw.getTargetPosition(fieldOrbit, fieldOrbit.getDate(), fieldOrbit.getFrame());
149         // THEN
150         final FieldVector3D<Complex> expectedPosition = nadirAttitudeLaw.getTargetPV(fieldOrbit, fieldOrbit.getDate(), fieldOrbit.getFrame()).getPosition();
151         Assertions.assertEquals(0., expectedPosition.subtract(actualPosition).getNorm().getReal(), 1e-9);
152     }
153 
154     /** Test in the case of a spheric earth : nadir pointing shall be
155      * the same as earth center pointing
156      */
157     @Test
158     void testSphericEarth() {
159 
160         // Spheric earth shape
161         OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
162 
163         // Create nadir pointing attitude provider
164         NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
165 
166         // Create earth center pointing attitude provider
167         BodyCenterPointing earthCenterAttitudeLaw =
168                 new BodyCenterPointing(FramesFactory.getEME2000(), earthShape);
169 
170         // Create satellite position as circular parameters
171         CircularOrbit circ =
172             new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(270.),
173                                    FastMath.toRadians(5.300), PositionAngleType.MEAN,
174                                    FramesFactory.getEME2000(), date, mu);
175 
176         // Get nadir attitude
177         Rotation rotNadir = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
178 
179         // Get earth center attitude
180         Rotation rotCenter = earthCenterAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
181 
182         // For a spheric earth, earth center pointing attitude and nadir pointing attitude
183         // shall be the same, i.e the composition of inverse earth pointing rotation
184         // with nadir pointing rotation shall be identity.
185         Rotation rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
186         double angle = rotCompo.getAngle();
187         Assertions.assertEquals(angle, 0.0, Utils.epsilonAngle);
188 
189     }
190 
191     /** Test in the case of an elliptic earth : nadir pointing shall be :
192      *   - the same as earth center pointing in case of equatorial or polar position
193      *   - different from earth center pointing in any other case
194      */
195     @Test
196     void testNonSphericEarth() {
197 
198         // Elliptic earth shape
199         OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
200 
201         // Create nadir pointing attitude provider
202         NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
203 
204         // Create earth center pointing attitude provider
205         BodyCenterPointing earthCenterAttitudeLaw =
206                 new BodyCenterPointing(FramesFactory.getEME2000(), earthShape);
207 
208         //  Satellite on equatorial position
209         // **********************************
210         KeplerianOrbit kep =
211             new KeplerianOrbit(7178000.0, 1.e-8, FastMath.toRadians(50.), 0., 0.,
212                                     0., PositionAngleType.TRUE, FramesFactory.getEME2000(), date, mu);
213 
214         // Get nadir attitude
215         Rotation rotNadir = nadirAttitudeLaw.getAttitude(kep, date, kep.getFrame()).getRotation();
216 
217         checkField(Binary64Field.getInstance(), nadirAttitudeLaw, kep, kep.getDate(), kep.getFrame());
218 
219         // Get earth center attitude
220         Rotation rotCenter = earthCenterAttitudeLaw.getAttitude(kep, date, kep.getFrame()).getRotation();
221 
222         // For a satellite at equatorial position, earth center pointing attitude and nadir pointing
223         // attitude shall be the same, i.e the composition of inverse earth pointing rotation
224         // with nadir pointing rotation shall be identity.
225         Rotation rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
226         double angle = rotCompo.getAngle();
227         Assertions.assertEquals(0.0, angle, 5.e-6);
228 
229         //  Satellite on polar position
230         // *****************************
231         CircularOrbit circ =
232             new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(90.), 0.,
233                                    FastMath.toRadians(90.), PositionAngleType.TRUE,
234                                    FramesFactory.getEME2000(), date, mu);
235 
236        // Get nadir attitude
237         rotNadir = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
238 
239         // Get earth center attitude
240         rotCenter = earthCenterAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
241 
242         // For a satellite at polar position, earth center pointing attitude and nadir pointing
243         // attitude shall be the same, i.e the composition of inverse earth pointing rotation
244         // with nadir pointing rotation shall be identity.
245         rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
246         angle = rotCompo.getAngle();
247         Assertions.assertEquals(angle, 0.0, 5.e-6);
248 
249         //  Satellite on any position
250         // ***************************
251         circ =
252             new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(50.), 0.,
253                                    FastMath.toRadians(90.), PositionAngleType.TRUE,
254                                    FramesFactory.getEME2000(), date, mu);
255 
256         // Get nadir attitude
257         rotNadir = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
258 
259         // Get earth center attitude
260         rotCenter = earthCenterAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
261 
262         // For a satellite at any position, earth center pointing attitude and nadir pointing
263         // and nadir pointing attitude shall not be the same, i.e the composition of inverse earth
264         // pointing rotation with nadir pointing rotation shall be different from identity.
265         rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
266         angle = rotCompo.getAngle();
267         Assertions.assertEquals(angle, FastMath.toRadians(0.16797386586252272), Utils.epsilonAngle);
268     }
269 
270     /** Vertical test : check that Z satellite axis is collinear to local vertical axis,
271         which direction is : (cos(lon)*cos(lat), sin(lon)*cos(lat), sin(lat)),
272         where lon et lat stand for observed point coordinates
273         (i.e satellite ones, since they are the same by construction,
274         but that's what is to test.
275      */
276     @Test
277     void testVertical() {
278 
279         // Elliptic earth shape
280         OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
281 
282         // Create earth center pointing attitude provider
283         NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
284 
285         //  Satellite on any position
286         CircularOrbit circ =
287             new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(50.), 0.,
288                                    FastMath.toRadians(90.), PositionAngleType.TRUE,
289                                    FramesFactory.getEME2000(), date, mu);
290 
291         //  Vertical test
292         // ***************
293         // Get observed ground point position/velocity
294         TimeStampedPVCoordinates pvTargetItrf = nadirAttitudeLaw.getTargetPV(circ, date, itrf);
295 
296         // Convert to geodetic coordinates
297         GeodeticPoint geoTarget = earthShape.transform(pvTargetItrf.getPosition(), itrf, date);
298 
299         // Compute local vertical axis
300         double xVert = FastMath.cos(geoTarget.getLongitude())*FastMath.cos(geoTarget.getLatitude());
301         double yVert = FastMath.sin(geoTarget.getLongitude())*FastMath.cos(geoTarget.getLatitude());
302         double zVert = FastMath.sin(geoTarget.getLatitude());
303         Vector3D targetVertical = new Vector3D(xVert, yVert, zVert);
304 
305         // Get attitude rotation state
306         Rotation rotSatEME2000 = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
307 
308         // Get satellite Z axis in EME2000 frame
309         Vector3D zSatEME2000 = rotSatEME2000.applyInverseTo(Vector3D.PLUS_K);
310         Vector3D zSatItrf = FramesFactory.getEME2000().getStaticTransformTo(itrf, date).transformVector(zSatEME2000);
311 
312         // Check that satellite Z axis is collinear to local vertical axis
313         double angle= Vector3D.angle(zSatItrf, targetVertical);
314         Assertions.assertEquals(0.0, FastMath.sin(angle), Utils.epsilonTest);
315 
316     }
317 
318     /** Test the derivatives of the sliding target
319      */
320     @Test
321     void testSlidingDerivatives() {
322 
323         // Elliptic earth shape
324         OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
325 
326         // Create earth center pointing attitude provider
327         NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
328 
329         //  Satellite on any position
330         CircularOrbit circ =
331             new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(50.), 0.,
332                                    FastMath.toRadians(90.), PositionAngleType.TRUE,
333                                    FramesFactory.getEME2000(), date, mu);
334 
335         List<TimeStampedPVCoordinates> sample = new ArrayList<>();
336         for (double dt = -0.1; dt < 0.1; dt += 0.05) {
337             Orbit o = circ.shiftedBy(dt);
338             sample.add(nadirAttitudeLaw.getTargetPV(o, o.getDate(), o.getFrame()));
339         }
340 
341         // create interpolator
342         final TimeInterpolator<TimeStampedPVCoordinates> interpolator =
343                 new TimeStampedPVCoordinatesHermiteInterpolator(sample.size(), CartesianDerivativesFilter.USE_P);
344 
345         TimeStampedPVCoordinates reference = interpolator.interpolate(circ.getDate(), sample);
346 
347         TimeStampedPVCoordinates target =
348                 nadirAttitudeLaw.getTargetPV(circ, circ.getDate(), circ.getFrame());
349 
350         Assertions.assertEquals(0.0,
351                             Vector3D.distance(reference.getPosition(),     target.getPosition()),
352                             1.0e-15 * reference.getPosition().getNorm());
353         Assertions.assertEquals(0.0,
354                             Vector3D.distance(reference.getVelocity(),     target.getVelocity()),
355                             3.0e-11 * reference.getVelocity().getNorm());
356         Assertions.assertEquals(0.0,
357                             Vector3D.distance(reference.getAcceleration(), target.getAcceleration()),
358                             1.3e-5 * reference.getAcceleration().getNorm());
359 
360     }
361 
362     @Test
363     void testSpin() {
364 
365         // Elliptic earth shape
366         OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
367 
368         // Create earth center pointing attitude provider
369         NadirPointing law = new NadirPointing(FramesFactory.getEME2000(), earthShape);
370 
371         //  Satellite on any position
372         KeplerianOrbit orbit =
373             new KeplerianOrbit(7178000.0, 1.e-4, FastMath.toRadians(50.),
374                               FastMath.toRadians(10.), FastMath.toRadians(20.),
375                               FastMath.toRadians(30.), PositionAngleType.MEAN,
376                               FramesFactory.getEME2000(), date, mu);
377 
378         Propagator propagator = new KeplerianPropagator(orbit, law, mu, 2500.0);
379 
380         double h = 0.1;
381         SpacecraftState sMinus = propagator.propagate(date.shiftedBy(-h));
382         SpacecraftState s0     = propagator.propagate(date);
383         SpacecraftState sPlus  = propagator.propagate(date.shiftedBy(h));
384 
385         // check spin is consistent with attitude evolution
386         double errorAngleMinus     = Rotation.distance(sMinus.shiftedBy(h).getAttitude().getRotation(),
387                                                        s0.getAttitude().getRotation());
388         double evolutionAngleMinus = Rotation.distance(sMinus.getAttitude().getRotation(),
389                                                        s0.getAttitude().getRotation());
390         Assertions.assertEquals(0.0, errorAngleMinus, 5.3e-9 * evolutionAngleMinus);
391         double errorAnglePlus      = Rotation.distance(s0.getAttitude().getRotation(),
392                                                        sPlus.shiftedBy(-h).getAttitude().getRotation());
393         double evolutionAnglePlus  = Rotation.distance(s0.getAttitude().getRotation(),
394                                                        sPlus.getAttitude().getRotation());
395         Assertions.assertEquals(0.0, errorAnglePlus, 8.1e-9 * evolutionAnglePlus);
396 
397         Vector3D spin0 = s0.getAttitude().getSpin();
398         Rotation rM = sMinus.getAttitude().getRotation();
399         Rotation rP = sPlus.getAttitude().getRotation();
400         Vector3D reference = AngularCoordinates.estimateRate(rM, rP, 2 * h);
401         Assertions.assertTrue(Rotation.distance(rM, rP) > 2.0e-4);
402         Assertions.assertEquals(0.0, spin0.subtract(reference).getNorm(), 2.0e-6);
403 
404     }
405 
406     private <T extends CalculusFieldElement<T>> void checkField(final Field<T> field, final GroundPointing provider,
407                                                             final Orbit orbit, final AbsoluteDate date,
408                                                             final Frame frame)
409         {
410 
411         final Attitude attitudeD = provider.getAttitude(orbit, date, frame);
412         final FieldOrbit<T> orbitF = new FieldSpacecraftState<>(field, new SpacecraftState(orbit)).getOrbit();
413         final FieldAbsoluteDate<T> dateF = new FieldAbsoluteDate<>(field, date);
414         final FieldAttitude<T> attitudeF = provider.getAttitude(orbitF, dateF, frame);
415         Assertions.assertEquals(0.0, Rotation.distance(attitudeD.getRotation(), attitudeF.getRotation().toRotation()), 1.0e-15);
416         Assertions.assertEquals(0.0, Vector3D.distance(attitudeD.getSpin(), attitudeF.getSpin().toVector3D()), 2.0e-14);
417         Assertions.assertEquals(0.0, Vector3D.distance(attitudeD.getRotationAcceleration(), attitudeF.getRotationAcceleration().toVector3D()), 4.0e-12);
418 
419         final TimeStampedPVCoordinates         pvD = provider.getTargetPV(orbit, date, frame);
420         final TimeStampedFieldPVCoordinates<T> pvF = provider.getTargetPV(orbitF, dateF, frame);
421         Assertions.assertEquals(0.0, Vector3D.distance(pvD.getPosition(),     pvF.getPosition().toVector3D()),     1.0e-15);
422         Assertions.assertEquals(0.0, Vector3D.distance(pvD.getVelocity(),     pvF.getVelocity().toVector3D()),     2.0e-8);
423         Assertions.assertEquals(0.0, Vector3D.distance(pvD.getAcceleration(), pvF.getAcceleration().toVector3D()), 3.0e-5);
424 
425     }
426 
427     @BeforeEach
428     public void setUp() {
429         try {
430 
431             Utils.setDataRoot("regular-data");
432 
433             // Computation date
434             date = new AbsoluteDate(new DateComponents(2008, 4, 7),
435                                     TimeComponents.H00,
436                                     TimeScalesFactory.getUTC());
437 
438             // Body mu
439             mu = 3.9860047e14;
440 
441             // Reference frame = ITRF
442             itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
443 
444         } catch (OrekitException oe) {
445             Assertions.fail(oe.getMessage());
446         }
447 
448     }
449 
450     @AfterEach
451     public void tearDown() {
452         date = null;
453         itrf = null;
454     }
455 
456 }
457