77 * 3. https://www.aanda.org/articles/aa/full/2002/45/aah3859/aah3859.html,
88 *
99 */
10-
10+ import { LinearInterpolator } from '../../util/Interp/LinearInterpolator.js' ;
11+ import { isDefined } from '../../util/WebUtil.js' ;
1112export const PLANE = 'PLANE' ;
1213export const LINEAR = 'LINEAR' ;
1314export const LOG = 'LOG' ;
@@ -200,7 +201,31 @@ function getWaveLengthNonLinear(ipt, cubeIdx, wlData) {
200201 return lamda ;
201202}
202203
203- const getArrayDataFromTable = ( table , rowIdx , columnName ) => undefined ; // todo implement
204+ /**
205+ * According to the reference papers above, the coordinate has M+1 dimension where the M means the
206+ * dependence on the M axis, Coords[M][K1][K2[]...[Km]. In our case, the M=1, the coordinate is the
207+ * two dimensional array, and the first dimension is M=1 and the second dimension is K1 which is the sampling
208+ * number the data has been sampled. Thus, each image point, it corresponding coordinate is
209+ * coords[1][K1]. For example, if the sampling count is K1=100, each cell in the coordinate table, contains 100
210+ * data values. The coordinate column can convert to 100 rows of the single value table.
211+ *
212+ *
213+ * @param table
214+ * @param columnName
215+ * @returns {* }
216+ */
217+ const getArrayDataFromTable = ( table , columnName ) => {
218+ let tableData = table . tableData ;
219+ let arrayData = tableData . data ;
220+ let columns = tableData . columns ;
221+ for ( let i = 0 ; i < columns . length ; i ++ ) {
222+ if ( columns [ i ] . name . toUpperCase ( ) === columnName . toUpperCase ( ) ) {
223+ return arrayData [ 0 ] [ i ] ;
224+
225+ }
226+ }
227+ return undefined ;
228+ } ;
204229
205230
206231/**
@@ -228,48 +253,239 @@ function getWaveLengthTable(ipt, cubeIdx, wlData) {
228253
229254
230255 //read the cell coordinate from the FITS table and save to two one dimensional arrays
231- const coordData = getArrayDataFromTable ( wlTable , 0 , ps3_1 || 'COORDS' ) ;
256+ const coordData = getArrayDataFromTable ( wlTable , ps3_1 || 'COORDS' ) ;
232257 if ( ! coordData ) return NaN ;
233258
234- const indexData = getArrayDataFromTable ( wlTable , 0 , ps3_2 || 'INDEX' ) ;
235- if ( ! indexData ) return coordData [ psi_m ] ;
259+ const indexData = getArrayDataFromTable ( wlTable , ps3_2 || 'INDEX' ) ;
260+ if ( ! indexData ) return coordData [ parseInt ( Math . abs ( psi_m ) ) ] ;
236261
237- const psiIndex = searchIndex ( indexData , psi_m ) ;
238- if ( isNaN ( psiIndex ) || psiIndex === - 1 ) return NaN ; // No index found in the index array, gamma is undefined, so is coordinate
239262
240- const gamma_m = calculateGamma_m ( indexData , psi_m , psiIndex ) ;
241- if ( isNaN ( gamma_m ) ) return NaN ;
263+ const gamma_m = calculateGamma_m ( indexData , psi_m ) ;
264+ if ( ! isDefined ( gamma_m ) ) return NaN ;
265+
266+ return calculateC_m ( gamma_m , coordData , indexData . length ) ;
242267
243- return coordData [ psiIndex ] + ( gamma_m - psiIndex ) * ( coordData [ psiIndex + 1 ] - coordData [ psiIndex ] ) ;
244268}
245269
270+ /**
271+ * In the case of a single separable coordinate with 1 ≤ k ≤ Υm < k+1 ≤K,
272+ * the coordinate value is given by
273+ * Cm = Ck + (Υm − k) (Ck+1 − Ck)
274+ * For Υm such that 0.5 ≤ Υm < 1 or K < Υm ≤ K + 0.5 linear
275+ * extrapolation is permitted, with Cm = C1 when K = 1.
276+ *
277+ * @param gamma_m
278+ * @param coordData
279+ * @param kMax
280+ * @returns {undefined }
281+ */
282+ function calculateC_m ( gamma_m , coordData , kMax ) {
283+
284+ let C_m = undefined ;
285+ if ( kMax === 1 ) {
286+ C_m = coordData [ 0 ] ;
287+ }
288+ const kIndex = Math . floor ( gamma_m ) ;
289+ if ( kIndex >= 0 && kIndex <= gamma_m && gamma_m < kIndex + 1 && kIndex + 1 <= kMax - 1 ) {
290+ C_m = coordData [ kIndex ] + ( gamma_m - kIndex - 1 ) * ( coordData [ kIndex + 1 ] - coordData [ kIndex ] ) ;
291+ }
292+ else {
293+ const inCoords = Array . from ( new Array ( coordData . length ) , ( x , i ) => i ) ;
294+ const linearInterpolator = LinearInterpolator ( inCoords , coordData , true ) ;
295+ if ( gamma_m >= 0.5 && gamma_m < 1 ) {
296+
297+ //linear extrapolation CoorData
298+ const coordData_far_left = linearInterpolator ( 0.5 ) ;
299+ C_m = coordData_far_left + gamma_m / ( coordData [ 0 ] - coordData_far_left ) ;
300+
301+ }
302+ else if ( kMax < gamma_m && gamma_m <= kMax + 0.5 ) {
303+ //linear extrapolation CoorData
304+ const coordData_far_right = linearInterpolator ( kMax + 0.5 ) ;
305+ C_m = coordData [ kMax - 1 ] + ( gamma_m - kMax ) / ( coordData_far_right - coordData [ kMax - 1 ] ) ;
306+
307+ }
308+
309+ }
310+ return C_m ;
311+ }
312+
313+ function getGammaByInterpolation ( psiIndex , psi_m , indexVec , sort ) {
314+
315+ let gamma_m = undefined ;
316+ /*--------------------------------------------------------------------------------
317+ * psiIndex is found, however the following four cases, gamma_m is undefined and so is C_m
318+ */
319+ //case 1: Ψk+1=Ψk=Ψm, return undefined
320+ if ( indexVec [ psiIndex ] === indexVec [ psiIndex + 1 ] && indexVec [ psiIndex ] === psi_m ) {
321+ return gamma_m ;
322+ }
246323
324+ /* case 2: Ψk < ψm = Ψk+1 for monotonically increasing index values,except when ψm = Ψ1,
325+ * If Ψk+2 = Ψk+1 = ψm (or Ψ2 = Ψ1 = ψm), then Υm and Cm are undefined.
326+ */
327+ if ( sort === 1 && psiIndex !== 0 && indexVec [ psiIndex ] < psi_m && psi_m === indexVec [ psiIndex + 1 ] ||
328+
329+ /* case 2: Ψk > ψm = Ψk+1 for monotonically decreasing index values,except when ψm = Ψ1
330+ * Ψk > ψm = Ψk+1 for monotonically decreasing index values,except when ψm = Ψ1
331+ */
332+ sort === - 1 && psiIndex !== 0 && indexVec [ psiIndex ] > psi_m && psi_m === indexVec [ psiIndex + 1 ] ) {
333+
334+ /* Since two consecutive index values may be equal, the index following
335+ * the matched index must be examined. If Ψk+2 = Ψk+1 = ψm
336+ * (or Ψ2 = Ψ1 = ψm), then Υm and Cm are undefined
337+ */
338+ if ( indexVec [ psiIndex + 2 ] === psi_m ) {
339+ return gamma_m ;
340+ }
341+ }
342+ //case 4: ψm = Ψ1
343+ if ( indexVec [ 0 ] === psi_m && indexVec [ 1 ] === psi_m ) {
344+ return gamma_m ;
345+ }
346+
347+ /*--------------------------------------------------------------------------------
348+ * psiIndex is found, the gamma_m can be interpolated
349+ */
350+ if ( indexVec [ psiIndex ] !== indexVec [ psiIndex + 1 ] ) {
351+ // Υm = k + (ψm − Ψk) / (Ψk+1− Ψk) where k = 1,... Kmax,
352+ // array index here is from 0, so the k = psiIndex +1. For example is psiIndex =0, it means k=1, Ψ1=ψm
353+ gamma_m = psiIndex + 1 + ( psi_m - indexVec [ psiIndex ] ) / ( indexVec [ psiIndex + 1 ] - indexVec [ psiIndex ] ) ;
354+ return gamma_m ;
355+ }
356+ }
357+ function getGammaByExtrarpolation ( psiIndex , psi_m , indexVec , sort ) {
358+ let gamma_m = undefined ;
359+ const kMax = indexVec . length ;
360+ const inCoords = Array . from ( new Array ( indexVec . length ) , ( x , i ) => i ) ;
361+ const linearInterpolator = LinearInterpolator ( inCoords , indexVec , true ) ;
362+ const left = indexVec [ 0 ] - ( indexVec [ 1 ] - indexVec [ 0 ] ) / 2 ;
363+ const right = indexVec [ kMax - 1 ] + ( indexVec [ kMax - 1 ] - indexVec [ kMax - 2 ] ) / 2 ;
364+
365+ // When no psi_m is found in the vector psiIndex=-1), we need to check if the gamma_m can be extrapolated.
366+
367+ if ( indexVec . length === 1 ) {
368+ /* When the indexVector's length = 1 with ψm in the range Ψ1 − 0.5 ≤ ψm ≤ Ψ1 + 0.5 (noting that Ψ1
369+ * should be equal to 1 in this case) whence Υm = ψm
370+ */
371+ if ( indexVec [ 0 ] - 0.5 <= psi_m && psi_m <= indexVec [ 0 ] + 0.5 ) {
372+ gamma_m = psi_m ;
373+ }
374+ }
375+ else { //do extrapolation
376+ switch ( sort ) {
377+ case 1 :
378+
379+ if ( left <= psi_m && psi_m < indexVec [ 0 ] ) {
380+ const psi_left = linearInterpolator ( left ) ;
381+ gamma_m = ( psi_m - psi_left ) / ( indexVec [ 0 ] - psi_left ) ;
382+
383+ }
384+ else if ( indexVec [ kMax - 1 ] < psi_m && psi_m <= right ) {
385+ const psi_right = linearInterpolator ( right ) ;
386+ gamma_m = indexVec . length + 1 + ( psi_m - indexVec [ kMax - 1 ] ) /
387+ ( psi_right - indexVec [ kMax - 1 ] ) ;
388+ }
389+
390+ break ;
391+ case - 1 :
392+ if ( left >= psi_m && psi_m > indexVec [ 0 ] ) {
393+ const psi_left = linearInterpolator ( left ) ;
394+ gamma_m = ( psi_m - psi_left ) /
395+ ( indexVec [ 0 ] - psi_left ) ;
396+
397+ }
398+ else if ( indexVec [ kMax - 1 ] > psi_m && psi_m >= right ) {
399+ const psi_right = linearInterpolator ( right ) ;
400+ gamma_m = indexVec . length + 1 + ( psi_m - indexVec [ kMax - 1 ] ) / ( psi_right - indexVec [ kMax - 1 ] ) ;
401+ }
402+
403+ break ;
404+ }
405+ }
406+
407+ return gamma_m ;
408+
409+ }
247410/**
411+ * The algorithm for computing Υm, and thence Cm,is as follows:
412+ * Scan the indexing vector, (Ψ1,Ψ2, . . .), sequentially
413+ * starting from the first element, Ψ1, until a successive
414+ * pair of index values is found that encompass ψm (i.e. such that
415+ * Ψk ≤ ψm ≤ Ψk+1 for monotonically increasing index values or
416+ * Ψk ≥ ψm ≥ Ψk+1 for monotonically decreasing index values
417+ * for some k). Then, when Ψk Ψk+1, interpolate linearly on the
418+ * indices Υm = k + (ψm − Ψk)/ (Ψk+1 − Ψk). The Ym (gamma_m) is the index in
419+ * the coordinate array.
420+ *
421+ * However if Ψk+1 = Ψk, the Υm is undefined.
422+ *
423+ * NOTE, the array index starting from 1, not 0 as in javascript
424+ *
425+ * Υm = (k + (psi_m-psi_k)/psi_k+1 - psi_k) )
426+ * Υm = k + ( (ψm − Ψk ) /( Ψk+1 − Ψk) )
427+ * How to calculate gamma_m (Υm):
428+ * case 1:
429+ * where psi is the index vector. In our case, it is indexVec.
430+ * If (psi_k <= psi_m <= psi_k+1) for for monotonically increasing index values
431+ * or
432+ * If (psi_k >= psi_m >= psi_k+1) for for monotonically decreasing index values
433+ * Then the gamma_m = (k + (psi_m-psi_k)/psi_k+1 - psi_k) )
434+ *
435+ * case 2:
436+ * if psi_k = psi_k+1 = psi_m, based on the formula above, the value is undefined. In this case,
437+ * we need to find a psi_k such that psi_k < psi_m = psi_k+1 for monotonically increasing index values
438+ * or psi_k > psi_m = psi_k+1 for monotonically decreasing index values. Since two consecutive index
439+ * values may be equal, the index following the matched index must be examined. If Ψk+2 = Ψk+1 = ψm
440+ * (or Ψ2 = Ψ1 = ψm), then Υm and Cm are undefined.
441+ *
442+ * case 3: linear interpolation
443+ * If psi_m in the range psi_1 to psi_k inclusive, interpolation is needed.
444+ *
445+ * case 4:
446+ * if Ψk+1 = Ψk, the Υm is undefined.
447+ *
448+ * case 5: extrapolation
449+ * psi_m outside range psi_1 - psi_k, and k>1,
450+ * if (psi_1 - (psi_2-psi_1)/2 ) < = psi_m <psi_1 or
451+ * psi_k <psi_m <= (psi_k + (psi_k - psi_k-1) /2)
452+ * monotonically increasing index values
453+ *
454+ * (psi_1 - (psi_2-psi_1)/2 ) > = psi_m > psi_1 or
455+ * psi_k > psi_m >= (psi_k + (psi_k - psi_k-1) /2)
456+ * for monotonically decreasing index values
457+ *
248458 *
249459 * @param {Array.<number> } indexVec
250- * @param {number } psi
251- * @param { number } idx
252- * @return {* }
460+ * @param {number } psi_m
461+ * @param sort
462+ * @returns {* }
253463 */
254- function calculateGamma_m ( indexVec , psi , idx ) {
255- /* Scan the indexing vector, (Ψ1, Ψ2,...), sequen-tially starting from the first element, Ψ1,
256- * until a successive pair of index values is found that encompass ψm (i.e. such that Ψk ≤ ψm ≤ Ψk+1
257- * for monotonically increasing index values or Ψk ≥ ψm ≥ Ψk+1 for monotonically decreasing index values
258- * for some k). Then, when Ψk Ψk+1, interpolate linearly on the indices
259- */
464+ function calculateGamma_m ( indexVec , psi_m , sort ) {
465+
466+ const psiIndex = searchIndex ( indexVec , psi_m , sort ) ;
260467
261468
262- if ( idx !== - 1 && indexVec [ idx - 1 ] !== indexVec [ idx ] ) {
263- // Υm = k + (ψm − Ψk) / (Ψk+1− Ψk)
264- return idx + ( psi - indexVec [ idx - 1 ] ) / ( indexVec [ idx ] - indexVec [ idx - 1 ] ) ;
469+
470+ if ( isNaN ( psiIndex ) ) { //The index vector is not sorted, return undefined
471+ return undefined ;
472+ }
473+
474+
475+ if ( psiIndex !== - 1 ) {
476+ /*
477+ Ψk ≤ ψm ≤ Ψk+1 for monotonically increasing index values or
478+ Ψk ≥ ψm ≥ Ψk+1 for monotonically decreasing index values for some k (here, we use psiIndex)
479+ */
480+ return getGammaByInterpolation ( psiIndex , psi_m , indexVec , sort ) ;
265481 }
266482 else {
267- return NaN ; // No index found in the index array, gamma is undefined, so is coordinate
483+ // psiIndex=-1: no range found, the psi_m is outside of the indexVector's range
484+ return getGammaByExtrarpolation ( psiIndex , psi_m , indexVec , sort ) ;
268485 }
269486
270- }
271-
272487
488+ }
273489
274490
275491
@@ -289,30 +505,37 @@ function isSorted(intArray) {
289505}
290506
291507
508+ /**
509+ /* Scan the indexing vector, (Ψ1, Ψ2,...), sequentially starting from the first element, Ψ1,
510+ * until a successive pair of index values is found that encompass ψm (i.e. such that Ψk ≤ ψm ≤ Ψk+1
511+ * for monotonically increasing index values or Ψk ≥ ψm ≥ Ψk+1 for monotonically decreasing index values
512+ * for some k). Then, when Ψk Ψk+1, interpolate linearly on the indices
513+ *
514+ * NOTE: the index in the algorthim is starting with 1, in Javascript, the index is starting from 0.
515+ *
516+ * @param indexVec
517+ * @param psi_m
518+ * @returns {number }
519+ */
520+ function searchIndex ( indexVec , psi_m ) {
292521
293522
294- function searchIndex ( indexVec , psi ) {
295- /*Scan the indexing vector, (Ψ1, Ψ2,...), sequen-tially starting from the first element, Ψ1,
296- until a successive pair of index values is found that encompass ψm (i.e. such that Ψk ≤ ψm ≤ Ψk+1
297- for monotonically increasing index values or Ψk ≥ ψm ≥ Ψk+1 for monotonically decreasing index values
298- for some k). Then, when Ψk Ψk+1, interpolate linearly on the indices
299- */
300-
301523 const sort = isSorted ( indexVec ) ; //1:ascending, -1: descending, 0: not sorted
302524 if ( sort === 0 ) {
303525 return NaN ; //The vector index array has to be either ascending or descending
304526 }
305527
306-
307- for ( let i = 1 ; i < indexVec . length ; i ++ ) {
308- if ( sort === 1 && indexVec [ i - 1 ] <= psi && psi <= indexVec [ i ] ) {
528+ for ( let i = 0 ; i < indexVec . length - 1 ; i ++ ) {
529+ if ( sort === 1 && indexVec [ i ] <= psi_m && psi_m <= indexVec [ i + 1 ] ) {
309530 return i ;
310531 }
311- if ( sort === - 1 && indexVec [ i - 1 ] >= psi && psi >= indexVec [ i ] ) {
532+ if ( sort === - 1 && indexVec [ i ] >= psi_m && psi_m >= indexVec [ i + 1 ] ) {
312533 return i ;
313534
314535 }
315536 }
537+
538+ //no range found, the psi_m is outside of the indexVector's range
316539 return - 1 ;
317540}
318541
0 commit comments