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: }