LALPulsar  6.1.0.1-fe68b98
TwoDMeshInternal.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 Jolien Creighton, Reinhard Prix, Teviet Creighton
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  * \author Creighton, T. D.
22  * \file
23  * \ingroup TwoDMesh_h
24  * \brief Low-level routines to place a mesh of templates on an 2-dimensional parameter space.
25  *
26  * ### Description ###
27  *
28  * These are low-level ``internal'' routines called by
29  * LALCreateTwoDMesh() to lay out an unevenly-spaced mesh on a
30  * 2-dimensional parameter space, according to the method discussed in
31  * \ref TwoDMesh_h. They are made globally available to allow greater
32  * control to users attempting to tile complicated parameter spaces.
33  *
34  * LALTwoDMesh() places a mesh on the parameter space specified by
35  * <tt>*params</tt>. On successful completion, the linked list of mesh
36  * points is attached to <tt>(*tail)->next</tt> (which must previously have
37  * been \c NULL), updates <tt>*tail</tt> to point to the new tail of
38  * the list, and increases <tt>params->nOut</tt> by the number of mesh
39  * points added. (This is useful for tiling several parameter regions
40  * independently with successive calls to LALTwoDMesh().) On an
41  * error, <tt>**tail</tt> is left unchanged, and <tt>params->nOut</tt>
42  * indicates where the error occurred.
43  *
44  * LALTwoDColumn() places a single column of such a mesh,
45  * according to the additional column restrictions in <tt>*column</tt>.
46  * Again, on success, the mesh points are attached to
47  * <tt>(*tail)->next</tt>, <tt>*tail</tt> is updated, and <tt>params->nOut</tt>
48  * increased. If the column specified by <tt>*column</tt> is deemed to be
49  * too wide for a single column of templates, then <tt>column->tooWide</tt>
50  * is set to 1, <tt>*tail</tt> and <tt>params->nOut</tt> are \e not
51  * updated, and the function returns normally (i.e.\ not with an error
52  * code set). Other more fatal errors are treated as for
53  * LALTwoDMesh(), above.
54  *
55  * LALTwoDNodeCopy() creates a copy of the node <tt>*old</tt> and
56  * points <tt>*new</tt> to the copy. If <tt>old->subMesh</tt> exists, each
57  * node in the submesh is copied into its corresponding place by
58  * recursive calls to LALTwoDNodeCopy(). On an error, the copy is
59  * destroyed and <tt>*new</tt> left unchanged.
60  *
61  * ### Algorithm ###
62  *
63  * \par LALTwoDMesh():
64  * This routine starts placing mesh
65  * points at the left side of the parameter region, \f$ x=x_\mathrm{min} \f$ .
66  * It calls <tt>params->getRange()</tt> to get the bottom and top of the
67  * left edge of the first column. It also calls <tt>params->getMetric</tt>
68  * at these two corners, estimates the optimum width for the first
69  * column, and uses <tt>params->getRange()</tt> again to get the two
70  * corners of the right edge of the column. It then calls the subroutine
71  * LALTwoDColumn() (below) to place the mesh points in this
72  * column.
73  *
74  * If LALTwoDColumn() reports that the estimated column width was
75  * too large, LALCreateTwoDMesh() tries again with the width
76  * reduced by the factor <tt>params->widthRetryFac</tt>. This continues
77  * until the estimated number of columns exceeds
78  * <tt>params->maxColumns</tt>; i.e.\ until the current column width is
79  * less than \f$ (x_\mathrm{max}-x_\mathrm{min})/ \f$ <tt>params->maxColumns</tt>.
80  * If this occurs, the linked list is destroyed using
81  * LALDestroyTwoDMesh(), and an error is returned.
82  *
83  * Otherwise, if LALTwoDColumn() returns success (and does not
84  * complain about the column width), LALCreateTwoDMesh() gets the
85  * width and heights of the next column, and calls LALTwoDColumn()
86  * again. This continues until eventually the right edge of a column
87  * lies beyond \f$ x_\mathrm{max} \f$ . This last column is squeezed so that
88  * its right edge lies exactly at \f$ x_\mathrm{max} \f$ ; once it is filled,
89  * the mesh is deemed complete, and no further columns are generated.
90  *
91  * \par LALTwoDColumn():
92  * This routine first locates the
93  * centreline of the column, and uses <tt>params->getRange()</tt> to see
94  * how much of this centreline is taken up by the requested parameter
95  * region, restricted by any clipping area specified in <tt>*column</tt>.
96  * If any region of this centreline remains uncovered,
97  * LALTwoDColumn() places a tile at the bottom of the uncovered
98  * portion, and stacks more tiles upward until it reaches the top of the
99  * uncovered line. The sizes and orientations of each tile are
100  * determined from calls to <tt>params->getMetric</tt>.
101  *
102  * While it is doing this, LALTwoDColumn() keeps track of the
103  * bottom and top corners of the newly-covered region. If it finds that
104  * the top corners are not increasing monotonically, this is usually an
105  * indication that the metric is changing too rapidly, or that the tiles
106  * are getting too thin and tilted. Often this can be corrected by using
107  * narrower (and taller) tiles, so LALTwoDColumn() reports this as
108  * a ``column too wide'' result: it sets <tt>column->tooWide</tt>, frees
109  * everythin attached to <tt>**tail</tt> and reduced <tt>params->nOut</tt>
110  * accordingly, then returns. This is also done if
111  * LALTwoDColumn() ever determines that the maximum width of a
112  * mismatch ellipse is less than <tt>params->widthMaxFac</tt> times the
113  * current column width.
114  *
115  * Having successfully stacked up the centreline of the current column,
116  * LALTwoDColumn() then checks to see whether corners of the
117  * parameter region extend above or below the top and bottom of the
118  * newly-tiled region on either side of the centreline, by looking at the
119  * values in <tt>column->leftRange</tt> and <tt>column->rightRange</tt>. If
120  * a corner remains uncovered, LALTwoDColumn() calls itself
121  * recursively on a half-width column on the appropriate side, setting
122  * the clipping area of the subroutine call to exclude the region already
123  * covered. In principle it could call itself up to four times (once for
124  * each column), and each recursive call could in turn call itself
125  * recursively in order to cover a particularly steep or complicated
126  * boundary. However, in most cases at most two additional tiles need to
127  * be placed (one on a top corner, one on a bottom corner). If you're
128  * concerned about a runaway process, set <tt>params->nIn</tt> to stop
129  * generation after a given number of tiles. If a recursive call reports
130  * the column is too wide, this information is passed up the calling
131  * chain.
132  *
133  * Once the centreline and any corners have been successfully covered,
134  * LALTwoDColumn() updates <tt>*tail</tt> to the new tail of the
135  * list, and returns.
136  *
137  * \par LALTwoDNodeCopy():
138  * This routine works by a simple
139  * recursive algorithm. First, a copy of the node is allocated and the
140  * output handle is pointed to it. Next, all non-pointer fields are
141  * copied over. Then, if <tt>new->subMesh</tt> exists,
142  * LALTwoDNodeCopy() navigates its way along the list, calling
143  * itself recursively on each node, and attaching copies of each node to
144  * a corresponding list in <tt>(*new)->subMesh</tt>. If any errors are
145  * detected, <tt>*new</tt> is destroyed via LALDestroyTwoDMesh(),
146  * restoring it to \c NULL.
147  *
148  * \par Computing tile sizes:
149  * Given a positive-definite
150  * 2-dimensional metric \f$ \mathsf{g}_{ab} \f$ , the elliptical contour
151  * corresponding to a maximum mismatch \f$ m_\mathrm{thresh} \f$ is given by
152  * the set of points offset from the centre point by amounts \f$ (\Delta
153  * x,\Delta y) \f$ , where:
154  * \f[
155  * m_\mathrm{thresh} = g_{xx}(\Delta x)^2 + g_{yy}(\Delta y)^2
156  * + 2g_{xy}\Delta x\Delta y \; .
157  * \f]
158  * Thus for a tile of some half-width \f$ \Delta x \f$ , the heights of the two
159  * right-hand corners of the tile relative to its centre are:
160  * \f[
161  * \Delta y = \frac{-g_{xy}\Delta x \pm\sqrt{g_{yy}m_\mathrm{thresh} -
162  * ( g_{xx}g_{yy} - g_{xy}^2 )(\Delta x)^2}}{g_{yy}} \; ,
163  * \f]
164  * and the maximum half-width of a tile is:
165  * \f[
166  * \Delta x_\mathrm{max} = \sqrt{\frac{g_{yy}m_\mathrm{thresh}}
167  * {g_{xx}g_{yy} - g_{xy}^2}} \; .
168  * \f]
169  * The positive-definiteness of the metric ensures that \f$ g_{xx}>0 \f$ ,
170  * \f$ g_{yy}>0 \f$ , and \f$ g_{xx}g_{yy}>g_{xy}^2 \f$ . Furthermore, if one
171  * maximizes the proper area of a tile with respect to \f$ \Delta x \f$ , one
172  * finds that the \e optimal tile half-width is:
173  * \f[
174  * \Delta x_\mathrm{opt} = \frac{\Delta x_\mathrm{max}}{\sqrt{2}} \; .
175  * \f]
176  *
177  * When estimating the width for the next column, LALTwoDMesh()
178  * computes \f$ \Delta x_\mathrm{opt} \f$ at both the bottom and the top of the
179  * column and uses the smaller value (it is almost always better to
180  * underestimate \f$ \Delta x \f$ than to overestimate it). In
181  * LALTwoDColumn(), tile heights are computed using the column
182  * half-width \f$ \Delta x \f$ and the value of the metric components at its
183  * particular location.
184  *
185  * We also note that the width of a column is computed using the metric
186  * evaluated at the edge joining it to the previous column, and the
187  * height of a tile is computed using the metric evaluated at the edge
188  * joining it to the previous tile. In principle it might be more
189  * accurate to refine our estimate of the column width or tile height by
190  * re-evaluating the metric at their centres, but this may be a
191  * significant excess computational burden. Furthermore, if the metric
192  * varies enough that the estimated width or height changes significantly
193  * over that distance, then the quadratic approximation to the match
194  * function is breaking down, and we shouldn't be treating the
195  * constant-mismatch contour as an ellipse. The routines here do not do
196  * any sophisticated sanity-checking, though.
197  *
198  * ### Uses ###
199  *
200  * \code
201  * lalDebugLevel
202  * LALInfo() XLALPrintError()
203  * LALMalloc() LALDestroyTwoDMesh()
204  * \endcode
205  *
206  * ### Notes ###
207  *
208  */
209 
210 #include <math.h>
211 #include <lal/LALStdlib.h>
212 #include <lal/LALConstants.h>
213 #include <lal/TwoDMesh.h>
214 
215 /** \cond DONT_DOXYGEN */
216 
217 /* Whether or not to track progress internally. */
218 static UINT4 columnNo;
219 
220 /* Local constants. */
221 #define TWODMESHINTERNALC_WMAXFAC (1.189207115)
222 #define TWODMESHINTERNALC_WRETRYFAC LAL_SQRT2
223 
224 /* Local macros. These macros replace repeated code blocks in the
225 routines, and operate within the scope of variables declared within
226 those routines. Required variables are documented below. */
227 
228 
229 /* This macro terminates the current routine if the column is found to
230 be too wide. It frees the linked list, decrements the node count,
231 sets the output flag, prints as an informational message the node
232 count where the error occured, and returns from the current routine.
233 In addition to the passed parameters, the folowing external variables
234 are required:
235 
236 TwoDMeshNode **tail: The list (*tail)->next is destroyed.
237 
238 LALStatus *stat: Used in reporting the error. stat->statusPtr is also
239  used in destroying the list.
240 
241 INT4 lalDebugLevel: Used in reporting the error.
242 
243 TwoDColumnParamStruc *column: The flag column->tooWide is set.
244 
245 TwoDMeshParamStruc *params: The field params->nOut is decremented. */
246 
247 #define TOOWIDERETURN \
248 do { \
249  UINT4 nFree; \
250  if ( lalDebugLevel&LALINFO ) { \
251  LALInfo( stat, "Column too wide" ); \
252  XLALPrintError( "\tnode count %u\n", params->nOut ); \
253  } \
254  TRY( LALDestroyTwoDMesh( stat->statusPtr, &((*tail)->next), \
255  &nFree ), stat ); \
256  params->nOut -= nFree; \
257  column->tooWide = 1; \
258  DETATCHSTATUSPTR( stat ); \
259  RETURN( stat ); \
260 } while (0)
261 
262 
263 /* This macro computes the maximum half-width of a mismatch ellipse
264 given the metric and a mismatch value. If the metric is not
265 positive-definite, an error returned. In addition to the passed
266 parameters, the folowing external variables are required:
267 
268 TwoDMeshNode **tail: The list (*tail)->next is destroyed on an error.
269 
270 LALStatus *stat: Used in reporting an error. stat->statusPtr is also
271  used in destroying the list. */
272 
273 #define GETWIDTH( dx, metric, mismatch ) \
274 do { \
275  REAL4 det = (metric)[0]*(metric)[1] - (metric)[2]*(metric)[2]; \
276  if ( ( (metric)[0] <= 0.0 ) || ( (metric)[1] <= 0.0 ) || \
277  ( det <= 0.0 ) ) { \
278  TRY( LALDestroyTwoDMesh( stat->statusPtr, &((*(tail))->next), \
279  NULL ), stat ); \
280  ABORT( stat, TWODMESHH_EMETRIC, TWODMESHH_MSGEMETRIC ); \
281  } \
282  (dx) = sqrt( (metric)[1]*(mismatch)/det ); \
283 } while (0)
284 
285 
286 /* This macro computes the positions of the right-hand corners of a
287 tile given a tile half width, the metric, and a mismatch value. If
288 the metric is not positive-definite, then an error is returned. If
289 the ellipse is not sufficiently wider than the requested width, then a
290 flag is set and the current subroutine will return. In addition to
291 the passed parameters, the folowing external variables are required:
292 
293 TwoDMeshNode **tail: The list (*tail)->next is destroyed on an error.
294 
295 LALStatus *stat: Used in reporting an error. stat->statusPtr is
296  also used in destroying the list.
297 
298 REAL4 widthMaxFac: The factor by which the maximum ellipse half-width
299  must exceed the given column half-width. */
300 
301 #define GETSIZE( dy, dx, metric, mismatch ) \
302 do { \
303  REAL4 det = (metric)[0]*(metric)[1] - (metric)[2]*(metric)[2]; \
304  REAL4 disc; \
305  if ( ( metric[0] <= 0.0 ) || ( metric[1] <= 0.0 ) || \
306  ( det <= 0.0 ) ) { \
307  TRY( LALDestroyTwoDMesh( stat->statusPtr, &((*(tail))->next), \
308  NULL ), stat ); \
309  ABORT( stat, TWODMESHH_EMETRIC, TWODMESHH_MSGEMETRIC ); \
310  } \
311  if ( widthMaxFac*(dx) > sqrt( (metric)[1]*(mismatch)/det ) ) \
312  TOOWIDERETURN; \
313  disc = sqrt( (metric)[1]*(mismatch) - det*(dx)*(dx) ); \
314  (dy)[0] = ( -metric[2]*dx - disc ) / metric[1]; \
315  (dy)[1] = ( -metric[2]*dx + disc ) / metric[1]; \
316 } while (0)
317 
318 /** \endcond */
319 
320 void
322  TwoDMeshNode **tail,
324 {
325  TwoDColumnParamStruc column; /* parameters for current column */
326  TwoDMeshNode *here; /* current tail of linked list */
327 
328  /* Default parameter values: */
329  REAL4 widthRetryFac = TWODMESHINTERNALC_WRETRYFAC;
330  REAL4 maxColumnFac = 0.0;
331  UINT4 nIn = ( UINT4 )( -1 );
332 
333  INITSTATUS( stat );
335 
336  /* Check that all parameters exist. */
342 
343  /* Check that **tail really is the tail. */
344  ASSERT( !( ( *tail )->next ), stat, TWODMESHH_EOUT, TWODMESHH_MSGEOUT );
345 
346  /* Reassign default parameter values if necessary. */
347  if ( params->widthRetryFac > 1.0 ) {
348  widthRetryFac = params->widthRetryFac;
349  }
350  if ( params->maxColumns > 0 ) {
351  maxColumnFac = 1.0 / params->maxColumns;
352  }
353  if ( params->nIn > 0 ) {
354  nIn = params->nIn;
355  }
356 
357  /* Set the clipping area to something irrelevant. */
358  column.leftClip[1] = column.rightClip[1] = 0.9 * LAL_REAL4_MAX;
359  column.leftClip[0] = column.rightClip[0] = -column.leftClip[1];
360 
361  /* Locate the first column's right-hand edge. */
362  column.domain[0] = params->domain[0];
363  TRY( ( params->getRange )( stat->statusPtr, column.leftRange,
364  column.domain[0], params->rangeParams ),
365  stat );
366 
367  if ( lalDebugLevel >= 3 ) {
368  columnNo = 0;
369  XLALPrintError( " Node count Column count\n" );
370  }
371 
372  /* Main loop: add columns until we're past the end of the space. */
373  here = *tail;
374  while ( column.domain[0] < params->domain[1] ) {
375  REAL4 position[2]; /* position in parameter space */
376  REAL4 metric[3]; /* components of metric at position */
377  REAL4 w1, w2; /* bottom and top widths of column */
378 
379  /* Estimate column width. */
380  position[0] = column.domain[0];
381  position[1] = column.leftRange[0];
382  ( params->getMetric )( stat->statusPtr, metric, position,
383  params->metricParams );
384  BEGINFAIL( stat )
385  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
386  NULL ), stat );
387  ENDFAIL( stat );
388  GETWIDTH( w1, metric, params->mThresh );
389  position[1] = column.leftRange[1];
390  ( params->getMetric )( stat->statusPtr, metric, position,
391  params->metricParams );
392  BEGINFAIL( stat )
393  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
394  NULL ), stat );
395  ENDFAIL( stat );
396  GETWIDTH( w2, metric, params->mThresh );
397  if ( w2 < w1 ) {
398  w1 = w2;
399  }
400  w1 *= LAL_SQRT2;
401 
402  /* Loop to try successively smaller column widths. */
403  do {
404  /* Make sure width is not too small or too big. */
405  if ( maxColumnFac * ( params->domain[1] - params->domain[0] )
406  > w1 ) {
407  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
408  NULL ), stat );
410  }
411  column.domain[1] = column.domain[0] + w1;
412  if ( column.domain[1] > params->domain[1] ) {
413  column.domain[1] = params->domain[1];
414  w1 = column.domain[1] - column.domain[0];
415  }
416 
417  /* Set remaining column parameters. */
418  ( params->getRange )( stat->statusPtr, column.rightRange,
419  column.domain[1], params->rangeParams );
420  BEGINFAIL( stat )
421  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
422  NULL ), stat );
423  ENDFAIL( stat );
424  column.tooWide = 0;
425 
426  /* Call LALTwoDColumn() to place the column. */
427  LALTwoDColumn( stat->statusPtr, &here, &column, params );
428  BEGINFAIL( stat )
429  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
430  NULL ), stat );
431  ENDFAIL( stat );
432 
433  /* See if we've reached the maximum number of mesh points. */
434  if ( params->nOut >= nIn ) {
435  *tail = here;
437  RETURN( stat );
438  }
439 
440  /* If necessary, repeat with a narrower column. */
441  w1 /= widthRetryFac;
442  } while ( column.tooWide );
443 
444  /* Otherwise, go on to the next column. */
445  column.domain[0] = column.domain[1];
446  column.leftRange[0] = column.rightRange[0];
447  column.leftRange[1] = column.rightRange[1];
448  if ( lalDebugLevel >= 3 ) {
449  XLALPrintError( "\r%16u%16u", params->nOut, columnNo++ );
450  }
451  }
452 
453  /* We're done. Update the *tail pointer and exit. */
454  if ( lalDebugLevel >= 3 ) {
455  XLALPrintError( "\n" );
456  }
457 
458  *tail = here;
460  RETURN( stat );
461 }
462 
463 
464 
465 void
467  TwoDMeshNode **tail,
468  TwoDColumnParamStruc *column,
470 {
471  BOOLEAN tiled = 0; /* whether tiles were placed on the centreline */
472  REAL4 position[2]; /* current top of column */
473  REAL4 dx; /* half-width of column */
474  REAL4 myy0, myy1; /* temporary variables storing y-coordinates */
475  REAL4 centreRange[2]; /* centreline of column parameter space */
476  REAL4 centreClip[2]; /* centre of clip boundary */
477  REAL4 leftTiled[2]; /* left side of region tiled */
478  REAL4 rightTiled[2]; /* right side of region tiled */
479  REAL4 metric[3]; /* current metric components */
480  TwoDMeshNode *here; /* current node in list */
481 
482  /* Default parameter values: */
483  REAL4 widthMaxFac = TWODMESHINTERNALC_WMAXFAC;
484  UINT4 nIn = ( UINT4 )( -1 );
485 
486  INITSTATUS( stat );
488 
489  /* Check that all parameters exist. */
496 
497  /* Check that **tail really is the tail. */
498  ASSERT( !( ( *tail )->next ), stat, TWODMESHH_EOUT, TWODMESHH_MSGEOUT );
499  here = *tail;
500 
501  /* Reassign default parameter values if necessary. */
502  if ( params->widthMaxFac > 1.0 ) {
503  widthMaxFac = params->widthMaxFac;
504  }
505  if ( params->nIn > 0 ) {
506  nIn = params->nIn;
507  }
508 
509  /* Set the boundaries of the regions that no longer need tiling. */
510  centreClip[0] = 0.5 * column->leftClip[0] + 0.5 * column->rightClip[0];
511  centreClip[1] = 0.5 * column->leftClip[1] + 0.5 * column->rightClip[1];
512  leftTiled[0] = column->leftClip[1];
513  leftTiled[1] = column->leftClip[0];
514  rightTiled[0] = column->rightClip[1];
515  rightTiled[1] = column->rightClip[0];
516 
517  /* Get the width and heights of this column. */
518  position[0] = 0.5 * ( column->domain[1] + column->domain[0] );
519  dx = 0.5 * ( column->domain[1] - column->domain[0] );
520  TRY( ( params->getRange )( stat->statusPtr, centreRange, position[0],
521  params->rangeParams ), stat );
522 
523  /* Add the column of tiles along the centreline, if the parameter
524  space intersects the clipping area along the centreline. */
525  position[1] = centreClip[0];
526  if ( position[1] < centreRange[0] ) {
527  position[1] = centreRange[0];
528  }
529  if ( position[1] <= centreRange[1] ) {
530 
531  /* Add base tile of column. */
532  tiled = 1;
533  TRY( ( params->getMetric )( stat->statusPtr, metric, position,
534  params->metricParams ), stat );
535  here->next = ( TwoDMeshNode * )LALMalloc( sizeof( TwoDMeshNode ) );
536  if ( here == NULL ) {
538  }
539  memset( here->next, 0, sizeof( TwoDMeshNode ) );
540  params->nOut++;
541  if ( lalDebugLevel >= 3 ) {
542  XLALPrintError( "\r%16u", params->nOut );
543  }
544  GETSIZE( here->next->dy, dx, metric, params->mThresh );
545  here->next->y = position[1];
546  here = here->next;
547  here->x = position[0];
548  here->dx = dx;
549  here->next = here->subMesh = NULL;
550  if ( params->nOut >= nIn ) {
551  *tail = here;
553  RETURN( stat );
554  }
555 
556  /* Determine the region that we've covered. */
557  myy0 = here->y + here->dy[0];
558  myy1 = here->y - here->dy[1];
559  if ( leftTiled[0] > myy1 ) {
560  leftTiled[0] = myy1;
561  }
562  if ( rightTiled[0] > myy0 ) {
563  rightTiled[0] = myy0;
564  }
565  leftTiled[1] = here->y - here->dy[0];
566  rightTiled[1] = here->y + here->dy[1];
567  position[1] = 0.5 * leftTiled[1] + 0.5 * rightTiled[1];
568 
569  /* Continue stacking tiles until we reach the top. */
570  while ( ( position[1] < centreRange[1] ) &&
571  ( position[1] < centreClip[1] ) ) {
572  ( params->getMetric )( stat->statusPtr, metric, position,
573  params->metricParams );
574  BEGINFAIL( stat )
575  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
576  NULL ), stat );
577  ENDFAIL( stat );
578  here->next = ( TwoDMeshNode * )LALMalloc( sizeof( TwoDMeshNode ) );
579  if ( here == NULL ) {
580  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
581  NULL ), stat );
583  }
584  memset( here->next, 0, sizeof( TwoDMeshNode ) );
585  params->nOut++;
586  if ( lalDebugLevel >= 3 ) {
587  XLALPrintError( "\r%16u", params->nOut );
588  }
589  GETSIZE( here->next->dy, dx, metric, params->mThresh );
590  myy0 = here->dy[1] - here->next->dy[0];
591  myy1 = here->next->dy[1] - here->dy[0];
592  if ( myy0 > myy1 ) {
593  myy0 = myy1;
594  }
595  if ( myy0 <= 0.0 ) {
596  TOOWIDERETURN;
597  }
598  here->next->y = here->y + myy0;
599  here = here->next;
600  if ( here->y > centreRange[1] ) {
601  here->y = centreRange[1];
602  }
603  here->x = position[0];
604  here->dx = dx;
605  here->next = here->subMesh = NULL;
606  if ( params->nOut >= nIn ) {
607  *tail = here;
609  RETURN( stat );
610  }
611 
612  /* Extend the covered region upwards. */
613  leftTiled[1] = here->y - here->dy[0];
614  rightTiled[1] = here->y + here->dy[1];
615  position[1] = 0.5 * leftTiled[1] + 0.5 * rightTiled[1];
616  }
617  }
618 
619  /* Centreline stacking is complete. Now check for exposed corners
620  of the parameter space, and call LALTwoDColumn() recursively. */
621 
622  /* Check bottom corners. */
623  myy0 = 0.5 * leftTiled[0] + 0.5 * rightTiled[0];
624 
625  /* Bottom-left: */
626  if ( ( ( column->leftClip[0] < leftTiled[0] ) ||
627  ( centreClip[0] < myy0 ) ) &&
628  ( column->leftRange[0] < leftTiled[0] ) &&
629  ( ( column->leftRange[1] > column->leftClip[0] ) ||
630  ( centreRange[1] > centreClip[0] ) ) ) {
631  TwoDColumnParamStruc column2;
632  column2.domain[0] = column->domain[0];
633  column2.domain[1] = position[0];
634  memcpy( column2.leftRange, column->leftRange, 2 * sizeof( REAL4 ) );
635  memcpy( column2.leftClip, column->leftClip, 2 * sizeof( REAL4 ) );
636  memcpy( column2.rightRange, centreRange, 2 * sizeof( REAL4 ) );
637  memcpy( column2.rightClip, centreClip, 2 * sizeof( REAL4 ) );
638  if ( ( leftTiled[0] < column2.leftClip[1] ) &&
639  ( myy0 < column2.rightClip[1] ) ) {
640  column2.leftClip[1] = leftTiled[0];
641  column2.rightClip[1] = myy0;
642  }
643  LALTwoDColumn( stat->statusPtr, &here, &column2, params );
644  BEGINFAIL( stat )
645  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
646  NULL ), stat );
647  ENDFAIL( stat );
648  if ( params->nOut >= nIn ) {
649  *tail = here;
651  RETURN( stat );
652  }
653  if ( column2.tooWide ) {
654  TOOWIDERETURN;
655  }
656  }
657 
658  /* Bottom-right: */
659  if ( ( ( column->rightClip[0] < rightTiled[0] ) ||
660  ( centreClip[0] < myy0 ) ) &&
661  ( column->rightRange[0] < rightTiled[0] ) &&
662  ( ( column->rightRange[1] > column->rightClip[0] ) ||
663  ( centreRange[1] > centreClip[0] ) ) ) {
664  TwoDColumnParamStruc column2;
665  column2.domain[1] = column->domain[1];
666  column2.domain[0] = position[0];
667  memcpy( column2.rightRange, column->rightRange, 2 * sizeof( REAL4 ) );
668  memcpy( column2.rightClip, column->rightClip, 2 * sizeof( REAL4 ) );
669  memcpy( column2.leftRange, centreRange, 2 * sizeof( REAL4 ) );
670  memcpy( column2.leftClip, centreClip, 2 * sizeof( REAL4 ) );
671  if ( ( rightTiled[0] < column2.rightClip[1] ) &&
672  ( myy0 < column2.leftClip[1] ) ) {
673  column2.rightClip[1] = rightTiled[0];
674  column2.leftClip[1] = myy0;
675  }
676  LALTwoDColumn( stat->statusPtr, &here, &column2, params );
677  BEGINFAIL( stat )
678  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
679  NULL ), stat );
680  ENDFAIL( stat );
681  if ( params->nOut >= nIn ) {
682  *tail = here;
684  RETURN( stat );
685  }
686  if ( column2.tooWide ) {
687  TOOWIDERETURN;
688  }
689  }
690 
691  /* Check top corners. */
692  if ( tiled ) {
693  myy0 = 0.5 * leftTiled[1] + 0.5 * rightTiled[1];
694 
695  /* Top-left: */
696  if ( ( ( column->leftClip[1] > leftTiled[1] ) ||
697  ( centreClip[1] > myy0 ) ) &&
698  ( column->leftRange[1] > leftTiled[1] ) &&
699  ( ( column->leftRange[0] < column->leftClip[1] ) ||
700  ( centreRange[0] < centreClip[1] ) ) ) {
701  TwoDColumnParamStruc column2;
702  column2.domain[0] = column->domain[0];
703  column2.domain[1] = position[0];
704  memcpy( column2.leftRange, column->leftRange, 2 * sizeof( REAL4 ) );
705  memcpy( column2.leftClip, column->leftClip, 2 * sizeof( REAL4 ) );
706  memcpy( column2.rightRange, centreRange, 2 * sizeof( REAL4 ) );
707  memcpy( column2.rightClip, centreClip, 2 * sizeof( REAL4 ) );
708  if ( ( leftTiled[1] > column2.leftClip[0] ) &&
709  ( myy0 > column2.rightClip[0] ) ) {
710  column2.leftClip[0] = leftTiled[1];
711  column2.rightClip[0] = myy0;
712  }
713  LALTwoDColumn( stat->statusPtr, &here, &column2, params );
714  BEGINFAIL( stat )
715  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
716  NULL ), stat );
717  ENDFAIL( stat );
718  if ( params->nOut >= nIn ) {
719  *tail = here;
721  RETURN( stat );
722  }
723  if ( column2.tooWide ) {
724  TOOWIDERETURN;
725  }
726  }
727 
728  /* Top-right: */
729  if ( ( ( column->rightClip[1] > rightTiled[1] ) ||
730  ( centreClip[1] > myy0 ) ) &&
731  ( column->rightRange[1] > rightTiled[1] ) &&
732  ( ( column->rightRange[0] < column->rightClip[1] ) ||
733  ( centreRange[0] < centreClip[1] ) ) ) {
734  TwoDColumnParamStruc column2;
735  column2.domain[1] = column->domain[1];
736  column2.domain[0] = position[0];
737  memcpy( column2.rightRange, column->rightRange, 2 * sizeof( REAL4 ) );
738  memcpy( column2.rightClip, column->rightClip, 2 * sizeof( REAL4 ) );
739  memcpy( column2.leftRange, centreRange, 2 * sizeof( REAL4 ) );
740  memcpy( column2.leftClip, centreClip, 2 * sizeof( REAL4 ) );
741  if ( ( rightTiled[1] > column2.rightClip[0] ) &&
742  ( myy0 > column2.leftClip[0] ) ) {
743  column2.rightClip[0] = rightTiled[1];
744  column2.leftClip[0] = myy0;
745  }
746  LALTwoDColumn( stat->statusPtr, &here, &column2, params );
747  BEGINFAIL( stat )
748  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( ( *tail )->next ),
749  NULL ), stat );
750  ENDFAIL( stat );
751  if ( params->nOut >= nIn ) {
752  *tail = here;
754  RETURN( stat );
755  }
756  if ( column2.tooWide ) {
757  TOOWIDERETURN;
758  }
759  }
760  }
761 
762  /* Everything worked fine, so update *tail and exit. */
763  *tail = here;
764  column->tooWide = 0;
766  RETURN( stat );
767 }
768 
769 
770 
771 void
773  TwoDMeshNode **new,
774  TwoDMeshNode *old )
775 {
776  TwoDMeshNode *tail; /* current tail of old->subMesh */
777  TwoDMeshNode **tailCopy; /* pointer to copy of *tail */
778 
779  INITSTATUS( stat );
781 
782  /* Check parameters. */
786 
787  /* Copy top-level node. */
788  *new = ( TwoDMeshNode * )LALMalloc( sizeof( TwoDMeshNode ) );
789  if ( *new == NULL ) {
791  }
792  **new = *old;
793  ( *new )->next = ( *new )->subMesh = NULL;
794 
795  /* Recursively copy submesh. */
796  tail = old->next;
797  tailCopy = &( ( *new )->next );
798  while ( tail != NULL ) {
799  LALTwoDNodeCopy( stat->statusPtr, tailCopy, tail );
800  BEGINFAIL( stat )
801  TRY( LALDestroyTwoDMesh( stat->statusPtr, new, NULL ), stat );
802  ENDFAIL( stat );
803  tail = tail->next;
804  tailCopy = &( ( *tailCopy )->next );
805  }
806 
807  /* Done. */
809  RETURN( stat );
810 }
#define LALMalloc(n)
#define ABORT(statusptr, code, mesg)
#define ENDFAIL(statusptr)
#define TRY(func, statusptr)
#define ATTATCHSTATUSPTR(statusptr)
#define ASSERT(assertion, statusptr, code, mesg)
#define DETATCHSTATUSPTR(statusptr)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
#define BEGINFAIL(statusptr)
const double w2
#define LAL_REAL4_MAX
#define LAL_SQRT2
unsigned char BOOLEAN
uint32_t UINT4
float REAL4
#define lalDebugLevel
void LALTwoDMesh(LALStatus *stat, TwoDMeshNode **tail, TwoDMeshParamStruc *params)
#define TWODMESHH_MSGENUL
Definition: TwoDMesh.h:111
#define TWODMESHH_EOUT
Definition: TwoDMesh.h:104
#define TWODMESHH_EMEM
Definition: TwoDMesh.h:105
#define TWODMESHH_MSGEMEM
Definition: TwoDMesh.h:113
void LALTwoDColumn(LALStatus *stat, TwoDMeshNode **tail, TwoDColumnParamStruc *column, TwoDMeshParamStruc *params)
#define TWODMESHH_MSGEWIDTH
Definition: TwoDMesh.h:115
#define TWODMESHH_ENUL
Definition: TwoDMesh.h:103
void LALTwoDNodeCopy(LALStatus *stat, TwoDMeshNode **new, TwoDMeshNode *old)
#define TWODMESHH_MSGEOUT
Definition: TwoDMesh.h:112
void LALDestroyTwoDMesh(LALStatus *stat, TwoDMeshNode **mesh, UINT4 *nFree)
Definition: TwoDMesh.c:159
#define TWODMESHH_EWIDTH
Definition: TwoDMesh.h:107
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
This structure stores additional parameters required when laying down a single column of a two-dimens...
Definition: TwoDMesh.h:185
BOOLEAN tooWide
This is set to 1 if the column-placement routine determines that the region is too wide to be covered...
Definition: TwoDMesh.h:191
REAL4 leftClip[2]
The values of the bottom and top corners (in that order) of the clipping boundary at domain[0].
Definition: TwoDMesh.h:189
REAL4 domain[2]
The region in spanned by the column; We require that domain[1] domain[0]
Definition: TwoDMesh.h:186
REAL4 rightClip[2]
The values of the bottom and top corners (in that order) of the clipping boundary at domain[1]
Definition: TwoDMesh.h:190
REAL4 rightRange[2]
The values of , (in that order) of the boundary functions at domain[1]
Definition: TwoDMesh.h:188
REAL4 leftRange[2]
The values , (in that order) of the boundary functions at domain[0]
Definition: TwoDMesh.h:187
This structure represents a single node in a linked list of mesh points, specified in the coordinate ...
Definition: TwoDMesh.h:124
struct tagTwoDMeshNode * next
The next mesh point in the linked list; NULL if this is the tail.
Definition: TwoDMesh.h:128
REAL4 dx
The half-width of the tile centred on the mesh point.
Definition: TwoDMesh.h:126
struct tagTwoDMeshNode * subMesh
The head of a linked list of fine mesh points within the rectangular area spanned by this mesh point ...
Definition: TwoDMesh.h:129
REAL4 dy[2]
The heights of the two right-hand corners of the tile, relative to the mesh point.
Definition: TwoDMesh.h:127
REAL4 y
The coordinates of the mesh point.
Definition: TwoDMesh.h:125
This structure stores the parameters required by the two-dimensional mesh placement functions.
Definition: TwoDMesh.h:142
int domain