1   /* Copyright 2002-2022 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.models.earth.atmosphere.data;
18  
19  import static org.hamcrest.MatcherAssert.assertThat;
20  import static org.orekit.OrekitMatchers.closeTo;
21  import static org.orekit.OrekitMatchers.pvCloseTo;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.ByteArrayOutputStream;
25  import java.io.IOException;
26  import java.io.ObjectInputStream;
27  import java.io.ObjectOutputStream;
28  
29  import org.hipparchus.ode.ODEIntegrator;
30  import org.hipparchus.ode.nonstiff.ClassicalRungeKuttaIntegrator;
31  import org.hipparchus.util.FastMath;
32  import org.junit.After;
33  import org.junit.Assert;
34  import org.junit.Before;
35  import org.junit.Test;
36  import org.orekit.Utils;
37  import org.orekit.bodies.CelestialBody;
38  import org.orekit.bodies.CelestialBodyFactory;
39  import org.orekit.bodies.OneAxisEllipsoid;
40  import org.orekit.data.DataContext;
41  import org.orekit.data.DataProvidersManager;
42  import org.orekit.errors.OrekitException;
43  import org.orekit.forces.drag.DragForce;
44  import org.orekit.forces.drag.IsotropicDrag;
45  import org.orekit.frames.Frame;
46  import org.orekit.frames.FramesFactory;
47  import org.orekit.models.earth.atmosphere.Atmosphere;
48  import org.orekit.models.earth.atmosphere.DTM2000;
49  import org.orekit.models.earth.atmosphere.DTM2000InputParameters;
50  import org.orekit.models.earth.atmosphere.NRLMSISE00;
51  import org.orekit.models.earth.atmosphere.NRLMSISE00InputParameters;
52  import org.orekit.models.earth.atmosphere.data.MarshallSolarActivityFutureEstimation.StrengthLevel;
53  import org.orekit.orbits.KeplerianOrbit;
54  import org.orekit.orbits.Orbit;
55  import org.orekit.orbits.OrbitType;
56  import org.orekit.orbits.PositionAngle;
57  import org.orekit.propagation.SpacecraftState;
58  import org.orekit.propagation.numerical.NumericalPropagator;
59  import org.orekit.propagation.sampling.OrekitStepHandler;
60  import org.orekit.time.AbsoluteDate;
61  import org.orekit.time.DateComponents;
62  import org.orekit.time.Month;
63  import org.orekit.time.TimeScale;
64  import org.orekit.time.TimeScalesFactory;
65  import org.orekit.utils.Constants;
66  import org.orekit.utils.IERSConventions;
67  
68  public class MarshallSolarActivityFutureEstimationTest {
69  
70      /**
71       * Check {@link MarshallSolarActivityFutureEstimation#get24HoursKp(AbsoluteDate)} and
72       * {@link MarshallSolarActivityFutureEstimation#getThreeHourlyKP(AbsoluteDate)} are
73       * continuous.
74       */
75      @Test
76      public void testGetKp() {
77          //setup
78          DTM2000InputParameters flux = getFlux();
79          final AbsoluteDate july = new AbsoluteDate(2008, 7, 1, utc);
80          final AbsoluteDate august = new AbsoluteDate(2008, 8, 1, utc);
81          final AbsoluteDate middle = july.shiftedBy(august.durationFrom(july) / 2.0);
82          final double minute = 60;
83          final AbsoluteDate before = middle.shiftedBy(-minute);
84          final AbsoluteDate after = middle.shiftedBy(+minute);
85  
86          // action + verify
87          // non-chaotic i.e. small change in input produces small change in output.
88          double kpHourlyDifference =
89                  flux.getThreeHourlyKP(before) - flux.getThreeHourlyKP(after);
90          assertThat(kpHourlyDifference, closeTo(0.0, 1e-4));
91          double kpDailyDifference = flux.get24HoursKp(before) - flux.get24HoursKp(after);
92          assertThat(kpDailyDifference, closeTo(0.0, 1e-4));
93          assertThat(flux.getThreeHourlyKP(middle), closeTo(2.18, 0.3));
94          assertThat(flux.get24HoursKp(middle), closeTo(2.18, 0.3));
95      }
96  
97      /**
98       * Check {@link MarshallSolarActivityFutureEstimation#getAp(AbsoluteDate)} is
99       * continuous.
100      */
101     @Test
102     public void testGetAp() {
103         //setup
104         NRLMSISE00InputParameters flux = getFlux();
105         final AbsoluteDate july = new AbsoluteDate(2008, 7, 1, utc);
106         final AbsoluteDate august = new AbsoluteDate(2008, 8, 1, utc);
107         final AbsoluteDate middle = july.shiftedBy(august.durationFrom(july) / 2.0);
108         final double minute = 60;
109         final AbsoluteDate before = middle.shiftedBy(-minute);
110         final AbsoluteDate after = middle.shiftedBy(+minute);
111 
112         // action + verify
113         // non-chaotic i.e. small change in input produces small change in output.
114         final double[] apBefore = flux.getAp(before);
115         final double[] apAfter  = flux.getAp(after);
116         for (int i = 0; i < apBefore.length; i++) {
117             assertThat(apBefore[i] - apAfter[i], closeTo(0.0, 1e-4));
118         }
119         for (double ap: flux.getAp(middle)) {
120             assertThat(ap, closeTo(8.0, 1e-10));
121         }
122     }
123 
124     /**
125      * Check integration error is small when integrating the same equations over the same
126      * interval.
127      */
128     @Test
129     public void testWithPropagator() {
130         CelestialBody sun = CelestialBodyFactory.getSun();
131         final Frame eci = FramesFactory.getGCRF();
132         final Frame ecef = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
133         AbsoluteDate date = new AbsoluteDate(2004, 1, 1, utc);
134         OneAxisEllipsoid earth = new OneAxisEllipsoid(
135                 Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
136                 Constants.WGS84_EARTH_FLATTENING,
137                 ecef);
138         Orbit orbit = new KeplerianOrbit(
139                 6378137 + 400e3, 1e-3, FastMath.toRadians(50), 0, 0, 0,
140                 PositionAngle.TRUE, eci, date, Constants.EIGEN5C_EARTH_MU);
141         final SpacecraftState ic = new SpacecraftState(orbit);
142 
143         final AbsoluteDate end = date.shiftedBy(5 * Constants.JULIAN_DAY);
144         final AbsoluteDate resetDate = date.shiftedBy(0.8 * Constants.JULIAN_DAY + 0.1);
145 
146         final SpacecraftState[] lastState = new SpacecraftState[1];
147         final OrekitStepHandler stepSaver = interpolator -> {
148             final AbsoluteDate start = interpolator.getPreviousState().getDate();
149             if (start.compareTo(resetDate) < 0) {
150                 lastState[0] = interpolator.getPreviousState();
151             }
152         };
153 
154         // propagate with state rest to take slightly different path
155         NumericalPropagator propagator = getNumericalPropagatorWithDTM(sun, earth, ic);
156         propagator.setStepHandler(stepSaver);
157         propagator.propagate(resetDate);
158         propagator.resetInitialState(lastState[0]);
159         propagator.clearStepHandlers();
160         SpacecraftState actual = propagator.propagate(end);
161 
162         // propagate straight through
163         propagator = getNumericalPropagatorWithDTM(sun, earth, ic);
164         propagator.resetInitialState(ic);
165         propagator.clearStepHandlers();
166         SpacecraftState expected = propagator.propagate(end);
167 
168         assertThat(actual.getPVCoordinates(), pvCloseTo(expected.getPVCoordinates(), 1.0));
169 
170         // propagate with state rest to take slightly different path
171         propagator = getNumericalPropagatorWithMSIS(sun, earth, ic);
172         propagator.setStepHandler(stepSaver);
173         propagator.propagate(resetDate);
174         propagator.resetInitialState(lastState[0]);
175         propagator.clearStepHandlers();
176         actual = propagator.propagate(end);
177 
178         // propagate straight through
179         propagator = getNumericalPropagatorWithMSIS(sun, earth, ic);
180         propagator.resetInitialState(ic);
181         propagator.clearStepHandlers();
182         expected = propagator.propagate(end);
183 
184         assertThat(actual.getPVCoordinates(), pvCloseTo(expected.getPVCoordinates(), 1.0));
185     }
186 
187     /**
188      * Configure a numerical propagator with DTM2000 atmosphere.
189      *
190      * @param sun   Sun.
191      * @param earth Earth.
192      * @param ic    initial condition.
193      * @return a propagator with DTM2000 atmosphere.
194      */
195     private NumericalPropagator getNumericalPropagatorWithDTM(CelestialBody sun,
196                                                               OneAxisEllipsoid earth,
197                                                               SpacecraftState ic)
198     {
199         // some non-integer step size to induce truncation error in flux interpolation
200         final ODEIntegrator integrator = new ClassicalRungeKuttaIntegrator(120 + 0.1);
201         NumericalPropagator propagator = new NumericalPropagator(integrator);
202         DTM2000InputParameters flux = getFlux();
203         final Atmosphere atmosphere = new DTM2000(flux, sun, earth);
204         final IsotropicDrag satellite = new IsotropicDrag(1, 3.2);
205         propagator.addForceModel(new DragForce(atmosphere, satellite));
206 
207         propagator.setInitialState(ic);
208         propagator.setOrbitType(OrbitType.CARTESIAN);
209 
210         return propagator;
211     }
212 
213     /**
214      * Configure a numerical propagator with NRLMSISE00 atmosphere.
215      *
216      * @param sun   Sun.
217      * @param earth Earth.
218      * @param ic    initial condition.
219      * @return a propagator with NRLMSISE00 atmosphere.
220      */
221     private NumericalPropagator getNumericalPropagatorWithMSIS(CelestialBody sun,
222                                                                OneAxisEllipsoid earth,
223                                                                SpacecraftState ic)
224     {
225         // some non-integer step size to induce truncation error in flux interpolation
226         final ODEIntegrator integrator = new ClassicalRungeKuttaIntegrator(120 + 0.1);
227         NumericalPropagator propagator = new NumericalPropagator(integrator);
228         NRLMSISE00InputParameters flux = getFlux();
229         final Atmosphere atmosphere = new NRLMSISE00(flux, sun, earth);
230         final IsotropicDrag satellite = new IsotropicDrag(1, 3.2);
231         propagator.addForceModel(new DragForce(atmosphere, satellite));
232 
233         propagator.setInitialState(ic);
234         propagator.setOrbitType(OrbitType.CARTESIAN);
235 
236         return propagator;
237     }
238 
239     /**
240      * Load an edited flux file.
241      *
242      * @return loaded flux file.
243      */
244     private MarshallSolarActivityFutureEstimation getFlux() {
245         MarshallSolarActivityFutureEstimation flux =
246                 new MarshallSolarActivityFutureEstimation(
247                         "Jan2000F10-edited-data.txt$",
248                         StrengthLevel.AVERAGE);
249         DataContext.getDefault().getDataProvidersManager().feed(flux.getSupportedNames(), flux);
250         return flux;
251     }
252 
253     @Test
254     public void testFileDate() {
255 
256         MarshallSolarActivityFutureEstimation msafe =
257             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.AVERAGE);
258         Assert.assertEquals(new DateComponents(2010, Month.NOVEMBER, 1),
259                             msafe.getFileDate(new AbsoluteDate("2010-05-01", utc)));
260         Assert.assertEquals(new DateComponents(2010, Month.DECEMBER, 1),
261                             msafe.getFileDate(new AbsoluteDate("2010-06-01", utc)));
262         Assert.assertEquals(new DateComponents(2011, Month.JANUARY, 1),
263                             msafe.getFileDate(new AbsoluteDate("2010-07-01", utc)));
264         Assert.assertEquals(new DateComponents(2011, Month.JANUARY, 1),
265                             msafe.getFileDate(new AbsoluteDate("2030-01-01", utc)));
266 
267     }
268 
269     @Test
270     public void testFluxStrong() {
271 
272         MarshallSolarActivityFutureEstimation msafe =
273             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.STRONG);
274         Assert.assertEquals(94.2,
275                             msafe.getMeanFlux(new AbsoluteDate("2010-10-01", utc)),
276                             1.0e-10);
277         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-10-01", utc)),
278                             msafe.getDailyFlux(new AbsoluteDate("2010-10-02", utc)),
279                             1.0e-10);
280         Assert.assertEquals(96.6,
281                             msafe.getMeanFlux(new AbsoluteDate("2010-10-16T12:00:00", utc)),
282                             1.0e-10);
283         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-10-16T12:00:00", utc)),
284                             msafe.getDailyFlux(new AbsoluteDate("2010-10-17T12:00:00", utc)),
285                             1.0e-10);
286         Assert.assertEquals(99.0,
287                             msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
288                             1.0e-10);
289         Assert.assertEquals(msafe.getInstantFlux(new AbsoluteDate("2010-11-01", utc)),
290                             msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
291                             1.0e-10);
292         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
293                             msafe.getDailyFlux(new AbsoluteDate("2010-11-02", utc)),
294                             1.0e-10);
295         Assert.assertEquals(msafe.getInstantFlux(new AbsoluteDate("2010-11-01", utc)),
296                             msafe.getDailyFlux(new AbsoluteDate("2010-11-02", utc)),
297                             1.0e-10);
298         Assert.assertEquals(MarshallSolarActivityFutureEstimation.StrengthLevel.STRONG,
299                             msafe.getStrengthLevel());
300     }
301 
302 
303     @Test
304     public void testFluxAverage() {
305 
306         MarshallSolarActivityFutureEstimation msafe =
307             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.AVERAGE);
308         Assert.assertEquals(87.6,
309                             msafe.getMeanFlux(new AbsoluteDate("2010-10-01", utc)),
310                             1.0e-10);
311         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-10-01", utc)),
312                             msafe.getDailyFlux(new AbsoluteDate("2010-10-02", utc)),
313                             1.0e-10);
314         Assert.assertEquals(88.7,
315                             msafe.getMeanFlux(new AbsoluteDate("2010-10-16T12:00:00", utc)),
316                             1.0e-10);
317         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-10-16T12:00:00", utc)),
318                             msafe.getDailyFlux(new AbsoluteDate("2010-10-17T12:00:00", utc)),
319                             1.0e-10);
320         Assert.assertEquals(89.8,
321                             msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
322                             1.0e-10);
323         Assert.assertEquals(msafe.getInstantFlux(new AbsoluteDate("2010-11-01", utc)),
324                             msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
325                             1.0e-10);
326         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
327                             msafe.getDailyFlux(new AbsoluteDate("2010-11-02", utc)),
328                             1.0e-10);
329         Assert.assertEquals(msafe.getInstantFlux(new AbsoluteDate("2010-11-01", utc)),
330                             msafe.getDailyFlux(new AbsoluteDate("2010-11-02", utc)),
331                             1.0e-10);
332         Assert.assertEquals(MarshallSolarActivityFutureEstimation.StrengthLevel.AVERAGE,
333                             msafe.getStrengthLevel());
334     }
335 
336 
337     @Test
338     public void testFluxWeak() {
339 
340         MarshallSolarActivityFutureEstimation msafe =
341             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK);
342         Assert.assertEquals(80.4,
343                             msafe.getMeanFlux(new AbsoluteDate("2010-10-01", utc)),
344                             1.0e-10);
345         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-10-01", utc)),
346                             msafe.getDailyFlux(new AbsoluteDate("2010-10-02", utc)),
347                             1.0e-10);
348         Assert.assertEquals(80.6,
349                             msafe.getMeanFlux(new AbsoluteDate("2010-10-16T12:00:00", utc)),
350                             1.0e-10);
351         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-10-16T12:00:00", utc)),
352                             msafe.getDailyFlux(new AbsoluteDate("2010-10-17T12:00:00", utc)),
353                             1.0e-10);
354         Assert.assertEquals(80.8,
355                             msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
356                             1.0e-10);
357         Assert.assertEquals(msafe.getInstantFlux(new AbsoluteDate("2010-11-01", utc)),
358                             msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
359                             1.0e-10);
360         Assert.assertEquals(msafe.getMeanFlux(new AbsoluteDate("2010-11-01", utc)),
361                             msafe.getDailyFlux(new AbsoluteDate("2010-11-02", utc)),
362                             1.0e-10);
363         Assert.assertEquals(msafe.getInstantFlux(new AbsoluteDate("2010-11-01", utc)),
364                             msafe.getDailyFlux(new AbsoluteDate("2010-11-02", utc)),
365                             1.0e-10);
366         Assert.assertEquals(MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK,
367                             msafe.getStrengthLevel());
368 
369     }
370 
371     private MarshallSolarActivityFutureEstimation loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel strength)
372         {
373 
374         MarshallSolarActivityFutureEstimation msafe =
375             new MarshallSolarActivityFutureEstimation(MarshallSolarActivityFutureEstimation.DEFAULT_SUPPORTED_NAMES, strength);
376         DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
377         manager.feed(msafe.getSupportedNames(), msafe);
378         return msafe;
379     }
380 
381     @Test
382     public void testKpStrong() {
383 
384         MarshallSolarActivityFutureEstimation msafe =
385             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.STRONG);
386         Assert.assertEquals(2 + 1.0 / 3.0,
387                             msafe.get24HoursKp(new AbsoluteDate("2010-10-01", utc)),
388                             0.2);
389         Assert.assertEquals(3.0,
390                             msafe.get24HoursKp(new AbsoluteDate("2011-05-01", utc)),
391                             0.1);
392 
393         // this one should get exactly to an element of the AP_ARRAY: ap = 7.0
394         Assert.assertEquals(2.0,
395                             msafe.get24HoursKp(new AbsoluteDate("2010-08-01", utc)),
396                             0.3);
397         Assert.assertEquals(msafe.getThreeHourlyKP(new AbsoluteDate("2010-08-01", utc)),
398                             msafe.get24HoursKp(new AbsoluteDate("2010-08-01", utc)),
399                             1.0e-14);
400 
401     }
402 
403     @Test
404     public void testKpAverage() {
405 
406         MarshallSolarActivityFutureEstimation msafe =
407             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.AVERAGE);
408         Assert.assertEquals(2 - 1.0 / 3.0,
409                             msafe.get24HoursKp(new AbsoluteDate("2010-10-01", utc)),
410                             0.1);
411         Assert.assertEquals(2 + 1.0 / 3.0,
412                             msafe.get24HoursKp(new AbsoluteDate("2011-05-01", utc)),
413                             0.1);
414         Assert.assertEquals(2.0 - 1.0 / 3.0,
415                             msafe.get24HoursKp(new AbsoluteDate("2010-08-01", utc)),
416                             0.1);
417         Assert.assertEquals(msafe.getThreeHourlyKP(new AbsoluteDate("2010-08-01", utc)),
418                             msafe.get24HoursKp(new AbsoluteDate("2010-08-01", utc)),
419                             1.0e-14);
420 
421     }
422 
423     @Test
424     public void testKpWeak() {
425 
426         MarshallSolarActivityFutureEstimation msafe =
427             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK);
428         Assert.assertEquals(1 + 1.0 / 3.0,
429                             msafe.get24HoursKp(new AbsoluteDate("2010-10-01", utc)),
430                             0.1);
431         Assert.assertEquals(2.0,
432                             msafe.get24HoursKp(new AbsoluteDate("2011-05-01", utc)),
433                             0.3);
434         Assert.assertEquals(1 + 1.0 / 3.0,
435                             msafe.get24HoursKp(new AbsoluteDate("2010-08-01", utc)),
436                             0.1);
437         Assert.assertEquals(msafe.getThreeHourlyKP(new AbsoluteDate("2010-08-01", utc)),
438                             msafe.get24HoursKp(new AbsoluteDate("2010-08-01", utc)),
439                             1.0e-14);
440 
441     }
442 
443     @Test
444     public void testApStrong() {
445 
446         MarshallSolarActivityFutureEstimation msafe =
447             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.STRONG);
448         for (double ap: msafe.getAp(new AbsoluteDate("2010-10-01", utc))) {
449             Assert.assertEquals(9.1, ap, 1e-10);
450         }
451         for (double ap: msafe.getAp(new AbsoluteDate("2011-05-01", utc))) {
452             Assert.assertEquals(14.4, ap, 1e-10);
453         }
454         for (double ap: msafe.getAp(new AbsoluteDate("2010-08-01", utc))) {
455             Assert.assertEquals(7.0, ap, 1e-10);
456         }
457     }
458 
459     @Test
460     public void testApAverage() {
461 
462         MarshallSolarActivityFutureEstimation msafe =
463             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.AVERAGE);
464         for (double ap: msafe.getAp(new AbsoluteDate("2010-10-01", utc))) {
465             Assert.assertEquals(6.4, ap, 1e-10);
466         }
467         for (double ap: msafe.getAp(new AbsoluteDate("2011-05-01", utc))) {
468             Assert.assertEquals(9.6, ap, 1e-10);
469         }
470         for (double ap: msafe.getAp(new AbsoluteDate("2010-08-01", utc))) {
471             Assert.assertEquals(6.1, ap, 1e-10);
472         }
473     }
474 
475     @Test
476     public void testApWeak() {
477 
478         MarshallSolarActivityFutureEstimation msafe =
479             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK);
480         for (double ap: msafe.getAp(new AbsoluteDate("2010-10-01", utc))) {
481             Assert.assertEquals(4.9, ap, 1e-10);
482         }
483         for (double ap: msafe.getAp(new AbsoluteDate("2011-05-01", utc))) {
484             Assert.assertEquals(6.9, ap, 1e-10);
485         }
486         for (double ap: msafe.getAp(new AbsoluteDate("2010-08-01", utc))) {
487             Assert.assertEquals(4.9, ap, 1e-10);
488         }
489     }
490 
491     @Test
492     public void testMinDate() {
493 
494         MarshallSolarActivityFutureEstimation msafe =
495             new MarshallSolarActivityFutureEstimation(MarshallSolarActivityFutureEstimation.DEFAULT_SUPPORTED_NAMES,
496                                                       MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK);
497         Assert.assertEquals(new AbsoluteDate("2010-05-01", utc), msafe.getMinDate());
498         Assert.assertEquals(78.1,
499                             msafe.getMeanFlux(msafe.getMinDate()),
500                             1.0e-14);
501     }
502 
503     @Test
504     public void testMaxDate() {
505 
506         MarshallSolarActivityFutureEstimation msafe =
507             new MarshallSolarActivityFutureEstimation(MarshallSolarActivityFutureEstimation.DEFAULT_SUPPORTED_NAMES,
508                                                       MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK);
509         Assert.assertEquals(new AbsoluteDate("2030-10-01", utc), msafe.getMaxDate());
510         Assert.assertEquals(67.0,
511                             msafe.getMeanFlux(msafe.getMaxDate()),
512                             1.0e-14);
513     }
514 
515     @Test(expected=OrekitException.class)
516     public void testPastOutOfRange() {
517         MarshallSolarActivityFutureEstimation msafe =
518             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK);
519         msafe.get24HoursKp(new AbsoluteDate("1960-10-01", utc));
520     }
521 
522     @Test(expected=OrekitException.class)
523     public void testFutureOutOfRange() {
524         MarshallSolarActivityFutureEstimation msafe =
525             loadMsafe(MarshallSolarActivityFutureEstimation.StrengthLevel.WEAK);
526         msafe.get24HoursKp(new AbsoluteDate("2060-10-01", utc));
527     }
528 
529     @Test(expected=OrekitException.class)
530     public void testExtraData() {
531         MarshallSolarActivityFutureEstimation msafe =
532             new MarshallSolarActivityFutureEstimation("Jan2011F10-extra-data\\.txt",
533                                                       MarshallSolarActivityFutureEstimation.StrengthLevel.STRONG);
534         DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
535         manager.feed(msafe.getSupportedNames(), msafe);
536     }
537 
538     @Test(expected=OrekitException.class)
539     public void testNoData() {
540         MarshallSolarActivityFutureEstimation msafe =
541             new MarshallSolarActivityFutureEstimation("Jan2011F10-no-data\\.txt",
542                                                       MarshallSolarActivityFutureEstimation.StrengthLevel.STRONG);
543         DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
544         manager.feed(msafe.getSupportedNames(), msafe);
545     }
546 
547     @Test
548     public void testSerialization() throws IOException, ClassNotFoundException {
549         MarshallSolarActivityFutureEstimation original =
550                         new MarshallSolarActivityFutureEstimation("Jan2000F10-edited-data.txt$",
551                                                                   StrengthLevel.AVERAGE);
552 
553         DataProvidersManager managerOriginal = DataContext.getDefault().getDataProvidersManager();
554         managerOriginal.feed(original.getSupportedNames(), original);
555 
556         ByteArrayOutputStream bos = new ByteArrayOutputStream();
557         ObjectOutputStream    oos = new ObjectOutputStream(bos);
558         oos.writeObject(original);
559 
560         Assert.assertTrue(bos.size() > 400);
561         Assert.assertTrue(bos.size() < 450);
562 
563         ByteArrayInputStream  bis = new ByteArrayInputStream(bos.toByteArray());
564         ObjectInputStream     ois = new ObjectInputStream(bis);
565         AbsoluteDate date = new AbsoluteDate(2004, 1, 1, utc);
566         MarshallSolarActivityFutureEstimation deserialized = (MarshallSolarActivityFutureEstimation) ois.readObject();
567         DataProvidersManager managerDeserialized = DataContext.getDefault().getDataProvidersManager();
568         managerDeserialized.feed(deserialized.getSupportedNames(), deserialized);
569         Assert.assertEquals(original.getMeanFlux(date),    deserialized.getMeanFlux(date),    1.0e-12);
570         Assert.assertEquals(original.getDailyFlux(date),   deserialized.getDailyFlux(date),   1.0e-12);
571         Assert.assertEquals(original.getInstantFlux(date), deserialized.getInstantFlux(date), 1.0e-12);
572     }
573 
574     @Before
575     public void setUp() {
576         Utils.setDataRoot("regular-data:atmosphere");
577         utc = TimeScalesFactory.getUTC();
578     }
579 
580     @After
581     public void tearDown() {
582         utc = null;
583     }
584 
585     private TimeScale utc;
586 
587 }