Actual source code: elemvec2d.c

  1: #ifdef PETSC_RCS_HEADER
  2: static char vcid[] = "$Id: elemvec2d.c,v 1.14 2000/01/31 17:51:54 knepley Exp $";
  3: #endif

  5: #include "src/grid/gridimpl.h"         /*I "grid.h" I*/
  6: #include "src/mesh/impls/triangular/triimpl.h"
  7: #include "elemvec2d.h"

  9: /*--------------------------------------------- Element Vector Functions --------------------------------------------*/
 10: int PrintVecIndices_Private(Grid grid, const char option[], int field, int node, int comp, int rowStart, int *rowIdx)
 11: {
 12:   MPI_Comm   comm;
 13:   int        rank;
 14:   int        var;
 15:   PetscTruth opt;
 16:   int        ierr;

 19:   PetscOptionsHasName(PETSC_NULL, option, &opt);
 20:   if (opt == PETSC_FALSE) return(0);
 21:   PetscObjectGetComm((PetscObject) grid, &comm);
 22:   MPI_Comm_rank(comm, &rank);
 23:   PetscPrintf(PETSC_COMM_SELF, "[%d]field: %d node: %dn", rank, field, node);
 24:   for(var = rowStart-comp; var < rowStart; var++)
 25:     PetscPrintf(PETSC_COMM_SELF, "[%d]rowIdx[%d]: %dn", rank, var, rowIdx[var]);
 26:   return(0);
 27: }

 29: /*
 30:   Reduction:

 32:   When the variables associated with boundary conditions are being reduced, the element vector is compressed
 33:   to account for their absence. This reduction only happens in the global numbering. When using the local
 34:   numbering, the original variable numbers are replaced by the corresponding index in grid->bdReduceVec
 35:   which contains the boundary values. In order to distinguish these indices, they are stored as -(idx+1).
 36:   The boundary values are retieved by GridLocalToElement(). The useOldStructs flag signals that we are
 37:   interpolating from a previous mesh, and thus the constraints must be calculated from the previous values.
 38: */
 39: int GridCalcElementVecIndices_Triangular_2D(Grid grid, Mesh mesh, int elem, VarOrdering order, VarOrdering reduceOrder,
 40:                                             PetscTruth localNumbering, PetscTruth useOldStructs, ElementVec vec)
 41: {
 42:   Mesh_Triangular      *tri          = (Mesh_Triangular *) mesh->data;
 43:   int                  *elements     = tri->faces;
 44:   int                   numCorners   = mesh->numCorners;
 45:   int                   numNodes     = mesh->numNodes;
 46:   PetscConstraintObject constCtx     = grid->constraintCtx;
 47:   int                  *firstVar     = order->firstVar;
 48:   int                  *offsets      = order->offsets;
 49:   int                  *localOffsets = order->localOffsets;
 50:   int                 **localStart   = order->localStart;
 51:   int                  *rowIdx       = vec->indices;
 52:   int                   rank         = mesh->part->rank;
 53:   int                   size         = vec->size;
 54:   PetscScalar          *array        = vec->array;
 55:   FieldClassMap         map;
 56:   int                   numFields;
 57:   int                  *fields;
 58:   int                 **fieldClasses, **reduceFieldClasses;
 59:   int                  *classes;
 60:   PetscTruth            isReduced, isConstrained;
 61:   int                  *isConst;
 62:   int                  *reduceFirstVar     = PETSC_NULL;
 63:   int                  *reduceOffsets      = PETSC_NULL;
 64:   int                  *reduceLocalOffsets = PETSC_NULL;
 65:   int                 **reduceLocalStart   = PETSC_NULL;
 66:   int                   field, node, nclass, comp, startVar, diff, inc;
 67:   int                   i, f, count, source, corner, row;
 68:   int                   ierr;

 71:   VarOrderingGetClassMap(order, &map);
 72:   numFields          = map->numFields;
 73:   fields             = map->fields;
 74:   fieldClasses       = map->fieldClasses;
 75:   reduceFieldClasses = map->reduceFieldClasses;
 76:   classes            = map->classes;
 77:   isReduced          = map->isReduced;
 78:   isConstrained      = map->isConstrained;
 79:   isConst            = map->isClassConstrained;
 80:   if (isReduced == PETSC_TRUE) {
 81:     reduceFirstVar     = reduceOrder->firstVar;
 82:     reduceOffsets      = reduceOrder->offsets;
 83:     reduceLocalOffsets = reduceOrder->localOffsets;
 84:     reduceLocalStart   = reduceOrder->localStart;
 85:   }
 86:   for(f = 0, count = 0, source = 0, inc = 0; f < numFields; f++) {
 87:     field = fields[f];
 88:     comp  = grid->fields[field].disc->comp;

 90:     for(corner = 0; corner < numCorners; corner++) {
 91:       node   = elements[elem*numCorners+corner];
 92:       nclass = classes[node];
 93:       if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
 94:         if (localNumbering == PETSC_FALSE) {
 95:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
 96:           source += comp;
 97:           inc    -= comp;
 98:         } else {
 99:           if (node >= numNodes)
100:             startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
101:           else
102:             startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
103:           for(i = 0; i < comp; i++, count++) {
104:             rowIdx[count] = -(startVar + i + 1);
105:           }
106: #ifdef PETSC_USE_BOPT_g
107:           PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
108: #endif
109:         }
110:       } else if ((isConstrained == PETSC_TRUE) && (isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
111:         /* We guarantee that count <= source here */
112:         diff = grid->fields[field].constraintCompDiff;
113:         inc += diff;
114:         /* Move rows to operate on */
115:         if (count < source) {
116:           for(row = 0; row < comp; row++)
117:             array[count+row] = array[source+row];
118:         }
119:         source += comp;
120:         /* We must replace this field with the constraint field and prevent overwriting in element vector */
121:         if (source - count < comp + diff) {
122:           /* Move old fields */
123:           for(row = size-(diff+1); row >= source; row--)
124:             array[row+diff] = array[row];
125:           source += diff;
126:         }
127:         /* Apply P^T to get constraint fields */
128:         (*constCtx->ops->constrainelemvec)(constCtx, mesh, order, field, node, count, localNumbering,
129:                                                   useOldStructs, CONSTRAINT_ROW, vec);
130: 
131:         count += comp + diff;
132:       } else if (fieldClasses[f][nclass]) {
133:         if (localNumbering == PETSC_FALSE) {
134:           startVar = offsets[node] + localStart[field][nclass];
135:         } else {
136:           if (node >= numNodes)
137:             startVar = localOffsets[node-numNodes] + localStart[field][nclass];
138:           else
139:             startVar = offsets[node] - firstVar[rank] + localStart[field][nclass];
140:         }
141:         for(i = 0; i < comp; i++, count++, source++) {
142:           rowIdx[count] = startVar + i;
143:           array[count]  = array[source];
144:         }
145: #ifdef PETSC_USE_BOPT_g
146:         PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
147: #endif
148:       }
149:     }
150:   }
151: #ifdef PETSC_USE_BOPT_g
152:   if (count != vec->reduceSize + inc) {
153:     SETERRQ3(PETSC_ERR_PLIB, "Invalid variable numbering elem: %d size: %d count: %dn", elem, vec->reduceSize+inc, count);
154:   }
155:   if (count > vec->size) {
156:     SETERRQ3(PETSC_ERR_PLIB, "Number of indices %d in elem %d exceeded maximum size %dn", count, elem, vec->size);
157:   }
158: #endif
159:   /* Set true vector size */
160:   vec->reduceSize = count;

162:   return(0);
163: }

165: /*
166:   Projection:

168:   We would like a mechanism to convert from the constrained to unconstrained variables, and vice versa,
169:   for an element vector. This code is also embedded in the element vector index calculation, and could
170:   perhaps be split out. This function is generally called to take a constrained element vector to
171:   unconstrained variables before an element integral is performed.
172: */
173: int GridProjectElementVec_Triangular_2D(Grid grid, Mesh mesh, int elem, VarOrdering order, VarOrdering reduceOrder,
174:                                         PetscTruth constrain, PetscTruth useOldStructs, ElementVec vec)
175: {
176:   Mesh_Triangular      *tri          = (Mesh_Triangular *) mesh->data;
177:   int                  *elements     = tri->faces;
178:   int                   numCorners   = mesh->numCorners;
179:   PetscConstraintObject constCtx     = grid->constraintCtx;
180:   int                   size         = vec->size;
181:   int                  *rowIdx       = vec->indices;
182:   PetscScalar          *array        = vec->array;
183:   FieldClassMap         map;
184:   int                   numFields;
185:   int                  *fields;
186:   int                 **fieldClasses, **reduceFieldClasses;
187:   int                  *classes;
188:   PetscTruth            isReduced, isConstrained;
189:   int                  *isConst;
190:   int                   field, node, nclass, comp, diff, inc;
191:   int                   i, f, count, source, corner, row;
192:   int                   ierr;

195:   VarOrderingGetClassMap(order, &map);
196:   numFields          = map->numFields;
197:   fields             = map->fields;
198:   fieldClasses       = map->fieldClasses;
199:   classes            = map->classes;
200:   isReduced          = map->isReduced;
201:   isConstrained      = map->isConstrained;
202:   isConst            = map->isClassConstrained;
203:   reduceFieldClasses = map->reduceFieldClasses;
204:   if (isConstrained == PETSC_FALSE)
205:     return(0);
206:   for(f = 0, count = 0, source = 0, inc = 0; f < numFields; f++) {
207:     field = fields[f];
208:     comp  = grid->fields[field].disc->comp;

210:     for(corner = 0; corner < numCorners; corner++) {
211:       node   = elements[elem*numCorners+corner];
212:       nclass = classes[node];
213:       if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
214:         for(i = 0; i < comp; i++, count++, source++) {
215:           rowIdx[count] = rowIdx[source];
216:           array[count]  = array[source];
217:         }
218:       } else if ((isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
219:         /* We guarantee that count <= source here */
220:         if (constrain == PETSC_TRUE) {
221:           diff  = grid->fields[field].constraintCompDiff;
222:         } else {
223:           diff  = -grid->fields[field].constraintCompDiff;
224:           comp += grid->fields[field].constraintCompDiff;
225:         }
226:         inc += diff;
227:         /* Move rows to operate on */
228:         if (count < source) {
229:           for(row = 0; row < comp; row++)
230:             array[count+row] = array[source+row];
231:         }
232:         source += comp;
233:         /* We must replace this field with the constraint field and prevent overwriting in element vector */
234:         if (source - count < comp + diff) {
235:           /* Move old fields */
236:           for(row = size-(diff+1); row >= source; row--)
237:             array[row+diff] = array[row];
238:           source += diff;
239:         }
240:         if (constrain == PETSC_TRUE) {
241:           /* Apply P^T to get constraint fields */
242:           (*constCtx->ops->constrainelemvec)(constCtx, mesh, order, field, node, count, PETSC_FALSE,
243:                                                     useOldStructs, CONSTRAINT_ROW, vec);
244: 
245:           count += comp + diff;
246:         } else {
247:           /* Apply P to get unconstrained fields */
248:           (*constCtx->ops->constrainelemvec)(constCtx, mesh, order, field, node, count, PETSC_FALSE,
249:                                                     useOldStructs, CONSTRAINT_ROW_TRANS, vec);
250: 
251:           count += comp + diff;
252:           comp  -= grid->fields[field].constraintCompDiff;
253:         }
254:       } else if (fieldClasses[f][nclass]) {
255:         for(i = 0; i < comp; i++, count++, source++) {
256:           rowIdx[count] = rowIdx[source];
257:           array[count]  = array[source];
258:         }
259:       }
260:     }
261:   }
262: #ifdef PETSC_USE_BOPT_g
263:   if (count != vec->reduceSize + inc) {
264:     SETERRQ3(PETSC_ERR_PLIB, "Invalid variable numbering elem: %d size: %d count: %dn", elem, vec->reduceSize+inc, count);
265:   }
266:   if (count > vec->size) {
267:     SETERRQ3(PETSC_ERR_PLIB, "Number of indices %d in elem %d exceeded maximum size %dn", count, elem, vec->size);
268:   }
269: #endif
270:   /* Set true vector size */
271:   vec->reduceSize = count;

273:   return(0);
274: }

276: int GridCalcBoundaryElementVecIndices_Triangular_2D(Grid grid, int bd, int edge, int midnode, VarOrdering order,
277:                                                     VarOrdering reduceOrder, PetscTruth localNumbering, ElementVec vec)
278: {
279:   Mesh_Triangular      *tri           = (Mesh_Triangular *) grid->mesh->data;
280:   int                  *edges         = tri->edges;
281:   int                   numNodes      = grid->mesh->numNodes;
282:   PetscConstraintObject constCtx      = grid->constraintCtx;
283:   int                  *firstVar      = order->firstVar;
284:   int                  *offsets       = order->offsets;
285:   int                  *localOffsets  = order->localOffsets;
286:   int                 **localStart    = order->localStart;
287:   int                  *rowIdx        = vec->indices;
288:   int                   size          = vec->size;
289:   PetscScalar          *array         = vec->array;
290:   int                   rank;
291:   FieldClassMap         map;
292:   int                   numFields;
293:   int                  *fields;
294:   int                 **fieldClasses, **reduceFieldClasses;
295:   int                  *classes;
296:   PetscTruth            isReduced, isConstrained;
297:   int                  *isConst;
298:   int                  *reduceFirstVar     = PETSC_NULL;
299:   int                  *reduceOffsets      = PETSC_NULL;
300:   int                  *reduceLocalOffsets = PETSC_NULL;
301:   int                 **reduceLocalStart   = PETSC_NULL;
302:   int                   field, node, nclass, comp, startVar, diff, inc;
303:   int                   i, f, count, source, corner, row;
304:   int                   ierr;

307:   MPI_Comm_rank(grid->comm, &rank);
308:   VarOrderingGetClassMap(order, &map);
309:   numFields          = map->numFields;
310:   fields             = map->fields;
311:   fieldClasses       = map->fieldClasses;
312:   reduceFieldClasses = map->reduceFieldClasses;
313:   classes            = map->classes;
314:   isReduced          = map->isReduced;
315:   isConstrained      = map->isConstrained;
316:   isConst            = map->isClassConstrained;
317:   if (isReduced == PETSC_TRUE) {
318:     reduceFirstVar     = reduceOrder->firstVar;
319:     reduceOffsets      = reduceOrder->offsets;
320:     reduceLocalOffsets = reduceOrder->localOffsets;
321:     reduceLocalStart   = reduceOrder->localStart;
322:   }
323:   for(f = 0, count = 0, source = 0, inc = 0; f < numFields; f++) {
324:     field = fields[f];
325:     comp  = grid->fields[field].disc->bdDisc->comp;

327:     for(corner = 0; corner < 2; corner++) {
328:       node   = edges[edge*2+corner];
329:       nclass = classes[node];

331:       if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
332:         if (localNumbering == PETSC_FALSE) {
333:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
334:           source += comp;
335:           inc    -= comp;
336:         } else {
337:           if (node >= numNodes)
338:             startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
339:           else
340:             startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
341:           for(i = 0; i < comp; i++, count++) {
342:             rowIdx[count] = -(startVar + i + 1);
343:           }
344: #ifdef PETSC_USE_BOPT_g
345:           PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
346: #endif
347:         }
348:       } else if ((isConstrained == PETSC_TRUE) && (isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
349:         /* We guarantee that count <= source here */
350:         diff = grid->fields[field].constraintCompDiff;
351:         inc += diff;
352:         /* Move rows to operate on */
353:         if (count < source) {
354:           for(row = 0; row < comp; row++)
355:             array[count+row] = array[source+row];
356:         }
357:         source += comp;
358:         /* We must replace this field with the constraint field and prevent overwriting in element vector */
359:         if (source - count < comp + diff) {
360:           /* Move old fields */
361:           for(row = size-(diff+1); row >= source; row--)
362:             array[row+diff] = array[row];
363:           source += diff;
364:         }
365:         /* Apply P^T to get constraint fields */
366:         (*constCtx->ops->constrainelemvec)(constCtx, grid->mesh, order, field, node, count, localNumbering,
367:                                                   PETSC_FALSE, CONSTRAINT_ROW, vec);
368: 
369:         count += comp + diff;
370:       } else if (fieldClasses[f][nclass]) {
371:         if (localNumbering == PETSC_FALSE) {
372:           startVar = offsets[node] + localStart[field][nclass];
373:         } else {
374:           if (node >= numNodes)
375:             startVar = localOffsets[node-numNodes] + localStart[field][nclass];
376:           else
377:             startVar = offsets[node] - firstVar[rank] + localStart[field][nclass];
378:         }
379:         for(i = 0; i < comp; i++, count++, source++) {
380:           rowIdx[count] = startVar + i;
381:           array[count]  = array[source];
382:         }
383: #ifdef PETSC_USE_BOPT_g
384:         PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
385: #endif
386:       }
387:     }

389:     if (midnode >= 0) {
390:       nclass = classes[midnode];

392:       if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
393:         if (localNumbering == PETSC_FALSE) {
394:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
395:           source += comp;
396:           inc    -= comp;
397:         } else {
398:           if (midnode >= numNodes)
399:             startVar = reduceLocalOffsets[midnode-numNodes] + reduceLocalStart[field][nclass];
400:           else
401:             startVar = reduceOffsets[midnode] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
402:           for(i = 0; i < comp; i++, count++) {
403:             rowIdx[count] = -(startVar + i + 1);
404:           }
405: #ifdef PETSC_USE_BOPT_g
406:           PrintVecIndices_Private(grid, "-trace_vec_assembly", field, midnode, comp, count, rowIdx);
407: #endif
408:         }
409:       } else if ((isConstrained == PETSC_TRUE) && (isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
410:         /* We guarantee that count <= source here */
411:         diff = grid->fields[field].constraintCompDiff;
412:         inc += diff;
413:         /* Move rows to operate on */
414:         if (count < source) {
415:           for(row = 0; row < comp; row++)
416:             array[count+row] = array[source+row];
417:         }
418:         source += comp;
419:         /* We must replace this field with the constraint field and prevent overwriting in element vector */
420:         if (source - count < comp + diff) {
421:           /* Move old fields */
422:           for(row = size-(diff+1); row >= source; row--)
423:             array[row+diff] = array[row];
424:           source += diff;
425:         }
426:         /* Apply P^T to get constraint fields */
427:         (*constCtx->ops->constrainelemvec)(constCtx, grid->mesh, order, field, midnode, count, localNumbering,
428:                                                   PETSC_FALSE, CONSTRAINT_ROW, vec);
429: 
430:         count += comp + diff;
431:       } else if (fieldClasses[f][nclass]) {
432:         if (localNumbering == PETSC_FALSE) {
433:           startVar = offsets[midnode] + localStart[field][nclass];
434:         } else {
435:           if (midnode >= numNodes)
436:             startVar = localOffsets[midnode-numNodes] + localStart[field][nclass];
437:           else
438:             startVar = offsets[midnode] - firstVar[rank] + localStart[field][nclass];
439:         }
440:         for(i = 0; i < comp; i++, count++, source++) {
441:           rowIdx[count] = startVar + i;
442:           array[count]  = array[source];
443:         }
444: #ifdef PETSC_USE_BOPT_g
445:         PrintVecIndices_Private(grid, "-trace_vec_assembly", field, midnode, comp, count, rowIdx);
446: #endif
447:       }
448:     }
449:   }
450: #ifdef PETSC_USE_BOPT_g
451:   if (count != vec->reduceSize + inc) {
452:     SETERRQ3(PETSC_ERR_PLIB, "Invalid variable numbering edge: %d size: %d count: %dn", edge, vec->reduceSize+inc, count);
453:   }
454:   if (count > vec->size) {
455:     SETERRQ3(PETSC_ERR_PLIB, "Number of indices %d on edge %d exceeded maximum size %dn", count, edge, vec->size);
456:   }
457: #endif
458:   /* Set true vector size */
459:   vec->reduceSize = count;

461:   return(0);
462: }

464: /*--------------------------------------------- Element Matrix Functions --------------------------------------------*/
465: /*
466:   Element Matrix Structure:

468:   The structure of the element matrix is diagrammed in src/gvec/grid/gridimpl.h.

470:   Reduction:

472:   When the variables associated with boundary conditions are being reduced, the element matrix is compressed
473:   to account for their absence. This reduction only happens in the global numbering. When using the local
474:   numbering, the original variable numbers are replaced by the corresponding index in grid->bdReduceVec
475:   which contains the boundary values. In order to distinguish these indices, they are stored as -(idx+1).
476:   The boundary values are retieved by GridLocalToElement().
477: */
478: int GridCalcElementMatIndices_Triangular_2D(Grid grid, int elem, VarOrdering sOrder, VarOrdering tOrder,
479:                                             VarOrdering reduceOrder, PetscTruth localNumbering, ElementMat mat)
480: {
481:   Mesh_Triangular      *tri             = (Mesh_Triangular *) grid->mesh->data;
482:   int                  *elements        = tri->faces;
483:   int                   numCorners      = grid->mesh->numCorners;
484:   PetscConstraintObject constCtx        = grid->constraintCtx;
485:   int                  *colFirstVar     = sOrder->firstVar;
486:   int                  *colOffsets      = sOrder->offsets;
487:   int                  *colLocalOffsets = sOrder->localOffsets;
488:   int                 **colLocalStart   = sOrder->localStart;
489:   int                  *rowFirstVar     = tOrder->firstVar;
490:   int                  *rowOffsets      = tOrder->offsets;
491:   int                  *rowLocalOffsets = tOrder->localOffsets;
492:   int                 **rowLocalStart   = tOrder->localStart;
493:   int                  *rowIdx          = mat->rowIndices;
494:   int                  *colIdx          = mat->colIndices;
495:   int                   rowSize         = mat->reduceRowSize;
496:   int                   colSize         = mat->reduceColSize;
497:   int                   origRowSize     = mat->reduceRowSize;
498:   int                   origColSize     = mat->reduceColSize;
499:   int                  *newCols         = mat->reduceCols;
500:   PetscScalar          *array           = mat->array;
501:   PetscScalar          *tempArray       = mat->tempArray;
502:   int                   rank            = grid->mesh->part->rank;
503:   FieldClassMap         rowMap,                  colMap;
504:   int                   numNodes;
505:   int                   numRowFields,            numColFields;
506:   int                  *rowFields,              *colFields;
507:   int                 **rowFieldClasses,       **colFieldClasses;
508:   int                 **rowReduceFieldClasses, **colReduceFieldClasses;
509:   int                  *rowClasses,             *colClasses;
510:   PetscTruth            rowIsReduced,            colIsReduced;
511:   PetscTruth            rowIsConstrained,        colIsConstrained;
512:   int                  *rowIsConst,             *colIsConst;
513:   int                  *reduceFirstVar     = PETSC_NULL;
514:   int                  *reduceOffsets      = PETSC_NULL;
515:   int                  *reduceLocalOffsets = PETSC_NULL;
516:   int                 **reduceLocalStart   = PETSC_NULL;
517:   int                   field, node, nclass, comp, startVar, diff, inc;
518:   int                   i, f, corner, rowCount, rowSource, colCount, colSource, row, col, newCol;
519:   int                   ierr;

522:   VarOrderingGetClassMap(tOrder, &rowMap);
523:   VarOrderingGetClassMap(sOrder, &colMap);
524:   numNodes              = rowMap->numNodes;
525:   numRowFields          = rowMap->numFields;
526:   rowFields             = rowMap->fields;
527:   rowFieldClasses       = rowMap->fieldClasses;
528:   rowReduceFieldClasses = rowMap->reduceFieldClasses;
529:   rowClasses            = rowMap->classes;
530:   rowIsReduced          = rowMap->isReduced;
531:   rowIsConstrained      = rowMap->isConstrained;
532:   rowIsConst            = rowMap->isClassConstrained;
533:   numColFields          = colMap->numFields;
534:   colFields             = colMap->fields;
535:   colFieldClasses       = colMap->fieldClasses;
536:   colReduceFieldClasses = colMap->reduceFieldClasses;
537:   colClasses            = colMap->classes;
538:   colIsReduced          = colMap->isReduced;
539:   colIsConstrained      = colMap->isConstrained;
540:   colIsConst            = colMap->isClassConstrained;
541:   if ((rowIsReduced == PETSC_TRUE) || (colIsReduced == PETSC_TRUE)) {
542:     reduceFirstVar     = reduceOrder->firstVar;
543:     reduceOffsets      = reduceOrder->offsets;
544:     reduceLocalOffsets = reduceOrder->localOffsets;
545:     reduceLocalStart   = reduceOrder->localStart;
546:   }
547:   for(f = 0, rowCount = 0, rowSource = 0, inc = 0; f < numRowFields; f++) {
548:     field = rowFields[f];
549:     comp  = grid->fields[field].disc->comp;

551:     for(corner = 0; corner < numCorners; corner++) {
552:       node   = elements[elem*numCorners+corner];
553:       nclass = rowClasses[node];

555:       if ((rowIsReduced == PETSC_TRUE) && (rowReduceFieldClasses[f][nclass])) {
556:         if (localNumbering == PETSC_FALSE) {
557:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
558:           rowSource += comp;
559:           inc       -= comp;
560:         } else {
561:           if (node >= numNodes)
562:             startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
563:           else
564:             startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
565:           for(i = 0; i < comp; i++, rowCount++, rowSource++) {
566:             rowIdx[rowCount] = -(startVar + i + 1);
567:           }
568:         }
569:       } else if ((rowIsConstrained == PETSC_TRUE) && (rowIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
570:         /* We guarantee that rowCount <= rowSource here */
571:         diff = grid->fields[field].constraintCompDiff;
572:         inc += diff;
573:         /* Move rows to operate on */
574:         if (rowCount < rowSource) {
575:           for(row = 0; row < comp; row++)
576:             for(col = 0; col < colSize; col++)
577:               array[(rowCount+row)*colSize+col] = array[(rowSource+row)*colSize+col];
578:         }
579:         rowSource += comp;
580:         /* We must replace this field with the constraint field and prevent overwriting in element matrix */
581:         if (rowSource - rowCount < comp + diff) {
582:           /* Move old fields */
583:           for(row = rowSize-1; row >= rowSource; row--)
584:             for(col = 0; col < colSize; col++)
585:               array[(row+diff)*colSize+col] = array[row*colSize+col];
586:           rowSource += diff;
587:           rowSize   += diff;
588:         }
589:         /* Apply P^T to get constraint fields */
590:         (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, tOrder, field, node, rowCount, CONSTRAINT_ROW, mat);
591: 
592:         rowCount += comp + diff;
593:       } else if (rowFieldClasses[f][nclass]) {
594:         if (localNumbering == PETSC_FALSE) {
595:           startVar = rowOffsets[node] + rowLocalStart[field][nclass];
596:         } else {
597:           if (node >= numNodes)
598:             startVar = rowLocalOffsets[node-numNodes] + rowLocalStart[field][nclass];
599:           else
600:             startVar = rowOffsets[node] - rowFirstVar[rank] + rowLocalStart[field][nclass];
601:         }
602:         for(i = 0; i < comp; i++, rowCount++, rowSource++) {
603:           rowIdx[rowCount] = startVar + i;
604:           /* Shrink rows -- I do not see a way around shrinking the whole matrix */
605:           if (rowCount != rowSource) {
606:             for(col = 0; col < colSize; col++)
607:               array[rowCount*colSize+col] = array[rowSource*colSize+col];
608:           }
609:         }
610:       }
611:     }
612:   }
613:   if (rowCount != origRowSize + inc) {
614:     SETERRQ3(PETSC_ERR_PLIB, "Invalid row numbering elem: %d size: %d count: %dn", elem, origRowSize+inc, rowCount);
615:   }
616:   if (rowSize  > mat->rowSize) {
617:     SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d in elem %d exceeded maximum size %dn", rowSize, elem, mat->rowSize);
618:   }
619:   if (rowCount > mat->rowSize) {
620:     SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d in elem %d exceeded maximum size %dn", rowCount, elem, mat->rowSize);
621:   }
622:   mat->reduceRowSize = rowCount;

624:   /* Calculate the columns ordering after reduction --
625:        colCount  - Number of columns stacked into mat
626:        colSource - Current column of mat being accessed
627:        inc       - The difference in size of the constrained matrix from the original
628:        newCols   - The column reordering, newCols[colSource] is the current column in the matrix, -1 for not present
629:   */
630:   for(f = 0, colCount = 0, colSource = 0, newCol = origColSize, inc = 0; f < numColFields; f++) {
631:     field = colFields[f];
632:     comp  = grid->fields[field].disc->comp;

634:     for(corner = 0; corner < numCorners; corner++) {
635:       node   = elements[elem*numCorners+corner];
636:       nclass = colClasses[node];
637: 
638:       if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
639:         if (localNumbering == PETSC_FALSE) {
640:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
641:           for(i = 0; i < comp; i++, colSource++) {
642:             newCols[colSource] = -1;
643:           }
644:           inc       -= comp;
645:         } else {
646:           /* Put in negative indices corresponding to boundary values */
647:           for(i = 0; i < comp; i++, colCount++, colSource++) {
648:             newCols[colSource] = colCount;
649:           }
650:         }
651:       } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
652:         /* We must replace this field with the constraint field and prevent overwriting in element matrix */
653:         diff = grid->fields[field].constraintCompDiff;
654:         inc += diff;
655:         if (diff > 0) {
656:           /* Assume new field were previously in the last columns */
657:           for(i = 0; i < comp; i++, colCount++, colSource++)
658:             newCols[colSource] = colCount;
659:           for(i = 0; i < diff; i++, colCount++, newCol++)
660:             newCols[newCol]    = colCount;
661:         } else {
662:           /* Just squeeze matrix */
663:           for(i = 0; i < comp + diff; i++, colCount++, colSource++)
664:             newCols[colSource] = colCount;
665:           for(i = comp+diff; i < comp; i++, colSource++)
666:             newCols[colSource] = -1;
667:         }
668:       } else if (colFieldClasses[f][nclass]) {
669:         for(i = 0; i < comp; i++, colCount++, colSource++) {
670:           newCols[colSource] = colCount;
671:         }
672:       }
673:     }
674:   }
675: #ifdef PETSC_USE_BOPT_g
676:   if (colCount != origColSize + inc) {
677:     SETERRQ3(PETSC_ERR_PLIB, "Invalid column numbering elem: %d size: %d count: %dn", elem, origColSize+inc, colCount);
678:   }
679:   if (colCount > mat->colSize) {
680:     SETERRQ3(PETSC_ERR_PLIB, "Number of column indices %d in elem %d exceeded maximum size %dn", colCount, elem, mat->colSize);
681:   }
682: #endif
683:   mat->reduceColSize = colCount;

685:   /* Reform the element matrix: newCols[original col] = new col */
686:   if (mat->reduceColSize != origColSize) {
687:     if (colIsConstrained == PETSC_TRUE) {
688:       for(row = 0; row < mat->reduceRowSize; row++)
689:         for(col = 0; col < origColSize; col++)
690:           if (newCols[col] >= 0)
691:             tempArray[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
692:       PetscMemcpy(array, tempArray, mat->reduceRowSize*mat->reduceColSize * sizeof(PetscScalar));
693:     } else {
694:       /* Can copy in place if no constraints were applied since BC just delete entries */
695:       for(row = 0; row < mat->reduceRowSize; row++)
696:         for(col = 0; col < origColSize; col++)
697:           if (newCols[col] >= 0)
698:             array[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
699:     }
700:   }

702:   /* Calculate indices and constrained matrix elements */
703:   for(f = 0, colCount = 0; f < numColFields; f++) {
704:     field = colFields[f];
705:     comp  = grid->fields[field].disc->comp;

707:     for(corner = 0; corner < numCorners; corner++) {
708:       node   = elements[elem*numCorners+corner];
709:       nclass = colClasses[node];
710: 
711:       if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
712:         if (localNumbering == PETSC_TRUE) {
713:           if (node >= numNodes)
714:             startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
715:           else
716:             startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
717:           for(i = 0; i < comp; i++, colCount++) {
718:             colIdx[colCount] = -(startVar + i + 1);
719:           }
720:         }
721:       } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
722:         /* Apply P to get constraint fields */
723:         (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, sOrder, field, node, colCount, CONSTRAINT_COL, mat);
724: 
725:         colCount  += comp + grid->fields[field].constraintCompDiff;
726:       } else if (colFieldClasses[f][nclass]) {
727:         if (localNumbering == PETSC_FALSE) {
728:           startVar = colOffsets[node] + colLocalStart[field][nclass];
729:         } else {
730:           if (node >= numNodes)
731:             startVar = colLocalOffsets[node-numNodes] + colLocalStart[field][nclass];
732:           else
733:             startVar = colOffsets[node] - colFirstVar[rank] + colLocalStart[field][nclass];
734:         }
735:         for(i = 0; i < comp; i++, colCount++) {
736:           colIdx[colCount] = startVar + i;
737:         }
738:       }
739:     }
740:   }

742:   return(0);
743: }

745: int GridCalcBoundaryElementMatIndices_Triangular_2D(Grid grid, int bd, int edge, int midnode, VarOrdering sOrder,
746:                                                     VarOrdering tOrder, VarOrdering reduceOrder, PetscTruth localNumbering,
747:                                                     ElementMat mat)
748: {
749:   Mesh_Triangular      *tri             = (Mesh_Triangular *) grid->mesh->data;
750:   int                   numCorners      = grid->mesh->numCorners;
751:   int                  *elements        = tri->faces;
752:   int                  *edges           = tri->edges;
753:   PetscConstraintObject constCtx        = grid->constraintCtx;
754:   int                  *colFirstVar     = sOrder->firstVar;
755:   int                  *colOffsets      = sOrder->offsets;
756:   int                  *colLocalOffsets = sOrder->localOffsets;
757:   int                 **colLocalStart   = sOrder->localStart;
758:   int                  *rowFirstVar     = tOrder->firstVar;
759:   int                  *rowOffsets      = tOrder->offsets;
760:   int                  *rowLocalOffsets = tOrder->localOffsets;
761:   int                 **rowLocalStart   = tOrder->localStart;
762:   int                  *rowIdx          = mat->rowIndices;
763:   int                  *colIdx          = mat->colIndices;
764:   int                   rowSize         = mat->reduceRowSize;
765:   int                   colSize         = mat->reduceColSize;
766:   int                   origRowSize     = mat->reduceRowSize;
767:   int                   origColSize     = mat->reduceColSize;
768:   int                  *newCols         = mat->reduceCols;
769:   PetscScalar          *array           = mat->array;
770:   PetscScalar          *tempArray       = mat->tempArray;
771:   int                   rank            = grid->mesh->part->rank;
772:   FieldClassMap         rowMap,                  colMap;
773:   int                   numNodes;
774:   int                   numRowFields,            numColFields;
775:   int                  *rowFields,              *colFields;
776:   int                 **rowFieldClasses,       **colFieldClasses;
777:   int                 **rowReduceFieldClasses, **colReduceFieldClasses;
778:   int                  *rowClasses,             *colClasses;
779:   PetscTruth            rowIsReduced,            colIsReduced;
780:   PetscTruth            rowIsConstrained,        colIsConstrained;
781:   int                  *rowIsConst,             *colIsConst;
782:   int                  *reduceFirstVar     = PETSC_NULL;
783:   int                  *reduceOffsets      = PETSC_NULL;
784:   int                  *reduceLocalOffsets = PETSC_NULL;
785:   int                 **reduceLocalStart   = PETSC_NULL;
786:   int                   field, node, nclass, comp, startVar, diff, inc;
787:   int                   i, f, elem, corner, rowCount, rowSource, colCount, colSource, row, col, newCol;
788:   int                   ierr;

791:   VarOrderingGetClassMap(tOrder, &rowMap);
792:   VarOrderingGetClassMap(sOrder, &colMap);
793:   numNodes              = rowMap->numNodes;
794:   numRowFields          = rowMap->numFields;
795:   rowFields             = rowMap->fields;
796:   rowFieldClasses       = rowMap->fieldClasses;
797:   rowReduceFieldClasses = rowMap->reduceFieldClasses;
798:   rowClasses            = rowMap->classes;
799:   rowIsReduced          = rowMap->isReduced;
800:   rowIsConstrained      = rowMap->isConstrained;
801:   rowIsConst            = rowMap->isClassConstrained;
802:   numColFields          = colMap->numFields;
803:   colFields             = colMap->fields;
804:   colFieldClasses       = colMap->fieldClasses;
805:   colReduceFieldClasses = colMap->reduceFieldClasses;
806:   colClasses            = colMap->classes;
807:   colIsReduced          = colMap->isReduced;
808:   colIsConstrained      = colMap->isConstrained;
809:   colIsConst            = colMap->isClassConstrained;
810:   if ((rowIsReduced == PETSC_TRUE) || (colIsReduced == PETSC_TRUE)) {
811:     reduceFirstVar     = reduceOrder->firstVar;
812:     reduceOffsets      = reduceOrder->offsets;
813:     reduceLocalOffsets = reduceOrder->localOffsets;
814:     reduceLocalStart   = reduceOrder->localStart;
815:   }
816:   MeshGetBdElementFromEdge(grid->mesh, edge, &elem);
817:   for(f = 0, rowCount = 0, rowSource = 0, inc = 0; f < numRowFields; f++) {
818:     field = rowFields[f];
819:     comp  = grid->fields[field].disc->comp;

821:     for(corner = 0; corner < numCorners; corner++) {
822:       node   = elements[elem*numCorners+corner];
823:       nclass = rowClasses[node];

825:       if ((rowIsReduced == PETSC_TRUE) && (rowReduceFieldClasses[f][nclass])) {
826:         if (localNumbering == PETSC_FALSE) {
827:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
828:           rowSource += comp;
829:           inc       -= comp;
830:         } else {
831:           if (node >= numNodes)
832:             startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
833:           else
834:             startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
835:           for(i = 0; i < comp; i++, rowCount++, rowSource++) {
836:             rowIdx[rowCount] = -(startVar + i + 1);
837:           }
838:         }
839:       } else if ((rowIsConstrained == PETSC_TRUE) && (rowIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
840:         /* We guarantee that rowCount <= rowSource here */
841:         diff = grid->fields[field].constraintCompDiff;
842:         inc += diff;
843:         /* Move rows to operate on */
844:         if (rowCount < rowSource) {
845:           for(row = 0; row < comp; row++)
846:             for(col = 0; col < colSize; col++)
847:               array[(rowCount+row)*colSize+col] = array[(rowSource+row)*colSize+col];
848:         }
849:         rowSource += comp;
850:         /* We must replace this field with the constraint field and prevent overwriting in element matrix */
851:         if (rowSource - rowCount < comp + diff) {
852:           /* Move old fields */
853:           for(row = rowSize-1; row >= rowSource; row--)
854:             for(col = 0; col < colSize; col++)
855:               array[(row+diff)*colSize+col] = array[row*colSize+col];
856:           rowSource += diff;
857:           rowSize   += diff;
858:         }
859:         /* Apply P^T to get constraint fields */
860:         (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, tOrder, field, node, rowCount, CONSTRAINT_ROW, mat);
861: 
862:         rowCount += comp + diff;
863:       } else if (rowFieldClasses[f][nclass]) {
864:         if (localNumbering == PETSC_FALSE) {
865:           startVar = rowOffsets[node] + rowLocalStart[field][nclass];
866:         } else {
867:           if (node >= numNodes)
868:             startVar = rowLocalOffsets[node-numNodes] + rowLocalStart[field][nclass];
869:           else
870:             startVar = rowOffsets[node] - rowFirstVar[rank] + rowLocalStart[field][nclass];
871:         }
872:         for(i = 0; i < comp; i++, rowCount++, rowSource++) {
873:           rowIdx[rowCount] = startVar + i;
874:           /* Shrink rows -- I do not see a way around shrinking the whole matrix */
875:           if (rowCount != rowSource) {
876:             for(col = 0; col < colSize; col++)
877:               array[rowCount*colSize+col] = array[rowSource*colSize+col];
878:           }
879:         }
880:       }
881:     }
882:   }
883:   if (rowCount != origRowSize + inc) {
884:     SETERRQ3(PETSC_ERR_PLIB, "Invalid row numbering edge: %d size: %d count: %dn", edge, origRowSize+inc, rowCount);
885:   }
886:   if (rowSize  > mat->rowSize) {
887:     SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d on edge %d exceeded maximum size %dn", rowSize, edge, mat->rowSize);
888:   }
889:   if (rowCount > mat->rowSize) {
890:     SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d on edge %d exceeded maximum size %dn", rowCount, edge, mat->rowSize);
891:   }
892:   mat->reduceRowSize = rowCount;

894:   /* Calculate the columns ordering after reduction --
895:        colCount  - Number of columns stacked into mat
896:        colSource - Current column of mat being accessed
897:        inc       - The difference in size of the constrained matrix from the original
898:        newCols   - The column reordering, newCols[colSource] is the current column in the matrix, -1 for not present
899:   */
900:   for(f = 0, colCount = 0, colSource = 0, newCol = origColSize, inc = 0; f < numColFields; f++) {
901:     field = colFields[f];
902:     comp  = grid->fields[field].disc->bdDisc->comp;

904:     for(corner = 0; corner < 2; corner++) {
905:       node   = edges[edge*2+corner];
906:       nclass = colClasses[node];

908:       if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
909:         if (localNumbering == PETSC_FALSE) {
910:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
911:           for(i = 0; i < comp; i++, colSource++) {
912:             newCols[colSource] = -1;
913:           }
914:           inc       -= comp;
915:         } else {
916:           /* Put in negative indices corresponding to boundary values */
917:           for(i = 0; i < comp; i++, colCount++, colSource++) {
918:             newCols[colSource] = colCount;
919:           }
920:         }
921:       } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
922:         /* We must replace this field with the constraint field and prevent overwriting in element matrix */
923:         diff = grid->fields[field].constraintCompDiff;
924:         inc += diff;
925:         if (diff > 0) {
926:           /* Assume new field were previously in the last columns */
927:           for(i = 0; i < comp; i++, colCount++, colSource++)
928:             newCols[colSource] = colCount;
929:           for(i = 0; i < diff; i++, colCount++, newCol++)
930:             newCols[newCol]    = colCount;
931:         } else {
932:           /* Just squeeze matrix */
933:           for(i = 0; i < comp + diff; i++, colCount++, colSource++)
934:             newCols[colSource] = colCount;
935:           for(i = comp+diff; i < comp; i++, colSource++)
936:             newCols[colSource] = -1;
937:         }
938:       } else if (colFieldClasses[f][nclass]) {
939:         for(i = 0; i < comp; i++, colCount++, colSource++) {
940:           newCols[colSource] = colCount;
941:         }
942:       }
943:     }

945:     if (midnode >= 0) {
946:       nclass = colClasses[midnode];

948:       if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
949:         if (localNumbering == PETSC_FALSE) {
950:           /* Increment source pointer in value array, which corresponds to skipping constrained variables */
951:           for(i = 0; i < comp; i++, colSource++) {
952:             newCols[colSource] = -1;
953:           }
954:           inc       -= comp;
955:         } else {
956:           /* Put in negative indices corresponding to boundary values */
957:           for(i = 0; i < comp; i++, colCount++, colSource++) {
958:             newCols[colSource] = colCount;
959:           }
960:         }
961:       } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
962:         /* We must replace this field with the constraint field and prevent overwriting in element matrix */
963:         diff = grid->fields[field].constraintCompDiff;
964:         inc += diff;
965:         if (diff > 0) {
966:           /* Assume new field were previously in the last columns */
967:           for(i = 0; i < comp; i++, colCount++, colSource++)
968:             newCols[colSource] = colCount;
969:           for(i = 0; i < diff; i++, colCount++, newCol++)
970:             newCols[newCol]    = colCount;
971:         } else {
972:           /* Just squeeze matrix */
973:           for(i = 0; i < comp + diff; i++, colCount++, colSource++)
974:             newCols[colSource] = colCount;
975:           for(i = comp+diff; i < comp; i++, colSource++)
976:             newCols[colSource] = -1;
977:         }
978:       } else if (colFieldClasses[f][nclass]) {
979:         for(i = 0; i < comp; i++, colCount++, colSource++) {
980:           newCols[colSource] = colCount;
981:         }
982:       }
983:     }
984:   }
985: #ifdef PETSC_USE_BOPT_g
986:   if (colCount != origColSize + inc) {
987:     SETERRQ3(PETSC_ERR_PLIB, "Invalid column numbering edge: %d size: %d count: %dn", edge, origColSize+inc, colCount);
988:   }
989:   if (colCount > mat->colSize) {
990:     SETERRQ3(PETSC_ERR_PLIB, "Number of column indices %d on edge %d exceeded maximum size %dn", colCount, edge, mat->colSize);
991:   }
992: #endif
993:   mat->reduceColSize = colCount;

995:   /* Reform the element matrix: newCols[original col] = new col */
996:   if (mat->reduceColSize != origColSize) {
997:     if (colIsConstrained == PETSC_TRUE) {
998:       for(row = 0; row < mat->reduceRowSize; row++)
999:         for(col = 0; col < origColSize; col++)
1000:           if (newCols[col] >= 0)
1001:             tempArray[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
1002:       PetscMemcpy(array, tempArray, mat->reduceRowSize*mat->reduceColSize * sizeof(PetscScalar));
1003:     } else {
1004:       /* Can copy in place if no constraints were applied since BC just delete entries */
1005:       for(row = 0; row < mat->reduceRowSize; row++)
1006:         for(col = 0; col < origColSize; col++)
1007:           if (newCols[col] >= 0)
1008:             array[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
1009:     }
1010:   }

1012:   /* Calculate indices and constrained matrix elements */
1013:   for(f = 0, colCount = 0; f < numColFields; f++) {
1014:     field = colFields[f];
1015:     comp  = grid->fields[field].disc->comp;

1017:     for(corner = 0; corner < 2; corner++) {
1018:       node   = edges[edge*2+corner];
1019:       nclass = colClasses[node];
1020: 
1021:       if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
1022:         if (localNumbering == PETSC_TRUE) {
1023:           if (node >= numNodes)
1024:             startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
1025:           else
1026:             startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
1027:           for(i = 0; i < comp; i++, colCount++) {
1028:             colIdx[colCount] = -(startVar + i + 1);
1029:           }
1030:         }
1031:       } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
1032:         /* Apply P to get constraint fields */
1033:         (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, sOrder, field, node, colCount, CONSTRAINT_COL, mat);
1034: 
1035:         colCount  += comp + grid->fields[field].constraintCompDiff;
1036:       } else if (colFieldClasses[f][nclass]) {
1037:         if (localNumbering == PETSC_FALSE) {
1038:           startVar = colOffsets[node] + colLocalStart[field][nclass];
1039:         } else {
1040:           if (node >= numNodes)
1041:             startVar = colLocalOffsets[node-numNodes] + colLocalStart[field][nclass];
1042:           else
1043:             startVar = colOffsets[node] - colFirstVar[rank] + colLocalStart[field][nclass];
1044:         }
1045:         for(i = 0; i < comp; i++, colCount++) {
1046:           colIdx[colCount] = startVar + i;
1047:         }
1048:       }
1049:     }

1051:     if (midnode >= 0) {
1052:       nclass = colClasses[midnode];
1053: 
1054:       if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
1055:         if (localNumbering == PETSC_TRUE) {
1056:           if (midnode >= numNodes)
1057:             startVar = reduceLocalOffsets[midnode-numNodes] + reduceLocalStart[field][nclass];
1058:           else
1059:             startVar = reduceOffsets[midnode] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
1060:           for(i = 0; i < comp; i++, colCount++) {
1061:             colIdx[colCount] = -(startVar + i + 1);
1062:           }
1063:         }
1064:       } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
1065:         /* Apply P to get constraint fields */
1066:         (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, sOrder, field, midnode, colCount, CONSTRAINT_COL, mat);
1067: 
1068:         colCount  += comp + grid->fields[field].constraintCompDiff;
1069:       } else if (colFieldClasses[f][nclass]) {
1070:         if (localNumbering == PETSC_FALSE) {
1071:           startVar = colOffsets[midnode] + colLocalStart[field][nclass];
1072:         } else {
1073:           if (midnode >= numNodes)
1074:             startVar = colLocalOffsets[midnode-numNodes] + colLocalStart[field][nclass];
1075:           else
1076:             startVar = colOffsets[midnode] - colFirstVar[rank] + colLocalStart[field][nclass];
1077:         }
1078:         for(i = 0; i < comp; i++, colCount++) {
1079:           colIdx[colCount] = startVar + i;
1080:         }
1081:       }
1082:     }
1083:   }

1085:   return(0);
1086: }