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.models.earth.displacement;
18
19 import java.io.InputStream;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Optional;
23 import java.util.stream.Collectors;
24
25 import org.orekit.annotation.DefaultDataContext;
26 import org.orekit.data.AbstractSelfFeedingLoader;
27 import org.orekit.data.DataContext;
28 import org.orekit.data.DataLoader;
29 import org.orekit.data.DataProvidersManager;
30 import org.orekit.data.DataSource;
31 import org.orekit.errors.OrekitException;
32 import org.orekit.errors.OrekitMessages;
33
34 /**
35 * Factory for ocean loading coefficients, using Onsala Space Observatory files in BLQ format.
36 * <p>
37 * Files in BLQ format can be generated using the form at the
38 * <a href="http://holt.oso.chalmers.se/loading/">Bos-Scherneck web site</a>,
39 * selecting BLQ as the output format.
40 * </p>
41 * <p>
42 * The sites names are extracted from the file content, not the file name, because the
43 * file can contain more than one station. As we expect existing files may have been
44 * stripped from headers and footers, we do not attempt to parse them. We only parse
45 * the series of 7 lines blocks starting with the lines with the station names and their
46 * coordinates and the 6 data lines that follows. Several such blocks may appear in the
47 * file. Copy-pasting the entire mail received from OSO after completing the web site
48 * form works, as intermediate lines between the 7 lines blocks are simply ignored.
49 * </p>
50 * @see OceanLoadingCoefficients
51 * @see OceanLoading
52 * @since 9.1
53 * @author Luc Maisonobe
54 */
55 public class OceanLoadingCoefficientsBLQFactory extends AbstractSelfFeedingLoader {
56
57 /** Default supported files name pattern for Onsala Space Observatory files in BLQ format. */
58 public static final String DEFAULT_BLQ_SUPPORTED_NAMES = "^.+\\.blq$";
59
60 /** Parsed coefficients. */
61 private final List<OceanLoadingCoefficients> coefficients;
62
63 /** Simple constructor. This constructor uses the {@link DataContext#getDefault()
64 * default data context}.
65 * <p>
66 * Files in BLQ format can be generated using the form at the
67 * <a href="http://holt.oso.chalmers.se/loading/">Bos-Scherneck web site</a>,
68 * selecting BLQ as the output format.
69 * </p>
70 * @param supportedNames regular expression for supported files names
71 * @see #DEFAULT_BLQ_SUPPORTED_NAMES
72 * @see #OceanLoadingCoefficientsBLQFactory(String, DataProvidersManager)
73 */
74 @DefaultDataContext
75 public OceanLoadingCoefficientsBLQFactory(final String supportedNames) {
76 this(supportedNames, DataContext.getDefault().getDataProvidersManager());
77 }
78
79 /**
80 * This constructor allows specification of the source of the BLQ auxiliary data
81 * files.
82 *
83 * <p>
84 * Files in BLQ format can be generated using the form at the
85 * <a href="http://holt.oso.chalmers.se/loading/">Bos-Scherneck web site</a>,
86 * selecting BLQ as the output format.
87 * </p>
88 * @param supportedNames regular expression for supported files names
89 * @param dataProvidersManager provides access to auxiliary data files.
90 * @see #DEFAULT_BLQ_SUPPORTED_NAMES
91 * @since 10.1
92 */
93 public OceanLoadingCoefficientsBLQFactory(final String supportedNames,
94 final DataProvidersManager dataProvidersManager) {
95 super(supportedNames, dataProvidersManager);
96
97 this.coefficients = new ArrayList<>();
98
99 }
100
101 /** Lazy loading of coefficients.
102 */
103 private void loadsIfNeeded() {
104 if (coefficients.isEmpty()) {
105 feed(new DataLoader() {
106
107 /** {@inheritDoc} */
108 @Override
109 public boolean stillAcceptsData() {
110 return true;
111 }
112
113 /** {@inheritDoc} */
114 @Override
115 public void loadData(final InputStream input, final String name) {
116 final OceanLoadingCoefficientsBlqParser parser = new OceanLoadingCoefficientsBlqParser();
117 coefficients.addAll(parser.parse(new DataSource(name, () -> input)));
118 }
119 });
120 }
121 }
122
123 /** Get the list of sites for which we have found coefficients, in lexicographic order ignoring case.
124 * @return list of sites for which we have found coefficients, in lexicographic order ignoring case
125 */
126 public List<String> getSites() {
127
128 loadsIfNeeded();
129
130 // extract sites names from the map
131 return coefficients.stream()
132 .map(OceanLoadingCoefficients::getSiteName)
133 // sort to ensure we have a reproducible order
134 .sorted(String::compareToIgnoreCase)
135 .collect(Collectors.toList());
136
137 }
138
139 /** Get the coefficients for a given site.
140 * @param site site name (as it appears in the Onsala Space Observatory files in BLQ format),
141 * ignoring case
142 * @return coefficients for the site
143 */
144 public OceanLoadingCoefficients getCoefficients(final String site) {
145
146 loadsIfNeeded();
147
148 final Optional<OceanLoadingCoefficients> optional =
149 coefficients.stream().filter(c -> c.getSiteName().equalsIgnoreCase(site)).findFirst();
150 if (!optional.isPresent()) {
151 throw new OrekitException(OrekitMessages.STATION_NOT_FOUND,
152 site,
153 String.join(", ", getSites()));
154 }
155
156 return optional.get();
157
158 }
159
160 }