Iau2006XysData.js 8.8 KB

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