LALPulsar  6.1.0.1-fe68b98
TwoDMesh.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 Jolien Creighton, 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 Creates or destroys a hierarchical mesh of templates on an 2-dimensional parameter space.
25  *
26  * ### Description ###
27  *
28  * The routine <tt>LALCreateTwoDMesh()</tt> lays out an unevenly-spaced
29  * mesh on a 2-dimensional parameter space, according to the method
30  * presented in \ref TwoDMesh_h and detailed in
31  * TwoDMeshInternal.c. The parameter \c mesh is a handle to
32  * the head of the newly-created linked list of mesh points, while
33  * \c params points to the parameter structure used to create the
34  * list. On completion, <tt>params->nOut</tt> is set to the number of mesh
35  * points created.
36  *
37  * The routine <tt>LALDestroyTwoDMesh()</tt> destroys the list pointed to
38  * by <tt>*mesh</tt>, including all sub-meshes, and sets
39  * <tt>*mesh</tt>=\c NULL. If <tt>*mesh</tt> is already \c NULL,
40  * nothing is done (this is \e not an erroneous usage). If
41  * \c nFree \f$ \neq \f$ \c NULL, then <tt>*nFree</tt> is set to the number
42  * of nodes freed.
43  *
44  * The routine <tt>LALRefineTwoDMesh()</tt> creates a heirarchical search
45  * mesh by inserting copies of the nodes in the list pointed to by
46  * \c fineMesh into the \c subMesh fields of appropriate nodes in
47  * the list pointed to by \c coarseMesh. The contents of the
48  * \c fineMesh list are untouched. If a \c fineMesh tile does
49  * not overlap with any \c cosarseMesh tile, a warning is generated,
50  * but this is not treated as an error. If an internal error does occur,
51  * the refinement will be left in a state of partial completion; there is
52  * just too much overhead involved in maintaining an uncorrupted copy of
53  * the \c coarseMesh list for it to be worthwhile.
54  *
55  * ### Algorithm ###
56  *
57  * \c LALCreateTwoDMesh() simply creates a dummy node to serve as the
58  * head of the linked list, and calls <tt>LALTwoDMesh()</tt> in
59  * TwoDMeshInternal.c to attach a mesh to it. The details of the
60  * algorithm are given in TwoDMeshInternal.c.
61  *
62  * <tt>LALDestroyTwoDMesh()</tt> navigates down the linked list of mesh
63  * points, destroying them as it goes. It calls itself recursively on
64  * any non-empty sub-meshes to destroy them too.
65  *
66  * <tt>LALRefineTwoDMesh()</tt> moves along the \c fineMesh list; for
67  * each node in the list, it searches the \c coarseMesh list for the
68  * any tile that overlaps with the fine mesh tile. It then \e copies
69  * the fine mesh node (and its submesh, if any) into the coarse mesh
70  * node's \c subMesh list, using <tt>LALTwoDNodeCopy()</tt> in
71  * TwoDMeshInternal.c. Although it uses more memory, this
72  * recursive copy routine is preferred over simple relinking, so as to
73  * avoid any possible memory leaks: destroying the coarse mesh list will
74  * leave the fine mesh list intact, and vice-versa.
75  *
76  * To create a \f$ >2 \f$ ~level hierarchical search mesh, build it from the
77  * bottom up: call <tt>LALRefineTwoDMesh()</tt> to add the finest mesh to
78  * the next finest, add that to the next finest, and so on up to the
79  * coarsest mesh.
80  *
81  * ### Uses ###
82  *
83  * \code
84  * lalDebugLevel XLALPrintError()
85  * LALWarning() LALInfo()
86  * LALTwoDMesh() LALTwoDNodeCopy()
87  * LALFree()
88  * \endcode
89  *
90  * ### Notes ###
91  *
92  */
93 
94 #include <math.h>
95 #include <lal/LALStdlib.h>
96 #include <lal/LALConstants.h>
97 #include <lal/TwoDMesh.h>
98 
99 #ifdef __GNUC__
100 #define UNUSED __attribute__ ((unused))
101 #else
102 #define UNUSED
103 #endif
104 
105 void
107  TwoDMeshNode **mesh,
109 {
110  TwoDMeshNode head; /* dummy head node */
111  TwoDMeshNode *headPtr; /* pointer to above */
112 
113  INITSTATUS( stat );
115 
116  /* Check that input parameters exist, but that the mesh handle
117  points to a null pointer. Parameter fields will be checked
118  within the subroutine. */
121  ASSERT( !( *mesh ), stat, TWODMESHH_EOUT, TWODMESHH_MSGEOUT );
122 
123  /* Ben wants a warning if the widthMaxFac or widthRetryFac are
124  larger than is reasonable. */
125  if ( lalDebugLevel & LALWARNING ) {
126  REAL4 retry = params->widthRetryFac;
127  if ( params->widthMaxFac > LAL_SQRT2 ) {
128  LALWarning( stat, "widthMaxFac > sqrt(2)" );
129  }
130  if ( retry > 1.0 && retry * retry > params->widthMaxFac ) {
131  LALWarning( stat, "widthRetryFac > sqrt(widthMaxFac)" );
132  }
133  }
134 
135  /* Create the list using LALTwoDMesh(). */
136  params->nOut = 0;
137  head.next = NULL;
138  headPtr = &head;
139  if ( lalDebugLevel & LALINFO ) {
140  LALInfo( stat, "Generating mesh\n" );
141  }
142  TRY( LALTwoDMesh( stat->statusPtr, &headPtr, params ), stat );
143  if ( lalDebugLevel & LALINFO )
144  if ( ( params->nIn == 0 ) || ( params->nOut < params->nIn ) ) {
145  XLALPrintError( "\n" );
146  LALInfo( stat, "Mesh complete" );
147  XLALPrintError( "\tnumber of mesh points: %u\n", params->nOut );
148  }
149 
150  /* Update the output, and exit. */
151  *mesh = head.next;
153  RETURN( stat );
154 }
155 
156 
157 
158 void
160  TwoDMeshNode **mesh,
161  UINT4 *nFree )
162 {
163  INITSTATUS( stat );
165 
166  /* Check that all parameters exist. */
168  if ( nFree ) {
169  *nFree = 0;
170  }
171 
172  /* Free everything, recursively freeing sub-meshes if necessary. */
173  while ( *mesh ) {
174  UINT4 nSub = 0; /* nodes freed from sub-meshes */
175  TwoDMeshNode *last = *mesh; /* pointer to previous node */
176  if ( last->subMesh ) {
177  TRY( LALDestroyTwoDMesh( stat->statusPtr, &( last->subMesh ),
178  &nSub ), stat );
179  }
180  *mesh = last->next;
181  LALFree( last );
182  if ( nFree ) {
183  *nFree += nSub + 1;
184  }
185  }
186 
187  /* If we got here without sigsegving, we're done. */
189  RETURN( stat );
190 }
191 
192 
193 
194 void
196  TwoDMeshNode *coarseMesh,
197  TwoDMeshNode *fineMesh )
198 {
199  BOOLEAN UNUSED found; /* whether a fine point is in any coarse tile */
200  UINT4 UNUSED lost = 0; /* number of fine points not found */
201  TwoDMeshNode *here; /* pointer to coarse mesh list */
202 
203  INITSTATUS( stat );
205 
206  ASSERT( coarseMesh, stat, TWODMESHH_ENUL, TWODMESHH_MSGENUL );
208 
209  /* Scan through fine mesh. We never return to the head of the fine
210  mesh, so we can directly increment the parameter *finemesh. */
211  for ( ; fineMesh != NULL; fineMesh = fineMesh->next ) {
212  /* Centre, width, height, and slope of fine tile */
213  REAL4 xFine = fineMesh->x;
214  REAL4 yFine = fineMesh->y;
215  REAL4 dxFine = fineMesh->dx;
216  REAL4 dyFine = 0.5 * ( fineMesh->dy[1] - fineMesh->dy[0] );
217  REAL4 mFine = 0.5 * ( fineMesh->dy[1] + fineMesh->dy[0] ) / dxFine;
218 
219  /* For each fine mesh tile, scan through coarse mesh, and look for
220  ones that overlap in their x domains. */
221  found = 0;
222  for ( here = coarseMesh; here != NULL; here = here->next ) {
223  REAL4 x = here->x - xFine;
224  if ( fabs( x ) <= dxFine + here->dx ) {
225 
226  /* Transform the coarse mesh tile into sheared coordinates
227  centred on the fine mesh tile. */
228  REAL4 y = here->y + mFine * x - yFine;
229  REAL4 dy0 = here->dy[0] + mFine * here->dx;
230  REAL4 dy1 = here->dy[1] + mFine * here->dx;
231 
232  /* See if there is any possibility of overlap. */
233  if ( ( fabs( y ) <= dyFine + fabs( dy0 ) ) ||
234  ( fabs( y ) <= dyFine + fabs( dy1 ) ) ) {
235 
236  /* We check for overlap on the left and right sides of the
237  common domain of the two tiles. On either side, the
238  coarse tile can be either completely below the fine tile
239  (-1), completely above the fine tile (+1), or overlapping
240  it (0). We store this information in two INT2's,
241  below. */
242  INT2 overlap[2] = { 0, 0 };
243 
244  /* Compute height and slope of coarse tile in the sheared
245  coordinates of the fine mesh tile. */
246  REAL4 dy = 0.5 * ( dy1 - dy0 );
247  REAL4 m = 0.5 * ( dy1 + dy0 );
248 
249  /* Find leftmost point of overlap of the two tiles relative
250  to the coarse mesh, and test the range of the coarse-mesh
251  tile at that point. */
252  REAL4 xOver = -here->dx;
253  if ( xOver < -x - dxFine ) {
254  xOver = -x - dxFine;
255  }
256  if ( -dy + m * xOver <= dyFine ) {
257  if ( dy + m * xOver >= -dyFine ) {
258  overlap[0] = 0;
259  } else {
260  overlap[0] = -1;
261  }
262  } else {
263  overlap[0] = 1;
264  }
265 
266  /* Find rightmost point of overlap of the two tiles relative
267  to the coarse mesh, and test the range of the coarse-mesh
268  tile at that point. */
269  if ( overlap[0] ) {
270  xOver = here->dx;
271  if ( xOver > -x + dxFine ) {
272  xOver = -x + dxFine;
273  }
274  if ( -dy + m * xOver <= dyFine ) {
275  if ( dy + m * xOver >= -dyFine ) {
276  overlap[1] = 0;
277  } else {
278  overlap[1] = -1;
279  }
280  } else {
281  overlap[1] = 1;
282  }
283  }
284 
285  /* The two tiles overlap if either side has a value of 0 or
286  if the two sides have opposite sign. */
287  overlap[0] *= overlap[1];
288  if ( !overlap[0] ) {
289 
290  /* This is it! Copy the fine mesh node and add it into
291  the coarse submesh. */
292  TwoDMeshNode *copy = NULL;
293  TRY( LALTwoDNodeCopy( stat->statusPtr, &copy, fineMesh ),
294  stat );
295  copy->next = coarseMesh->subMesh;
296  coarseMesh->subMesh = copy;
297  found = 1;
298  }
299  }
300  }
301  }
302  /* If no coarse tile overlapped, make a note of this. */
303  if ( !found ) {
304  lost++;
305  if ( lalDebugLevel & LALINFO ) {
306  LALInfo( stat, "Fine mesh tile has no overlapping coarse tile" );
307  XLALPrintError( "\tlocation: (%f,%f)\n", xFine, yFine );
308  }
309  }
310  }
311  /* If any fine mesh tiles were lost, warn the user. */
312  if ( lalDebugLevel & LALWARNING )
313  if ( lost > 0 ) {
314  LALWarning( stat, "Some fine mesh tiles were lost" );
315  XLALPrintError( "\tnumber lost = %u\n", lost );
316  }
317 
318  /* Done. */
320  RETURN( stat );
321 }
#define LALFree(p)
#define TRY(func, statusptr)
#define ATTATCHSTATUSPTR(statusptr)
#define ASSERT(assertion, statusptr, code, mesg)
#define DETATCHSTATUSPTR(statusptr)
#define INITSTATUS(statusptr)
#define RETURN(statusptr)
#define LAL_SQRT2
unsigned char BOOLEAN
int16_t INT2
uint32_t UINT4
float REAL4
#define lalDebugLevel
LALINFO
LALWARNING
int LALWarning(LALStatus *status, const char *warning)
int LALInfo(LALStatus *status, const char *info)
static const INT4 m
void LALTwoDMesh(LALStatus *status, TwoDMeshNode **tail, TwoDMeshParamStruc *params)
#define TWODMESHH_MSGENUL
Definition: TwoDMesh.h:111
#define TWODMESHH_EOUT
Definition: TwoDMesh.h:104
#define TWODMESHH_ENUL
Definition: TwoDMesh.h:103
void LALCreateTwoDMesh(LALStatus *stat, TwoDMeshNode **mesh, TwoDMeshParamStruc *params)
Definition: TwoDMesh.c:106
void LALTwoDNodeCopy(LALStatus *status, TwoDMeshNode **new_, TwoDMeshNode *old)
void LALRefineTwoDMesh(LALStatus *stat, TwoDMeshNode *coarseMesh, TwoDMeshNode *fineMesh)
Definition: TwoDMesh.c:195
#define TWODMESHH_MSGEOUT
Definition: TwoDMesh.h:112
void LALDestroyTwoDMesh(LALStatus *stat, TwoDMeshNode **mesh, UINT4 *nFree)
Definition: TwoDMesh.c:159
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
list y
int found
head
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