Hitmap 1.3
 All Data Structures Namespaces Files Functions Variables Typedefs Friends Macros Groups Pages
hit_tile.c
Go to the documentation of this file.
1 
15 /*
16  * <license>
17  *
18  * Hitmap v1.2
19  *
20  * This software is provided to enhance knowledge and encourage progress in the scientific
21  * community. It should be used only for research and educational purposes. Any reproduction
22  * or use for commercial purpose, public redistribution, in source or binary forms, with or
23  * without modifications, is NOT ALLOWED without the previous authorization of the copyright
24  * holder. The origin of this software must not be misrepresented; you must not claim that you
25  * wrote the original software. If you use this software for any purpose (e.g. publication),
26  * a reference to the software package and the authors must be included.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND ANY
29  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
31  * THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Copyright (c) 2007-2015, Trasgo Group, Universidad de Valladolid.
39  * All rights reserved.
40  *
41  * More information on http://trasgo.infor.uva.es/
42  *
43  * </license>
44 */
45 
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdarg.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <hit_allocP.h>
52 #include <hit_sshape.h>
53 #include <hit_cshape.h>
54 #include <hit_bshape.h>
55 #include <hit_tile.h>
56 
57 /* Hit NULL VARIABLE */
58 /*
59 unsigned char HitNullData[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 };
60 #define HIT_TILE_NULL_STATIC { 0, HIT_SHAPE_NULL_STATIC, { 0,0,0,0 }, 0, { 0,0,0,0,0 }, { 0,0,0,0 }, &HitNullData, NULL, NULL, HIT_MS_NULL, HIT_NONHIERARCHICAL, HIT_HIERARCHY_UNDEFINED_CHILDREN }
61 */
62 
63 HitTile HIT_TILE_NULL = HIT_TILE_NULL_STATIC;
65 
66 /* DEBUG: DUMP VARIABLE STRUCTURE INFORMATION */ //yuri
67 /*void hit_tileDumpTileInternal(const void *var, const char* name, FILE *file) {
68  int i;
69  const HitTile *v = (const HitTile *)var;
70 
71  fprintf(file,"Dump tile %s, address %p\n",name,var);
72  if (var == NULL) return;
73 
74  fprintf(file,"\tmemStatus: %d\n", v->memStatus);
75  fprintf(file,"\tnumDims: %d\n", hit_shapeDims(v->shape));
76  fprintf(file,"\tbaseExtent: %d\n", (unsigned int) v->baseExtent);
77  for (i=0; i<hit_shapeDims(v->shape); i++) fprintf(file,"\tcard[%d]: %d\n", i, v->card[i]);
78  fprintf(file,"\tacumCard: %d\n", v->acumCard);
79  for (i=0; i<hit_shapeDims(v->shape)+1; i++) fprintf(file,"\torigAcumCard[%d]: %d\n", i, v->origAcumCard[i]);
80  for (i=0; i<hit_shapeDims(v->shape); i++) {
81  fprintf(file,"\tqstride[%d]: %d\n", i, v->qstride[i]);
82  }
83  for (i=0; i<hit_shapeDims(v->shape); i++) {
84  fprintf(file,"\tSig[%d]: %d, %d, %d\n", i, hit_shapeSig(v->shape,i).begin, hit_shapeSig(v->shape,i).end, hit_shapeSig(v->shape,i).stride);
85  }
86  fprintf(file,"\thierDepth: %d\n", v->hierDepth);
87  fprintf(file,"\tchildBegin: { ");
88  for (i=0; i<HIT_MAXDIMS; i++) fprintf(file,"%d ", v->childBegin[i]);
89  fprintf(file,"}\n");
90  fprintf(file,"\tchildSize: { ");
91  for (i=0; i<HIT_MAXDIMS; i++) fprintf(file,"%d ", v->childSize[i]);
92  fprintf(file,"}\n");
93  fprintf(file,"\tdata: %p\n", v->data);
94  fprintf(file,"\tmemPtr: %p\n", v->memPtr);
95  fprintf(file,"\tref: %p\n", (void*) v->ref);
96  fprintf(file,"\n");
97 }*/
98 
99 
100 
101 /* Hit UPDATE MEMORY CARDINALITIES: INTERNAL */
102 static inline void hit_tileUpdateAcumCards(void *newVarP) {
103  HitTile *newVar = (HitTile *)newVarP;
104  int i;
105  int cardinality;
106 
107  newVar->origAcumCard[hit_shapeDims(newVar->shape)] = 1;
108  cardinality=1;
109  for(i=hit_shapeDims(newVar->shape)-1; i>=0; i--) {
110  cardinality = cardinality * newVar->card[i];
111  newVar->origAcumCard[i] = cardinality;
112  }
113  newVar->acumCard = newVar->origAcumCard[0];
114 }
115 
116 
117 /* Hit OFFSET TO THE START OF THE REAL DATA FROM THE FIRST MEMORY POSITION */
118 /* Several uses:
119 * offset to compute the data pointer from the memory start
120 * -offset to compute the data pointer of the global coordinates of a selection
121 */
122 static inline size_t hit_tileOffset(const void *varP) {
123  const HitTile *v = (const HitTile *)varP;
124  int i;
125  size_t offset=0;
126 
127  for (i=0; i<hit_shapeDims(v->shape); i++)
128  offset = offset + (size_t)hit_shapeSig(v->shape,i).begin * (size_t)v->origAcumCard[i+1];
129  return offset;
130 }
131 
132 
133 /* Hit BUILD A TILE ON A SINGLE VARIABLE OF ANY TYPE */
134 /* @arturo Nov 2012 */
135 void hit_tileSingleInternal( void *tileP, void *varP, size_t size ) {
136  HitTile *result = (HitTile *)tileP;
137  *result = HIT_TILE_NULL;
138 
139  /* 1. ONE DIMENSION, ONE ELEMENT */
140  result->shape = hit_shape( 1, hit_sigStd(1) );
141  result->card[0] = 1;
142  result->card[1] = 1;
143  result->acumCard = 1;
144  result->origAcumCard[0] = 1;
145  result->origAcumCard[1] = 1;
146  result->qstride[0] = 1;
147 
148  /* 2. NOT_OWNER MEMORY STATUS, THE FREE OPERATION SHOULD IGNORE IT, IT WORKS LIKE A SELECTION */
149  result->memStatus = HIT_MS_NOT_OWNER;
150  result->data = varP;
151 
152  /* 3. OTHER FIELDS */
153  result->baseExtent = size;
154  result->hierDepth = 0;
155 
156  /* 4. RETURN NEW TILE */
157  return;
158 }
159 
160 
161 /* Hit VARIABLE DECLARATION: ARRAY */
162 void hit_tileDomainInternal(void *newVarP, size_t baseExtent, int hierDepth, int numDims, ...){
163  int i;
164  va_list ap;
165  HitPTile newVar = (HitPTile)newVarP;
166  *newVar = HIT_TILE_NULL;
167 
168 #ifdef DEBUG
169 fprintf(stderr,"CTRL DomainInternal, baseExtent: %d, hierDepth: %d, numDims: %d\n", (unsigned int)baseExtent, hierDepth, numDims);
170 #endif
171 
172  /* 1. NUM OF DIMENSIONS, MARK NO MEMORY STATUS, AND NULL POINTERS */
173  hit_shapeDimsSet(newVar->shape,numDims);
174  newVar->baseExtent = baseExtent;
175  newVar->memStatus = HIT_MS_NOMEM;
176  newVar->hierDepth = (char)hierDepth;
177  newVar->ref = NULL;
178  newVar->data = NULL;
179  newVar->memPtr = NULL;
180 
181  /* 2. PROCESS PARAMETERS AS CARDINALITIES */
182  va_start(ap, numDims);
183  for(i=0; i<numDims; i++) {
184  newVar->card[i] = va_arg(ap, int);
185  // @arturo Oct 2016: RETURN NULL FOR INVALID SHAPES
186  if ( newVar->card[i] < 1 ) { *newVar = HIT_TILE_NULL; return; }
187  hit_shapeSig(newVar->shape,i).begin = 0;
188  hit_shapeSig(newVar->shape,i).end = newVar->card[i]-1;
189  hit_shapeSig(newVar->shape,i).stride = 1;
190  newVar->qstride[i] = 1;
191  }
192  va_end(ap);
193 
194  /* 3. COMPUTE ACCUMULATED CARDINALITIES */
195  hit_tileUpdateAcumCards(newVar);
196 }
197 
198 
199 /* Hit VARIABLE DECLARATION WITH SHAPE: ARRAY */
200 void hit_tileDomainShapeInternal(void * newVarP, size_t baseExtent, int hierDepth, HitShape shape) {
201  int i;
202  HitPTile newVar = (HitPTile)newVarP;
203  *newVar = HIT_TILE_NULL;
204 
205 #ifdef DEBUG
206 fprintf(stderr,"CTRL DomainShapeInternal, baseExtent: %d, hierDepth: %d\n", (unsigned int)baseExtent, hierDepth);
207 #endif
208 
209  /* 1. NUM OF DIMENSIONS, MARK NO MEMORY STATUS, AND NULL POINTERS */
210  newVar->shape = shape;
211  newVar->baseExtent = baseExtent;
212  newVar->memStatus = HIT_MS_NOMEM;
213  newVar->hierDepth = (char)hierDepth;
214  newVar->ref = NULL;
215  newVar->data = NULL;
216  newVar->memPtr = NULL;
217 
218  /* 2. PROCESS PARAMETERS AS CARDINALITIES */
219  if( hit_shapeType(shape) == HIT_SIG_SHAPE ){
220  for(i=0; i<hit_shapeDims(newVar->shape); i++) {
221  /* if stride is not greater than 0, the domain is erroneous */
222  newVar->card[i] = (hit_shapeSig(shape,i).stride>0) ? hit_sigCard(hit_shapeSig(shape,i)) : 0;
223  newVar->qstride[i] = 1;
224  }
225  } else {
226  newVar->card[0] = hit_cShapeNvertices(shape);
227  newVar->qstride[0] = 1;
228  }
229 
230  /* 3. COMPUTE ACCUMULATED CARDINALITIES */
231  hit_tileUpdateAcumCards(newVar);
232 }
233 
234 
235 
236 
237 
238 
239 
240 
241 
242 /* Hit VARIABLE DECLARATION AND INITIALIZATION: ARRAY */
243 void hit_tileAllocInternal(void *newVarP, const char *name, const char *file, int numLine) {
244  HitPTile newVar = (HitPTile)newVarP;
245 
246 
247  /* 0. SKIP ALLOC WHEN NULL OR WHEN CARDINALITY=0 */
248  if ( newVar->memStatus == HIT_MS_NULL || newVar->acumCard==0 ) return;
249 
250 
251  /* 1. CHECK VARIABLE TYPE, CANNOT ALREADY HAVE ITS OWN MEMORY */
252  if ( newVar->memStatus == HIT_MS_OWNER ){
253  hit_errInternal(__FUNCTION__,"Trying to reallocate a Tile: ",name,file,numLine);
254  }
255 
256  /* 2. (v0.9.2 Change) MEMORY FOR THE DATA */
257 #ifdef DEBUG
258 fprintf(stderr,"CTRL Alloc Internal: Mem size: %d x %d = %d\n", newVar->acumCard,
259  (unsigned int)newVar->baseExtent,
260  (unsigned int)newVar->acumCard * (unsigned int)newVar->baseExtent);
261 #endif
262 
263  // @arturo Ago 2015: New allocP interface
264  // hit_malloc(newVar->memPtr,(size_t)newVar->acumCard * newVar->baseExtent,void*);
265  hit_vmalloc(newVar->memPtr, (size_t)newVar->acumCard * newVar->baseExtent);
266  newVar->data = newVar->memPtr;
267 
268  /* 3. UPDATES FOR SHADOW COPIES, OR ALLOCATION OF SELECTIONS OF NO-MEMORY VARIABLES */
269  if ( newVar->memStatus == HIT_MS_NOT_OWNER
270  || newVar->memStatus == HIT_MS_NOMEM ) {
271  /* 3.1. NEW STRIDES TO ACCESS ARE ALWAYS 1 */
272  int i;
273  for (i=0; i<hit_shapeDims(newVar->shape); i++) newVar->qstride[i] = 1;
274 
275  /* 3.2. UPDATE ORIGINAL ACUMULATED CARDINALITIES, NOW IT HAS ITS OWN MEMORY */
276  hit_tileUpdateAcumCards(newVar);
277  }
278 
279  /* 4. CHANGE MEMORY STATUS */
280  newVar->memStatus = HIT_MS_OWNER;
281 
282  /* 5. END */
283 }
284 
285 
286 
287 /* Hit SIGNATURE HELPER: ONLY USED IN THE hit_tileFill FUNCTIONALITY */
288 static inline int hit_sigBlockSizeInternal( HitSig a ) {
289  /* 1. TRIVIAL CASE: STRIDE = 1 */
290  if ( a.stride == 1 ) return (a.end - a.begin + 1);
291  /* 2. NORMALIZE THE END COMPONENT */
292  int jumps = (a.end - a.begin) / a.stride;
293  a.end = a.begin + jumps * a.stride;
294  /* 3. COMPUTE SIZE OF THE BLOCK */
295  return (a.end - a.begin + a.stride);
296 }
297 
298 
299 /* Hit FILL UTILITY: RECURSIVELY UPDATE THE ARRAY COORDINATES OF A REGULAR MULTILEVEL HIERARCHY */
301  int dim;
302  int displacement[HIT_MAXDIMS] = { 0, 0, 0, 0 };
303 
304  /* 1. COMPUTE DISPLACEMENTS AND UPDATE ARRAY COORDINATES */
305  for(dim=0; dim < hit_tileDims(*root); dim++) {
306  displacement[dim] = coords[dim] * hit_sigBlockSizeInternal( hit_tileDimSig(*root,dim) );
307 
308  hit_tileDimBegin(*root,dim) = displacement[dim] + hit_tileDimBegin(*root,dim);
309  hit_tileDimEnd(*root,dim) = displacement[dim] + hit_tileDimEnd(*root,dim);
310  }
311 
312  /* 2. RECURSION END */
313  if ( root->hierDepth == HIT_NONHIERARCHICAL ) return;
314 
315  /* 3. TRAVERSE ALL POSITIONS OF ROOT TILE TO RECURSIVELY UPDATE THEIR COORDINATES */
316  int ind[HIT_MAXDIMS];
317  memset(ind, 0, (size_t)hit_tileDims(*root)*sizeof(int));
318 
319  int i,j;
320  for(i=0; i < root->acumCard; i++) {
321  /* 3.1. COMPUTE THE offset IN PARENT MEMORY AND GET CHILD POINTER */
322  size_t offset=0;
323  for(j=0; j < hit_tileDims(*root); j++)
324  offset += (size_t)ind[j] * (size_t)root->qstride[j] * (size_t)root->origAcumCard[j+1];
325  HitTile *child = (HitTile *)( (char *)root->data + offset * root->baseExtent );
326 
327  /* 3.2. RECURSION */
328  hit_tileFillUpdateArrayCoordinatesRec( child, displacement );
329 
330  /* 3.3. NEXT COORDINATES */
331  j = hit_shapeDims( root->shape )-1;
332  do{
333  ind[j] = (ind[j]+1) % (root->card[j]);
334  if ( ind[j] != 0 ) break;
335  j--;
336  } while( j >= 0 );
337  }
338 }
339 
340 
341 /* Hit FILL: FILL A TILE WITH A GIVEN VALUE */
342 void hit_tileFillInternal(void * varP, void * value, const char *name, const char *file, int numLine) {
343  HitTile *var = (HitTile *)varP;
344  int i;
345  int ind[HIT_MAXDIMS], j;
346  size_t offset;
347  char *ptr;
348  HitTile reducedDomainVar[2];
349 
350  /* NOTE: CHECKING IF THE TARGET VARIABLE IS A MULTILEVEL-HIERARCHY ONLY ONCE IS
351  * MORE EFFICIENT, BUT IT HAS IMPLIED THE DUPLICATING OF SOME CODE */
352 
353  /* 0.1. SKIP FILLING NULL OR TILES WITH NO MEMORY */
354  if ( var->memStatus == HIT_MS_NULL || var->memStatus == HIT_MS_NOMEM ) return;
355 
356 /* @arturo: Jul 2014.
357  * BUG CORRECTED: Fill of selection variables with no boundary that extend beyond limits
358  * The function accessed elements that were not in the original allocated variable */
359  /* 0.2. SELECTION VARIABLES THAT EXPAND BEYOND LIMITS OF THE FIRST ALLOCATED ANCESTOR
360  * SUBSELECT THE INTERSECTION OF SHAPES */
361  /* 0.2.1. LOCATE THE FIRST ALLOCATED ANCESTOR */
362  HitTile *ancestor = var;
363  while ( ancestor->memStatus != HIT_MS_OWNER ) ancestor = ancestor->ref;
364  /* 0.2.2. INTERSECT SHAPES */
365  if ( ancestor != var ) {
366  HitShape intersection = hit_shapeIntersect( hit_tileShape(*var),hit_tileShape(*ancestor) );
367 
368  /* 0.2.3. SUBSTITUTE THE VARIABLE BY A SELECTION OF THE INTERSECTION */
369  hit_tileSelectArrayCoords( &reducedDomainVar[0], var, intersection );
370  var = &reducedDomainVar[0];
371  }
372 
373  /* 0.4. INTERSECTIONS MAY DERIVE IN AN EMPTY VARIABLE */
374  if ( var->memStatus == HIT_MS_NULL ) return;
375 
376  /* 1. SHALLOW TILES (NATIVE OR PROGRAMMER-DEFINED BASE TYPE) */
377  if( var->hierDepth == HIT_NONHIERARCHICAL ) {
378  switch( var->memStatus ) {
379  /* 1.1. REAL OWNER VARIABLE, SET ALL THE CONTIGUOS DATA */
380  case HIT_MS_OWNER:
381  ptr=(char *)var->data;
382  for(i=0; i<var->acumCard; i++) {
383  memcpy(ptr, value, var->baseExtent);
384  ptr += var->baseExtent;
385  }
386  break;
387 
388  /* 1.2. SELECTION, COPY DATA LIKE AN UPDATE, LOCATING EACH POSITION ON PARENT */
389  case HIT_MS_NOT_OWNER:
390  /* 1.2.1. INITIALISE ind WITH 0 */
391  memset(ind,0, (size_t)hit_shapeDims(var->shape)*sizeof(int));
392  /* 1.2.2. TRAVERSE ALL POSITIONS */
393  for(i=0;i<var->acumCard;i++) {
394  /* 1.2.2.1. COMPUTE THE offset IN PARENT MEMORY */
395  offset=0;
396  for(j=0;j<hit_shapeDims(var->shape);j++) {
397  offset += (size_t)ind[j] * (size_t)var->qstride[j] * (size_t)var->origAcumCard[j+1];
398  }
399  /* 1.2.2.2. COPY DATA ON THE POSITION */
400  memcpy( (char *)var->data+offset*var->baseExtent, value, var->baseExtent );
401 
402  /* 1.2.2.3. NEXT POSITION */
403  j=hit_shapeDims(var->shape)-1;
404  do{
405  ind[j]=(ind[j]+1)% (var->card[j]);
406  if (ind[j]!=0) break;
407  j--;
408  } while(j>=0);
409  }
410  break;
411 
412  /* 1.3. PARANOID CHECK: IMPOSIBLE STATE */
413  default: hit_errInternal("tileFill", "Unknown memory state in variable to fill:", name, file, numLine);
414  break;
415  }
416  }
417  /* 2. MULTILEVEL HIERARCHY OF TILES */
418  else if (var->hierDepth > 0) { // PARANOID CHECK
419  HitTile *child = (HitTile *)value;
420 
421  /* 2.1. UPDATE THE LEVEL OF THE HIERARCHY */
422  var->hierDepth = (char)((int)(child -> hierDepth) + 1);
423 
424  /* 2.2. UPDATE THE childSize/childBegin FIELDS WITH CHILDREN INFORMATION */
425  for ( i=0; i < hit_tileDims(*child); i++ ) {
426  /* 2.3.1. GET THE SIZE OF THE NORMALIZED SIGNATURE */
427  var->childSize[i] = hit_sigBlockSizeInternal( hit_tileDimSig( *child, i ) );
428 
429  /* 2.3.2. IF CHILDREN TILES ARE ALSO MULTILEVEL, MULTIPLY BY THEIR CHILDREN SIZE */
430  /* NOTE: IF CHILDREN DOMAINS ARE NOT INITIALIZED, childSize IS MULTIPLIED BY ZERO!!! */
431  if ( child->hierDepth ) var->childSize[i] *= child->childSize[i];
432 
433  /* 2.3.3. GET THE STARTING ARRAY COORDINATE OF CHILDREN */
434  if ( child->hierDepth )
435  var->childBegin[i] = child->childSize[i] * hit_tileDimBegin( *child, i )
436  + child->childBegin[i];
437  else
438  var->childBegin[i] = hit_tileDimBegin( *child, i );
439  }
440 
441  /* 2.3. CLONE ELEMENTS AND UPDATE THEIR ARRAY COORDINATES */
442  switch( var->memStatus ) {
443  /* 2.3.1. REAL OWNER VARIABLE, CLONE THE SUB-TILE ON EACH POSITION */
444  case HIT_MS_OWNER:
445  /* WE NEED THE ELEMENT ARRAY INDEXES TO UPDATE THE LOWER LEVEL COORDINATES
446  * THUS, USE THE CODE OF THE NOT_OWNER MEMORY STATUS
447  ptr=var->data;
448  for(i=0;i<var->acumCard;i++) {
449  hit_tileCloneInternal(ptr, value, name, file, numLine);
450  ptr = (char *)ptr + var->baseExtent;
451  }
452  break;
453  */
454 
455  /* 2.3.2. SELECTION, COPY DATA LIKE AN UPDATE, LOCATING EACH POSITION ON PARENT */
456  case HIT_MS_NOT_OWNER:
457  /* 2.3.2.1. INITIALISE ind WITH 0 */
458  memset(ind,0, (size_t)hit_shapeDims(var->shape)*sizeof(int));
459  /* 2.3.2.2. TRAVERSE ALL POSITIONS */
460  for(i=0;i<var->acumCard;i++) {
461  /* 2.3.2.2.1. COMPUTE THE offset IN PARENT MEMORY */
462  offset=0;
463  for(j=0;j<hit_shapeDims(var->shape);j++) {
464  offset += (size_t)ind[j] * (size_t)var->qstride[j] * (size_t)var->origAcumCard[j+1];
465  }
466  /* 2.3.2.2.2. CLONE THE INPUT SUB-TILE ON THE POSITION */
467  HitTile *pos = (HitTile *)((char *)var->data+offset*var->baseExtent);
468  hit_tileCloneInternal( (char *)pos, value, name, file, numLine );
469 
470  /* TODO: Patch (TO BE DEPRECATED IN v1.2, see PERSONAL NOTES Nov-2011-02.1) */
471  pos->ancestor = (HitTile*) varP;
472 
473 
474  pos->ref=NULL;
475 
476  /* 2.3.2.2.3. RECURSIVELY UPDATE THE ARRAY COORDINATES */
477  int arrayCoords[HIT_MAXDIMS] = { 0, 0, 0, 0 };
478  for(j=0;j<hit_shapeDims(var->shape);j++)
479  arrayCoords[j] = ind[j] * hit_tileDimStride(*var,j) + hit_tileDimBegin(*var,j);
480  hit_tileFillUpdateArrayCoordinatesRec( pos, arrayCoords );
481 
482  /* 2.3.2.2.4. NEXT POSITION */
483  j=hit_shapeDims(var->shape)-1;
484  do{
485  ind[j]=(ind[j]+1)% (var->card[j]);
486  if (ind[j]!=0) break;
487  j--;
488  } while(j>=0);
489  }
490  break;
491 
492  /* 2.3.3. PARANOID CHECK: IMPOSIBLE STATE */
493  default: hit_errInternal("tileFill", "Unknown memory state in variable to fill:", name, file, numLine);
494  break;
495  }
496  }
497  /* 3. PARANOID CHECK: NEGATIVE VALUE IN HIERARCHY-LEVEL FIELD */
498  else hit_errInternal("tileFill", "Negative value in hierarchy-level of variable:", name, file, numLine);
499 }
500 
501 
502 
503 /* Hit MULTILEVEL TILES: LOCATE BLOCK WHICH CONTAINS THE GIVEN ARRAY COORDINATES */
504 void *hit_mtileBlockArrayCoord( HitTile *root, int coords[HIT_MAXDIMS] ) {
505  int thisLevelTileCoords[HIT_MAXDIMS];
506 
507  /* 0. CHECK: SHOULD NOT BE NULL AND MEMORY SHOULD BE INITIALIZED */
508  if ( root->memStatus == HIT_MS_NULL || root->memStatus == HIT_MS_NOMEM ) return NULL;
509 
510  /* 1. TRANSFORM TO ROOT TILE COORDINATES USING THE CHILDREN BLOCK INFORMATION */
511  int dim;
512  for ( dim=0; dim < hit_tileDims(*root); dim++ ) {
513  /* 1.1. TRANSFORM TO LOCAL BLOCK COORDINATES */
514  int arrayCoord = (int)floor(( coords[dim] - root->childBegin[dim] ) / (double)root->childSize[dim]);
515  /* 1.2. CHECK IF THE BLOCK IS IN THE ROOT TILE DOMAIN */
516  if ( ! hit_sigIn( hit_tileDimSig(*root,dim), arrayCoord ) ) return NULL;
517  /* 1.3. STORE THE TILE COORDINATE */
518  thisLevelTileCoords[dim] = (int)floor(( arrayCoord - hit_tileDimBegin(*root,dim) ) / (double)hit_tileDimStride(*root,dim) );
519  }
520 
521  /* 2. IF IT IS A LEAF, RETURN THE TILE */
522  if ( root->hierDepth == HIT_NONHIERARCHICAL ) return root;
523 
524  /* 3. NOT A LEAF, RECURSION WITH THE CHILD ELEMENT */
525  size_t offset;
526  int j;
527  offset=0;
528  for(j=0; j < hit_tileDims(*root); j++) {
529  offset += (size_t)thisLevelTileCoords[j] * (size_t)root->qstride[j] * (size_t)root->origAcumCard[j+1];
530  }
531  HitTile *child = (HitTile *) root->data + offset;
532  return hit_mtileBlockArrayCoord( child, coords );
533 }
534 
535 /* Hit MULTILEVEL TILES: LOCATE THE ELEMENT WITH THE GIVEN ARRAY COORDINATES */
536 void *hit_mtileElemAtArrayCoord( HitTile *root, int coords[HIT_MAXDIMS] ) {
537  int thisLevelTileCoords[HIT_MAXDIMS];
538 
539  /* 0. CHECK: SHOULD NOT BE NULL AND MEMORY SHOULD BE INITIALIZED */
540  if ( root->memStatus == HIT_MS_NULL || root->memStatus == HIT_MS_NOMEM ) return NULL;
541 
542  /* 1. TRANSFORM TO ROOT TILE COORDINATES USING THE CHILDREN BLOCK INFORMATION */
543  int dim;
544  for ( dim=0; dim < hit_tileDims(*root); dim++ ) {
545  /* 1.1. TRANSFORM TO LOCAL BLOCK COORDINATES */
546  int arrayCoord = (int)floor(( coords[dim] - root->childBegin[dim] ) / (double)root->childSize[dim]);
547  /* 1.2. CHECK IF THE BLOCK IS IN THE ROOT TILE DOMAIN */
548  if ( ! hit_sigIn( hit_tileDimSig(*root,dim), arrayCoord ) ) return NULL;
549  /* 1.3. STORE THE TILE COORDINATE */
550  thisLevelTileCoords[dim] = (int)floor(( arrayCoord - hit_tileDimBegin(*root,dim) ) / (double)hit_tileDimStride(*root,dim) );
551  }
552 
553  /* 2. LOCATE THE TILE ELEMENT */
554  size_t offset;
555  int j;
556  offset=0;
557  for(j=0; j < hit_tileDims(*root); j++) {
558  offset += (size_t)thisLevelTileCoords[j] * (size_t)root->qstride[j] * (size_t)root->origAcumCard[j+1];
559  }
560 
561  /* 3. IF IT IS A LEAF, RETURN THE ELEMENT POINTER */
562  if ( root->hierDepth == HIT_NONHIERARCHICAL ) return (char *)root->data + offset * root->baseExtent;
563 
564  /* 4. NOT A LEAF, RECURSION WITH THE CHILD ELEMENT */
565  return hit_mtileElemAtArrayCoord( (HitTile *)root->data + offset, coords );
566 }
567 
568 
569 
570 
571 /* Hit FUNCTION TO READ/WRITE TILES FROM/TO BINARY OR TEXT FILES USING A GIVEN FORMAT */
573  void * varP,
574  const int fileFormat,
575  const int fileMode,
576  const int tileMode,
577  const int type,
578  const int formatSize1, const int formatSize2,
579  const char *fileName,
580  const char *debugVarName,
581  const char *debugCodeFile,
582  int debugCodeLine
583  ) {
584 
585  HitTile *var = (HitTile *)varP;
586 
587  /* 1. CHECK FILE MODE PARAMETER.
588  * WRITE MODE: ENSURE THAT THE FILE IS CREATED
589  * (IT AVOIDS CONCURRENCY PROBLEMS WHEN OPENING IN OVER-WRITE MODE) */
590  int ok;
591  switch ( fileMode ) {
592  case HIT_FILE_READ: break;
593 
594  case HIT_FILE_WRITE:
595  ok = open( fileName, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR );
596  if (ok == -1) hit_errInternal(__FUNCTION__, "Creating file", fileName, debugCodeFile, debugCodeLine);
597  close( ok );
598  break;
599 
600  default:
601  hit_errInternal(__FUNCTION__, "Unknown file mode", debugVarName, debugCodeFile, debugCodeLine);
602  break;
603  }
604 
605  /* @arturo Feb 2013: Open file before checking if the variable is empty to generate
606  * and empty file instead of skipping the file creation for empty variables.
607  * This helps in tracing, debugging and scripting.
608  */
609  /* 2. SKIP HIT_TILE_NULL VARIABLE AND VARIABLES WITH NO MEMORY */
610  if ( var->memStatus == HIT_MS_NULL || var->memStatus == HIT_MS_NOMEM ) return 1;
611 
612  /* 3. DECLARE VARIABLES */
613  int ind[HIT_MAXDIMS],i,j,indsh[HIT_MAXDIMS];
614  size_t offset;
615  long file_offset;
616  void *ptr = NULL;
617  char patternRead[32];
618  char patternWrite[32];
619 
620  /* 4. OPEN FILE FOR READ/WRITE */
621  FILE *fich;
622  fich = fopen(fileName,"r+");
623  if ( fich == NULL )
624  hit_errInternal(__FUNCTION__, "Fail opening file", fileName, debugCodeFile, debugCodeLine);
625 
626  /* 5. BUILD FORMAT */
627  if ( fileFormat != HIT_FILE_BINARY ) {
628  switch ( type ) {
629  case HIT_FILE_INT:
630  sprintf( patternRead, "%%0%dd\n", formatSize1 );
631  sprintf( patternWrite, "%%0%dd\n", formatSize1 );
632  break;
633  case HIT_FILE_LONG:
634  sprintf( patternRead, "%%0%dld\n", formatSize1 );
635  sprintf( patternWrite, "%%0%dld\n", formatSize1 );
636  break;
637  case HIT_FILE_FLOAT:
638  sprintf( patternRead, "%%0%df\n", formatSize1 );
639  sprintf( patternWrite, "%%0%d.%df\n", formatSize1, formatSize2 );
640  break;
641  case HIT_FILE_DOUBLE:
642  sprintf( patternRead, "%%0%dlf\n", formatSize1 );
643  sprintf( patternWrite, "%%0%d.%dlf\n", formatSize1, formatSize2 );
644  break;
645  default:
646  hit_errInternal(__FUNCTION__, "Unknown file type for variable", debugVarName, debugCodeFile, debugCodeLine);
647  break;
648  }
649  }
650 
651  /* 6. LOCATE THE ROOT TILE TO GET THE ORIG ACUM CARDS OF THE ARRAY COORDINATES
652  * THEY ARE USED TO COMPUTE POSITIONS IN THE FILE WHEN USING ARRAY COORDINATES MODE
653  *
654  * THIS CARDS ARE DIFFERENT FROM CURRENT origAcumCard WHEN AN ANCESTOR OF THIS VARIABLE
655  * IS A SELECTION OF THE ARRAY WHICH ALLOCATED MEMORY BEFORE CREATING NEW SELECTIONS
656  * OF IT
657  *
658  * WARNING: IT DOES NOT WORK FOR ROOT ARRAYS THAT DO NOT START AT 0, OR HAVE INITIAL STRIDE
659  */
660  HitTile *rootTile;
661  for (rootTile = var; rootTile->ref != NULL; rootTile = rootTile->ref);
662 
663  /* Patch for BlockTiles (TO BE DEPRECATED) */
664  for ( ; rootTile->ancestor != NULL; rootTile = rootTile->ancestor);
665  //int *rootChildSize = rootTile->childSize;
666  //int acumChildSizes[5] = { 0, 0, 0, 0, 0 };
667  //acumChildSizes[ hit_shapeDims(var->shape) ] = 1;
668  //for( i=hit_shapeDims(var->shape)-1; i>=0; i-- ) acumChildSizes[i] = acumChildSizes[i+1] * rootChildSize[i];
669  for ( ; rootTile->ref != NULL; rootTile = rootTile->ref);
670  /* END Patch for BlockTiles */
671 
672  /* Patch for Padded tiles, used in BlockTiles (TO BE DEPRECATED) */
673  if ( var->unpadded != NULL ) var = var->unpadded;
674  /* END Patch for Padded tiles */
675 
676 
677  int *rootAcumCard = rootTile->origAcumCard;
678 
679  /* 7. ARRAY MODE: INITIALISE indsh WITH THE SIGNATURE-BEGIN OF THE CORRESPONDING DIMENSION */
680  if ( tileMode == HIT_FILE_ARRAY )
681  for( i=0; i<hit_shapeDims(var->shape); i++ )
682  indsh[i] = hit_shapeSig(var->shape,i).begin;
683 
684  /* 8. INITIALIZATION OF MEMORY LOCATION POINTERS/INDECES */
685  /* 8.1. REAL OWNER VARIABLE: INITIALIZE POINTER AT BEGINNING OF DATA REGION */
686  if ( var->memStatus == HIT_MS_OWNER ) ptr = var->data;
687  /* 8.2. SELECTION VARIABLES: INITIALIZE INDECES TO LOCATE DATA IN MEMORY */
688  else for( i=0; i<hit_shapeDims(var->shape); i++ ) ind[i] = 0;
689 
690  /* 9. FOR ALL ELEMENTS IN THE TILE */
691  for( i=0; i<var->acumCard; i++ ) {
692  /* 9.1. SELECTION VARIABLE: LOCATE NEXT ELEMENT IN MEMORY */
693  if ( var->memStatus == HIT_MS_NOT_OWNER ) {
694  offset = 0;
695  for( j=0; j<hit_shapeDims(var->shape); j++) {
696  offset += (size_t)ind[j] * (size_t)var->qstride[j] * (size_t)var->origAcumCard[j+1];
697  }
698  ptr = (char *)var->data + offset * (size_t)var->baseExtent;
699  }
700 
701  /* 9.2. ARRAY MODE: COMPUTE OFFSET IN THE FILE AND RELOCATE FILE POINTER */
702  if ( tileMode == HIT_FILE_ARRAY ) {
703  file_offset = 0;
704  for( j=0; j<hit_shapeDims(var->shape); j++) {
705  file_offset += indsh[j] * rootAcumCard[j+1];
706  /* Patch for BlockTiles (TO BE DEPRECATED) */
707  //file_offset += indsh[j] * acumChildSizes[j+1] * rootAcumCard[j+1];
708  }
709  /* 9.2.1. BINARY FORMAT */
710  if ( fileFormat == HIT_FILE_BINARY )
711  ok = fseek( fich, file_offset * (long)var->baseExtent, SEEK_SET );
712  /* 9.2.2. TEXT FORMAT */
713  else
714  ok = fseek( fich, file_offset * (formatSize1 + 1), SEEK_SET );
715 
716  /* 9.2.3. CHECK ERROR */
717  if ( ok != 0 ) {
718  fclose( fich );
719  hit_errInternal(__FUNCTION__, "Positioning in file", fileName, debugCodeFile, debugCodeLine);
720  }
721  }
722 
723  /* 9.3. TRY OPERATION: USE THE APROPRIATE DATA TYPE AND FORMAT */
724  int result = 0;
725  /* 9.3.1. BINARY FORMAT */
726  if ( fileFormat == HIT_FILE_BINARY ) {
727  switch ( fileMode ) {
728  case HIT_FILE_READ: result = (int)fread( ptr, var->baseExtent, 1, fich );
729  break;
730  case HIT_FILE_WRITE: result = (int)fwrite( ptr, var->baseExtent, 1, fich );
731  break;
732  }
733  }
734  /* 9.3.2. TEXT FORMAT */
735  else {
736  switch ( fileMode ) {
737  case HIT_FILE_READ:
738  switch ( type ) {
739  case HIT_FILE_INT: result = fscanf( fich, patternRead, (int*)(ptr) );
740  break;
741  case HIT_FILE_LONG: result = fscanf( fich, patternRead, (long*)(ptr) );
742  break;
743  case HIT_FILE_FLOAT: result = fscanf( fich, patternRead, (float*)(ptr) );
744  break;
745  case HIT_FILE_DOUBLE: result = fscanf( fich, patternRead, (double*)(ptr) );
746  break;
747  }
748  break;
749 
750  case HIT_FILE_WRITE:
751  switch ( type ) {
752  case HIT_FILE_INT: result = fprintf( fich, patternWrite, *(int*)(ptr) );
753  break;
754  case HIT_FILE_LONG: result = fprintf( fich, patternWrite, *(long*)(ptr) );
755  break;
756  case HIT_FILE_FLOAT: result = fprintf( fich, patternWrite, *(float*)(ptr) );
757  break;
758  case HIT_FILE_DOUBLE: result = fprintf( fich, patternWrite, *(double*)(ptr) );
759  break;
760  }
761  break;
762  }
763  }
764 
765  /* 9.4. CHECK OPERATION RESULT */
766  if ( fileMode == HIT_FILE_READ ) {
767  if ( result != 1 ) {
768  fclose( fich );
769  hit_errInternal(__FUNCTION__, "Reading data in file", fileName, debugCodeFile, debugCodeLine);
770  }
771  }
772  else if ( fileFormat == HIT_FILE_BINARY ) {
773  if ( result != 1 ) {
774  fclose( fich );
775  hit_errInternal(__FUNCTION__, "Writing binary data in file", fileName, debugCodeFile, debugCodeLine);
776  }
777  }
778  else if ( result != formatSize1+1 ) {
779  fclose( fich );
780  hit_errInternal(__FUNCTION__, "Writing text data in file", fileName, debugCodeFile, debugCodeLine);
781  }
782 
783  /* 9.5. REAL OWNER: ADVANCE MEMORY POINTER TO THE NEXT ELEMENT */
784  if ( var->memStatus == HIT_MS_OWNER ) ptr = (char *)ptr + var->baseExtent;
785 
786  /* 9.6. SELECTION VARIABLES: ADVANCE TILE COORDINATES */
787  if ( var->memStatus == HIT_MS_NOT_OWNER ) {
788  j = hit_shapeDims(var->shape)-1;
789  do {
790  ind[j] = (ind[j]+1) % (var->card[j]);
791 
792  if ( ind[j] != 0 ) break;
793  j--;
794  } while( j>=0 );
795  }
796 
797  /* 9.7. ARRAY MODE: ADVANCE ARRAY COORDINATES */
798  if ( tileMode == HIT_FILE_ARRAY ) {
799  j = hit_shapeDims(var->shape)-1;
800  do {
801  if ( indsh[j] == hit_shapeSig(var->shape,j).end ) {
802  indsh[j] = hit_shapeSig(var->shape,j).begin;
803  }
804  else {
805  indsh[j] += hit_shapeSig(var->shape,j).stride;
806  break;
807  }
808  j--;
809  } while(j>=0);
810  }
811  }
812 
813  /* 10. END */
814  fclose( fich );
815  return 0;
816 }
817 
818 /* Hit CLONE: DUPLICATE VARIABLE, MEMORY AND DATA */
819 void hit_tileCloneInternal(void *newVarP, const void *oldVarP, const char *name, const char *file, int numLine) {
820  HitTile *newVar = (HitTile *)newVarP;
821  const HitTile *oldVar = (const HitTile *)oldVarP;
822  int i;
823 
824  /* 1. DUPLICATE HANDLER */
825  *newVar = *oldVar;
826 
827  /* 2. NULL VARIABLE: RETURN */
828  if ( oldVar->memStatus == HIT_MS_NULL ) return;
829 
830  /* 3. ALLOCATE NEW MEMORY */
831  /* 3.1. ALLOCATE */
832  // @arturo Ago 2015: New allocP interface
833  // hit_malloc(newVar->memPtr,(size_t)newVar->acumCard * newVar->baseExtent,void*);
834  hit_vmalloc(newVar->memPtr, (size_t)newVar->acumCard * newVar->baseExtent );
835 
836  newVar->data = newVar->memPtr;
837  newVar->memStatus = HIT_MS_OWNER;
838 
839  /* 3.2. NEW STRIDES TO ACCESS ARE ALWAYS 1 */
840  for (i=0; i<hit_shapeDims(newVar->shape); i++) newVar->qstride[i] = 1;
841 
842  /* 3.3. UPDATE ORIGINAL ACUMULATED CARDINALITIES, NOW IT HAS ITS OWN MEMORY */
843  hit_tileUpdateAcumCards(newVar);
844 
845  /* NO MEMORY: RETURN */
846  if(oldVar->memStatus==HIT_MS_NOMEM) return;
847 
848  /* PARENT TILE IS THE ORIGINAL TILE: CLONE IS LIKE A SELECTION + ALLOCATION + UPDATE */
849 #ifdef __cplusplus
850  newVar->ref = const_cast<HitTile*>(oldVar);
851 #else
852  newVar->ref = oldVar;
853 #endif
854 
855  /* HIERARCHICAL STRUCTURE: PROCESS CHILDREN */
856  if( oldVar->hierDepth > 0 ) {
857  switch( oldVar->memStatus ) {
858  /* 4.1. NO MEMORY, RETURN*/
859  case HIT_MS_NOMEM: return;
860 
861  /* 4.2. REAL OWNER VARIABLE, CLONE ALL THE CHILDS, MEMORY IS CONTIGUOUS */
862  case HIT_MS_OWNER:
863  for(i=0;i<oldVar->acumCard;i++) {
864  hit_tileCloneInternal( (char *)newVar->data+(size_t)i*newVar->baseExtent, (char *)oldVar->data+(size_t)i*oldVar->baseExtent, name, file, numLine);
865  }
866  break;
867 
868  /* 4.3. SELECTION, CLONE ALL THE CHILDS, MEMORY IS NOT CONTIGUOUS */
869  case HIT_MS_NOT_OWNER:
870  // Fake as a shadow to call Update
871  //newVar->ref = oldVar;
872  hit_tileUpdateFromToAncestorInternal(newVar, HIT_UPDATE_FROM, name, file, numLine);
873  //newVar->ref = NULL;
874  break;
875 
876  /* 4.4. IMPOSIBLE STATE */
877  default: hit_errInternal("tileClone", "Unknown memory state in source variable:", name, file, numLine);
878  break;
879  }
880  }
881  /* LEAF TILE */
882  else if( oldVar->hierDepth == HIT_NONHIERARCHICAL ) { // PARANOID CHECK
883  switch( oldVar->memStatus ) {
884  /* 4.1. NO MEMORY, RETURN*/
885  case HIT_MS_NOMEM: return;
886 
887  /* 4.2. REAL OWNER VARIABLE, COPY ALL THE CONTIGUOS DATA */
888  case HIT_MS_OWNER: memcpy(newVar->memPtr, oldVar->memPtr,
889  newVar->baseExtent * (size_t)newVar->acumCard);
890  break;
891 
892  /* 4.3. SELECTION, COPY DATA LIKE AN UPDATE */
893  case HIT_MS_NOT_OWNER:
894  /* Fake as a shadow to call Update */
895  //newVar->ref = oldVar;
896  hit_tileUpdateFromToAncestorInternal(newVar, HIT_UPDATE_FROM, name, file, numLine);
897  //newVar->ref=NULL;
898  break;
899 
900  /* 4.4. IMPOSIBLE STATE */
901  default: hit_errInternal("tileClone", "Unknown memory state in source variable:", name, file, numLine);
902  break;
903  }
904  }
905  /* PARANOID CHECK: IMPOSIBLE VALUE IN HIERARCHY-LEVEL FIELD */
906  else hit_errInternal("tileClone", "Negative value in hierarchy-level field of variable:", name, file, numLine);
907 
908  /* 5. END */
909  return;
910 }
911 
912 /* Hit INTERNAL: SELECTION FUNCTIONS: UPDATE ANCESTOR REFERENCE POINTER */
913 void hit_tileSelectRefPointer( HitTile *newVar, const HitTile *oldVar ){
914  switch( oldVar->memStatus ) {
915  case HIT_MS_NULL:
916  newVar->ref = NULL;
917  break;
918 
919  case HIT_MS_NOMEM:
920  /* IF PARENT HAS NO MEMORY, COPY ITS REFERENCE TO ALLOW UPDATES IF IT IS
921  * ALLOCATED IN THE FUTURE */
922  case HIT_MS_OWNER:
923 #ifdef __cplusplus
924  newVar->ref = const_cast<HitTile*>(oldVar);
925 #else
926  newVar->ref = oldVar;
927 #endif
928  break;
929 
930  case HIT_MS_NOT_OWNER:
931  newVar->ref = oldVar->ref;
932  break;
933 
934  default: /* PARANOID CHECK */
935  hit_errInternal("tileSelectInternal", "Unknown memory state in source tile.", "", __FILE__, __LINE__);
936  break;
937  }
938 }
939 
940 
941 /* Hit SELECTING FROM A VARIABLE (LOCAL COORDINATES) */
942 int hit_tileSelectInternal(void *newVarP, const void *oldVarP, HitShape sh, int out) {
943  int i;
944  // (v1.1) Use size_t types to ensure correctness for 64 bits
945  //int offset = 0;
946  size_t offset = 0;
947  HitTile *newVar = (HitTile *)newVarP;
948  const HitTile *oldVar = (const HitTile *)oldVarP;
949 
950  int numDims;
951  *newVar = HIT_TILE_NULL;
952 
953  /* 0.1. OPTIMIZE WHEN SELECTING A NULL SHAPE */
954  if ( hit_shapeDims(sh) == -1 ) return 1;
955 
956  /* 0.2 OPTIMIZE WHEN SELECTING HitNull */
957  if (oldVar->memStatus == HIT_MS_NULL) return 1;
958 
959  /* 0.3 OPTIMIZE WHEN SELECTING THE WHOLE VARIABLE */
960  //selecting with HIT_SHAPE_WHOLE
961  if (hit_shapeDims(sh) == 0) {
962  memcpy(newVarP, oldVarP, sizeof(HitTile));
963  /* MEMORY STATUS MAY CHANGE ON THE SELECTION */
964  if ( oldVar->memStatus != HIT_MS_NOMEM ) newVar->memStatus = HIT_MS_NOT_OWNER;
965  /* UPDATE REFERENCE POINTER */
966  hit_tileSelectRefPointer( newVar, oldVar );
967  return 1;
968  }
969 
970  /* 0.4. COPY HIERARCHICAL DEPTH PROPERTIES */
971  newVar->hierDepth=oldVar->hierDepth;
972  memcpy(newVar->childSize, oldVar->childSize, HIT_MAXDIMS*sizeof(int));
973  memcpy(newVar->childBegin, oldVar->childBegin, HIT_MAXDIMS*sizeof(int));
974 
975  /* COMPUTE SIGNATURES, DETECT AND STOP OUT-OF-BOUNDS SELECTIONS */
976  /* 1. GET NUMBER OF DIMENSIONS */
977  numDims = hit_shapeDims(oldVar->shape);
978 
979  /* 2. BLEND SIGNATURES FROM PARAMETERS */
980  for(i=0; i<hit_shapeDims(sh); i++) {
981  HitSig newSig = hit_shapeSig(sh,i);
982  // (v1.1 @arturo) ACCEPT HIT_SIG_WHOLE TO INDICATE THAT THE WHOLE DIMENSION IS SELECTED
983  if ( hit_sigCmp( newSig, HIT_SIG_WHOLE )) newSig = hit_sigStd( oldVar->card[i] );
984  else
985  /* CHECK OUT OF BOUNDS */
986  if ( out == HIT_OUTOFBOUNDS_CHECK
987  && (
988  newSig.begin < 0
989  || newSig.end < newSig.begin
990  || newSig.stride < 1
991  || newSig.end > oldVar->card[i]
992  )
993  )
994  {
995 #ifdef DEBUG
996 fprintf(stderr,"CTRL tileSelect: Out of bounds in signature %d: (%d,%d,%d) -> (%d,%d,%d)\n", i, newSig.begin, newSig.end, newSig.stride, hit_shapeSig(oldVar->shape,i).begin, hit_shapeSig(oldVar->shape,i).end, hit_shapeSig(oldVar->shape,i).stride);
997 #endif
998  /* RETURN NULL */
999  *newVar = HIT_TILE_NULL;
1000  return 0;
1001  }
1002 
1003  /* COMPUTE OFFSET */
1004  // @arturo Mar 13, BUG CORRECTED: Selection of several levels of depth with stride
1005  //offset = offset + (size_t)(newSig.begin) * (size_t)(oldVar->origAcumCard[i+1]);
1006  offset = offset + (size_t)(newSig.begin * oldVar->qstride[i]) * (size_t)(oldVar->origAcumCard[i+1]);
1007 
1008  /* ALIGN END TO STRIDE */
1009  newSig.end = newSig.end - (newSig.end - newSig.begin) % newSig.stride;
1010 
1011  /* STRIDE NORMALIZATION FOR BEGIN=END */
1012  if ( newSig.begin == newSig.end ) newSig.stride=1;
1013 
1014  /* BLEND SIGNATURES */
1015  hit_shapeSig(newVar->shape,i) = hit_sigBlend( hit_shapeSig(oldVar->shape,i), newSig );
1016  newVar->card[i] = hit_sigCard( hit_shapeSig(newVar->shape,i));
1017  newVar->qstride[i] = newSig.stride*oldVar->qstride[i];
1018  }
1019 
1020  /* 3. IF NEEDED COPY OTHER SIGNATURES FROM ORIGINAL VARIABLE */
1021  for(i=hit_shapeDims(sh); i<hit_shapeDims(oldVar->shape); i++) {
1022  hit_shapeSig(newVar->shape,i) = hit_shapeSig(oldVar->shape,i);
1023  newVar->card[i] = oldVar->card[i];
1024  newVar->qstride[i] = oldVar->qstride[i];
1025  }
1026 
1027  /* 4. SET SELECTION, NUMBER OF DIMENSIONS, SIGs AND CARDINALITIES */
1028  hit_shapeDimsSet(newVar->shape,numDims);
1029  newVar->baseExtent = oldVar->baseExtent;
1030 
1031  /* 3. COMPUTE NEW ACCUMULATED CARDINALITIES */
1032  hit_tileUpdateAcumCards(newVar);
1033 
1034  /* 4. COPY ORIGINAL ACUMMULATED CARDS */
1035  memcpy(newVar->origAcumCard,
1036  oldVar->origAcumCard,
1037  (size_t)(hit_shapeDims(newVar->shape)+1)*sizeof(int)
1038  );
1039 
1040  /* 5. SET THE DATA POINTER */
1041  /* START AT OLD DATA POINTER
1042  * ADD THE OFFSET OF REDUCED DIMENSIONS
1043  * ADD THE OFFSET OF THE NON-REDUCED DIMENSIONS (BEGINS)
1044  *
1045  * NOTE: SELECTION OF NO-MEMORY VARIABLES INHERIT THE NO-MEMORY STATUS
1046  */
1047  if ( oldVar->memStatus == HIT_MS_NOMEM ) {
1048  newVar->data = NULL;
1049  newVar->memStatus = HIT_MS_NOMEM;
1050  }
1051  else {
1052  newVar->data = (char*)(oldVar->data) + offset * oldVar->baseExtent;
1053  newVar->memStatus = HIT_MS_NOT_OWNER;
1054  }
1055 
1056  /* 6. SET THE REFERENCE FIELD */
1057  /* NO-MEMORY SELECTION SHOULD BECOME A SHADOW WHEN ALLOCATED: PREPARE THE REFERENCE
1058  * a) SUBSELECTION OF SELECTION: COPY OLD REFERENCE
1059  * b) SUBSELECTION OF A VARIABLE: REFERENCE TO THAT VARIABLE
1060  */
1061  /* v1.1: ALLOW UPDATES TO PARENT MEMORY TILES OF SECOND GENERATION OR MORE
1062  newVar->ref = ( oldVar->ref == NULL ) ? oldVar : oldVar->ref;
1063  */
1064  hit_tileSelectRefPointer( newVar, oldVar );
1065 
1066  /* 7. END */
1067  return 1;
1068 }
1069 
1070 
1073 int hit_tileCheckBoundaryArrayCoords(const void *tileP, HitShape sh) {
1074  int i;
1075 
1076  const HitTile *tile = (const HitTile*) tileP;
1077 
1078  for (i = 0; i < hit_shapeDims(sh); i++) {
1079  HitSig newSig = hit_shapeSig(sh,i);
1080  HitSig tileSig = hit_shapeSig(hit_tileShape(*tile),i);
1081 
1082  /* CHECK OUT OF BOUNDS */
1083  if (newSig.begin < tileSig.begin || newSig.end > tileSig.end
1084  || newSig.end < newSig.begin || newSig.stride < 1){
1085 
1086  return HIT_OUTOFBOUNDS_CHECK;
1087  }
1088  }
1089  return HIT_NO_OUTOFBOUNDS_CHECK;
1090 }
1091 
1092 
1095 int hit_tileCheckBoundaryTileCoords(const void *tileP, HitShape sh) {
1096  int i;
1097 
1098  const HitTile *tile = (const HitTile*) tileP;
1099 
1100  for (i = 0; i < hit_shapeDims(sh); i++) {
1101  HitSig newSig = hit_shapeSig(sh,i);
1102 
1103  /* CHECK OUT OF BOUNDS */
1104  if (newSig.begin < 0 || newSig.end < newSig.begin || newSig.stride < 1
1105  || newSig.end >= tile->card[i]){
1106 
1107  return HIT_OUTOFBOUNDS_CHECK;
1108  }
1109  }
1110  return HIT_NO_OUTOFBOUNDS_CHECK;
1111 }
1112 
1113 
1114 
1115 /* Hit SELECTING FROM A VARIABLE (GLOBAL COORDINATES) */
1116 int hit_tileSelectArrayCoordsInternal(void *newVarP, const void *oldVarP, HitShape sh, int out) {
1117  int i;
1118  // (v1.1) Use size_t types to ensure correctness for 64 bits
1119  //int offset = 0;
1120  size_t offset = 0;
1121  HitTile *newVar = (HitTile *)newVarP;
1122  const HitTile *oldVar = (const HitTile *)oldVarP;
1123 
1124  int numDims;
1125  *newVar = HIT_TILE_NULL;
1126 
1127  /* 0.1. OPTIMIZE WHEN SELECTING A NULL SHAPE */
1128  if ( hit_shapeDims(sh) == -1 ) return 1;
1129 
1130  /* 0.2 OPTIMIZE WHEN SELECTING HitNull */
1131  if (oldVar->memStatus == HIT_MS_NULL) return 1;
1132 
1133  /* 0.3 OPTIMIZE WHEN SELECTING THE WHOLE VARIABLE */
1134  if (hit_shapeDims(sh) == 0) {
1135  memcpy(newVarP, oldVarP, sizeof(HitTile));
1136  /* MEMORY STATUS MAY CHANGE ON THE SELECTION */
1137  if ( oldVar->memStatus != HIT_MS_NOMEM ) newVar->memStatus = HIT_MS_NOT_OWNER;
1138  /* UPDATE REFERENCE POINTER */
1139  hit_tileSelectRefPointer( newVar, oldVar );
1140  return 1;
1141  }
1142 
1143  /* 0.4 RETURN NULL TILE IF SHAPE NOT IN TILE DOMAIN */
1144  for(i=0; i<hit_shapeDims(sh); i++) {
1145  if( out == HIT_OUTOFBOUNDS_CHECK
1146  && ! hit_sigIn(hit_shapeSig(oldVar->shape,i),hit_shapeSig(sh,i).begin) ) {
1147  *newVar = HIT_TILE_NULL;
1148 #ifdef DEBUG
1149  printf("---- TileSelect, Out of Bounds Check! CTRL 1\n");
1150 #endif
1151  return 1;
1152  }
1153  if( out == HIT_OUTOFBOUNDS_CHECK
1154  && ! hit_sigIn(hit_shapeSig(oldVar->shape,i),hit_shapeSig(sh,i).end) ) {
1155  *newVar = HIT_TILE_NULL;
1156 #ifdef DEBUG
1157  printf("---- TileSelect, Out of Bounds Check! CTRL 2: %d in [%d:%d:%d] is false\n",
1158  hit_shapeSig(sh,i).end,
1159  hit_shapeSig(oldVar->shape,i).begin,
1160  hit_shapeSig(oldVar->shape,i).end,
1161  hit_shapeSig(oldVar->shape,i).stride
1162  );
1163 #endif
1164  return 1;
1165  }
1166  if( hit_shapeSig(sh,i).stride % hit_shapeSig(oldVar->shape,i).stride != 0 ) {
1167 #ifdef DEBUG
1168  printf("---- TileSelect, Out of Bounds Check! CTRL 3\n");
1169 #endif
1170  *newVar = HIT_TILE_NULL;
1171  return 1;
1172  }
1173  }
1174 
1175  /* 0.5. COPY THE HIERARCHICAL DEPTH PROPERTIES */
1176  newVar->hierDepth=oldVar->hierDepth;
1177  memcpy(newVar->childSize, oldVar->childSize, HIT_MAXDIMS*sizeof(int));
1178  memcpy(newVar->childBegin, oldVar->childBegin, HIT_MAXDIMS*sizeof(int));
1179 
1180  /* 1. COMPUTE SIGNATURES, DETECT AND STOP OUT-OF-BOUNDS SELECTIONS */
1181  /* 1.1. GET NUMBER OF DIMENSIONS */
1182  numDims = hit_shapeDims(oldVar->shape);
1183 
1184  /* 1.2. BLEND FIRST SIGNATURES FROM PARAMETERS */
1185  for(i=0; i<hit_shapeDims(sh); i++) {
1186  // CIRCUMVENT A BUG IN GCC 4.6
1187 #if ( __GNUC__ == 4 && __GNUC_MINOR__ == 6 )
1188  HitSig newSig;
1189  memcpy( &newSig, &hit_shapeSig( sh, i ), sizeof(newSig) );
1190 #else
1191  HitSig newSig = hit_shapeSig(sh,i);
1192 #endif
1193  // (v1.1 @arturo) ACCEPT HIT_SIG_WHOLE TO INDICATE THAT THE WHOLE DIMENSION IS SELECTED
1194  if ( hit_sigCmp( newSig, HIT_SIG_WHOLE )) newSig = hit_sigStd( oldVar->card[i] );
1195  else {
1196  /* CHECK OUT OF BOUNDS */
1197  if ( out == HIT_OUTOFBOUNDS_CHECK
1198  && (
1199  newSig.begin < hit_shapeSig(oldVar->shape,i).begin
1200  || newSig.end > hit_shapeSig(oldVar->shape,i).end
1201  || newSig.stride < 1
1202  /* WHEN ONLY ONE ELEMENT IS SELECTED (BEGIN=END) ANY STRIDE IS OK
1203  * IT WILL BE NORMALIZED TO 1 AFTERWARDS */
1204  || ( newSig.begin != newSig.end &&
1205  newSig.stride % hit_shapeSig(oldVar->shape,i).stride != 0
1206  )
1207  || ( newSig.begin - hit_shapeSig(oldVar->shape,i).begin )
1208  % hit_shapeSig(oldVar->shape,i).stride != 0
1209  || newSig.end < newSig.begin
1210  )
1211  )
1212  {
1213 #ifdef DEBUG
1214  fprintf(stderr,"CTRL tileSelect: Out of bounds in global signature %d: (%d,%d,%d)\n", i, newSig.begin, newSig.end, newSig.stride);
1215  fprintf(stderr,"CTRL tileSelect: Old var signature %d: (%d,%d,%d)\n", i, hit_shapeSig(oldVar->shape,i).begin, hit_shapeSig(oldVar->shape,i).end, hit_shapeSig(oldVar->shape,i).stride);
1216 #endif
1217  /* RETURN NULL */
1218  *newVar = HIT_TILE_NULL;
1219  return 0;
1220  }
1221 
1222  /* TRANSLATE TO LOCAL COORDINATES: SEVERAL ELEMENTS SELECTED */
1223  newSig.begin = (newSig.begin - hit_shapeSig(oldVar->shape,i).begin) / hit_shapeSig(oldVar->shape,i).stride;
1224  newSig.end = (newSig.end - hit_shapeSig(oldVar->shape,i).begin) / hit_shapeSig(oldVar->shape,i).stride;
1225  newSig.stride = newSig.stride / hit_shapeSig(oldVar->shape,i).stride;
1226  }
1227 
1228  /* COMPUTE OFFSET */
1229  // offset = offset + (size_t)(newSig.begin) * (size_t)(oldVar->origAcumCard[i+1]);
1230  // @arturo Mar 13, BUG CORRECTED: Selection of several levels of depth with stride
1231  offset = offset + (size_t)(newSig.begin * oldVar->qstride[i]) * (size_t)(oldVar->origAcumCard[i+1]);
1232 
1233  /* ALIGN END TO THE NEW STRIDE */
1234  // @arturo Mar 2013, BUG CORRECTED
1235  newSig.end = newSig.end - (newSig.end - newSig.begin) % newSig.stride;
1236 
1237  /* STRIDE NORMALIZATION FOR BEGIN=END */
1238  if ( newSig.begin == newSig.end ) newSig.stride=1;
1239 
1240  /* BLEND SIGNATURES */
1241  hit_shapeSig(newVar->shape,i) = hit_sigBlend( hit_shapeSig(oldVar->shape,i), newSig );
1242  newVar->card[i] = hit_sigCard( hit_shapeSig(newVar->shape,i));
1243  newVar-> qstride[i] = newSig.stride*oldVar->qstride[i];
1244  }
1245  /* 1.3. IF NEEDED COPY OTHER SIGNATURES FROM ORIGINAL VARIABLE */
1246  for(i=hit_shapeDims(sh); i<hit_shapeDims(oldVar->shape); i++) {
1247  hit_shapeSig(newVar->shape,i) = hit_shapeSig(oldVar->shape,i);
1248  newVar->card[i] = oldVar->card[i];
1249  newVar->qstride[i] = oldVar->qstride[i];
1250  }
1251 
1252  /* 2. SET SELECTION, NUMBER OF DIMENSIONS, SIGs AND CARDINALITIES */
1253  hit_shapeDimsSet(newVar->shape,numDims);
1254  newVar->baseExtent = oldVar->baseExtent;
1255 
1256  /* 3. COMPUTE NEW ACCUMULATED CARDINALITIES */
1257  hit_tileUpdateAcumCards(newVar);
1258 
1259  /* 4. COPY ORIGINAL ACUMMULATED CARDS */
1260  memcpy(newVar->origAcumCard,
1261  oldVar->origAcumCard,
1262  (size_t)(hit_shapeDims(newVar->shape)+1)*sizeof(int)
1263  );
1264 
1265  /* START AT OLD DATA POINTER
1266  * ADD THE OFFSET OF REDUCED DIMENSIONS
1267  * ADD THE OFFSET OF THE NON-REDUCED DIMENSIONS (BEGINS)
1268  *
1269  * NOTE: SELECTION OF NO-MEMORY VARIABLES INHERIT THE NO-MEMORY STATUS
1270  */
1271  if ( oldVar->memStatus == HIT_MS_NOMEM ) {
1272  newVar->memStatus = HIT_MS_NOMEM;
1273  newVar->data = NULL;
1274  }
1275  else {
1276  newVar->memStatus = HIT_MS_NOT_OWNER;
1277  newVar->data = (char*)(oldVar->data) + offset * oldVar->baseExtent;
1278  }
1279 
1280  /* 6. SET THE REFERENCE FIELD */
1281  /* NO-MEMORY SELECTION SHOULD BECOME A SHADOW WHEN ALLOCATED: PREPARE THE REFERENCE
1282  * a) SUBSELECTION OF SELECTION: COPY OLD REFERENCE
1283  * b) SUBSELECTION OF A VARIABLE: REFERENCE TO THAT VARIABLE
1284  */
1285  /* v1.1: ALLOW UPDATES TO PARENT MEMORY TILES OF SECOND GENERATION OR MORE
1286  newVar->ref = ( oldVar->ref == NULL ) ? oldVar : oldVar->ref;
1287  */
1288  hit_tileSelectRefPointer( newVar, oldVar );
1289 
1290  /* 7. END */
1291  return 1;
1292 }
1293 
1294 
1295 /* Hit REDUCE DIMENSIONS */
1296 int hit_tileReduceDims(void *newVarP, int numReductions) {
1297  int i;
1298  HitTile *newVar = (HitTile *)newVarP;
1299 
1300  /* 1. CHECK NUM DIMENSIONS */
1301  if (numReductions >= hit_shapeDims(newVar->shape)) {
1302  *newVar = HIT_TILE_NULL;
1303  return 1;
1304  }
1305 
1306  /* 2. CHECK DIMENSIONS TO REDUCE: SHOULD HAVE CARDINALITY 1 */
1307  for (i=0; i<numReductions; i++) {
1308  if (newVar->card[i] != 1) {
1309  *newVar = HIT_TILE_NULL;
1310  return 1;
1311  }
1312  }
1313 
1314  /* 3. REDUCE DIMENSIONS */
1315  for (i=numReductions; i<hit_shapeDims(newVar->shape); i++) {
1316  hit_shapeSig(newVar->shape,i-numReductions) = hit_shapeSig(newVar->shape,i);
1317  newVar->card[i-numReductions] = newVar->card[i];
1318  newVar->origAcumCard[i-numReductions] = newVar->origAcumCard[i];
1319  newVar->qstride[i-numReductions] = newVar->qstride[i];
1320  }
1321  newVar->origAcumCard[i-numReductions] = newVar->origAcumCard[i];
1322  hit_shapeDimsSet(newVar->shape,hit_shapeDims(newVar->shape) - numReductions);
1323 
1324  /* 4. END */
1325  return 0;
1326 }
1327 
1328 /* Hit EXPAND DIMENSIONS */
1329 int hit_tileExpandDims(void *newVarP, int numExpansions) {
1330  int i;
1331  HitTile *newVar = (HitTile *)newVarP;
1332 
1333  /* 1. CHECK NUM DIMENSIONS */
1334  if (numExpansions + hit_shapeDims(newVar->shape) > HIT_MAXDIMS) {
1335  *newVar = HIT_TILE_NULL;
1336  return 0;
1337  }
1338 
1339  /* 2. EXPAND DIMENSIONS */
1340  newVar->origAcumCard[hit_shapeDims(newVar->shape) + numExpansions] = newVar->origAcumCard[hit_shapeDims(newVar->shape)];
1341  for (i=hit_shapeDims(newVar->shape)-1; i>=0; i--) {
1342  hit_shapeSig(newVar->shape,i+numExpansions) = hit_shapeSig(newVar->shape,i);
1343  newVar->card[i+numExpansions] = newVar->card[i];
1344  newVar->origAcumCard[i+numExpansions] = newVar->origAcumCard[i];
1345  newVar->qstride[i+numExpansions] = newVar->qstride[i];
1346  }
1347  /* 3. DIMENSIONS EXPANDED: SHOULD HAVE CARDINALITY 1 */
1348  hit_shapeDimsSet(newVar->shape,hit_shapeDims(newVar->shape) + numExpansions);
1349 
1350  for (i=0; i<numExpansions; i++) {
1351  newVar->card[i] = 1;
1352  newVar->origAcumCard[i] = 1;
1353  newVar->qstride[i] = 1;
1354  hit_shapeSig(newVar->shape,i).begin = 1;
1355  hit_shapeSig(newVar->shape,i).end = 1;
1356  hit_shapeSig(newVar->shape,i).stride = 1;
1357  }
1358 
1359  /* 4. END */
1360  return 1;
1361 }
1362 
1363 
1364 
1365 /* Hit UPDATE A SHADOW COPY FROM/TO ITS ANCESTOR
1366  * v1.1, Dec 2011
1367  * v1.2, Apr 2014
1368  * v1.3, Oct 2016
1369  * @arturo
1370  */
1371 void hit_tileUpdateFromToAncestorInternal( void *sh, int fromTo,
1372  const char *name, const char *file, int numLine) {
1373  HitPTile shadow = (HitPTile)sh;
1374  HitPTile shadowOrig = shadow->ref;
1375  HitTile reducedDomainShadow;
1376  int ind[ hit_tileDims( *shadow ) ];
1377  int i,j,dim;
1378  size_t k;
1379  size_t chunkSize;
1380 
1381 #ifdef DEBUG
1382 const char *strFromTo[2] = { "FROM", "TO" };
1383 fprintf(stderr,"CTRL Starting UPDATE %s ANCESTOR\n", strFromTo[ fromTo ]);
1384 #endif
1385  /* 0.1. SKIP UPDATING NULL */
1386  if ( shadow->memStatus == HIT_MS_NULL ) return;
1387 
1388  /* 0.2. ONLY SHADOWS: REFERING TO ORIGINAL VARIABLES WITH MEMORY */
1389  if ( shadow->memStatus != HIT_MS_OWNER
1390  ||
1391  ( shadowOrig->memStatus != HIT_MS_OWNER && shadowOrig->memStatus != HIT_MS_NOT_OWNER )
1392  )
1393  {
1394  hit_errInternal(__FUNCTION__,"Bad variable type",name,file,numLine);
1395  }
1396 
1397  /* 1. COMPUTE INTERSECTION SHAPE TO DETECT SELECTIONS WHICH EXPANDED THE ORIGINAL SHAPE.
1398  * IT MEANS TILES CREATED WITH THE NO-BOUNDARY SELECTION FUNCTION.
1399  * FOR NORMAL SELECTIONS THE INTERSECTION IS THE SHAME SHAPE THAN THE SHAPE IN shadow */
1400 
1401  /* 1.1. COMPUTE INTERSECTION SHAPE */
1402  HitShape intersection = hit_shapeIntersect( hit_tileShape(*shadow),hit_tileShape(*shadowOrig) );
1403 
1404  /* 1.2. IF DIFFERENT, CHANGE shadow BY A NEW SELECTION TILE WITH THE INTERSECTION SHAPE
1405  * NO NEED TO UPDATE ref FIELD, WE WILL ONLY USE THE CARDINALITIES AND DATA POINTER */
1406  if ( ! hit_shapeCmp( intersection, hit_tileShape( *shadow ) ) ) {
1407 #ifdef DEBUG
1408 fprintf(stderr,"CTRL UPDATE %s ANCESTOR: Intersection detects an expanded tile, CREATING SELECTION\n", strFromTo[ fromTo ]);
1409 #endif
1410  hit_tileSelectArrayCoords( &reducedDomainShadow, shadow, intersection );
1411  shadow = &reducedDomainShadow;
1412  }
1413 
1418 
1419  /* 2. COMPUTE THE SIZE OF THE MAXIMAL CONTIGUOS CHUNK OF DATA */
1420 
1421  /* 2.1. CHECK EACH DIMENSION UNTIL SOMETHING PREVENTS MORE DIMENSIONS TO BE CONTIGUOUS
1422  * IN ONE OR BOTH VARIABLES
1423  * DIMENSIONS' RANGE: (dim in [-1,numDims-1]), -1 INDICATES WHOLE CONTIGUOUS VARIABLES */
1424  chunkSize = (size_t)1;
1425  for ( dim = hit_tileDims( *shadow )-1
1426  ;
1427  dim >= 0
1428  // SAME NUMBER OF ELEMENTS IN BOTH VARIABLES
1429  && shadow->card[dim] == shadowOrig->card[dim]
1430  // WITH NO STRIDE
1431  && shadowOrig->qstride[dim] == 1 && shadow->qstride[dim] == 1
1432  // THE SAME MEMORY SPACE IN BOTH VARIABLES TO ALLOW FURTHER DIMENSIONS TO BE CONTIGUOUS.
1433  && shadow->origAcumCard[dim+1] == shadowOrig->origAcumCard[dim+1]
1434  // WITH THE SAME NUMBER OF ELEMENTS AS IN MEMORY SPACE (NO EXTRA BEGINNING/ENDING ELEMENTS)
1435  && shadow->origAcumCard[dim] == (int)chunkSize * shadow->card[dim]
1436  ;
1437  dim-- )
1438  chunkSize = chunkSize * (size_t)shadow->card[ dim ];
1439 
1440  /* 2.2. LAST CONTIGUOUS DIMENSION: CHUNK SIZE IS MULTIPLIED BY THE NUMBER OF ELEMENTS IN
1441  * THIS DIMENSION WHICH ARE CONTIGUOS IN BOTH VARIABLES */
1442  /* @arturo Mar 2014, BUG CORRECTED: COMPARE REAL STRIDES, AND MEMORY CONTIGUOUS */
1443  // if ( dim > -1 && shadowOrig->qstride[dim] == 1 && shadow->qstride[dim] == 1 ) {
1444  if ( dim > -1
1445  && hit_tileDimStride( *shadowOrig, dim ) == hit_tileDimStride( *shadow, dim )
1446  && shadowOrig->qstride[dim] == 1 ) {
1447 #ifdef DEBUG
1448 fprintf(stderr,"CTRL UPDATE %s ANCESTOR: Contiguous after dimension %d\n", strFromTo[ fromTo ], dim);
1449 #endif
1450  chunkSize = chunkSize * (size_t)shadow->card[ dim ];
1451  dim--;
1452  }
1453  size_t chunkMemSize = shadow->baseExtent * chunkSize;
1454 
1455 #ifdef DEBUG
1456 fprintf(stderr,"CTRL dim=%d, chunkSize=%d, Shadow: OrigAcumCard=%d\n", dim, (unsigned int)chunkSize, shadow->origAcumCard[0]);
1457 #endif
1458 
1459  /* 4. INIT INDICES */
1460  for(i=0; i< dim+1; i++) ind[i] = 0;
1461 
1462  /* 5. COPY DATA (AS MANY CHUNKS AS NEEDED) */
1463  /* 5.1. OPTIMIZATION: AVOID FROM/TO CONDITIONALS INSIDE THE LOOP */
1464  HitTile *sourceTile, *targetTile;
1465  /* @arturo Mar 2014, BUG CORRECTED:
1466  * COMPUTE DATA START POSITION IN THE ORIGINAL VAR
1467  * AND RELATIVE STRIDES FOR THE SHADOW SUBSELECTION */
1468  int sourceStart, targetStart;
1469  int relativeBegin = 0;
1470  int relativeStride[ hit_tileDims( *shadow ) ];
1471  int relativeNoStride[ hit_tileDims( *shadow ) ];
1472  int *relativeStrideSource, *relativeStrideTarget;
1473 
1474  for (i=0; i<hit_tileDims( *shadow ); i++) {
1475  relativeBegin = relativeBegin +
1476  ( hit_tileDimBegin( *shadow, i ) - hit_tileDimBegin( *shadowOrig, i ) )
1477  * shadowOrig->origAcumCard[i+1]
1478  /* @arturo Oct 2016, BUG CORRECTED:
1479  * FOR ORIGINAL (MEMORY OWNER) TILES WITH STRIDED DOMAINS
1480  * DIVIDE THE START-OFFSET BY THE ORIGINAL STRIDE IN THAT DIMENSION */
1481  / hit_tileDimStride( *shadowOrig, i );
1482  // MULTIPLY BY qstride, IN CASE PARENT IS A STRIDED SELECTION OF ANOTHER ANCESTOR VARIABLE
1483  relativeStride[ i ] = shadowOrig->qstride[i] *
1484  hit_tileDimStride( *shadow, i ) / hit_tileDimStride( *shadowOrig, i );
1485  relativeNoStride[ i ] = 1;
1486  }
1487  if ( fromTo == HIT_UPDATE_FROM ) {
1488  sourceTile = shadowOrig;
1489  targetTile = shadow;
1490  sourceStart = relativeBegin;
1491  targetStart = 0;
1492  relativeStrideSource = relativeStride;
1493  relativeStrideTarget = relativeNoStride;
1494  }
1495  else {
1496  sourceTile = shadow;
1497  targetTile = shadowOrig;
1498  sourceStart = 0;
1499  targetStart = relativeBegin;
1500  relativeStrideSource = relativeNoStride;
1501  relativeStrideTarget = relativeStride;
1502  }
1503 
1504  /* OPTIMIZATION: AVOID CONDITIONALS INSIDE THE LOOP
1505  * DUPLICATE CODE FOR NATIVE TYPE ELEMENTS AND HIT_TILE TYPE ELEMENTS */
1506  /* 5.2. NATIVE TYPE ELEMENTS */
1507  if ( sourceTile->hierDepth == HIT_NONHIERARCHICAL ) {
1508  if ( dim < 0 ) { // WHOLE CONTIGUOUS CHUNK
1509  memcpy( (char*)(targetTile->data) + (size_t)targetStart * shadow->baseExtent,
1510  (char*)(sourceTile->data) + (size_t)sourceStart * shadow->baseExtent,
1511  shadow->baseExtent * chunkSize
1512  );
1513  }
1514  else {
1515  /* @arturo Apr 2014: OPTIMIZATION, INNER LOOP */
1516  //for(i=0; i< (int)((size_t)shadow->acumCard/chunkSize); i++)
1517  for(i=0; i< (int)((size_t)shadow->acumCard/(size_t)shadow->card[dim]/chunkSize); i++) {
1518  /* @arturo Mar 2014, BUG CORRECTED: POSITIONS FOR SUBSECLECTIONS AND STRIDES */
1519  int sourcePos = sourceStart;
1520  int targetPos = targetStart;
1521 
1522  /* 5.2.1. COMPUTE NEXT POSITIONS IN THE shadow AND ORIGINAL VARIABLES */
1523  /* @arturo Apr 2014: OPTIMIZATION, INNER LOOP */
1524  //for(j=0; j< dim+1; j++)
1525  for(j=0; j< dim; j++) {
1526  /* @arturo Mar 2014, BUG CORRECTED: qstride[dim] SHOULD BE qstride[j] */
1527  //sourcePos = sourcePos + ind[j] * sourceTile->qstride[j] * sourceTile->origAcumCard[j+1];
1528  //targetPos = targetPos + ind[j] * targetTile->qstride[j] * targetTile->origAcumCard[j+1];
1529  /* @arturo Mar 2014, BUG CORRECTED: MULTIPLY BY THE RATIO BETWEEN STRIDES */
1530  sourcePos = sourcePos + ind[j] * relativeStrideSource[j] * sourceTile->origAcumCard[j+1];
1531  targetPos = targetPos + ind[j] * relativeStrideTarget[j] * targetTile->origAcumCard[j+1];
1532  }
1533 #ifdef DEBUG
1534 fprintf(stderr,"CTRL UPDATE-%s sourcePos=%d\n", strFromTo[ fromTo ], sourcePos);
1535 fprintf(stderr,"CTRL UPDATE-%s targetPos=%d\n", strFromTo[ fromTo ], targetPos);
1536 #endif
1537 
1538  char *sourcePointer = (char *)(sourceTile->data)
1539  + (size_t)sourcePos * shadow->baseExtent;
1540  char *targetPointer = (char *)(targetTile->data)
1541  + (size_t)targetPos * shadow->baseExtent;
1542 
1543  size_t loopJumpSource = (size_t)( relativeStrideSource[dim] * sourceTile->origAcumCard[dim+1] ) * shadow->baseExtent;
1544  size_t loopJumpTarget = (size_t)( relativeStrideTarget[dim] * targetTile->origAcumCard[dim+1] ) * shadow->baseExtent;
1545 
1546  /* 5.2.2. COPY DATA AT THE NEXT POSITION */
1547  /* @arturo Apr 2014: OPTIMIZATION, INNER LOOP */
1548  int innerLoopIdx;
1549  for ( innerLoopIdx = 0; innerLoopIdx < shadow->card[dim];
1550  innerLoopIdx++,
1551  sourcePointer += loopJumpSource,
1552  targetPointer += loopJumpTarget
1553  ) {
1554  memcpy( targetPointer, sourcePointer, chunkMemSize );
1555  }
1556  /* 5.2.3. ADVANCE INDECES */
1557  /* @arturo Apr 2014: OPTIMIZATION, INNER LOOP */
1558  //for(j=dim; j>=0; j--)
1559  for(j=dim-1; j>=0; j--) {
1560  ind[j]++;
1561  if (ind[j]==shadow->card[j]) ind[j]=0;
1562  else break;
1563  }
1564  }
1565  }
1566  }
1567  /* 5.3. HIT_TILE TYPE ELEMENTS */
1568  else if ( shadowOrig->hierDepth > 0 ) {
1569  for(i=0; i< (int)((size_t)shadow->acumCard/chunkSize); i++) {
1570  int sourcePos = 0;
1571  int targetPos = 0;
1572 
1573  /* 5.3.1. COMPUTE NEXT POSITIONS IN THE shadow AND ORIGINAL VARIABLES */
1574  for(j=0; j< dim+1; j++) {
1575  sourcePos = sourcePos + ind[j] * sourceTile->qstride[dim] * sourceTile->origAcumCard[j+1];
1576  targetPos = targetPos + ind[j] * targetTile->qstride[dim] * targetTile->origAcumCard[j+1];
1577  }
1578 #ifdef DEBUG
1579 fprintf(stderr,"CTRL UPDATE-%s sourcePos=%d\n", strFromTo[ fromTo ], sourcePos);
1580 fprintf(stderr,"CTRL UPDATE-%s targetPos=%d\n", strFromTo[ fromTo ], targetPos);
1581 #endif
1582 
1583  /* 5.3.2. COPY DATA AT THE NEXT POSITION */
1584  for( k=0; k < chunkSize; k++ ) {
1586  (char *)targetTile->data + (k+(size_t)targetPos) * shadow->baseExtent,
1587  (char *)sourceTile->data + (k+(size_t)sourcePos) * shadow->baseExtent,
1588  name, file, numLine);
1589  }
1590 
1591  /* 5.3.3. ADVANCE INDECES */
1592  for(j=dim; j>=0; j--) {
1593  ind[j]++;
1594  if (ind[j]==shadow->card[j]) ind[j]=0;
1595  else break;
1596  }
1597  }
1598  }
1599  // 5.4. PARANOID CHECK: IMPOSIBLE VALUE IN FIELD
1600  else hit_errInternal(__FUNCTION__, "Negative value in hierarchy-level field of variable:", name, file, numLine);
1601 
1602  /* 6. RETURN */
1603  return;
1604 }
1605 
1606 /* @arturo Feb 2013 */
1607 /* Hit GENERATE THE SHAPE OF A TILE IN LOCAL COORDINATES */
1608 HitShape hit_tileShapeLocal( const void *inTile ) {
1609  HitTile tile = *(const HitTile *)inTile;
1610  HitShape newShp = HIT_SHAPE_NULL;
1611 
1612  hit_sshapeDims( newShp ) = hit_tileDims( tile );
1613 
1614  int dim;
1615  for ( dim=0; dim < hit_tileDims( tile ); dim++ )
1616  hit_shapeSig( newShp, dim ) = hit_sigStd( hit_tileDimCard( tile, dim ) );
1617 
1618  return newShp;
1619 }
1620 
1621 /* Hit TRANSFORM TILE COORDINATES TO ARRAY COORDINATES */
1623  int i;
1624  HitTile *v = (HitTile *) var;
1625  HitShape newShp=HIT_SHAPE_NULL_STATIC;
1626  hit_shapeDimsSet(newShp,hit_shapeDims(sh));
1627  for(i=0;i<hit_shapeDims(sh);i++) {
1628  // TRANSLATION FOR EACH DIMENSION
1629  hit_shapeSig(newShp,i).begin = hit_shapeSig(sh,i).begin * hit_shapeSig(v->shape,i).stride + hit_shapeSig(v->shape,i).begin ;
1630  hit_shapeSig(newShp,i).end = hit_shapeSig(sh,i).end * hit_shapeSig(v->shape,i).stride + hit_shapeSig(v->shape,i).begin ;
1631  if ( hit_shapeSig(newShp,i).begin == hit_shapeSig(newShp,i).end )
1632  hit_shapeSig(newShp,i).stride=1;
1633  else
1634  hit_shapeSig(newShp,i).stride = hit_shapeSig(sh,i).stride * hit_shapeSig(v->shape,i).stride;
1635  }
1636  return newShp;
1637 }
1638 
1639 /* Hit TRANSFORM TILE COORDINATES TO ARRAY COORDINATES */
1641  int i;
1642  HitTile *v = (HitTile *) var;
1643  HitShape newShp=HIT_SHAPE_NULL_STATIC;
1644  hit_shapeDimsSet(newShp,hit_shapeDims(sh));
1645  for(i=0;i<hit_shapeDims(sh);i++) {
1646  // TRANSLATION FOR EACH DIMENSION
1647  hit_shapeSig(newShp,i).begin = (hit_shapeSig(sh,i).begin - hit_shapeSig(v->shape,i).begin) / hit_shapeSig(v->shape,i).stride;
1648  hit_shapeSig(newShp,i).end = (hit_shapeSig(sh,i).end - hit_shapeSig(v->shape,i).begin) / hit_shapeSig(v->shape,i).stride;
1649  if ( hit_shapeSig(newShp,i).begin == hit_shapeSig(newShp,i).end )
1650  hit_shapeSig(newShp,i).stride=1;
1651  else
1652  hit_shapeSig(newShp,i).stride = hit_shapeSig(sh,i).stride / hit_shapeSig(v->shape,i).stride;
1653  }
1654  return newShp;
1655 }
1656 
1657 /* Hit FREE DATA: WORKS RECURSIVELY IN A HIERARCHICAL TILE */
1658 void hit_tileFreeRecInternal(void * varP) {
1659 
1660  HitTile *var = (HitTile *)varP;
1661  int i;
1662  //int j, ind[HIT_MAXDIMS];
1663  //size_t offset;
1664  void * ptr;
1665  if ( var->memStatus == HIT_MS_OWNER) {
1666  ptr=var->data;
1667  for(i=0;i<var->acumCard;i++) {
1668  hit_tileFree(*((HitTile *)ptr));
1669  ptr = (char *)ptr + var->baseExtent;
1670  }
1671  }
1672  // May 2015 @arturo BUG CORRECTED: NOT OWNER SHOULD NOT FREE ANYTHING
1673  /*
1674  else if ( var->memStatus == HIT_MS_NOT_OWNER) {
1675  //initialise ind with 0
1676  memset(ind,0, (size_t)hit_shapeDims(var->shape)*sizeof(int));
1677  for(i=0;i<var->acumCard;i++) {
1678  offset=0;
1679  for(j=0;j<hit_shapeDims(var->shape);j++) {
1680  offset+=(size_t)ind[j]*(size_t)var->qstride[j]*(size_t)var->origAcumCard[j+1];
1681  }
1682  offset+=(size_t)ind[j]*(size_t)var->qstride[j];
1683  hit_tileFree(*((HitTile *)( (char *)var->data+offset*var->baseExtent )));
1684  j=0;
1685  do {
1686  ind[j]=(ind[j]+1)% (var->card[j]);
1687  j++;
1688  } while(j<hit_shapeDims(var->shape) && ind[j-1]==0 && var->card[j]!=0);
1689  }
1690  }
1691  */
1692 }
1693 
1694 
1695 /* @arturo Feb 2013 */
1696 /* HitTile GLUE TILES WITH TOUCHING BOUNDARIES OF THE SAME GEOMETRY */
1697 /* TODO: Extent to more than one dimension */
1698 void hit_tileGlue( void *tileInA, void *tileInB, void *tileOut ) {
1699  HitTile *inA = (HitTile *)tileInA;
1700  HitTile *inB = (HitTile *)tileInB;
1701  HitTile *out = (HitTile *)tileOut;
1702 
1703  /* 1.1. CHECK: BOTH NOT NULL SHAPES, RETURN NULL */
1704  if ( hit_shapeCmp( hit_tileShape( *inA ), HIT_SHAPE_NULL )
1705  &&
1707  ) {
1708  *out = HIT_TILE_NULL;
1709  return;
1710  }
1711  /* 1.2. CHECK: A SHAPE IS NULL, RETURN B */
1712  else if ( hit_shapeCmp( hit_tileShape( *inA ), HIT_SHAPE_NULL ) ) {
1713  *out = *inB;
1714  return;
1715  }
1716  /* 1.3. CHECK: B SHAPE IS NULL, RETURN A */
1717  else if ( hit_shapeCmp( hit_tileShape( *inB ), HIT_SHAPE_NULL ) ) {
1718  *out = *inA;
1719  return;
1720  }
1721 
1722  /* 0. CHECK THAT INPUT SHAPES HAVE EXACTLY ONE DIMENSION */
1723  if ( hit_tileDims( *inA ) != 1 || hit_tileDims( *inB ) != 1 ) {
1724  hit_warnInternal(__FUNCTION__, "Sorry, Glue for tiles with more than one dimension not yet implemented.", "", __FILE__, __LINE__ );
1725  *out = HIT_TILE_NULL;
1726  return;
1727  }
1728 
1729  /* 2. CHECK GLUE CONDITION: NOT TOUCHING SHAPES WITH THE SAME STRIDE, RETURN NULL */
1730  if ( hit_tileDimStride( *inA, 0 ) != hit_tileDimStride( *inB, 0 )
1731  ||
1732  hit_tileDimBegin( *inB, 0 ) - hit_tileDimEnd( *inA, 0 ) != hit_tileDimStride( *inA, 0 )
1733  ) {
1734  *out = HIT_TILE_NULL;
1735  return;
1736  }
1737 
1738  /* 3. GLUE: ALLOCATE NEW TILE */
1739  HitShape newShp = hit_shape( 1,
1740  hit_sig(
1741  hit_tileDimBegin( *inA, 0 ), hit_tileDimEnd( *inB, 0 ), hit_tileDimStride( *inA, 0 )
1742  ) );
1743  hit_tileDomainShapeInternal( out, inA->baseExtent, HIT_NONHIERARCHICAL, newShp );
1744  hit_tileAlloc( out );
1745 
1746  /* 4. COPY DATA */
1747  memcpy( out->data, inA->data, inA->baseExtent * (size_t)hit_tileCard( *inA ) );
1748  memcpy( (char *)(out->data) + inA->baseExtent * (size_t)hit_tileCard(*inA), inB->data, inB->baseExtent * (size_t)hit_tileCard( *inB ) );
1749 
1750  /* 5. FREE ORIGINAL TILES */
1751  hit_tileFree( *inA );
1752  hit_tileFree( *inB );
1753 }
HitPTile HIT_TILE_NULL_POINTER
Definition: hit_tile.c:64
#define hit_shape(nd,...)
Definition: hit_sshape.h:175
#define hit_tileDimStride(var, dim)
Definition: hit_tile.h:806
int hit_tileFileInternal(void *varP, const int fileFormat, const int fileMode, const int tileMode, const int type, const int formatSize1, const int formatSize2, const char *fileName, const char *debugVarName, const char *debugCodeFile, int debugCodeLine)
Definition: hit_tile.c:572
int hit_tileReduceDims(void *newVar, int numReductions)
Definition: hit_tile.c:1296
void hit_tileGlue(void *tileInA, void *tileInB, void *tileOut)
Definition: hit_tile.c:1698
void hit_tileFillUpdateArrayCoordinatesRec(HitTile *root, int coords[HIT_MAXDIMS])
Definition: hit_tile.c:300
HitShape hit_shapeIntersect(HitShape sh1, HitShape sh2)
Definition: hit_shape.c:123
#define hit_shapeDimsSet(shape, value)
Definition: hit_sshape.h:387
void hit_tileSingleInternal(void *tileP, void *varP, size_t size)
Definition: hit_tile.c:135
void hit_tileDomainShapeInternal(void *newVarP, size_t baseExtent, int hierDepth, HitShape shape)
Definition: hit_tile.c:200
HitShape hit_tileShapeTile2Array(void *var, HitShape sh)
Definition: hit_tile.c:1622
#define hit_tileDims(var)
Definition: hit_tile.h:713
int hit_shapeCmp(HitShape sh1, HitShape sh2)
Definition: hit_shape.c:109
#define hit_tileDimSig(var, dim)
Definition: hit_tile.h:776
int hit_tileCheckBoundaryArrayCoords(const void *tileP, HitShape sh)
Definition: hit_tile.c:1073
#define hit_tileAlloc(var)
Definition: hit_tile.h:319
#define hit_sigCard(sig)
Definition: hit_sig.h:162
Definition: hit_sig.h:79
void hit_tileFillInternal(void *varP, void *value, const char *name, const char *file, int numLine)
Definition: hit_tile.c:342
#define HIT_MAXDIMS
Definition: hit_shape.h:72
#define hit_sigIn(sig, ind)
Definition: hit_sig.h:186
#define HIT_FILE_DOUBLE
Definition: hit_tile.h:189
#define HIT_FILE_FLOAT
Definition: hit_tile.h:184
void hit_tileDomainInternal(void *newVarP, size_t baseExtent, int hierDepth, int numDims,...)
Definition: hit_tile.c:162
#define hit_tileCard(var)
Definition: hit_tile.h:763
#define HIT_SIG_SHAPE
Definition: hit_shape.h:171
int hit_tileSelectInternal(void *newVarP, const void *oldVarP, HitShape sh, int out)
Definition: hit_tile.c:942
int begin
Definition: hit_sig.h:80
void hit_tileSelectRefPointer(HitTile *newVar, const HitTile *oldVar)
Definition: hit_tile.c:913
void hit_tileCloneInternal(void *newVarP, const void *oldVarP, const char *name, const char *file, int numLine)
Definition: hit_tile.c:819
#define hit_tileDimCard(var, dim)
Definition: hit_tile.h:750
#define hit_shapeDims(shape)
Definition: hit_sshape.h:364
#define hit_cShapeNvertices(shape)
#define hit_tileDimBegin(var, dim)
Definition: hit_tile.h:786
Hitmap functions to allocate memory.
int size[2]
Definition: SWcommon.c:57
int end
Definition: hit_sig.h:81
void * hit_mtileElemAtArrayCoord(HitTile *root, int coords[HIT_MAXDIMS])
Definition: hit_tile.c:536
HitShape hit_tileShapeArray2Tile(void *var, HitShape sh)
Definition: hit_tile.c:1640
void * hit_mtileBlockArrayCoord(HitTile *root, int coords[HIT_MAXDIMS])
Definition: hit_tile.c:504
#define HIT_FILE_INT
Definition: hit_tile.h:174
int hit_tileCheckBoundaryTileCoords(const void *tileP, HitShape sh)
Definition: hit_tile.c:1095
void hit_tileUpdateFromToAncestorInternal(void *sh, int fromTo, const char *name, const char *file, int numLine)
Definition: hit_tile.c:1371
HitShape HIT_SHAPE_NULL
Definition: hit_shape.c:60
HitShape shape
HitSig HIT_SIG_WHOLE
Definition: hit_sig.c:49
#define HIT_FILE_LONG
Definition: hit_tile.h:179
void hit_tileAllocInternal(void *newVarP, const char *name, const char *file, int numLine)
Definition: hit_tile.c:243
HitShape hit_tileShapeLocal(const void *inTile)
Definition: hit_tile.c:1608
#define hit_tileDimEnd(var, dim)
Definition: hit_tile.h:796
int hit_tileExpandDims(void *newVarP, int numExpansions)
Definition: hit_tile.c:1329
int hit_tileSelectArrayCoordsInternal(void *newVarP, const void *oldVarP, HitShape sh, int out)
Definition: hit_tile.c:1116
#define hit_vmalloc(ptr, size)
Definition: hit_allocP.h:72
#define HIT_FILE_ARRAY
Definition: hit_tile.h:201
int stride
Definition: hit_sig.h:82
#define hit_shapeType(s)
Definition: hit_shape.h:266
#define hit_tileSelectArrayCoords(newVar, oldVar, shape)
Definition: hit_tile.h:494
HitTile HIT_TILE_NULL
Definition: hit_tile.c:63
#define v(a, b, c)
#define hit_warnInternal(routine, text, extraParam, file, numLine)
Definition: hit_error.h:69
#define hit_shapeSig(shape, dim)
Definition: hit_sshape.h:400
#define hit_tileFree(var)
Definition: hit_tile.h:369
#define hit_errInternal(routine, text, extraParam, file, numLine)
Definition: hit_error.h:63
void hit_tileFreeRecInternal(void *varP)
Definition: hit_tile.c:1658
#define hit_sshapeDims(shape)
Definition: hit_sshape.h:376
#define hit_sigCmp(s1, s2)
Definition: hit_sig.h:174
#define hit_tileShape(var)
Definition: hit_tile.h:723