MOAB: Mesh Oriented datABase  (version 5.5.0)
tstt_perf.cpp
Go to the documentation of this file.
1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2004 Sandia Corporation. Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 
16 /** TSTT Mesh Interface brick mesh performance test
17  *
18  * This program tests TSTT mesh interface functions used to create a square structured
19  * mesh. Boilerplate taken from tstt mesh interface test in MOAB and performance test in MOAB
20  *
21  */
22 
23 // Different platforms follow different conventions for usage
24 #if !defined( _NT ) && !defined( _MSC_VER ) && !defined( __MINGW32__ )
25 #include <sys/resource.h>
26 #endif
27 #ifdef SOLARIS
28 extern "C" int getrusage( int, struct rusage* );
29 #ifndef RUSAGE_SELF
30 #include </usr/ucbinclude/sys/rusage.h>
31 #endif
32 #endif
33 
34 #include <cstdlib>
35 #include <cstdio>
36 #include <iostream>
37 
38 //-------------------------------------------------------
39 // CHANGE THESE DEFINITIONS TO SUIT YOUR IMPLEMENTATION
40 
41 // #include here any files with declarations needed to instantiate your
42 // implementation instance
43 #include "TSTT_MOAB.hh"
44 
45 // define IMPLEMENTATION_CLASS to be the namespace::class of your implementation
46 #define IMPLEMENTATION_CLASS TSTT_MOAB::MoabMesh
47 //-------------------------------------------------------
48 
49 #define CAST_INTERFACE( var_in, var_out, iface ) \
50  TSTT::iface var_out; \
51  try \
52  { \
53  ( var_out ) = var_in; \
54  } \
55  catch( TSTT::Error ) \
56  { \
57  cerr << "Error: current interface doesn't support iface." << endl; \
58  return; \
59  }
60 
61 #define CAST_MINTERFACE( var_in, var_out, iface ) \
62  TSTTM::iface var_out; \
63  try \
64  { \
65  ( var_out ) = var_in; \
66  } \
67  catch( TSTT::Error ) \
68  { \
69  cerr << "Error: current interface doesn't support iface." << endl; \
70  return; \
71  }
72 
73 #include <iostream>
74 #include "TSTT.hh"
75 #include "TSTTM.hh"
76 
77 // needed to get the proper size for handles
78 typedef void* Entity_Handle;
79 
80 using namespace std;
81 
82 #define ARRAY_PTR( array, type ) ( reinterpret_cast< ( type )* >( ( array )._get_ior()->d_firstElement ) )
83 #define HANDLE_ARRAY_PTR( array ) ( reinterpret_cast< Entity_Handle* >( ( array )._get_ior()->d_firstElement ) )
84 #define ARRAY_SIZE( array ) ( ( array )._is_nil() ? 0 : ( array ).upper( 0 ) - ( array ).lower( 0 ) + 1 )
85 #define CHECK_SIZE( array, size ) \
86  if( ( array )._is_nil() || ARRAY_SIZE( array ) == 0 ) \
87  ( array ) = ( array ).create1d( size ); \
88  else if( ARRAY_SIZE( array ) < ( size ) ) \
89  { \
90  cerr << "Array passed in is non-zero but too short." << endl; \
91  assert( false ); \
92  }
93 
94 double LENGTH = 1.0;
95 
96 // forward declare some functions
97 void query_vert_to_elem( TSTTM::Mesh& mesh );
98 void query_elem_to_vert( TSTTM::Mesh& mesh );
99 void print_time( const bool print_em, double& tot_time, double& utime, double& stime );
100 void build_connect( const int nelem, const int vstart, int*& connect );
101 void testB( TSTTM::Mesh& mesh, const int nelem, sidl::array< double >& coords, const int* connect );
102 void testC( TSTTM::Mesh& mesh, const int nelem, sidl::array< double >& coords );
103 void compute_edge( double* start, const int nelem, const double xint, const int stride );
104 void compute_face( double* a, const int nelem, const double xint, const int stride1, const int stride2 );
105 void build_coords( const int nelem, sidl::array< double >& coords );
106 void build_connect( const int nelem, const int vstart, int*& connect );
107 
108 int main( int argc, char* argv[] )
109 {
110  int nelem = 20;
111  if( argc < 3 )
112  {
113  std::cout << "Usage: " << argv[0] << " <ints_per_side> <A|B|C>" << std::endl;
114  return 1;
115  }
116 
117  char which_test = '\0';
118 
119  sscanf( argv[1], "%d", &nelem );
120  sscanf( argv[2], "%c", &which_test );
121 
122  if( which_test != 'B' && which_test != 'C' )
123  {
124  std::cout << "Must indicate B or C for test." << std::endl;
125  return 1;
126  }
127 
128  std::cout << "number of elements: " << nelem << "; test " << which_test << std::endl;
129 
130  // pre-build the coords array
131  sidl::array< double > coords;
132  build_coords( nelem, coords );
133  assert( NULL != coords );
134 
135  int* connect = NULL;
136  build_connect( nelem, 1, connect );
137 
138  // create an implementation
139  TSTTM::Mesh mesh = IMPLEMENTATION_CLASS::_create();
140 
141  switch( which_test )
142  {
143  case 'B':
144  // test B: create mesh using bulk interface
145  testB( mesh, nelem, coords, connect );
146  break;
147 
148  case 'C':
149  // test C: create mesh using individual interface
150  testC( mesh, nelem, coords );
151  break;
152  }
153 
154  return 0;
155 }
156 
157 void testB( TSTTM::Mesh& mesh, const int nelem, sidl::array< double >& coords, const int* connect )
158 {
159  double utime, stime, ttime0, ttime1, ttime2, ttime3;
160 
161  print_time( false, ttime0, utime, stime );
162  int num_verts = ( nelem + 1 ) * ( nelem + 1 ) * ( nelem + 1 );
163  int num_elems = nelem * nelem * nelem;
164 
165  // create vertices as a block
166  CAST_MINTERFACE( mesh, mesh_arrmod, ArrMod );
167  sidl::array< Entity_Handle > sidl_vertices, dum_handles;
168  CHECK_SIZE( dum_handles, num_verts );
169  int sidl_vertices_size;
170 
171  try
172  {
173  mesh_arrmod.createVtxArr( num_verts, TSTTM::StorageOrder_BLOCKED, coords, 3 * num_verts, sidl_vertices,
174  sidl_vertices_size );
175  }
176  catch( TSTT::Error& /* err */ )
177  {
178  cerr << "Couldn't create vertices in bulk call" << endl;
179  return;
180  }
181 
182  // need to explicitly fill connectivity array, since we don't know
183  // the format of entity handles
184  sidl::array< Entity_Handle > sidl_connect;
185  int sidl_connect_size = 8 * num_elems;
186  CHECK_SIZE( sidl_connect, 8 * num_elems );
187  Entity_Handle* sidl_connect_ptr = HANDLE_ARRAY_PTR( sidl_connect );
188 
189  Entity_Handle* sidl_vertices_ptr = HANDLE_ARRAY_PTR( sidl_vertices );
190  for( int i = 0; i < sidl_connect_size; i++ )
191  {
192  // use connect[i]-1 because we used starting vertex index (vstart) of 1
193  assert( connect[i] - 1 < num_verts );
194  sidl_connect_ptr[i] = sidl_vertices_ptr[connect[i] - 1];
195  }
196 
197  // create the entities
198  sidl::array< Entity_Handle > new_hexes;
199  int new_hexes_size;
200  sidl::array< TSTTM::CreationStatus > status;
201  int status_size;
202 
203  try
204  {
205  mesh_arrmod.createEntArr( TSTTM::EntityTopology_HEXAHEDRON, sidl_connect, sidl_connect_size, new_hexes,
206  new_hexes_size, status, status_size );
207  }
208  catch( TSTT::Error& /* err */ )
209  {
210  cerr << "Couldn't create hex elements in bulk call" << endl;
211  return;
212  }
213 
214  print_time( false, ttime1, utime, stime );
215 
216  // query the mesh 2 ways
218 
219  print_time( false, ttime2, utime, stime );
220 
222 
223  print_time( false, ttime3, utime, stime );
224 
225  std::cout << "TSTT/MOAB ucd blocked: nelem, construct, e_to_v query, v_to_e query = " << nelem << ", "
226  << ttime1 - ttime0 << ", " << ttime2 - ttime1 << ", " << ttime3 - ttime2 << " seconds" << std::endl;
227 }
228 
229 void testC( TSTTM::Mesh& mesh, const int nelem, sidl::array< double >& coords )
230 {
231  double utime, stime, ttime0, ttime1, ttime2, ttime3;
232  print_time( false, ttime0, utime, stime );
233 
234  CAST_MINTERFACE( mesh, mesh_arrmod, ArrMod );
235 
236  // need some dimensions
237  int numv = nelem + 1;
238  int numv_sq = numv * numv;
239  int num_verts = numv * numv * numv;
240 #define VINDEX( i, j, k ) ( ( i ) + ( (j)*numv ) + ( (k)*numv_sq ) )
241 
242  // array to hold vertices created individually
243  sidl::array< Entity_Handle > sidl_vertices;
244  // int sidl_vertices_size = num_verts;
245  CHECK_SIZE( sidl_vertices, num_verts );
246 
247  // temporary array to hold vertex positions for single vertex
248  sidl::array< double > tmp_coords;
249  int tmp_coords_size = 3;
250  CHECK_SIZE( tmp_coords, 3 );
251  double* dum_coords = ARRAY_PTR( tmp_coords, double );
252 
253  // get direct pointer to coordinate array
254  double* coords_ptr = ARRAY_PTR( coords, double );
255 
256  for( int i = 0; i < num_verts; i++ )
257  {
258 
259  // temporary array to hold (single) vertices
260  sidl::array< Entity_Handle > tmp_vertices;
261  int tmp_vertices_size = 0;
262 
263  // create the vertex
264  dum_coords[0] = coords_ptr[i];
265  dum_coords[1] = coords_ptr[num_verts + i];
266  dum_coords[2] = coords_ptr[2 * num_verts + i];
267  try
268  {
269  mesh_arrmod.createVtxArr( 1, TSTTM::StorageOrder_BLOCKED, tmp_coords, tmp_coords_size, tmp_vertices,
270  tmp_vertices_size );
271  }
272  catch( TSTT::Error& /* err */ )
273  {
274  cerr << "Couldn't create vertex in individual call" << endl;
275  return;
276  }
277 
278  // assign into permanent vertex array
279  sidl_vertices.set( i, tmp_vertices.get( 0 ) );
280  }
281 
282  // get vertex array pointer for reading into tmp_conn
283  Entity_Handle* tmp_sidl_vertices = HANDLE_ARRAY_PTR( sidl_vertices );
284 
285  for( int i = 0; i < nelem; i++ )
286  {
287  for( int j = 0; j < nelem; j++ )
288  {
289  for( int k = 0; k < nelem; k++ )
290  {
291 
292  sidl::array< Entity_Handle > tmp_conn;
293  int tmp_conn_size = 8;
294  CHECK_SIZE( tmp_conn, 8 );
295 
296  int vijk = VINDEX( i, j, k );
297  tmp_conn.set( 0, tmp_sidl_vertices[vijk] );
298  tmp_conn.set( 1, tmp_sidl_vertices[vijk + 1] );
299  tmp_conn.set( 2, tmp_sidl_vertices[vijk + 1 + numv] );
300  tmp_conn.set( 3, tmp_sidl_vertices[vijk + numv] );
301  tmp_conn.set( 4, tmp_sidl_vertices[vijk + numv * numv] );
302  tmp_conn.set( 5, tmp_sidl_vertices[vijk + 1 + numv * numv] );
303  tmp_conn.set( 6, tmp_sidl_vertices[vijk + 1 + numv + numv * numv] );
304  tmp_conn.set( 7, tmp_sidl_vertices[vijk + numv + numv * numv] );
305 
306  // create the entity
307 
308  sidl::array< Entity_Handle > new_hex;
309  int new_hex_size = 0;
310  sidl::array< TSTTM::CreationStatus > status;
311  int status_size = 0;
312 
313  try
314  {
315  mesh_arrmod.createEntArr( TSTTM::EntityTopology_HEXAHEDRON, tmp_conn, tmp_conn_size, new_hex,
316  new_hex_size, status, status_size );
317  }
318  catch( TSTT::Error& /* err */ )
319  {
320  cerr << "Couldn't create hex element in individual call" << endl;
321  return;
322  }
323  }
324  }
325  }
326 
327  print_time( false, ttime1, utime, stime );
328 
329  // query the mesh 2 ways
331 
332  print_time( false, ttime2, utime, stime );
333 
335 
336  print_time( false, ttime3, utime, stime );
337 
338  std::cout << "TSTT/MOAB ucd indiv: nelem, construct, e_to_v query, v_to_e query = " << nelem << ", "
339  << ttime1 - ttime0 << ", " << ttime2 - ttime1 << ", " << ttime3 - ttime2 << " seconds" << std::endl;
340 }
341 
342 void query_elem_to_vert( TSTTM::Mesh& mesh )
343 {
344  sidl::array< Entity_Handle > all_hexes;
345  int all_hexes_size;
346  CAST_MINTERFACE( mesh, mesh_ent, Entity );
347 
348  // get all the hex elements
349  try
350  {
351  mesh.getEntities( 0, TSTTM::EntityType_REGION, TSTTM::EntityTopology_HEXAHEDRON, all_hexes, all_hexes_size );
352  }
353  catch( TSTT::Error& /* err */ )
354  {
355  cerr << "Couldn't get all hex elements in query_mesh" << endl;
356  return;
357  }
358 
359  try
360  {
361  // set up some tmp arrays and array ptrs
362  Entity_Handle* all_hexes_ptr = HANDLE_ARRAY_PTR( all_hexes );
363 
364  // now loop over elements
365  for( int i = 0; i < all_hexes_size; i++ )
366  {
367  sidl::array< int > dum_offsets;
368  sidl::array< Entity_Handle > dum_connect;
369  int dum_connect_size = 0;
370  // get the connectivity of this element; will allocate space on 1st iteration,
371  // but will have correct size on subsequent ones
372  mesh_ent.getEntAdj( all_hexes_ptr[i], TSTTM::EntityType_VERTEX, dum_connect, dum_connect_size );
373 
374  // get vertex coordinates; ; will allocate space on 1st iteration,
375  // but will have correct size on subsequent ones
376  sidl::array< double > dum_coords;
377  int dum_coords_size = 0;
378  TSTTM::StorageOrder order = TSTTM::StorageOrder_UNDETERMINED;
379  mesh.getVtxArrCoords( dum_connect, dum_connect_size, order, dum_coords, dum_coords_size );
380 
381  assert( 24 == dum_coords_size && ARRAY_SIZE( dum_coords ) == 24 );
382  double* dum_coords_ptr = ARRAY_PTR( dum_coords, double );
383  double centroid[3] = { 0.0, 0.0, 0.0 };
384  if( order == TSTTM::StorageOrder_BLOCKED )
385  {
386  for( int j = 0; j < 8; j++ )
387  {
388  centroid[0] += dum_coords_ptr[j];
389  centroid[1] += dum_coords_ptr[8 + j];
390  centroid[2] += dum_coords_ptr[16 + j];
391  centroid[0] += dum_coords.get( j );
392  centroid[1] += dum_coords.get( 8 + j );
393  centroid[2] += dum_coords.get( 16 + j );
394  }
395  }
396  else
397  {
398  for( int j = 0; j < 8; j++ )
399  {
400  centroid[0] += dum_coords_ptr[3 * j];
401  centroid[1] += dum_coords_ptr[3 * j + 1];
402  centroid[2] += dum_coords_ptr[3 * j + 2];
403  }
404  }
405  }
406  }
407  catch( TSTT::Error& /* err */ )
408  {
409  cerr << "Problem getting connectivity or vertex coords." << endl;
410  return;
411  }
412 }
413 
414 void query_vert_to_elem( TSTTM::Mesh& mesh )
415 {
416  sidl::array< Entity_Handle > all_verts;
417  int all_verts_size;
418  CAST_MINTERFACE( mesh, mesh_ent, Entity );
419 
420  // get all the vertices elements
421  try
422  {
423  mesh.getEntities( 0, TSTTM::EntityType_VERTEX, TSTTM::EntityTopology_POINT, all_verts, all_verts_size );
424  }
425  catch( TSTT::Error& /* err */ )
426  {
427  cerr << "Couldn't get all vertices in query_vert_to_elem" << endl;
428  return;
429  }
430 
431  try
432  {
433  // set up some tmp arrays and array ptrs
434  Entity_Handle* all_verts_ptr = HANDLE_ARRAY_PTR( all_verts );
435 
436  // now loop over vertices
437  for( int i = 0; i < all_verts_size; i++ )
438  {
439  sidl::array< Entity_Handle > dum_hexes;
440  int dum_hexes_size;
441 
442  // get the connectivity of this element; will have to allocate space on every
443  // iteration, since size can vary
444  mesh_ent.getEntAdj( all_verts_ptr[i], TSTTM::EntityType_REGION, dum_hexes, dum_hexes_size );
445  }
446  }
447  catch( TSTT::Error& /* err */ )
448  {
449  cerr << "Problem getting connectivity or vertex coords." << endl;
450  return;
451  }
452 }
453 
454 void print_time( const bool print_em, double& tot_time, double& utime, double& stime )
455 {
456  struct rusage r_usage;
457  getrusage( RUSAGE_SELF, &r_usage );
458  utime = (double)r_usage.ru_utime.tv_sec + ( (double)r_usage.ru_utime.tv_usec / 1.e6 );
459  stime = (double)r_usage.ru_stime.tv_sec + ( (double)r_usage.ru_stime.tv_usec / 1.e6 );
460  tot_time = utime + stime;
461  if( print_em )
462  std::cout << "User, system, total time = " << utime << ", " << stime << ", " << tot_time << std::endl;
463 #ifndef LINUX
464  std::cout << "Max resident set size = " << r_usage.ru_maxrss * 4096 << " bytes" << std::endl;
465  std::cout << "Int resident set size = " << r_usage.ru_idrss << std::endl;
466 #else
467  system( "ps o args,drs,rss | grep perf | grep -v grep" ); // RedHat 9.0 doesnt fill in actual
468  // memory data
469 #endif
470 }
471 
472 void compute_edge( double* start, const int nelem, const double xint, const int stride )
473 {
474  for( int i = 1; i < nelem; i++ )
475  {
476  start[i * stride] = start[0] + i * xint;
477  start[nelem + 1 + i * stride] = start[nelem + 1] + i * xint;
478  start[2 * ( nelem + 1 ) + i * stride] = start[2 * ( nelem + 1 )] + i * xint;
479  }
480 }
481 
482 void compute_face( double* a, const int nelem, const double xint, const int stride1, const int stride2 )
483 {
484  // 2D TFI on a face starting at a, with strides stride1 in ada and stride2 in tse
485  for( int j = 1; j < nelem; j++ )
486  {
487  double tse = j * xint;
488  for( int i = 1; i < nelem; i++ )
489  {
490  double ada = i * xint;
491 
492  a[i * stride1 + j * stride2] =
493  ( 1.0 - ada ) * a[i * stride1] + ada * a[i * stride1 + nelem * stride2] +
494  ( 1.0 - tse ) * a[j * stride2] + tse * a[j * stride2 + nelem * stride1] -
495  ( 1.0 - tse ) * ( 1.0 - ada ) * a[0] - ( 1.0 - tse ) * ada * a[nelem * stride1] -
496  tse * ( 1.0 - ada ) * a[nelem * stride2] - tse * ada * a[nelem * ( stride1 + stride2 )];
497  a[nelem + 1 + i * stride1 + j * stride2] =
498  ( 1.0 - ada ) * a[nelem + 1 + i * stride1] + ada * a[nelem + 1 + i * stride1 + nelem * stride2] +
499  ( 1.0 - tse ) * a[nelem + 1 + j * stride2] + tse * a[nelem + 1 + j * stride2 + nelem * stride1] -
500  ( 1.0 - tse ) * ( 1.0 - ada ) * a[nelem + 1 + 0] -
501  ( 1.0 - tse ) * ada * a[nelem + 1 + nelem * stride1] -
502  tse * ( 1.0 - ada ) * a[nelem + 1 + nelem * stride2] -
503  tse * ada * a[nelem + 1 + nelem * ( stride1 + stride2 )];
504  a[2 * ( nelem + 1 ) + i * stride1 + j * stride2] =
505  ( 1.0 - ada ) * a[2 * ( nelem + 1 ) + i * stride1] +
506  ada * a[2 * ( nelem + 1 ) + i * stride1 + nelem * stride2] +
507  ( 1.0 - tse ) * a[2 * ( nelem + 1 ) + j * stride2] +
508  tse * a[2 * ( nelem + 1 ) + j * stride2 + nelem * stride1] -
509  ( 1.0 - tse ) * ( 1.0 - ada ) * a[2 * ( nelem + 1 ) + 0] -
510  ( 1.0 - tse ) * ada * a[2 * ( nelem + 1 ) + nelem * stride1] -
511  tse * ( 1.0 - ada ) * a[2 * ( nelem + 1 ) + nelem * stride2] -
512  tse * ada * a[2 * ( nelem + 1 ) + nelem * ( stride1 + stride2 )];
513  }
514  }
515 }
516 
517 void build_coords( const int nelem, sidl::array< double >& coords )
518 {
519  double ttime0, ttime1, utime1, stime1;
520  print_time( false, ttime0, utime1, stime1 );
521 
522  // allocate the memory
523  int numv = nelem + 1;
524  int numv_sq = numv * numv;
525  int tot_numv = numv * numv * numv;
526  CHECK_SIZE( coords, 3 * tot_numv );
527  double* coords_ptr = ARRAY_PTR( coords, double );
528 
529 // use FORTRAN-like indexing
530 #define VINDEX( i, j, k ) ( ( i ) + ( (j)*numv ) + ( (k)*numv_sq ) )
531  int idx;
532  double scale1, scale2, scale3;
533  // use these to prevent optimization on 1-scale, etc (real map wouldn't have
534  // all these equal)
535  scale1 = LENGTH / nelem;
536  scale2 = LENGTH / nelem;
537  scale3 = LENGTH / nelem;
538 
539 #ifdef REALTFI
540  // use a real TFI xform to compute coordinates
541  // initialize positions of 8 corners
542  coords_ptr[VINDEX( 0, 0, 0 )] = coords_ptr[VINDEX( 0, 0, 0 ) + nelem + 1] =
543  coords_ptr[VINDEX( 0, 0, 0 ) + 2 * ( nelem + 1 )] = 0.0;
544  coords_ptr[VINDEX( 0, nelem, 0 )] = coords_ptr[VINDEX( 0, nelem, 0 ) + 2 * ( nelem + 1 )] = 0.0;
545  coords_ptr[VINDEX( 0, nelem, 0 ) + nelem + 1] = LENGTH;
546  coords_ptr[VINDEX( 0, 0, nelem )] = coords_ptr[VINDEX( 0, 0, nelem ) + nelem + 1] = 0.0;
547  coords_ptr[VINDEX( 0, 0, nelem ) + 2 * ( nelem + 1 )] = LENGTH;
548  coords_ptr[VINDEX( 0, nelem, nelem )] = 0.0;
549  coords_ptr[VINDEX( 0, nelem, nelem ) + nelem + 1] = coords_ptr[VINDEX( 0, nelem, nelem ) + 2 * ( nelem + 1 )] =
550  LENGTH;
551  coords_ptr[VINDEX( nelem, 0, 0 )] = LENGTH;
552  coords_ptr[VINDEX( nelem, 0, 0 ) + nelem + 1] = coords_ptr[VINDEX( nelem, 0, 0 ) + 2 * ( nelem + 1 )] = 0.0;
553  coords_ptr[VINDEX( nelem, 0, nelem )] = coords_ptr[VINDEX( nelem, 0, nelem ) + 2 * ( nelem + 1 )] = LENGTH;
554  coords_ptr[VINDEX( nelem, 0, nelem ) + nelem + 1] = 0.0;
555  coords_ptr[VINDEX( nelem, nelem, 0 )] = coords_ptr[VINDEX( nelem, nelem, 0 ) + nelem + 1] = LENGTH;
556  coords_ptr[VINDEX( nelem, nelem, 0 ) + 2 * ( nelem + 1 )] = 0.0;
557  coords_ptr[VINDEX( nelem, nelem, nelem )] = coords_ptr[VINDEX( nelem, nelem, nelem ) + nelem + 1] =
558  coords_ptr[VINDEX( nelem, nelem, nelem ) + 2 * ( nelem + 1 )] = LENGTH;
559 
560  // compute edges
561  // i (stride=1)
562  compute_edge( &coords_ptr[VINDEX( 0, 0, 0 )], nelem, scale1, 1 );
563  compute_edge( &coords_ptr[VINDEX( 0, nelem, 0 )], nelem, scale1, 1 );
564  compute_edge( &coords_ptr[VINDEX( 0, 0, nelem )], nelem, scale1, 1 );
565  compute_edge( &coords_ptr[VINDEX( 0, nelem, nelem )], nelem, scale1, 1 );
566  // j (stride=numv)
567  compute_edge( &coords_ptr[VINDEX( 0, 0, 0 )], nelem, scale1, numv );
568  compute_edge( &coords_ptr[VINDEX( nelem, 0, 0 )], nelem, scale1, numv );
569  compute_edge( &coords_ptr[VINDEX( 0, 0, nelem )], nelem, scale1, numv );
570  compute_edge( &coords_ptr[VINDEX( nelem, 0, nelem )], nelem, scale1, numv );
571  // k (stride=numv^2)
572  compute_edge( &coords_ptr[VINDEX( 0, 0, 0 )], nelem, scale1, numv_sq );
573  compute_edge( &coords_ptr[VINDEX( nelem, 0, 0 )], nelem, scale1, numv_sq );
574  compute_edge( &coords_ptr[VINDEX( 0, nelem, 0 )], nelem, scale1, numv_sq );
575  compute_edge( &coords_ptr[VINDEX( nelem, nelem, 0 )], nelem, scale1, numv_sq );
576 
577  // compute faces
578  // i=0, nelem
579  compute_face( &coords_ptr[VINDEX( 0, 0, 0 )], nelem, scale1, numv, numv_sq );
580  compute_face( &coords_ptr[VINDEX( nelem, 0, 0 )], nelem, scale1, numv, numv_sq );
581  // j=0, nelem
582  compute_face( &coords_ptr[VINDEX( 0, 0, 0 )], nelem, scale1, 1, numv_sq );
583  compute_face( &coords_ptr[VINDEX( 0, nelem, 0 )], nelem, scale1, 1, numv_sq );
584  // k=0, nelem
585  compute_face( &coords_ptr[VINDEX( 0, 0, 0 )], nelem, scale1, 1, numv );
586  compute_face( &coords_ptr[VINDEX( 0, 0, nelem )], nelem, scale1, 1, numv );
587 
588  // initialize corner indices
589  int i000 = VINDEX( 0, 0, 0 );
590  int ia00 = VINDEX( nelem, 0, 0 );
591  int i0t0 = VINDEX( 0, nelem, 0 );
592  int iat0 = VINDEX( nelem, nelem, 0 );
593  int i00g = VINDEX( 0, 0, nelem );
594  int ia0g = VINDEX( nelem, 0, nelem );
595  int i0tg = VINDEX( 0, nelem, nelem );
596  int iatg = VINDEX( nelem, nelem, nelem );
597  double cX, cY, cZ;
598  int adaInts = nelem;
599  int tseInts = nelem;
600  int gammaInts = nelem;
601 
602  for( int i = 1; i < nelem; i++ )
603  {
604  for( int j = 1; j < nelem; j++ )
605  {
606  for( int k = 1; k < nelem; k++ )
607  {
608  // idx = VINDEX(i,j,k);
609  double tse = i * scale1;
610  double ada = j * scale2;
611  double gamma = k * scale3;
612  double tm1 = 1.0 - tse;
613  double am1 = 1.0 - ada;
614  double gm1 = 1.0 - gamma;
615 
616  cX = gm1 * ( am1 * ( tm1 * coords_ptr[i000] + tse * coords_ptr[i0t0] ) +
617  ada * ( tm1 * coords_ptr[ia00] + tse * coords_ptr[iat0] ) ) +
618  gamma * ( am1 * ( tm1 * coords_ptr[i00g] + tse * coords_ptr[i0tg] ) +
619  ada * ( tm1 * coords_ptr[ia0g] + tse * coords_ptr[iatg] ) );
620 
621  cY = gm1 * ( am1 * ( tm1 * coords_ptr[i000] + tse * coords_ptr[i0t0] ) +
622  ada * ( tm1 * coords_ptr[ia00] + tse * coords_ptr[iat0] ) ) +
623  gamma * ( am1 * ( tm1 * coords_ptr[i00g] + tse * coords_ptr[i0tg] ) +
624  ada * ( tm1 * coords_ptr[ia0g] + tse * coords_ptr[iatg] ) );
625 
626  cZ = gm1 * ( am1 * ( tm1 * coords_ptr[i000] + tse * coords_ptr[i0t0] ) +
627  ada * ( tm1 * coords_ptr[ia00] + tse * coords_ptr[iat0] ) ) +
628  gamma * ( am1 * ( tm1 * coords_ptr[i00g] + tse * coords_ptr[i0tg] ) +
629  ada * ( tm1 * coords_ptr[ia0g] + tse * coords_ptr[iatg] ) );
630 
631  double* ai0k = &coords_ptr[VINDEX( k, 0, i )];
632  double* aiak = &coords_ptr[VINDEX( k, adaInts, i )];
633  double* a0jk = &coords_ptr[VINDEX( k, j, 0 )];
634  double* atjk = &coords_ptr[VINDEX( k, j, tseInts )];
635  double* aij0 = &coords_ptr[VINDEX( 0, j, i )];
636  double* aijg = &coords_ptr[VINDEX( gammaInts, j, i )];
637 
638  coords_ptr[VINDEX( i, j, k )] = ( am1 * ai0k[0] + ada * aiak[0] + tm1 * a0jk[0] + tse * atjk[0] +
639  gm1 * aij0[0] + gamma * aijg[0] ) /
640  2.0 -
641  cX / 2.0;
642 
643  coords_ptr[nelem + 1 + VINDEX( i, j, k )] =
644  ( am1 * ai0k[nelem + 1] + ada * aiak[nelem + 1] + tm1 * a0jk[nelem + 1] + tse * atjk[nelem + 1] +
645  gm1 * aij0[nelem + 1] + gamma * aijg[nelem + 1] ) /
646  2.0 -
647  cY / 2.0;
648 
649  coords_ptr[2 * ( nelem + 1 ) + VINDEX( i, j, k )] =
650  ( am1 * ai0k[2 * ( nelem + 1 )] + ada * aiak[2 * ( nelem + 1 )] + tm1 * a0jk[2 * ( nelem + 1 )] +
651  tse * atjk[2 * ( nelem + 1 )] + gm1 * aij0[2 * ( nelem + 1 )] +
652  gamma * aijg[2 * ( nelem + 1 )] ) /
653  2.0 -
654  cZ / 2.0;
655  }
656  }
657  }
658 
659 #else
660  for( int i = 0; i < numv; i++ )
661  {
662  for( int j = 0; j < numv; j++ )
663  {
664  for( int k = 0; k < numv; k++ )
665  {
666  idx = VINDEX( i, j, k );
667  // blocked coordinate ordering
668  coords_ptr[idx] = i * scale1;
669  coords_ptr[tot_numv + idx] = j * scale2;
670  coords_ptr[2 * tot_numv + idx] = k * scale3;
671  }
672  }
673  }
674 #endif
675  print_time( false, ttime1, utime1, stime1 );
676  std::cout << "TSTT/MOAB: TFI time = " << ttime1 - ttime0 << " sec" << std::endl;
677 }
678 
679 void build_connect( const int nelem, const int vstart, int*& connect )
680 {
681  // allocate the memory
682  int nume_tot = nelem * nelem * nelem;
683  connect = new int[8 * nume_tot];
684 
685  int vijk;
686  int numv = nelem + 1;
687  int numv_sq = numv * numv;
688  int idx = 0;
689  for( int i = 0; i < nelem; i++ )
690  {
691  for( int j = 0; j < nelem; j++ )
692  {
693  for( int k = 0; k < nelem; k++ )
694  {
695  vijk = vstart + VINDEX( i, j, k );
696  connect[idx++] = vijk;
697  connect[idx++] = vijk + 1;
698  connect[idx++] = vijk + 1 + numv;
699  connect[idx++] = vijk + numv;
700  connect[idx++] = vijk + numv * numv;
701  connect[idx++] = vijk + 1 + numv * numv;
702  connect[idx++] = vijk + 1 + numv + numv * numv;
703  connect[idx++] = vijk + numv + numv * numv;
704  assert( i <= numv * numv * numv );
705  }
706  }
707  }
708 }