1   /* Copyright 2002-2017 CS Systèmes d'Information
2    * Licensed to CS Systèmes d'Information (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.bodies;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.ObjectInputStream;
23  import java.io.ObjectOutputStream;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.List;
27  import java.util.concurrent.ExecutorService;
28  import java.util.concurrent.Executors;
29  import java.util.concurrent.Future;
30  import java.util.concurrent.TimeUnit;
31  import java.util.concurrent.atomic.AtomicReference;
32  
33  import org.hipparchus.geometry.euclidean.threed.Vector3D;
34  import org.junit.Assert;
35  import org.junit.Test;
36  import org.orekit.Utils;
37  import org.orekit.errors.OrekitException;
38  import org.orekit.frames.Frame;
39  import org.orekit.frames.FramesFactory;
40  import org.orekit.time.AbsoluteDate;
41  import org.orekit.time.TimeScalesFactory;
42  import org.orekit.utils.TimeStampedPVCoordinates;
43  
44  public class CelestialBodyFactoryTest {
45  
46      @Test
47      public void getSun() throws OrekitException {
48          Utils.setDataRoot("regular-data");
49  
50          CelestialBody sun = CelestialBodyFactory.getSun();
51          Assert.assertNotNull(sun);
52      }
53  
54      @Test
55      public void clearCache() throws OrekitException {
56          Utils.setDataRoot("regular-data");
57  
58          CelestialBody sun = CelestialBodyFactory.getSun();
59          Assert.assertNotNull(sun);
60          CelestialBodyFactory.clearCelestialBodyCache();
61          CelestialBody sun2 = CelestialBodyFactory.getSun();
62          Assert.assertNotNull(sun2);
63          Assert.assertNotSame(sun, sun2);
64      }
65  
66      @Test
67      public void clearLoaders() throws OrekitException {
68          Utils.setDataRoot("regular-data");
69  
70          CelestialBody sun = CelestialBodyFactory.getSun();
71          Assert.assertNotNull(sun);
72          CelestialBodyFactory.clearCelestialBodyLoaders();
73          CelestialBody sun2 = CelestialBodyFactory.getSun();
74          Assert.assertNotNull(sun2);
75          Assert.assertNotSame(sun, sun2);
76          CelestialBodyFactory.clearCelestialBodyLoaders(CelestialBodyFactory.SUN);
77          CelestialBodyFactory.clearCelestialBodyCache(CelestialBodyFactory.SUN);
78          CelestialBodyFactory.addDefaultCelestialBodyLoader(JPLEphemeridesLoader.DEFAULT_DE_SUPPORTED_NAMES);
79          CelestialBody sun3 = CelestialBodyFactory.getSun();
80          Assert.assertNotNull(sun3);
81          Assert.assertNotSame(sun,  sun3);
82          Assert.assertNotSame(sun2, sun3);
83      }
84  
85      @Test
86      public void testHorizon() throws OrekitException {
87  
88          // The following data are an excerpt from a telnet session with JPL Horizon system
89          // note that in Horizon we selected Jupiter barycenter rather than Jupiter body center
90          // this seems to match better the content of the DE-431 ephemeris
91  
92          //  *******************************************************************************
93          //  Ephemeris / PORT_LOGIN Mon Oct 26 04:53:43 2015 Pasadena, USA    / Horizons
94          //  *******************************************************************************
95          //  Target body name: Jupiter Barycenter (5)          {source: DE-0431LE-0431}
96          //  Center body name: Solar System Barycenter (0)     {source: DE-0431LE-0431}
97          //  Center-site name: BODY CENTER
98          //  *******************************************************************************
99          //  Start time      : A.D. 2000-Jan-01 00:00:00.0000 CT
100         //  Stop  time      : A.D. 2003-Dec-31 23:59:00.0000 CT
101         //  Step-size       : 1440 minutes
102         //  *******************************************************************************
103         //  Center geodetic : 0.00000000,0.00000000,0.0000000 {E-lon(deg),Lat(deg),Alt(km)}
104         //  Center cylindric: 0.00000000,0.00000000,0.0000000 {E-lon(deg),Dxy(km),Dz(km)}
105         //  Center radii    : (undefined)
106         //  Output units    : KM-S
107         //  Output format   : 02
108         //  Reference frame : ICRF/J2000.0
109         //  Output type     : GEOMETRIC cartesian states
110         //  Coordinate systm: Earth Mean Equator and Equinox of Reference Epoch
111         //  *******************************************************************************
112         //  JDCT
113         //     X     Y     Z
114         //     VX    VY    VZ
115         //  *******************************************************************************
116         //  $$SOE
117         //  2451544.500000000 = A.D. 2000-Jan-01 00:00:00.0000 (TDB)
118         //   X = 5.978411018921824E+08 Y = 4.085508359611598E+08 Z = 1.605595308103096E+08
119         //   VX=-7.892151874487445E+00 VY= 1.017751699703826E+01 VZ= 4.554715748011852E+00
120         //  2451545.500000000 = A.D. 2000-Jan-02 00:00:00.0000 (TDB)
121         //   X = 5.971584965869523E+08 Y = 4.094296790808872E+08 Z = 1.609528639632485E+08
122         //   VX=-7.908893450088906E+00 VY= 1.016606978596496E+01 VZ= 4.550216570971850E+00
123         //  2451546.500000000 = A.D. 2000-Jan-03 00:00:00.0000 (TDB)
124         //   X = 5.964744456934582E+08 Y = 4.103075321378759E+08 Z = 1.613458079269412E+08
125         //   VX=-7.925614558638352E+00 VY= 1.015459888397081E+01 VZ= 4.545706740033853E+00
126         //  2451547.500000000 = A.D. 2000-Jan-04 00:00:00.0000 (TDB)
127         //   X = 5.957889509819047E+08 Y = 4.111843930867567E+08 Z = 1.617383617815004E+08
128         //   VX=-7.942315157290042E+00 VY= 1.014310432640078E+01 VZ= 4.541186269306714E+00
129         //  2451548.500000000 = A.D. 2000-Jan-05 00:00:00.0000 (TDB)
130         //   X = 5.951020142261952E+08 Y = 4.120602598852173E+08 Z = 1.621305246082588E+08
131         //   VX=-7.958995203281466E+00 VY= 1.013158614867071E+01 VZ= 4.536655172931710E+00
132         //  2451549.500000000 = A.D. 2000-Jan-06 00:00:00.0000 (TDB)
133         //   X = 5.944136372039236E+08 Y = 4.129351304940084E+08 Z = 1.625222954897725E+08
134         //   VX=-7.975654653933506E+00 VY= 1.012004438626713E+01 VZ= 4.532113465082445E+00
135         final TimeStampedPVCoordinates[] refPV = new TimeStampedPVCoordinates[] {
136             createPV(2000, 1, 1,
137                      5.978411018921824E+08, 4.085508359611598E+08, 1.605595308103096E+08,
138                      -7.892151874487445E+00, 1.017751699703826E+01, 4.554715748011852E+00),
139             createPV(2000, 1, 2,
140                      5.971584965869523E+08, 4.094296790808872E+08, 1.609528639632485E+08,
141              -7.908893450088906E+00, 1.016606978596496E+01, 4.550216570971850E+00),
142             createPV(2000, 1, 3,
143                      5.964744456934582E+08, 4.103075321378759E+08, 1.613458079269412E+08,
144              -7.925614558638352E+00, 1.015459888397081E+01, 4.545706740033853E+00),
145             createPV(2000, 1, 4,
146                      5.957889509819047E+08, 4.111843930867567E+08, 1.617383617815004E+08,
147                      -7.942315157290042E+00, 1.014310432640078E+01, 4.541186269306714E+00),
148             createPV(2000, 1, 5,
149                      5.951020142261952E+08, 4.120602598852173E+08, 1.621305246082588E+08,
150                      -7.958995203281466E+00, 1.013158614867071E+01, 4.536655172931710E+00),
151             createPV(2000, 1, 6,
152                      5.944136372039236E+08, 4.129351304940084E+08, 1.625222954897725E+08,
153                      -7.975654653933506E+00, 1.012004438626713E+01, 4.532113465082445E+00)
154         };
155 
156         Utils.setDataRoot("regular-data");
157         final CelestialBody jupiter = CelestialBodyFactory.getJupiter();
158         for (final TimeStampedPVCoordinates ref : refPV) {
159             TimeStampedPVCoordinates testPV = jupiter.getPVCoordinates(ref.getDate(),
160                                                                        FramesFactory.getICRF());
161             Assert.assertEquals(0.0,
162                                 Vector3D.distance(ref.getPosition(), testPV.getPosition()),
163                                 4.0e-4);
164             Assert.assertEquals(0.0,
165                                 Vector3D.distance(ref.getVelocity(), testPV.getVelocity()),
166                                 1.0e-11);
167         }
168 
169    }
170 
171     private TimeStampedPVCoordinates createPV(int year, int month, int day,
172                                               double xKm, double yKm, double zKM,
173                                               double vxKmS, double vyKms, double vzKms) {
174         return new TimeStampedPVCoordinates(new AbsoluteDate(year, month, day, TimeScalesFactory.getTDB()),
175                                             new Vector3D(  xKm * 1000,   yKm * 1000,   zKM * 1000),
176                                             new Vector3D(vxKmS * 1000, vyKms * 1000, vzKms * 1000));
177     }
178 
179     @Test
180     public void testSerialization()
181             throws OrekitException, IOException, ClassNotFoundException {
182         Utils.setDataRoot("regular-data");
183         for (String name : new String[] {
184             CelestialBodyFactory.SOLAR_SYSTEM_BARYCENTER, CelestialBodyFactory.SUN, CelestialBodyFactory.MERCURY,
185             CelestialBodyFactory.VENUS, CelestialBodyFactory.EARTH_MOON, CelestialBodyFactory.EARTH,
186             CelestialBodyFactory.MOON, CelestialBodyFactory.MARS, CelestialBodyFactory.JUPITER,
187             CelestialBodyFactory.SATURN, CelestialBodyFactory.URANUS, CelestialBodyFactory.NEPTUNE, CelestialBodyFactory.PLUTO
188         }) {
189 
190             CelestialBody original = CelestialBodyFactory.getBody(name);
191 
192             ByteArrayOutputStream bosBody = new ByteArrayOutputStream();
193             ObjectOutputStream    oosBody = new ObjectOutputStream(bosBody);
194             oosBody.writeObject(original);
195             Assert.assertTrue(bosBody.size() > 400);
196             Assert.assertTrue(bosBody.size() < 460);
197 
198             ByteArrayInputStream  bisBody = new ByteArrayInputStream(bosBody.toByteArray());
199             ObjectInputStream     oisBody = new ObjectInputStream(bisBody);
200             CelestialBody deserializedBody  = (CelestialBody) oisBody.readObject();
201             Assert.assertTrue(original == deserializedBody);
202 
203             ByteArrayOutputStream bosInertialFrame = new ByteArrayOutputStream();
204             ObjectOutputStream    oosInertialFrame = new ObjectOutputStream(bosInertialFrame);
205             oosInertialFrame.writeObject(original.getInertiallyOrientedFrame());
206             Assert.assertTrue(bosInertialFrame.size() > 400);
207             Assert.assertTrue(bosInertialFrame.size() < 460);
208 
209             ByteArrayInputStream  bisInertialFrame = new ByteArrayInputStream(bosInertialFrame.toByteArray());
210             ObjectInputStream     oisInertialFrame = new ObjectInputStream(bisInertialFrame);
211             Frame deserializedInertialFrame  = (Frame) oisInertialFrame.readObject();
212             Assert.assertTrue(original.getInertiallyOrientedFrame() == deserializedInertialFrame);
213 
214             ByteArrayOutputStream bosBodyFrame = new ByteArrayOutputStream();
215             ObjectOutputStream    oosBodyFrame = new ObjectOutputStream(bosBodyFrame);
216             oosBodyFrame.writeObject(original.getBodyOrientedFrame());
217             Assert.assertTrue(bosBodyFrame.size() > 400);
218             Assert.assertTrue(bosBodyFrame.size() < 460);
219 
220             ByteArrayInputStream  bisBodyFrame = new ByteArrayInputStream(bosBodyFrame.toByteArray());
221             ObjectInputStream     oisBodyFrame = new ObjectInputStream(bisBodyFrame);
222             Frame deserializedBodyFrame  = (Frame) oisBodyFrame.readObject();
223             Assert.assertTrue(original.getBodyOrientedFrame() == deserializedBodyFrame);
224 
225         }
226     }
227 
228     @Test
229     public void multithreadTest() throws OrekitException {
230         Utils.setDataRoot("regular-data");
231         checkMultiThread(10, 100);
232     }
233 
234     private void checkMultiThread(final int threads, final int runs) throws OrekitException {
235 
236         final AtomicReference<OrekitException> caught = new AtomicReference<OrekitException>();
237         ExecutorService executorService = Executors.newFixedThreadPool(threads);
238 
239         List<Future<?>> results = new ArrayList<Future<?>>();
240         for (int i = 0; i < threads; i++) {
241             Future<?> result = executorService.submit(new Runnable() {
242                 public void run() {
243                     try {
244                         for (int run = 0; run < runs; run++) {
245                             CelestialBody mars = CelestialBodyFactory.getBody(CelestialBodyFactory.MARS);
246                             Assert.assertNotNull(mars);
247                             CelestialBodyFactory.clearCelestialBodyLoaders();
248                         }
249                     } catch (OrekitException oe) {
250                         caught.set(oe);
251                     }
252                 }
253             });
254             results.add(result);
255         }
256 
257         try {
258             executorService.shutdown();
259             executorService.awaitTermination(5, TimeUnit.SECONDS);
260         } catch (InterruptedException ie) {
261             Assert.fail(ie.getLocalizedMessage());
262         }
263 
264         for (Future<?> result : results) {
265             Assert.assertTrue("Not all threads finished -> possible deadlock", result.isDone());
266         }
267 
268         if (caught.get() != null) {
269             throw caught.get();
270         }
271     }
272 
273     @Test
274     public void testEarthMoonBarycenter() throws OrekitException {
275         Utils.setDataRoot("regular-data/de405-ephemerides");
276         CelestialBody sun = CelestialBodyFactory.getSun();
277         CelestialBody mars = CelestialBodyFactory.getMars();
278         CelestialBody earth = CelestialBodyFactory.getEarth();
279         CelestialBody earthMoonBarycenter = CelestialBodyFactory.getEarthMoonBarycenter();
280         List<Frame> frames = Arrays.asList(FramesFactory.getEME2000(),
281                                            FramesFactory.getGCRF(),
282                                            sun.getInertiallyOrientedFrame(),
283                                            mars.getInertiallyOrientedFrame(),
284                                            earth.getInertiallyOrientedFrame());
285 
286         AbsoluteDate date = new AbsoluteDate(1969, 7, 23, TimeScalesFactory.getTT());
287         final double refDistance = bodyDistance(sun, earthMoonBarycenter, date, frames.get(0));
288         for (Frame frame : frames) {
289             Assert.assertEquals(frame.toString(), refDistance,
290                                 bodyDistance(sun, earthMoonBarycenter, date, frame),
291                                 1.0e-14 * refDistance);
292         }
293     }
294 
295     private double bodyDistance(CelestialBody body1, CelestialBody body2, AbsoluteDate date, Frame frame)
296         throws OrekitException {
297         Vector3D body1Position = body1.getPVCoordinates(date, frame).getPosition();
298         Vector3D body2Position = body2.getPVCoordinates(date, frame).getPosition();
299         Vector3D bodyPositionDifference = body1Position.subtract(body2Position);
300         return bodyPositionDifference.getNorm();
301     }
302 
303 }