Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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. */
218static 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
225routines, and operate within the scope of variables declared within
226those routines. Required variables are documented below. */
227
228
229/* This macro terminates the current routine if the column is found to
230be too wide. It frees the linked list, decrements the node count,
231sets the output flag, prints as an informational message the node
232count where the error occured, and returns from the current routine.
233In addition to the passed parameters, the folowing external variables
234are required:
235
236TwoDMeshNode **tail: The list (*tail)->next is destroyed.
237
238LALStatus *stat: Used in reporting the error. stat->statusPtr is also
239 used in destroying the list.
240
241INT4 lalDebugLevel: Used in reporting the error.
242
243TwoDColumnParamStruc *column: The flag column->tooWide is set.
244
245TwoDMeshParamStruc *params: The field params->nOut is decremented. */
246
247#define TOOWIDERETURN \
248do { \
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
264given the metric and a mismatch value. If the metric is not
265positive-definite, an error returned. In addition to the passed
266parameters, the folowing external variables are required:
267
268TwoDMeshNode **tail: The list (*tail)->next is destroyed on an error.
269
270LALStatus *stat: Used in reporting an error. stat->statusPtr is also
271 used in destroying the list. */
272
273#define GETWIDTH( dx, metric, mismatch ) \
274do { \
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
287tile given a tile half width, the metric, and a mismatch value. If
288the metric is not positive-definite, then an error is returned. If
289the ellipse is not sufficiently wider than the requested width, then a
290flag is set and the current subroutine will return. In addition to
291the passed parameters, the folowing external variables are required:
292
293TwoDMeshNode **tail: The list (*tail)->next is destroyed on an error.
294
295LALStatus *stat: Used in reporting an error. stat->statusPtr is
296 also used in destroying the list.
297
298REAL4 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 ) \
302do { \
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
320void
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
465void
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
771void
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