Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
smooth_mesquite_ng_1.C
Go to the documentation of this file.
1 /* *******************************************************************
2  * Rocstar Simulation Suite *
3  * Copyright@2015, Illinois Rocstar LLC. All rights reserved. *
4  * *
5  * Illinois Rocstar LLC *
6  * Champaign, IL *
7  * www.illinoisrocstar.com *
8  * sales@illinoisrocstar.com *
9  * *
10  * License: See LICENSE file in top level of distribution package or *
11  * http://opensource.org/licenses/NCSA *
12  *********************************************************************/
13 /* *******************************************************************
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES *
16  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *
17  * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR *
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
21  * USE OR OTHER DEALINGS WITH THE SOFTWARE. *
22  *********************************************************************/
23 #ifdef MESQUITE
24 #define USE_STD_INCLUDES 1
25 #define USE_C_PREFIX_INCLUDES 1
26 #include "Mesquite.hpp"
27 #include "MeshImpl.hpp"
28 #include "MsqError.hpp"
29 #include "InstructionQueue.hpp"
30 #include "MeshSet.hpp"
31 #include "TerminationCriterion.hpp"
32 #include "QualityAssessor.hpp"
33 #include "PlanarDomain.hpp"
34 #include "ShapeImprovementWrapper.hpp"
35 
36 // algorithms
37 #include "MeanRatioFunctions.hpp"
38 #include "EdgeLengthQualityMetric.hpp"
39 #include "LPtoPTemplate.hpp"
40 #include "FeasibleNewton.hpp"
41 #include "ConjugateGradient.hpp"
42 #include "MesqPane_95.h"
43 
44 using namespace Mesquite;
45 #endif
46 
47 #include "Rocmop_1.h"
48 #include "roccom.h"
49 #include "Pane.h"
50 #include "Rocblas.h"
51 #include "Rocmap.h"
52 #include "Geometric_Metrics_3.h"
53 #include "Pane_connectivity.h"
54 #include "Pane_boundary.h"
55 #include "Pane_communicator.h"
56 
58 
59 using MAP::Rocmap;
60 /*
61 //FIXME, much of the information gathering can be moved to
62 // the smoother specific initialization routine.
63 void Rocmop::smooth_vol_mesq_ng(double initial_quality){
64 
65  if(_verb)
66  std::cout << " Entering Rocmop::smooth_mesquite_ng" << std::endl;
67 
68  const std::string surf_attr("is_surface");
69  COM::Attribute* w_is_surface = _buf_window->attribute(surf_attr);
70  COM_assertion_msg( w_is_surface, "Unexpected NULL pointer");
71 
72  // First Perform Element-based Laplacian smoothing on pane boundary volume nodes
73  // implemented as follows:
74 
75  // * this part should go into smoother_specific_init
76  // 0 Declare and resize variables and buffers
77  // 1 Loop through panes
78  // a. Find the set of shared nodes.
79  // b. Remove surface nodes from above set, "leaving submerged boundary nodes"
80  // c. Loop through all elements
81  // if(element contains submersed boundary nodes)
82  // increment submersed_boundary nodes' adj. element count
83  // add element center to each submersed_boundary nodes' new position
84 
85 
86  // 2 Sum reduction on nodal positions and adj. element counts
87  // 3 Divide new nodal positions by element counts
88 
89  // 0 Declare and resize data structures.
90  if(_verb > 2) std::cout << " Declaring Variables\n";
91 
92  // Allocate buffer space for new nodal positions
93  COM::Attribute *w_new_coords =
94  _buf_window->new_attribute("new_coords", 'n', COM_DOUBLE, 3, "");
95  _buf_window->resize_array(w_new_coords, 0);
96 
97  // Allocate buffer space for adjacent element counts
98  COM::Attribute *w_adj_elem_cnts =
99  _buf_window->new_attribute("adj_elem_cnts", 'n', COM_DOUBLE, 1, "");
100  _buf_window->resize_array(w_adj_elem_cnts, 0);
101  _buf_window->init_done();
102 
103  // Allocate buffer space for safe distance
104  COM::Attribute *w_safe_dist =
105  _buf_window->new_attribute("safe_dist", 'n', COM_DOUBLE, 1, "");
106  _buf_window->resize_array(w_safe_dist, 0);
107  _buf_window->init_done();
108 
109  // Allocate buffer space for backup coords
110  COM::Attribute *w_backup =
111  _buf_window->new_attribute("backup", 'n', COM_DOUBLE, 3, "");
112  _buf_window->resize_array(w_backup, 0);
113  _buf_window->init_done();
114 
115  // Allocate buffer space for reset flags
116  COM::Attribute *w_reset =
117  _buf_window->new_attribute("reset", 'n', COM_INT, 1, "");
118  _buf_window->resize_array(w_reset, 0);
119  _buf_window->init_done();
120 
121  // Initialize buffer spaces to zeroes.
122  double dzero = 0.;
123  double dlarge =99999999;
124  int izero = 0;
125  Rocblas::copy_scalar( &dzero, w_new_coords);
126  Rocblas::copy_scalar( &dzero, w_adj_elem_cnts);
127  Rocblas::copy_scalar( &dlarge, w_safe_dist);
128  Rocblas::copy_scalar( &izero, w_reset);
129 
130  //backup nodal coords.
131  Rocblas::copy( _buf_window->attribute(COM::COM_NC), w_backup);
132 
133  // Get worst qualities, pre smoothing.
134 
135  // Get a list of local panes
136  std::vector<COM::Pane*> allpanes;
137  _buf_window->panes(allpanes);
138  int total_npanes = (int)allpanes.size();
139 
140  // Allocate space for the set of submerged_boundary.
141  std::vector<std::vector<bool> > is_sub_bnd; // Is submerged boundary node?
142  std::vector<std::vector<bool> > is_pan_bnd; // Is pane boundary node?
143  is_sub_bnd.resize(total_npanes);
144  is_pan_bnd.resize(total_npanes);
145 
146  // Get attribute ids
147  int new_coords_id = w_new_coords->id();
148  int adj_elem_cnts_id = w_adj_elem_cnts->id();
149  int is_surface_id = w_is_surface->id();
150  int safe_dist_id = w_safe_dist->id();
151  int reset_id = w_reset->id();
152  int backup_id = w_backup->id();
153 
154  // get the pconn offset
155  int pconn_offset = MAP::Pane_connectivity::pconn_offset();
156 
157  // 1 Loop through panes
158 
159  if(_verb > 2) std::cout << " Step 1\n";
160  for(int i=0; i < total_npanes; ++i){
161  int size_of_real_nodes = allpanes[i]->size_of_real_nodes();
162  int size_of_real_elems = allpanes[i]->size_of_real_elements();
163  is_sub_bnd[i].resize(size_of_real_nodes,0);
164  is_pan_bnd[i].resize(size_of_real_nodes,0);
165 
166  std::vector<bool> is_isolated; // is a node isolated?
167  MAP::Pane_boundary pb (allpanes[i]);
168  pb.determine_border_nodes(is_pan_bnd[i], is_isolated);
169 
170  // a. Find the set of shared nodes.
171 
172  // get pane level pointers
173  COM::Attribute *p_is_surface = allpanes[i]->attribute(is_surface_id);
174  int *is_surface_ptr = (int*)p_is_surface->pointer();
175 
176  double * adj_elem_cnts_ptr = reinterpret_cast<double*>
177  (allpanes[i]->attribute(adj_elem_cnts_id)->pointer());
178 
179  double * safe_dist_ptr =
180  (double*)(allpanes[i]->attribute(safe_dist_id)->pointer());
181 
182  const Vector_3<double> *pnts = reinterpret_cast<Vector_3<double>*>
183  (allpanes[i]->attribute(COM_NC)->pointer());
184 
185  Vector_3<double> *new_coords_ptr = reinterpret_cast<Vector_3<double>*>
186  (allpanes[i]->attribute(new_coords_id)->pointer());
187 
188  // Obtain the pane connectivity of the local pane
189  const COM::Attribute *pconn = allpanes[i]->attribute(COM::COM_PCONN);
190  const int *vs = (const int*)pconn->pointer() + pconn_offset;
191  int vs_size = pconn->size_of_real_items() - pconn_offset;
192 
193  // Determine the number of communicating panes for shared nodes.
194  int count=0;
195  for (int j=0, nj=vs_size; j<nj; j+=vs[j+1]+2) {
196  if (_buf_window->owner_rank( vs[j]) >=0) ++count;
197  }
198 
199  int index = 0;
200  // Loop through communicating panes for shared nodes.
201  for ( int j=0; j<count; ++j, index+=vs[index+1]+2) {
202  // We skip the panes that are not in the current window
203  while ( _buf_window->owner_rank(vs[index])<0) {
204  index+=vs[index+1]+2;
205  COM_assertion_msg( index<=vs_size, "Invalid communication map");
206  }
207  // Mark node as shared
208  for(int k=0; k<vs[index+1]; ++k){
209  is_sub_bnd[i][vs[index+2+k]-1]=1;
210  }
211  }
212 
213  // b. Remove surface nodes from above set, leaving submerged boundary nodes
214  for (int j =0; j < size_of_real_nodes; ++j){
215  if(is_surface_ptr[j])
216  is_sub_bnd[i][j] = 0;
217  }
218 
219  // c. Loop through all elements
220  // if(element contains submersed boundary nodes)
221  // increment submersed_boundary nodes' adj. element count
222  // add element center to each submersed_boundary nodes' new position
223  Element_node_enumerator ene(allpanes[i],1);
224  for(int j =0; j < size_of_real_elems; ++j, ene.next()){
225  // Collect element indices of submerged boundary nodes.
226  int nn = ene.size_of_nodes(), flag = 0;
227  for(int k =0; k < nn; ++k){
228  if(is_sub_bnd[i][ene[k]-1]){
229  flag = 1;
230  adj_elem_cnts_ptr[ene[k]-1] += 1.0;
231  }
232  }
233  // If the element contains submerged boundary nodes
234  if(flag!=0){
235  // Calculate the element's center
236  Vector_3<double> elem_cntr_pos(0.0,0.0,0.0);
237  for(int k =0; k < nn; ++k){
238  elem_cntr_pos += pnts[ene[k]-1];
239  }
240  elem_cntr_pos /= (double)nn;
241  // Add the center position to the accumulating new positions
242  // of the constituent submerged boundary nodes.
243  // And update safe distance if needed
244  for(int k =0; k < nn; ++k){
245  if(is_sub_bnd[i][ene[k]-1]){
246  // initialize safe distance with distance to center
247  double local_safe_dist = (pnts[ene[k]-1] - elem_cntr_pos).norm();
248  int long_src = -1;
249  double long_dist = -1.0;
250  // replace safe distance with .5 shortest adj. edge length
251  // if less than distance to center.
252  int safe_source = -1;
253  for(int ii=1; ii<nn; ++ii){
254  double cur_edge_dist =
255  .5*(pnts[ene[k]-1] - pnts[ene[(k+ii)%nn]-1]).norm();
256  if(cur_edge_dist < local_safe_dist){
257  safe_source = ii;
258  local_safe_dist = cur_edge_dist;
259  }
260  if(cur_edge_dist > long_dist){
261  long_dist = cur_edge_dist;
262  long_src = ii;
263  }
264  }
265  new_coords_ptr[ene[k]-1] += elem_cntr_pos;
266 #if 0
267  if(safe_source == -1)
268  new_coords_ptr[ene[k]-1] += elem_cntr_pos;
269  else {
270  Vector_3<double> direction =
271  (pnts[ene[(k+long_src)%nn]-1] - pnts[ene[k]-1]);
272  direction.normalize();
273  new_coords_ptr[ene[k]-1] += pnts[ene[k]-1];
274  new_coords_ptr[ene[k]-1] += direction*local_safe_dist;
275  //new_coords_ptr[ene[k]-1] -= pnts[ene[(k+safe_source)%nn]-1];
276  }
277 #endif
278  if(local_safe_dist < safe_dist_ptr[ene[k]-1])
279  safe_dist_ptr[ene[k]-1] = local_safe_dist;
280  }
281  }
282  }
283  }
284  }
285 
286  // 2 Sum reduction on nodal positions and adj. element counts
287  if(_verb > 1) std::cout << " Step 2\n";
288  reduce_sum_on_shared_nodes(w_new_coords);
289  reduce_sum_on_shared_nodes(w_adj_elem_cnts);
290  if(COMMPI_Initialized()){
291  MAP::Pane_communicator pc(_buf_window, _buf_window->get_communicator());
292  pc.init(w_safe_dist);
293  pc.begin_update_shared_nodes();
294  pc.reduce_on_shared_nodes(MPI_MIN);
295  pc.end_update_shared_nodes();
296  }
297 
298  // 3 Divide new nodal positions by element counts
299  if(_verb > 1) std::cout << " Step 3\n";
300  Rocblas::div(w_new_coords, w_adj_elem_cnts, w_new_coords);
301 
302  //std::string msg("\n I submerged quality = ");
303  //print_mquality(msg, is_sub_bnd);
304  //msg = " I pane boundary quality = ";
305  //print_mquality(msg, is_pan_bnd);
306 
307  std::vector<std::vector<bool> > elem_to_check;
308  mark_elems_from_nodes(is_sub_bnd, elem_to_check);
309 
310  // get min,max angles for later use
311  double max_angle = 0.0;
312  double min_angle = 180.0;
313  double angles[] = {0.0, 0.0};
314  for(int i=0,ni = allpanes.size(); i<ni; ++i){
315  for(int k =0,nk = elem_to_check[i].size(); k<nk; ++k){
316  if(elem_to_check[i][k]){
317  Element_node_enumerator ene(allpanes[i],k+1);
318  Angle_Metric_3 am;
319  am.initialize(ene);
320  am.compute(angles);
321  if(angles[1]>max_angle)
322  max_angle = angles[1];
323  if(angles[0]<min_angle)
324  min_angle = angles[0];
325  }
326  }
327  }
328  int rank =0;
329  double temp = min_angle;
330  if(COMMPI_Initialized()){
331  agree_double(max_angle,MPI_MAX);
332  agree_double(min_angle,MPI_MIN);
333  int ierr = MPI_Comm_rank( _buf_window->get_communicator()
334  , &rank);
335  assert( ierr == 0);
336  }
337 
338  if(_verb > 1) std::cout << " Step 4\n";
339  // 4 Copy new nodal coords into mesh for submerged boundary nodes
340 
341  for(int i=0; i < total_npanes; ++i){
342 
343  // get pane level attributes
344  Vector_3<double>* new_coords_ptr =
345  reinterpret_cast<Vector_3<double>* >(allpanes[i]->
346  attribute(new_coords_id)->
347  pointer());
348  Vector_3<double>* coords_ptr =
349  reinterpret_cast<Vector_3<double>* >(allpanes[i]->
350  attribute(COM::COM_NC)
351  ->pointer());
352 
353  double* safe_dist_ptr =
354  (double*)(allpanes[i]->attribute(safe_dist_id)->pointer());
355 
356  for (int j = 0, nj = allpanes[i]->size_of_real_nodes(); j<nj; ++j){
357  if(is_sub_bnd[i][j]){
358  Vector_3<double> direction =
359  new_coords_ptr[j] - coords_ptr[j];
360  double dist = direction.norm();
361  if (dist > safe_dist_ptr[j]){
362  double alpha = .9*safe_dist_ptr[j]/dist;
363  coords_ptr[j] =
364  alpha*new_coords_ptr[j] +(1.0-alpha)*coords_ptr[j];
365  }
366  else{
367  coords_ptr[j] = .5*new_coords_ptr[j] +.5*coords_ptr[j];
368  }
369  }
370  }
371  }
372  //msg = ("\n L submerged quality = ");
373  //print_mquality(msg, is_sub_bnd);
374  //msg = " L pane boundary quality = ";
375  //print_mquality(msg, is_pan_bnd);
376  //msg = " L overall quality = ";
377  //print_quality(msg);
378 
379  // Decide which positions to reset
380  for(int i=0; i < total_npanes; ++i){
381 
382  int* reset_ptr =
383  (int*)(allpanes[i]->attribute(reset_id)->pointer());
384 
385  for(int k =0,nk = elem_to_check[i].size(); k<nk; ++k){
386  if(elem_to_check[i][k]){
387  double angles[] = {0.0, 0.0};
388 
389  Element_node_enumerator ene(allpanes[i],k+1);
390  Angle_Metric_3 am;
391  am.initialize(ene);
392  am.compute(angles);
393  if(angles[1]>max_angle ||
394  angles[0]<min_angle){
395  std::vector<int> nodes;
396  ene.get_nodes(nodes);
397  for(int j =0, nj=nodes.size(); j<nj; ++j){
398  if (is_sub_bnd[i][nodes[j]-1])
399  reset_ptr[nodes[j]-1] = 1;
400  }
401  }
402  }
403  }
404  }
405 
406  // All nodes being moved are shared, so this should be valid
407  Rocmap::reduce_maxabs_on_shared_nodes(w_reset);
408 
409  for(int i=0; i < total_npanes; ++i){
410 
411  // get pane level attributes
412  Vector_3<double>* backup_ptr =
413  reinterpret_cast<Vector_3<double>* >(allpanes[i]->
414  attribute(backup_id)->
415  pointer());
416  Vector_3<double>* coords_ptr =
417  reinterpret_cast<Vector_3<double>* >(allpanes[i]->
418  attribute(COM::COM_NC)
419  ->pointer());
420 
421  int* reset_ptr =
422  (int*)(allpanes[i]->attribute(reset_id)->pointer());
423 
424  for(int j=0, nj = allpanes[i]->size_of_real_nodes(); j<nj; ++j){
425  if(reset_ptr[j])
426  coords_ptr[j] = backup_ptr[j];
427  }
428  }
429 
430  //msg = ("\n R submerged quality = ");
431  //print_mquality(msg, is_sub_bnd);
432  //msg = " R pane boundary quality = ";
433  //print_mquality(msg, is_pan_bnd);
434  //msg = " R overall quality = ";
435  //print_quality(msg);
436 
437  // Smooth using mesquite.
438  smooth_mesquite(allpanes,0);
439 
440  //msg = "\n M submerged quality = ";
441  //print_mquality(msg, is_sub_bnd);
442  // msg = " M pane boundary quality = ";
443  //print_mquality(msg, is_pan_bnd);
444  //msg = " M overall quality = ";
445  //print_quality(msg);
446 
447  //Deallocate buffer space
448  _buf_window->delete_attribute( w_adj_elem_cnts->name());
449  _buf_window->delete_attribute( w_new_coords->name());
450  _buf_window->init_done();
451 
452  if(_verb > 1)
453  std::cout << " Exiting Rocmop::smooth_mesquite_ng" << std::endl;
454 }
455 */
456 
458 struct Four_tuple {
459  Four_tuple( int a, int b, int c, int d)
460  : _a(a), _b(b), _c(c), _d(d) {}
461  int &operator[](int i) { return (&_a)[i]; }
462  const int &operator[](int i) const { return (&_a)[i]; }
463  bool operator<( const Four_tuple &x) const {
464  return _a<x._a || (_a==x._a && (_b<x._b || _b==x._b &&
465  (_c<x._c || _c==x._c && _d<x._d)));
466  }
467 private:
468  int _a, _b, _c, _d;
469 };
470 
471 typedef std::map< Four_tuple, MAP::Facet_ID> Corners2Face_Map;
472 typedef std::map< int, int> Id_Map;
473 
474 void Rocmop::determine_physical_border(COM::Attribute* w_is_surface){
475  COM_assertion_msg( w_is_surface, "Unexpected NULL pointer");
476  COM_assertion_msg( COM_compatible_types( w_is_surface->data_type(), COM_INT),
477  "Surface-list must have integer type");
478  COM_assertion_msg( w_is_surface->is_nodal() == 1,
479  "Surface-list must be nodal");
480  COM_assertion_msg( w_is_surface->size_of_components() == 1,
481  "Surface-list must have a single component");
482  int w_is_surface_id = w_is_surface->id();
483 
484  // This function is implemented as follows:
485  // 0 Declare and resize data structures.
486  //
487  // Loop through panes
488  // 1 Get the pane boundary nodes and faces using Rocmap::Pane_boundary
489  // 2 Identify adjacent panes, and shared nodes. Also, create an id mappings
490  // from a node's id to its index in the shared node array and vice versa.
491  // 3 Identify "possibly shared faces", those faces whose nodes are all
492  // shared with the same adjacent pane. Make a list of these faces.
493  // 4 Communicate the size of the local face list to send to / recieve from
494  // adjacent panes.
495  // 5 Create buffers for the incoming face list and communicate faces lists.
496  // 6 For every face received, remove any matching faces in the list of
497  // boundary faces.
498  // 7 Mark all nodes still contained in boundary faces as physical boundary
499  // nodes.
500 
501 
502  // 0 Declare and resize data structures.
503 
504  // vector corresponds to adjacent panes (reused amongst local panes)
505  std::vector<bool> is_border; // is a node a border node?
506  std::vector<bool> is_shared; // is a node a shared node?
507  std::vector<bool> is_isolated; // is a node isolated?
508  std::vector<MAP::Facet_ID> border_facet_list;
509 
510  // Space in which false pconns are built. (reused amongs local panes)
511  // outside vectors correspond to adjacent panes
512  // inside vectors correspond to connectivity information
513  //std::vector<std::vector<int> > false_pconn;
514 
515  // Per-local-pane data structures
516  // outside vectors correspond to the local panes
517  // inside vectors correspond to adjacent panes
518  std::vector<std::set<MAP::Facet_ID> > border_facets; // List of all border faces.
519  std::vector<std::vector<Corners2Face_Map> > maybe_shared; // Possibly shared facets
520  std::vector<std::vector<Id_Map > > lid2ind; // map from local id to pconn index
521  std::vector<std::vector<Id_Map > > ind2lid; // map from pconn index to local id
522  std::vector<std::vector<std::set<int> > > adj_pane_set; // nodes shared with adjacent panes
523  std::vector<std::vector<int> > adj_pane_id; // ids of adjacent panes
524  std::vector<std::vector<int> > adj_pane_recv; // amount of data coming from adjacent panes.
525 
526  // The amount of data to be sent by each pane
527  std::vector<int> send_sizes;
528 
529  std::set<MAP::Facet_ID>::iterator bf_it, bf_it2;
530  Id_Map::iterator idm_it,idm_it2; // iterator for lid2ind or ind2lid
531  Corners2Face_Map::iterator ms_it,ms_it2;
532  std::set<int >::iterator aps_it, aps_it2; //iterator for adj_pane_map
533 
534  // get the pconn offset
535  int pconn_offset = MAP::Pane_connectivity::pconn_offset();
536 
537  // Resize per-local-pane data structures
538  std::vector<COM::Pane*> allpanes;
539  COM::Window * wrk_window = w_is_surface->window();
540  wrk_window->panes(allpanes);
541  int total_npanes = (int)allpanes.size();
542  border_facets.resize(total_npanes);
543  maybe_shared.resize(total_npanes);
544  lid2ind.resize(total_npanes);
545  ind2lid.resize(total_npanes);
546  adj_pane_set.resize(total_npanes);
547  adj_pane_id.resize(total_npanes);
548  adj_pane_recv.resize(total_npanes);
549  send_sizes.resize(total_npanes);
550 
551  // Register an attribute for our fake pconn.
552  COM::Attribute * false_pconn = wrk_window->new_attribute("false_pconn", 'p', COM_INT, 1, "");
553 
554  // Register an attribute for sending and receiving sizes
555  // also used for sending buffer
556  COM::Attribute *com_buff = wrk_window->new_attribute("com_buff", 'p', COM_INT, 1,"");
557  int w_com_buff_id = com_buff->id();
558 
559  // Loop through panes
560  for(int i=0; i<total_npanes; ++i){
561  int size_of_real_nodes = allpanes[i]->size_of_real_nodes();
562  is_border.clear();
563  is_shared.clear();
564  is_isolated.clear();
565  is_border.resize(size_of_real_nodes,0);
566  is_shared.resize(size_of_real_nodes,0);
567  is_isolated.resize(size_of_real_nodes,0);
568  send_sizes[i] = 0;
569 
570  // 1 Get the pane boundary nodes and faces using Rocmap::Pane_boundary
571  // Determine the border nodes.
572  MAP::Pane_boundary pb(allpanes[i]);
573  pb.determine_border_nodes(is_border, is_isolated, &border_facet_list);
574 
575  // put the list of border facets into a set for faster searching
576  for(int j =0, nj=border_facet_list.size(); j<nj; ++j)
577  border_facets[i].insert(border_facet_list[j]);
578 
579  // 2 Identify adjacent panes, and shared nodes. Also, create an id mappings
580  // from a node's id to its index in the shared node array and vice versa.
581 
582  // Obtain the pane connectivity of the local pane
583  const COM::Attribute *pconn = allpanes[i]->attribute(COM::COM_PCONN);
584  const int *vs = (const int*)pconn->pointer() + pconn_offset;
585  int vs_size = pconn->size_of_real_items() - pconn_offset;
586 
587  // Determine the number of communicating panes for shared nodes.
588  int count=0;
589  for (int j=0, nj=vs_size; j<nj; j+=vs[j+1]+2) {
590  if (wrk_window->owner_rank( vs[j]) >=0) ++count;
591  }
592 
593  // Resize per-adjacent-pane data structures
594  //false_pconn.resize(count);
595  maybe_shared[i].resize(count);
596  lid2ind[i].resize(count);
597  ind2lid[i].resize(count);
598  adj_pane_set[i].resize(count);
599  adj_pane_id[i].resize(count);
600  adj_pane_recv[i].resize(count);
601 
602  int index = 0;
603  // Loop through communicating panes for shared nodes.
604  for ( int j=0; j<count; ++j, index+=vs[index+1]+2) {
605  // We skip the panes that are not in the current window
606  while ( wrk_window->owner_rank(vs[index])<0) {
607  index+=vs[index+1]+2;
608  COM_assertion_msg( index<=vs_size, "Invalid communication map");
609  }
610  adj_pane_id[i][j] = vs[index];
611  // Add this pane to current shared node's list, mark node as shared and
612  // keep track of the mapping between array index and local node id
613  for(int k=0; k<vs[index+1]; ++k){
614  is_shared[vs[index+2+k]-1]=1;
615  adj_pane_set[i][j].insert(vs[index+2+k]);
616  lid2ind[i][j].insert(std::make_pair(vs[index+2+k],k));
617  ind2lid[i][j].insert(std::make_pair(k,vs[index+2+k]));
618  }
619  }
620 #if 0
621 
622  std::cout << "Pane " << allpanes[i]->id() << " lid2ind = \n";
623  for(int j=0; j < count; ++j){
624  std::cout << " to Pane " << adj_pane_id[i][j] << " =\n";
625  for(int k =0; k < ind2lid[i][j].size();++k){
626  std::cout << "(" << k << "," << ind2lid[i][j][k] << ") ";
627  }
628  std::cout << "\n";
629  }
630  std::cout << "Pane " << i << "\n"
631  << " shared nodes = \n";
632 
633  for(int j=0; j<is_shared.size(); ++j){
634  if(is_shared[j])
635  std::cout << j+1 << " ";
636  }
637  std::cout << "\n\n nodes shared with othe panes";
638 
639  aps_it = adj_pane_set[i][0].begin();
640  for(; aps_it != adj_pane_set[i][0].end(); ++aps_it){
641  std::cout << *aps_it << " ";
642  }
643 
644 #endif
645 
646  // 3 Identify "possibly shared faces", those faces whose nodes are all
647  // shared with the same adjacent pane. Make a list of these faces.
648 
649  bf_it2 = border_facets[i].end();
650  bf_it = border_facets[i].begin();
651  //for(int j=0, nj=border_facets[i].size(); j<nj; ++j){
652  for(; bf_it != bf_it2; ++bf_it){
653  Element_node_enumerator ene(allpanes[i], (*bf_it).eid());
654  Facet_node_enumerator fne (&ene, (*bf_it).lid());
655  //if all the nodes are shared
656  if( is_shared[fne[0]-1] &&
657  is_shared[fne[1]-1] &&
658  is_shared[fne[2]-1] &&
659  fne.size_of_edges()>3?is_shared[fne[3]-1]:1
660  ){
661  // then see if they are all shared by the same panes
662  Four_tuple ns( fne[0], fne[1], fne[2], fne.size_of_edges()>3?fne[3]:-1);
663  for(int k=0; k<count; ++k){
664  aps_it2 = adj_pane_set[i][k].end();
665  if(aps_it2 != adj_pane_set[i][k].find(fne[0]) &&
666  aps_it2 != adj_pane_set[i][k].find(fne[1]) &&
667  aps_it2 != adj_pane_set[i][k].find(fne[2]) &&
668  (fne.size_of_edges()>3?(adj_pane_set[i][k].find(fne[3]) != aps_it2):1)){
669  // and if they are
670  // then this facet is possibly shared with the adjacent node
671  Four_tuple ns( fne[0], fne[1], fne[2], fne.size_of_edges()>3?fne[3]:-1);
672  std::sort(&ns[0],&ns[4]);
673  maybe_shared[i][k].insert(std::make_pair(ns,(*bf_it)));
674  }
675  }
676  }
677  }
678 
679 #if 0
680  // print out the list of possibly shared nodes:
681  std::cout << "Pane " << allpanes[i]->id() << " possibly shared panes\n";
682  for(int j = 0; j<count; ++j){
683  std::cout << " faces possibly shared with Pane " << adj_pane_id[i][j] << "\n";
684  ms_it2 = maybe_shared[i][j].end();
685  for(ms_it = maybe_shared[i][j].begin(); ms_it != ms_it2; ++ms_it){
686  std::cout << "(" << (ms_it->first)[0] << " "
687  << (ms_it->first)[1] << " "
688  << (ms_it->first)[2] << " "
689  << (ms_it->first)[3] << ") ";
690  }
691  std::cout << "\n";
692  }
693 #endif
694 
695  wrk_window->set_size("com_buff", allpanes[i]->id(), count, 0);
696  int* my_buff;
697  wrk_window->resize_array("com_buff", (const int)allpanes[i]->id(),
698  reinterpret_cast<void**>(&my_buff));
699 
700  // find the size of the pconn to create
701  // 3*(pconn_offset) // number of communicating blocks
702  // + 3 // shared node block
703  // + 6*count // (pane id,node count,array-id for each adj. pane)*2blocks
704 
705  int my_size = 3*pconn_offset + 3 + 6*count;
706  int* my_pconn;
707  wrk_window->set_size("false_pconn", allpanes[i]->id(), my_size,
708  my_size-(3+pconn_offset));
709  wrk_window->resize_array("false_pconn", (const int)allpanes[i]->id(),
710  reinterpret_cast<void**>(&my_pconn));
711  // Add shared node data
712  if(pconn_offset){my_pconn[0]=1;++my_pconn;}
713  my_pconn[0]=1; my_pconn[1]=1; my_pconn[2]=1;
714  my_pconn += 3;
715 
716  // filling in send buffer and real nodes to send info.
717  if(pconn_offset){my_pconn[0]=count;++my_pconn;}
718  for(int j=0; j<count; ++j){
719  // print communicating pane id
720  my_pconn[0] = adj_pane_id[i][j];
721  // print number of ints to communicate
722  my_pconn[1] = 1;
723  // print index-id of information
724  my_pconn[2] = j+1;
725  my_pconn+=3;
726  // store size of information to send
727  my_buff[j] = 4*maybe_shared[i][j].size();
728  send_sizes[i] += my_buff[j];
729  }
730 
731  // add ghost nodes to receive info.
732  if(pconn_offset){my_pconn[0]=count;++my_pconn;}
733  for(int j=0; j<count; ++j){
734  my_pconn[0] = adj_pane_id[i][j];
735  my_pconn[1] = 1;
736  my_pconn[2] = j+1;
737  my_pconn+=3;
738  }
739 
740 #if 0
741  for ( int j=0; j<count; ++j, index+=vs[index+1]+2) {
742  // We skip the panes that are not in the current window
743  while ( wrk_window->owner_rank(vs[index])<0)
744  index+=vs[index+1]+2;
745  // List the communicating pane, 1 item to send, and the index of that item in a
746  // local panel array
747  my_pconn[3*j] = vs[index];
748  my_pconn[3*j+1] = 1;
749  my_pconn[3*j+2] = j+1;
750 
751  my_pconn[3*(count+j)+pconn_offset] = vs[index];
752  my_pconn[3*(count+j)+1+pconn_offset] = 1;
753  my_pconn[3*(count+j)+2+pconn_offset] = j+1;
754 
755  my_pconn[3*(2*count+j)+2*pconn_offset] = vs[index];
756  my_pconn[3*(2*count+j)+1+2*pconn_offset] = 1;
757  my_pconn[3*(2*count+j)+2+2*pconn_offset] = j+1;
758 
759 
760  // store the size of the buffer to send across
761  my_buff[j] = 4*maybe_shared[i][j].size();
762  send_sizes[i] += my_buff[j];
763  }
764 #endif
765 #if 0
766  std::cout << "pconn_offset = " << pconn_offset << "\n";
767  std::cout << "total size = " << my_size << "\n";
768  std::cout << "ghost sized = " << my_size - pconn_offset << "\n\n";
769 #endif
770  }
771  wrk_window->init_done();
772 
773 #if 0
774  //print out pconn, for debugging.
775  for(int i=0; i<total_npanes; ++i){
776  std::cout << "FALSE pconn for pane " << allpanes[i]->id() << std::endl;
777  COM::Attribute *my_pconn = allpanes[i]->attribute(w_false_pconn_id);
778  int* ptr = (int*)my_pconn->pointer();
779  for(int k=0,nk=my_pconn->size_of_items();k<nk;++k){
780  std::cout << ptr[k] << " ";
781  }
782  std::cout << "\n\n";
783 
784  // print out size of buffer being sent across
785  std::cout << "size of face list\n";
786  COM::Attribute *my_bsize = allpanes[i]->attribute(w_com_buff_id);
787  ptr = (int*)my_bsize->pointer();
788  for(int j =0; j<my_bsize->size_of_items(); ++j)
789  std::cout << ptr[j] << " ";
790  std::cout << "\n\n";
791  }
792 #endif
793 
794  // 4 Communicate the size of the local face list to send to / recieve from
795  // adjacent panes.Pane_connectivity::
796  Rocmap::update_ghosts(com_buff,
797  false_pconn);
798 
799  //print out pconn, for debugging.
800 #if 0
801  for(int i=0; i<total_npanes; ++i){
802  COM::Attribute *my_pconn = allpanes[i]->attribute(w_false_pconn_id);
803  int* ptr = (int*)my_pconn->pointer();
804  for(int k=0,nk=my_pconn->size_of_items();k<nk;++k){
805  std::cout << ptr[k] << " ";
806  }
807  std::cout << "\n\n";
808  // print out possibly shared faces
809  std::cout << "possibly shared faces\n";
810  for(ms_it = maybe_shared[i][0].begin(), ms_it2 = maybe_shared[i][0].end();
811  ms_it != ms_it2; ++ms_it){
812  std::cout << "("
813  << (ms_it->first)[0] << " "
814  << (ms_it->first)[1] << " "
815  << (ms_it->first)[2] << " "
816  << (ms_it->first)[3] << ") ";
817  }
818  std::cout << "\n\n";
819  // print out size of buffer being sent across
820  std::cout << "size of communicated face list\n";
821  COM::Attribute *my_bsize = allpanes[i]->attribute(w_com_buff_id);
822  ptr = (int*)my_bsize->pointer();
823  for(int j =0; j <adj_pane_id[i].size(); ++j)
824  std::cout << ptr[j] << " ";
825  std::cout << "\n\n";
826  }
827 #endif
828 
829  // 5 Create buffers for the incoming face list and communicate faces lists.
830  // loop through panes
831  for(int i=0; i<total_npanes; ++i){
832 
833  // get pane level attributes and pointers
834  COM::Attribute *p_com_buff = allpanes[i]->attribute(w_com_buff_id);
835  int *com_buff_ptr = (int*)p_com_buff->pointer();
836 
837  // find the number of adjacent panes
838  int count = adj_pane_id[i].size();
839 
840  // find the size of data to be received and sent.
841  int recv_size = 0;
842  // add up the sizes of all the buffers being sent
843  for(int j=0; j< count; ++j){
844  recv_size += com_buff_ptr[j];
845  adj_pane_recv[i][j] = com_buff_ptr[j];
846  }
847  int send_size = send_sizes[i];
848 
849  // find the size of the pconn to create
850  // 3*(pconn_offset) // number of communicating blocks
851  // + 3 // shared node block
852  // + 4*count // (pane id and node count for each adj. pane)*2blocks
853  // + recv_size+send_size // number of nodes in facet lists
854  int pconn_size = 3*(pconn_offset)+3+4*count+recv_size+send_size;
855 
856 #if 0
857 
858  std::cout << " SIZES\nrecv_size = " << recv_size << " send_size = " << send_size
859  << " pconn size = " << pconn_size << "\n"
860  << " 3*pconn_offset = " << 3*pconn_offset
861  << " 4*count = " << 4*count << "\n\n";
862 
863 #endif
864 
865  wrk_window->set_size("com_buff", allpanes[i]->id(),std::max(send_size,recv_size),0);
866  wrk_window->resize_array("com_buff", (const int)allpanes[i]->id(),
867  reinterpret_cast<void**>(&com_buff_ptr));
868  int* pconn_ptr;
869  wrk_window->set_size("false_pconn", allpanes[i]->id(), pconn_size,
870  pconn_size - (3+pconn_offset));
871  wrk_window->resize_array("false_pconn", (const int)allpanes[i]->id(),
872  reinterpret_cast<void**>(&pconn_ptr));
873 
874  // add shared node data
875  if(pconn_offset){pconn_ptr[0]=1;++pconn_ptr;}
876  pconn_ptr[0]=1; pconn_ptr[1]=1; pconn_ptr[2]=1;
877  pconn_ptr += 3;
878 
879  // now fill in the send buffer and real nodes to send info. in the pconn
880  if(pconn_offset){pconn_ptr[0]=count;++pconn_ptr;}
881  int com_ind = 0; // index of next place in com_buff
882  for(int j =0; j<count; ++j){
883  pconn_ptr[0]=adj_pane_id[i][j];
884  pconn_ptr[1]=4*maybe_shared[i][j].size();
885  pconn_ptr+=2;
886  ms_it2 = maybe_shared[i][j].end();
887  for(ms_it = maybe_shared[i][j].begin(); ms_it != ms_it2;
888  ++ms_it, com_ind+=4, pconn_ptr+=4){
889  // Convert nodal id's to pconn based index id's and place in the comm buffer
890  const Four_tuple* ft = &(ms_it->first);
891  if ((*ft)[0]==-1)
892  com_buff_ptr[com_ind] = -1;
893  else
894  idm_it = lid2ind[i][j].find((*ft)[0]);
895  idm_it = lid2ind[i][j].find((*ft)[1]);
896  com_buff_ptr[com_ind+1] = idm_it->second;
897  idm_it = lid2ind[i][j].find((*ft)[2]);
898  com_buff_ptr[com_ind+2] = idm_it->second;
899  idm_it = lid2ind[i][j].find((*ft)[3]);
900  com_buff_ptr[com_ind+3] = idm_it->second;
901  std::sort(&com_buff_ptr[com_ind],&com_buff_ptr[com_ind+4]);
902  // Also fill in the pconn
903  pconn_ptr[0] = com_ind+1;
904  pconn_ptr[1] = com_ind+2;
905  pconn_ptr[2] = com_ind+3;
906  pconn_ptr[3] = com_ind+4;
907  }
908  }
909 
910  // now fill in the ghost nodes to receive info. in the pconn
911  if(pconn_offset){pconn_ptr[0]=count;++pconn_ptr;}
912  com_ind = 1;
913  for(int j=0; j<count; ++j){
914  pconn_ptr[0]=adj_pane_id[i][j];
915  pconn_ptr[1]=adj_pane_recv[i][j];
916  for(int k=0; k<adj_pane_recv[i][j]; ++k){
917  pconn_ptr[k+2] = k+com_ind;
918  }
919  com_ind += adj_pane_recv[i][j];
920  pconn_ptr += 2+adj_pane_recv[i][j];
921  }
922  }
923 
924 #if 0
925  //print out pconn, for debugging.
926  for(int i=0; i<total_npanes; ++i){
927  std::cout << "Facet list FALSE pconn for pane " << allpanes[i]->id() << std::endl;
928  COM::Attribute *my_pconn = allpanes[i]->attribute(w_false_pconn_id);
929  int* ptr = (int*)my_pconn->pointer();
930  for(int k=0,nk=my_pconn->size_of_items();k<nk;++k){
931  std::cout << ptr[k] << " ";
932  }
933  std::cout << "\n\n";
934 
935  std::cout << "Facet list buffer for pane " << allpanes[i]->id() << std::endl;
936  COM::Attribute *my_buff = allpanes[i]->attribute(w_com_buff_id);
937  ptr = (int*)my_buff->pointer();
938  for(int k=0,nk=my_buff->size_of_items();k<nk;++k){
939  std::cout << ptr[k] << " ";
940  }
941  std::cout << "\n\n";
942  }
943 #endif
944 
945  // update
946  Rocmap::update_ghosts(com_buff,
947  false_pconn);
948 
949 #if 0
950  //print out pconn, for debugging.
951  for(int i=0; i<total_npanes; ++i){
952  std::cout << "Updated Facet list buffer for pane " << allpanes[i]->id() << std::endl;
953  COM::Attribute *my_buff = allpanes[i]->attribute(w_com_buff_id);
954  int* ptr = (int*)my_buff->pointer();
955  for(int k=0,nk=my_buff->size_of_items();k<nk;++k){
956  std::cout << ptr[k] << " ";
957  }
958  std::cout << "\n\n";
959  }
960 #endif
961  // 6 For every face received, remove any matching faces in the list of
962  // boundary faces.
963  // loop through all panes
964  for(int i =0; i<total_npanes; ++i){
965  COM::Attribute *my_buff = allpanes[i]->attribute(w_com_buff_id);
966  int* buff_ptr = (int*)my_buff->pointer();
967 
968  int count = adj_pane_recv[i].size();
969  // loop through adjacent panes
970  //std::cout << "Pane " << allpanes[i]->id() << "\n";
971  for(int j=0;j<count; buff_ptr += adj_pane_recv[i][j], ++j){
972 
973  //std::cout << "Converting node array\n";
974  // convert all node array indices to local id
975  //std::cout << adj_pane_recv[i][j] << " items being converted\n";
976  for(int k=0, nk =adj_pane_recv[i][j]; k<nk; ++k){
977  if(buff_ptr[k]!=-1){
978  buff_ptr[k] = ind2lid[i][j][buff_ptr[k]];
979  }
980  }
981  // std::cout << "Checking for matching facets with pane" << adj_pane_id[i][j] << "\n";
982  // check for matching facets
983  ms_it2 = maybe_shared[i][j].end();
984  bf_it2 = border_facets[i].end();
985  for(int k=0, nk=adj_pane_recv[i][j]; k<nk; k+=4){
986  Four_tuple ns(buff_ptr[k],buff_ptr[k+1],buff_ptr[k+2],buff_ptr[k+3]);
987  std::sort(&ns[0],&ns[4]);
988  //std::cout << " (" << ns[0] << " " << ns[1] << " " << ns[2] << " " << ns[3] << ") ";
989  ms_it = maybe_shared[i][j].find(ns);
990  if(ms_it != ms_it2){
991  //std::cout << "found ";
992  Element_node_enumerator ene(allpanes[i], (ms_it->second).eid());
993  Facet_node_enumerator fne (&ene, (ms_it->second).lid());
994  //std::cout << "(" << fne[0] << " " << fne[1]
995  // << " " << fne[2];
996  // if(fne.size_of_edges()>3)
997  // std::cout << " " << fne[3];
998  //std::cout << ")\n";
999  MAP::Facet_ID fid = ms_it->second;
1000  bf_it = border_facets[i].find(fid);
1001  if(bf_it != bf_it2)
1002  border_facets[i].erase(fid);
1003  }
1004  else
1005  ;
1006  //std::cout << "not found\n";
1007  }
1008  }
1009  }
1010 
1011  // std::cout << "On to step 7 \n";
1012 
1013  // 7 Mark all nodes still contained in boundary faces as physical boundary
1014  // nodes.
1015  for(int i =0; i < total_npanes; ++i){
1016  // std::cout << "Pane " << i << " detected surface faces\n";
1017  bf_it2 = border_facets[i].end();
1018  for(bf_it = border_facets[i].begin(); bf_it!= bf_it2; ++bf_it){
1019  Element_node_enumerator ene(allpanes[i], (*bf_it).eid());
1020  Facet_node_enumerator fne (&ene, (*bf_it).lid());
1021 
1022  //std::cout << "(" << fne[0] << " " << fne[1]
1023  // << " " << fne[2];
1024  // if(fne.size_of_edges()>3)
1025  // std::cout << " " << fne[3];
1026  //std::cout << ")";
1027  }
1028  //std::cout << "\n\n";
1029  }
1030 
1031  for(int i = 0; i < total_npanes; ++i){
1032  COM::Attribute *p_is_surface = allpanes[i]->attribute(w_is_surface_id);
1033  int* surf_ptr = (int*)p_is_surface->pointer();
1034  // initialize surface to 0s
1035  for(int j=0, nj= p_is_surface->size_of_items();j<nj; ++j){
1036  surf_ptr[j] = 0;
1037  }
1038  bf_it2 = border_facets[i].end();
1039  //std::cout << "Pane " << allpanes[i]->id() << " marking surface nodes\n";
1040  for(bf_it = border_facets[i].begin(); bf_it!= bf_it2; ++bf_it){
1041  Element_node_enumerator ene(allpanes[i], (*bf_it).eid());
1042  Facet_node_enumerator fne (&ene, (*bf_it).lid());
1043  surf_ptr[fne[0]-1] = 1;
1044  surf_ptr[fne[1]-1] = 1;
1045  surf_ptr[fne[2]-1] = 1;
1046  //std::cout << fne[0] << " " << fne[1] << " " << fne[2] << "\n";
1047  if(fne.size_of_edges()>3)
1048  surf_ptr[fne[3]-1] = 1;
1049  }
1050  // std::cout << "\n\n";
1051  }
1052 
1053 #if 0
1054  for(int i = 0; i < total_npanes; ++i){
1055  COM::Attribute *p_pconn = allpanes[i]->attribute(COM::COM_PCONN);
1056  // std::cout << "PANE " << allpanes[i]->id() << "'s real pconn size = "
1057  // << p_pconn->size_of_real_items() << " and ghost size = "
1058  // << p_pconn->size_of_items()-p_pconn->size_of_real_items() << "\n\n";
1059 
1060  //int* ptr = (int*)p_pconn->pointer();
1061  //for(int j=0, nj=p_pconn->size_of_items(); j<nj; ++j){
1062  // std::cout << ptr[j] << " ";
1063  //}
1064  // std::cout << "\n\n";
1065  }
1066 #endif
1067 
1068  // update
1070  Rocmap::update_ghosts(w_is_surface);
1071 
1072  // delete buffer and false pconn attributes
1073  wrk_window->delete_attribute(com_buff->name());
1074  wrk_window->delete_attribute(false_pconn->name());
1075 
1076 }
1077 
1079 
1080 
1081 
1082 
1083 
1084 
bool operator<(const Four_tuple &x) const
void determine_physical_border()
Determine which nodes and elements are on the physical border.
Definition: Rocmop.C:677
A structure used to represent element faces.
Definition: Pane_boundary.C:60
Utility for constructing pane connectivities in parallel.
std::map< int, int > Id_Map
const NT & d
Contains the prototypes for the Pane object.
j indices k indices k
Definition: Indexing.h:6
#define COM_assertion_msg(EX, msg)
Vector_n max(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:354
This file contains the prototypes for Roccom API.
3D geometric quality Metric declarations.
const int & operator[](int i) const
Handles communication of shared nodes, ghost nodes or ghost cells across panes.
const int total_npanes
Definition: ex1.C:94
std::map< Four_tuple, Facet_ID > Corners2Face_Map
Definition: Pane_boundary.C:73
static void reduce_maxabs_on_shared_nodes(COM::Attribute *att, COM::Attribute *pconn=NULL)
Perform a maxabs-reduction on the shared nodes for the given attribute.
Definition: Rocmap.C:77
int COM_compatible_types(COM_Type type1, COM_Type type2)
Definition: roccom_c++.h:563
blockLoc i
Definition: read.cpp:79
void int int REAL * x
Definition: read.cpp:74
Four_tuple(int a, int b, int c, int d)
int & operator[](int i)
#define MOP_END_NAMESPACE
Definition: mopbasic.h:29
Definition for Rocblas API.
void int int * nk
Definition: read.cpp:74
static void update_ghosts(COM::Attribute *att, const COM::Attribute *pconn=NULL)
Update ghost nodal or elemental values for the given attribute.
Definition: Rocmap.C:87
j indices j
Definition: Indexing.h:6
#define MOP_BEGIN_NAMESPACE
Definition: mopbasic.h:28
void int * nj
Definition: read.cpp:74
Utility for detecting boundaries of a pane.