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: MPI_Comm comm;
12: int rank;
13: int var;
14: PetscTruth opt;
15: int ierr;
18: PetscOptionsHasName(PETSC_NULL, option, &opt);
19: if (opt == PETSC_FALSE) return(0);
20: PetscObjectGetComm((PetscObject) grid, &comm);
21: MPI_Comm_rank(comm, &rank);
22: PetscPrintf(PETSC_COMM_SELF, "[%d]field: %d node: %dn", rank, field, node);
23: for(var = rowStart-comp; var < rowStart; var++)
24: PetscPrintf(PETSC_COMM_SELF, "[%d]rowIdx[%d]: %dn", rank, var, rowIdx[var]);
25: return(0);
26: }
28: /*
29: Reduction:
31: When the variables associated with boundary conditions are being reduced, the element vector is compressed
32: to account for their absence. This reduction only happens in the global numbering. When using the local
33: numbering, the original variable numbers are replaced by the corresponding index in grid->bdReduceVec
34: which contains the boundary values. In order to distinguish these indices, they are stored as -(idx+1).
35: The boundary values are retieved by GridLocalToElement(). The useOldStructs flag signals that we are
36: interpolating from a previous mesh, and thus the constraints must be calculated from the previous values.
37: */
38: int GridCalcElementVecIndices_Triangular_2D(Grid grid, Mesh mesh, int elem, VarOrdering order, VarOrdering reduceOrder,
39: PetscTruth localNumbering, PetscTruth useOldStructs, ElementVec vec)
40: {
41: int numCorners = mesh->numCorners;
42: int numNodes = mesh->numNodes;
43: PetscConstraintObject constCtx = grid->constraintCtx;
44: int *firstVar = order->firstVar;
45: int *offsets = order->offsets;
46: int *localOffsets = order->localOffsets;
47: int **localStart = order->localStart;
48: int *rowIdx = vec->indices;
49: int rank = mesh->part->rank;
50: int size = vec->size;
51: PetscScalar *array = vec->array;
52: FieldClassMap map;
53: int numFields;
54: int *fields;
55: int **fieldClasses, **reduceFieldClasses;
56: int *classes;
57: PetscTruth isReduced, isConstrained;
58: int *isConst;
59: int *reduceFirstVar = PETSC_NULL;
60: int *reduceOffsets = PETSC_NULL;
61: int *reduceLocalOffsets = PETSC_NULL;
62: int **reduceLocalStart = PETSC_NULL;
63: int field, node, nclass, comp, startVar, diff, inc;
64: int i, f, count, source, corner, row;
65: int ierr;
68: VarOrderingGetClassMap(order, &map);
69: numFields = map->numFields;
70: fields = map->fields;
71: fieldClasses = map->fieldClasses;
72: reduceFieldClasses = map->reduceFieldClasses;
73: classes = map->classes;
74: isReduced = map->isReduced;
75: isConstrained = map->isConstrained;
76: isConst = map->isClassConstrained;
77: if (isReduced == PETSC_TRUE) {
78: reduceFirstVar = reduceOrder->firstVar;
79: reduceOffsets = reduceOrder->offsets;
80: reduceLocalOffsets = reduceOrder->localOffsets;
81: reduceLocalStart = reduceOrder->localStart;
82: }
83: for(f = 0, count = 0, source = 0, inc = 0; f < numFields; f++) {
84: field = fields[f];
85: comp = grid->fields[field].disc->comp;
87: for(corner = 0; corner < numCorners; corner++) {
88: MeshGetNodeFromElement(mesh, elem, corner, &node);
89: nclass = classes[node];
90: if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
91: if (localNumbering == PETSC_FALSE) {
92: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
93: source += comp;
94: inc -= comp;
95: } else {
96: if (node >= numNodes)
97: startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
98: else
99: startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
100: for(i = 0; i < comp; i++, count++) {
101: rowIdx[count] = -(startVar + i + 1);
102: }
103: #ifdef PETSC_USE_BOPT_g
104: PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
105: #endif
106: }
107: } else if ((isConstrained == PETSC_TRUE) && (isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
108: /* We guarantee that count <= source here */
109: diff = grid->fields[field].constraintCompDiff;
110: inc += diff;
111: /* Move rows to operate on */
112: if (count < source) {
113: for(row = 0; row < comp; row++)
114: array[count+row] = array[source+row];
115: }
116: source += comp;
117: /* We must replace this field with the constraint field and prevent overwriting in element vector */
118: if (source - count < comp + diff) {
119: /* Move old fields */
120: for(row = size-(diff+1); row >= source; row--)
121: array[row+diff] = array[row];
122: source += diff;
123: }
124: /* Apply P^T to get constraint fields */
125: (*constCtx->ops->constrainelemvec)(constCtx, mesh, order, field, node, count, localNumbering,
126: useOldStructs, CONSTRAINT_ROW, vec);
127:
128: count += comp + diff;
129: } else if (fieldClasses[f][nclass]) {
130: if (localNumbering == PETSC_FALSE) {
131: startVar = offsets[node] + localStart[field][nclass];
132: } else {
133: if (node >= numNodes)
134: startVar = localOffsets[node-numNodes] + localStart[field][nclass];
135: else
136: startVar = offsets[node] - firstVar[rank] + localStart[field][nclass];
137: }
138: for(i = 0; i < comp; i++, count++, source++) {
139: rowIdx[count] = startVar + i;
140: array[count] = array[source];
141: }
142: #ifdef PETSC_USE_BOPT_g
143: PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
144: #endif
145: }
146: }
147: }
148: #ifdef PETSC_USE_BOPT_g
149: if (count != vec->reduceSize + inc) {
150: SETERRQ3(PETSC_ERR_PLIB, "Invalid variable numbering elem: %d size: %d count: %dn", elem, vec->reduceSize+inc, count);
151: }
152: if (count > vec->size) {
153: SETERRQ3(PETSC_ERR_PLIB, "Number of indices %d in elem %d exceeded maximum size %dn", count, elem, vec->size);
154: }
155: #endif
156: /* Set true vector size */
157: vec->reduceSize = count;
159: return(0);
160: }
162: /*
163: Projection:
165: We would like a mechanism to convert from the constrained to unconstrained variables, and vice versa,
166: for an element vector. This code is also embedded in the element vector index calculation, and could
167: perhaps be split out. This function is generally called to take a constrained element vector to
168: unconstrained variables before an element integral is performed.
169: */
170: int GridProjectElementVec_Triangular_2D(Grid grid, Mesh mesh, int elem, VarOrdering order, VarOrdering reduceOrder,
171: PetscTruth constrain, PetscTruth useOldStructs, ElementVec vec)
172: {
173: int numCorners = mesh->numCorners;
174: PetscConstraintObject constCtx = grid->constraintCtx;
175: int size = vec->size;
176: int *rowIdx = vec->indices;
177: PetscScalar *array = vec->array;
178: FieldClassMap map;
179: int numFields;
180: int *fields;
181: int **fieldClasses, **reduceFieldClasses;
182: int *classes;
183: PetscTruth isReduced, isConstrained;
184: int *isConst;
185: int field, node, nclass, comp, diff, inc;
186: int i, f, count, source, corner, row;
187: int ierr;
190: VarOrderingGetClassMap(order, &map);
191: numFields = map->numFields;
192: fields = map->fields;
193: fieldClasses = map->fieldClasses;
194: classes = map->classes;
195: isReduced = map->isReduced;
196: isConstrained = map->isConstrained;
197: isConst = map->isClassConstrained;
198: reduceFieldClasses = map->reduceFieldClasses;
199: if (isConstrained == PETSC_FALSE)
200: return(0);
201: for(f = 0, count = 0, source = 0, inc = 0; f < numFields; f++) {
202: field = fields[f];
203: comp = grid->fields[field].disc->comp;
205: for(corner = 0; corner < numCorners; corner++) {
206: MeshGetNodeFromElement(mesh, elem, corner, &node);
207: nclass = classes[node];
208: if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
209: for(i = 0; i < comp; i++, count++, source++) {
210: rowIdx[count] = rowIdx[source];
211: array[count] = array[source];
212: }
213: } else if ((isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
214: /* We guarantee that count <= source here */
215: if (constrain == PETSC_TRUE) {
216: diff = grid->fields[field].constraintCompDiff;
217: } else {
218: diff = -grid->fields[field].constraintCompDiff;
219: comp += grid->fields[field].constraintCompDiff;
220: }
221: inc += diff;
222: /* Move rows to operate on */
223: if (count < source) {
224: for(row = 0; row < comp; row++)
225: array[count+row] = array[source+row];
226: }
227: source += comp;
228: /* We must replace this field with the constraint field and prevent overwriting in element vector */
229: if (source - count < comp + diff) {
230: /* Move old fields */
231: for(row = size-(diff+1); row >= source; row--)
232: array[row+diff] = array[row];
233: source += diff;
234: }
235: if (constrain == PETSC_TRUE) {
236: /* Apply P^T to get constraint fields */
237: (*constCtx->ops->constrainelemvec)(constCtx, mesh, order, field, node, count, PETSC_FALSE,
238: useOldStructs, CONSTRAINT_ROW, vec);
239:
240: count += comp + diff;
241: } else {
242: /* Apply P to get unconstrained fields */
243: (*constCtx->ops->constrainelemvec)(constCtx, mesh, order, field, node, count, PETSC_FALSE,
244: useOldStructs, CONSTRAINT_ROW_TRANS, vec);
245:
246: count += comp + diff;
247: comp -= grid->fields[field].constraintCompDiff;
248: }
249: } else if (fieldClasses[f][nclass]) {
250: for(i = 0; i < comp; i++, count++, source++) {
251: rowIdx[count] = rowIdx[source];
252: array[count] = array[source];
253: }
254: }
255: }
256: }
257: #ifdef PETSC_USE_BOPT_g
258: if (count != vec->reduceSize + inc) {
259: SETERRQ3(PETSC_ERR_PLIB, "Invalid variable numbering elem: %d size: %d count: %dn", elem, vec->reduceSize+inc, count);
260: }
261: if (count > vec->size) {
262: SETERRQ3(PETSC_ERR_PLIB, "Number of indices %d in elem %d exceeded maximum size %dn", count, elem, vec->size);
263: }
264: #endif
265: /* Set true vector size */
266: vec->reduceSize = count;
268: return(0);
269: }
271: int GridCalcBoundaryElementVecIndices_Triangular_2D(Grid grid, int bd, int edge, int midnode, VarOrdering order,
272: VarOrdering reduceOrder, PetscTruth localNumbering, ElementVec vec)
273: {
274: Mesh_Triangular *tri = (Mesh_Triangular *) grid->mesh->data;
275: int *edges = tri->edges;
276: int numNodes = grid->mesh->numNodes;
277: PetscConstraintObject constCtx = grid->constraintCtx;
278: int *firstVar = order->firstVar;
279: int *offsets = order->offsets;
280: int *localOffsets = order->localOffsets;
281: int **localStart = order->localStart;
282: int *rowIdx = vec->indices;
283: int size = vec->size;
284: PetscScalar *array = vec->array;
285: int rank;
286: FieldClassMap map;
287: int numFields;
288: int *fields;
289: int **fieldClasses, **reduceFieldClasses;
290: int *classes;
291: PetscTruth isReduced, isConstrained;
292: int *isConst;
293: int *reduceFirstVar = PETSC_NULL;
294: int *reduceOffsets = PETSC_NULL;
295: int *reduceLocalOffsets = PETSC_NULL;
296: int **reduceLocalStart = PETSC_NULL;
297: int field, node, nclass, comp, startVar, diff, inc;
298: int i, f, count, source, corner, row;
299: int ierr;
302: MPI_Comm_rank(grid->comm, &rank);
303: VarOrderingGetClassMap(order, &map);
304: numFields = map->numFields;
305: fields = map->fields;
306: fieldClasses = map->fieldClasses;
307: reduceFieldClasses = map->reduceFieldClasses;
308: classes = map->classes;
309: isReduced = map->isReduced;
310: isConstrained = map->isConstrained;
311: isConst = map->isClassConstrained;
312: if (isReduced == PETSC_TRUE) {
313: reduceFirstVar = reduceOrder->firstVar;
314: reduceOffsets = reduceOrder->offsets;
315: reduceLocalOffsets = reduceOrder->localOffsets;
316: reduceLocalStart = reduceOrder->localStart;
317: }
318: for(f = 0, count = 0, source = 0, inc = 0; f < numFields; f++) {
319: field = fields[f];
320: comp = grid->fields[field].disc->bdDisc->comp;
322: for(corner = 0; corner < 2; corner++) {
323: node = edges[edge*2+corner];
324: nclass = classes[node];
326: if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
327: if (localNumbering == PETSC_FALSE) {
328: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
329: source += comp;
330: inc -= comp;
331: } else {
332: if (node >= numNodes)
333: startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
334: else
335: startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
336: for(i = 0; i < comp; i++, count++) {
337: rowIdx[count] = -(startVar + i + 1);
338: }
339: #ifdef PETSC_USE_BOPT_g
340: PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
341: #endif
342: }
343: } else if ((isConstrained == PETSC_TRUE) && (isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
344: /* We guarantee that count <= source here */
345: diff = grid->fields[field].constraintCompDiff;
346: inc += diff;
347: /* Move rows to operate on */
348: if (count < source) {
349: for(row = 0; row < comp; row++)
350: array[count+row] = array[source+row];
351: }
352: source += comp;
353: /* We must replace this field with the constraint field and prevent overwriting in element vector */
354: if (source - count < comp + diff) {
355: /* Move old fields */
356: for(row = size-(diff+1); row >= source; row--)
357: array[row+diff] = array[row];
358: source += diff;
359: }
360: /* Apply P^T to get constraint fields */
361: (*constCtx->ops->constrainelemvec)(constCtx, grid->mesh, order, field, node, count, localNumbering,
362: PETSC_FALSE, CONSTRAINT_ROW, vec);
363:
364: count += comp + diff;
365: } else if (fieldClasses[f][nclass]) {
366: if (localNumbering == PETSC_FALSE) {
367: startVar = offsets[node] + localStart[field][nclass];
368: } else {
369: if (node >= numNodes)
370: startVar = localOffsets[node-numNodes] + localStart[field][nclass];
371: else
372: startVar = offsets[node] - firstVar[rank] + localStart[field][nclass];
373: }
374: for(i = 0; i < comp; i++, count++, source++) {
375: rowIdx[count] = startVar + i;
376: array[count] = array[source];
377: }
378: #ifdef PETSC_USE_BOPT_g
379: PrintVecIndices_Private(grid, "-trace_vec_assembly", field, node, comp, count, rowIdx);
380: #endif
381: }
382: }
384: if (midnode >= 0) {
385: nclass = classes[midnode];
387: if ((isReduced == PETSC_TRUE) && (reduceFieldClasses[f][nclass])) {
388: if (localNumbering == PETSC_FALSE) {
389: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
390: source += comp;
391: inc -= comp;
392: } else {
393: if (midnode >= numNodes)
394: startVar = reduceLocalOffsets[midnode-numNodes] + reduceLocalStart[field][nclass];
395: else
396: startVar = reduceOffsets[midnode] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
397: for(i = 0; i < comp; i++, count++) {
398: rowIdx[count] = -(startVar + i + 1);
399: }
400: #ifdef PETSC_USE_BOPT_g
401: PrintVecIndices_Private(grid, "-trace_vec_assembly", field, midnode, comp, count, rowIdx);
402: #endif
403: }
404: } else if ((isConstrained == PETSC_TRUE) && (isConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
405: /* We guarantee that count <= source here */
406: diff = grid->fields[field].constraintCompDiff;
407: inc += diff;
408: /* Move rows to operate on */
409: if (count < source) {
410: for(row = 0; row < comp; row++)
411: array[count+row] = array[source+row];
412: }
413: source += comp;
414: /* We must replace this field with the constraint field and prevent overwriting in element vector */
415: if (source - count < comp + diff) {
416: /* Move old fields */
417: for(row = size-(diff+1); row >= source; row--)
418: array[row+diff] = array[row];
419: source += diff;
420: }
421: /* Apply P^T to get constraint fields */
422: (*constCtx->ops->constrainelemvec)(constCtx, grid->mesh, order, field, midnode, count, localNumbering,
423: PETSC_FALSE, CONSTRAINT_ROW, vec);
424:
425: count += comp + diff;
426: } else if (fieldClasses[f][nclass]) {
427: if (localNumbering == PETSC_FALSE) {
428: startVar = offsets[midnode] + localStart[field][nclass];
429: } else {
430: if (midnode >= numNodes)
431: startVar = localOffsets[midnode-numNodes] + localStart[field][nclass];
432: else
433: startVar = offsets[midnode] - firstVar[rank] + localStart[field][nclass];
434: }
435: for(i = 0; i < comp; i++, count++, source++) {
436: rowIdx[count] = startVar + i;
437: array[count] = array[source];
438: }
439: #ifdef PETSC_USE_BOPT_g
440: PrintVecIndices_Private(grid, "-trace_vec_assembly", field, midnode, comp, count, rowIdx);
441: #endif
442: }
443: }
444: }
445: #ifdef PETSC_USE_BOPT_g
446: if (count != vec->reduceSize + inc) {
447: SETERRQ3(PETSC_ERR_PLIB, "Invalid variable numbering edge: %d size: %d count: %dn", edge, vec->reduceSize+inc, count);
448: }
449: if (count > vec->size) {
450: SETERRQ3(PETSC_ERR_PLIB, "Number of indices %d on edge %d exceeded maximum size %dn", count, edge, vec->size);
451: }
452: #endif
453: /* Set true vector size */
454: vec->reduceSize = count;
456: return(0);
457: }
459: /*--------------------------------------------- Element Matrix Functions --------------------------------------------*/
460: /*
461: Element Matrix Structure:
463: The structure of the element matrix is diagrammed in src/gvec/grid/gridimpl.h.
465: Reduction:
467: When the variables associated with boundary conditions are being reduced, the element matrix is compressed
468: to account for their absence. This reduction only happens in the global numbering. When using the local
469: numbering, the original variable numbers are replaced by the corresponding index in grid->bdReduceVec
470: which contains the boundary values. In order to distinguish these indices, they are stored as -(idx+1).
471: The boundary values are retieved by GridLocalToElement().
472: */
473: int GridCalcElementMatIndices_Triangular_2D(Grid grid, int elem, VarOrdering sOrder, VarOrdering tOrder,
474: VarOrdering reduceOrder, PetscTruth localNumbering, ElementMat mat)
475: {
476: Mesh mesh;
477: int numCorners = grid->mesh->numCorners;
478: PetscConstraintObject constCtx = grid->constraintCtx;
479: int *colFirstVar = sOrder->firstVar;
480: int *colOffsets = sOrder->offsets;
481: int *colLocalOffsets = sOrder->localOffsets;
482: int **colLocalStart = sOrder->localStart;
483: int *rowFirstVar = tOrder->firstVar;
484: int *rowOffsets = tOrder->offsets;
485: int *rowLocalOffsets = tOrder->localOffsets;
486: int **rowLocalStart = tOrder->localStart;
487: int *rowIdx = mat->rowIndices;
488: int *colIdx = mat->colIndices;
489: int rowSize = mat->reduceRowSize;
490: int colSize = mat->reduceColSize;
491: int origRowSize = mat->reduceRowSize;
492: int origColSize = mat->reduceColSize;
493: int *newCols = mat->reduceCols;
494: PetscScalar *array = mat->array;
495: PetscScalar *tempArray = mat->tempArray;
496: int rank = grid->mesh->part->rank;
497: FieldClassMap rowMap, colMap;
498: int numNodes;
499: int numRowFields, numColFields;
500: int *rowFields, *colFields;
501: int **rowFieldClasses, **colFieldClasses;
502: int **rowReduceFieldClasses, **colReduceFieldClasses;
503: int *rowClasses, *colClasses;
504: PetscTruth rowIsReduced, colIsReduced;
505: PetscTruth rowIsConstrained, colIsConstrained;
506: int *rowIsConst, *colIsConst;
507: int *reduceFirstVar = PETSC_NULL;
508: int *reduceOffsets = PETSC_NULL;
509: int *reduceLocalOffsets = PETSC_NULL;
510: int **reduceLocalStart = PETSC_NULL;
511: int field, node, nclass, comp, startVar, diff, inc;
512: int i, f, corner, rowCount, rowSource, colCount, colSource, row, col, newCol;
513: int ierr;
516: GridGetMesh(grid, &mesh);
517: VarOrderingGetClassMap(tOrder, &rowMap);
518: VarOrderingGetClassMap(sOrder, &colMap);
519: numNodes = rowMap->numNodes;
520: numRowFields = rowMap->numFields;
521: rowFields = rowMap->fields;
522: rowFieldClasses = rowMap->fieldClasses;
523: rowReduceFieldClasses = rowMap->reduceFieldClasses;
524: rowClasses = rowMap->classes;
525: rowIsReduced = rowMap->isReduced;
526: rowIsConstrained = rowMap->isConstrained;
527: rowIsConst = rowMap->isClassConstrained;
528: numColFields = colMap->numFields;
529: colFields = colMap->fields;
530: colFieldClasses = colMap->fieldClasses;
531: colReduceFieldClasses = colMap->reduceFieldClasses;
532: colClasses = colMap->classes;
533: colIsReduced = colMap->isReduced;
534: colIsConstrained = colMap->isConstrained;
535: colIsConst = colMap->isClassConstrained;
536: if ((rowIsReduced == PETSC_TRUE) || (colIsReduced == PETSC_TRUE)) {
537: reduceFirstVar = reduceOrder->firstVar;
538: reduceOffsets = reduceOrder->offsets;
539: reduceLocalOffsets = reduceOrder->localOffsets;
540: reduceLocalStart = reduceOrder->localStart;
541: }
542: for(f = 0, rowCount = 0, rowSource = 0, inc = 0; f < numRowFields; f++) {
543: field = rowFields[f];
544: comp = grid->fields[field].disc->comp;
546: for(corner = 0; corner < numCorners; corner++) {
547: MeshGetNodeFromElement(mesh, elem, corner, &node);
548: nclass = rowClasses[node];
550: if ((rowIsReduced == PETSC_TRUE) && (rowReduceFieldClasses[f][nclass])) {
551: if (localNumbering == PETSC_FALSE) {
552: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
553: rowSource += comp;
554: inc -= comp;
555: } else {
556: if (node >= numNodes)
557: startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
558: else
559: startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
560: for(i = 0; i < comp; i++, rowCount++, rowSource++) {
561: rowIdx[rowCount] = -(startVar + i + 1);
562: }
563: }
564: } else if ((rowIsConstrained == PETSC_TRUE) && (rowIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
565: /* We guarantee that rowCount <= rowSource here */
566: diff = grid->fields[field].constraintCompDiff;
567: inc += diff;
568: /* Move rows to operate on */
569: if (rowCount < rowSource) {
570: for(row = 0; row < comp; row++)
571: for(col = 0; col < colSize; col++)
572: array[(rowCount+row)*colSize+col] = array[(rowSource+row)*colSize+col];
573: }
574: rowSource += comp;
575: /* We must replace this field with the constraint field and prevent overwriting in element matrix */
576: if (rowSource - rowCount < comp + diff) {
577: /* Move old fields */
578: for(row = rowSize-1; row >= rowSource; row--)
579: for(col = 0; col < colSize; col++)
580: array[(row+diff)*colSize+col] = array[row*colSize+col];
581: rowSource += diff;
582: rowSize += diff;
583: }
584: /* Apply P^T to get constraint fields */
585: (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, tOrder, field, node, rowCount, CONSTRAINT_ROW, mat);
586:
587: rowCount += comp + diff;
588: } else if (rowFieldClasses[f][nclass]) {
589: if (localNumbering == PETSC_FALSE) {
590: startVar = rowOffsets[node] + rowLocalStart[field][nclass];
591: } else {
592: if (node >= numNodes)
593: startVar = rowLocalOffsets[node-numNodes] + rowLocalStart[field][nclass];
594: else
595: startVar = rowOffsets[node] - rowFirstVar[rank] + rowLocalStart[field][nclass];
596: }
597: for(i = 0; i < comp; i++, rowCount++, rowSource++) {
598: rowIdx[rowCount] = startVar + i;
599: /* Shrink rows -- I do not see a way around shrinking the whole matrix */
600: if (rowCount != rowSource) {
601: for(col = 0; col < colSize; col++)
602: array[rowCount*colSize+col] = array[rowSource*colSize+col];
603: }
604: }
605: }
606: }
607: }
608: if (rowCount != origRowSize + inc) {
609: SETERRQ3(PETSC_ERR_PLIB, "Invalid row numbering elem: %d size: %d count: %dn", elem, origRowSize+inc, rowCount);
610: }
611: if (rowSize > mat->rowSize) {
612: SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d in elem %d exceeded maximum size %dn", rowSize, elem, mat->rowSize);
613: }
614: if (rowCount > mat->rowSize) {
615: SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d in elem %d exceeded maximum size %dn", rowCount, elem, mat->rowSize);
616: }
617: mat->reduceRowSize = rowCount;
619: /* Calculate the columns ordering after reduction --
620: colCount - Number of columns stacked into mat
621: colSource - Current column of mat being accessed
622: inc - The difference in size of the constrained matrix from the original
623: newCols - The column reordering, newCols[colSource] is the current column in the matrix, -1 for not present
624: */
625: for(f = 0, colCount = 0, colSource = 0, newCol = origColSize, inc = 0; f < numColFields; f++) {
626: field = colFields[f];
627: comp = grid->fields[field].disc->comp;
629: for(corner = 0; corner < numCorners; corner++) {
630: MeshGetNodeFromElement(mesh, elem, corner, &node);
631: nclass = colClasses[node];
632:
633: if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
634: if (localNumbering == PETSC_FALSE) {
635: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
636: for(i = 0; i < comp; i++, colSource++) {
637: newCols[colSource] = -1;
638: }
639: inc -= comp;
640: } else {
641: /* Put in negative indices corresponding to boundary values */
642: for(i = 0; i < comp; i++, colCount++, colSource++) {
643: newCols[colSource] = colCount;
644: }
645: }
646: } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
647: /* We must replace this field with the constraint field and prevent overwriting in element matrix */
648: diff = grid->fields[field].constraintCompDiff;
649: inc += diff;
650: if (diff > 0) {
651: /* Assume new field were previously in the last columns */
652: for(i = 0; i < comp; i++, colCount++, colSource++)
653: newCols[colSource] = colCount;
654: for(i = 0; i < diff; i++, colCount++, newCol++)
655: newCols[newCol] = colCount;
656: } else {
657: /* Just squeeze matrix */
658: for(i = 0; i < comp + diff; i++, colCount++, colSource++)
659: newCols[colSource] = colCount;
660: for(i = comp+diff; i < comp; i++, colSource++)
661: newCols[colSource] = -1;
662: }
663: } else if (colFieldClasses[f][nclass]) {
664: for(i = 0; i < comp; i++, colCount++, colSource++) {
665: newCols[colSource] = colCount;
666: }
667: }
668: }
669: }
670: #ifdef PETSC_USE_BOPT_g
671: if (colCount != origColSize + inc) {
672: SETERRQ3(PETSC_ERR_PLIB, "Invalid column numbering elem: %d size: %d count: %dn", elem, origColSize+inc, colCount);
673: }
674: if (colCount > mat->colSize) {
675: SETERRQ3(PETSC_ERR_PLIB, "Number of column indices %d in elem %d exceeded maximum size %dn", colCount, elem, mat->colSize);
676: }
677: #endif
678: mat->reduceColSize = colCount;
680: /* Reform the element matrix: newCols[original col] = new col */
681: if (mat->reduceColSize != origColSize) {
682: if (colIsConstrained == PETSC_TRUE) {
683: for(row = 0; row < mat->reduceRowSize; row++)
684: for(col = 0; col < origColSize; col++)
685: if (newCols[col] >= 0)
686: tempArray[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
687: PetscMemcpy(array, tempArray, mat->reduceRowSize*mat->reduceColSize * sizeof(PetscScalar));
688: } else {
689: /* Can copy in place if no constraints were applied since BC just delete entries */
690: for(row = 0; row < mat->reduceRowSize; row++)
691: for(col = 0; col < origColSize; col++)
692: if (newCols[col] >= 0)
693: array[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
694: }
695: }
697: /* Calculate indices and constrained matrix elements */
698: for(f = 0, colCount = 0; f < numColFields; f++) {
699: field = colFields[f];
700: comp = grid->fields[field].disc->comp;
702: for(corner = 0; corner < numCorners; corner++) {
703: MeshGetNodeFromElement(mesh, elem, corner, &node);
704: nclass = colClasses[node];
705:
706: if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
707: if (localNumbering == PETSC_TRUE) {
708: if (node >= numNodes)
709: startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
710: else
711: startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
712: for(i = 0; i < comp; i++, colCount++) {
713: colIdx[colCount] = -(startVar + i + 1);
714: }
715: }
716: } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
717: /* Apply P to get constraint fields */
718: (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, sOrder, field, node, colCount, CONSTRAINT_COL, mat);
719:
720: colCount += comp + grid->fields[field].constraintCompDiff;
721: } else if (colFieldClasses[f][nclass]) {
722: if (localNumbering == PETSC_FALSE) {
723: startVar = colOffsets[node] + colLocalStart[field][nclass];
724: } else {
725: if (node >= numNodes)
726: startVar = colLocalOffsets[node-numNodes] + colLocalStart[field][nclass];
727: else
728: startVar = colOffsets[node] - colFirstVar[rank] + colLocalStart[field][nclass];
729: }
730: for(i = 0; i < comp; i++, colCount++) {
731: colIdx[colCount] = startVar + i;
732: }
733: }
734: }
735: }
737: return(0);
738: }
740: int GridCalcBoundaryElementMatIndices_Triangular_2D(Grid grid, int bd, int edge, int midnode, VarOrdering sOrder,
741: VarOrdering tOrder, VarOrdering reduceOrder, PetscTruth localNumbering,
742: ElementMat mat)
743: {
744: Mesh_Triangular *tri = (Mesh_Triangular *) grid->mesh->data;
745: int numCorners = grid->mesh->numCorners;
746: int *elements = tri->faces;
747: int *edges = tri->edges;
748: PetscConstraintObject constCtx = grid->constraintCtx;
749: int *colFirstVar = sOrder->firstVar;
750: int *colOffsets = sOrder->offsets;
751: int *colLocalOffsets = sOrder->localOffsets;
752: int **colLocalStart = sOrder->localStart;
753: int *rowFirstVar = tOrder->firstVar;
754: int *rowOffsets = tOrder->offsets;
755: int *rowLocalOffsets = tOrder->localOffsets;
756: int **rowLocalStart = tOrder->localStart;
757: int *rowIdx = mat->rowIndices;
758: int *colIdx = mat->colIndices;
759: int rowSize = mat->reduceRowSize;
760: int colSize = mat->reduceColSize;
761: int origRowSize = mat->reduceRowSize;
762: int origColSize = mat->reduceColSize;
763: int *newCols = mat->reduceCols;
764: PetscScalar *array = mat->array;
765: PetscScalar *tempArray = mat->tempArray;
766: int rank = grid->mesh->part->rank;
767: FieldClassMap rowMap, colMap;
768: int numNodes;
769: int numRowFields, numColFields;
770: int *rowFields, *colFields;
771: int **rowFieldClasses, **colFieldClasses;
772: int **rowReduceFieldClasses, **colReduceFieldClasses;
773: int *rowClasses, *colClasses;
774: PetscTruth rowIsReduced, colIsReduced;
775: PetscTruth rowIsConstrained, colIsConstrained;
776: int *rowIsConst, *colIsConst;
777: int *reduceFirstVar = PETSC_NULL;
778: int *reduceOffsets = PETSC_NULL;
779: int *reduceLocalOffsets = PETSC_NULL;
780: int **reduceLocalStart = PETSC_NULL;
781: int field, node, nclass, comp, startVar, diff, inc;
782: int i, f, elem, corner, rowCount, rowSource, colCount, colSource, row, col, newCol;
783: int ierr;
786: VarOrderingGetClassMap(tOrder, &rowMap);
787: VarOrderingGetClassMap(sOrder, &colMap);
788: numNodes = rowMap->numNodes;
789: numRowFields = rowMap->numFields;
790: rowFields = rowMap->fields;
791: rowFieldClasses = rowMap->fieldClasses;
792: rowReduceFieldClasses = rowMap->reduceFieldClasses;
793: rowClasses = rowMap->classes;
794: rowIsReduced = rowMap->isReduced;
795: rowIsConstrained = rowMap->isConstrained;
796: rowIsConst = rowMap->isClassConstrained;
797: numColFields = colMap->numFields;
798: colFields = colMap->fields;
799: colFieldClasses = colMap->fieldClasses;
800: colReduceFieldClasses = colMap->reduceFieldClasses;
801: colClasses = colMap->classes;
802: colIsReduced = colMap->isReduced;
803: colIsConstrained = colMap->isConstrained;
804: colIsConst = colMap->isClassConstrained;
805: if ((rowIsReduced == PETSC_TRUE) || (colIsReduced == PETSC_TRUE)) {
806: reduceFirstVar = reduceOrder->firstVar;
807: reduceOffsets = reduceOrder->offsets;
808: reduceLocalOffsets = reduceOrder->localOffsets;
809: reduceLocalStart = reduceOrder->localStart;
810: }
811: MeshGetBdElementFromEdge(grid->mesh, edge, &elem);
812: for(f = 0, rowCount = 0, rowSource = 0, inc = 0; f < numRowFields; f++) {
813: field = rowFields[f];
814: comp = grid->fields[field].disc->comp;
816: for(corner = 0; corner < numCorners; corner++) {
817: node = elements[elem*numCorners+corner];
818: nclass = rowClasses[node];
820: if ((rowIsReduced == PETSC_TRUE) && (rowReduceFieldClasses[f][nclass])) {
821: if (localNumbering == PETSC_FALSE) {
822: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
823: rowSource += comp;
824: inc -= comp;
825: } else {
826: if (node >= numNodes)
827: startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
828: else
829: startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
830: for(i = 0; i < comp; i++, rowCount++, rowSource++) {
831: rowIdx[rowCount] = -(startVar + i + 1);
832: }
833: }
834: } else if ((rowIsConstrained == PETSC_TRUE) && (rowIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
835: /* We guarantee that rowCount <= rowSource here */
836: diff = grid->fields[field].constraintCompDiff;
837: inc += diff;
838: /* Move rows to operate on */
839: if (rowCount < rowSource) {
840: for(row = 0; row < comp; row++)
841: for(col = 0; col < colSize; col++)
842: array[(rowCount+row)*colSize+col] = array[(rowSource+row)*colSize+col];
843: }
844: rowSource += comp;
845: /* We must replace this field with the constraint field and prevent overwriting in element matrix */
846: if (rowSource - rowCount < comp + diff) {
847: /* Move old fields */
848: for(row = rowSize-1; row >= rowSource; row--)
849: for(col = 0; col < colSize; col++)
850: array[(row+diff)*colSize+col] = array[row*colSize+col];
851: rowSource += diff;
852: rowSize += diff;
853: }
854: /* Apply P^T to get constraint fields */
855: (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, tOrder, field, node, rowCount, CONSTRAINT_ROW, mat);
856:
857: rowCount += comp + diff;
858: } else if (rowFieldClasses[f][nclass]) {
859: if (localNumbering == PETSC_FALSE) {
860: startVar = rowOffsets[node] + rowLocalStart[field][nclass];
861: } else {
862: if (node >= numNodes)
863: startVar = rowLocalOffsets[node-numNodes] + rowLocalStart[field][nclass];
864: else
865: startVar = rowOffsets[node] - rowFirstVar[rank] + rowLocalStart[field][nclass];
866: }
867: for(i = 0; i < comp; i++, rowCount++, rowSource++) {
868: rowIdx[rowCount] = startVar + i;
869: /* Shrink rows -- I do not see a way around shrinking the whole matrix */
870: if (rowCount != rowSource) {
871: for(col = 0; col < colSize; col++)
872: array[rowCount*colSize+col] = array[rowSource*colSize+col];
873: }
874: }
875: }
876: }
877: }
878: if (rowCount != origRowSize + inc) {
879: SETERRQ3(PETSC_ERR_PLIB, "Invalid row numbering edge: %d size: %d count: %dn", edge, origRowSize+inc, rowCount);
880: }
881: if (rowSize > mat->rowSize) {
882: SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d on edge %d exceeded maximum size %dn", rowSize, edge, mat->rowSize);
883: }
884: if (rowCount > mat->rowSize) {
885: SETERRQ3(PETSC_ERR_PLIB, "Number of row indices %d on edge %d exceeded maximum size %dn", rowCount, edge, mat->rowSize);
886: }
887: mat->reduceRowSize = rowCount;
889: /* Calculate the columns ordering after reduction --
890: colCount - Number of columns stacked into mat
891: colSource - Current column of mat being accessed
892: inc - The difference in size of the constrained matrix from the original
893: newCols - The column reordering, newCols[colSource] is the current column in the matrix, -1 for not present
894: */
895: for(f = 0, colCount = 0, colSource = 0, newCol = origColSize, inc = 0; f < numColFields; f++) {
896: field = colFields[f];
897: comp = grid->fields[field].disc->bdDisc->comp;
899: for(corner = 0; corner < 2; corner++) {
900: node = edges[edge*2+corner];
901: nclass = colClasses[node];
903: if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
904: if (localNumbering == PETSC_FALSE) {
905: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
906: for(i = 0; i < comp; i++, colSource++) {
907: newCols[colSource] = -1;
908: }
909: inc -= comp;
910: } else {
911: /* Put in negative indices corresponding to boundary values */
912: for(i = 0; i < comp; i++, colCount++, colSource++) {
913: newCols[colSource] = colCount;
914: }
915: }
916: } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
917: /* We must replace this field with the constraint field and prevent overwriting in element matrix */
918: diff = grid->fields[field].constraintCompDiff;
919: inc += diff;
920: if (diff > 0) {
921: /* Assume new field were previously in the last columns */
922: for(i = 0; i < comp; i++, colCount++, colSource++)
923: newCols[colSource] = colCount;
924: for(i = 0; i < diff; i++, colCount++, newCol++)
925: newCols[newCol] = colCount;
926: } else {
927: /* Just squeeze matrix */
928: for(i = 0; i < comp + diff; i++, colCount++, colSource++)
929: newCols[colSource] = colCount;
930: for(i = comp+diff; i < comp; i++, colSource++)
931: newCols[colSource] = -1;
932: }
933: } else if (colFieldClasses[f][nclass]) {
934: for(i = 0; i < comp; i++, colCount++, colSource++) {
935: newCols[colSource] = colCount;
936: }
937: }
938: }
940: if (midnode >= 0) {
941: nclass = colClasses[midnode];
943: if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
944: if (localNumbering == PETSC_FALSE) {
945: /* Increment source pointer in value array, which corresponds to skipping constrained variables */
946: for(i = 0; i < comp; i++, colSource++) {
947: newCols[colSource] = -1;
948: }
949: inc -= comp;
950: } else {
951: /* Put in negative indices corresponding to boundary values */
952: for(i = 0; i < comp; i++, colCount++, colSource++) {
953: newCols[colSource] = colCount;
954: }
955: }
956: } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
957: /* We must replace this field with the constraint field and prevent overwriting in element matrix */
958: diff = grid->fields[field].constraintCompDiff;
959: inc += diff;
960: if (diff > 0) {
961: /* Assume new field were previously in the last columns */
962: for(i = 0; i < comp; i++, colCount++, colSource++)
963: newCols[colSource] = colCount;
964: for(i = 0; i < diff; i++, colCount++, newCol++)
965: newCols[newCol] = colCount;
966: } else {
967: /* Just squeeze matrix */
968: for(i = 0; i < comp + diff; i++, colCount++, colSource++)
969: newCols[colSource] = colCount;
970: for(i = comp+diff; i < comp; i++, colSource++)
971: newCols[colSource] = -1;
972: }
973: } else if (colFieldClasses[f][nclass]) {
974: for(i = 0; i < comp; i++, colCount++, colSource++) {
975: newCols[colSource] = colCount;
976: }
977: }
978: }
979: }
980: #ifdef PETSC_USE_BOPT_g
981: if (colCount != origColSize + inc) {
982: SETERRQ3(PETSC_ERR_PLIB, "Invalid column numbering edge: %d size: %d count: %dn", edge, origColSize+inc, colCount);
983: }
984: if (colCount > mat->colSize) {
985: SETERRQ3(PETSC_ERR_PLIB, "Number of column indices %d on edge %d exceeded maximum size %dn", colCount, edge, mat->colSize);
986: }
987: #endif
988: mat->reduceColSize = colCount;
990: /* Reform the element matrix: newCols[original col] = new col */
991: if (mat->reduceColSize != origColSize) {
992: if (colIsConstrained == PETSC_TRUE) {
993: for(row = 0; row < mat->reduceRowSize; row++)
994: for(col = 0; col < origColSize; col++)
995: if (newCols[col] >= 0)
996: tempArray[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
997: PetscMemcpy(array, tempArray, mat->reduceRowSize*mat->reduceColSize * sizeof(PetscScalar));
998: } else {
999: /* Can copy in place if no constraints were applied since BC just delete entries */
1000: for(row = 0; row < mat->reduceRowSize; row++)
1001: for(col = 0; col < origColSize; col++)
1002: if (newCols[col] >= 0)
1003: array[row*mat->reduceColSize+newCols[col]] = array[row*origColSize+col];
1004: }
1005: }
1007: /* Calculate indices and constrained matrix elements */
1008: for(f = 0, colCount = 0; f < numColFields; f++) {
1009: field = colFields[f];
1010: comp = grid->fields[field].disc->comp;
1012: for(corner = 0; corner < 2; corner++) {
1013: node = edges[edge*2+corner];
1014: nclass = colClasses[node];
1015:
1016: if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
1017: if (localNumbering == PETSC_TRUE) {
1018: if (node >= numNodes)
1019: startVar = reduceLocalOffsets[node-numNodes] + reduceLocalStart[field][nclass];
1020: else
1021: startVar = reduceOffsets[node] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
1022: for(i = 0; i < comp; i++, colCount++) {
1023: colIdx[colCount] = -(startVar + i + 1);
1024: }
1025: }
1026: } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
1027: /* Apply P to get constraint fields */
1028: (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, sOrder, field, node, colCount, CONSTRAINT_COL, mat);
1029:
1030: colCount += comp + grid->fields[field].constraintCompDiff;
1031: } else if (colFieldClasses[f][nclass]) {
1032: if (localNumbering == PETSC_FALSE) {
1033: startVar = colOffsets[node] + colLocalStart[field][nclass];
1034: } else {
1035: if (node >= numNodes)
1036: startVar = colLocalOffsets[node-numNodes] + colLocalStart[field][nclass];
1037: else
1038: startVar = colOffsets[node] - colFirstVar[rank] + colLocalStart[field][nclass];
1039: }
1040: for(i = 0; i < comp; i++, colCount++) {
1041: colIdx[colCount] = startVar + i;
1042: }
1043: }
1044: }
1046: if (midnode >= 0) {
1047: nclass = colClasses[midnode];
1048:
1049: if ((colIsReduced == PETSC_TRUE) && (colReduceFieldClasses[f][nclass])) {
1050: if (localNumbering == PETSC_TRUE) {
1051: if (midnode >= numNodes)
1052: startVar = reduceLocalOffsets[midnode-numNodes] + reduceLocalStart[field][nclass];
1053: else
1054: startVar = reduceOffsets[midnode] - reduceFirstVar[rank] + reduceLocalStart[field][nclass];
1055: for(i = 0; i < comp; i++, colCount++) {
1056: colIdx[colCount] = -(startVar + i + 1);
1057: }
1058: }
1059: } else if ((colIsConstrained == PETSC_TRUE) && (colIsConst[nclass]) && (grid->fields[field].isConstrained == PETSC_TRUE)) {
1060: /* Apply P to get constraint fields */
1061: (*constCtx->ops->constrainelemmat)(constCtx, grid->mesh, sOrder, field, midnode, colCount, CONSTRAINT_COL, mat);
1062:
1063: colCount += comp + grid->fields[field].constraintCompDiff;
1064: } else if (colFieldClasses[f][nclass]) {
1065: if (localNumbering == PETSC_FALSE) {
1066: startVar = colOffsets[midnode] + colLocalStart[field][nclass];
1067: } else {
1068: if (midnode >= numNodes)
1069: startVar = colLocalOffsets[midnode-numNodes] + colLocalStart[field][nclass];
1070: else
1071: startVar = colOffsets[midnode] - colFirstVar[rank] + colLocalStart[field][nclass];
1072: }
1073: for(i = 0; i < comp; i++, colCount++) {
1074: colIdx[colCount] = startVar + i;
1075: }
1076: }
1077: }
1078: }
1080: return(0);
1081: }