LALPulsar  6.1.0.1-fe68b98
CacheResults.c
Go to the documentation of this file.
1 //
2 // Copyright (C) 2016, 2017 Karl Wette
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with with program; see the file COPYING. If not, write to the
16 // Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 // MA 02110-1301 USA
18 //
19 
20 ///
21 /// \file
22 /// \ingroup lalpulsar_bin_Weave
23 ///
24 
25 #include "CacheResults.h"
26 
27 #include <lal/LALHeap.h>
28 #include <lal/LALHashTbl.h>
29 #include <lal/LALBitset.h>
30 
31 // Compare two quantities, and return a sort order value if they are unequal
32 #define COMPARE_BY( x, y ) do { if ( (x) < (y) ) return -1; if ( (x) > (y) ) return +1; } while(0)
33 
34 ///
35 /// Item stored in the cache
36 ///
37 typedef struct {
38  /// Generation, used both to find items in cache and to decide how long to keep items
40  /// Relevance, used to decide how long to keep items
42  /// Coherent locator index, used to find items in cache
44  /// Results of a coherent computation on a single segment
45  WeaveCohResults *coh_res;
46 } cache_item;
47 
48 ///
49 /// Container for a series of cache queries
50 ///
52  /// Number of parameter-space dimensions
53  size_t ndim;
54  /// Lowest tiled parameter-space dimension
55  size_t dim0;
56  // Frequency spacing used by lattices
57  double dfreq;
58  /// Number of queries for which space is allocated
60  /// Number of partitions to divide semicoherent frequency block into
62  /// Index to current partition of semicoherent frequency block
64  /// Offset to apply to coherent left-most index to enclose a frequency partition
66  /// Offset to apply to coherent right-most index to enclose a frequency partition
68  /// Sequential indexes for each queried coherent frequency block
70  /// Physical points of each queried coherent frequency block
72  /// Indexes of left-most point in queried coherent frequency block
74  /// Indexes of right-most point in queried coherent frequency block
76  /// Relevance of each queried coherent frequency block
78  /// Number of computed coherent results (per query)
80  /// Number of coherent templates (per query)
82  /// Reduced supersky transform data for semicoherent lattice
83  const SuperskyTransformData *semi_rssky_transf;
84  /// Sequential index for the current semicoherent frequency block
86  // Current semicoherent frequency block in dimension 'dim0'
88  /// Physical coordinates of the current semicoherent frequency block
90  /// Index of left-most point in current semicoherent frequency block
92  /// Index of right-most point in current semicoherent frequency block
94  /// Relevance of the current semicoherent frequency block
96  /// Offset used in computation of semicoherent point relevance
98  /// Number of semicoherent templates (over all queries)
100 };
101 
102 ///
103 /// Cache used to store coherent results
104 ///
106  /// Number of parameter-space dimensions
107  size_t ndim;
108  /// Lowest tiled parameter-space dimension
109  size_t dim0;
110  /// Reduced supersky transform data for coherent lattice
111  const SuperskyTransformData *coh_rssky_transf;
112  /// Reduced supersky transform data for semicoherent lattice
113  const SuperskyTransformData *semi_rssky_transf;
114  /// Input data required for computing coherent results
115  WeaveCohInput *coh_input;
116  /// Coherent parameter-space tiling locator
117  LatticeTilingLocator *coh_locator;
118  /// Maximum value of index from coherent locator
120  /// Current generation of cache items
122  /// Heap which ranks cache items by relevance
123  LALHeap *relevance_heap;
124  /// Maximum size obtained by relevance heap
126  /// Hash table which looks up cache items by index
127  LALHashTbl *coh_index_hash;
128  /// Bitset which records whether an item has ever been computed
130  /// Offset used in computation of coherent point relevance
132  /// Whether any garbage collection of results should be used
134  /// Whether garbage collection should remove as many results as possible
136  /// Save an no-longer-used cache item for re-use
138 };
139 
140 ///
141 /// \name Internal functions
142 ///
143 /// @{
144 
145 static int cache_left_right_offsets( const UINT4 semi_nfreqs, const UINT4 nfreq_partitions, const UINT4 freq_partition_index, INT4 *left_offset, INT4 *right_offset );
146 static int cache_max_semi_bbox_sample_dim0( const WeaveCache *cache, const LatticeTiling *coh_tiling, const size_t i, gsl_vector *coh_bbox_sample, gsl_vector *semi_bbox_sample, double *max_semi_bbox_sample_dim0 );
147 static UINT8 cache_item_hash( const void *x );
148 static int cache_item_compare_by_coh_index( const void *x, const void *y );
149 static int cache_item_compare_by_relevance( const void *x, const void *y );
150 static void cache_item_destroy( void *x );
151 
152 /// @}
153 
154 ///
155 /// Destroy a cache item
156 ///
158  void *x
159 )
160 {
161  if ( x != NULL ) {
162  cache_item *ix = ( cache_item * ) x;
164  XLALFree( ix );
165  }
166 }
167 
168 ///
169 /// Compare cache items by generation, then relevance
170 ///
172  const void *x,
173  const void *y
174 )
175 {
176  const cache_item *ix = ( const cache_item * ) x;
177  const cache_item *iy = ( const cache_item * ) y;
178  COMPARE_BY( ix->generation, iy->generation ); // Compare in ascending order
179  COMPARE_BY( ix->relevance, iy->relevance ); // Compare in ascending order
180  return 0;
181 }
182 
183 ///
184 /// Compare cache items by generation, then locator index
185 ///
187  const void *x,
188  const void *y
189 )
190 {
191  const cache_item *ix = ( const cache_item * ) x;
192  const cache_item *iy = ( const cache_item * ) y;
193  COMPARE_BY( ix->generation, iy->generation ); // Compare in ascending order
194  COMPARE_BY( ix->coh_index, iy->coh_index ); // Compare in ascending order
195  return 0;
196 }
197 
198 ///
199 /// Hash cache items by generation and locator index
200 ///
202  const void *x
203 )
204 {
205  const cache_item *ix = ( const cache_item * ) x;
206  UINT4 hval = 0;
207  XLALPearsonHash( &hval, sizeof( hval ), &ix->generation, sizeof( ix->generation ) );
208  XLALPearsonHash( &hval, sizeof( hval ), &ix->coh_index, sizeof( ix->coh_index ) );
209  return hval;
210 }
211 
212 ///
213 /// Sample points on surface of coherent bounding box, convert to semicoherent supersky
214 /// coordinates, and record maximum value of semicoherent coordinate in dimension 'dim0'
215 ///
217  const WeaveCache *cache,
218  const LatticeTiling *coh_tiling,
219  const size_t i,
220  gsl_vector *coh_bbox_sample,
221  gsl_vector *semi_bbox_sample,
222  double *max_semi_bbox_sample_dim0
223 )
224 {
225 
226  if ( i < cache->ndim ) {
227 
228  // Get coherent lattice tiling bounding box in dimension 'i'
229  const double coh_bbox_i = XLALLatticeTilingBoundingBox( coh_tiling, i );
231 
232  // Get current value of 'coh_bbox_sample' in dimension 'i'
233  const double coh_bbox_sample_i = gsl_vector_get( coh_bbox_sample, i );
234 
235  // Move 'coh_bbox_sample' in dimension 'i' to vertices, edge centres and face centres of bounding box, and proceed to higher dimensions
236  for ( int step = -1; step <= 1; ++ step ) {
237  gsl_vector_set( coh_bbox_sample, i, coh_bbox_sample_i - step * 0.5 * coh_bbox_i );
238  XLAL_CHECK( cache_max_semi_bbox_sample_dim0( cache, coh_tiling, i + 1, coh_bbox_sample, semi_bbox_sample, max_semi_bbox_sample_dim0 ) == XLAL_SUCCESS, XLAL_EFUNC );
239  }
240 
241  // Restore current value of 'coh_bbox_sample' in dimension 'i'
242  gsl_vector_set( coh_bbox_sample, i, coh_bbox_sample_i );
243 
244  } else {
245 
246  // Convert 'coh_bbox_sample' to semicoherent reduced supersky coordinates
247  XLAL_CHECK( XLALConvertSuperskyToSuperskyPoint( semi_bbox_sample, cache->semi_rssky_transf, coh_bbox_sample, coh_bbox_sample, cache->coh_rssky_transf ) == XLAL_SUCCESS, XLAL_EINVAL );
248 
249  // Record maximum value of semicoherent coordinate in dimension 'dim0'
250  *max_semi_bbox_sample_dim0 = GSL_MAX( *max_semi_bbox_sample_dim0, gsl_vector_get( semi_bbox_sample, cache->dim0 ) );
251 
252  }
253 
254  return XLAL_SUCCESS;
255 
256 }
257 
258 ///
259 /// Compute left/right-most index offsets to select a given partition
260 ///
262  const UINT4 semi_nfreqs,
263  const UINT4 nfreq_partitions,
264  const UINT4 freq_partition_index,
265  INT4 *left_offset,
266  INT4 *right_offset
267 )
268 {
269 
270  // Minimum number of points in the current frequency partition
271  const UINT4 min_part_nfreqs = semi_nfreqs / nfreq_partitions;
272 
273  // Excess number of points which must be added to get 'semi_nfreqs' in total
274  INT4 excess_nfreqs = semi_nfreqs - nfreq_partitions * min_part_nfreqs;
275 
276  // Initialise number of points in this frequency partition
277  // - If there are excess points, add an extra point
278  INT4 part_nfreqs = min_part_nfreqs;
279  if ( excess_nfreqs > 0 ) {
280  ++part_nfreqs;
281  }
282 
283  // Compute offsets to left/right-most indexes to the select each given partition
284  // - Add 'part_nfreqs' to '*left_offset' for each increase in partition index
285  // - Decrease number of excess points; if zero, subtract extra point from 'part_nfreqs'
286  *left_offset = 0;
287  for ( size_t i = 0; i < freq_partition_index; ++i ) {
288  *left_offset += part_nfreqs;
289  --excess_nfreqs;
290  if ( excess_nfreqs == 0 ) {
291  --part_nfreqs;
292  }
293  }
294  *right_offset = *left_offset + part_nfreqs - semi_nfreqs;
295  XLAL_CHECK( *left_offset >= 0, XLAL_EDOM );
296  XLAL_CHECK( *right_offset <= 0, XLAL_EDOM );
297 
298  return XLAL_SUCCESS;
299 
300 }
301 
302 ///
303 /// Create storage for a series of cache queries
304 ///
305 WeaveCacheQueries *XLALWeaveCacheQueriesCreate(
306  const LatticeTiling *semi_tiling,
307  const SuperskyTransformData *semi_rssky_transf,
308  const double dfreq,
309  const UINT4 nqueries,
310  const UINT4 nfreq_partitions
311 )
312 {
313 
314  // Check input
315  XLAL_CHECK_NULL( semi_tiling != NULL, XLAL_EFAULT );
317  XLAL_CHECK_NULL( nqueries > 0, XLAL_EINVAL );
318  XLAL_CHECK_NULL( nfreq_partitions > 0, XLAL_EINVAL );
319 
320  // Allocate memory
321  WeaveCacheQueries *queries = XLALCalloc( 1, sizeof( *queries ) );
322  XLAL_CHECK_NULL( queries != NULL, XLAL_ENOMEM );
323  queries->coh_part_left_offset = XLALCalloc( nfreq_partitions, sizeof( *queries->coh_part_left_offset ) );
324  XLAL_CHECK_NULL( queries->coh_part_left_offset != NULL, XLAL_ENOMEM );
325  queries->coh_part_right_offset = XLALCalloc( nfreq_partitions, sizeof( *queries->coh_part_right_offset ) );
326  XLAL_CHECK_NULL( queries->coh_part_right_offset != NULL, XLAL_ENOMEM );
327  queries->coh_index = XLALCalloc( nqueries, sizeof( *queries->coh_index ) );
328  XLAL_CHECK_NULL( queries->coh_index != NULL, XLAL_ENOMEM );
329  queries->coh_phys = XLALCalloc( nqueries, sizeof( *queries->coh_phys ) );
330  XLAL_CHECK_NULL( queries->coh_phys != NULL, XLAL_ENOMEM );
331  queries->coh_left = XLALCalloc( nqueries, sizeof( *queries->coh_left ) );
332  XLAL_CHECK_NULL( queries->coh_left != NULL, XLAL_ENOMEM );
333  queries->coh_right = XLALCalloc( nqueries, sizeof( *queries->coh_right ) );
334  XLAL_CHECK_NULL( queries->coh_right != NULL, XLAL_ENOMEM );
335  queries->coh_relevance = XLALCalloc( nqueries, sizeof( *queries->coh_relevance ) );
336  XLAL_CHECK_NULL( queries->coh_relevance != NULL, XLAL_ENOMEM );
337  queries->coh_nres = XLALCalloc( nqueries, sizeof( *queries->coh_nres ) );
338  XLAL_CHECK_NULL( queries->coh_nres != NULL, XLAL_ENOMEM );
339  queries->coh_ntmpl = XLALCalloc( nqueries, sizeof( *queries->coh_ntmpl ) );
340  XLAL_CHECK_NULL( queries->coh_ntmpl != NULL, XLAL_ENOMEM );
341 
342  // Set fields
343  queries->semi_rssky_transf = semi_rssky_transf;
344  queries->dfreq = dfreq;
345  queries->nqueries = nqueries;
346  queries->nfreq_partitions = nfreq_partitions;
347 
348  // Get number of parameter-space dimensions
349  queries->ndim = XLALTotalLatticeTilingDimensions( semi_tiling );
351 
352  // Get lowest tiled parameter-space dimension
353  if ( XLALTiledLatticeTilingDimensions( semi_tiling ) > 0 ) {
354  queries->dim0 = XLALLatticeTilingTiledDimension( semi_tiling, 0 );
355  } else {
356  queries->dim0 = 0;
357  }
359 
360  // Compute offset used in computation of semicoherent point relevance:
361  // - Negative half of semicoherent lattice tiling bounding box in dimension 'dim0'
362  queries->semi_relevance_offset = -0.5 * XLALLatticeTilingBoundingBox( semi_tiling, queries->dim0 );
364 
365  // Minimum number of points in a semicoherent frequency block
366  const LatticeTilingStats *stats = XLALLatticeTilingStatistics( semi_tiling, queries->ndim - 1 );
367  XLAL_CHECK_NULL( stats != NULL, XLAL_EFUNC );
368  XLAL_CHECK_NULL( stats->min_points > 0, XLAL_EFAILED );
369 
370  // Compute offsets to coherent left/right-most indexes to enclose each frequency partition
371  // - Use 'semi_min_freqs' to make offsets less than or equal to any semicoherent offsets
372  for ( size_t i = 0; i < queries->nfreq_partitions; ++i ) {
373  XLAL_CHECK_NULL( cache_left_right_offsets( stats->min_points, queries->nfreq_partitions, i, &queries->coh_part_left_offset[i], &queries->coh_part_right_offset[i] ) == XLAL_SUCCESS, XLAL_EFUNC );
374  }
375 
376  return queries;
377 
378 }
379 
380 ///
381 /// Destroy storage for a series of cache queries
382 ///
384  WeaveCacheQueries *queries
385 )
386 {
387  if ( queries != NULL ) {
388  XLALFree( queries->coh_part_left_offset );
389  XLALFree( queries->coh_part_right_offset );
390  XLALFree( queries->coh_index );
391  XLALFree( queries->coh_phys );
392  XLALFree( queries->coh_left );
393  XLALFree( queries->coh_right );
394  XLALFree( queries->coh_relevance );
395  XLALFree( queries->coh_nres );
396  XLALFree( queries->coh_ntmpl );
397  XLALFree( queries );
398  }
399 }
400 
401 ///
402 /// Initialise a series of cache queries
403 ///
405  WeaveCacheQueries *queries,
406  const UINT8 semi_index,
407  const gsl_vector *semi_rssky,
408  const INT4 semi_left,
409  const INT4 semi_right,
410  const UINT4 freq_partition_index
411 )
412 {
413 
414  // Check input
415  XLAL_CHECK( queries != NULL, XLAL_EFAULT );
416  XLAL_CHECK( semi_rssky != NULL, XLAL_EFAULT );
417  XLAL_CHECK( freq_partition_index < queries->nfreq_partitions, XLAL_EINVAL );
418 
419  // Reset coherent sequential indexes to zero, indicating no query
420  memset( queries->coh_index, 0, queries->nqueries * sizeof( queries->coh_index[0] ) );
421 
422  // Save current semicoherent sequential index
423  queries->semi_index = semi_index;
424 
425  // Save current semicoherent frequency block in dimension 'dim0'
426  queries->semi_rssky_dim0 = gsl_vector_get( semi_rssky, queries->dim0 );
427 
428  // Convert semicoherent point to physical coordinates
429  XLAL_CHECK( XLALConvertSuperskyToPhysicalPoint( &queries->semi_phys, semi_rssky, NULL, queries->semi_rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC );
430 
431  // Save indexes of left/right-most point in current semicoherent frequency block
432  queries->semi_left = semi_left;
433  queries->semi_right = semi_right;
434 
435  // Save index to current partition of semicoherent frequency block
436  queries->freq_partition_index = freq_partition_index;
437 
438  // Compute the relevance of the current semicoherent frequency block
439  // - Relevance is semicoherent reduced supersky point in dimension 'dim0', plus offset
440  queries->semi_relevance = gsl_vector_get( semi_rssky, queries->dim0 ) + queries->semi_relevance_offset;
441 
442  return XLAL_SUCCESS;
443 
444 }
445 
446 ///
447 /// Query a cache for the results nearest to a given coherent point
448 ///
450  const WeaveCache *cache,
451  WeaveCacheQueries *queries,
452  const UINT4 query_index
453 )
454 {
455 
456  // Check input
457  XLAL_CHECK( cache != NULL, XLAL_EFAULT );
458  XLAL_CHECK( queries != NULL, XLAL_EFAULT );
459  XLAL_CHECK( cache->ndim == queries->ndim, XLAL_ESIZE );
460  XLAL_CHECK( cache->dim0 == queries->dim0, XLAL_ESIZE );
461  XLAL_CHECK( query_index < queries->nqueries, XLAL_EINVAL );
462 
463  // Convert semicoherent physical point to coherent reduced supersky coordinates
464  double coh_point_array[cache->ndim];
465  gsl_vector_view coh_point_view = gsl_vector_view_array( coh_point_array, cache->ndim );
466  XLAL_CHECK( XLALConvertPhysicalToSuperskyPoint( &coh_point_view.vector, &queries->semi_phys, cache->coh_rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC );
467 
468  // Initialise nearest point to semicoherent point in coherent reduced supersky coordinates
469  double coh_near_point_array[cache->ndim];
470  gsl_vector_view coh_near_point_view = gsl_vector_view_array( coh_near_point_array, cache->ndim );
471  gsl_vector_memcpy( &coh_near_point_view.vector, &coh_point_view.vector );
472 
473  // Initialise values for a non-interpolating search
474  queries->coh_index[query_index] = queries->semi_index;
475  queries->coh_left[query_index] = queries->semi_left;
476  queries->coh_right[query_index] = queries->semi_right;
477 
478  // If performing an interpolating search, find the nearest coherent frequency pass in this segment
479  // - 'coh_near_point' is set to the nearest point to the mid-point of the semicoherent frequency block
480  // - 'coh_index' is set to the index of this coherent frequency block, used for cache lookup
481  // - 'coh_left' and 'coh_right' are set of number of points to the left/right of 'coh_near_point';
482  // check that these are sufficient to contain the number of points to the left/right of 'semi_rssky'
483  if ( cache->coh_locator != NULL ) {
484  XLAL_CHECK( XLALNearestLatticeTilingBlock( cache->coh_locator, &coh_point_view.vector, cache->ndim - 1, &coh_near_point_view.vector, &queries->coh_index[query_index], &queries->coh_left[query_index], &queries->coh_right[query_index] ) == XLAL_SUCCESS, XLAL_EFUNC );
485  XLAL_CHECK( queries->coh_index[query_index] < cache->coh_max_index, XLAL_EFAILED, "Coherent index %"LAL_UINT8_FORMAT" out of range [0,%"LAL_UINT8_FORMAT") at semicoherent index %"LAL_UINT8_FORMAT", query index %u", queries->coh_index[query_index], cache->coh_max_index, queries->semi_index, query_index );
486  XLAL_CHECK( queries->coh_left[query_index] <= queries->coh_right[query_index], XLAL_EINVAL );
487  XLAL_CHECK( queries->coh_left[query_index] <= queries->semi_left && queries->semi_right <= queries->coh_right[query_index], XLAL_EFAILED, "Range of coherent tiling [%i,%i] does not contain semicoherent tiling [%i,%i] at semicoherent index %"LAL_UINT8_FORMAT", query index %u", queries->coh_left[query_index], queries->coh_right[query_index], queries->semi_left, queries->semi_right, queries->semi_index, query_index );
488  }
489 
490  // Make 'coh_index' a 1-based index, so zero can be used to indicate a missing query
491  ++queries->coh_index[query_index];
492 
493  // Convert nearest coherent point to physical coordinates
494  XLAL_INIT_MEM( queries->coh_phys[query_index] );
495  XLAL_CHECK( XLALConvertSuperskyToPhysicalPoint( &queries->coh_phys[query_index], &coh_near_point_view.vector, &coh_point_view.vector, cache->coh_rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC );
496 
497  // Compute the relevance of the current coherent frequency block:
498  // - Convert nearest coherent point to semicoherent reduced supersky coordinates
499  // - Relevance is nearest coherent point in semicoherent reduced supersky coordinates in dimension 'dim0', plus offset
500  {
501  double semi_near_point_array[cache->ndim];
502  gsl_vector_view semi_near_point_view = gsl_vector_view_array( semi_near_point_array, cache->ndim );
503  XLAL_CHECK( XLALConvertSuperskyToSuperskyPoint( &semi_near_point_view.vector, cache->semi_rssky_transf, &coh_near_point_view.vector, &coh_point_view.vector, cache->coh_rssky_transf ) == XLAL_SUCCESS, XLAL_EINVAL );
504  const double semi_near_point_dim0 = gsl_vector_get( &semi_near_point_view.vector, cache->dim0 );
505  queries->coh_relevance[query_index] = GSL_MAX( semi_near_point_dim0, queries->semi_rssky_dim0 ) + cache->coh_relevance_offset;
506  }
507 
508  return XLAL_SUCCESS;
509 
510 }
511 
512 ///
513 /// Finalise a series of cache queries
514 ///
516  WeaveCacheQueries *queries,
517  PulsarDopplerParams *semi_phys,
518  UINT4 *semi_nfreqs
519 )
520 {
521 
522  // Check input
523  XLAL_CHECK( queries != NULL, XLAL_EFAULT );
524  XLAL_CHECK( semi_phys != NULL, XLAL_EFAULT );
525  XLAL_CHECK( semi_nfreqs != NULL, XLAL_EFAULT );
526 
527  // Check that every 'coh_index' is at least 1, i.e. a query was made
528  for ( size_t i = 0; i < queries->nqueries; ++i ) {
529  XLAL_CHECK( queries->coh_index[i] > 0, XLAL_EINVAL, "Missing query at index %zu", i );
530  }
531 
532  // Compute the total number of points in the semicoherent frequency block
533  *semi_nfreqs = queries->semi_right - queries->semi_left + 1;
534 
535  // Compute offsets to semicoherent left/right-most indexes to select each frequency partition
536  INT4 semi_part_left_offset = 0, semi_part_right_offset = 0;
537  XLAL_CHECK( cache_left_right_offsets( *semi_nfreqs, queries->nfreq_partitions, queries->freq_partition_index, &semi_part_left_offset, &semi_part_right_offset ) == XLAL_SUCCESS, XLAL_EFUNC );
538  XLAL_CHECK( queries->coh_part_left_offset[queries->freq_partition_index] <= semi_part_left_offset && semi_part_right_offset <= queries->coh_part_right_offset[queries->freq_partition_index], XLAL_EFAILED );
539 
540  // Adjust semicoherent left/right-most indexes to select the given partition
541  // - If there are fewer points in the semicoherent frequency block than partitions,
542  // then some partitions will have 'semi_right' < 'semi_left', i.e. no points. In
543  // which set '*semi_nfreqs' to zero indicates that this partition should be skipped
544  // for this semicoherent frequency block
545  queries->semi_left += semi_part_left_offset;
546  queries->semi_right += semi_part_right_offset;
547  if ( queries->semi_right < queries->semi_left ) {
548  *semi_nfreqs = 0;
549  return XLAL_SUCCESS;
550  }
551 
552  // Compute the total number of points in the semicoherent frequency block partition
553  *semi_nfreqs = queries->semi_right - queries->semi_left + 1;
554 
555  // Adjust coherent left/right-most indexes to enclose the given partition
556  for ( size_t i = 0; i < queries->nqueries; ++i ) {
557  queries->coh_left[i] += queries->coh_part_left_offset[queries->freq_partition_index];
558  queries->coh_right[i] += queries->coh_part_right_offset[queries->freq_partition_index];
559  }
560 
561  // Shift physical frequencies to first point in coherent/semicoherent frequency block partition
562  queries->semi_phys.fkdot[0] += queries->dfreq * queries->semi_left;
563  for ( size_t i = 0; i < queries->nqueries; ++i ) {
564  queries->coh_phys[i].fkdot[0] += queries->dfreq * queries->coh_left[i];
565  }
566 
567  // Return first point in semicoherent frequency block partition
568  *semi_phys = queries->semi_phys;
569 
570  // Increment number of semicoherent templates
571  queries->semi_ntmpl += *semi_nfreqs;
572 
573  return XLAL_SUCCESS;
574 
575 }
576 
577 ///
578 /// Get number of computed coherent results, and number of coherent and semicoherent templates
579 ///
581  const WeaveCacheQueries *queries,
582  UINT8 *coh_nres,
583  UINT8 *coh_ntmpl,
584  UINT8 *semi_ntmpl
585 )
586 {
587 
588  // Check input
589  XLAL_CHECK( queries != NULL, XLAL_EFAULT );
590  XLAL_CHECK( coh_nres != NULL, XLAL_EFAULT );
591  XLAL_CHECK( coh_ntmpl != NULL, XLAL_EFAULT );
592  XLAL_CHECK( semi_ntmpl != NULL, XLAL_EFAULT );
593 
594  // Return number of computed coherent results
595  *coh_nres = 0;
596  for ( size_t i = 0; i < queries->nqueries; ++i ) {
597  *coh_nres += queries->coh_nres[i];
598  }
599 
600  // Return number of computed coherent templates
601  *coh_ntmpl = 0;
602  for ( size_t i = 0; i < queries->nqueries; ++i ) {
603  *coh_ntmpl += queries->coh_ntmpl[i];
604  }
605 
606  // Write number of semicoherent templates
607  *semi_ntmpl = queries->semi_ntmpl;
608 
609  return XLAL_SUCCESS;
610 
611 }
612 
613 ///
614 /// Create a cache
615 ///
617  const LatticeTiling *coh_tiling,
618  const BOOLEAN interpolation,
619  const SuperskyTransformData *coh_rssky_transf,
620  const SuperskyTransformData *semi_rssky_transf,
621  WeaveCohInput *coh_input,
622  const UINT4 max_size,
623  const BOOLEAN all_gc
624 )
625 {
626 
627  // Check input
628  XLAL_CHECK_NULL( coh_tiling != NULL, XLAL_EFAULT );
629  XLAL_CHECK_NULL( coh_input != NULL, XLAL_EFAULT );
630 
631  // Allocate memory
632  WeaveCache *cache = XLALCalloc( 1, sizeof( *cache ) );
633  XLAL_CHECK_NULL( cache != NULL, XLAL_ENOMEM );
634 
635  // Set fields
636  cache->coh_rssky_transf = coh_rssky_transf;
637  cache->semi_rssky_transf = semi_rssky_transf;
638  cache->coh_input = coh_input;
639  cache->generation = 0;
640 
641  // Set garbage collection mode:
642  // - Garbage collection is not performed for a fixed-size cache (i.e. 'max_size > 0'),
643  // i.e. the cache will only discard items once the fixed-size cache is full, but not
644  // try to remove cache items earlier based on their relevances
645  // - Garbage collection is applied to as many items as possible if 'all_gc' is true
646  cache->any_gc = ( max_size == 0 );
647  cache->all_gc = all_gc;
648 
649  // Get number of parameter-space dimensions
650  cache->ndim = XLALTotalLatticeTilingDimensions( coh_tiling );
652 
653  // Get lowest tiled parameter-space dimension
654  if ( XLALTiledLatticeTilingDimensions( coh_tiling ) > 0 ) {
655  cache->dim0 = XLALLatticeTilingTiledDimension( coh_tiling, 0 );
656  } else {
657  cache->dim0 = 0;
658  }
660 
661  // Compute offset used in computation of semicoherent point relevance:
662  {
663 
664  // Convert a physical point far from any parameter-space boundaries to coherent and semicoherent reduced supersky coordinates
665  PulsarDopplerParams phys_origin = { .Alpha = 0, .Delta = LAL_PI_2, .fkdot = {0} };
666  XLAL_CHECK_NULL( XLALSetPhysicalPointSuperskyRefTime( &phys_origin, cache->coh_rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC );
667  double coh_origin_array[cache->ndim];
668  gsl_vector_view coh_origin_view = gsl_vector_view_array( coh_origin_array, cache->ndim );
669  XLAL_CHECK_NULL( XLALConvertPhysicalToSuperskyPoint( &coh_origin_view.vector, &phys_origin, cache->coh_rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC );
670  double semi_origin_array[cache->ndim];
671  gsl_vector_view semi_origin_view = gsl_vector_view_array( semi_origin_array, cache->ndim );
672  XLAL_CHECK_NULL( XLALConvertPhysicalToSuperskyPoint( &semi_origin_view.vector, &phys_origin, cache->semi_rssky_transf ) == XLAL_SUCCESS, XLAL_EFUNC );
673  const double semi_origin_dim0 = gsl_vector_get( &semi_origin_view.vector, cache->dim0 );
674 
675  // Sample vertices of bounding box around 'coh_origin', and record maximum vertex in semicoherent reduced supersky coordinates in dimension 'dim0'
676  double coh_bbox_sample_array[cache->ndim];
677  gsl_vector_view coh_bbox_sample_view = gsl_vector_view_array( coh_bbox_sample_array, cache->ndim );
678  gsl_vector_memcpy( &coh_bbox_sample_view.vector, &coh_origin_view.vector );
679  double semi_bbox_sample_array[cache->ndim];
680  gsl_vector_view semi_bbox_sample_view = gsl_vector_view_array( semi_bbox_sample_array, cache->ndim );
681  double max_semi_bbox_sample_dim0 = semi_origin_dim0;
682  XLAL_CHECK_NULL( cache_max_semi_bbox_sample_dim0( cache, coh_tiling, 0, &coh_bbox_sample_view.vector, &semi_bbox_sample_view.vector, &max_semi_bbox_sample_dim0 ) == XLAL_SUCCESS, XLAL_EFUNC );
683 
684  // Subtract off origin of 'semi_origin' to get relevance offset
685  cache->coh_relevance_offset = max_semi_bbox_sample_dim0 - semi_origin_dim0;
686 
687  }
688 
689  // If this is an interpolating search, create a lattice tiling locator
690  if ( interpolation ) {
691  cache->coh_locator = XLALCreateLatticeTilingLocator( coh_tiling );
692  XLAL_CHECK_NULL( cache->coh_locator != NULL, XLAL_EFUNC );
693  const LatticeTilingStats *stats = XLALLatticeTilingStatistics( coh_tiling, cache->ndim - 2 );
694  XLAL_CHECK_NULL( stats != NULL, XLAL_EFUNC );
695  cache->coh_max_index = stats->total_points;
696  }
697 
698  // Create a heap which sorts items by "relevance", a quantity which determines how long
699  // cache items are kept. Consider the following scenario:
700  //
701  // +-----> parameter-space dimension 'dim0'
702  // |
703  // V parameter-space dimensions > 'dim0'
704  //
705  // :
706  // : R[S1] = relevance of semicoherent point 'S1'
707  // :
708  // +-----+
709  // | /`\ |
710  // || S1||
711  // | \,/ |
712  // +-----+
713  // + :
714  // / \ : R[S2] = relevance of semicoherent point 'S2'
715  // /,,,\ :
716  // /( \\ +-----+
717  // + ( \\ | /`\ |
718  // \\ C \\ || S2||
719  // \\ ) + | \,/ |
720  // \\ )/: +-----+
721  // \```/ :
722  // \ / :
723  // + : R[C] = relevance of coherent point 'C'
724  // :
725  //
726  // The relevance R[C] of the coherent point 'C' is given by the coordinate in dimension 'dim0' of
727  // the *rightmost* edge of the bounding box surrounding its metric ellipse. The relevances of
728  // two semicoherent points S1 and S2, R[S1] and R[S2], are given by the *leftmost* edges of the
729  // bounding box surrounding their metric ellipses.
730  //
731  // Note that iteration over the parameter space is ordered such that dimension 'dim0' is the slowest
732  // (tiled) coordinate, i.e. dimension 'dim0' is passed over only once, therefore coordinates in this
733  // dimension are monotonically increasing, therefore relevances are also monotonically increasing.
734  //
735  // Suppose S1 is the current point in the semicoherent parameter-space tiling; note that R[C] > R[S1].
736  // It is clear that, as iteration progresses, some future semicoherent points will overlap with C.
737  // Therefore C cannot be discarded from the cache, since it will be the closest point for future
738  // semicoherent points. Now suppose that S2 is the current point; note that R[C] < R[S1]. It is clear
739  // that neither S2, nor any future point in the semicoherent parameter-space tiling, can ever overlap
740  // with C. Therefore C can never be the closest point for any future semicoherent points, and therefore
741  // it can safely be discarded from the cache.
742  //
743  // In short, an item in the cache can be discarded once its relevance falls below the threshold set
744  // by the current point semicoherent in the semicoherent parameter-space tiling.
745  //
746  // Items removed from the heap are destroyed by calling cache_item_destroy().
747  cache->relevance_heap = XLALHeapCreate( cache_item_destroy, max_size, -1, cache_item_compare_by_relevance );
748  XLAL_CHECK_NULL( cache->relevance_heap != NULL, XLAL_EFUNC );
749 
750  // Create a hash table which looks up cache items by partition and locator index. Items removed
751  // from the hash table are NOT destroyed, since items are shared with 'relevance_heap'.
753  XLAL_CHECK_NULL( cache->coh_index_hash != NULL, XLAL_EFUNC );
754 
755  // Create a bitset which records which cache items have ever been computed.
756  cache->coh_computed_bitset = XLALBitsetCreate();
757  XLAL_CHECK_NULL( cache->coh_computed_bitset != NULL, XLAL_EFUNC );
758 
759  return cache;
760 
761 }
762 
763 ///
764 /// Destroy a cache
765 ///
767  WeaveCache *cache
768 )
769 {
770  if ( cache != NULL ) {
771  XLALDestroyLatticeTilingLocator( cache->coh_locator );
772  XLALHeapDestroy( cache->relevance_heap );
773  XLALHashTblDestroy( cache->coh_index_hash );
774  cache_item_destroy( cache->saved_item );
775  XLALBitsetDestroy( cache->coh_computed_bitset );
776  XLALFree( cache );
777  }
778 }
779 
780 ///
781 /// Determine the mean maximum size obtained by caches
782 ///
784  REAL4 *cache_mean_max_size,
785  const size_t ncache,
786  WeaveCache *const *cache
787 )
788 {
789 
790  // Check input
791  XLAL_CHECK( cache_mean_max_size != NULL, XLAL_EFAULT );
792  XLAL_CHECK( ncache > 0, XLAL_ESIZE );
793  XLAL_CHECK( cache != NULL, XLAL_EFAULT );
794 
795  // Determine the mean maximum size obtained by caches
796  *cache_mean_max_size = 0;
797  for ( size_t i = 0; i < ncache; ++i ) {
798  *cache_mean_max_size += cache[i]->heap_max_size;
799  }
800  *cache_mean_max_size /= ncache;
801 
802  return XLAL_SUCCESS;
803 
804 }
805 
806 ///
807 /// Write various information from caches to a FITS file
808 ///
810  FITSFile *file,
811  const size_t ncache,
812  WeaveCache *const *cache
813 )
814 {
815 
816  // Check input
817  XLAL_CHECK( file != NULL, XLAL_EFAULT );
818  XLAL_CHECK( ncache > 0, XLAL_ESIZE );
819  XLAL_CHECK( cache != NULL, XLAL_EFAULT );
820 
821  // Write the mean maximum size obtained by caches
822  REAL4 cache_mean_max_size = 0;
823  XLAL_CHECK( XLALWeaveGetCacheMeanMaxSize( &cache_mean_max_size, ncache, cache ) == XLAL_SUCCESS, XLAL_EFUNC );
824  XLAL_CHECK( XLALFITSHeaderWriteREAL4( file, "cachemmx", cache_mean_max_size, "Mean maximum size obtained by cache" ) == XLAL_SUCCESS, XLAL_EFUNC );
825 
826  return XLAL_SUCCESS;
827 
828 }
829 
830 ///
831 /// Expire all items in the cache
832 ///
834  WeaveCache *cache
835 )
836 {
837 
838  // Check input
839  XLAL_CHECK( cache != NULL, XLAL_EFAULT );
840 
841  // Advance current generation of cache items
842  // - Existing items will no longer be accessible, but are still kept for reuse
843  ++cache->generation;
844 
845  return XLAL_SUCCESS;
846 
847 }
848 
849 ///
850 /// Clear all items in the cache from memory
851 ///
853  WeaveCache *cache
854 )
855 {
856 
857  // Check input
858  XLAL_CHECK( cache != NULL, XLAL_EFAULT );
859 
860  // Clear items in the relevance heap and hash table from memory
861  XLAL_CHECK( XLALHeapClear( cache->relevance_heap ) == XLAL_SUCCESS, XLAL_EFUNC );
862  XLAL_CHECK( XLALHashTblClear( cache->coh_index_hash ) == XLAL_SUCCESS, XLAL_EFUNC );
863 
864  // Reset current generation of cache items
865  cache->generation = 0;
866 
867  return XLAL_SUCCESS;
868 
869 }
870 
871 ///
872 /// Retrieve coherent results for a given query, or compute new coherent results if not found
873 ///
875  WeaveCache *cache,
876  const WeaveCacheQueries *queries,
877  const UINT4 query_index,
878  const WeaveCohResults **coh_res,
879  UINT8 *coh_index,
880  UINT4 *coh_offset,
881  WeaveSearchTiming *tim
882 )
883 {
884 
885  // Check input
886  XLAL_CHECK( cache != NULL, XLAL_EFAULT );
887  XLAL_CHECK( queries != NULL, XLAL_EFAULT );
888  XLAL_CHECK( query_index < queries->nqueries, XLAL_EINVAL );
889  XLAL_CHECK( coh_res != NULL, XLAL_EFAULT );
890  XLAL_CHECK( coh_offset != NULL, XLAL_EFAULT );
891  XLAL_CHECK( tim != NULL, XLAL_EFAULT );
892 
893  // See if coherent results are already cached
894  const cache_item find_key = { .generation = cache->generation, .coh_index = queries->coh_index[query_index] };
895  const cache_item *find_item = NULL;
896  XLAL_CHECK( XLALHashTblFind( cache->coh_index_hash, &find_key, ( const void ** ) &find_item ) == XLAL_SUCCESS, XLAL_EFUNC );
897  if ( find_item == NULL ) {
898 
899  // Reuse 'saved_item' if possible, otherwise allocate memory for a new cache item
900  if ( cache->saved_item == NULL ) {
901  cache->saved_item = XLALCalloc( 1, sizeof( *cache->saved_item ) );
902  XLAL_CHECK( cache->saved_item != NULL, XLAL_EINVAL );
903  }
904  cache_item *new_item = cache->saved_item;
905  find_item = new_item;
906 
907  // Set the key of the new cache item for future lookups
908  new_item->generation = find_key.generation;
909  new_item->coh_index = find_key.coh_index;
910 
911  // Set the relevance of the coherent frequency block associated with the new cache item
912  new_item->relevance = queries->coh_relevance[query_index];
913 
914  // Determine the number of points in the coherent frequency block
915  const UINT4 coh_nfreqs = queries->coh_right[query_index] - queries->coh_left[query_index] + 1;
916 
917  // Compute coherent results for the new cache item
918  XLAL_CHECK( XLALWeaveCohResultsCompute( &new_item->coh_res, cache->coh_input, &queries->coh_phys[query_index], coh_nfreqs, tim ) == XLAL_SUCCESS, XLAL_EFUNC );
919 
920  // Add new cache item to the index hash table
921  XLAL_CHECK( XLALHashTblAdd( cache->coh_index_hash, new_item ) == XLAL_SUCCESS, XLAL_EFUNC );
922 
923  // Get the item in the cache with the smallest relevance
924  const cache_item *least_relevant_item = ( const cache_item * ) XLALHeapRoot( cache->relevance_heap );
926 
927  // Create a 'fake' item specifying thresholds for cache item relevance, for comparison with 'least_relevant_item'
928  const cache_item relevance_threshold = { .generation = cache->generation, .relevance = queries->semi_relevance };
929 
930  // If garbage collection is enabled, and item's relevance has fallen below the threshold relevance, it can be removed from the cache
931  if ( cache->any_gc && least_relevant_item != NULL && least_relevant_item != new_item && cache_item_compare_by_relevance( least_relevant_item, &relevance_threshold ) < 0 ) {
932 
933  // Remove least relevant item from index hash table
934  XLAL_CHECK( XLALHashTblRemove( cache->coh_index_hash, least_relevant_item ) == XLAL_SUCCESS, XLAL_EFUNC );
935 
936  // Exchange 'saved_item' with the least relevant item in the relevance heap
937  XLAL_CHECK( XLALHeapExchangeRoot( cache->relevance_heap, ( void ** ) &cache->saved_item ) == XLAL_SUCCESS, XLAL_EFUNC );
938 
939  // If maximal garbage collection is enabled, remove as many results as possible
940  while ( cache->all_gc ) {
941 
942  // Get the item in the cache with the smallest relevance
943  least_relevant_item = ( const cache_item * ) XLALHeapRoot( cache->relevance_heap );
945 
946  // If item's relevance has fallen below the threshold relevance, it can be removed from the cache
947  if ( least_relevant_item != NULL && least_relevant_item != new_item && cache_item_compare_by_relevance( least_relevant_item, &relevance_threshold ) < 0 ) {
948 
949  // Remove least relevant item from index hash table
950  XLAL_CHECK( XLALHashTblRemove( cache->coh_index_hash, least_relevant_item ) == XLAL_SUCCESS, XLAL_EFUNC );
951 
952  // Remove and destroy least relevant item from the relevance heap
953  XLAL_CHECK( XLALHeapRemoveRoot( cache->relevance_heap ) == XLAL_SUCCESS, XLAL_EINVAL );
954 
955  } else {
956 
957  // All cache items are still relevant
958  break;
959 
960  }
961 
962  }
963 
964  } else {
965 
966  // Add new cache item to the relevance heap; 'saved_item' many now contains an item removed from the heap
967  XLAL_CHECK( XLALHeapAdd( cache->relevance_heap, ( void ** ) &cache->saved_item ) == XLAL_SUCCESS, XLAL_EFUNC );
968 
969  // If 'saved_item' contains an item removed from the heap, also remove it from the index hash table
970  if ( cache->saved_item != NULL ) {
971  XLAL_CHECK( XLALHashTblRemove( cache->coh_index_hash, cache->saved_item ) == XLAL_SUCCESS, XLAL_EFUNC );
972  }
973 
974  }
975 
976  // Update maximum size obtained by relevance heap
977  const UINT4 heap_size = XLALHeapSize( cache->relevance_heap );
978  if ( cache->heap_max_size < heap_size ) {
979  cache->heap_max_size = heap_size;
980  }
981 
982  // Increment number of computed coherent results
983  queries->coh_nres[query_index] += coh_nfreqs;
984 
985  // Check if coherent results have been computed previously
986  const UINT8 coh_bitset_index = queries->freq_partition_index * cache->coh_max_index + find_key.coh_index;
987  BOOLEAN computed = 0;
988  XLAL_CHECK( XLALBitsetGet( cache->coh_computed_bitset, coh_bitset_index, &computed ) == XLAL_SUCCESS, XLAL_EFUNC );
989  if ( !computed ) {
990 
991  // Coherent results have not been computed before: increment the number of coherent templates
992  queries->coh_ntmpl[query_index] += coh_nfreqs;
993 
994  // This coherent result has now been computed
995  XLAL_CHECK( XLALBitsetSet( cache->coh_computed_bitset, coh_bitset_index, 1 ) == XLAL_SUCCESS, XLAL_EFUNC );
996 
997  }
998 
999  }
1000 
1001  // Return coherent results from cache
1002  *coh_res = find_item->coh_res;
1003 
1004  // Return index of coherent result
1005  *coh_index = find_item->coh_index;
1006 
1007  // Return offset at which coherent results should be combined with semicoherent results
1008  *coh_offset = queries->semi_left - queries->coh_left[query_index];
1009 
1010  return XLAL_SUCCESS;
1011 
1012 }
1013 
1014 // Local Variables:
1015 // c-file-style: "linux"
1016 // c-basic-offset: 2
1017 // End:
static int cache_item_compare_by_coh_index(const void *x, const void *y)
Compare cache items by generation, then locator index.
Definition: CacheResults.c:186
void XLALWeaveCacheQueriesDestroy(WeaveCacheQueries *queries)
Destroy storage for a series of cache queries.
Definition: CacheResults.c:383
int XLALWeaveCacheQuery(const WeaveCache *cache, WeaveCacheQueries *queries, const UINT4 query_index)
Query a cache for the results nearest to a given coherent point.
Definition: CacheResults.c:449
int XLALWeaveCacheQueriesFinal(WeaveCacheQueries *queries, PulsarDopplerParams *semi_phys, UINT4 *semi_nfreqs)
Finalise a series of cache queries.
Definition: CacheResults.c:515
int XLALWeaveCacheQueriesInit(WeaveCacheQueries *queries, const UINT8 semi_index, const gsl_vector *semi_rssky, const INT4 semi_left, const INT4 semi_right, const UINT4 freq_partition_index)
Initialise a series of cache queries.
Definition: CacheResults.c:404
int XLALWeaveCacheExpire(WeaveCache *cache)
Expire all items in the cache.
Definition: CacheResults.c:833
int XLALWeaveGetCacheMeanMaxSize(REAL4 *cache_mean_max_size, const size_t ncache, WeaveCache *const *cache)
Determine the mean maximum size obtained by caches.
Definition: CacheResults.c:783
static int cache_left_right_offsets(const UINT4 semi_nfreqs, const UINT4 nfreq_partitions, const UINT4 freq_partition_index, INT4 *left_offset, INT4 *right_offset)
Compute left/right-most index offsets to select a given partition.
Definition: CacheResults.c:261
WeaveCache * XLALWeaveCacheCreate(const LatticeTiling *coh_tiling, const BOOLEAN interpolation, const SuperskyTransformData *coh_rssky_transf, const SuperskyTransformData *semi_rssky_transf, WeaveCohInput *coh_input, const UINT4 max_size, const BOOLEAN all_gc)
Create a cache.
Definition: CacheResults.c:616
void XLALWeaveCacheDestroy(WeaveCache *cache)
Destroy a cache.
Definition: CacheResults.c:766
#define COMPARE_BY(x, y)
Definition: CacheResults.c:32
int XLALWeaveCacheRetrieve(WeaveCache *cache, const WeaveCacheQueries *queries, const UINT4 query_index, const WeaveCohResults **coh_res, UINT8 *coh_index, UINT4 *coh_offset, WeaveSearchTiming *tim)
Retrieve coherent results for a given query, or compute new coherent results if not found.
Definition: CacheResults.c:874
int XLALWeaveCacheQueriesGetCounts(const WeaveCacheQueries *queries, UINT8 *coh_nres, UINT8 *coh_ntmpl, UINT8 *semi_ntmpl)
Get number of computed coherent results, and number of coherent and semicoherent templates.
Definition: CacheResults.c:580
int XLALWeaveCacheClear(WeaveCache *cache)
Clear all items in the cache from memory.
Definition: CacheResults.c:852
static void cache_item_destroy(void *x)
Destroy a cache item.
Definition: CacheResults.c:157
WeaveCacheQueries * XLALWeaveCacheQueriesCreate(const LatticeTiling *semi_tiling, const SuperskyTransformData *semi_rssky_transf, const double dfreq, const UINT4 nqueries, const UINT4 nfreq_partitions)
Create storage for a series of cache queries.
Definition: CacheResults.c:305
static int cache_item_compare_by_relevance(const void *x, const void *y)
Compare cache items by generation, then relevance.
Definition: CacheResults.c:171
int XLALWeaveCacheWriteInfo(FITSFile *file, const size_t ncache, WeaveCache *const *cache)
Write various information from caches to a FITS file.
Definition: CacheResults.c:809
static UINT8 cache_item_hash(const void *x)
Hash cache items by generation and locator index.
Definition: CacheResults.c:201
static int cache_max_semi_bbox_sample_dim0(const WeaveCache *cache, const LatticeTiling *coh_tiling, const size_t i, gsl_vector *coh_bbox_sample, gsl_vector *semi_bbox_sample, double *max_semi_bbox_sample_dim0)
Sample points on surface of coherent bounding box, convert to semicoherent supersky coordinates,...
Definition: CacheResults.c:216
Module which caches computed coherent results.
void XLALWeaveCohResultsDestroy(WeaveCohResults *coh_res)
Destroy coherent results.
int XLALWeaveCohResultsCompute(WeaveCohResults **coh_res, WeaveCohInput *coh_input, const PulsarDopplerParams *coh_phys, const UINT4 coh_nfreqs, WeaveSearchTiming *tim)
Create and compute coherent results.
int XLALFITSHeaderWriteREAL4(FITSFile UNUSED *file, const CHAR UNUSED *key, const REAL4 UNUSED value, const CHAR UNUSED *comment)
Definition: FITSFileIO.c:1089
struct tagFITSFile FITSFile
Representation of a FITS file.
Definition: FITSFileIO.h:54
LALBitset * XLALBitsetCreate(void)
void XLALBitsetDestroy(LALBitset *bs)
int XLALBitsetGet(const LALBitset *bs, const UINT8 idx, BOOLEAN *is_set)
int XLALBitsetSet(LALBitset *bs, const UINT8 idx, const BOOLEAN is_set)
#define LAL_PI_2
unsigned char BOOLEAN
#define XLAL_INIT_MEM(x)
uint64_t UINT8
uint32_t UINT4
int32_t INT4
float REAL4
int XLALPearsonHash(void *hval, const size_t hval_len, const void *data, const size_t data_len)
int XLALHashTblFind(const LALHashTbl *ht, const void *x, const void **y)
LALHashTbl * XLALHashTblCreate(LALHashTblDtorFcn dtor, LALHashTblHashFcn hash, LALHashTblCmpFcn cmp)
int XLALHashTblAdd(LALHashTbl *ht, void *x)
int XLALHashTblRemove(LALHashTbl *ht, const void *x)
void XLALHashTblDestroy(LALHashTbl *ht)
int XLALHashTblClear(LALHashTbl *ht)
const void * XLALHeapRoot(const LALHeap *h)
int XLALHeapAdd(LALHeap *h, void **x)
int XLALHeapSize(const LALHeap *h)
int XLALHeapExchangeRoot(LALHeap *h, void **x)
int XLALHeapRemoveRoot(LALHeap *h)
int XLALHeapClear(LALHeap *h)
LALHeap * XLALHeapCreate(LALHeapDtorFcn dtor, int max_size, int min_or_max_heap, LALHeapCmpFcn cmp)
void XLALHeapDestroy(LALHeap *h)
void * XLALCalloc(size_t m, size_t n)
void XLALFree(void *p)
#define LAL_UINT8_FORMAT
size_t XLALTotalLatticeTilingDimensions(const LatticeTiling *tiling)
Return the total number of dimensions of the lattice tiling.
const LatticeTilingStats * XLALLatticeTilingStatistics(const LatticeTiling *tiling, const size_t dim)
Return statistics related to the number/value of lattice tiling points in a dimension.
int XLALNearestLatticeTilingBlock(const LatticeTilingLocator *loc, const gsl_vector *point, const size_t dim, gsl_vector *nearest_point, UINT8 *nearest_index, INT4 *nearest_left, INT4 *nearest_right)
Locate the nearest block in a lattice tiling to a given point.
void XLALDestroyLatticeTilingLocator(LatticeTilingLocator *loc)
Destroy a lattice tiling locator.
size_t XLALTiledLatticeTilingDimensions(const LatticeTiling *tiling)
Return the number of tiled dimensions of the lattice tiling.
size_t XLALLatticeTilingTiledDimension(const LatticeTiling *tiling, const size_t tiled_dim)
Return the dimension of the tiled lattice tiling dimension indexed by 'tiled_dim'.
LatticeTilingLocator * XLALCreateLatticeTilingLocator(const LatticeTiling *tiling)
Create a new lattice tiling locator.
REAL8 XLALLatticeTilingBoundingBox(const LatticeTiling *tiling, const size_t dim)
Return the bounding box extent of the lattice tiling in a given dimension, or 0 for non-tiled dimensi...
int XLALSetPhysicalPointSuperskyRefTime(PulsarDopplerParams *out_phys, const SuperskyTransformData *rssky_transf)
Set the reference time of a physical point to that of the reduced supersky coordinates.
int XLALConvertPhysicalToSuperskyPoint(gsl_vector *out_rssky, const PulsarDopplerParams *in_phys, const SuperskyTransformData *rssky_transf)
Convert a point from physical to supersky coordinates.
int XLALConvertSuperskyToPhysicalPoint(PulsarDopplerParams *out_phys, const gsl_vector *in_rssky, const gsl_vector *ref_rssky, const SuperskyTransformData *rssky_transf)
Convert a point from supersky to physical coordinates.
int XLALConvertSuperskyToSuperskyPoint(gsl_vector *out_rssky, const SuperskyTransformData *out_rssky_transf, const gsl_vector *in_rssky, const gsl_vector *ref_rssky, const SuperskyTransformData *in_rssky_transf)
Convert a point between supersky coordinates.
#define xlalErrno
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_ESIZE
XLAL_EINVAL
XLAL_EFAILED
list y
Statistics related to the number/value of lattice tiling points in a dimension.
UINT4 min_points
Minimum number of points in this dimension.
UINT8 total_points
Total number of points up to this dimension.
Type containing the 'Doppler-parameters' affecting the time-evolution of the phase.
REAL8 Alpha
Sky position: RA (longitude) in equatorial coords and radians.
Item stored in the cache.
Definition: CacheResults.c:37
REAL4 relevance
Relevance, used to decide how long to keep items.
Definition: CacheResults.c:41
UINT8 coh_index
Coherent locator index, used to find items in cache.
Definition: CacheResults.c:43
UINT4 generation
Generation, used both to find items in cache and to decide how long to keep items.
Definition: CacheResults.c:39
WeaveCohResults * coh_res
Results of a coherent computation on a single segment.
Definition: CacheResults.c:45
Cache used to store coherent results.
Definition: CacheResults.c:105
UINT8 coh_max_index
Maximum value of index from coherent locator.
Definition: CacheResults.c:119
double coh_relevance_offset
Offset used in computation of coherent point relevance.
Definition: CacheResults.c:131
size_t ndim
Number of parameter-space dimensions.
Definition: CacheResults.c:107
size_t dim0
Lowest tiled parameter-space dimension.
Definition: CacheResults.c:109
LatticeTilingLocator * coh_locator
Coherent parameter-space tiling locator.
Definition: CacheResults.c:117
WeaveCohInput * coh_input
Input data required for computing coherent results.
Definition: CacheResults.c:115
UINT4 generation
Current generation of cache items.
Definition: CacheResults.c:121
LALHashTbl * coh_index_hash
Hash table which looks up cache items by index.
Definition: CacheResults.c:127
BOOLEAN all_gc
Whether garbage collection should remove as many results as possible.
Definition: CacheResults.c:135
LALBitset * coh_computed_bitset
Bitset which records whether an item has ever been computed.
Definition: CacheResults.c:129
const SuperskyTransformData * semi_rssky_transf
Reduced supersky transform data for semicoherent lattice.
Definition: CacheResults.c:113
UINT4 heap_max_size
Maximum size obtained by relevance heap.
Definition: CacheResults.c:125
cache_item * saved_item
Save an no-longer-used cache item for re-use.
Definition: CacheResults.c:137
const SuperskyTransformData * coh_rssky_transf
Reduced supersky transform data for coherent lattice.
Definition: CacheResults.c:111
BOOLEAN any_gc
Whether any garbage collection of results should be used.
Definition: CacheResults.c:133
LALHeap * relevance_heap
Heap which ranks cache items by relevance.
Definition: CacheResults.c:123
Container for a series of cache queries.
Definition: CacheResults.c:51
UINT4 freq_partition_index
Index to current partition of semicoherent frequency block.
Definition: CacheResults.c:63
UINT8 semi_index
Sequential index for the current semicoherent frequency block.
Definition: CacheResults.c:85
INT4 * coh_part_right_offset
Offset to apply to coherent right-most index to enclose a frequency partition.
Definition: CacheResults.c:67
REAL4 semi_relevance
Relevance of the current semicoherent frequency block.
Definition: CacheResults.c:95
UINT8 * coh_nres
Number of computed coherent results (per query)
Definition: CacheResults.c:79
UINT8 semi_ntmpl
Number of semicoherent templates (over all queries)
Definition: CacheResults.c:99
PulsarDopplerParams * coh_phys
Physical points of each queried coherent frequency block.
Definition: CacheResults.c:71
size_t dim0
Lowest tiled parameter-space dimension.
Definition: CacheResults.c:55
UINT4 nfreq_partitions
Number of partitions to divide semicoherent frequency block into.
Definition: CacheResults.c:61
INT4 * coh_right
Indexes of right-most point in queried coherent frequency block.
Definition: CacheResults.c:75
UINT4 nqueries
Number of queries for which space is allocated.
Definition: CacheResults.c:59
INT4 semi_right
Index of right-most point in current semicoherent frequency block.
Definition: CacheResults.c:93
UINT8 * coh_ntmpl
Number of coherent templates (per query)
Definition: CacheResults.c:81
size_t ndim
Number of parameter-space dimensions.
Definition: CacheResults.c:53
const SuperskyTransformData * semi_rssky_transf
Reduced supersky transform data for semicoherent lattice.
Definition: CacheResults.c:83
INT4 * coh_part_left_offset
Offset to apply to coherent left-most index to enclose a frequency partition.
Definition: CacheResults.c:65
double semi_relevance_offset
Offset used in computation of semicoherent point relevance.
Definition: CacheResults.c:97
UINT8 * coh_index
Sequential indexes for each queried coherent frequency block.
Definition: CacheResults.c:69
PulsarDopplerParams semi_phys
Physical coordinates of the current semicoherent frequency block.
Definition: CacheResults.c:89
INT4 * coh_left
Indexes of left-most point in queried coherent frequency block.
Definition: CacheResults.c:73
REAL4 * coh_relevance
Relevance of each queried coherent frequency block.
Definition: CacheResults.c:77
INT4 semi_left
Index of left-most point in current semicoherent frequency block.
Definition: CacheResults.c:91