GeoMagneticModelParser.java

  1. /* Copyright 2011-2012 Space Applications Services
  2.  * Licensed to CS Communication & Systèmes (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;

  18. import org.orekit.data.DataSource;

  19. import java.io.IOException;
  20. import java.io.StreamTokenizer;
  21. import java.util.ArrayList;
  22. import java.util.List;

  23. /** Loads geomagnetic field models from a given input stream. A stream may contain multiple
  24.  * models, the loader reads all available models in consecutive order.
  25.  * <p>
  26.  * The format of the expected model file is either:
  27.  * <ul>
  28.  *   <li>combined format as used by the geomag software, available from the
  29.  *       <a href="http://www.ngdc.noaa.gov/IAGA/vmod/igrf.html">IGRF model site</a>;
  30.  *       supports multiple epochs per file</li>
  31.  *   <li>original format as used by the
  32.  *       <a href="http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml">WMM model site</a>.
  33.  * </ul>
  34.  * <p>
  35.  * <b>Combined Format</b>
  36.  * <pre>
  37.  *     {model name} {epoch} {nMax} {nMaxSec} {nMax3} {validity start} {validity end} {minAlt} {maxAlt} {model name} {line number}
  38.  * {n} {m} {gnm} {hnm} {dgnm} {dhnm} {model name} {line number}
  39.  * </pre>
  40.  * <p>
  41.  * Example:
  42.  * </p>
  43.  * <pre>
  44.  *    WMM2010  2010.00 12 12  0 2010.00 2015.00   -1.0  600.0          WMM2010   0
  45.  * 1  0  -29496.6       0.0      11.6       0.0                        WMM2010   1
  46.  * 1  1   -1586.3    4944.4      16.5     -25.9                        WMM2010   2
  47.  * </pre>
  48.  * <p>
  49.  * <b>Original WMM Format</b>
  50.  * <pre>
  51.  *    {epoch} {model name} {validity start}
  52.  * {n} {m} {gnm} {hnm} {dgnm} {dhnm}
  53.  * </pre>
  54.  * <p>
  55.  * Example:
  56.  * </p>
  57.  * <pre>
  58.  *    2015.0            WMM-2015        12/15/2014
  59.  *  1  0  -29438.5       0.0       10.7        0.0
  60.  *  1  1   -1501.1    4796.2       17.9      -26.8
  61.  * </pre>
  62.  *
  63.  * @author Thomas Neidhart
  64.  * @author Luc Maisonobe
  65.  * @since 13.0
  66.  */
  67. public class GeoMagneticModelParser {

  68.     /** Empty constructor.
  69.      */
  70.     public GeoMagneticModelParser() {
  71.         // nothing to do
  72.     }

  73.     /** Parse a model.
  74.      * @param dataSource source data
  75.      * @return parsed fields
  76.      * @throws IOException if an I/O error occurs
  77.      */
  78.     public List<GeoMagneticField> parse(final DataSource dataSource) throws IOException {

  79.         // open data file and parse values
  80.         final StreamTokenizer str = new StreamTokenizer(dataSource.getOpener().openReaderOnce());

  81.         // read all the models from source
  82.         final List<GeoMagneticField> fields = new ArrayList<>();
  83.         for (GeoMagneticField model = readModel(str); model != null; model = readModel(str)) {
  84.             fields.add(model);
  85.         }

  86.         return fields;

  87.     }

  88.     /** Read the model from the given {@link StreamTokenizer}.
  89.      * @param stream the stream to read the model from
  90.      * @return the parsed geomagnetic field model
  91.      * @throws IOException if an I/O error occurs
  92.      */
  93.     private GeoMagneticField readModel(final StreamTokenizer stream) throws IOException {

  94.         // check whether there is another model available in the stream
  95.         final int ttype = stream.nextToken();
  96.         if (ttype == StreamTokenizer.TT_EOF) {
  97.             return null;
  98.         }

  99.         if (ttype == StreamTokenizer.TT_WORD) {
  100.             return readCombinedFormat(stream);
  101.         } else {
  102.             return readOriginalWMMFormat(stream);
  103.         }
  104.     }

  105.     /** Read a magnetic field from combined format.
  106.      * @param stream the stream to read the model from
  107.      * @return magnetic field
  108.      * @throws IOException if some read error occurs
  109.      */
  110.     private GeoMagneticField readCombinedFormat(final StreamTokenizer stream)
  111.         throws IOException {
  112.         final String modelName = stream.sval;
  113.         stream.nextToken();
  114.         final double epoch = stream.nval;
  115.         stream.nextToken();
  116.         final int nMax = (int) stream.nval;
  117.         stream.nextToken();
  118.         final int nMaxSecVar = (int) stream.nval;

  119.         // ignored
  120.         stream.nextToken();

  121.         stream.nextToken();
  122.         final double startYear = stream.nval;

  123.         stream.nextToken();
  124.         final double endYear = stream.nval;

  125.         final GeoMagneticField model = new GeoMagneticField(modelName, epoch, nMax, nMaxSecVar,
  126.                                                             startYear, endYear);

  127.         // the rest is ignored
  128.         stream.nextToken();
  129.         @SuppressWarnings("unused")
  130.         final double altmin = stream.nval;

  131.         stream.nextToken();
  132.         @SuppressWarnings("unused")
  133.         final double altmax = stream.nval;

  134.         stream.nextToken();
  135.         stream.nextToken();

  136.         // loop to get model data from file
  137.         boolean done;
  138.         int n;
  139.         int m;

  140.         do {
  141.             stream.nextToken();
  142.             n = (int) stream.nval;
  143.             stream.nextToken();
  144.             m = (int) stream.nval;

  145.             stream.nextToken();
  146.             final double gnm = stream.nval;
  147.             stream.nextToken();
  148.             final double hnm = stream.nval;
  149.             stream.nextToken();
  150.             final double dgnm = stream.nval;
  151.             stream.nextToken();
  152.             final double dhnm = stream.nval;

  153.             model.setMainFieldCoefficients(n, m, gnm, hnm);
  154.             if (n <= nMaxSecVar && m <= nMaxSecVar) {
  155.                 model.setSecularVariationCoefficients(n, m, dgnm, dhnm);
  156.             }

  157.             stream.nextToken();
  158.             stream.nextToken();

  159.             done = n == nMax && m == nMax;
  160.         } while (!done);

  161.         return model;
  162.     }

  163.     /** Read a magnetic field from original WMM files.
  164.      * @param stream the stream to read the model from
  165.      * @return magnetic field
  166.      * @throws IOException if some read error occurs
  167.      */
  168.     private GeoMagneticField readOriginalWMMFormat(final StreamTokenizer stream) throws IOException {

  169.         // hard-coded values in original WMM format
  170.         final int nMax = 12;
  171.         final int nMaxSecVar = 12;

  172.         // the validity start is encoded in format MM/dd/yyyy
  173.         // use the slash as whitespace character to get separate tokens
  174.         stream.whitespaceChars('/', '/');

  175.         final double epoch = stream.nval;
  176.         stream.nextToken();
  177.         final String modelName = stream.sval;
  178.         stream.nextToken();
  179.         final double month = stream.nval;
  180.         stream.nextToken();
  181.         final double day = stream.nval;
  182.         stream.nextToken();
  183.         final double year = stream.nval;

  184.         final double startYear = GeoMagneticField.getDecimalYear((int) day, (int) month, (int) year);

  185.         final GeoMagneticField model = new GeoMagneticField(modelName, epoch, nMax, nMaxSecVar,
  186.                                                             startYear, epoch + 5.0);

  187.         // loop to get model data from file
  188.         boolean done;
  189.         int n;
  190.         int m;

  191.         do {
  192.             stream.nextToken();
  193.             n = (int) stream.nval;
  194.             stream.nextToken();
  195.             m = (int) stream.nval;

  196.             stream.nextToken();
  197.             final double gnm = stream.nval;
  198.             stream.nextToken();
  199.             final double hnm = stream.nval;
  200.             stream.nextToken();
  201.             final double dgnm = stream.nval;
  202.             stream.nextToken();
  203.             final double dhnm = stream.nval;

  204.             model.setMainFieldCoefficients(n, m, gnm, hnm);
  205.             if (n <= nMaxSecVar && m <= nMaxSecVar) {
  206.                 model.setSecularVariationCoefficients(n, m, dgnm, dhnm);
  207.             }

  208.             done = n == nMax && m == nMax;
  209.         } while (!done);

  210.         // the original format closes with two delimiting lines of '9's
  211.         stream.nextToken();
  212.         stream.nextToken();

  213.         return model;
  214.     }

  215. }