yzt
2023-05-26 de4278af2fd46705a40bac58ec01122db6b7f3d7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
import when from "../ThirdParty/when.js";
import buildModuleUrl from "./buildModuleUrl.js";
import defaultValue from "./defaultValue.js";
import defined from "./defined.js";
import Iau2006XysSample from "./Iau2006XysSample.js";
import JulianDate from "./JulianDate.js";
import Resource from "./Resource.js";
import TimeStandard from "./TimeStandard.js";
 
/**
 * A set of IAU2006 XYS data that is used to evaluate the transformation between the International
 * Celestial Reference Frame (ICRF) and the International Terrestrial Reference Frame (ITRF).
 *
 * @alias Iau2006XysData
 * @constructor
 *
 * @param {Object} [options] Object with the following properties:
 * @param {Resource|String} [options.xysFileUrlTemplate='Assets/IAU2006_XYS/IAU2006_XYS_{0}.json'] A template URL for obtaining the XYS data.  In the template,
 *                 `{0}` will be replaced with the file index.
 * @param {Number} [options.interpolationOrder=9] The order of interpolation to perform on the XYS data.
 * @param {Number} [options.sampleZeroJulianEphemerisDate=2442396.5] The Julian ephemeris date (JED) of the
 *                 first XYS sample.
 * @param {Number} [options.stepSizeDays=1.0] The step size, in days, between successive XYS samples.
 * @param {Number} [options.samplesPerXysFile=1000] The number of samples in each XYS file.
 * @param {Number} [options.totalSamples=27426] The total number of samples in all XYS files.
 *
 * @private
 */
function Iau2006XysData(options) {
  options = defaultValue(options, defaultValue.EMPTY_OBJECT);
 
  this._xysFileUrlTemplate = Resource.createIfNeeded(
    options.xysFileUrlTemplate
  );
  this._interpolationOrder = defaultValue(options.interpolationOrder, 9);
  this._sampleZeroJulianEphemerisDate = defaultValue(
    options.sampleZeroJulianEphemerisDate,
    2442396.5
  );
  this._sampleZeroDateTT = new JulianDate(
    this._sampleZeroJulianEphemerisDate,
    0.0,
    TimeStandard.TAI
  );
  this._stepSizeDays = defaultValue(options.stepSizeDays, 1.0);
  this._samplesPerXysFile = defaultValue(options.samplesPerXysFile, 1000);
  this._totalSamples = defaultValue(options.totalSamples, 27426);
  this._samples = new Array(this._totalSamples * 3);
  this._chunkDownloadsInProgress = [];
 
  var order = this._interpolationOrder;
 
  // Compute denominators and X values for interpolation.
  var denom = (this._denominators = new Array(order + 1));
  var xTable = (this._xTable = new Array(order + 1));
 
  var stepN = Math.pow(this._stepSizeDays, order);
 
  for (var i = 0; i <= order; ++i) {
    denom[i] = stepN;
    xTable[i] = i * this._stepSizeDays;
 
    for (var j = 0; j <= order; ++j) {
      if (j !== i) {
        denom[i] *= i - j;
      }
    }
 
    denom[i] = 1.0 / denom[i];
  }
 
  // Allocate scratch arrays for interpolation.
  this._work = new Array(order + 1);
  this._coef = new Array(order + 1);
}
 
var julianDateScratch = new JulianDate(0, 0.0, TimeStandard.TAI);
 
function getDaysSinceEpoch(xys, dayTT, secondTT) {
  var dateTT = julianDateScratch;
  dateTT.dayNumber = dayTT;
  dateTT.secondsOfDay = secondTT;
  return JulianDate.daysDifference(dateTT, xys._sampleZeroDateTT);
}
 
/**
 * Preloads XYS data for a specified date range.
 *
 * @param {Number} startDayTT The Julian day number of the beginning of the interval to preload, expressed in
 *                 the Terrestrial Time (TT) time standard.
 * @param {Number} startSecondTT The seconds past noon of the beginning of the interval to preload, expressed in
 *                 the Terrestrial Time (TT) time standard.
 * @param {Number} stopDayTT The Julian day number of the end of the interval to preload, expressed in
 *                 the Terrestrial Time (TT) time standard.
 * @param {Number} stopSecondTT The seconds past noon of the end of the interval to preload, expressed in
 *                 the Terrestrial Time (TT) time standard.
 * @returns {Promise<void>} A promise that, when resolved, indicates that the requested interval has been
 *                    preloaded.
 */
Iau2006XysData.prototype.preload = function (
  startDayTT,
  startSecondTT,
  stopDayTT,
  stopSecondTT
) {
  var startDaysSinceEpoch = getDaysSinceEpoch(this, startDayTT, startSecondTT);
  var stopDaysSinceEpoch = getDaysSinceEpoch(this, stopDayTT, stopSecondTT);
 
  var startIndex =
    (startDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) |
    0;
  if (startIndex < 0) {
    startIndex = 0;
  }
 
  var stopIndex =
    (stopDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) |
    (0 + this._interpolationOrder);
  if (stopIndex >= this._totalSamples) {
    stopIndex = this._totalSamples - 1;
  }
 
  var startChunk = (startIndex / this._samplesPerXysFile) | 0;
  var stopChunk = (stopIndex / this._samplesPerXysFile) | 0;
 
  var promises = [];
  for (var i = startChunk; i <= stopChunk; ++i) {
    promises.push(requestXysChunk(this, i));
  }
 
  return when.all(promises);
};
 
/**
 * Computes the XYS values for a given date by interpolating.  If the required data is not yet downloaded,
 * this method will return undefined.
 *
 * @param {Number} dayTT The Julian day number for which to compute the XYS value, expressed in
 *                 the Terrestrial Time (TT) time standard.
 * @param {Number} secondTT The seconds past noon of the date for which to compute the XYS value, expressed in
 *                 the Terrestrial Time (TT) time standard.
 * @param {Iau2006XysSample} [result] The instance to which to copy the interpolated result.  If this parameter
 *                           is undefined, a new instance is allocated and returned.
 * @returns {Iau2006XysSample} The interpolated XYS values, or undefined if the required data for this
 *                             computation has not yet been downloaded.
 *
 * @see Iau2006XysData#preload
 */
Iau2006XysData.prototype.computeXysRadians = function (
  dayTT,
  secondTT,
  result
) {
  var daysSinceEpoch = getDaysSinceEpoch(this, dayTT, secondTT);
  if (daysSinceEpoch < 0.0) {
    // Can't evaluate prior to the epoch of the data.
    return undefined;
  }
 
  var centerIndex = (daysSinceEpoch / this._stepSizeDays) | 0;
  if (centerIndex >= this._totalSamples) {
    // Can't evaluate after the last sample in the data.
    return undefined;
  }
 
  var degree = this._interpolationOrder;
 
  var firstIndex = centerIndex - ((degree / 2) | 0);
  if (firstIndex < 0) {
    firstIndex = 0;
  }
  var lastIndex = firstIndex + degree;
  if (lastIndex >= this._totalSamples) {
    lastIndex = this._totalSamples - 1;
    firstIndex = lastIndex - degree;
    if (firstIndex < 0) {
      firstIndex = 0;
    }
  }
 
  // Are all the samples we need present?
  // We can assume so if the first and last are present
  var isDataMissing = false;
  var samples = this._samples;
  if (!defined(samples[firstIndex * 3])) {
    requestXysChunk(this, (firstIndex / this._samplesPerXysFile) | 0);
    isDataMissing = true;
  }
 
  if (!defined(samples[lastIndex * 3])) {
    requestXysChunk(this, (lastIndex / this._samplesPerXysFile) | 0);
    isDataMissing = true;
  }
 
  if (isDataMissing) {
    return undefined;
  }
 
  if (!defined(result)) {
    result = new Iau2006XysSample(0.0, 0.0, 0.0);
  } else {
    result.x = 0.0;
    result.y = 0.0;
    result.s = 0.0;
  }
 
  var x = daysSinceEpoch - firstIndex * this._stepSizeDays;
 
  var work = this._work;
  var denom = this._denominators;
  var coef = this._coef;
  var xTable = this._xTable;
 
  var i, j;
  for (i = 0; i <= degree; ++i) {
    work[i] = x - xTable[i];
  }
 
  for (i = 0; i <= degree; ++i) {
    coef[i] = 1.0;
 
    for (j = 0; j <= degree; ++j) {
      if (j !== i) {
        coef[i] *= work[j];
      }
    }
 
    coef[i] *= denom[i];
 
    var sampleIndex = (firstIndex + i) * 3;
    result.x += coef[i] * samples[sampleIndex++];
    result.y += coef[i] * samples[sampleIndex++];
    result.s += coef[i] * samples[sampleIndex];
  }
 
  return result;
};
 
function requestXysChunk(xysData, chunkIndex) {
  if (xysData._chunkDownloadsInProgress[chunkIndex]) {
    // Chunk has already been requested.
    return xysData._chunkDownloadsInProgress[chunkIndex];
  }
 
  var deferred = when.defer();
 
  xysData._chunkDownloadsInProgress[chunkIndex] = deferred;
 
  var chunkUrl;
  var xysFileUrlTemplate = xysData._xysFileUrlTemplate;
  if (defined(xysFileUrlTemplate)) {
    chunkUrl = xysFileUrlTemplate.getDerivedResource({
      templateValues: {
        0: chunkIndex,
      },
    });
  } else {
    chunkUrl = new Resource({
      url: buildModuleUrl(
        "Assets/IAU2006_XYS/IAU2006_XYS_" + chunkIndex + ".json"
      ),
    });
  }
 
  when(chunkUrl.fetchJson(), function (chunk) {
    xysData._chunkDownloadsInProgress[chunkIndex] = false;
 
    var samples = xysData._samples;
    var newSamples = chunk.samples;
    var startIndex = chunkIndex * xysData._samplesPerXysFile * 3;
 
    for (var i = 0, len = newSamples.length; i < len; ++i) {
      samples[startIndex + i] = newSamples[i];
    }
 
    deferred.resolve();
  });
 
  return deferred.promise;
}
export default Iau2006XysData;