FEI Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SNL_FEI_Structure.cpp
Go to the documentation of this file.
1 /*--------------------------------------------------------------------*/
2 /* Copyright 2005 Sandia Corporation. */
3 /* Under the terms of Contract DE-AC04-94AL85000, there is a */
4 /* non-exclusive license for use of this work by or on behalf */
5 /* of the U.S. Government. Export of this program may require */
6 /* a license from the United States Government. */
7 /*--------------------------------------------------------------------*/
8 
9 #include "fei_sstream.hpp"
10 #include "fei_fstream.hpp"
11 
12 #include <limits>
13 #include <cmath>
14 #include <assert.h>
15 
16 #include "fei_defs.h"
17 
18 #include "fei_TemplateUtils.hpp"
19 #include <fei_CommUtils.hpp>
20 #include "snl_fei_Constraint.hpp"
22 
23 #include "fei_NodeDescriptor.hpp"
24 #include "fei_NodeCommMgr.hpp"
25 #include "fei_NodeDatabase.hpp"
26 
27 #include "fei_SlaveVariable.hpp"
28 
29 #include "fei_BlockDescriptor.hpp"
30 
32 #include "fei_ProcEqns.hpp"
33 #include "fei_EqnBuffer.hpp"
34 #include <fei_FillableMat.hpp>
35 #include <fei_CSRMat.hpp>
36 #include <fei_CSVec.hpp>
37 #include "fei_EqnCommMgr.hpp"
38 
39 #include "fei_Lookup.hpp"
41 #include "snl_fei_Utils.hpp"
42 #include "SNL_FEI_Structure.hpp"
43 
44 #undef fei_file
45 #define fei_file "SNL_FEI_Structure.cpp"
46 #include "fei_ErrMacros.hpp"
47 
48 //-----Constructor-------------------------------------------------------------
50  : comm_(comm),
51  localProc_(0),
52  masterProc_(0),
53  numProcs_(1),
54  fieldIDs_(),
55  fieldSizes_(),
56  fieldDatabase_(new std::map<int,int>),
57  fieldDofMap_(),
58  workarray_(),
59  blockIDs_(),
60  blocks_(),
61  connTables_(),
62  nodeDatabase_(NULL),
63  activeNodesInitialized_(false),
64  globalNodeOffsets_(),
65  globalEqnOffsets_(),
66  globalBlkEqnOffsets_(),
67  slaveVars_(NULL),
68  slaveEqns_(NULL),
69  slvEqnNumbers_(NULL),
70  numSlvs_(0),
71  lowestSlv_(0),
72  highestSlv_(0),
73  slaveMatrix_(NULL),
74  globalNumNodesVanished_(),
75  localVanishedNodeNumbers_(),
76  nodeCommMgr_(NULL),
77  eqnCommMgr_(NULL),
78  slvCommMgr_(NULL),
79  numGlobalEqns_(0),
80  numLocalEqns_(0),
81  localStartRow_(0),
82  localEndRow_(0),
83  numLocalNodalEqns_(0),
84  numLocalElemDOF_(0),
85  numLocalMultCRs_(0),
86  reducedStartRow_(0),
87  reducedEndRow_(0),
88  numLocalReducedRows_(0),
89  Kid_(NULL),
90  Kdi_(NULL),
91  Kdd_(NULL),
92  tmpMat1_(),
93  tmpMat2_(),
94  reducedEqnCounter_(0),
95  reducedRHSCounter_(0),
96  rSlave_(),
97  cSlave_(),
98  work_nodePtrs_(),
99  structureFinalized_(false),
100  generateGraph_(true),
101  sysMatIndices_(NULL),
102  blockMatrix_(false),
103  numGlobalEqnBlks_(0),
104  numLocalEqnBlks_(0),
105  numLocalReducedEqnBlks_(0),
106  localBlkOffset_(0),
107  localReducedBlkOffset_(0),
108  globalMaxBlkSize_(0),
109  firstLocalNodeNumber_(-1),
110  numGlobalNodes_(0),
111  sysBlkMatIndices_(NULL),
112  matIndicesDestroyed_(false),
113  workSpace_(),
114  blkEqnMapper_(new snl_fei::PointBlockMap()),
115  multCRs_(),
116  penCRs_(),
117  checkSharedNodes_(false),
118  name_(),
119  outputLevel_(0),
120  debugOutput_(false),
121  dbgPath_(),
122  dbgOStreamPtr_(NULL),
123  setDbgOutCalled_(true)
124 {
125  numProcs_ = 1, localProc_ = 0, masterProc_ = 0;
126 
129  masterProc_ = 0;
130 
131  slaveVars_ = new std::vector<SlaveVariable*>;
132  slaveEqns_ = new EqnBuffer;
133 
134  nodeCommMgr_ = new NodeCommMgr(comm_, *this);
135 
138 
140 
141  Kid_ = new fei::FillableMat;
142  Kdi_ = new fei::FillableMat;
143  Kdd_ = new fei::FillableMat;
144 }
145 
146 //-----------------------------------------------------------------------------
147 int SNL_FEI_Structure::parameters(int numParams, const char*const* paramStrings)
148 {
149  const char* param = NULL;
150 
151  param = snl_fei::getParamValue("outputLevel",numParams,paramStrings);
152  if (param != NULL){
153  std::string str(param);
154  FEI_ISTRINGSTREAM isstr(str);
155  isstr >> outputLevel_;
156  }
157 
158  param = snl_fei::getParam("debugOutput",numParams,paramStrings);
159  if (param != NULL){
160  debugOutput_ = true;
161  }
162 
163  param = snl_fei::getParam("debugOutputOff",numParams,paramStrings);
164  if (param != NULL){
165  debugOutput_ = false;
166  }
167 
168  param = snl_fei::getParam("FEI_CHECK_SHARED_IDS", numParams,paramStrings);
169  if (param != NULL){
170  checkSharedNodes_ = true;
171  }
172 
173  param = snl_fei::getParamValue("sharedNodeOwnership",
174  numParams,paramStrings);
175  if (param != NULL){
176  if (!strcmp(param, "LowNumberedProc")) {
178  }
179  if (!strcmp(param, "ProcWithLocalElem")) {
181  }
182  if (!strcmp(param, "SierraSpecifies")) {
184  }
185  }
186 
187  return(0);
188 }
189 
190 //-----Destructor--------------------------------------------------------------
192 {
193  for(size_t j=0; j<slaveVars_->size(); j++) {
194  delete (*slaveVars_)[j];
195  }
196  delete slaveVars_;
197 
198  delete slaveEqns_;
199  delete slaveMatrix_;
200 
203 
204  delete nodeCommMgr_;
205  delete eqnCommMgr_;
206  delete blkEqnMapper_;
207 
209 
210  deleteMultCRs();
211 
212  int numPCRs = penCRs_.size();
213  if (numPCRs > 0) {
215  penCRs_.clear();
216  }
217 
218  delete nodeDatabase_;
219  delete fieldDatabase_;
220 
221  delete Kid_;
222  delete Kdi_;
223  delete Kdd_;
224 }
225 
226 //------------------------------------------------------------------------------
228  const char* path, const char* feiName)
229 {
230  dbgOStreamPtr_ = &ostr;
231  setDbgOutCalled_ = true;
232  if (path != NULL) {
233  dbgPath_ = path;
234  }
235  else {
236  dbgPath_ = ".";
237  }
238  if (feiName != NULL) {
239  name_ = feiName;
240  }
241 
242  debugOutput_ = true;
243  return(0);
244 }
245 
246 //------------------------------------------------------------------------------
248 {
249  for(size_t i=0; i<blockIDs_.size(); i++) delete blocks_[i];
250  blocks_.resize(0);
251 }
252 
253 //------------------------------------------------------------------------------
255 {
256  for(size_t i=0; i<blockIDs_.size(); i++) {
257  delete connTables_[i];
258  }
259  connTables_.resize(0);
260 }
261 
262 //------------------------------------------------------------------------------
264 {
265  if (matIndicesDestroyed_ == true) return;
266 
267  delete [] sysMatIndices_;
268  sysMatIndices_ = NULL;
269 
270  delete [] sysBlkMatIndices_;
271  sysBlkMatIndices_ = NULL;
272 
273  matIndicesDestroyed_ = true;
274 }
275 
276 //------------------------------------------------------------------------------
278 {
279  BlockDescriptor* block = NULL;
280  int err = getBlockDescriptor(blockID, block);
281  if (err) return(NULL);
282 
283  return(block->fieldsPerNodePtr());
284 }
285 
286 //------------------------------------------------------------------------------
288 {
289  BlockDescriptor* block = NULL;
290  int err = getBlockDescriptor(blockID, block);
291  if (err) return(NULL);
292 
293  return(block->fieldIDsTablePtr());
294 }
295 
296 //------------------------------------------------------------------------------
298  int& interleaveStrategy, int& lumpingStrategy,
299  int& numElemDOF, int& numElements,
300  int& numNodesPerElem, int& numEqnsPerElem)
301 {
302  BlockDescriptor* block = NULL;
303  int err = getBlockDescriptor(blockID, block);
304  if (err) {
305  interleaveStrategy = -1;
306  lumpingStrategy = -1;
307  numElemDOF = -1;
308  numElements = -1;
309  numNodesPerElem = -1;
310  numEqnsPerElem = -1;
311  }
312 
313  interleaveStrategy = block->getInterleaveStrategy();
314  lumpingStrategy = block->getLumpingStrategy();
315  numElemDOF = block->getNumElemDOFPerElement();
316  numElements = block->getNumElements();
317  numNodesPerElem = block->getNumNodesPerElement();
318  numEqnsPerElem = block->getNumEqnsPerElement();
319 }
320 
321 //------------------------------------------------------------------------------
322 int SNL_FEI_Structure::getEqnNumber(int nodeNumber, int fieldID)
323 {
324  //this function is only used by clients of the Lookup interface, who are
325  //expecting equations in the 'reduced' equation space.
326 
327  int eqnNumber;
328 
329  const NodeDescriptor* node = NULL;
330  CHK_ERR( nodeDatabase_->getNodeWithNumber(nodeNumber, node) );
331 
332  bool hasField = node->getFieldEqnNumber(fieldID, eqnNumber);
333  if (!hasField) {
334  fei::console_out() << "SNL_FEI_Structure::getEqnNumber: ERROR, node with nodeNumber "
335  << nodeNumber << " doesn't have fieldID " << fieldID << FEI_ENDL;
336  ERReturn(-1);
337  }
338 
339  int reducedEqn = -1;
340  bool isSlave = translateToReducedEqn(eqnNumber, reducedEqn);
341  if (isSlave) return(-1);
342 
343  return(reducedEqn);
344 }
345 
346 //------------------------------------------------------------------------------
348 {
349  if (eqn < 0) return(-1);
350 
351  int len = globalEqnOffsets_.size(); // len is numProcs+1...
352 
353  for(int i=0; i<len-1; i++) {
354  if (eqn >= globalEqnOffsets_[i] && eqn < globalEqnOffsets_[i+1]) return(i);
355  }
356 
357  return(-1);
358 }
359 
360 //------------------------------------------------------------------------------
361 int SNL_FEI_Structure::initFields(int numFields,
362  const int *fieldSizes,
363  const int *fieldIDs,
364  const int *fieldTypes)
365 {
366  // store the incoming solution fields
367  //
368  if (debugOutput_) {
369  FEI_OSTREAM& ostr = dbgOut();
370  ostr << "FEI: initFields" << FEI_ENDL
371  << "#num-fields" << FEI_ENDL << numFields << FEI_ENDL;
372  int nf;
373  ostr << "#field-sizes" << FEI_ENDL;
374  for(nf=0; nf<numFields; nf++) {
375  ostr <<fieldSizes[nf] << " ";
376  }
377  ostr << FEI_ENDL << "#field-ids" << FEI_ENDL;
378  for(nf=0; nf<numFields; nf++) {
379  ostr << fieldIDs[nf] << " ";
380  }
381  if (fieldTypes != NULL) {
382  ostr << FEI_ENDL << "#field-types" << FEI_ENDL;
383  for(nf=0; nf<numFields; nf++) {
384  ostr << fieldTypes[nf] << " ";
385  }
386  }
387  ostr<<FEI_ENDL;
388  }
389 
390  for (int i=0; i<numFields; i++) {
391  fieldDatabase_->insert(std::pair<int,int>(fieldIDs[i], fieldSizes[i]));
392  int offs = fei::sortedListInsert(fieldIDs[i], fieldIDs_);
393  if (offs >= 0) fieldSizes_.insert(fieldSizes_.begin()+offs, fieldSizes[i]);
394 
395  if (fieldIDs[i] >= 0) {
396  if (fieldTypes != NULL) {
397  fieldDofMap_.add_field(fieldIDs[i], fieldSizes[i], fieldTypes[i]);
398  }
399  else {
400  fieldDofMap_.add_field(fieldIDs[i], fieldSizes[i]);
401  }
402  }
403  }
404 
405  return(FEI_SUCCESS);
406 }
407 
408 //------------------------------------------------------------------------------
410  int numElements,
411  int numNodesPerElement,
412  const int* numFieldsPerNode,
413  const int* const* nodalFieldIDs,
414  int numElemDofFieldsPerElement,
415  const int* elemDofFieldIDs,
416  int interleaveStrategy)
417 {
418  int nn, nf;
419  if (debugOutput_) {
420  FEI_OSTREAM& os = dbgOut();
421  os << "FEI: initElemBlock" << FEI_ENDL << "#elemBlockID" << FEI_ENDL
422  << (int)elemBlockID << FEI_ENDL;
423  os << "#numElements"<< FEI_ENDL << numElements << FEI_ENDL;
424  os << "#numNodesPerElement"<< FEI_ENDL <<numNodesPerElement << FEI_ENDL;
425  os << "#numFieldsPerNode -- one entry per node " << FEI_ENDL;
426  for(nn=0; nn<numNodesPerElement; nn++) os << numFieldsPerNode[nn]<<" ";
427  os << FEI_ENDL << "#nodalFieldIDs -- one row per node" << FEI_ENDL;
428  for(nn=0; nn<numNodesPerElement; ++nn) {
429  for(nf=0; nf<numFieldsPerNode[nn]; ++nf) os << nodalFieldIDs[nn][nf] << " ";
430  os << FEI_ENDL;
431  }
432  os << "#numElemDofFieldsPerElement" << FEI_ENDL
433  << numElemDofFieldsPerElement<<FEI_ENDL;
434  os << "#elemDofFieldIDs -- 'numElemDofFieldsPerElement' entries" << FEI_ENDL;
435  for(nn=0; nn<numElemDofFieldsPerElement; ++nn) {
436  os << elemDofFieldIDs[nn] << " ";
437  }
438  if (numElemDofFieldsPerElement > 0) os << FEI_ENDL;
439  os << "#interleaveStrategy" << FEI_ENDL << interleaveStrategy << FEI_ENDL;
440  }
441  int j;
442 
443  CHK_ERR( addBlock(elemBlockID) );
444  BlockDescriptor* block = NULL;
445  CHK_ERR( getBlockDescriptor(elemBlockID, block) );
446 
447  CHK_ERR( block->setNumNodesPerElement(numNodesPerElement) );
448  block->setNumElements(numElements);
449  block->setElemDofFieldIDs(numElemDofFieldsPerElement, elemDofFieldIDs);
450  block->setInterleaveStrategy(interleaveStrategy);
451 
452  int *fieldsPerNodePtr = block->fieldsPerNodePtr();
453 
454 // construct the list of nodal solution cardinalities for this block
455 
456  int numNodalEqns = 0;
457  int countDOF;
458  std::vector<int> distinctFields(0);
459 
460  for(j=0; j<numNodesPerElement; j++) {
461 
462  countDOF = 0;
463  for(int k = 0; k < numFieldsPerNode[j]; k++) {
464  fei::sortedListInsert(nodalFieldIDs[j][k], distinctFields);
465 
466  int fieldSize = getFieldSize(nodalFieldIDs[j][k]);
467  if (fieldSize < 0) {
468  fei::console_out() << "SNL_FEI_Structure::initElemBlock ERROR: fieldID " <<
469  nodalFieldIDs[j][k] << " has negative size. " << FEI_ENDL;
470  ERReturn(-1);
471  }
472  countDOF += fieldSize;
473  }
474 
475  fieldsPerNodePtr[j] = numFieldsPerNode[j];
476  numNodalEqns += countDOF;
477  }
478 
479  block->setNumDistinctFields(distinctFields.size());
480 
481  int numElemDOFPerElement = 0;
482  for(j=0; j<numElemDofFieldsPerElement; j++) {
483  int fieldSize = getFieldSize(elemDofFieldIDs[j]);
484  if (fieldSize < 0) {
485  fei::console_out() << "SNL_FEI_Structure::initElemBlock ERROR: elemDoffieldID " <<
486  elemDofFieldIDs[j] << " has negative size. " << FEI_ENDL;
487  ERReturn(-1);
488  }
489  numElemDOFPerElement += fieldSize;
490  }
491 
492  block->setNumElemDOFPerElement(numElemDOFPerElement);
493  block->setNumEqnsPerElement(numNodalEqns + numElemDOFPerElement);
494  block->setNumBlkEqnsPerElement(numNodesPerElement + numElemDOFPerElement);
495 
496 // cache a copy of the element fields array for later use...
497 
498  CHK_ERR( block->allocateFieldIDsTable() );
499  int **fieldIDsTablePtr = block->fieldIDsTablePtr();
500 
501  for (j = 0; j < numNodesPerElement; j++) {
502  for(int k = 0; k < numFieldsPerNode[j]; k++) {
503  fieldIDsTablePtr[j][k] = nodalFieldIDs[j][k];
504  }
505  }
506 
507 // create data structures for storage of element ID and topology info
508 
509  if (numElements > 0) {
510  CHK_ERR( allocateBlockConnectivity(elemBlockID) );
511  }
512 
513  return(FEI_SUCCESS);
514 }
515 
516 //------------------------------------------------------------------------------
518  GlobalID elemID,
519  const GlobalID* elemConn)
520 {
521  if (debugOutput_ && outputLevel_ > 2) {
522  FEI_OSTREAM& os = dbgOut();
523  os << "FEI: initElem"<<FEI_ENDL;
524  os << "#blkID"<<FEI_ENDL<<(int)elemBlockID<<FEI_ENDL<<"#elmID"<<FEI_ENDL
525  <<(int)elemID<< FEI_ENDL;
526  }
527 
528  //first get the block-descriptor for this elemBlockID...
529 
530  BlockDescriptor* block = NULL;
531  CHK_ERR( getBlockDescriptor(elemBlockID, block) );
532 
533  ConnectivityTable& connTable = getBlockConnectivity(elemBlockID);
534 
535  std::map<GlobalID,int>& elemIDList = connTable.elemIDs;
536  GlobalID* conn = &((*connTable.elem_conn_ids)[0]);
537 
538  int elemIndex = elemIDList.size();
539  std::map<GlobalID,int>::iterator
540  iter = elemIDList.find(elemID);
541 
542  bool redundantElem = false;
543 
544  if (iter != elemIDList.end()) {
545  elemIndex = iter->second;
546  redundantElem = true;
547  }
548  else {
549  elemIDList.insert(std::make_pair(elemID,elemIndex));
550  }
551 
552  int numNodes = block->getNumNodesPerElement();
553 
554  if (debugOutput_ && outputLevel_ > 2) {
555  FEI_OSTREAM& os = dbgOut();
556  os << "#n-nodes"<<FEI_ENDL<<numNodes<<FEI_ENDL<<"#nodeIDs"<<FEI_ENDL;
557  for(int nn=0; nn<numNodes; nn++) os << (int)elemConn[nn] << " ";
558  os << FEI_ENDL;
559  }
560 
561  if (redundantElem) {
562  //redundantElem == true means this element has been initialized before.
563  //So we'll simply make sure the connectivity is the same as it was, and
564  //if it isn't return -1.
565 
566  int offset = elemIndex*numNodes;
567  for(int j=0; j<numNodes; j++) {
568  if ( conn[offset+j] != elemConn[j]) {
569  fei::console_out() << "SNL_FEI_Structure::initElem ERROR, elemID " << (int)elemID
570  << " registered more than once, with differing connectivity."
571  << FEI_ENDL;
572  return(-1);
573  }
574  }
575  }
576  else {
577  int offset = elemIndex*numNodes;
578  for(int j = 0; j < numNodes; j++) {
579  conn[offset+j] = elemConn[j];
580  }
581 
582  CHK_ERR( nodeDatabase_->initNodeIDs(&(conn[offset]), numNodes) );
583  }
584 
585  return(FEI_SUCCESS);
586 }
587 
588 //------------------------------------------------------------------------------
590  int slaveFieldID,
591  int offsetIntoSlaveField,
592  int numMasterNodes,
593  const GlobalID* masterNodeIDs,
594  const int* masterFieldIDs,
595  const double* weights,
596  double rhsValue)
597 {
598  if (debugOutput_) {
599  FEI_OSTREAM& os = dbgOut();
600  os << "FEI: initSlaveVariable" << FEI_ENDL;
601  os << "#slvNodeID" << FEI_ENDL << (int)slaveNodeID << FEI_ENDL
602  << "#slvFieldID"<< FEI_ENDL << slaveFieldID << FEI_ENDL
603  << "#offsetIntoSlvField" << FEI_ENDL << offsetIntoSlaveField << FEI_ENDL
604  << "#numMasterNodes" << FEI_ENDL << numMasterNodes << FEI_ENDL
605  << "#masterNodeIDs" << FEI_ENDL;
606  int nn;
607  for(nn=0; nn<numMasterNodes; ++nn) {
608  os <<(int)masterNodeIDs[nn]<<" ";
609  }
610  os << FEI_ENDL << "#masterFieldIDs" << FEI_ENDL;
611  for(nn=0; nn<numMasterNodes; ++nn) {
612  os <<masterFieldIDs[nn] << " ";
613  }
614  os << FEI_ENDL << "#field-sizes" << FEI_ENDL;
615  for(nn=0; nn<numMasterNodes; ++nn) {
616  int size = getFieldSize(masterFieldIDs[nn]);
617  os << size << " ";
618  }
619  os << FEI_ENDL << "#weights" << FEI_ENDL;
620  int offset = 0;
621  for(nn=0; nn<numMasterNodes; ++nn) {
622  int size = getFieldSize(masterFieldIDs[nn]);
623  for(int j=0; j<size; ++j) {
624  os << weights[offset++] << " ";
625  }
626  }
627  os << FEI_ENDL << "#rhsValue" << FEI_ENDL << rhsValue << FEI_ENDL;
628  }
629 
630  //Create and initialize a slave-variable object with the incoming data,
631  //and add it to our list.
632 
633  SlaveVariable* svar = new SlaveVariable;
634  svar->setNodeID(slaveNodeID);
635  svar->setFieldID(slaveFieldID);
636  svar->setFieldOffset(offsetIntoSlaveField);
637 
638  int woffset = 0;
639 
640  for(int i=0; i<numMasterNodes; i++) {
641  svar->addMasterNodeID(masterNodeIDs[i]);
642  svar->addMasterField(masterFieldIDs[i]);
643  int fieldSize = getFieldSize(masterFieldIDs[i]);
644  if (fieldSize < 0) ERReturn(-1);
645 
646  for(int j=0; j<fieldSize; j++) {
647  svar->addWeight(weights[woffset++]);
648  }
649  }
650 
651  addSlaveVariable(svar);
652 
653  return(FEI_SUCCESS);
654 }
655 
656 //------------------------------------------------------------------------------
658 {
659  int numMCRs = multCRs_.size();
660  if (numMCRs > 0) {
662  multCRs_.clear();
663  }
664  return(0);
665 }
666 
667 //------------------------------------------------------------------------------
668 int SNL_FEI_Structure::initSharedNodes(int numSharedNodes,
669  const GlobalID *sharedNodeIDs,
670  const int* numProcsPerNode,
671  const int *const *sharingProcIDs)
672 {
673  if (debugOutput_) {
674  FEI_OSTREAM& os = dbgOut();
675  os << "FEI: initSharedNodes"<<FEI_ENDL;
676  os << "#n-nodes"<<FEI_ENDL<<numSharedNodes<<FEI_ENDL;
677  os << "#num-procs-per-node"<<FEI_ENDL;
678  int nn;
679  for(nn=0; nn<numSharedNodes; ++nn) {
680  os << numProcsPerNode[nn] << " ";
681  }
682  os << FEI_ENDL << "#following lines: nodeID sharing-procs" << FEI_ENDL;
683  for(nn=0; nn<numSharedNodes; nn++) {
684  os << (int)sharedNodeIDs[nn]<<" ";
685  for(int np=0; np<numProcsPerNode[nn]; np++) os<<sharingProcIDs[nn][np]<<" ";
686  os << FEI_ENDL;
687  }
688  os << "#end shared nodes"<<FEI_ENDL;
689  }
690 
691  // In this function we simply accumulate the incoming data into the
692  // NodeCommMgr object.
693  //
694  CHK_ERR( nodeCommMgr_->addSharedNodes(sharedNodeIDs, numSharedNodes,
695  sharingProcIDs, numProcsPerNode) );
696 
698  //if active nodes have already been initialized, then we won't be
699  //re-running the element-connectivities during the next call to
700  //initComplete(), which means we won't have an opportunity to call the
701  //NodeCommMgr::informLocal() method for nodes that reside locally. So we
702  //need to check now for any locally residing shared nodes and make that
703  //call. This is expensive, but it's a case that only arises when constraints
704  //change between solves and nothing else changes. In general, constraints
705  //are the only structural features allowed to change without requiring a
706  //complete destruction and re-calculation of the FEI structure.
707  //
708  for(int i=0; i<numSharedNodes; ++i) {
709  for(size_t nc=0; nc<connTables_.size(); ++nc) {
710  if (connTables_[nc]->elem_conn_ids == NULL) continue;
711  int len = connTables_[nc]->elem_conn_ids->size();
712  if (len < 1) continue;
713  GlobalID* conn_ids = &((*connTables_[nc]->elem_conn_ids)[0]);
714  NodeDescriptor** nodes = &((*connTables_[nc]->elem_conn_ptrs)[0]);
715 
716  for(int j=0; j<len; ++j) {
717  if (conn_ids[j] == sharedNodeIDs[i]) {
718  CHK_ERR( nodeCommMgr_->informLocal(*(nodes[j])));
719  break;
720  }
721  }
722  }
723  }
724  }
725 
726  return(FEI_SUCCESS);
727 }
728 
729 //------------------------------------------------------------------------------
730 int SNL_FEI_Structure::initCRMult(int numCRNodes,
731  const GlobalID* CRNodes,
732  const int *CRFields,
733  int& CRID)
734 {
735  if (debugOutput_) {
736  FEI_OSTREAM& os = dbgOut();
737  os << "FEI: initCRMult" << FEI_ENDL << "# numCRNodes: "<<FEI_ENDL<<numCRNodes<<FEI_ENDL;
738  os << "#CRNodes:"<<FEI_ENDL;
739  int nn;
740  for(nn=0; nn<numCRNodes; nn++) {
741  os << (int)CRNodes[nn]<<" ";
742  }
743  os << FEI_ENDL<<"#fields:"<<FEI_ENDL;
744  for(nn=0; nn<numCRNodes; nn++) {
745  os << CRFields[nn]<<" ";
746  }
747  os<<FEI_ENDL;
748  }
749  // tasks: add local constraint equations, determine sparsity
750  // patterns for the new constraint relation
751  //
752 
753  CRID = localProc_*100000 + multCRs_.size();
754  ConstraintType* multCRPtr = NULL;
755  addCR(CRID, multCRPtr, multCRs_);
756 
757  ConstraintType& multCR = *multCRPtr;
758 
759  multCR.setConstraintID(CRID);
760 
761  std::vector<GlobalID>& CRNodeArray = multCR.getMasters();
762  std::vector<int>& CRFieldArray = multCR.getMasterFieldIDs();
763 
764  for(int j = 0; j < numCRNodes; j++) {
765  CRNodeArray.push_back(CRNodes[j]);
766  CRFieldArray.push_back(CRFields[j]);
767  }
768 
769  if (debugOutput_) dbgOut() << "#(output) CRID:"<<FEI_ENDL << CRID << FEI_ENDL;
770 
771  return(FEI_SUCCESS);
772 }
773 
774 //------------------------------------------------------------------------------
775 int SNL_FEI_Structure::initCRPen(int numCRNodes,
776  const GlobalID* CRNodes,
777  const int *CRFields,
778  int& CRID)
779 {
780  if (debugOutput_) {
781  FEI_OSTREAM& os = dbgOut();
782  os << "initCRPen, numCRNodes: "<<numCRNodes<<FEI_ENDL;
783  for(int nn=0; nn<numCRNodes; nn++) {
784  os << " crNodeID: "<<(int)CRNodes[nn]<<", field: "<<CRFields[nn]<<FEI_ENDL;
785  }
786  }
787 
788  CRID = localProc_*100000 + penCRs_.size();
789 
790  ConstraintType* penCRPtr = NULL;
791  addCR(CRID, penCRPtr, penCRs_);
792 
793  ConstraintType& penCR = *penCRPtr;
794 
795  penCR.setConstraintID(CRID);
796  penCR.setIsPenalty(true);
797 
798  std::vector<GlobalID>& CRNodesArray = penCR.getMasters();
799 
800  std::vector<int>& CRFieldArray = penCR.getMasterFieldIDs();
801 
802  for(int i = 0; i < numCRNodes; i++) {
803  CRNodesArray.push_back(CRNodes[i]);
804  CRFieldArray.push_back(CRFields[i]);
805  }
806 
807  return(FEI_SUCCESS);
808 }
809 
810 //------------------------------------------------------------------------------
812 {
813  //I'm going to make an assumption: if we're running in serial, then there
814  //are no remote anythings, and the node in question must be in a local
815  //element.
816  if (numProcs_ < 2) return(true);
817 
818  const NodeDescriptor* node = NULL;
819  int err = nodeDatabase_->getNodeWithNumber(nodeNumber, node);
820  if (err != 0) return(false);
821 
822  GlobalID nodeID = node->getGlobalNodeID();
823 
824  //now let's find out if this node is a shared node.
825  int shIndx = nodeCommMgr_->getSharedNodeIndex(nodeID);
826  if (shIndx < 0) {
827  //if shIndx < 0, then this isn't a shared node. For now, we will assume
828  //that it must be a local node.
829  return(true);
830  }
831 
832  //If we reach this line, then the node is a shared node. Let's now ask if
833  //it appears locally...
834  std::vector<GlobalID>& localNodes = nodeCommMgr_->getLocalNodeIDs();
835  int index = fei::binarySearch(nodeID, &localNodes[0], localNodes.size());
836  if (index >= 0) return(true);
837 
838  //If we reach this line, then the node is shared, but doesn't appear in the
839  //"localNodeIDs" held by NodeCommMgr. This means it is not in a local element,
840  //so we'll return false.
841  return(false);
842 }
843 
844 //------------------------------------------------------------------------------
845 int SNL_FEI_Structure::initComplete(bool generateGraph)
846 {
847  //This is the most significant function in SNL_FEI_Structure. This is where
848  //the underlying matrix structure is calculated from all the data that has
849  //been provided since construction. Calculating the equation space and
850  //forming the matrix structure is a multi-step process, which proceeds like
851  //this:
852  //
853  //1. finalizeActiveNodes()
854  // - makes sure that all shared nodes have been identified to the
855  // NodeDatabase, then has the NodeDatabase allocate its internal list of
856  // NodeDescriptor objects.
857  // - runs the element-connectivity tables and sets the nodal field and block
858  // info on the NodeDescriptors in the NodeDatabase. IMPORTANT: At this
859  // point, the nodeIDs in the connectivitiy tables are replaced with
860  // indices into the nodeDatabase to speed future lookups.
861  // - As the connectivity tables are being run, the NodeCommMgr is given the
862  // nodeID of each node that is connected to a local element, and the node's
863  // owner is set to the initial value of localProc_.
864  //1a. finalizeNodeCommMgr()
865  // - NodeCommMgr::initComplete is called, at which time the ownership of all
866  // shared nodes is determined.
867  //
868  //2. Next, all local nodal degrees of freedom can be counted. This, together
869  // with the number of lagrange multipliers and element-centered DOFs are used
870  // by the function calcGlobalEqnInfo(), which determines global equation
871  // counts and offsets.
872  //
873  //3. setNodalEqnInfo() runs all locally active nodes and for each one that's
874  // locally owned, sets global equation-numbers on it, as well as its
875  // numNodalDOF and block-entry equation-number.
876  //
877  //4. setElemDOFEqnInfo() and setMultCREqnInfo() associate global equation-
878  // numbers with each of the lagrange multipliers and element-dofs.
879  //
880  //5. NodeDatabase::synchronize() is called, which associates nodeNumbers with
881  // each node, and also in turn calls NodeCommMgr::exchangeEqnInfo() to obtain
882  // equation-numbers and field/block info for remotely-owned shared nodes.
883  //
884  //6. setNumNodesAndEqnsPerBlock() then runs the active nodes again and counts
885  // active nodes and equations per element-block. This couldn't be done before
886  // because NodeCommMgr::exchangeEqnInfo() may have found out about new blocks
887  // that are associated with shared nodes on other processors.
888  //
889  //7. calculateSlaveEqns() associates equation-numbers with slave-nodes and
890  // master-nodes that have been identified locally, then gathers slave
891  // equation info from all processors onto all other processors, so that all
892  // processors know about all slave equations.
893  //
894  //8. initializeEqnCommMgr() runs the shared-nodes from NodeCommMgr and lets
895  // EqnCommMgr know which equations will be sent to other processors, and
896  // which will be received from other processors.
897  //
898  //9. translate localStartRow_ and localEndRow_ into the reduced equation
899  // space, where they are called reducedStartRow_ and reducedEndRow_, after
900  // which we know how many local equations there are not including any
901  // slave equations. At this point we can allocate the sysMatIndices_ array
902  // of arrays, which will hold the point-entry matrix structure.
903  //
904  //10. formMatrixStructure()
905  // - initElemBlockStructure() for each element in each element-block,
906  // obtains scatter-indices and makes the corresponding structurally
907  // symmetric contributions to the matrix structure. This process includes
908  // calculations associated with reducing out slave equations, and with
909  // putting off-processor contributions (element contributions with shared
910  // nodes) into the EqnCommMgr object.
911  // - initMultCRStructure() and initPenCRStructure() follow the same general
912  // routine as for the initElemBlockStructure() function.
913  // - EqnCommMgr::exchangeIndices() is called, which sends all shared
914  // contributions to the processors that own the corresponding equations,
915  // after which the receiving processors insert those contributions into
916  // the local matrix structure.
917  //
918  //11. initializeBlkEqnMapper() run all nodes, elem-dof, multiplier constraints
919  // and pass global point-equation-numbers with corresponding block-equation
920  // numbers to the snl_fei::PointBlockMap object which maintains a mapping
921  // between the point-entry and block-entry equation spaces.
922  //
923  //12. EqnCommMgr::exchangePtToBlkInfo() ensures that the point-to-block
924  // mapping data is globally consistent across all processors.
925  //
926  //13. The sysBlkMatIndices_ array is allocated, which is the array of
927  // arrays that will hold the block-entry matrix structure. This block-entry
928  // matrix structure is not filled, however, until later if/when the
929  // method getMatrixStructure is called specifically requesting block-entry
930  // structure data.
931  //
932  //14. Finally, if the debugOutputLevel_ is greater than 0, a file is written
933  // which contains a mapping from equations to nodes. This file is often very
934  // useful for post-mortem debugging operations, and is also necessary if the
935  // matrix produced from a serial run is to be compared with a matrix
936  // produced from a similar run on multiple processors. The equation-to-node
937  // mapping is the only way to reconcile the equation-orderings between the
938  // two matrices.
939  //
940 
941  if (debugOutput_) {
942  FEI_OSTREAM& os = dbgOut();
943  os << "FEI: initComplete" << FEI_ENDL;
944  }
945  // marshall all of the nodes we received in element connectivities into an
946  // active node list, and set the fields, blocks and owning processors
947  // associated with those nodes.
948 
949  //IMPORTANT!!! Note that at this point, the nodeIDs in the
950  //connectivitiy tables are being replaced with indices from the nodeDatabase.
951 
953 
955 
958 
959  // ok, now the active equation calculations -- we need to count how many
960  // local equations there are, then obtain the global equation info, then
961  // set equation numbers on all of our active nodes.
962 
963  int numLocalNodes = nodeDatabase_->countLocalNodeDescriptors(localProc_);
965 
968 
969  if (debugOutput_) {
970  FEI_OSTREAM& os = dbgOut();
971  os << "# numMultCRs: " << numLocalMultCRs_ << ", numElemDOF: "
972  << numLocalElemDOF_ << ", numLocalNodalEqns: " <<numLocalNodalEqns_
973  << FEI_ENDL;
974  os << "# numLocalEqns_: " << numLocalEqns_ << FEI_ENDL;
975  }
976 
978 
980 
981  //now we need to set equation numbers for the element-DOF's, and for the
982  //lagrange-multipler constraints.
983  //(exactly where to put these element DOF is an interesting issue... here,
984  //just toss them at the end of the nodal active eqns, which may or may not
985  //be such a great choice.)
986 
988 
990 
991  //now have the NodeDatabase run through the list of active nodes and
992  //do whatever final initializations it needs to do. This function also
993  //calls nodeCommMgr::exchangeEqnInfo.
995  localProc_, comm_) );
996 
997  //now run the active nodes again and set the number of
998  //active nodes and equations per block. We couldn't do this
999  //before, because the nodeCommMgr::initComplete() and
1000  //nodeCommMgr::exchangeEqnInfo functions may both have found out about new
1001  //blocks that are associated with shared nodes.
1002 
1004 
1005  //at this point we'll run through any SlaveVariable records that were set,
1006  //and establish an EqnBuffer of slave equation numbers, and gather the slave
1007  //equations initialized on any other processors.
1008 
1009  slvCommMgr_ = new EqnCommMgr(comm_);
1010  slvCommMgr_->setNumRHSs(1);
1011 
1013 
1014  //From this point on, all computations involving equation numbers will assume
1015  //that those numbers are in the reduced equation space. So we'll start by
1016  //translating the contents of eqnCommMgr_ to the reduced space.
1017  //CHK_ERR( translateToReducedEqns(*eqnCommMgr_) );
1018 
1020 
1022  int startRow = localStartRow_;
1023  while(isSlaveEqn(startRow)) startRow++;
1026 
1027  generateGraph_ = generateGraph;
1028 
1029  if (generateGraph_) {
1031  }
1032 
1033  //Now we'll run through all the data structures that have been initialized
1034  //and form the matrix structure (lists of column-indices).
1035 
1037 
1039 
1040  if (globalMaxBlkSize_ > 1) {
1042  if (numSlvs_ > 0) {
1043  try {
1045  }
1046  catch (std::runtime_error& exc) {
1047  fei::console_out() << exc.what() << FEI_ENDL;
1048  ERReturn(-1);
1049  }
1050 
1052  }
1053  }
1054 
1055  localReducedBlkOffset_ = ptEqnToBlkEqn(reducedStartRow_);
1056  int lastLocalReducedBlkEqn = ptEqnToBlkEqn(reducedEndRow_);
1057  numLocalReducedEqnBlks_ = lastLocalReducedBlkEqn - localReducedBlkOffset_ + 1;
1058 
1059  if (globalMaxBlkSize_ > 1 && generateGraph_) {
1062  }
1063 
1064  delete slvCommMgr_;
1065 
1066  blockMatrix_ = true;
1067 
1068  structureFinalized_ = true;
1069  matIndicesDestroyed_ = false;
1070 
1071  //while we're here, let's write an equation -> nodeNumber map into a file
1072  //for possible debugging purposes... it will come in handy if we need to
1073  //compare matrices/vectors from different parallel runs.
1075 
1076  if (debugOutput_) dbgOut() << "#leaving initComplete" << FEI_ENDL;
1077  return(FEI_SUCCESS);
1078 }
1079 
1080 //------------------------------------------------------------------------------
1082 {
1083  FEI_OSTREAM& os = dbgOut();
1084  if (debugOutput_) os << "# formMatrixStructure" << FEI_ENDL;
1085 
1086  //do our local equation profile calculations (i.e., determine
1087  //how long each row is). use the element scatter arrays to determine
1088  //the sparsity pattern
1089 
1091 
1092  // next, handle the matrix structure imposed by the constraint relations...
1093  //
1094 
1096 
1097  // we also need to accomodate penalty constraints, so let's process them
1098  // now...
1099 
1101 
1102  //we've now processed all of the local data that produces matrix structure.
1103  //so now let's have the equation comm manager exchange indices with the
1104  //other processors so we can account for remote contributions to our
1105  //matrix structure.
1106  try {
1108  }
1109  catch(std::runtime_error& exc) {
1110  fei::console_out() << exc.what() << FEI_ENDL;
1111  ERReturn(-1);
1112  }
1113 
1114  //so now the remote contributions should be available, let's get them out
1115  //of the eqn comm mgr and put them into our local matrix structure.
1116 
1117  int numRecvEqns = eqnCommMgr_->getNumLocalEqns();
1118  std::vector<int>& recvEqnNumbers = eqnCommMgr_->localEqnNumbers();
1119  std::vector<fei::CSVec*>& recvEqns = eqnCommMgr_->localEqns();
1120  int i;
1121  if (debugOutput_) {
1122  os << "# after eqnCommMgr_->exchangeIndices, numRecvEqns: "
1123  << numRecvEqns << FEI_ENDL;
1124  }
1125 
1126  for(i=0; i<numRecvEqns; i++) {
1127  int eqn = recvEqnNumbers[i];
1128  if ((reducedStartRow_ > eqn) || (reducedEndRow_ < eqn)) {
1129  fei::console_out() << "SNL_FEI_Structure::initComplete: ERROR, recvEqn " << eqn
1130  << " out of range. (reducedStartRow_: " << reducedStartRow_
1131  << ", reducedEndRow_: " << reducedEndRow_ << ", localProc_: "
1132  << localProc_ << ")" << FEI_ENDL;
1133  return(-1);
1134  }
1135 
1136  for(size_t j=0; j<recvEqns[i]->size(); j++) {
1137  CHK_ERR( createMatrixPosition(eqn, recvEqns[i]->indices()[j],
1138  "frmMatStr") );
1139  }
1140  }
1141 
1142  if (debugOutput_) {
1143  os << "# leaving formMatrixStructure" << FEI_ENDL;
1144  }
1145 
1146  return(0);
1147 }
1148 
1149 //------------------------------------------------------------------------------
1151 {
1152  int numBlocks = getNumElemBlocks();
1153 
1154  FEI_OSTREAM& os = dbgOut();
1155  if (debugOutput_) {
1156  os << "# initElemBlockStructure" << FEI_ENDL;
1157  os << "# numElemBlocks: " << numBlocks << FEI_ENDL;
1158  }
1159 
1160  for (int bIndex = 0; bIndex < numBlocks; bIndex++) {
1161  BlockDescriptor* block = NULL;
1162  CHK_ERR( getBlockDescriptor_index(bIndex, block) );
1163 
1164  int numEqns = block->getNumEqnsPerElement();
1165  int interleave = block->getInterleaveStrategy();
1166  std::vector<int> scatterIndices(numEqns);
1167 
1168  GlobalID elemBlockID = block->getGlobalBlockID();
1169  ConnectivityTable& connTable = getBlockConnectivity(elemBlockID);
1170 
1171  std::map<GlobalID,int>& elemIDList = connTable.elemIDs;
1172  block->setNumElements(elemIDList.size());
1173  int numBlockElems = block->getNumElements();
1174 
1175  //loop over all the elements, determining the elemental (both from nodes
1176  //and from element DOF) contributions to the sparse matrix structure
1177  if (debugOutput_) {
1178  os << "# block " << bIndex << ", numElems: " << numBlockElems<<FEI_ENDL;
1179  }
1180  for(int elemIndex = 0; elemIndex < numBlockElems; elemIndex++) {
1181 
1182  getScatterIndices_index(bIndex, elemIndex, interleave,
1183  &scatterIndices[0]);
1184 
1185  //now, store the structure that will arise from this contribution,
1186  //after first performing any manipulations associated with slave
1187  //reduction.
1188 
1189  CHK_ERR( createSymmEqnStructure(scatterIndices) );
1190  }
1191  }
1192 
1194 
1195  if (debugOutput_) os << "# leaving initElemBlockStructure" << FEI_ENDL;
1196  return(FEI_SUCCESS);
1197 }
1198 
1199 //------------------------------------------------------------------------------
1200 int SNL_FEI_Structure::getMatrixRowLengths(std::vector<int>& rowLengths)
1201 {
1202  if (!structureFinalized_) return(-1);
1203 
1204  rowLengths.resize(numLocalReducedRows_);
1205 
1206  for(int i=0; i<numLocalReducedRows_; i++) {
1207  rowLengths[i] = sysMatIndices_[i].size();
1208  }
1209  return(0);
1210 }
1211 
1212 //------------------------------------------------------------------------------
1214  std::vector<int>& rowLengths)
1215 {
1216  if (!structureFinalized_) return(-1);
1217 
1218  rowLengths.resize(numLocalReducedRows_);
1219 
1220  for(int i=0; i<numLocalReducedRows_; i++) {
1221  rowLengths[i] = sysMatIndices_[i].size();
1222  fei::copySetToArray(sysMatIndices_[i], rowLengths[i], indices[i]);
1223  }
1224 
1225  return(0);
1226 }
1227 
1228 //------------------------------------------------------------------------------
1230  std::vector<int>& ptRowLengths,
1231  int** blkColIndices,
1232  int* blkIndices_1D,
1233  std::vector<int>& blkRowLengths,
1234  std::vector<int>& numPtRowsPerBlkRow)
1235 {
1236  int err = getMatrixStructure(ptColIndices, ptRowLengths);
1237  if (err != 0) return(-1);
1238 
1239  if (globalMaxBlkSize_ == 1) {
1240  //No block-equations have more than one point-equation, so we'll just assign
1241  //the block-structure arrays to be the same as the point-structure arrays.
1242  int numRows = ptRowLengths.size();
1243  blkRowLengths.resize(numRows);
1244  numPtRowsPerBlkRow.assign(numRows, 1);
1245 
1246  blkRowLengths.resize(ptRowLengths.size());
1247  for(size_t ii=0; ii<ptRowLengths.size(); ++ii) {
1248  blkRowLengths[ii] = ptRowLengths[ii];
1249  }
1250 
1251  for(int i=0; i<numRows; i++) {
1252  blkColIndices[i] = ptColIndices[i];
1253  }
1254  }
1255  else {
1256  //There are block-equations with more than 1 point-equation, so let's
1257  //calculate the actual block-structure.
1258 
1259  std::map<int,int>* ptEqns = blkEqnMapper_->getPtEqns();
1260  int numPtEqns = ptEqns->size();
1261 
1262  std::map<int,int>::const_iterator
1263  pteq = ptEqns->begin(),
1264  pteq_end = ptEqns->end();
1265 
1266  int lastBlkRow = -1;
1267 
1268  for(int jj=0; jj<numPtEqns; ++jj, ++pteq) {
1269  int ptEqn = (*pteq).first;
1270  int localPtEqn = ptEqn - reducedStartRow_;
1271  if (localPtEqn < 0 || localPtEqn >= numLocalReducedRows_) continue;
1272 
1273  int rowLength = sysMatIndices_[localPtEqn].size();
1274 
1275  int blkRow = blkEqnMapper_->eqnToBlkEqn(ptEqn);
1276  if (blkRow < 0) {
1277  ERReturn(-1);
1278  }
1279 
1280  if (blkRow == lastBlkRow) continue;
1281 
1282  int localBlkRow = blkRow - localReducedBlkOffset_;
1283  if (localBlkRow < 0 || localBlkRow >= numLocalReducedEqnBlks_) {
1284  ERReturn(-1);
1285  }
1286 
1287  fei::ctg_set<int>& sysBlkIndices = sysBlkMatIndices_[localBlkRow];
1288 
1289  int* theseColIndices = ptColIndices[localPtEqn];
1290 
1291  for(int colj=0; colj<rowLength; colj++) {
1292  int blkCol = blkEqnMapper_->eqnToBlkEqn(theseColIndices[colj]);
1293  if (blkCol < 0) {
1295  <<"SNL_FEI_Structure::getMatrixStructure ERROR pt row "
1296  << ptEqn << ", pt col "
1297  << ptColIndices[localPtEqn][colj]
1298  << " doesn't have a corresponding block" << FEI_ENDL;
1299  blkCol = blkEqnMapper_->eqnToBlkEqn(theseColIndices[colj]);
1300  std::abort();
1301  }
1302 
1303  sysBlkIndices.insert2(blkCol);
1304  }
1305 
1306  lastBlkRow = blkRow;
1307  }
1308 
1309  //now we're ready to set the block-sizes...
1310 
1311  numPtRowsPerBlkRow.resize(numLocalReducedEqnBlks_);
1312  blkRowLengths.resize(numLocalReducedEqnBlks_);
1313  int offset = 0;
1314  for(int i=0; i<numLocalReducedEqnBlks_; i++) {
1315  blkRowLengths[i] = sysBlkMatIndices_[i].size();
1316  fei::copySetToArray(sysBlkMatIndices_[i],blkRowLengths[i],
1317  &(blkIndices_1D[offset]));
1318  offset += blkRowLengths[i];
1319 
1320  int blkEqn = localReducedBlkOffset_ + i;
1321  numPtRowsPerBlkRow[i] = blkEqnMapper_->getBlkEqnSize(blkEqn);
1322  }
1323  }
1324 
1325  return(0);
1326 }
1327 
1328 //------------------------------------------------------------------------------
1330  std::vector<int>& slaveEqns)
1331 {
1332  int numFields = node->getNumFields();
1333  const int* fieldIDs = node->getFieldIDList();
1334  const int* fieldEqns= node->getFieldEqnNumbers();
1335 
1336  for(int i=0; i<numFields; ++i) {
1337  int fieldSize = getFieldSize(fieldIDs[i]);
1338  for(int eqn=0; eqn<fieldSize; ++eqn) {
1339  int thisEqn = fieldEqns[i] + eqn;
1340  if (fei::binarySearch(thisEqn, slaveEqns) < 0) {
1341  //found a nodal eqn that's not a slave eqn, so return false.
1342  return(false);
1343  }
1344  }
1345  }
1346 
1347  return(true);
1348 }
1349 
1350 //------------------------------------------------------------------------------
1352 {
1353 //
1354 //This function returns a NodeDescriptor reference if nodeID is an active node.
1355 //
1356  NodeDescriptor* node = NULL;
1357  int err = nodeDatabase_->getNodeWithID(nodeID, node);
1358 
1359  if (err != 0) {
1360  fei::console_out() << "ERROR, findNodeDescriptor unable to find node " << (int)nodeID
1361  << FEI_ENDL;
1362  std::abort();
1363  }
1364 
1365  return( *node );
1366 }
1367 
1368 //------------------------------------------------------------------------------
1370 {
1371  NodeDescriptor* node = NULL;
1372  nodeDatabase_->getNodeWithID(nodeID, node);
1373  return node;
1374 }
1375 
1376 //------------------------------------------------------------------------------
1378 {
1379  FEI_OSTREAM& os = dbgOut();
1380  if (debugOutput_) os << "# initMultCRStructure" << FEI_ENDL;
1381  //
1382  //Private SNL_FEI_Structure function, to be called from initComplete.
1383  //
1384  //Records the system matrix structure arising from Lagrange Multiplier
1385  //Constraint Relations.
1386  //
1387  // since at initialization all we are being passed is the
1388  // general form of the constraint equations, we can't check to see if any
1389  // of the weight terms are zeros at this stage of the game. Hence, we
1390  // have to reserve space for all the nodal weight vectors, even though
1391  // they might turn out to be zeros during the load step....
1392 
1393  std::map<GlobalID,ConstraintType*>::const_iterator
1394  cr_iter = multCRs_.begin(),
1395  cr_end = multCRs_.end();
1396 
1397  while(cr_iter != cr_end) {
1398  ConstraintType& multCR = *((*cr_iter).second);
1399 
1400  int lenList = multCR.getMasters().size();
1401 
1402  std::vector<GlobalID>& CRNode_vec = multCR.getMasters();
1403  GlobalID *CRNodePtr = &CRNode_vec[0];
1404  std::vector<int>& CRField_vec = multCR.getMasterFieldIDs();
1405  int* CRFieldPtr = &CRField_vec[0];
1406 
1407  int crEqn = multCR.getEqnNumber();
1408  int reducedCrEqn = 0;
1409  translateToReducedEqn(crEqn, reducedCrEqn);
1410 
1411  createMatrixPosition(reducedCrEqn, reducedCrEqn, "initMCRStr");
1412 
1413  for(int j=0; j<lenList; j++) {
1414  GlobalID nodeID = CRNodePtr[j];
1415  int fieldID = CRFieldPtr[j];
1416 
1417  NodeDescriptor *nodePtr = findNode(nodeID);
1418  if(nodePtr==NULL) continue;
1419  NodeDescriptor& node = *nodePtr;
1420 
1421  //first, store the column indices associated with this node, in
1422  //the constraint's equation. i.e., position (crEqn, node)
1423 
1424  storeNodalColumnIndices(crEqn, node, fieldID);
1425 
1426  //now we need to store the transpose of the above contribution,
1427  //i.e., position(s) (node, crEqn)
1428 
1429  if (node.getOwnerProc() == localProc_) {
1430  //if we own this node, we will simply store its equation
1431  //numbers in local rows (equations) of the matrix.
1432 
1433  storeNodalRowIndices(node, fieldID, crEqn);
1434  }
1435  else {
1436  //if we don't own it, then we need to register with the
1437  //eqn comm mgr that we'll be sending contributions to
1438  //column crEqn of the remote equations associated with this
1439  //node.
1440 
1441  storeNodalSendIndex(node, fieldID, crEqn);
1442  }
1443  }
1444  ++cr_iter;
1445  }
1446  return(FEI_SUCCESS);
1447 }
1448 
1449 //------------------------------------------------------------------------------
1451 {
1452  FEI_OSTREAM& os = dbgOut();
1453  if (debugOutput_) os << "# initPenCRStructure" << FEI_ENDL;
1454 //
1455 //This function oversees the putting in of any matrix structure that results
1456 //from Penalty constraint relations.
1457 //
1458 // note that penalty constraints don't generate new equations
1459 // (unlike Lagrange constraints), but they do add terms to the system
1460 // stiffness matrix that couple all the nodes that contribute to the
1461 // penalty constraint. In addition, each submatrix is defined by the pair
1462 // of nodes that creates its contribution, hence a submatrix can be defined
1463 // in terms of two weight vectors (of length p and q) instead of the
1464 // generally larger product matrix (of size pq)
1465 
1466 // the additional terms take the form of little submatrices that look a lot
1467 // like an element stiffness and load matrix, where the nodes in the
1468 // constraint list take on the role of the nodes associated with an
1469 // element, and the individual matrix terms arise from the outer products
1470 // of the constraint nodal weight vectors
1471 
1472 // rather than get elegant and treat this task as such an elemental energy
1473 // term, we'll use some brute force to construct these penalty contributions
1474 // on the fly, primarily to simplify -reading- this thing, so that the
1475 // derivations in the annotated implementation document are more readily
1476 // followed...
1477  std::map<GlobalID,ConstraintType*>::const_iterator
1478  cr_iter = penCRs_.begin(),
1479  cr_end = penCRs_.end();
1480 
1481  while(cr_iter != cr_end) {
1482  ConstraintType& penCR = *((*cr_iter).second);
1483 
1484  int lenList = penCR.getMasters().size();
1485  std::vector<GlobalID>& CRNode_vec = penCR.getMasters();
1486  GlobalID* CRNodesPtr = &CRNode_vec[0];
1487 
1488  std::vector<int>& CRField_vec = penCR.getMasterFieldIDs();
1489  int* CRFieldPtr = &CRField_vec[0];
1490 
1491  // each constraint equation generates a set of nodal energy terms, so
1492  // we have to process a matrix of nodes for each constraint
1493 
1494  for(int i = 0; i < lenList; i++) {
1495  GlobalID iNodeID = CRNodesPtr[i];
1496  int iField = CRFieldPtr[i];
1497 
1498  NodeDescriptor* iNodePtr = findNode(iNodeID);
1499  if(!iNodePtr) continue;
1500  NodeDescriptor& iNode = *iNodePtr;
1501 
1502  for(int j = 0; j < lenList; j++) {
1503  GlobalID jNodeID = CRNodesPtr[j];
1504  int jField = CRFieldPtr[j];
1505 
1506  NodeDescriptor* jNodePtr = findNode(jNodeID);
1507  if(!jNodePtr) continue;
1508  NodeDescriptor &jNode = *jNodePtr;
1509 
1510  if (iNode.getOwnerProc() == localProc_) {
1511  //if iNode is local, we'll put equations into the local
1512  //matrix structure.
1513 
1514  storeLocalNodeIndices(iNode, iField, jNode, jField);
1515  }
1516  else {
1517  //if iNode is remotely owned, we'll be registering equations
1518  //to send to its owning processor.
1519 
1520  storeNodalSendIndices(iNode, iField, jNode, jField);
1521  }
1522  }
1523  } // end i loop
1524  ++cr_iter;
1525  } // end while loop
1526  return(FEI_SUCCESS);
1527 }
1528 
1529 //------------------------------------------------------------------------------
1531  int col)
1532 {
1533  //
1534  //This is a private SNL_FEI_Structure function. We can safely assume that it
1535  //will only be called with a node that is not locally owned.
1536  //
1537  //This function tells the eqn comm mgr that we'll be sending contributions
1538  //to column 'col' for the equations associated with 'fieldID', on 'node', on
1539  //node's owning processor.
1540  //
1541  int proc = node.getOwnerProc();
1542 
1543  int eqnNumber = -1;
1544  if (!node.getFieldEqnNumber(fieldID, eqnNumber)) voidERReturn;
1545 
1546  int numEqns = getFieldSize(fieldID);
1547  if (numEqns < 1) {
1548  fei::console_out() << "FEI error, attempt to store indices for field ("<<fieldID
1549  <<") with size "<<numEqns<<FEI_ENDL;
1550  voidERReturn;
1551  }
1552 
1553  for(int i=0; i<numEqns; i++) {
1554  eqnCommMgr_->addRemoteIndices(eqnNumber+i, proc, &col, 1);
1555  }
1556 }
1557 
1558 //------------------------------------------------------------------------------
1560  NodeDescriptor& jNode, int jField){
1561 //
1562 //This function will register with the eqn comm mgr the equations associated
1563 //with iNode, field 'iField' having column indices that are the equations
1564 //associated with jNode, field 'jField', to be sent to the owner of iNode.
1565 //
1566  int proc = iNode.getOwnerProc();
1567 
1568  int iEqn = -1, jEqn = -1;
1569  if (!iNode.getFieldEqnNumber(iField, iEqn)) return; //voidERReturn;
1570  if (!jNode.getFieldEqnNumber(jField, jEqn)) return; //voidERReturn;
1571 
1572  int iNumParams = getFieldSize(iField);
1573  int jNumParams = getFieldSize(jField);
1574  if (iNumParams < 1 || jNumParams < 1) {
1575  fei::console_out() << "FEI ERROR, attempt to store indices for field with non-positive size"
1576  << " field "<<iField<<", size "<<iNumParams<<", field "<<jField<<", size "
1577  << jNumParams<<FEI_ENDL;
1578  voidERReturn;
1579  }
1580 
1581  for(int i=0; i<iNumParams; i++) {
1582  int eqn = iEqn + i;
1583 
1584  for(int j=0; j<jNumParams; j++) {
1585  int col = jEqn + j;
1586  eqnCommMgr_->addRemoteIndices(eqn, proc, &col, 1);
1587  }
1588  }
1589 }
1590 
1591 //------------------------------------------------------------------------------
1593  NodeDescriptor& jNode, int jField)
1594 {
1595 //
1596 //This function will add to the local matrix structure the equations associated
1597 //with iNode at iField, having column indices that are the equations associated
1598 //with jNode at jField.
1599 //
1600  int iEqn = -1, jEqn = -1;
1601  if (!iNode.getFieldEqnNumber(iField, iEqn)) return; //voidERReturn;
1602  if (!jNode.getFieldEqnNumber(jField, jEqn)) return; //voidERReturn;
1603 
1604  int iNumParams = getFieldSize(iField);
1605  int jNumParams = getFieldSize(jField);
1606  if (iNumParams < 1 || jNumParams < 1) {
1607  fei::console_out() << "FEI ERROR, attempt to store indices for field with non-positive size"
1608  << " field "<<iField<<", size "<<iNumParams<<", field "<<jField<<", size "
1609  << jNumParams<<FEI_ENDL;
1610  voidERReturn;
1611  }
1612 
1613  for(int i=0; i<iNumParams; i++) {
1614  int row = iEqn + i;
1615  int reducedRow = -1;
1616  bool isSlave = translateToReducedEqn(row, reducedRow);
1617  if (isSlave) continue;
1618 
1619  for(int j=0; j<jNumParams; j++) {
1620  int col = jEqn + j;
1621  int reducedCol = -1;
1622  isSlave = translateToReducedEqn(col, reducedCol);
1623  if (isSlave) continue;
1624 
1625  createMatrixPosition(reducedRow, reducedCol,
1626  "storeLocNdInd");
1627  }
1628  }
1629 }
1630 
1631 //------------------------------------------------------------------------------
1633  int fieldID)
1634 {
1635  //
1636  //This function stores the equation numbers associated with 'node' at
1637  //'fieldID' as column indices in row 'eqn' of the system matrix structure.
1638  //
1639  if ((localStartRow_ > eqn) || (eqn > localEndRow_)) {
1640  return;
1641  }
1642 
1643  int colNumber = -1;
1644  if (!node.getFieldEqnNumber(fieldID, colNumber)) voidERReturn;
1645 
1646  int numParams = getFieldSize(fieldID);
1647  if (numParams < 1) {
1648  fei::console_out() << "FEI error, attempt to store indices for field ("<<fieldID
1649  <<") with size "<<numParams<<FEI_ENDL;
1650  voidERReturn;
1651  }
1652 
1653  int reducedEqn = -1;
1654  bool isSlave = translateToReducedEqn(eqn, reducedEqn);
1655  if (isSlave) return;
1656 
1657  for(int j=0; j<numParams; j++) {
1658  int reducedCol = -1;
1659  isSlave = translateToReducedEqn(colNumber+j, reducedCol);
1660  if (isSlave) continue;
1661 
1662  createMatrixPosition(reducedEqn, reducedCol,
1663  "storeNdColInd");
1664  }
1665 }
1666 
1667 //------------------------------------------------------------------------------
1669  int fieldID, int eqn)
1670 {
1671  //
1672  //This function stores column 'eqn' in equation numbers associated with
1673  //'node' at 'fieldID' in the system matrix structure.
1674  //
1675  int eqnNumber = -1;
1676  if (!node.getFieldEqnNumber(fieldID, eqnNumber)) voidERReturn;
1677 
1678  int numParams = getFieldSize(fieldID);
1679  if (numParams < 1) {
1680  fei::console_out() << "FEI error, attempt to store indices for field ("<<fieldID
1681  <<") with size "<<numParams<<FEI_ENDL;
1682  voidERReturn;
1683  }
1684 
1685  int reducedEqn = -1;
1686  bool isSlave = translateToReducedEqn(eqn, reducedEqn);
1687  if (isSlave) return;
1688 
1689  for(int j=0; j<numParams; j++) {
1690  int reducedRow = -1;
1691  isSlave = translateToReducedEqn(eqnNumber+j, reducedRow);
1692  if (isSlave) continue;
1693 
1694  createMatrixPosition(reducedRow, reducedEqn, "storeNdRowInd");
1695  }
1696 }
1697 
1698 //------------------------------------------------------------------------------
1699 int SNL_FEI_Structure::createSymmEqnStructure(std::vector<int>& scatterIndices)
1700 {
1701  //scatterIndices are both the rows and the columns for a structurally
1702  //symmetric 2-dimensional contribution to the matrix.
1703  //
1704 
1705  //if there aren't any slaves in the whole problem, store the scatter-indices
1706  //using a fast function (no translations-to-reduced-space) and return.
1707  if (numSlaveEquations() == 0) {
1708  CHK_ERR( storeElementScatterIndices_noSlaves(scatterIndices) );
1709  return(FEI_SUCCESS);
1710  }
1711 
1712  try {
1713 
1714  int len = scatterIndices.size();
1715  bool anySlaves = false;
1716  rSlave_.resize(len);
1717  for(int is=0; is<len; is++) {
1718  rSlave_[is] = isSlaveEqn(scatterIndices[is]) ? 1 : 0;
1719  if (rSlave_[is] == 1) anySlaves = true;
1720  }
1721 
1722  //if there aren't any slaves in this contribution, then just store it
1723  //and return
1724  if (!anySlaves) {
1725  CHK_ERR( storeElementScatterIndices(scatterIndices) );
1726  return(FEI_SUCCESS);
1727  }
1728 
1729  int* scatterPtr = &scatterIndices[0];
1730 
1731  workSpace_.resize(len);
1732  for(int j=0; j<len; j++) {
1733  translateToReducedEqn(scatterPtr[j], workSpace_[j]);
1734  }
1735 
1736  for(int i=0; i<len; i++) {
1737  int row = scatterPtr[i];
1738  if (rSlave_[i] == 1) {
1740  //
1741  //'row' is a slave equation, so add this row to Kdi_. But as we do that,
1742  //watch for columns that are slave equations and add them to Kid_.
1743  //
1744  for(int jj=0; jj<len; jj++) {
1745  int col = scatterPtr[jj];
1746 
1747  if (rSlave_[jj] == 1) {
1748  //'col' is a slave equation, so add this column to Kid_.
1749  for(int ii=0; ii<len; ii++) {
1750  int rowi = scatterPtr[ii];
1751 
1752  //only add the non-slave rows for this column.
1753  if (rSlave_[ii] == 1) continue;
1754 
1755  Kid_->createPosition(rowi, col);
1756  }
1757  //now skip to the next column
1758  continue;
1759  }
1760 
1761  Kdi_->createPosition(row, col);
1762  }
1763 
1764  //finally, add all slave columns in this slave row to Kdd_.
1765  for(int kk=0; kk<len; kk++) {
1766  int colk = scatterPtr[kk];
1767 
1768  if (rSlave_[kk] != 1) continue;
1769 
1770  Kdd_->createPosition(row, colk);
1771  }
1772  }
1773  else {
1774  //this is not a slave row, so we will loop across it, creating matrix
1775  //positions for all non-slave columns in it.
1776  int reducedRow = -1;
1777  translateToReducedEqn(row, reducedRow);
1778 
1779  bool rowIsLocal = true;
1780  int owner = localProc_;
1781  if (reducedStartRow_ > reducedRow || reducedEndRow_ < reducedRow) {
1782  rowIsLocal = false;
1783  owner = getOwnerProcForEqn(row);
1784  }
1785 
1786  for(int j=0; j<len; j++) {
1787  if (rSlave_[j] == 1) continue;
1788 
1789  int reducedCol = workSpace_[j];
1790 
1791  if (rowIsLocal) {
1792  CHK_ERR( createMatrixPosition(reducedRow, reducedCol,
1793  "crtSymmEqnStr") );
1794  }
1795  else {
1796  eqnCommMgr_->addRemoteIndices(reducedRow, owner, &reducedCol, 1);
1797  }
1798  }
1799  }
1800  }
1801 
1803 
1804  }
1805  catch(std::runtime_error& exc) {
1806  fei::console_out() << exc.what() << FEI_ENDL;
1807  ERReturn(-1);
1808  }
1809 
1810  return(FEI_SUCCESS);
1811 }
1812 
1813 //------------------------------------------------------------------------------
1814 int SNL_FEI_Structure::createBlkSymmEqnStructure(std::vector<int>& scatterIndices)
1815 {
1816  //scatterIndices are both the rows and the columns for a structurally
1817  //symmetric 2-dimensional contribution to the matrix.
1818  //
1819 
1820  //if there aren't any slaves in the whole problem, store the scatter-indices
1821  //using a fast function (no translations-to-reduced-space) and return.
1822  if (numSlaveEquations() == 0) {
1823  return( storeElementScatterBlkIndices_noSlaves(scatterIndices) );
1824  }
1825 
1826  try {
1827 
1828  int len = scatterIndices.size();
1829  bool anySlaves = false;
1830  rSlave_.resize(len);
1831  for(int is=0; is<len; is++) {
1832  rSlave_[is] = isSlaveEqn(scatterIndices[is]) ? 1 : 0;
1833  if (rSlave_[is] == 1) anySlaves = true;
1834  }
1835 
1836  //if there aren't any slaves in this contribution, then just store it
1837  //and return
1838  if (!anySlaves) {
1839  CHK_ERR( storeElementScatterIndices(scatterIndices) );
1840  return(FEI_SUCCESS);
1841  }
1842 
1843  int* scatterPtr = &scatterIndices[0];
1844 
1845  workSpace_.resize(len);
1846  for(int j=0; j<len; j++) {
1847  translateToReducedEqn(scatterPtr[j], workSpace_[j]);
1848  }
1849 
1850  for(int i=0; i<len; i++) {
1851  int row = scatterPtr[i];
1852  if (rSlave_[i] == 1) {
1854  //
1855  //'row' is a slave equation, so add this row to Kdi_. But as we do that,
1856  //watch for columns that are slave equations and add them to Kid_.
1857  //
1858  for(int jj=0; jj<len; jj++) {
1859  int col = scatterPtr[jj];
1860 
1861  if (rSlave_[jj] == 1) {
1862  //'col' is a slave equation, so add this column to Kid_.
1863  for(int ii=0; ii<len; ii++) {
1864  int rowi = scatterPtr[ii];
1865 
1866  //only add the non-slave rows for this column.
1867  if (rSlave_[ii] == 1) continue;
1868 
1869  Kid_->createPosition(rowi, col);
1870  }
1871  //now skip to the next column
1872  continue;
1873  }
1874 
1875  Kdi_->createPosition(row, col);
1876  }
1877 
1878  //finally, add all slave columns in this slave row to Kdd_.
1879  for(int kk=0; kk<len; kk++) {
1880  int colk = scatterPtr[kk];
1881 
1882  if (rSlave_[kk] != 1) continue;
1883 
1884  Kdd_->createPosition(row, colk);
1885  }
1886  }
1887  else {
1888  //this is not a slave row, so we will loop across it, creating matrix
1889  //positions for all non-slave columns in it.
1890  int reducedRow = -1;
1891  translateToReducedEqn(row, reducedRow);
1892 
1893  bool rowIsLocal = true;
1894  int owner = localProc_;
1895  if (reducedStartRow_ > reducedRow || reducedEndRow_ < reducedRow) {
1896  rowIsLocal = false;
1897  owner = getOwnerProcForEqn(row);
1898  }
1899 
1900  for(int j=0; j<len; j++) {
1901  if (rSlave_[j] == 1) continue;
1902 
1903  int reducedCol = workSpace_[j];
1904 
1905  if (rowIsLocal) {
1906  CHK_ERR( createMatrixPosition(reducedRow, reducedCol,
1907  "crtSymmEqnStr") );
1908  }
1909  else {
1910  eqnCommMgr_->addRemoteIndices(reducedRow, owner, &reducedCol, 1);
1911  }
1912  }
1913  }
1914  }
1915 
1917 
1918  }
1919  catch(std::runtime_error& exc) {
1920  fei::console_out() << exc.what() << FEI_ENDL;
1921  ERReturn(-1);
1922  }
1923 
1924  return(FEI_SUCCESS);
1925 }
1926 
1927 //------------------------------------------------------------------------------
1929 {
1930 //This function takes a list of equation numbers, as input, and for each
1931 //one, if it is a local equation number, goes to that row of the sysMatIndices
1932 //structure and stores the whole list of equation numbers as column indices
1933 //in that row of the matrix structure. If the equation number is not local,
1934 //then it is given to the EqnCommMgr.
1935 //
1936  int numIndices = indices.size();
1937  int* indPtr = &indices[0];
1938 
1939  workSpace_.resize(numIndices);
1940  int* workPtr = &workSpace_[0];
1941  int reducedEqn = -1;
1942  for(size_t j=0; j<indices.size(); j++) {
1943  bool isSlave = translateToReducedEqn(indPtr[j], reducedEqn);
1944  if (isSlave) ERReturn(-1);
1945  workPtr[j] = reducedEqn;
1946  }
1947 
1948  for(int i=0; i<numIndices; i++) {
1949  int row = indPtr[i];
1950  int rrow = workPtr[i];
1951 
1952  if ((localStartRow_ > row) || (row > localEndRow_)) {
1953 
1954  int owner = getOwnerProcForEqn(row);
1955  eqnCommMgr_->addRemoteIndices(rrow, owner, workPtr, numIndices);
1956  continue;
1957  }
1958 
1959  CHK_ERR( createMatrixPositions(rrow, numIndices, workPtr,
1960  "storeElemScttrInd") );
1961  }
1962 
1963  return(FEI_SUCCESS);
1964 }
1965 
1966 //------------------------------------------------------------------------------
1968 {
1969  //This function takes a list of equation numbers as input and for each one,
1970  //if it is a local equation number, goes to that row of the sysMatIndices
1971  //structure and stores the whole list of equation numbers as column indices
1972  //in that row of the matrix structure. If the equation number is not local,
1973  //then it is given to the EqnCommMgr.
1974  //
1975  int i, numIndices = indices.size();
1976  int* indPtr = &indices[0];
1977 
1978  for(i=0; i<numIndices; i++) {
1979  int row = indPtr[i];
1980  if (row < localStartRow_ || row > localEndRow_) {
1981  int owner = getOwnerProcForEqn(row);
1982  eqnCommMgr_->addRemoteIndices(row, owner, indPtr, numIndices);
1983  continue;
1984  }
1985 
1986  if (generateGraph_) {
1987  fei::ctg_set<int>& thisRow =
1989 
1990  for(int j=0; j<numIndices; ++j) {
1991  if (debugOutput_ && outputLevel_ > 2) {
1992  dbgOut() << "# storeElemScttrInds_ns crtMatPoss("
1993  << row << "," << indPtr[j] << ")"<<FEI_ENDL;
1994  }
1995 
1996  thisRow.insert2(indPtr[j]);
1997  }
1998  }
1999  }
2000 
2001  return(FEI_SUCCESS);
2002 }
2003 
2004 //------------------------------------------------------------------------------
2006 {
2007  //This function takes a list of equation numbers as input and for each one,
2008  //if it is a local equation number, goes to that row of the sysMatIndices
2009  //structure and stores the whole list of equation numbers as column indices
2010  //in that row of the matrix structure. If the equation number is not local,
2011  //then it is given to the EqnCommMgr.
2012  //
2013  int i, numIndices = indices.size();
2014  int* indPtr = &indices[0];
2015 
2016  for(i=0; i<numIndices; i++) {
2017  int row = indPtr[i];
2018  if (row < localStartRow_ || row > localEndRow_) {
2019  int owner = getOwnerProcForEqn(row);
2020  eqnCommMgr_->addRemoteIndices(row, owner, indPtr, numIndices);
2021  continue;
2022  }
2023 
2024  if (generateGraph_) {
2025  fei::ctg_set<int>& thisRow =
2027 
2028  for(int j=0; j<numIndices; ++j) {
2029  if (debugOutput_ && outputLevel_ > 2) {
2030  dbgOut() << "# storeElemScttrInds_ns crtMatPoss("
2031  << row << "," << indPtr[j] << ")"<<FEI_ENDL;
2032  }
2033 
2034  thisRow.insert2(indPtr[j]);
2035  }
2036  }
2037  }
2038 
2039  return(FEI_SUCCESS);
2040 }
2041 
2042 //------------------------------------------------------------------------------
2044 {
2045  //This function performs the appropriate manipulations (matrix-matrix-products,
2046  //matrix-vector-products) on the Kid,Kdi,Kdd matrices and then assembles the
2047  //results into the global matrix structure. This function also adds any
2048  //resulting contributions to off-processor portions of the matrix structure to
2049  //the EqnCommMgr.
2050  //
2052 
2053  csrD = *D;
2054  csrKid = *Kid_;
2055  csrKdi = *Kdi_;
2056  csrKdd = *Kdd_;
2057 
2058  //form tmpMat1_ = Kid_*D
2060 
2061  //form tmpMat2_ = D^T*Kdi_
2063 
2066  if (numProcs_ > 1) {
2069  }
2070 
2073 
2074  //form tmpMat1_ = D^T*Kdd_
2076 
2077  //form tmpMat2_ = tmpMat1_*D = D^T*Kdd_*D
2079 
2080 
2082  if (numProcs_ > 1) {
2084  }
2086 
2087  Kdi_->clear();
2088  Kid_->clear();
2089  Kdd_->clear();
2090  reducedEqnCounter_ = 0;
2091 
2092  return(FEI_SUCCESS);
2093 }
2094 
2095 //------------------------------------------------------------------------------
2097 {
2098  if (numSlvs_ < 1) return(0);
2099 
2100  CHK_ERR( translateToReducedEqns(*(eqnCommMgr.getRecvProcEqns())) );
2101  CHK_ERR( translateToReducedEqns(*(eqnCommMgr.getRecvEqns())) );
2102  CHK_ERR( translateToReducedEqns(*(eqnCommMgr.getSendProcEqns())) );
2103  CHK_ERR( translateToReducedEqns(*(eqnCommMgr.getSendEqns())) );
2104 
2105  return(0);
2106 }
2107 
2108 //------------------------------------------------------------------------------
2110 {
2111  int numEqns = eqnBuf.getNumEqns();
2112  int* eqnNumbers = &(eqnBuf.eqnNumbers()[0]);
2113  std::vector<fei::CSVec*>& eqnArray = eqnBuf.eqns();
2114  for(int i=0; i<numEqns; ++i) {
2115  int reducedEqn;
2116  translateToReducedEqn(eqnNumbers[i], reducedEqn);
2117  eqnNumbers[i] = reducedEqn;
2118 
2119  int* indicesPtr = &(eqnArray[i]->indices()[0]);
2120  int numIndices = eqnArray[i]->size();
2121  for(int j=0; j<numIndices; ++j) {
2122  translateToReducedEqn(indicesPtr[j], reducedEqn);
2123  indicesPtr[j] = reducedEqn;
2124  }
2125  }
2126 
2127  return(0);
2128 }
2129 
2130 //------------------------------------------------------------------------------
2132 {
2133  std::vector<std::vector<int>*>& eqnTable = procEqns.procEqnNumbersPtr();
2134  int dim1 = eqnTable.size();
2135  for(int i=0; i<dim1; ++i) {
2136  int dim2 = eqnTable[i]->size();
2137  int* indicesPtr = &(*(eqnTable[i]))[0];
2138  for(int j=0; j<dim2; ++j) {
2139  int reducedEqn;
2140  translateToReducedEqn(indicesPtr[j], reducedEqn);
2141  indicesPtr[j] = reducedEqn;
2142  }
2143  }
2144 
2145  return(0);
2146 }
2147 
2148 //------------------------------------------------------------------------------
2150 {
2151  //Given a matrix in unreduced numbering, convert all of its contents to the
2152  //"reduced" equation space. If any of the row-numbers or column-indices in
2153  //this matrix object are slave equations, they will not be referenced. In
2154  //this case, a positive warning-code will be returned.
2155 
2156  int reducedEqn = -1;
2157  int foundSlave = 0;
2158 
2159  fei::SparseRowGraph& srg = mat.getGraph();
2160 
2161  std::vector<int>& rowNumbers = srg.rowNumbers;
2162  for(size_t i=0; i<rowNumbers.size(); ++i) {
2163  bool isSlave = translateToReducedEqn(rowNumbers[i], reducedEqn);
2164  if (isSlave) foundSlave = 1;
2165  else rowNumbers[i] = reducedEqn;
2166  }
2167 
2168  std::vector<int>& colIndices = srg.packedColumnIndices;
2169  for(size_t i=0; i<colIndices.size(); ++i) {
2170  bool isSlave = translateToReducedEqn(colIndices[i], reducedEqn);
2171  if (isSlave) foundSlave = 1;
2172  else colIndices[i] = reducedEqn;
2173  }
2174 
2175  return(foundSlave);
2176 }
2177 
2178 //------------------------------------------------------------------------------
2180 {
2181  if (!generateGraph_) {
2182  return(0);
2183  }
2184 
2185  //This function must be called with a CSRMat object that already has its
2186  //contents numbered in "reduced" equation-numbers.
2187  //
2188  //This function has one simple task -- for each row,col pair stored in 'mat',
2189  //call 'createMatrixPosition' to make an entry in the global matrix structure
2190  //if it doesn't already exist.
2191  //
2192  const std::vector<int>& rowNumbers = mat.getGraph().rowNumbers;
2193  const std::vector<int>& rowOffsets = mat.getGraph().rowOffsets;
2194  const std::vector<int>& pckColInds = mat.getGraph().packedColumnIndices;
2195 
2196  for(size_t i=0; i<rowNumbers.size(); ++i) {
2197  int row = rowNumbers[i];
2198  int offset = rowOffsets[i];
2199  int rowlen = rowOffsets[i+1]-offset;
2200  const int* indices = &pckColInds[offset];
2201 
2202  for(int j=0; j<rowlen; j++) {
2203  CHK_ERR( createMatrixPosition(row, indices[j], "crtMatPos(CSRMat)") );
2204  }
2205  }
2206 
2207  return(0);
2208 }
2209 
2210 //------------------------------------------------------------------------------
2212  const char* callingFunction)
2213 {
2214  if (!generateGraph_) {
2215  return(0);
2216  }
2217 
2218  //
2219  //This function inserts the column index 'col' in the system matrix structure
2220  //in 'row', if it isn't already there.
2221  //
2222  //This is a private SNL_FEI_Structure function. These row/col numbers must be
2223  //global, 0-based equation numbers in the "reduced" equation space..
2224  //
2225 
2226  //if the equation isn't local, just return. (The assumption being that
2227  //this call is also being made on the processor that owns the equation.)
2228  if (row < reducedStartRow_ || row > reducedEndRow_) {
2229  if (debugOutput_) {
2230  dbgOut() << " " << callingFunction << " passed " <<row<<","<<col
2231  << ", not local." << FEI_ENDL;
2232  }
2233 
2234  return(0);
2235  }
2236 
2237  if (debugOutput_ && outputLevel_ > 2) {
2238  dbgOut() << "# " << callingFunction << " crtMatPos("
2239  << row << "," << col << ")"<<FEI_ENDL;
2240  }
2241 
2243 
2244  thisRow.insert2(col);
2245 
2246  return(0);
2247 }
2248 
2249 //------------------------------------------------------------------------------
2250 int SNL_FEI_Structure::createMatrixPositions(int row, int numCols, int* cols,
2251  const char* callingFunction)
2252 {
2253  if (!generateGraph_) {
2254  return(0);
2255  }
2256 
2257  //
2258  //This function inserts the column indices 'cols' in the system matrix structure
2259  //in 'row', if they aren't already there.
2260  //
2261  //This is a private SNL_FEI_Structure function. These row/col numbers must be
2262  //global, 0-based equation numbers in the "reduced" equation space..
2263  //
2264 
2265  //if the equation isn't local, just return. (The assumption being that
2266  //this call is also being made on the processor that owns the equation.)
2267  if (row < reducedStartRow_ || row > reducedEndRow_) {
2268  if (debugOutput_) {
2269  dbgOut() << " " << callingFunction << " passed " <<row
2270  << ", not local." << FEI_ENDL;
2271  }
2272 
2273  return(0);
2274  }
2275 
2277 
2278  for(int i=0; i<numCols; i++) {
2279  if (debugOutput_ && outputLevel_ > 2) {
2280  dbgOut() << "# " << callingFunction << " crtMatPoss("
2281  << row << "," << cols[i] << ")"<<FEI_ENDL;
2282  }
2283 
2284  thisRow.insert2(cols[i]);
2285  }
2286 
2287  return(0);
2288 }
2289 
2290 //------------------------------------------------------------------------------
2292 {
2293  //Run the nodes, elem-dof's and multiplier constraints, establishing the
2294  //point-equation to block-equation mappings. Note that this data is
2295  //initialized as non-reduced (i.e., not accounting for any slave equations)
2296  //equation numbers, then translated to the reduced space at the end of this
2297  //function.
2298 
2299  if (blkEqnMapper_ != NULL) delete blkEqnMapper_;
2301  snl_fei::PointBlockMap& blkEqnMapper = getBlkEqnMapper();
2302 
2303  //First, if there's only one (non-negative) fieldID and that fieldID's size
2304  //is 1, then we don't need to execute the rest of this function.
2305  int numFields = fieldDatabase_->size();
2306  const int* fieldIDs = getFieldIDsPtr();
2307  const int* fieldSizes = fieldIDs+numFields;
2308  int numNonNegativeFields = 0;
2309  int maxFieldSize = 0;
2310  for(int f=0; f<numFields; f++) {
2311  if (fieldIDs[f] >= 0) {
2312  numNonNegativeFields++;
2313  if (fieldSizes[f] > maxFieldSize) maxFieldSize = fieldSizes[f];
2314  }
2315  }
2316 
2317  if (numNonNegativeFields == 1 && maxFieldSize == 1) {
2318  globalMaxBlkSize_ = 1;
2319  blkEqnMapper.setPtEqualBlk();
2320  return(0);
2321  }
2322 
2323  int localVanishedNodeAdjustment = 0;
2324  for(int i=0; i<localProc_; ++i) {
2325  localVanishedNodeAdjustment += globalNumNodesVanished_[i];
2326  }
2327 
2328  int eqnNumber, blkEqnNumber;
2329 
2330  std::map<GlobalID,int>& nodeIDmap = nodeDatabase_->getNodeIDs();
2331  std::map<GlobalID,int>::iterator
2332  iter = nodeIDmap.begin(), iter_end = nodeIDmap.end();
2333 
2334  for(; iter!=iter_end; ++iter) {
2335  NodeDescriptor* node = NULL;
2336  nodeDatabase_->getNodeAtIndex(iter->second, node);
2337 
2338  // If the node doesn't exist, skip.
2339  if (node==NULL) continue;
2340 
2341  // If the node doesn't have any fields, skip
2342  int numFields = node->getNumFields();
2343  if(numFields == 0) continue;
2344 
2345  int firstPtEqn = node->getFieldEqnNumbers()[0];
2346  int numNodalDOF = node->getNumNodalDOF();
2347  blkEqnNumber = node->getBlkEqnNumber() - localVanishedNodeAdjustment;
2348 
2349  int blkSize = numNodalDOF;
2350 
2351  for(int j=0; j<numNodalDOF; ++j) {
2352  bool isSlave = translateToReducedEqn(firstPtEqn+j, eqnNumber);
2353  if (isSlave) {
2354  --blkSize;
2355  }
2356  else {
2357  CHK_ERR( blkEqnMapper.setEqn(eqnNumber, blkEqnNumber) );
2358  }
2359  }
2360 
2361  if (blkSize > 0) {
2362  CHK_ERR( blkEqnMapper.setBlkEqnSize(blkEqnNumber, blkSize) );
2363  }
2364  else {
2365  ++localVanishedNodeAdjustment;
2366  }
2367  }
2368 
2369  //
2370  //Now the element-dofs...
2371  //
2372  int numBlocks = getNumElemBlocks();
2373  int numLocalNodes = globalNodeOffsets_[localProc_+1]-globalNodeOffsets_[localProc_];
2374  eqnNumber = localStartRow_ + numLocalNodalEqns_;
2375  blkEqnNumber = localBlkOffset_ + numLocalNodes;
2376 
2377  for(int i = 0; i < numBlocks; i++) {
2378  BlockDescriptor* block = NULL;
2379  CHK_ERR( getBlockDescriptor_index(i, block) );
2380 
2381  int numElemDOF = block->getNumElemDOFPerElement();
2382 
2383  if (numElemDOF > 0) {
2384  int numElems = block->getNumElements();
2385 
2386  for(int j=0; j<numElems; j++) {
2387 
2388  for(int ede=0; ede<numElemDOF; ede++) {
2389  blkEqnMapper.setEqn(eqnNumber+ede, blkEqnNumber+ede);
2390  blkEqnMapper.setBlkEqnSize(blkEqnNumber+ede, 1);
2391  }
2392 
2393  eqnNumber += numElemDOF;
2394  blkEqnNumber += numElemDOF;
2395  }
2396  }
2397  }
2398 
2399  //Now we'll set mappings for all local multiplier constraint-relations,
2400  //and also gather the equation numbers for other processors' multipliers
2401  //to record in our snl_fei::PointBlockMap object.
2402  //
2403  std::map<GlobalID,ConstraintType*>::const_iterator
2404  cr_iter = multCRs_.begin(),
2405  cr_end = multCRs_.end();
2406 
2407  std::vector<int> localMultEqns;
2408  localMultEqns.reserve(multCRs_.size()*2);
2409  while(cr_iter != cr_end) {
2410  ConstraintType* multCR = (*cr_iter).second;
2411  eqnNumber = multCR->getEqnNumber();
2412  blkEqnNumber = multCR->getBlkEqnNumber();
2413 
2414  CHK_ERR( blkEqnMapper_->setEqn(eqnNumber, blkEqnNumber) );
2415  CHK_ERR( blkEqnMapper_->setBlkEqnSize(blkEqnNumber, 1) );
2416 
2417  localMultEqns.push_back(eqnNumber);
2418  localMultEqns.push_back(blkEqnNumber);
2419  ++cr_iter;
2420  }
2421 
2422  //Now gather and store the equation-numbers arising from other
2423  //processors' multiplier constraints. (We obviously only need to do this if
2424  //there is more than one processor, and we can skip it if the problem
2425  //only contains 1 scalar equation for each block-equation.)
2426 
2427  int localMaxBlkEqnSize = blkEqnMapper_->getMaxBlkEqnSize();
2428  globalMaxBlkSize_ = 0;
2429  CHK_ERR( fei::GlobalMax(comm_, localMaxBlkEqnSize, globalMaxBlkSize_) );
2430 
2432 
2433  if (globalMaxBlkSize_ == 1) {
2434  //If the globalMax block-size is 1 then tell the blkEqnMapper, and it will
2435  //reclaim the memory it allocated in arrays, etc.
2437  return(0);
2438  }
2439 
2440  if (numProcs_ > 1) {
2441  std::vector<int> recvLengths, globalMultEqns;
2442  CHK_ERR(fei::Allgatherv(comm_, localMultEqns, recvLengths, globalMultEqns));
2443 
2444  int offset = 0;
2445  for(int p=0; p<numProcs_; p++) {
2446  if (p == localProc_) { offset += recvLengths[p]; continue; }
2447 
2448  for(int j=0; j<recvLengths[p]/2; j++) {
2449  blkEqnMapper_->setEqn(globalMultEqns[offset], globalMultEqns[offset+1]);
2450  blkEqnMapper_->setBlkEqnSize(globalMultEqns[offset+1], 1);
2451  offset += 2;
2452  }
2453  }
2454  }
2455 
2456  return(0);
2457 }
2458 
2459 //------------------------------------------------------------------------------
2461 {
2462  //We'll set equation-numbers on all local multiplier constraint-relations,
2463  //and also gather the equation numbers for other processors' multipliers
2464  //to record in our snl_fei::PointBlockMap object.
2465  //
2466  std::map<GlobalID,ConstraintType*>::const_iterator
2467  cr_iter = multCRs_.begin(),
2468  cr_end = multCRs_.end();
2469 
2472 
2473  while(cr_iter != cr_end) {
2474  ConstraintType* multCR = (*cr_iter).second;
2475 
2476  multCR->setEqnNumber(eqnNumber);
2477 
2478  multCR->setBlkEqnNumber(blkEqnNum);
2479 
2480  ++eqnNumber;
2481  ++blkEqnNum;
2482  ++cr_iter;
2483  }
2484 
2485  return(0);
2486 }
2487 
2488 //------------------------------------------------------------------------------
2490 {
2491  FEI_OSTRINGSTREAM osstr;
2492  osstr << dbgPath_ << "/FEI" << name_ << "_nID_nNum_blkEq_ptEq."
2493  << numProcs_ << "." << localProc_;
2494 
2495  FEI_OFSTREAM e2nFile(osstr.str().c_str());
2496 
2497  if (!e2nFile) {
2498  fei::console_out() << "SNL_FEI_Structure::writeEqn2NodeMap: ERROR, couldn't open file "
2499  << osstr.str() << FEI_ENDL;
2500  ERReturn(-1);
2501  }
2502 
2503  std::map<GlobalID,ConstraintType*>::const_iterator
2504  cr_iter = multCRs_.begin(),
2505  cr_end = multCRs_.end();
2506 
2507  while(cr_iter != cr_end) {
2508  ConstraintType* multCR = (*cr_iter).second;
2509  int eqnNumber = multCR->getEqnNumber();
2510  int blkEqnNumber = multCR->getBlkEqnNumber();
2511 
2512  e2nFile << "-999 -999 " << blkEqnNumber << " " << eqnNumber << FEI_ENDL;
2513  ++cr_iter;
2514  }
2515 
2516  std::map<GlobalID,int>& nodeIDmap = nodeDatabase_->getNodeIDs();
2517  std::map<GlobalID,int>::iterator
2518  iter = nodeIDmap.begin(), iter_end = nodeIDmap.end();
2519 
2520  for(; iter!=iter_end; ++iter) {
2521  NodeDescriptor* node = NULL;
2522  nodeDatabase_->getNodeAtIndex(iter->second, node);
2523 
2524  if (node==NULL || node->getOwnerProc() != localProc_) {
2525  continue;
2526  }
2527 
2528  const int* fieldIDList = node->getFieldIDList();
2529  const int* eqnNumbers = node->getFieldEqnNumbers();
2530  int nodeNum = node->getNodeNumber();
2531  int blkEqnNumber = node->getBlkEqnNumber();
2532  int numFields = node->getNumFields();
2533 
2534  for(int j=0; j<numFields; j++) {
2535  int numFieldParams = getFieldSize(fieldIDList[j]);
2536  assert( numFieldParams > 0 );
2537 
2538  for(int k=0; k<numFieldParams; k++) {
2539  e2nFile << (int)node->getGlobalNodeID() << " " << nodeNum
2540  << " " << blkEqnNumber << " " << eqnNumbers[j]+k<<FEI_ENDL;
2541  }
2542  }
2543  }
2544 
2545  return(FEI_SUCCESS);
2546 }
2547 
2548 //------------------------------------------------------------------------------
2550 {
2551  int numBlocks = getNumElemBlocks();
2552  int totalNumElemDOF = 0;
2553 
2554  for(int i = 0; i < numBlocks; i++) {
2555  BlockDescriptor* block = NULL;
2556  CHK_ERR( getBlockDescriptor_index(i, block) );
2557  int numElemDOF = block->getNumElemDOFPerElement();
2558  if (numElemDOF > 0) {
2559  int numElems = block->getNumElements();
2560 
2561  totalNumElemDOF += numElems*numElemDOF;
2562  }
2563  }
2564 
2565  return(totalNumElemDOF);
2566 }
2567 
2568 //------------------------------------------------------------------------------
2570 {
2571  int totalNumMultCRs = 0;
2572  int numMCRecords = getNumMultConstRecords();
2573 
2574  totalNumMultCRs = numMCRecords;
2575 
2576  return( totalNumMultCRs );
2577 }
2578 
2579 //------------------------------------------------------------------------------
2580 void SNL_FEI_Structure::calcGlobalEqnInfo(int numLocallyOwnedNodes,
2581  int numLocalEqns,
2582  int numLocalEqnBlks)
2583 {
2584  FEI_OSTREAM& os = dbgOut();
2585  if (debugOutput_) os << "# entering calcGlobalEqnInfo" << FEI_ENDL;
2586 
2587 //
2588 //This function does the inter-process communication necessary to obtain,
2589 //on each processor, the global number of equations, and the local starting
2590 //and ending equation numbers.
2591 //While we're here, we do the same thing for node-numbers.
2592 //
2593 
2594  //first, get each processor's local number of equations on the master proc.
2595 
2596  std::vector<int> numProcNodes(numProcs_);
2597  std::vector<int> numProcEqns(numProcs_);
2598  std::vector<int> numProcEqnBlks(numProcs_);
2599 
2600  if (numProcs_ > 1) {
2601 #ifndef FEI_SER
2602  int glist[3];
2603  std::vector<int> recvList(3*numProcs_);
2604 
2605  glist[0] = numLocallyOwnedNodes;
2606  glist[1] = numLocalEqns;
2607  glist[2] = numLocalEqnBlks;
2608  if (MPI_Gather(&glist[0], 3, MPI_INT, &recvList[0], 3,
2609  MPI_INT, masterProc_, comm_) != MPI_SUCCESS) {
2610  fei::console_out() << "SNL_FEI_Structure::calcGlobalEqnInfo: ERROR in MPI_Gather" << FEI_ENDL;
2611  MPI_Abort(comm_, -1);
2612  }
2613 
2614  for(int p=0; p<numProcs_; p++) {
2615  numProcNodes[p] = recvList[p*3];
2616  numProcEqns[p] = recvList[p*3+1];
2617  numProcEqnBlks[p] = recvList[p*3+2];
2618  }
2619 #endif
2620  }
2621  else {
2622  numProcNodes[0] = numLocallyOwnedNodes;
2623  numProcEqns[0] = numLocalEqns;
2624  numProcEqnBlks[0] = numLocalEqnBlks;
2625  }
2626 
2627  //compute offsets for all processors (starting index for local equations)
2628 
2629  globalNodeOffsets_.resize(numProcs_+1);
2630  globalEqnOffsets_.resize(numProcs_+1);
2631  globalBlkEqnOffsets_.resize(numProcs_+1);
2632 
2633  globalNodeOffsets_[0] = 0; // 0-based node-numbers
2634  globalEqnOffsets_[0] = 0; // we're going to start rows & cols at 0 (global)
2635  globalBlkEqnOffsets_[0] = 0;
2636 
2637  if (localProc_ == masterProc_) {
2638  for(int i=1;i<numProcs_;i++) {
2639  globalNodeOffsets_[i] = globalNodeOffsets_[i-1] +numProcNodes[i-1];
2640  globalEqnOffsets_[i] = globalEqnOffsets_[i-1] + numProcEqns[i-1];
2642  numProcEqnBlks[i-1];
2643  }
2644 
2646  numProcNodes[numProcs_-1];
2648  numProcEqns[numProcs_-1];
2650  numProcEqnBlks[numProcs_-1];
2651  }
2652 
2653  //now, broadcast vector of eqnOffsets to all processors
2654 
2655  if (numProcs_ > 1) {
2656 #ifndef FEI_SER
2657  std::vector<int> blist(3*(numProcs_+1));
2658 
2659  if (localProc_ == masterProc_) {
2660  int offset = 0;
2661  for(int i=0; i<numProcs_+1; i++) {
2662  blist[offset++] = globalNodeOffsets_[i];
2663  blist[offset++] = globalEqnOffsets_[i];
2664  blist[offset++] = globalBlkEqnOffsets_[i];
2665  }
2666  }
2667 
2668  if (MPI_Bcast(&blist[0], 3*(numProcs_+1), MPI_INT,
2669  masterProc_, comm_) != MPI_SUCCESS) {
2670  fei::console_out() << "SNL_FEI_Structure::calcGlobalEqnInfo: ERROR in MPI_Bcast" << FEI_ENDL;
2671  MPI_Abort(comm_, -1);
2672  }
2673 
2674  if (localProc_ != masterProc_) {
2675  int offset = 0;
2676  for(int i=0; i<numProcs_+1; i++) {
2677  globalNodeOffsets_[i] = blist[offset++];
2678  globalEqnOffsets_[i] = blist[offset++];
2679  globalBlkEqnOffsets_[i] = blist[offset++];
2680  }
2681  }
2682 #endif
2683  }
2684 
2688 
2691 
2694 
2695  if (debugOutput_) {
2696  os << "# localStartRow_: " << localStartRow_ << FEI_ENDL;
2697  os << "# localEndRow_: " << localEndRow_ << FEI_ENDL;
2698  os << "# numGlobalEqns_: " << numGlobalEqns_ << FEI_ENDL;
2699  os << "# numGlobalEqnBlks_: " << numGlobalEqnBlks_ << FEI_ENDL;
2700  os << "# localBlkOffset_: " << localBlkOffset_ << FEI_ENDL;
2701  os << "# firstLocalNodeNumber_: " << firstLocalNodeNumber_ << FEI_ENDL;
2702  size_t n;
2703  os << "# numGlobalNodes_: " << numGlobalNodes_ << FEI_ENDL;
2704  os << "# " << globalNodeOffsets_.size() << " globalNodeOffsets_: ";
2705  for(size_t nn=0; nn<globalNodeOffsets_.size(); nn++)
2706  os << globalNodeOffsets_[nn] << " ";
2707  os << FEI_ENDL;
2708  os << "# " << globalEqnOffsets_.size() << " globalEqnOffsets_: ";
2709  for(n=0; n<globalEqnOffsets_.size(); n++)
2710  os << globalEqnOffsets_[n] << " ";
2711  os << FEI_ENDL;
2712  os << "# " << globalBlkEqnOffsets_.size() << " globalBlkEqnOffsets_: ";
2713  for(n=0; n<globalBlkEqnOffsets_.size(); n++)
2714  os << globalBlkEqnOffsets_[n] << " ";
2715  os << FEI_ENDL;
2716  os << "# leaving calcGlobalEqnInfo" << FEI_ENDL;
2717  }
2718 }
2719 
2720 //------------------------------------------------------------------------------
2722 {
2723 //
2724 //Private SNL_FEI_Structure function, to be called in initComplete, after
2725 //'calcGlobalEqnInfo()'.
2726 //
2727 //This function sets global equation numbers on the nodes.
2728 //
2729 //The return value is an error-code.
2730 //
2731  int eqn = localStartRow_;
2732 
2733  //localBlkOffset_ is 0-based, and so is blkEqnNumber.
2734  int blkEqnNumber = localBlkOffset_;
2735 
2736  std::map<GlobalID,int>& nodeIDmap = nodeDatabase_->getNodeIDs();
2737  std::map<GlobalID,int>::iterator
2738  iter = nodeIDmap.begin(), iter_end = nodeIDmap.end();
2739 
2740  for(; iter!=iter_end; ++iter) {
2741  NodeDescriptor* node = NULL;
2742  nodeDatabase_->getNodeAtIndex(iter->second, node);
2743 
2744  if (node==NULL) continue;
2745 
2746  int numFields = node->getNumFields();
2747  const int* fieldIDs = node->getFieldIDList();
2748 
2749  if (node->getOwnerProc() == localProc_) {
2750  int numNodalDOF = 0;
2751 
2752  for(int j=0; j<numFields; j++) {
2753  node->setFieldEqnNumber(fieldIDs[j], eqn);
2754  int fieldSize = getFieldSize(fieldIDs[j]);
2755  eqn += fieldSize;
2756  numNodalDOF += fieldSize;
2757  }
2758 
2759  node->setNumNodalDOF(numNodalDOF);
2760  node->setBlkEqnNumber(blkEqnNumber++);
2761  }
2762  }
2763 
2764  return(0);
2765 }
2766 
2767 //------------------------------------------------------------------------------
2769 {
2770  //
2771  //Private SNL_FEI_Structure function, to be called from initComplete after
2772  //setBlkEqnInfo() has been called.
2773  //
2774  //Sets global equation numbers for all element-DOF.
2775  //
2776  int numBlocks = getNumElemBlocks();
2777 
2778  int eqnNumber = localStartRow_ + numLocalNodalEqns_;
2779 
2780  for(int i = 0; i < numBlocks; i++) {
2781  BlockDescriptor* block = NULL;
2782  int err = getBlockDescriptor_index(i, block);
2783  if (err) voidERReturn;
2784 
2785  int numElemDOF = block->getNumElemDOFPerElement();
2786 
2787  if (numElemDOF > 0) {
2788  std::vector<int>& elemDOFEqns = block->elemDOFEqnNumbers();
2789  std::map<GlobalID,int>& elemIDs = connTables_[i]->elemIDs;
2790 
2791  std::map<GlobalID,int>::const_iterator
2792  iter = elemIDs.begin(),
2793  iter_end = elemIDs.end();
2794 
2795  for(; iter != iter_end; ++iter) {
2796  elemDOFEqns[iter->second] = eqnNumber;
2797 
2798  eqnNumber += numElemDOF;
2799  }
2800  }
2801  }
2802 }
2803 
2804 //------------------------------------------------------------------------------
2806 //
2807 //Append a blockID to our (unsorted) list of blockIDs if it isn't
2808 //already present. Also, add a block-descriptor if blockID wasn't
2809 //already present, and a ConnectivityTable to go with it.
2810 //
2811  int insertPoint = -1;
2812  int found = fei::binarySearch(blockID, blockIDs_, insertPoint);
2813 
2814  if (found<0) {
2815  blockIDs_.insert(blockIDs_.begin()+insertPoint, blockID);
2816 
2817  BlockDescriptor* block = new BlockDescriptor;
2818  block->setGlobalBlockID(blockID);
2819 
2820  blocks_.insert(blocks_.begin()+insertPoint, block);
2821 
2822  ConnectivityTable* newConnTable = new ConnectivityTable;
2823  connTables_.insert(connTables_.begin()+insertPoint, newConnTable);
2824  }
2825 
2826  return(FEI_SUCCESS);
2827 }
2828 
2829 //------------------------------------------------------------------------------
2831  BlockDescriptor*& block)
2832 {
2833  int index = fei::binarySearch(blockID, blockIDs_);
2834 
2835  if (index < 0) {
2836  fei::console_out() << "SNL_FEI_Structure::getBlockDescriptor: ERROR, blockID "
2837  << (int)blockID << " not found." << FEI_ENDL;
2838  return(-1);
2839  }
2840 
2841  block = blocks_[index];
2842 
2843  return(FEI_SUCCESS);
2844 }
2845 
2846 //------------------------------------------------------------------------------
2848 {
2849  int index = fei::binarySearch(blockID, blockIDs_);
2850  return(index);
2851 }
2852 
2853 //------------------------------------------------------------------------------
2855  BlockDescriptor*& block)
2856 {
2857  if (index < 0 || index >= (int)blockIDs_.size()) ERReturn(FEI_FATAL_ERROR);
2858 
2859  block = blocks_[index];
2860 
2861  return(FEI_SUCCESS);
2862 }
2863 
2864 //------------------------------------------------------------------------------
2866 
2867  int index = fei::binarySearch(blockID, blockIDs_);
2868 
2869  if (index < 0) {
2870  fei::console_out() << "SNL_FEI_Structure::allocateConnectivityTable: ERROR, blockID "
2871  << (int)blockID << " not found. Aborting." << FEI_ENDL;
2872  MPI_Abort(comm_, -1);
2873  }
2874 
2875  connTables_[index]->numNodesPerElem =
2876  blocks_[index]->getNumNodesPerElement();
2877 
2878  int numRows = blocks_[index]->getNumElements();
2879  int numCols = connTables_[index]->numNodesPerElem;
2880 
2881  if ((numRows <= 0) || (numCols <= 0)) {
2882  fei::console_out() << "SNL_FEI_Structure::allocateConnectivityTable: ERROR, either "
2883  << "numElems or numNodesPerElem not yet set for blockID "
2884  << (int)blockID << ". Aborting." << FEI_ENDL;
2885  MPI_Abort(comm_, -1);
2886  }
2887 
2888  connTables_[index]->elemNumbers.resize(numRows);
2889 
2890  connTables_[index]->elem_conn_ids = new std::vector<GlobalID>(numRows*numCols);
2891 
2892  return(FEI_SUCCESS);
2893 }
2894 
2895 //------------------------------------------------------------------------------
2897 
2898  int index = fei::binarySearch(blockID, blockIDs_);
2899 
2900  if (index < 0) {
2901  fei::console_out() << "SNL_FEI_Structure::getBlockConnectivity: ERROR, blockID "
2902  << (int)blockID << " not found. Aborting." << FEI_ENDL;
2903  MPI_Abort(comm_, -1);
2904  }
2905 
2906  return(*(connTables_[index]));
2907 }
2908 
2909 //------------------------------------------------------------------------------
2911 {
2912  FEI_OSTREAM& os = dbgOut();
2913  if (debugOutput_) {
2914  os << "# finalizeActiveNodes" << FEI_ENDL;
2915  }
2916  //First, make sure that the shared-node IDs are in the nodeDatabase, since
2917  //they might not have been added yet...
2918 
2919  std::vector<GlobalID>& shNodeIDs = nodeCommMgr_->getSharedNodeIDs();
2920  for(unsigned i=0; i<shNodeIDs.size(); i++) {
2921  CHK_ERR( nodeDatabase_->initNodeID(shNodeIDs[i]) );
2922  }
2923 
2924  if (activeNodesInitialized_) return(0);
2925  //
2926  //Now run through the connectivity tables and set the nodal field and block
2927  //info. Also, replace the nodeID in the element-connectivity lists with an
2928  //index from the NodeDatabase object. This will save us a lot of time when
2929  //looking up nodes later.
2930  //
2931  //One other thing we're going to do is give all elements an element-number.
2932  //This element-number will start at zero locally (meaning that it's not
2933  //globally unique).
2934  //
2935  int elemNumber = 0;
2936  int numBlocks = blockIDs_.size();
2937  for(int bIndex=0; bIndex<numBlocks; bIndex++) {
2938 
2939  GlobalID blockID = blocks_[bIndex]->getGlobalBlockID();
2940  ConnectivityTable& conn = *(connTables_[bIndex]);
2941 
2942  GlobalID* elemConn = NULL;
2943  NodeDescriptor** elemNodeDescPtrs = NULL;
2944 
2945  int numElems = conn.elemIDs.size();
2946  if (numElems > 0) {
2947  elemConn = &((*conn.elem_conn_ids)[0]);
2948  if (!activeNodesInitialized_) {
2949  int elemConnLen = conn.elem_conn_ids->size();
2950  conn.elem_conn_ptrs = new std::vector<NodeDescriptor*>(elemConnLen);
2951  }
2952  elemNodeDescPtrs = &((*conn.elem_conn_ptrs)[0]);
2953  }
2954  int nodesPerElem = conn.numNodesPerElem;
2955 
2956  int* fieldsPerNodePtr = blocks_[bIndex]->fieldsPerNodePtr();
2957  int** fieldIDsTablePtr = blocks_[bIndex]->fieldIDsTablePtr();
2958 
2959  //
2960  //Now we want to go through the connectivity table, and for each node,
2961  //add its fields and this block to the correct NodeDescriptor from the
2962  //nodeDatabase_.
2963  //(Note that the addField and addBlock functions only add the input if
2964  //it isn't already present in that NodeDescriptor.)
2965  //
2966  //We also need to set its owner proc to localProc_ as a default, and
2967  //inform the nodeCommMgr that the node appears in local connectivities.
2968  //
2969 
2970  conn.elemNumbers.resize(numElems);
2971 
2972  int numDistinctFields = blocks_[bIndex]->getNumDistinctFields();
2973  int fieldID = fieldIDsTablePtr[0][0];
2974 
2975  int elem;
2976  for(elem=0; elem<numElems; elem++) {
2977  conn.elemNumbers[elem] = elemNumber++;
2978  GlobalID* elemNodes = &(elemConn[elem*nodesPerElem]);
2979  NodeDescriptor** elemNodePtrs = &(elemNodeDescPtrs[elem*nodesPerElem]);
2980 
2981  for(int n=0; n<nodesPerElem; n++) {
2982  NodeDescriptor* node = NULL;
2983  int index = nodeDatabase_->getNodeWithID( elemNodes[n], node );
2984  if (index < 0) {
2985  fei::console_out() << "ERROR in SNL_FEI_Structure::initializeActiveNodes, "
2986  << FEI_ENDL << "failed to find node "
2987  << (int)(elemNodes[n]) << FEI_ENDL;
2988  }
2989 
2990  if (numDistinctFields == 1) {
2991  node->addField(fieldID);
2992  }
2993  else {
2994  for(int i=0; i<fieldsPerNodePtr[n]; i++) {
2995  node->addField(fieldIDsTablePtr[n][i]);
2996  }
2997  }
2998 
2999  int blk_idx = getIndexOfBlock(blockID);
3000  if (blk_idx >= 0) {
3001  node->addBlockIndex(blk_idx);
3002  }
3003 
3004  //now store this NodeDescriptor pointer, for fast future lookups
3005  elemNodePtrs[n] = node;
3006 
3007  node->setOwnerProc(localProc_);
3008  if (numProcs_ > 1) nodeCommMgr_->informLocal(*node);
3009  }
3010  }
3011  }
3012 
3013  //
3014  //we also need to run through the penalty constraints and inform the
3015  //nodeCommMgr that the constrained nodes are local.
3016  //
3017 
3018  if (numProcs_ > 1) {
3019  std::map<GlobalID,ConstraintType*>::const_iterator
3020  cr_iter = getPenConstRecords().begin(),
3021  cr_end = getPenConstRecords().end();
3022 
3023  while(cr_iter != cr_end) {
3024  ConstraintType& cr = *((*cr_iter).second);
3025  std::vector<GlobalID>& nodeID_vec = cr.getMasters();
3026  GlobalID* nodeIDs = &nodeID_vec[0];
3027  int numNodes = cr.getMasters().size();
3028 
3029  NodeDescriptor* node = NULL;
3030  for(int k=0; k<numNodes; ++k) {
3031  int err = nodeDatabase_->getNodeWithID(nodeIDs[k], node) ;
3032  if ( err != -1 ) {
3033  nodeCommMgr_->informLocal(*node);
3034  }
3035  //CHK_ERR( nodeDatabase_->getNodeWithID(nodeIDs[k], node) );
3036  //CHK_ERR( nodeCommMgr_->informLocal(*node) );
3037  }
3038  ++cr_iter;
3039  }
3040  }
3041 
3042  activeNodesInitialized_ = true;
3043 
3044  if (debugOutput_) os << "# leaving finalizeActiveNodes" << FEI_ENDL;
3045  return(FEI_SUCCESS);
3046 }
3047 
3048 //------------------------------------------------------------------------------
3050 {
3051  //call initComplete() on the nodeCommMgr, so that it can
3052  //finalize shared-node ownerships, etc.
3053 
3054  //request the safetyCheck if the user requested it via the
3055  //parameters function.
3056  bool safetyCheck = checkSharedNodes_;
3057 
3058  if (safetyCheck && localProc_==0 && numProcs_>1 && outputLevel_>0) {
3059  FEI_COUT << "FEI Info: A consistency-check of shared-node data will be "
3060  << "performed, which involves all-to-all communication. This check is "
3061  << "done only if explicitly requested by parameter "
3062  << "'FEI_CHECK_SHARED_IDS'."<<FEI_ENDL;
3063  }
3064 
3065  CHK_ERR( nodeCommMgr_->initComplete(*nodeDatabase_, safetyCheck) );
3066 
3067  if (debugOutput_) {
3068  FEI_OSTREAM& os = dbgOut();
3069  int numSharedNodes = nodeCommMgr_->getNumSharedNodes();
3070  os << "# numSharedNodes: " << numSharedNodes << FEI_ENDL;
3071  for(int ns=0; ns<numSharedNodes; ns++) {
3073  GlobalID nodeID = node.getGlobalNodeID();
3074  int proc = node.getOwnerProc();
3075  os << "# shNodeID " << (int)nodeID << ", owned by proc "<<proc<<FEI_ENDL;
3076  }
3077  }
3078 
3079  return(0);
3080 }
3081 
3082 //------------------------------------------------------------------------------
3084 {
3085  //This function will count how
3086  //many active nodes there are for each block.
3087 
3088  int numBlocks = blockIDs_.size();
3089  std::vector<int> nodesPerBlock(numBlocks);
3090  std::vector<int> eqnsPerBlock(numBlocks);
3091 
3092  int j;
3093  for(j=0; j<numBlocks; j++) {
3094  nodesPerBlock[j] = 0;
3095  eqnsPerBlock[j] = 0;
3096  }
3097 
3098  int numNodes = nodeDatabase_->getNumNodeDescriptors();
3099 
3100  for(j=0; j<numNodes; j++) {
3101  NodeDescriptor* node = NULL;
3102  nodeDatabase_->getNodeAtIndex(j, node);
3103  if (node==NULL) continue;
3104 
3105  const int* fieldIDList = node->getFieldIDList();
3106 
3107  int numFields = node->getNumFields();
3108 
3109  const std::vector<unsigned>& blkIndices = node->getBlockIndexList();
3110  for(std::vector<unsigned>::const_iterator b=blkIndices.begin(), bend=blkIndices.end();
3111  b!=bend; ++b) {
3112  nodesPerBlock[*b]++;
3113 
3114  for(int fld=0; fld<numFields; fld++) {
3115  if (blocks_[*b]->containsField(fieldIDList[fld])) {
3116  int fSize = getFieldSize(fieldIDList[fld]);
3117  assert(fSize >= 0);
3118  eqnsPerBlock[*b] += fSize;
3119  }
3120  }
3121  }
3122  }
3123 
3124  for(j=0; j<numBlocks; j++) {
3125  blocks_[j]->setNumActiveNodes(nodesPerBlock[j]);
3126  }
3127 
3128  //now we need to add the elem-dof to the eqn-count for each block,
3129  //and then set the total number of eqns on each block.
3130 
3131  for(j=0; j<numBlocks; j++) {
3132  eqnsPerBlock[j] += blocks_[j]->getNumElemDOFPerElement() *
3133  blocks_[j]->getNumElements();
3134 
3135  blocks_[j]->setTotalNumEqns(eqnsPerBlock[j]);
3136  }
3137  return(0);
3138 }
3139 
3140 //------------------------------------------------------------------------------
3142 {
3143  FEI_OSTREAM& os = dbgOut();
3144  if (debugOutput_) os << "# initializeEqnCommMgr" << FEI_ENDL;
3145 
3146  //This function will take information from the (internal member) nodeCommMgr
3147  //and use it to tell the eqnCommMgr which equations we can expect other
3148  //processors to contribute to, and also which equations we'll be sending to
3149  //other processors.
3150  //
3151  //This function can not be called until after initComplete() has been called
3152  //on the nodeCommMgr.
3153  //
3154  int numSharedNodes = nodeCommMgr_->getNumSharedNodes();
3155 
3156  for(int i=0; i<numSharedNodes; i++) {
3158 
3159  int numFields = node.getNumFields();
3160  const int* nodeFieldIDList = node.getFieldIDList();
3161  const int* nodeEqnNums = node.getFieldEqnNumbers();
3162 
3163  int owner = node.getOwnerProc();
3164  if (owner == localProc_) {
3165  std::vector<int>& proc = nodeCommMgr_->getSharedNodeProcs(i);
3166  int numProcs = proc.size();
3167 
3168  for(int p=0; p<numProcs; p++) {
3169 
3170  if (proc[p] == localProc_) continue;
3171 
3172  for(int j=0; j<numFields; j++) {
3173  int numEqns = getFieldSize(nodeFieldIDList[j]);
3174  assert(numEqns >= 0);
3175 
3176  int eqn;
3177  for(eqn=0; eqn<numEqns; eqn++) {
3178  int reducedEqn = -1;
3179  bool isSlave = translateToReducedEqn(nodeEqnNums[j]+eqn,
3180  reducedEqn);
3181  if (isSlave) continue;
3182 
3183  eqnCommMgr_->addLocalEqn(reducedEqn, proc[p]);
3184  }
3185  }
3186  }
3187  }
3188  else {
3189  for(int j=0; j<numFields; j++) {
3190  int numEqns = getFieldSize(nodeFieldIDList[j]);
3191  assert(numEqns >= 0);
3192  for(int eqn=0; eqn<numEqns; eqn++) {
3193  int reducedEqn = -1;
3194  bool isSlave = translateToReducedEqn(nodeEqnNums[j]+eqn, reducedEqn);
3195  if (isSlave) continue;
3196 
3197  eqnCommMgr_->addRemoteIndices(reducedEqn, owner, NULL, 0);
3198  }
3199  }
3200  }
3201  }
3202 
3203  if (debugOutput_) os << "# leaving initializeEqnCommMgr" << FEI_ENDL;
3204 }
3205 
3206 //------------------------------------------------------------------------------
3207 void SNL_FEI_Structure::getEqnInfo(int& numGlobalEqns, int& numLocalEqns,
3208  int& localStartRow, int& localEndRow){
3209 
3210  numGlobalEqns = numGlobalEqns_;
3211  numLocalEqns = numLocalEqns_;
3212  localStartRow = localStartRow_;
3213  localEndRow = localEndRow_;
3214 }
3215 
3216 //------------------------------------------------------------------------------
3218  int idType, int fieldID,
3219  int& numEqns, int* eqnNumbers)
3220 {
3221  //for now, only allow node ID. allowance for element ID is coming soon!!!
3222  if (idType != FEI_NODE) ERReturn(-1);
3223 
3224  NodeDescriptor* node = NULL;
3225  CHK_ERR( nodeDatabase_->getNodeWithID(ID, node) );
3226 
3227  numEqns = getFieldSize(fieldID);
3228  if (numEqns < 0) ERReturn(-1);
3229 
3230  int nodeFieldEqnNumber = -1;
3231  if (!node->getFieldEqnNumber(fieldID, nodeFieldEqnNumber)) {
3232  ERReturn(-1);
3233  }
3234 
3235  for(int i=0; i<numEqns; i++) eqnNumbers[i] = nodeFieldEqnNumber + i;
3236 
3237  return(FEI_SUCCESS);
3238 }
3239 
3240 //------------------------------------------------------------------------------
3242  const GlobalID* IDs,
3243  int idType, int fieldID,
3244  int& numEqns, int* eqnNumbers)
3245 {
3246  //for now, only allow node ID. allowance for element ID is coming soon!!!
3247  if (idType != FEI_NODE) ERReturn(-1);
3248 
3249  int fieldSize = getFieldSize(fieldID);
3250  if (fieldSize < 0) {
3251  ERReturn(-1);
3252  }
3253 
3254  int offset = 0;
3255  for(int i=0; i<numIDs; ++i) {
3256  NodeDescriptor* node = NULL;
3257 
3258  if ( nodeDatabase_->getNodeWithID(IDs[i], node) != 0 ) {
3259  // fei::console_out() << "SNL_FEI_Structure::getEqnNumbers: ERROR getting node " << IDs[i] << FEI_ENDL;
3260  for(int ii=0; ii<fieldSize; ii++) {
3261  eqnNumbers[offset++] = -1;
3262  }
3263  continue;
3264  // ERReturn(-1);
3265  }
3266 
3267  int nodeFieldEqnNumber = -1;
3268 
3269  if ( !node->getFieldEqnNumber(fieldID, nodeFieldEqnNumber) ) {
3270  //if we didn't find a field eqn-number, set eqnNumbers to -1. These
3271  //positions will then be skipped by code that passes the data on down to
3272  //underlying solver objects.
3273  for(int ii=0; ii<fieldSize; ii++) {
3274  eqnNumbers[offset++] = -1;
3275  }
3276  }
3277  else {
3278  //else we did find valid eqn-numbers...
3279  for(int ii=0; ii<fieldSize; ii++) {
3280  eqnNumbers[offset++] = nodeFieldEqnNumber + ii;
3281  }
3282  }
3283  }
3284 
3285  numEqns = fieldSize*numIDs;
3286 
3287  return(FEI_SUCCESS);
3288 }
3289 
3290 //------------------------------------------------------------------------------
3292 {
3293  if (proc != localProc_) {
3294  return(nodeNumber - globalNumNodesVanished_[proc]);
3295  }
3296 
3297  int insertPoint = -1;
3298  int index =
3299  fei::binarySearch(nodeNumber, localVanishedNodeNumbers_, insertPoint);
3300 
3301  int localAdjustment = index < 0 ? insertPoint : index + 1;
3302 
3303  return(nodeNumber - localAdjustment - globalNumNodesVanished_[proc]);
3304 }
3305 
3306 //------------------------------------------------------------------------------
3307 void SNL_FEI_Structure::getEqnBlkInfo(int& numGlobalEqnBlks,
3308  int& numLocalEqnBlks,
3309  int& localBlkOffset) {
3310 
3311  numGlobalEqnBlks = numGlobalEqnBlks_;
3312  numLocalEqnBlks = numLocalEqnBlks_;
3313  localBlkOffset = localBlkOffset_;
3314 }
3315 
3316 //------------------------------------------------------------------------------
3318 {
3319  FEI_OSTREAM& os = dbgOut();
3320  if (debugOutput_) os << "# calculateSlaveEqns" << FEI_ENDL;
3321 
3322  if (eqnCommMgr_ != NULL) delete eqnCommMgr_;
3323  eqnCommMgr_ = new EqnCommMgr(comm_);
3324  eqnCommMgr_->setNumRHSs(1);
3325 
3326  std::vector<int> eqns;
3327  std::vector<int> mEqns;
3328  std::vector<double> mCoefs;
3329 
3330  for(size_t i=0; i<slaveVars_->size(); i++) {
3331  int numEqns;
3332  SlaveVariable* svar = (*slaveVars_)[i];
3333 
3334  eqns.resize( getFieldSize(svar->getFieldID()));
3335  CHK_ERR( getEqnNumbers(svar->getNodeID(), FEI_NODE, svar->getFieldID(),
3336  numEqns, &eqns[0]));
3337 
3338  int slaveEqn = eqns[svar->getFieldOffset()];
3339 
3340  const std::vector<GlobalID>* mNodes = svar->getMasterNodeIDs();
3341  const std::vector<int>* mFields = svar->getMasterFields();
3342  const std::vector<double>* mWeights = svar->getWeights();
3343  const std::vector<double>& mWeightsRef = *mWeights;
3344  int mwOffset = 0;
3345 
3346  for(size_t j=0; j<mNodes->size(); j++) {
3347  int mfSize = getFieldSize((*mFields)[j]);
3348 
3349  eqns.resize(mfSize);
3350  GlobalID mNodeID = (*mNodes)[j];
3351  int mFieldID = (*mFields)[j];
3352  CHK_ERR( getEqnNumbers( mNodeID, FEI_NODE, mFieldID,
3353  mfSize, &eqns[0]));
3354 
3355  double fei_eps = 1.e-49;
3356 
3357  for(int k=0; k<mfSize; k++) {
3358  if (std::abs(mWeightsRef[mwOffset++]) > fei_eps) {
3359  mEqns.push_back(eqns[k]);
3360  mCoefs.push_back(mWeightsRef[mwOffset-1]);
3361  }
3362  }
3363  }
3364 
3365  CHK_ERR( slaveEqns_->addEqn(slaveEqn, &mCoefs[0], &mEqns[0],
3366  mEqns.size(), false) );
3367  mEqns.resize(0);
3368  mCoefs.resize(0);
3369  }
3370 
3371 #ifndef FEI_SER
3372  int numLocalSlaves = slaveVars_->size();
3373  int globalMaxSlaves = 0;
3374  CHK_ERR( fei::GlobalMax(comm_, numLocalSlaves, globalMaxSlaves) );
3375 
3376  if (globalMaxSlaves > 0) {
3378  }
3379 #endif
3380 
3381  globalNumNodesVanished_.resize(numProcs_+1, 0);
3382 
3384  numSlvs_ = slvEqnNumbers_->size();
3385  if (numSlvs_ > 0) {
3386  //first, let's remove any 'couplings' among the slave equations. A coupling
3387  //is where a slave depends on a master which is also a slave that depends on
3388  //other masters.
3389 
3390  if (debugOutput_) {
3391  os << "# slave-equations:" << FEI_ENDL;
3392  os << *slaveEqns_;
3393  os << "# leaving calculateSlaveEqns" << FEI_ENDL;
3394  }
3395 
3396  int levelsOfCoupling;
3397  CHK_ERR( removeCouplings(*slaveEqns_, levelsOfCoupling) );
3398 
3399  if (debugOutput_) {
3400  os << "# SNL_FEI_Structure: " << levelsOfCoupling
3401  << " level(s) of coupling removed: " << FEI_ENDL;
3402  }
3403 
3404  lowestSlv_ = (*slvEqnNumbers_)[0];
3405  highestSlv_ = (*slvEqnNumbers_)[numSlvs_-1];
3406 
3407  //For each slave equation, we need to find out if we (the local proc) either
3408  //own or share the node from which that equation arises. If we own or share
3409  //a slave node, then we will need access to the solution for each of the
3410  //associated master equations, and all other processors that share the slave
3411  //will also need access to all of the master solutions.
3412  //So,
3413  // 1. for each slave node that we share but don't own, we need to add the
3414  // master equations to the eqnCommMgr_ object using addRemoteIndices, if
3415  // they're not local.
3416  // 2. for each slave node that we own, we need to add the master equations
3417  // to the eqnCommMgr_ object using addLocalEqn for each processor that
3418  // shares the slave node.
3419 
3420  std::vector<int>& slvEqns = *slvEqnNumbers_;
3421  std::vector<fei::CSVec*>& mstrEqns = slaveEqns_->eqns();
3422 
3423  //keep track of the number of locally owned nodes that vanish due to the
3424  //fact that all equations at that node are slave equations.
3425  int numLocalNodesVanished = 0;
3426 
3427  GlobalID lastNodeID = -1;
3428 
3429  for(int i=0; i<numSlvs_; i++) {
3430  const NodeDescriptor* node = NULL;
3431  int reducedSlaveEqn;
3432  translateToReducedEqn(slvEqns[i], reducedSlaveEqn);
3433  int numMasters = mstrEqns[i]->size();
3434 
3435  int err = nodeDatabase_->getNodeWithEqn(slvEqns[i], node);
3436  if (err != 0) {
3437  if (debugOutput_) {
3438  os << "# no local node for slave eqn " << slvEqns[i] << FEI_ENDL;
3439  }
3440 
3441  continue;
3442  }
3443 
3444  if (node->getGlobalNodeID() != lastNodeID &&
3445  node->getOwnerProc() == localProc_) {
3446  if (nodalEqnsAllSlaves(node, slvEqns)) {
3447  numLocalNodesVanished++;
3449  == -2) {
3450  ERReturn(-1);
3451  }
3452  }
3453  lastNodeID = node->getGlobalNodeID();
3454  }
3455 
3456  GlobalID slvNodeID = node->getGlobalNodeID();
3457  int shIndex = nodeCommMgr_->getSharedNodeIndex(slvNodeID);
3458  if (shIndex < 0) {
3459  continue;
3460  }
3461 
3462  std::vector<int>& sharingProcs = nodeCommMgr_->getSharedNodeProcs(shIndex);
3463 
3464  for(int j=0; j<numMasters; j++) {
3465  int masterEquation = mstrEqns[i]->indices()[j];
3466  int owner = getOwnerProcForEqn( masterEquation );
3467 
3468  int reducedMasterEqn;
3469  translateToReducedEqn(masterEquation, reducedMasterEqn);
3470 
3471  if (owner == localProc_) {
3472  int numSharing = sharingProcs.size();
3473  for(int sp=0; sp<numSharing; sp++) {
3474  if (sharingProcs[sp] == localProc_) continue;
3475 
3476  if (debugOutput_) {
3477  os << "# slave node " << (int)slvNodeID << ",eqn "<<slvEqns[i]
3478  << ", master eqn " << masterEquation << " eqnCommMgr_->addLocal "
3479  << reducedMasterEqn << ", proc " << sharingProcs[sp] << FEI_ENDL;
3480  }
3481  eqnCommMgr_->addLocalEqn(reducedMasterEqn, sharingProcs[sp]);
3482  slvCommMgr_->addRemoteIndices(reducedSlaveEqn, sharingProcs[sp],
3483  &reducedMasterEqn, 1);
3484  }
3485  }
3486  else {
3487  if (debugOutput_) {
3488  os << "# slave node " << (int)slvNodeID << ",eqn "<<slvEqns[i]
3489  << ", master eqn " << masterEquation << " eqnCommMgr_->addRemote "
3490  << reducedMasterEqn << ", proc " << owner << FEI_ENDL;
3491  }
3492  eqnCommMgr_->addRemoteIndices(reducedMasterEqn, owner,
3493  &reducedMasterEqn, 1);
3494  slvCommMgr_->addLocalEqn(reducedSlaveEqn, owner);
3495  }
3496  }
3497  }
3498 
3499  std::vector<int> tmp(1), tmp2(numProcs_);
3500  tmp[0] = numLocalNodesVanished;
3502 
3503  if ((int)globalNumNodesVanished_.size() != numProcs_) {
3504  ERReturn(-1);
3505  }
3506 
3508  int tmpNumVanished = 0;
3509  for(int proc=0; proc<numProcs_; ++proc) {
3510  int temporary = tmpNumVanished;
3511  tmpNumVanished += globalNumNodesVanished_[proc];
3512  globalNumNodesVanished_[proc] = temporary;
3513  }
3514  globalNumNodesVanished_[numProcs_] = tmpNumVanished;
3515  }
3516 
3517  if (slaveMatrix_ != NULL) delete slaveMatrix_;
3519 
3520  if (debugOutput_) {
3521  os << "# slave-equations:" << FEI_ENDL;
3522  os << *slaveEqns_;
3523  os << "# leaving calculateSlaveEqns" << FEI_ENDL;
3524  }
3525 
3526  return(0);
3527 }
3528 
3529 //------------------------------------------------------------------------------
3530 int SNL_FEI_Structure::removeCouplings(EqnBuffer& eqnbuf, int& levelsOfCoupling)
3531 {
3532  std::vector<int>& eqnNumbers = eqnbuf.eqnNumbers();
3533  std::vector<fei::CSVec*>& eqns = eqnbuf.eqns();
3534 
3535  std::vector<double> tempCoefs;
3536  std::vector<int> tempIndices;
3537 
3538  levelsOfCoupling = 0;
3539  bool finished = false;
3540  while(!finished) {
3541  bool foundCoupling = false;
3542  for(size_t i=0; i<eqnNumbers.size(); i++) {
3543  int rowIndex = eqnbuf.isInIndices(eqnNumbers[i]);
3544 
3545  if (rowIndex == (int)i) {
3546  fei::console_out() <<" SNL_FEI_Structure::removeCouplings ERROR,"
3547  << " illegal master-slave constraint coupling. Eqn "
3548  << eqnNumbers[i] << " is both master and slave. " << FEI_ENDL;
3549  ERReturn(-1);
3550  }
3551 
3552  while(rowIndex >= 0) {
3553  foundCoupling = true;
3554  double coef = 0.0;
3555  CHK_ERR( eqnbuf.getCoefAndRemoveIndex( eqnNumbers[rowIndex],
3556  eqnNumbers[i], coef) );
3557 
3558  std::vector<int>& indicesRef = eqns[i]->indices();
3559  std::vector<double>& coefsRef = eqns[i]->coefs();
3560 
3561  int len = indicesRef.size();
3562  tempCoefs.resize(len);
3563  tempIndices.resize(len);
3564 
3565  double* tempCoefsPtr = &tempCoefs[0];
3566  int* tempIndicesPtr = &tempIndices[0];
3567  double* coefsPtr = &coefsRef[0];
3568  int* indicesPtr = &indicesRef[0];
3569 
3570  for(int j=0; j<len; ++j) {
3571  tempIndicesPtr[j] = indicesPtr[j];
3572  tempCoefsPtr[j] = coef*coefsPtr[j];
3573  }
3574 
3575  CHK_ERR( eqnbuf.addEqn(eqnNumbers[rowIndex], tempCoefsPtr,
3576  tempIndicesPtr, len, true) );
3577 
3578  rowIndex = eqnbuf.isInIndices(eqnNumbers[i]);
3579  }
3580  }
3581  if (foundCoupling) ++levelsOfCoupling;
3582  else finished = true;
3583 
3584  if (levelsOfCoupling>1 && !finished) {
3585  fei::console_out() <<" SNL_FEI_Structure::removeCouplings ERROR,"
3586  << " too many (>1) levels of master-slave constraint coupling. "
3587  << "Hint: coupling is considered infinite if two slaves depend on "
3588  << "each other. This may or may not be the case here." << FEI_ENDL;
3589  ERReturn(-1);
3590  }
3591  }
3592 
3593  return(0);
3594 }
3595 
3596 #ifndef FEI_SER
3597 //------------------------------------------------------------------------------
3599  EqnCommMgr* eqnCommMgr,
3600  EqnBuffer* slaveEqns)
3601 {
3602  int numProcs = 0;
3603  if (MPI_Comm_size(comm, &numProcs) != MPI_SUCCESS) return(-1);
3604  if (numProcs == 1) return(0);
3605  int localProc;
3606  if (MPI_Comm_rank(comm, &localProc) != MPI_SUCCESS) return(-1);
3607 
3608  //We're going to send all of our slave equations to all other processors, and
3609  //receive the slave equations from all other processors.
3610  //So we'll first fill a ProcEqns object with all of our eqn/proc pairs,
3611  //then use the regular exchange functions from EqnCommMgr.
3612  ProcEqns localProcEqns, remoteProcEqns;
3613  std::vector<int>& slvEqnNums = slaveEqns->eqnNumbers();
3614  fei::CSVec** slvEqnsPtr = NULL;
3615  if (slaveEqns->eqns().size() > 0) slvEqnsPtr = &(slaveEqns->eqns()[0]);
3616 
3617  for(size_t i=0; i<slvEqnNums.size(); i++) {
3618  for(int p=0; p<numProcs; p++) {
3619  if (p == localProc) continue;
3620 
3621  localProcEqns.addEqn(slvEqnNums[i], slvEqnsPtr[i]->size(), p);
3622  }
3623  }
3624 
3625  CHK_ERR( eqnCommMgr->mirrorProcEqns(localProcEqns, remoteProcEqns) );
3626 
3627  CHK_ERR( eqnCommMgr->mirrorProcEqnLengths(localProcEqns,
3628  remoteProcEqns));
3629 
3630  EqnBuffer remoteEqns;
3631  CHK_ERR( EqnCommMgr::exchangeEqnBuffers(comm, &localProcEqns, slaveEqns,
3632  &remoteProcEqns, &remoteEqns,
3633  false) );
3634 
3635  //Now the remoteEqns buffer should hold the slave equations from all other
3636  //processors, so let's add them to the ones we already have.
3637  CHK_ERR( slaveEqns->addEqns(remoteEqns, false) );
3638 
3639  return(0);
3640 }
3641 #endif
3642 
3643 //------------------------------------------------------------------------------
3645 {
3646  if (numSlvs_ == 0) return(false);
3647 
3648  std::vector<int>& slvEqns = slaveEqns_->eqnNumbers();
3649  int insertPoint = -1;
3650  int foundOffset = fei::binarySearch(eqn, slvEqns, insertPoint);
3651 
3652  if (foundOffset >= 0) return(true);
3653  else return(false);
3654 }
3655 
3656 //------------------------------------------------------------------------------
3657 bool SNL_FEI_Structure::translateToReducedEqn(int eqn, int& reducedEqn)
3658 {
3659  if (numSlvs_ == 0) { reducedEqn = eqn; return(false); }
3660 
3661  if (eqn < lowestSlv_) {reducedEqn = eqn; return(false); }
3662  if (eqn > highestSlv_) {reducedEqn = eqn - numSlvs_; return(false); }
3663 
3664  int index = 0;
3665  int foundOffset = fei::binarySearch(eqn, *slvEqnNumbers_, index);
3666 
3667  bool isSlave = false;
3668 
3669  if (foundOffset < 0) {
3670  reducedEqn = eqn - index;
3671  }
3672  else {
3673  isSlave = true; reducedEqn = eqn - (foundOffset+1);
3674  }
3675 
3676  return(isSlave);
3677 }
3678 
3679 //------------------------------------------------------------------------------
3681 {
3682  int numSlvs = slaveEqns_->getNumEqns();
3683 
3684  if (numSlvs == 0) return(reducedEqn);
3685 
3686  const int* slvEqns = &(slaveEqns_->eqnNumbers()[0]);
3687 
3688  if (reducedEqn < slvEqns[0]) return(reducedEqn);
3689 
3690  int eqn = reducedEqn;
3691 
3692  for(int i=0; i<numSlvs; i++) {
3693  if (eqn < slvEqns[i]) return(eqn);
3694  eqn++;
3695  }
3696 
3697  return(eqn);
3698 }
3699 
3700 //------------------------------------------------------------------------------
3702  std::vector<int>*& masterEqns)
3703 {
3704  if (slaveEqns_->getNumEqns() == 0) {
3705  masterEqns = NULL;
3706  return(0);
3707  }
3708 
3709  std::vector<int>& slvEqns = slaveEqns_->eqnNumbers();
3710  int index = 0;
3711  int foundOffset = fei::binarySearch(slaveEqn, slvEqns, index);
3712 
3713  if (foundOffset >= 0) {
3714  masterEqns = &(slaveEqns_->eqns()[foundOffset]->indices());
3715  }
3716  else {
3717  masterEqns = NULL;
3718  }
3719 
3720  return(0);
3721 }
3722 
3723 //------------------------------------------------------------------------------
3725  std::vector<double>*& masterCoefs)
3726 {
3727  if (slaveEqns_->getNumEqns() == 0) {
3728  masterCoefs = NULL;
3729  return(0);
3730  }
3731 
3732  std::vector<int>& slvEqns = slaveEqns_->eqnNumbers();
3733  int index = 0;
3734  int foundOffset = fei::binarySearch(slaveEqn, slvEqns, index);
3735 
3736  if (foundOffset >= 0) {
3737  masterCoefs = &(slaveEqns_->eqns()[foundOffset]->coefs());
3738  }
3739  else {
3740  masterCoefs = NULL;
3741  }
3742 
3743  return(0);
3744 }
3745 
3746 //------------------------------------------------------------------------------
3748  double& rhsValue)
3749 {
3750  if (slaveEqns_->getNumEqns() == 0) {
3751  return(0);
3752  }
3753 
3754  std::vector<int>& slvEqns = slaveEqns_->eqnNumbers();
3755  int index = 0;
3756  int foundOffset = fei::binarySearch(slaveEqn, slvEqns, index);
3757 
3758  if (foundOffset >= 0) {
3759  std::vector<double>* rhsCoefsPtr = (*(slaveEqns_->rhsCoefsPtr()))[foundOffset];
3760  rhsValue = (*rhsCoefsPtr)[0];
3761  }
3762 
3763  return(0);
3764 }
3765 
3766 //------------------------------------------------------------------------------
3768  int interleaveStrategy,
3769  int* scatterIndices)
3770 {
3771  int index = fei::binarySearch(blockID, blockIDs_);
3772 
3773  if (index < 0) {
3774  fei::console_out() << "SNL_FEI_Structure::getScatterIndices_ID: ERROR, blockID "
3775  << (int)blockID << " not found. Aborting." << FEI_ENDL;
3776  std::abort();
3777  }
3778 
3779  std::map<GlobalID,int>& elemIDs = connTables_[index]->elemIDs;
3780 
3781  std::map<GlobalID,int>::const_iterator
3782  iter = elemIDs.find(elemID);
3783 
3784  if (iter == elemIDs.end()) {
3785  fei::console_out() << "SNL_FEI_Structure::getScatterIndices_ID: ERROR, blockID: "
3786  << (int)blockID << ", elemID "
3787  << (int)elemID << " not found. Aborting." << FEI_ENDL;
3788  std::abort();
3789  }
3790 
3791  int elemIndex = iter->second;
3792 
3793  getScatterIndices_index(index, elemIndex,
3794  interleaveStrategy, scatterIndices);
3795 }
3796 
3797 //------------------------------------------------------------------------------
3799  int interleaveStrategy,
3800  int* scatterIndices,
3801  int* blkScatterIndices,
3802  int* blkSizes)
3803 {
3804  int index = fei::binarySearch(blockID, blockIDs_);
3805 
3806  if (index < 0) {
3807  fei::console_out() << "SNL_FEI_Structure::getScatterIndices_ID: ERROR, blockID "
3808  << (int)blockID << " not found. Aborting." << FEI_ENDL;
3809  std::abort();
3810  }
3811 
3812  std::map<GlobalID,int>& elemIDs = connTables_[index]->elemIDs;
3813 
3814  std::map<GlobalID,int>::const_iterator
3815  iter = elemIDs.find(elemID);
3816 
3817  if (iter == elemIDs.end()) {
3818  fei::console_out() << "SNL_FEI_Structure::getScatterIndices_ID: ERROR, blockID: "
3819  << (int)blockID << ", elemID "
3820  << (int)elemID << " not found. Aborting." << FEI_ENDL;
3821  std::abort();
3822  }
3823 
3824  int elemIndex = iter->second;
3825 
3826  getScatterIndices_index(index, elemIndex,
3827  interleaveStrategy, scatterIndices,
3828  blkScatterIndices, blkSizes);
3829 }
3830 
3831 //------------------------------------------------------------------------------
3833  int elemIndex,
3834  int* scatterIndices)
3835 {
3836  BlockDescriptor& block = *(blocks_[blockIndex]);
3837  int numNodes = block.getNumNodesPerElement();
3838  work_nodePtrs_.resize(numNodes);
3839  NodeDescriptor** nodes = &work_nodePtrs_[0];
3840  int err = getElemNodeDescriptors(blockIndex, elemIndex, nodes);
3841  if (err) {
3842  fei::console_out() << "SNL_FEI_Structure::getBlkScatterIndices_index: ERROR getting"
3843  << " node descriptors." << FEI_ENDL;
3844  ERReturn(-1);
3845  }
3846 
3847  int offset = 0;
3848  return( getNodeBlkIndices(nodes, numNodes, scatterIndices, offset) );
3849 }
3850 
3851 //------------------------------------------------------------------------------
3852 void SNL_FEI_Structure::getScatterIndices_index(int blockIndex, int elemIndex,
3853  int interleaveStrategy,
3854  int* scatterIndices)
3855 {
3856 //On input, scatterIndices, is assumed to be allocated by the calling code,
3857 // and be of length the number of equations per element.
3858 //
3859  BlockDescriptor& block = *(blocks_[blockIndex]);
3860  int numNodes = block.getNumNodesPerElement();
3861  int* fieldsPerNode = block.fieldsPerNodePtr();
3862  int** fieldIDs = block.fieldIDsTablePtr();
3863 
3864  work_nodePtrs_.resize(numNodes);
3865  NodeDescriptor** nodes = &work_nodePtrs_[0];
3866 
3867  int err = getElemNodeDescriptors(blockIndex, elemIndex, nodes);
3868  if (err) {
3869  fei::console_out() << "SNL_FEI_Structure::getScatterIndices_index: ERROR getting"
3870  << " node descriptors." << FEI_ENDL;
3871  std::abort();
3872  }
3873 
3874  int offset = 0;
3875  if (fieldDatabase_->size() == 1) {
3876  err = getNodeIndices_simple(nodes, numNodes, fieldIDs[0][0],
3877  scatterIndices, offset);
3878  if (err) fei::console_out() << "ERROR in getNodeIndices_simple." << FEI_ENDL;
3879  }
3880  else {
3881  switch (interleaveStrategy) {
3882  case 0:
3883  err = getNodeMajorIndices(nodes, numNodes, fieldIDs, fieldsPerNode,
3884  scatterIndices, offset);
3885  if (err) fei::console_out() << "ERROR in getNodeMajorIndices." << FEI_ENDL;
3886  break;
3887 
3888  case 1:
3889  err = getFieldMajorIndices(nodes, numNodes, fieldIDs, fieldsPerNode,
3890  scatterIndices, offset);
3891  if (err) fei::console_out() << "ERROR in getFieldMajorIndices." << FEI_ENDL;
3892  break;
3893 
3894  default:
3895  fei::console_out() << "ERROR, unrecognized interleaveStrategy." << FEI_ENDL;
3896  break;
3897  }
3898  }
3899 
3900  //now the element-DOF.
3901  int numElemDOF = blocks_[blockIndex]->getNumElemDOFPerElement();
3902  std::vector<int>& elemDOFEqns = blocks_[blockIndex]->elemDOFEqnNumbers();
3903 
3904  for(int i=0; i<numElemDOF; i++) {
3905  scatterIndices[offset++] = elemDOFEqns[elemIndex] + i;
3906  }
3907 }
3908 
3909 //------------------------------------------------------------------------------
3910 void SNL_FEI_Structure::getScatterIndices_index(int blockIndex, int elemIndex,
3911  int interleaveStrategy,
3912  int* scatterIndices,
3913  int* blkScatterIndices,
3914  int* blkSizes)
3915 {
3916 //On input, scatterIndices, is assumed to be allocated by the calling code,
3917 // and be of length the number of equations per element.
3918 //
3919  BlockDescriptor& block = *(blocks_[blockIndex]);
3920  int numNodes = block.getNumNodesPerElement();
3921  int* fieldsPerNode = block.fieldsPerNodePtr();
3922  int** fieldIDs = block.fieldIDsTablePtr();
3923 
3924  work_nodePtrs_.resize(numNodes);
3925  NodeDescriptor** nodes = &work_nodePtrs_[0];
3926 
3927  int err = getElemNodeDescriptors(blockIndex, elemIndex, nodes);
3928  if (err) {
3929  fei::console_out() << "SNL_FEI_Structure::getScatterIndices_index: ERROR getting"
3930  << " node descriptors." << FEI_ENDL;
3931  std::abort();
3932  }
3933 
3934  int offset = 0, blkOffset = 0;
3935  if (fieldDatabase_->size() == 1) {
3936  err = getNodeIndices_simple(nodes, numNodes, fieldIDs[0][0],
3937  scatterIndices, offset,
3938  blkScatterIndices, blkSizes, blkOffset);
3939  if (err) fei::console_out() << "ERROR in getNodeIndices_simple." << FEI_ENDL;
3940  }
3941  else {
3942  switch (interleaveStrategy) {
3943  case 0:
3944  err = getNodeMajorIndices(nodes, numNodes, fieldIDs, fieldsPerNode,
3945  scatterIndices, offset,
3946  blkScatterIndices, blkSizes, blkOffset);
3947  if (err) fei::console_out() << "ERROR in getNodeMajorIndices." << FEI_ENDL;
3948  break;
3949 
3950  case 1:
3951  err = getFieldMajorIndices(nodes, numNodes, fieldIDs, fieldsPerNode,
3952  scatterIndices, offset);
3953  if (err) fei::console_out() << "ERROR in getFieldMajorIndices." << FEI_ENDL;
3954  break;
3955 
3956  default:
3957  fei::console_out() << "ERROR, unrecognized interleaveStrategy." << FEI_ENDL;
3958  break;
3959  }
3960  }
3961 
3962  //now the element-DOF.
3963  int numElemDOF = blocks_[blockIndex]->getNumElemDOFPerElement();
3964  std::vector<int>& elemDOFEqns = blocks_[blockIndex]->elemDOFEqnNumbers();
3965 
3966  for(int i=0; i<numElemDOF; i++) {
3967  scatterIndices[offset++] = elemDOFEqns[elemIndex] + i;
3968  if (interleaveStrategy == 0) {
3969  blkSizes[blkOffset] = 1;
3970  blkScatterIndices[blkOffset++] = elemDOFEqns[elemIndex] + i;
3971  }
3972  }
3973 }
3974 
3975 //------------------------------------------------------------------------------
3976 int SNL_FEI_Structure::getElemNodeDescriptors(int blockIndex, int elemIndex,
3977  NodeDescriptor** nodes)
3978 {
3979  //Private function, called by 'getScatterIndices_index'. We can safely
3980  //assume that blockIndex and elemIndex are valid in-range indices.
3981  //
3982  //This function's task is to obtain the NodeDescriptor objects, from the
3983  //nodeDatabase, that are connected to the specified element.
3984  //
3985  int numNodes = connTables_[blockIndex]->numNodesPerElem;
3986 
3988  NodeDescriptor** elemNodePtrs =
3989  &((*connTables_[blockIndex]->elem_conn_ptrs)[elemIndex*numNodes]);
3990  for(int i=0; i<numNodes; ++i) nodes[i] = elemNodePtrs[i];
3991  }
3992  else {
3993  const GlobalID* elemConn =
3994  &((*connTables_[blockIndex]->elem_conn_ids)[elemIndex*numNodes]);
3995  for(int i=0; i<numNodes; ++i) {
3996  CHK_ERR( nodeDatabase_->getNodeWithID(elemConn[i], nodes[i]));
3997  }
3998  }
3999 
4000  return(FEI_SUCCESS);
4001 }
4002 
4003 //------------------------------------------------------------------------------
4005  int numNodes,
4006  int fieldID,
4007  int* scatterIndices,
4008  int& offset)
4009 {
4010  int fieldSize = getFieldSize(fieldID);
4011 
4012  for(int nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
4013  NodeDescriptor& node = *(nodes[nodeIndex]);
4014  const int* eqnNumbers = node.getFieldEqnNumbers();
4015  int eqn = eqnNumbers[0];
4016  scatterIndices[offset++] = eqn;
4017  if (fieldSize > 1) {
4018  for(int i=1; i<fieldSize; i++) {
4019  scatterIndices[offset++] = eqn+i;
4020  }
4021  }
4022  }
4023  return(0);
4024 }
4025 
4026 //------------------------------------------------------------------------------
4028  int numNodes,
4029  int fieldID,
4030  int* scatterIndices,
4031  int& offset,
4032  int* blkScatterIndices,
4033  int* blkSizes,
4034  int& blkOffset)
4035 {
4036  int fieldSize = getFieldSize(fieldID);
4037 
4038  for(int nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
4039  NodeDescriptor& node = *(nodes[nodeIndex]);
4040  const int* eqnNumbers = node.getFieldEqnNumbers();
4041  int eqn = eqnNumbers[0];
4042  scatterIndices[offset++] = eqn;
4043  if (fieldSize > 1) {
4044  for(int i=1; i<fieldSize; i++) {
4045  scatterIndices[offset++] = eqn+i;
4046  }
4047  }
4048  blkSizes[blkOffset] = node.getNumNodalDOF();
4049  blkScatterIndices[blkOffset++] = node.getBlkEqnNumber();
4050  }
4051  return(0);
4052 }
4053 
4054 //------------------------------------------------------------------------------
4056  int** fieldIDs, int* fieldsPerNode,
4057  int* scatterIndices, int& offset)
4058 {
4059  for(int nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
4060 
4061  NodeDescriptor& node = *(nodes[nodeIndex]);
4062 
4063  const int* nodeFieldIDList = node.getFieldIDList();
4064  const int* nodeEqnNums = node.getFieldEqnNumbers();
4065  int numFields = node.getNumFields();
4066 
4067  int* fieldID_ind = fieldIDs[nodeIndex];
4068 
4069  for(int j=0; j<fieldsPerNode[nodeIndex]; j++) {
4070  int numEqns = getFieldSize(fieldID_ind[j]);
4071  assert(numEqns >= 0);
4072 
4073  int insert = -1;
4074  int nind = fei::binarySearch(fieldID_ind[j], nodeFieldIDList,
4075  numFields, insert);
4076 
4077  if (nind >= 0) {
4078  int eqn = nodeEqnNums[nind];
4079 
4080  if (eqn < 0) {
4081  FEI_COUT << "SNL_FEI_Structure::getNodeMajorIndices: ERROR, node "
4082  << (int)node.getGlobalNodeID()
4083  << ", field " << nodeFieldIDList[nind]
4084  << " has equation number " << eqn << FEI_ENDL;
4085  std::abort();
4086  }
4087 
4088  for(int jj=0; jj<numEqns; jj++) {
4089  scatterIndices[offset++] = eqn+jj;
4090  }
4091  }
4092  else {
4093  if (outputLevel_ > 2) {
4094  fei::console_out() << "WARNING, field ID " << fieldIDs[nodeIndex][j]
4095  << " not found for node "
4096  << (int)(node.getGlobalNodeID()) << FEI_ENDL;
4097  }
4098  }
4099  }
4100  }
4101 
4102  return(FEI_SUCCESS);
4103 }
4104 
4105 //------------------------------------------------------------------------------
4107  int numNodes,
4108  int* scatterIndices,
4109  int& offset)
4110 {
4111  for(int nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
4112  NodeDescriptor* node = nodes[nodeIndex];
4113  scatterIndices[offset++] = node->getBlkEqnNumber();
4114  }
4115  return(0);
4116 }
4117 
4118 //------------------------------------------------------------------------------
4120  int** fieldIDs, int* fieldsPerNode,
4121  int* scatterIndices, int& offset,
4122  int* blkScatterIndices,
4123  int* blkSizes,
4124  int& blkOffset)
4125 {
4126  for(int nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
4127 
4128  NodeDescriptor& node = *(nodes[nodeIndex]);
4129 
4130  const int* nodeFieldIDList = node.getFieldIDList();
4131  const int* nodeEqnNums = node.getFieldEqnNumbers();
4132  int numFields = node.getNumFields();
4133 
4134  blkSizes[blkOffset] = node.getNumNodalDOF();
4135  blkScatterIndices[blkOffset++] = node.getBlkEqnNumber();
4136 
4137  int* fieldID_ind = fieldIDs[nodeIndex];
4138 
4139  for(int j=0; j<fieldsPerNode[nodeIndex]; j++) {
4140  int numEqns = getFieldSize(fieldID_ind[j]);
4141  assert(numEqns >= 0);
4142 
4143  int insert = -1;
4144  int nind = fei::binarySearch(fieldID_ind[j], nodeFieldIDList,
4145  numFields, insert);
4146 
4147  if (nind >= 0) {
4148  int eqn = nodeEqnNums[nind];
4149  if (eqn < 0) {
4150  FEI_COUT << "SNL_FEI_Structure::getNodeMajorIndices: ERROR, node "
4151  << (int)node.getGlobalNodeID()
4152  << ", field " << nodeFieldIDList[nind]
4153  << " has equation number " << eqn << FEI_ENDL;
4154  std::abort();
4155  }
4156 
4157  for(int jj=0; jj<numEqns; jj++) {
4158  scatterIndices[offset++] = eqn+jj;
4159  }
4160  }
4161  else {
4162  if (outputLevel_ > 2) {
4163  fei::console_out() << "WARNING, field ID " << fieldIDs[nodeIndex][j]
4164  << " not found for node "
4165  << (int)(node.getGlobalNodeID()) << FEI_ENDL;
4166  }
4167  }
4168  }
4169  }
4170 
4171  return(FEI_SUCCESS);
4172 }
4173 
4174 //------------------------------------------------------------------------------
4176  std::vector<int>* fieldIDs,
4177  std::vector<int>& fieldsPerNode,
4178  std::vector<int>& scatterIndices)
4179 {
4180  int offset = 0;
4181  scatterIndices.resize(0);
4182 
4183  for(int nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
4184 
4185  NodeDescriptor& node = *(nodes[nodeIndex]);
4186 
4187  const int* nodeFieldIDList = node.getFieldIDList();
4188  const int* nodeEqnNums = node.getFieldEqnNumbers();
4189  int numFields = node.getNumFields();
4190 
4191  int* fieldID_ind = &(fieldIDs[nodeIndex][0]);
4192 
4193  for(int j=0; j<fieldsPerNode[nodeIndex]; j++) {
4194  int numEqns = getFieldSize(fieldID_ind[j]);
4195  assert(numEqns >= 0);
4196 
4197  int insert = -1;
4198  int nind = fei::binarySearch(fieldID_ind[j], nodeFieldIDList,
4199  numFields, insert);
4200 
4201  if (nind >= 0) {
4202  int eqn = nodeEqnNums[nind];
4203 
4204  if (eqn < 0) {
4205  FEI_COUT << "SNL_FEI_Structure::getNodeMajorIndices: ERROR, node "
4206  << (int)node.getGlobalNodeID()
4207  << ", field " << nodeFieldIDList[nind]
4208  << " has equation number " << eqn << FEI_ENDL;
4209  MPI_Abort(comm_, -1);
4210  }
4211 
4212  scatterIndices.resize(offset+numEqns);
4213  int* inds = &scatterIndices[0];
4214 
4215  for(int jj=0; jj<numEqns; jj++) {
4216  inds[offset+jj] = eqn+jj;
4217  }
4218  offset += numEqns;
4219  }
4220  else {
4221  if (outputLevel_ > 2) {
4222  fei::console_out() << "WARNING, field ID " << fieldID_ind[j]
4223  << " not found for node "
4224  << (int)node.getGlobalNodeID() << FEI_ENDL;
4225  }
4226  }
4227  }
4228  }
4229 
4230  return(FEI_SUCCESS);
4231 }
4232 
4233 //------------------------------------------------------------------------------
4235  int** fieldIDs, int* fieldsPerNode,
4236  int* scatterIndices, int& offset)
4237 {
4238  //In this function we want to group equations by field, but
4239  //in what order should the fields be?
4240  //Let's just run through the fieldIDs table, and add the fields to a
4241  //flat list, in the order we encounter them, but making sure no fieldID
4242  //gets added more than once.
4243 
4244  std::vector<int> fields;
4245  for(int ii=0; ii<numNodes; ii++) {
4246  for(int j=0; j<fieldsPerNode[ii]; j++) {
4247  if (std::find(fields.begin(), fields.end(), fieldIDs[ii][j]) == fields.end()) {
4248  fields.push_back(fieldIDs[ii][j]);
4249  }
4250  }
4251  }
4252 
4253  int* fieldsPtr = fields.size()>0 ? &fields[0] : NULL;
4254 
4255  //ok, we've got our flat list of fields, so let's proceed to get the
4256  //scatter indices.
4257 
4258  for(size_t i=0; i<fields.size(); i++) {
4259  int field = fieldsPtr[i];
4260 
4261  for(int nodeIndex = 0; nodeIndex < numNodes; ++nodeIndex) {
4262  int fidx = fei::searchList(field, fieldIDs[nodeIndex],
4263  fieldsPerNode[nodeIndex]);
4264  if (fidx < 0) {
4265  continue;
4266  }
4267 
4268  NodeDescriptor* node = nodes[nodeIndex];
4269 
4270  const int* nodeFieldIDList = node->getFieldIDList();
4271  const int* nodeEqnNums = node->getFieldEqnNumbers();
4272  int numFields = node->getNumFields();
4273 
4274  int numEqns = getFieldSize(field);
4275  assert(numEqns >= 0);
4276 
4277  int insert = -1;
4278  int nind = fei::binarySearch(field, nodeFieldIDList,
4279  numFields, insert);
4280 
4281  if (nind > -1) {
4282  for(int jj=0; jj<numEqns; ++jj) {
4283  scatterIndices[offset++] = nodeEqnNums[nind]+jj;
4284  }
4285  }
4286  else {
4287  ERReturn(-1);
4288  }
4289  }
4290  }
4291 
4292  return(FEI_SUCCESS);
4293 }
4294 
4295 //------------------------------------------------------------------------------
4297  std::vector<int>* fieldIDs,
4298  std::vector<int>& fieldsPerNode,
4299  std::vector<int>& scatterIndices)
4300 {
4301  //In this function we want to group equations by field, but
4302  //in what order should the fields be?
4303  //Let's just run through the fieldIDs table, and add the fields to a
4304  //flat list, in the order we encounter them, but making sure no fieldID
4305  //gets added more than once.
4306 
4307  std::vector<int> fields;
4308  for(int ii=0; ii<numNodes; ii++) {
4309  for(int j=0; j<fieldsPerNode[ii]; j++) {
4310  std::vector<int>& fldIDs = fieldIDs[ii];
4311  if (std::find(fields.begin(), fields.end(), fldIDs[j]) == fields.end()) {
4312  fields.push_back(fldIDs[j]);
4313  }
4314  }
4315  }
4316 
4317  //ok, we've got our flat list of fields, so let's proceed to get the
4318  //scatter indices.
4319 
4320  int offset = 0;
4321  scatterIndices.resize(0);
4322 
4323  for(size_t i=0; i<fields.size(); i++) {
4324  for(int nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
4325 
4326  const int* nodeFieldIDList = nodes[nodeIndex]->getFieldIDList();
4327  const int* nodeEqnNums = nodes[nodeIndex]->getFieldEqnNumbers();
4328  int numFields = nodes[nodeIndex]->getNumFields();
4329 
4330  int numEqns = getFieldSize(fields[i]);
4331  assert(numEqns >= 0);
4332 
4333  int insert = -1;
4334  int nind = fei::binarySearch(fields[i], nodeFieldIDList,
4335  numFields, insert);
4336 
4337  if (nind >= 0) {
4338  for(int jj=0; jj<numEqns; jj++) {
4339  scatterIndices.push_back(nodeEqnNums[nind]+jj);
4340  offset++;
4341  }
4342  }
4343  else {
4344  if (outputLevel_ > 2) {
4345  fei::console_out() << "WARNING, field ID " << fields[i]
4346  << " not found for node "
4347  << (int)nodes[nodeIndex]->getGlobalNodeID() << FEI_ENDL;
4348  }
4349  }
4350  }
4351  }
4352 
4353  return(FEI_SUCCESS);
4354 }
4355 
4356 //------------------------------------------------------------------------------
4359  std::map<GlobalID,snl_fei::Constraint<GlobalID>* >& crDB)
4360 {
4361  std::map<GlobalID,snl_fei::Constraint<GlobalID>* >::iterator
4362  cr_iter = crDB.find(CRID);
4363 
4364  if (cr_iter == crDB.end()) {
4365  cr = new ConstraintType;
4366  crDB.insert(std::pair<GlobalID,snl_fei::Constraint<GlobalID>*>(CRID, cr));
4367  }
4368 }
void addMasterField(int masterField)
static int exchangeEqnBuffers(MPI_Comm comm, ProcEqns *sendProcEqns, EqnBuffer *sendEqns, ProcEqns *recvProcEqns, EqnBuffer *recvEqns, bool accumulate)
int isInIndices(int eqn)
int setDbgOut(std::ostream &ostr, const char *path, const char *feiName)
std::vector< fei::CSVec * > & localEqns()
int sortedListInsert(const T &item, std::vector< T > &list)
std::vector< BlockDescriptor * > blocks_
int translateMatToReducedEqns(fei::CSRMat &mat)
fei::FieldDofMap< int > fieldDofMap_
void setBlkEqnNumber(int blkEqn)
snl_fei::PointBlockMap * blkEqnMapper_
std::vector< int > & localEqnNumbers()
int createMatrixPositions(int row, int numCols, int *cols, const char *callingFunction)
std::vector< int > & getSharedNodeProcs(int index)
int getFieldSize(int fieldID)
const int * getFieldIDsPtr()
int Allgatherv(MPI_Comm comm, std::vector< T > &sendbuf, std::vector< int > &recvLengths, std::vector< T > &recvbuf)
void f()
std::vector< int > globalNumNodesVanished_
std::ostream & dbgOut()
int getNumFields() const
int countLocalNodeDescriptors(int localRank)
std::vector< int > & getMasterFieldIDs()
int getBlockDescriptor_index(int index, BlockDescriptor *&block)
#define FEI_COUT
std::map< GlobalID, int > & getNodeIDs()
int getNodeWithNumber(int nodeNumber, const NodeDescriptor *&node) const
std::map< GlobalID, snl_fei::Constraint< GlobalID > * > penCRs_
int addSharedNodes(const GlobalID *nodeIDs, int numNodes, const int *const *procs, const int *numProcs)
fei::FillableMat * slaveMatrix_
int getElemNodeDescriptors(int blockIndex, int elemIndex, NodeDescriptor **nodes)
void addWeight(double weight)
int getNumNodalDOF() const
int addEqn(int eqnNumber, const double *coefs, const int *indices, int len, bool accumulate, bool create_indices_union=false)
SNL_FEI_Structure(MPI_Comm comm)
void multiply_CSRMat_CSRMat(const CSRMat &A, const CSRMat &B, CSRMat &C, bool storeResultZeros)
Definition: fei_CSRMat.cpp:189
int getMasterEqnRHS(int slaveEqn, double &rhsValue)
bool nodalEqnsAllSlaves(const NodeDescriptor *node, std::vector< int > &slaveEqns)
int initNodeID(GlobalID nodeID)
int GlobalID
Definition: fei_defs.h:60
std::vector< GlobalID > blockIDs_
std::vector< int > * slvEqnNumbers_
int size() const
const std::vector< GlobalID > * getMasterNodeIDs()
const int * getFieldIDList() const
int ptEqnToBlkEqn(int ptEqn)
std::vector< fei::CSVec * > & eqns()
ProcEqns * getSendProcEqns()
int addRemoteEqns(fei::CSRMat &mat, bool onlyIndices)
int getInterleaveStrategy() const
std::vector< NodeDescriptor * > work_nodePtrs_
void getScatterIndices_index(int blockIndex, int elemIndex, int interleaveStrategy, int *scatterIndices)
snl_fei::PointBlockMap & getBlkEqnMapper()
void setNumEqnsPerElement(int numEqns)
fei::FillableMat * Kdi_
std::vector< int > localVanishedNodeNumbers_
int getMasterEqnCoefs(int slaveEqn, std::vector< double > *&masterCoefs)
int getEqnNumbers(GlobalID ID, int idType, int fieldID, int &numEqns, int *eqnNumbers)
int mirrorProcEqns(ProcEqns &inProcEqns, ProcEqns &outProcEqns)
std::vector< GlobalID > * elem_conn_ids
void addEqn(int eqnNumber, int proc)
std::vector< int > rowNumbers
std::vector< int > & eqnNumbers()
const int * getFieldEqnNumbers() const
fei::FillableMat * getSlaveDependencies()
int storeElementScatterBlkIndices_noSlaves(std::vector< int > &scatterIndices)
void setFieldEqnNumber(int fieldID, int eqn)
static int removeCouplings(EqnBuffer &eqnbuf, int &levelsOfCoupling)
int exchangePtToBlkInfo(snl_fei::PointBlockMap &blkEqnMapper)
void copySetToArray(const SET_TYPE &set_obj, int lenList, int *list)
bool getFieldEqnNumber(int fieldID, int &eqnNumber) const
fei::ctg_set< int > * sysMatIndices_
int createBlkSymmEqnStructure(std::vector< int > &scatterIndices)
int setElemDofFieldIDs(int numFields, const int *fieldIDs)
int storeElementScatterIndices(std::vector< int > &scatterIndices)
#define FEI_FATAL_ERROR
Definition: fei_defs.h:100
const std::vector< double > * getWeights()
#define MPI_Abort(a, b)
Definition: fei_mpi.h:59
void addBlockIndex(unsigned blk_idx)
std::vector< int > fieldSizes_
void getEqnInfo(int &numGlobalEqns, int &numLocalEqns, int &localStartRow, int &localEndRow)
int getSharedNodeIndex(GlobalID nodeID)
void createPosition(int row, int col)
std::vector< int > elemNumbers
#define MPI_Comm
Definition: fei_mpi.h:56
ProcEqns * getRecvProcEqns()
#define MPI_SUCCESS
Definition: fei_mpi.h:62
int createSymmEqnStructure(std::vector< int > &scatterIndices)
int getMasterEqnNumbers(int slaveEqn, std::vector< int > *&masterEqns)
std::vector< int > packedColumnIndices
std::vector< std::vector< double > * > * rhsCoefsPtr()
int initElemBlock(GlobalID elemBlockID, int numElements, int numNodesPerElement, const int *numFieldsPerNode, const int *const *nodalFieldIDs, int numElemDofFieldsPerElement, const int *elemDofFieldIDs, int interleaveStrategy)
std::vector< int > rowOffsets
void setBlkEqnNumber(int blkEqn)
NodeDescriptor & getSharedNodeAtIndex(int index)
void addLocalEqn(int eqnNumber, int srcProc)
NodeDatabase * nodeDatabase_
int initComplete(NodeDatabase &nodeDB, bool safetyCheck)
std::vector< GlobalID > & getLocalNodeIDs()
int binarySearch(const T &item, const T *list, int len)
int getNodeWithEqn(int eqnNumber, const NodeDescriptor *&node) const
int translateToReducedNodeNumber(int nodeNumber, int proc)
void setNumElemDOFPerElement(int ndof)
#define FEI_OSTREAM
Definition: fei_iosfwd.hpp:24
int initFields(int numFields, const int *fieldSizes, const int *fieldIDs, const int *fieldTypes=NULL)
void setFieldID(int fid)
int getMatrixRowLengths(std::vector< int > &rowLengths)
int synchronize(int firstLocalNodeNumber, int firstLocalEqn, int localRank, MPI_Comm comm)
std::vector< int > & elemDOFEqnNumbers()
void setGlobalBlockID(GlobalID blockID)
int getOwnerProc() const
#define FEI_ISTRINGSTREAM
Definition: fei_sstream.hpp:31
std::ostream * dbgOStreamPtr_
int getMatrixStructure(int **colIndices, std::vector< int > &rowLengths)
std::vector< NodeDescriptor * > * elem_conn_ptrs
void add_field(LocalOrdinal fieldID, LocalOrdinal fieldSize, LocalOrdinal fieldType=fei::UNKNOWN)
int initSharedNodes(int numSharedNodes, const GlobalID *sharedNodeIDs, const int *numProcsPerNode, const int *const *sharingProcIDs)
int exchangeIndices(std::ostream *dbgOut=NULL)
EqnBuffer * getRecvEqns()
#define FEI_OFSTREAM
Definition: fei_fstream.hpp:14
int addBlock(GlobalID blockID)
std::vector< std::vector< int > * > & procEqnNumbersPtr()
int calculateSlaveEqns(MPI_Comm comm)
const std::vector< int > * getMasterFields()
void getNodeAtIndex(int i, const NodeDescriptor *&node) const
std::map< GlobalID, snl_fei::Constraint< GlobalID > * > & getPenConstRecords()
std::vector< int > fieldIDs_
fei::ctg_set< int > * sysBlkMatIndices_
void getEqnBlkInfo(int &numGlobalEqnBlks, int &numLocalEqnBlks, int &localBlkOffset)
GlobalID getGlobalNodeID() const
int getNodeMajorIndices(NodeDescriptor **nodes, int numNodes, int **fieldIDs, int *fieldsPerNode, int *scatterIndices, int &offset)
void setFieldOffset(int foff)
int setBlkEqnSize(int blkEqn, int size)
void getScatterIndices_ID(GlobalID blockID, GlobalID elemID, int interleaveStrategy, int *scatterIndices)
std::map< GlobalID, int > elemIDs
void setSharedOwnershipRule(int ownershipRule)
void setNumNodalDOF(int dof)
#define FEI_SUCCESS
Definition: fei_defs.h:99
int informLocal(const NodeDescriptor &node)
void addRemoteIndices(int eqnNumber, int destProc, int *indices, int num)
void insert2(const T &item)
#define ERReturn(a)
int translateToReducedEqns(EqnCommMgr &eqnCommMgr)
std::vector< int > workSpace_
int getCoefAndRemoveIndex(int eqnNumber, int colIndex, double &coef)
#define FEI_NODE
Definition: fei_defs.h:71
int initCRMult(int numCRNodes, const GlobalID *CRNodes, const int *CRFields, int &CRID)
bool isInLocalElement(int nodeNumber)
void storeNodalRowIndices(NodeDescriptor &node, int fieldID, int eqn)
void addSlaveVariable(SlaveVariable *svar)
int initCRPen(int numCRNodes, const GlobalID *CRNodes, const int *CRFields, int &CRID)
int setEqn(int ptEqn, int blkEqn)
const int * getNumFieldsPerNode(GlobalID blockID)
void addCR(int CRID, snl_fei::Constraint< GlobalID > *&cr, std::map< GlobalID, snl_fei::Constraint< GlobalID > * > &crDB)
int getNumLocalEqns()
int eqnToBlkEqn(int eqn) const
int countLocalNodalEqns(int localRank)
int getNumNodesPerElement() const
const char * getParam(const char *key, int numParams, const char *const *paramStrings)
int addEqns(EqnBuffer &inputEqns, bool accumulate)
void addMasterNodeID(GlobalID masterNode)
#define voidERReturn
int getBlkEqnNumber() const
void setInterleaveStrategy(int strat)
int storeElementScatterIndices_noSlaves(std::vector< int > &scatterIndices)
int getBlockDescriptor(GlobalID blockID, BlockDescriptor *&block)
std::map< GlobalID, snl_fei::Constraint< GlobalID > * > multCRs_
#define FEI_ENDL
std::vector< int > globalBlkEqnOffsets_
SparseRowGraph & getGraph()
Definition: fei_CSRMat.hpp:27
bool translateToReducedEqn(int eqn, int &reducedEqn)
ConnectivityTable & getBlockConnectivity(GlobalID blockID)
std::ostream & console_out()
int initSlaveVariable(GlobalID slaveNodeID, int slaveFieldID, int offsetIntoSlaveField, int numMasterNodes, const GlobalID *masterNodeIDs, const int *masterFieldIDs, const double *weights, double rhsValue)
int GlobalMax(MPI_Comm comm, std::vector< T > &local, std::vector< T > &global)
const std::vector< unsigned > & getBlockIndexList() const
void storeNodalSendIndices(NodeDescriptor &iNode, int iField, NodeDescriptor &jNode, int jField)
std::vector< SlaveVariable * > * slaveVars_
std::vector< int > globalNodeOffsets_
int getNodeIndices_simple(NodeDescriptor **nodes, int numNodes, int fieldID, int *scatterIndices, int &offset)
int getOwnerProcForEqn(int eqn)
int getBlkScatterIndices_index(int blockIndex, int elemIndex, int *scatterIndices)
void setIsPenalty(bool isPenaltyConstr)
void multiply_trans_CSRMat_CSRMat(const CSRMat &A, const CSRMat &B, CSRMat &C, bool storeResultZeros)
Definition: fei_CSRMat.cpp:268
int getNodeBlkIndices(NodeDescriptor **nodes, int numNodes, int *scatterIndices, int &offset)
int createMatrixPosition(int row, int col, const char *callingFunction)
int localProc(MPI_Comm comm)
int mirrorProcEqnLengths(ProcEqns &inProcEqns, ProcEqns &outProcEqns)
void setNumBlkEqnsPerElement(int numBlkEqns)
void storeLocalNodeIndices(NodeDescriptor &iNode, int iField, NodeDescriptor &jNode, int jField)
int getLumpingStrategy() const
NodeDescriptor & findNodeDescriptor(GlobalID nodeID)
void setNumRHSs(int numRHSs)
void storeNodalSendIndex(NodeDescriptor &node, int fieldID, int col)
std::map< int, int > * getPtEqns()
std::vector< int > rSlave_
int initElem(GlobalID elemBlockID, GlobalID elemID, const GlobalID *elemConn)
void setNodeID(GlobalID nid)
NodeDescriptor * findNode(GlobalID nodeID)
std::vector< ConnectivityTable * > connTables_
void storeNodalColumnIndices(int eqn, NodeDescriptor &node, int fieldID)
std::vector< int > & getMasters()
std::map< int, int > * fieldDatabase_
void destroyValues(MAP_TYPE &map_obj)
int getNumNodeDescriptors() const
#define CHK_ERR(a)
int translateFromReducedEqn(int reducedEqn)
int getNodeWithID(GlobalID nodeID, const NodeDescriptor *&node) const
void setOwnerProc(int proc)
EqnBuffer * getSendEqns()
int allocateBlockConnectivity(GlobalID blockID)
size_t getNumSharedNodes()
void setNumElements(int numElems)
NodeCommMgr * nodeCommMgr_
void addField(int fieldID)
int parameters(int numParams, const char *const *paramStrings)
GlobalID getNodeID()
int n
snl_fei::Constraint< GlobalID > ConstraintType
fei::FillableMat * Kid_
#define FEI_OSTRINGSTREAM
Definition: fei_sstream.hpp:32
void getElemBlockInfo(GlobalID blockID, int &interleaveStrategy, int &lumpingStrategy, int &numElemDOF, int &numElements, int &numNodesPerElem, int &numEqnsPerElem)
const char * getParamValue(const char *key, int numParams, const char *const *paramStrings, char separator=' ')
void calcGlobalEqnInfo(int numLocallyOwnedNodes, int numLocalEqns, int numLocalEqnBlks)
std::vector< int > globalEqnOffsets_
std::vector< GlobalID > & getSharedNodeIDs()
int searchList(const T &item, const T *list, int len)
int getNodeNumber() const
int initComplete(bool generateGraph=true)
static int gatherSlaveEqns(MPI_Comm comm, EqnCommMgr *eqnCommMgr, EqnBuffer *slaveEqns)
int getFieldMajorIndices(NodeDescriptor **nodes, int numNodes, int **fieldIDs, int *fieldsPerNode, int *scatterIndices, int &offset)
int setNumNodesPerElement(int numNodes)
int numProcs(MPI_Comm comm)
int getIndexOfBlock(GlobalID blockID) const
const int *const * getFieldIDsTable(GlobalID blockID)
int getEqnNumber(int nodeNumber, int fieldID)
int initNodeIDs(GlobalID *nodeIDs, int numNodes)
fei::FillableMat * Kdd_
void setNumDistinctFields(int nFields)
int getNumEqns()