MUSE Pipeline Reference Manual  2.1.1
muse_pixgrid.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2005-2017 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 /*----------------------------------------------------------------------------*
27  * Includes *
28  *----------------------------------------------------------------------------*/
29 #include <cpl.h>
30 #include <math.h>
31 #include <string.h>
32 #ifndef _OPENMP
33 #define omp_get_max_threads() 1
34 #define omp_get_thread_num() 0
35 #else
36 #include <omp.h>
37 #endif
38 
39 #include "muse_pixgrid.h"
40 
41 #include "muse_pfits.h"
42 #include "muse_quality.h"
43 #include "muse_utils.h"
44 #include "muse_wcs.h"
45 
46 /*----------------------------------------------------------------------------*/
54 /*----------------------------------------------------------------------------*/
55 
58 /*---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------*/
69 static muse_pixgrid *
70 muse_pixgrid_new(cpl_size aSizeX, cpl_size aSizeY, cpl_size aSizeZ,
71  unsigned short aNMaps)
72 {
73  muse_pixgrid *pixels = cpl_calloc(1, sizeof(muse_pixgrid));
74  pixels->nx = aSizeX;
75  pixels->ny = aSizeY;
76  pixels->nz = aSizeZ;
77  pixels->pix = cpl_calloc(aSizeX * aSizeY * aSizeZ, sizeof(cpl_size));
78  /* extension maps for possibly multiple threads */
79  pixels->nmaps = aNMaps;
80  pixels->nxalloc = cpl_calloc(aNMaps, sizeof(cpl_size));
81  pixels->xmaps = cpl_calloc(aNMaps, sizeof(muse_pixels_ext *));
82  pixels->nxmap = cpl_calloc(aNMaps, sizeof(cpl_size));
83  return pixels;
84 } /* muse_pixgrid_new() */
85 
86 /*---------------------------------------------------------------------------*/
102 /*---------------------------------------------------------------------------*/
103 static void
104 muse_pixgrid_add(muse_pixgrid *aGrid, cpl_size aIndex, cpl_size aRow,
105  unsigned short aXIdx)
106 {
107  if (aIndex < 0) {
108  return;
109  }
110 
111  if (aGrid->pix[aIndex] == 0 && aRow > 0) {
112  /* First pixel is stored directly. */
113  aGrid->pix[aIndex] = aRow;
114  } else if (aGrid->pix[aIndex] == 0 && aRow == 0) {
115  /* Special case: we cannot put "0" into the main map. */
116  cpl_size iext = aGrid->nxmap[aXIdx]++;
117  if (aGrid->nxmap[aXIdx] > aGrid->nxalloc[aXIdx]) {
118  /* double the number of allocated entries */
119  aGrid->nxalloc[aXIdx] = 2 * aGrid->nxmap[aXIdx];
120  aGrid->xmaps[aXIdx] = cpl_realloc(aGrid->xmaps[aXIdx],
121  aGrid->nxalloc[aXIdx]
122  * sizeof(muse_pixels_ext));
123  }
124  aGrid->xmaps[aXIdx][iext].npix = 1;
125  aGrid->xmaps[aXIdx][iext].pix = cpl_malloc(sizeof(cpl_size));
126  aGrid->xmaps[aXIdx][iext].pix[0] = aRow;
127  aGrid->pix[aIndex] = -(iext + 1 + ((cpl_size)aXIdx << XMAP_LSHIFT));
128  } else if (aGrid->pix[aIndex] > 0) {
129  /* When a second pixel is added, put both to the extension map. */
130  cpl_size iext = aGrid->nxmap[aXIdx]++;
131  if (aGrid->nxmap[aXIdx] > aGrid->nxalloc[aXIdx]) {
132  /* double the number of allocated entries */
133  aGrid->nxalloc[aXIdx] = 2 * aGrid->nxmap[aXIdx];
134  aGrid->xmaps[aXIdx] = cpl_realloc(aGrid->xmaps[aXIdx],
135  aGrid->nxalloc[aXIdx]
136  * sizeof(muse_pixels_ext));
137  }
138  aGrid->xmaps[aXIdx][iext].npix = 2;
139  aGrid->xmaps[aXIdx][iext].pix = cpl_malloc(2 * sizeof(cpl_size));
140  aGrid->xmaps[aXIdx][iext].pix[0] = aGrid->pix[aIndex];
141  aGrid->xmaps[aXIdx][iext].pix[1] = aRow;
142  aGrid->pix[aIndex] = -(iext + 1 + ((cpl_size)aXIdx << XMAP_LSHIFT));
143  } else {
144  /* Append additional pixels to the extension map. */
145  cpl_size iext = (-aGrid->pix[aIndex] - 1) & PT_IDX_MASK;
146  /* index of the new entry in this grid point */
147  unsigned int ipix = aGrid->xmaps[aXIdx][iext].npix;
148  aGrid->xmaps[aXIdx][iext].npix++;
149  aGrid->xmaps[aXIdx][iext].pix = cpl_realloc(aGrid->xmaps[aXIdx][iext].pix,
150  (ipix + 1) * sizeof(cpl_size));
151  aGrid->xmaps[aXIdx][iext].pix[ipix] = aRow;
152  }
153 } /* muse_pixgrid_add() */
154 
155 /*---------------------------------------------------------------------------*/
162 /*---------------------------------------------------------------------------*/
163 static void
164 muse_pixgrid_dump_xmaps(muse_pixgrid *aGrid, cpl_boolean aFull)
165 {
166  if (!aGrid) {
167  return;
168  }
169  /* clean up extension maps */
170  cpl_msg_debug(__func__, "Dumping %u extension maps:", aGrid->nmaps);
171  unsigned short ix;
172  for (ix = 0; ix < aGrid->nmaps; ix++) {
173  cpl_msg_debug(__func__, "- Map %u (%"CPL_SIZE_FORMAT" / %"CPL_SIZE_FORMAT
174  " entries):", ix + 1u, aGrid->nxmap[ix], aGrid->nxalloc[ix]);
175  cpl_size iext, /* index in this extension map */
176  nmax = aFull ? aGrid->nxalloc[ix] : 0;
177  for (iext = 0; iext < nmax; iext++) {
178  unsigned int ipix;
179  for (ipix = 0; ipix < aGrid->xmaps[ix][iext].npix; ipix++) {
180  cpl_size value = aGrid->xmaps[ix][iext].pix[ipix];
181  char *warning = NULL;
182  if (value < 0 || value > 13534057) {
183  warning = cpl_sprintf(" WARNING!!!");
184  }
185  if (ipix == 0) {
186  cpl_msg_debug(__func__, " %08"CPL_SIZE_FORMAT" %u: %"CPL_SIZE_FORMAT"%s",
187  iext + 1, ipix + 1u, value, warning ? warning : "");
188  cpl_free(warning);
189  continue;
190  }
191  cpl_msg_debug(__func__, " %u: %"CPL_SIZE_FORMAT"%s", ipix + 1u,
192  value, warning ? warning : "");
193  cpl_free(warning);
194  }
195  if (1 + iext > aGrid->nxmap[ix]) {
196  cpl_msg_debug(__func__, "Not initialized!");
197  }
198  } /* for iext (all allocated pixels in this extension map) */
199  } /* for ix (all extension maps) */
200 } /* muse_pixgrid_dump_xmaps() */
201 
202 /*---------------------------------------------------------------------------*/
235 /*---------------------------------------------------------------------------*/
236 muse_pixgrid *
237 muse_pixgrid_create(muse_pixtable *aPixtable, cpl_propertylist *aHeader,
238  cpl_size aXSize, cpl_size aYSize, cpl_size aZSize)
239 {
240  cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, NULL);
241  cpl_size nrow = muse_pixtable_get_nrow(aPixtable);
242  if (nrow == 0) {
243  cpl_msg_error(__func__, "Invalid pixel table (no entries?)");
244  cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
245  return NULL;
246  }
247  cpl_ensure(aXSize > 0 && aYSize > 0 && aZSize > 0, CPL_ERROR_ILLEGAL_INPUT,
248  NULL);
249  muse_pixtable_wcs wcstype = muse_pixtable_wcs_check(aPixtable);
250  cpl_ensure(wcstype == MUSE_PIXTABLE_WCS_CELSPH ||
251  wcstype == MUSE_PIXTABLE_WCS_PIXEL, CPL_ERROR_UNSUPPORTED_MODE,
252  NULL);
253 
254  double crval3 = muse_pfits_get_crval(aHeader, 3),
255  crpix3 = muse_pfits_get_crpix(aHeader, 3),
256  cd33 = muse_pfits_get_cd(aHeader, 3, 3);
257  const char *ctype3 = muse_pfits_get_ctype(aHeader, 3);
258  muse_wcs *wcs = muse_wcs_new(aHeader);
259  wcs->iscelsph = wcstype == MUSE_PIXTABLE_WCS_CELSPH;
260  cpl_boolean loglambda = ctype3 && (!strncmp(ctype3, "AWAV-LOG", 9) ||
261  !strncmp(ctype3, "WAVE-LOG", 9));
262  /* get all (relevant) table columns for easy pointer access */
263  double ptxoff = 0., ptyoff = 0.;
264  if (wcs->iscelsph) {
265  ptxoff = muse_pfits_get_crval(aPixtable->header, 1);
266  ptyoff = muse_pfits_get_crval(aPixtable->header, 2);
267  }
268  float *xpos = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_XPOS),
269  *ypos = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_YPOS),
270  *lbda = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA);
271  if (!xpos || !ypos || !lbda) {
272  cpl_msg_error(__func__, "Missing pixel table column (%p %p %p): %s",
273  (void *)xpos, (void *)ypos, (void *)lbda,
274  cpl_error_get_message());
275  cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
276  cpl_free(wcs);
277  return NULL;
278  }
279 #ifdef ESO_ENABLE_DEBUG
280  int debug = 0;
281  if (getenv("MUSE_DEBUG_GRID_CONVERSION")) {
282  debug = atoi(getenv("MUSE_DEBUG_GRID_CONVERSION"));
283  }
284  if (debug) {
285  printf("crpix=%f %f %f, crval=%f %f %f, cd=%e %e %f\n",
286  wcs->crpix1, wcs->crpix2, crpix3, wcs->crval1, wcs->crval2, crval3,
287  wcs->cd11, wcs->cd22, cd33);
288  }
289 #endif
290  if (wcs->iscelsph) {
291  wcs->crval1 /= CPL_MATH_DEG_RAD; /* convert to radians before calling... */
292  wcs->crval2 /= CPL_MATH_DEG_RAD; /* ...muse_wcs_pixel_from_celestial_fast() */
293  }
294  double timeinit = cpl_test_get_walltime(),
295  timeprogress = timeinit,
296  cpuinit = cpl_test_get_cputime();
297  cpl_boolean showprogress = cpl_msg_get_level() == CPL_MSG_DEBUG
298  || cpl_msg_get_log_level() == CPL_MSG_DEBUG;
299 
300  /* check for the selected pixels in the pixel table, only those *
301  * are used to construct the pixel grid; since constructing the *
302  * array of selected pixels costs significant amounts of time, *
303  * do that only when not all pixels are selected! */
304  cpl_array *asel = NULL;
305  const cpl_size *sel = NULL;
306  cpl_size nsel = cpl_table_count_selected(aPixtable->table);
307  if (nsel < nrow) {
308  asel = cpl_table_where_selected(aPixtable->table);
309  sel = cpl_array_get_data_cplsize_const(asel);
310  }
311 
312  /* can use at most XMAP_BITMASK threads so that the bitmask does not *
313  * overflow, but ensure that we are not using more cores than available... */
314  int nth = omp_get_max_threads() > XMAP_BITMASK ? XMAP_BITMASK
315  : omp_get_max_threads();
316  /* prepare the ranges for the different threads, store them in arrays */
317  cpl_array *az1 = cpl_array_new(nth, CPL_TYPE_INT),
318  *az2 = cpl_array_new(nth, CPL_TYPE_INT);
319  if (aZSize < nth) {
320  /* pre-fill arrays with values that cause the threads to do nothing */
321  cpl_array_fill_window_int(az1, aZSize, nth, -1);
322  cpl_array_fill_window_int(az2, aZSize, nth, -2);
323  }
324  /* now fill the (first) ones with real ranges */
325  double base = nth > aZSize ? 1. : (double)aZSize / nth;
326  int ith;
327  for (ith = 0; ith < nth && ith < aZSize; ith++) {
328  cpl_array_set_int(az1, ith, lround(base * ith));
329  cpl_array_set_int(az2, ith, lround(base * (ith + 1) - 1));
330  } /* for */
331  /* make sure that we don't lose pixels at the edges of the wavelength *
332  * range, put them into the extreme threads by making their ranges larger; *
333  * set the relevant array entries to something close to the largest value, *
334  * that we can still add as an integer (to compute the z-range) */
335  cpl_array_set_int(az1, 0, -INT_MAX / 2 + 1);
336  cpl_array_set_int(az2, ith - 1, INT_MAX / 2 - 1);
337 #if 0 /* DEBUG */
338  if (aZSize < 2*nth) {
339  printf("arrays (base = %f, aZSize = %d, nth = %d):\n",
340  base, (int)aZSize, nth);
341  cpl_array_dump(az1, 0, nth, stdout);
342  cpl_array_dump(az2, 0, nth, stdout);
343  fflush(stdout);
344  }
345 #endif
346 
347  /* create the pixel grid with extension maps for threads */
348  muse_pixgrid *grid = muse_pixgrid_new(aXSize, aYSize, aZSize, nth);
349 
350  /* parallel region to fill the pixel grid */
351 #ifdef ESO_ENABLE_DEBUG
352  #pragma omp parallel num_threads(nth) default(none) /* as req. by Ralf */ \
353  shared(aXSize, aYSize, aZSize, az1, az2, cd33, crpix3, crval3, debug,\
354  grid, lbda, loglambda, nsel, ptxoff, ptyoff, sel, \
355  showprogress, timeinit, timeprogress, wcs, xpos, ypos)
356 #else
357  #pragma omp parallel num_threads(nth) default(none) /* as req. by Ralf */ \
358  shared(aXSize, aYSize, aZSize, az1, az2, cd33, crpix3, crval3, grid, \
359  lbda, loglambda, nsel, ptxoff, ptyoff, sel, showprogress, \
360  timeinit, timeprogress, wcs, xpos, ypos)
361 #endif
362  {
363  /* split the work up into threads, for non-overlapping wavelength ranges */
364  unsigned short ithread = omp_get_thread_num(); /* index of this thread */
365  int z1 = cpl_array_get_int(az1, ithread, NULL),
366  z2 = cpl_array_get_int(az2, ithread, NULL),
367  zrange = z2 - z1 + 1;
368 
369  /* check if we actually need to enter the (parallel) loop, i.e. *
370  * if the current thread is handling any wavelength planes */
371 #if 0 /* DEBUG */
372  if (zrange > 0) {
373  cpl_msg_debug(__func__, "%lld z pixels, thread index %hu, z range: %d..%d "
374  "(%d planes)", aZSize, ithread, z1, z2, zrange);
375  } else {
376  cpl_msg_debug(__func__, "%lld z pixels, thread index %hu, z range: %d..%d "
377  "(%d planes) --> thread not used!", aZSize, ithread, z1, z2,
378  zrange);
379  }
380 #endif
381 
382  /* now the actual parallel loop */
383  cpl_size isel;
384  for (isel = 0 ; zrange > 0 && isel < nsel; isel++) {
385  #pragma omp master /* only output progress from the master thread */
386  if (showprogress && !((isel+1) % 1000000ll)) { /* output before every millionth entry */
387  double timenow = cpl_test_get_walltime();
388  if (timenow - timeprogress > 30.) { /* and more than half a minute passed */
389  timeprogress = timenow;
390  double percent = 100. * (isel + 1.) / nsel,
391  elapsed = timeprogress - timeinit,
392  remaining = (100. - percent) * elapsed / percent;
393  /* overwritable only exists for INFO mode, but we check *
394  * above that we want this only for DEBUG mode output... */
395  cpl_msg_info_overwritable(__func__, "pixel grid creation is %.1f%% "
396  "complete, %.1fs elapsed, ~%.1fs remaining",
397  percent, elapsed, remaining);
398  } /* if: 1/2 min passed */
399  } /* if: want debug output */
400 
401  /* either use the index from the array of selected rows *
402  * or the row numberdirectly (for a fully selected table) */
403  cpl_size n = sel ? sel[isel] : isel;
404  int z = -1;
405  if (loglambda) {
406  z = lround(crval3 / cd33 * log(lbda[n] / crval3)) + crpix3 - 1;
407  } else {
408  z = lround((lbda[n] - crval3) / cd33 + crpix3) - 1;
409  }
410  if (z < z1 || z > z2) {
411  continue; /* skip this entry, one of the other threads handles it */
412  }
413 
414  /* determine the pixel coordinates in the grid (indices, starting at 0) */
415  double xpx, ypx;
416  if (wcs->iscelsph) {
417  muse_wcs_pixel_from_celestial_fast(wcs, (xpos[n] + ptxoff) / CPL_MATH_DEG_RAD,
418  (ypos[n] + ptyoff) / CPL_MATH_DEG_RAD,
419  &xpx, &ypx);
420  } else {
421  muse_wcs_pixel_from_projplane_fast(wcs, xpos[n], ypos[n],
422  &xpx, &ypx);
423  }
424  int x = lround(xpx) - 1,
425  y = lround(ypx) - 1;
426  cpl_size idx = muse_pixgrid_get_index(grid, x, y, z, CPL_TRUE);
427 #ifdef ESO_ENABLE_DEBUG
428  if (debug) {
429  printf("%"CPL_SIZE_FORMAT": %f %f %f -> %d %d %d (%"CPL_SIZE_FORMAT")\n",
430  n, xpos[n] + ptxoff, ypos[n] + ptyoff, lbda[n], x, y, z, idx);
431  }
432 #endif
433 
434  /* write the pixel values to the correct place in the grid */
435  muse_pixgrid_add(grid, idx, n, ithread);
436  } /* for isel (all selected pixel table rows) */
437 
438  /* Clean up the possibly too many allocations; this is not strictly *
439  * needed but nice to only consume as much memory as we need. */
440  grid->xmaps[ithread] = cpl_realloc(grid->xmaps[ithread],
441  grid->nxmap[ithread]
442  * sizeof(muse_pixels_ext));
443  grid->nxalloc[ithread] = grid->nxmap[ithread];
444  } /* omp parallel */
445  cpl_array_delete(asel);
446  cpl_free(wcs);
447  cpl_array_delete(az1);
448  cpl_array_delete(az2);
449 #ifdef ESO_ENABLE_DEBUG
450  if (debug) {
451  fflush(stdout);
452  }
453 #endif
454 
455  cpl_size idx, npix = 0;
456  for (idx = 0; idx < aXSize * aYSize * aZSize; idx++) {
457  npix += muse_pixgrid_get_count(grid, idx);
458  }
459  cpl_size nxmap = 0;
460  for (idx = 0; idx < (cpl_size)grid->nmaps; idx++) {
461  nxmap += grid->nxmap[idx];
462  }
463  if (npix != nsel) {
464  char *msg = cpl_sprintf("Pixels got lost while creating the cube (input "
465  "pixel table: %"CPL_SIZE_FORMAT", output pixel grid"
466  ": %"CPL_SIZE_FORMAT")", nsel, npix);
467  cpl_msg_error(__func__, "%s:", msg);
468  muse_pixgrid_dump_xmaps(grid, CPL_FALSE);
469  cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT, "%s!", msg);
470  cpl_free(msg);
471  }
472  double timefini = cpl_test_get_walltime(),
473  cpufini = cpl_test_get_cputime();
474  cpl_msg_debug(__func__, "pixel grid: %dx%dx%d, %"CPL_SIZE_FORMAT" pixels "
475  "total, %"CPL_SIZE_FORMAT" (%.1f%%) in %hu extension maps; took"
476  " %gs (wall-clock) and %gs (CPU) to create", (int)grid->nx,
477  (int)grid->ny, (int)grid->nz, npix, nxmap,
478  (double)nxmap / npix * 100., grid->nmaps, timefini - timeinit,
479  cpufini - cpuinit);
480 
481  return grid;
482 } /* muse_pixgrid_create() */
483 
484 /*---------------------------------------------------------------------------*/
505 /*---------------------------------------------------------------------------*/
506 muse_pixgrid *
507 muse_pixgrid_2d_create(cpl_table *aTable, double aDX,
508  double aZMin, double aZMax, double aDZ, float *aXMin)
509 {
510  cpl_ensure(aTable, CPL_ERROR_NULL_INPUT, NULL);
511  cpl_size nrow = cpl_table_get_nrow(aTable);
512  if (nrow == 0) {
513  cpl_msg_error(__func__, "Invalid pixel table (no entries?)");
514  cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
515  return NULL;
516  }
517 
518  /* get the (relevant) table columns for easy pointer access */
519  float *xpos = cpl_table_get_data_float(aTable, MUSE_PIXTABLE_XPOS),
520  *lbda = cpl_table_get_data_float(aTable, MUSE_PIXTABLE_LAMBDA);
521  if (!xpos || !lbda) {
522  cpl_msg_error(__func__, "Missing pixel table column (%p %p): %s",
523  (void *)xpos, (void *)lbda, cpl_error_get_message());
524  cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
525  return NULL;
526  }
527 
528  /* get the selection for fast access to the relevant rows */
529  cpl_array *selection = cpl_table_where_selected(aTable);
530  cpl_size nsel = cpl_array_get_size(selection);
531  const cpl_size *sel = cpl_array_get_data_cplsize_const(selection);
532 
533  /* search for lowest x value in selected rows */
534  float xlo = FLT_MAX, xhi = -FLT_MAX;
535  cpl_size i;
536  for (i = 0; i < nsel; i++) {
537  if (xpos[sel[i]] > xhi) xhi = xpos[sel[i]];
538  if (xpos[sel[i]] < xlo) xlo = xpos[sel[i]];
539  } /* for i (all selected pixel table rows) */
540  if (aXMin) {
541  *aXMin = xlo;
542  }
543 
544  /* create the empty 2D grid depending on size of input data */
545  cpl_size xsize = ceil((xhi - xlo) / aDX) + 1,
546  zsize = ceil((aZMax - aZMin) / aDZ) + 1;
547  muse_pixgrid *grid = muse_pixgrid_new(xsize, 1, zsize, 1);
548 
549  /* loop through the pixel table and write values into the pixel grid */
550  for (i = 0; i < nsel; i++) {
551  /* determine the pixel coordinates in the grid; offset is min-1 to *
552  * have all these indices start at 0 for easy buffer access */
553  int x = lround((xpos[sel[i]] - xlo) / aDX),
554  z = lround((lbda[sel[i]] - aZMin) / aDZ);
555  cpl_size idx = muse_pixgrid_get_index(grid, x, 0, z, CPL_TRUE);
556  /* write the pixel values to the correct place in the grid */
557  muse_pixgrid_add(grid, idx, sel[i], 0);
558  } /* for i (all selected pixel table rows) */
559  cpl_array_delete(selection);
560  /* clean up the possibly too many allocations */
561  grid->xmaps[0] = cpl_realloc(grid->xmaps[0],
562  grid->nxmap[0] * sizeof(muse_pixels_ext));
563  grid->nxalloc[0] = grid->nxmap[0];
564 
565  return grid;
566 } /* muse_pixgrid_2d_create() */
567 
568 /*---------------------------------------------------------------------------*/
573 /*---------------------------------------------------------------------------*/
574 void
576 {
577  if (!aGrid) {
578  return;
579  }
580  cpl_free(aGrid->pix);
581  aGrid->pix = NULL;
582  /* clean up extension maps */
583  unsigned short ix;
584  for (ix = 0; ix < aGrid->nmaps; ix++) {
585  cpl_size iext; /* index in this extension map */
586  for (iext = 0; iext < aGrid->nxalloc[ix]; iext++) {
587  cpl_free(aGrid->xmaps[ix][iext].pix);
588  } /* for iext (all allocated pixels in this extension map) */
589 
590  cpl_free(aGrid->xmaps[ix]);
591  } /* for ix (all extension maps) */
592  cpl_free(aGrid->xmaps);
593  aGrid->xmaps = NULL;
594  cpl_free(aGrid->nxmap);
595  aGrid->nxmap = NULL;
596  cpl_free(aGrid->nxalloc);
597  aGrid->nxalloc = NULL;
598  cpl_free(aGrid);
599 } /* muse_pixgrid_delete() */
600 
double crpix2
Definition: muse_wcs.h:106
#define MUSE_PIXTABLE_XPOS
Definition: muse_pixtable.h:51
muse_pixtable_wcs
State of the astrometric calibration of a MUSE pixel table.
double muse_pfits_get_cd(const cpl_propertylist *aHeaders, unsigned int aAxisI, unsigned int aAxisJ)
find out the WCS coordinate at the reference point
Definition: muse_pfits.c:446
muse_pixgrid * muse_pixgrid_2d_create(cpl_table *aTable, double aDX, double aZMin, double aZMax, double aDZ, float *aXMin)
Convert selected rows of a pixel table into 2D pixel grid, linking the grid points to entries (=rows)...
Definition: muse_pixgrid.c:507
double muse_pfits_get_crval(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS coordinate at the reference point
Definition: muse_pfits.c:423
A structure containing a spatial two-axis WCS.
Definition: muse_wcs.h:105
double cd22
Definition: muse_wcs.h:108
muse_pixgrid * muse_pixgrid_create(muse_pixtable *aPixtable, cpl_propertylist *aHeader, cpl_size aXSize, cpl_size aYSize, cpl_size aZSize)
Convert selected rows of a pixel table into pixel grid, linking the grid points to entries (=rows) in...
Definition: muse_pixgrid.c:237
cpl_size muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
get the number of rows within the pixel table
static void muse_wcs_pixel_from_projplane_fast(muse_wcs *aWCS, double aX, double aY, double *aXOut, double *aYOut)
Convert from projection plane coordinates to pixel coordinates.
Definition: muse_wcs.h:245
The pixel extension map.
Definition: muse_pixgrid.h:55
The pixel grid.
Definition: muse_pixgrid.h:65
cpl_table * table
The pixel table.
double muse_pfits_get_crpix(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS reference point
Definition: muse_pfits.c:401
void muse_pixgrid_delete(muse_pixgrid *aGrid)
Delete a pixel grid and remove its memory.
Definition: muse_pixgrid.c:575
muse_wcs * muse_wcs_new(cpl_propertylist *aHeader)
Create a new WCS structure from a given FITS header.
Definition: muse_wcs.c:1870
Structure definition of MUSE pixel table.
muse_pixtable_wcs muse_pixtable_wcs_check(muse_pixtable *aPixtable)
Check the state of the world coordinate system of a pixel table.
static void muse_wcs_pixel_from_celestial_fast(muse_wcs *aWCS, double aRA, double aDEC, double *aX, double *aY)
Convert from celestial spherical coordinates to pixel coordinates.
Definition: muse_wcs.h:176
const char * muse_pfits_get_ctype(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS axis type string
Definition: muse_pfits.c:469
#define MUSE_PIXTABLE_LAMBDA
Definition: muse_pixtable.h:53
static cpl_size muse_pixgrid_get_index(muse_pixgrid *aGrid, cpl_size aX, cpl_size aY, cpl_size aZ, cpl_boolean aAllowOutside)
Get the grid index determined from all three coordinates.
Definition: muse_pixgrid.h:100
cpl_boolean iscelsph
Definition: muse_wcs.h:112
double crval2
Definition: muse_wcs.h:107
#define MUSE_PIXTABLE_YPOS
Definition: muse_pixtable.h:52
static cpl_size muse_pixgrid_get_count(muse_pixgrid *aGrid, cpl_size aIndex)
Return the number of rows stored in one pixel.
Definition: muse_pixgrid.h:140
cpl_propertylist * header
The FITS header.