GeoMagneticModelLoader.java
- /* Copyright 2011-2012 Space Applications Services
- * Licensed to CS Communication & Systèmes (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.models.earth;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.StreamTokenizer;
- import java.nio.charset.StandardCharsets;
- import java.text.ParseException;
- import java.util.Collection;
- import java.util.LinkedList;
- import java.util.List;
- import org.orekit.data.DataLoader;
- /** Loads geomagnetic field models from a given input stream. A stream may contain multiple
- * models, the loader reads all available models in consecutive order.
- * <p>
- * The format of the expected model file is either:
- * <ul>
- * <li>combined format as used by the geomag software, available from the
- * <a href="http://www.ngdc.noaa.gov/IAGA/vmod/igrf.html">IGRF model site</a>;
- * supports multiple epochs per file</li>
- * <li>original format as used by the
- * <a href="http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml">WMM model site</a>.
- * </ul>
- * <p>
- * <b>Combined Format</b>
- * <pre>
- * {model name} {epoch} {nMax} {nMaxSec} {nMax3} {validity start} {validity end} {minAlt} {maxAlt} {model name} {line number}
- * {n} {m} {gnm} {hnm} {dgnm} {dhnm} {model name} {line number}
- * </pre>
- * <p>
- * Example:
- * </p>
- * <pre>
- * WMM2010 2010.00 12 12 0 2010.00 2015.00 -1.0 600.0 WMM2010 0
- * 1 0 -29496.6 0.0 11.6 0.0 WMM2010 1
- * 1 1 -1586.3 4944.4 16.5 -25.9 WMM2010 2
- * </pre>
- * <p>
- * <b>Original WMM Format</b>
- * <pre>
- * {epoch} {model name} {validity start}
- * {n} {m} {gnm} {hnm} {dgnm} {dhnm}
- * </pre>
- * <p>
- * Example:
- * </p>
- * <pre>
- * 2015.0 WMM-2015 12/15/2014
- * 1 0 -29438.5 0.0 10.7 0.0
- * 1 1 -1501.1 4796.2 17.9 -26.8
- * </pre>
- *
- * @author Thomas Neidhart
- */
- public class GeoMagneticModelLoader implements DataLoader {
- /** The loaded models. */
- private List<GeoMagneticField> models = new LinkedList<GeoMagneticField>();
- /** Empty constructor.
- * <p>
- * This constructor is not strictly necessary, but it prevents spurious
- * javadoc warnings with JDK 18 and later.
- * </p>
- * @since 12.0
- */
- public GeoMagneticModelLoader() {
- // nothing to do
- }
- /** Returns a {@link Collection} of the {@link GeoMagneticField} models that
- * have been successfully loaded. The {@link Collection} is in
- * insertion-order, thus it may not be sorted in order of the model epoch.
- * @return a {@link Collection} of {@link GeoMagneticField} models
- */
- public Collection<GeoMagneticField> getModels() {
- return models;
- }
- /** {@inheritDoc} */
- public boolean stillAcceptsData() {
- return models == null || models.isEmpty();
- }
- /** {@inheritDoc} */
- public void loadData(final InputStream input, final String name)
- throws IOException, ParseException {
- // open data file and parse values
- final StreamTokenizer str = new StreamTokenizer(new InputStreamReader(input, StandardCharsets.UTF_8));
- while (true) {
- final GeoMagneticField model = readModel(str);
- if (model != null) {
- models.add(model);
- } else {
- break;
- }
- }
- }
- /** Read the model from the given {@link StreamTokenizer}.
- * @param stream the stream to read the model from
- * @return the parsed geomagnetic field model
- * @throws IOException if an I/O error occurs
- */
- private GeoMagneticField readModel(final StreamTokenizer stream) throws IOException {
- // check whether there is another model available in the stream
- final int ttype = stream.nextToken();
- if (ttype == StreamTokenizer.TT_EOF) {
- return null;
- }
- if (ttype == StreamTokenizer.TT_WORD) {
- return readCombinedFormat(stream);
- } else {
- return readOriginalWMMFormat(stream);
- }
- }
- /** Read a magnetic field from combined format.
- * @param stream the stream to read the model from
- * @return magnetic field
- * @throws IOException if some read error occurs
- */
- private GeoMagneticField readCombinedFormat(final StreamTokenizer stream)
- throws IOException {
- final String modelName = stream.sval;
- stream.nextToken();
- final double epoch = stream.nval;
- stream.nextToken();
- final int nMax = (int) stream.nval;
- stream.nextToken();
- final int nMaxSecVar = (int) stream.nval;
- // ignored
- stream.nextToken();
- stream.nextToken();
- final double startYear = stream.nval;
- stream.nextToken();
- final double endYear = stream.nval;
- final GeoMagneticField model = new GeoMagneticField(modelName, epoch, nMax, nMaxSecVar,
- startYear, endYear);
- // the rest is ignored
- stream.nextToken();
- @SuppressWarnings("unused")
- final double altmin = stream.nval;
- stream.nextToken();
- @SuppressWarnings("unused")
- final double altmax = stream.nval;
- stream.nextToken();
- stream.nextToken();
- // loop to get model data from file
- boolean done = false;
- int n;
- int m;
- do {
- stream.nextToken();
- n = (int) stream.nval;
- stream.nextToken();
- m = (int) stream.nval;
- stream.nextToken();
- final double gnm = stream.nval;
- stream.nextToken();
- final double hnm = stream.nval;
- stream.nextToken();
- final double dgnm = stream.nval;
- stream.nextToken();
- final double dhnm = stream.nval;
- model.setMainFieldCoefficients(n, m, gnm, hnm);
- if (n <= nMaxSecVar && m <= nMaxSecVar) {
- model.setSecularVariationCoefficients(n, m, dgnm, dhnm);
- }
- stream.nextToken();
- stream.nextToken();
- done = n == nMax && m == nMax;
- } while (!done);
- return model;
- }
- /** Read a magnetic field from original WMM files.
- * @param stream the stream to read the model from
- * @return magnetic field
- * @throws IOException if some read error occurs
- */
- private GeoMagneticField readOriginalWMMFormat(final StreamTokenizer stream)
- throws IOException {
- // hard-coded values in original WMM format
- final int nMax = 12;
- final int nMaxSecVar = 12;
- // the validity start is encoded in format MM/dd/yyyy
- // use the slash as whitespace character to get separate tokens
- stream.whitespaceChars('/', '/');
- final double epoch = stream.nval;
- stream.nextToken();
- final String modelName = stream.sval;
- stream.nextToken();
- final double month = stream.nval;
- stream.nextToken();
- final double day = stream.nval;
- stream.nextToken();
- final double year = stream.nval;
- final double startYear = GeoMagneticField.getDecimalYear((int) day, (int) month, (int) year);
- final GeoMagneticField model = new GeoMagneticField(modelName, epoch, nMax, nMaxSecVar,
- startYear, epoch + 5.0);
- // loop to get model data from file
- boolean done = false;
- int n;
- int m;
- do {
- stream.nextToken();
- n = (int) stream.nval;
- stream.nextToken();
- m = (int) stream.nval;
- stream.nextToken();
- final double gnm = stream.nval;
- stream.nextToken();
- final double hnm = stream.nval;
- stream.nextToken();
- final double dgnm = stream.nval;
- stream.nextToken();
- final double dhnm = stream.nval;
- model.setMainFieldCoefficients(n, m, gnm, hnm);
- if (n <= nMaxSecVar && m <= nMaxSecVar) {
- model.setSecularVariationCoefficients(n, m, dgnm, dhnm);
- }
- done = n == nMax && m == nMax;
- } while (!done);
- // the original format closes with two delimiting lines of '9's
- stream.nextToken();
- stream.nextToken();
- return model;
- }
- }