Anasazi Version of the Day
Loading...
Searching...
No Matches
ModeLaplace3DQ1.cpp
1// @HEADER
2// *****************************************************************************
3// Anasazi: Block Eigensolvers Package
4//
5// Copyright 2004 NTESS and the Anasazi contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10//**************************************************************************
11//
12// NOTICE
13//
14// This software is a result of the research described in the report
15//
16// " A comparison of algorithms for modal analysis in the absence
17// of a sparse direct method", P. ArbenZ, R. Lehoucq, and U. Hetmaniuk,
18// Sandia National Laboratories, Technical report SAND2003-1028J.
19//
20// It is based on the Epetra, AztecOO, and ML packages defined in the Trilinos
21// framework ( http://software.sandia.gov/trilinos/ ).
22//
23// The distribution of this software follows also the rules defined in Trilinos.
24// This notice shall be marked on anY reproduction of this software, in whole or
25// in part.
26//
27// This program is distributed in the hope that it will be useful, but
28// WITHOUT ANY WARRANTY; without even the implied warranty of
29// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
30//
31// Code Authors: U. Hetmaniuk (ulhetma@sandia.gov), R. Lehoucq (rblehou@sandia.gov)
32//
33//**************************************************************************
34
35#include "ModeLaplace3DQ1.h"
36#include "Teuchos_Assert.hpp"
37
38
39const int ModeLaplace3DQ1::dofEle = 8;
40const int ModeLaplace3DQ1::maxConnect = 27;
41#ifndef M_PI
42const double ModeLaplace3DQ1::M_PI = 3.14159265358979323846;
43#endif
44
45
46ModeLaplace3DQ1::ModeLaplace3DQ1(const Epetra_Comm &_Comm, double _Lx, int _nX,
47 double _Ly, int _nY, double _Lz, int _nZ)
48 : myVerify(_Comm),
49 MyComm(_Comm),
50 mySort(),
51 Map(0),
52 K(0),
53 M(0),
54 Lx(_Lx),
55 nX(_nX),
56 Ly(_Ly),
57 nY(_nY),
58 Lz(_Lz),
59 nZ(_nZ),
60 x(0),
61 y(0),
62 z(0)
63 {
64
65 preProcess();
66
67}
68
69
70ModeLaplace3DQ1::~ModeLaplace3DQ1() {
71
72 if (Map)
73 delete Map;
74 Map = 0;
75
76 if (K)
77 delete K;
78 K = 0;
79
80 if (M)
81 delete M;
82 M = 0;
83
84 if (x)
85 delete[] x;
86 x = 0;
87
88 if (y)
89 delete[] y;
90 y = 0;
91
92 if (z)
93 delete[] z;
94 z = 0;
95
96}
97
98
99void ModeLaplace3DQ1::preProcess() {
100
101 // Create the distribution of equations across processors
102 makeMap();
103
104 // Count the number of elements touched by this processor
105 bool *isTouched = new bool[nX*nY*nZ];
106 int i, j, k;
107 for (k = 0; k < nZ; ++k)
108 for (j = 0; j < nY; ++j)
109 for (i=0; i<nX; ++i)
110 isTouched[i + j*nX + k*nX*nY] = false;
111
112 int numEle = countElements(isTouched);
113
114 // Create the mesh
115 int *elemTopo = new int[dofEle*numEle];
116 makeMyElementsTopology(elemTopo, isTouched);
117
118 delete[] isTouched;
119
120 // Get the number of nonZeros per row
121 int localSize = Map->NumMyElements();
122 int *numNz = new int[localSize];
123 int *connectivity = new int[localSize*maxConnect];
124 makeMyConnectivity(elemTopo, numEle, connectivity, numNz);
125
126 // Make the stiffness matrix
127 makeStiffness(elemTopo, numEle, connectivity, numNz);
128
129 // Assemble the mass matrix
130 makeMass(elemTopo, numEle, connectivity, numNz);
131
132 // Free some memory
133 delete[] elemTopo;
134 delete[] numNz;
135 delete[] connectivity;
136
137 // Get the geometrical coordinates of the managed nodes
138 double hx = Lx/nX;
139 double hy = Ly/nY;
140 double hz = Lz/nZ;
141
142 x = new double[localSize];
143 y = new double[localSize];
144 z = new double[localSize];
145
146 for (k=0; k<nZ-1; ++k) {
147 for (j=0; j<nY-1; ++j) {
148 for (i=0; i<nX-1; ++i) {
149 int node = i + j*(nX-1) + k*(nX-1)*(nY-1);
150 if (Map->LID(node) > -1) {
151 x[Map->LID(node)] = (i+1)*hx;
152 y[Map->LID(node)] = (j+1)*hy;
153 z[Map->LID(node)] = (k+1)*hz;
154 }
155 }
156 }
157 }
158
159}
160
161
162void ModeLaplace3DQ1::makeMap() {
163
164 int numProc = MyComm.NumProc();
165 int globalSize = (nX - 1)*(nY - 1)*(nZ - 1);
166 assert(globalSize > numProc);
167
168#ifdef _USE_CHACO
169 // Use the partitioner Chaco to distribute the unknowns
170 int *start = new int[globalSize+1];
171 memset(start, 0, (globalSize+1)*sizeof(int));
172
173 int i, j, k;
174 for (k=0; k<nZ-1; ++k) {
175 for (j=0; j<nY-1; ++j) {
176 for (i=0; i<nX-1; ++i) {
177 int node = i + j*(nX-1) + k*(nX-1)*(nY-1);
178 int connect = 1;
179 connect *= ((i == 0) || (i == nX-2)) ? 2 : 3;
180 connect *= ((j == 0) || (j == nY-2)) ? 2 : 3;
181 connect *= ((k == 0) || (k == nZ-2)) ? 2 : 3;
182 // Don't count the node itself for Chaco
183 start[node+1] = connect - 1;
184 }
185 }
186 }
187
188 for (i = 0; i < globalSize; ++i)
189 start[i+1] += start[i];
190
191 int *adjacency = new int[start[globalSize]];
192 memset(adjacency, 0, start[globalSize]*sizeof(int));
193
194 int *elemTopo = new int[dofEle];
195 for (k=0; k<nZ; ++k) {
196 for (j=0; j<nY; ++j) {
197 for (i=0; i<nX; ++i) {
198 int leftCorner = i-1 + (j-1)*(nX-1) + (k-1)*(nX-1)*(nY-1);
199 elemTopo[0] = ((i==0) || (j==0) || (k==0)) ? -1 : leftCorner;
200 elemTopo[1]= ((i==nX-1) || (j==0) || (k==0)) ? -1 : leftCorner+1;
201 elemTopo[2]= ((i==nX-1) || (j==nY-1) || (k==0)) ? -1 : leftCorner+nX;
202 elemTopo[3]= ((i==0) || (j==nY-1) || (k==0)) ? -1 : leftCorner+nX-1;
203 elemTopo[4]= ((i==0) || (j==0) || (k==nZ-1)) ? -1 : leftCorner+(nX-1)*(nY-1);
204 elemTopo[5]= ((i==nX-1) || (j==0) || (k==nZ-1)) ? -1 : leftCorner+1+(nX-1)*(nY-1);
205 elemTopo[6]= ((i==nX-1) || (j==nY-1) || (k==nZ-1)) ? -1 : leftCorner+nX+(nX-1)*(nY-1);
206 elemTopo[7]= ((i==0) || (j==nY-1) || (k==nZ-1)) ? -1 : leftCorner+nX-1+(nX-1)*(nY-1);
207 for (int iD = 0; iD < dofEle; ++iD) {
208 if (elemTopo[iD] == -1)
209 continue;
210 for (int jD = 0; jD < dofEle; ++jD) {
211 int neighbor = elemTopo[jD];
212 // Don't count the node itself for Chaco
213 if ((neighbor == -1) || (iD == jD))
214 continue;
215 // Check if this neighbor is already stored
216 for (int l = start[elemTopo[iD]]; l < start[elemTopo[iD]+1]; ++l) {
217 // Note that Chaco uses a Fortran numbering
218 if (adjacency[l] == neighbor + 1)
219 break;
220 if (adjacency[l] == 0) {
221 // Store the node ID
222 // Note that Chaco uses a Fortran numbering
223 adjacency[l] = elemTopo[jD] + 1;
224 break;
225 }
226 } // for (int l = start[elemTopo[iD]]; l < start[elemTopo[iD]+1]; ++l)
227 } // for (int jD = 0; jD < dofEle; ++jD)
228 } // for (int iD = 0; iD < dofEle; ++iD)
229 }
230 }
231 }
232 delete[] elemTopo;
233
234 int nDir[3];
235 nDir[0] = numProc;
236 nDir[1] = 0;
237 nDir[2] = 0;
238 short int *partition = new short int[globalSize];
239 // Call Chaco to partition the matrix
240 interface(globalSize, start, adjacency, 0, 0, 0, 0, 0, 0, 0,
241 partition, 1, 1, nDir, 0, 1, 1, 1, 250, 1, 0.001, 7654321L);
242 // Define the Epetra_Map
243 int localSize = 0;
244 int myPid = MyComm.MyPID();
245 for (i = 0; i < globalSize; ++i) {
246 if (partition[i] == myPid)
247 localSize += 1;
248 }
249 int *myRows = new int[localSize];
250 localSize = 0;
251 for (i = 0; i < globalSize; ++i) {
252 if (partition[i] == myPid) {
253 myRows[localSize] = i;
254 localSize +=1 ;
255 }
256 }
257 delete[] partition;
258 delete[] adjacency;
259 delete[] start;
260 Map = new Epetra_Map(globalSize, localSize, myRows, 0, MyComm);
261 delete[] myRows;
262#else
263 // Create a uniform distribution of the unknowns across processors
264 Map = new Epetra_Map(globalSize, 0, MyComm);
265#endif
266
267}
268
269
270int ModeLaplace3DQ1::countElements(bool *isTouched) {
271
272 // This routine counts and flags the elements that contain the nodes
273 // on this processor.
274
275 int i, j, k;
276 int numEle = 0;
277
278 for (k=0; k<nZ; ++k) {
279 for (j=0; j<nY; ++j) {
280 for (i=0; i<nX; ++i) {
281 isTouched[i + j*nX + k*nX*nY] = false;
282 int leftCorner = i-1 + (j-1)*(nX-1) + (k-1)*(nX-1)*(nY-1);
283 int node;
284 node = ((i==0) || (j==0) || (k==0)) ? -1 : leftCorner;
285 if ((node > -1) && (Map->LID(node) > -1)) {
286 isTouched[i + j*nX + k*nX*nY] = true;
287 numEle += 1;
288 continue;
289 }
290 node = ((i==nX-1) || (j==0) || (k==0)) ? -1 : leftCorner+1;
291 if ((node > -1) && (Map->LID(node) > -1)) {
292 isTouched[i + j*nX + k*nX*nY] = true;
293 numEle += 1;
294 continue;
295 }
296 node = ((i==nX-1) || (j==nY-1) || (k==0)) ? -1 : leftCorner+nX;
297 if ((node > -1) && (Map->LID(node) > -1)) {
298 isTouched[i + j*nX + k*nX*nY] = true;
299 numEle += 1;
300 continue;
301 }
302 node = ((i==0) || (j==nY-1) || (k==0)) ? -1 : leftCorner+nX-1;
303 if ((node > -1) && (Map->LID(node) > -1)) {
304 isTouched[i + j*nX + k*nX*nY] = true;
305 numEle += 1;
306 continue;
307 }
308 node = ((i==0) || (j==0) || (k==nZ-1)) ? -1 : leftCorner+(nX-1)*(nY-1);
309 if ((node > -1) && (Map->LID(node) > -1)) {
310 isTouched[i + j*nX + k*nX*nY] = true;
311 numEle += 1;
312 continue;
313 }
314 node = ((i==nX-1) || (j==0) || (k==nZ-1)) ? -1 : leftCorner+1+(nX-1)*(nY-1);
315 if ((node > -1) && (Map->LID(node) > -1)) {
316 isTouched[i + j*nX + k*nX*nY] = true;
317 numEle += 1;
318 continue;
319 }
320 node = ((i==nX-1) || (j==nY-1) || (k==nZ-1)) ? -1 : leftCorner+nX+(nX-1)*(nY-1);
321 if ((node > -1) && (Map->LID(node) > -1)) {
322 isTouched[i + j*nX + k*nX*nY] = true;
323 numEle += 1;
324 continue;
325 }
326 node = ((i==0) || (j==nY-1) || (k==nZ-1)) ? -1 : leftCorner+nX-1+(nX-1)*(nY-1);
327 if ((node > -1) && (Map->LID(node) > -1)) {
328 isTouched[i + j*nX + k*nX*nY] = true;
329 numEle += 1;
330 continue;
331 }
332 }
333 }
334 }
335
336 return numEle;
337
338}
339
340
341void ModeLaplace3DQ1::makeMyElementsTopology(int *elemTopo, bool *isTouched) {
342
343 // Create the element topology for the elements containing nodes for this processor
344 // Note: Put the flag -1 when the node has a Dirichlet boundary condition
345
346 int i, j, k;
347 int numEle = 0;
348
349 for (k=0; k<nZ; ++k) {
350 for (j=0; j<nY; ++j) {
351 for (i=0; i<nX; ++i) {
352 if (isTouched[i + j*nX + k*nX*nY] == false)
353 continue;
354 int leftCorner = i-1 + (j-1)*(nX-1) + (k-1)*(nX-1)*(nY-1);
355 elemTopo[8*numEle] = ((i==0) || (j==0) || (k==0)) ?
356 -1 : leftCorner;
357 elemTopo[8*numEle+1]= ((i==nX-1) || (j==0) || (k==0)) ?
358 -1 : leftCorner+1;
359 elemTopo[8*numEle+2]= ((i==nX-1) || (j==nY-1) || (k==0)) ?
360 -1 : leftCorner+nX;
361 elemTopo[8*numEle+3]= ((i==0) || (j==nY-1) || (k==0)) ?
362 -1 : leftCorner+nX-1;
363 elemTopo[8*numEle+4]= ((i==0) || (j==0) || (k==nZ-1)) ?
364 -1 : leftCorner+(nX-1)*(nY-1);
365 elemTopo[8*numEle+5]= ((i==nX-1) || (j==0) || (k==nZ-1)) ?
366 -1 : leftCorner+1+(nX-1)*(nY-1);
367 elemTopo[8*numEle+6]= ((i==nX-1) || (j==nY-1) || (k==nZ-1)) ?
368 -1 : leftCorner+nX+(nX-1)*(nY-1);
369 elemTopo[8*numEle+7]= ((i==0) || (j==nY-1) || (k==nZ-1)) ?
370 -1 : leftCorner+nX-1+(nX-1)*(nY-1);
371 numEle += 1;
372 }
373 }
374 }
375
376}
377
378
379void ModeLaplace3DQ1::makeMyConnectivity(int *elemTopo, int numEle, int *connectivity,
380 int *numNz) {
381
382 // This routine creates the connectivity of each managed node
383 // from the element topology.
384
385 int i, j;
386 int localSize = Map->NumMyElements();
387
388 for (i=0; i<localSize; ++i) {
389 numNz[i] = 0;
390 for (j=0; j<maxConnect; ++j) {
391 connectivity[i*maxConnect + j] = -1;
392 }
393 }
394
395 for (i=0; i<numEle; ++i) {
396 for (j=0; j<dofEle; ++j) {
397 if (elemTopo[dofEle*i+j] == -1)
398 continue;
399 int node = Map->LID(elemTopo[dofEle*i+j]);
400 if (node > -1) {
401 int k;
402 for (k=0; k<dofEle; ++k) {
403 int neighbor = elemTopo[dofEle*i+k];
404 if (neighbor == -1)
405 continue;
406 // Check if this neighbor is already stored
407 int l;
408 for (l=0; l<maxConnect; ++l) {
409 if (neighbor == connectivity[node*maxConnect + l])
410 break;
411 if (connectivity[node*maxConnect + l] == -1) {
412 connectivity[node*maxConnect + l] = neighbor;
413 numNz[node] += 1;
414 break;
415 }
416 } // for (l = 0; l < maxConnect; ++l)
417 } // for (k = 0; k < dofEle; ++k)
418 } // if (node > -1)
419 } // for (j = 0; j < dofEle; ++j)
420 } // for (i = 0; i < numEle; ++i)
421
422}
423
424
425void ModeLaplace3DQ1::makeStiffness(int *elemTopo, int numEle, int *connectivity,
426 int *numNz) {
427
428 // Create Epetra_Matrix for stiffness
429 K = new Epetra_CrsMatrix(Copy, *Map, numNz);
430
431 int i;
432 int localSize = Map->NumMyElements();
433
434 double *values = new double[maxConnect];
435 for (i=0; i<maxConnect; ++i)
436 values[i] = 0.0;
437
438 for (i=0; i<localSize; ++i) {
439 int info = K->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity+maxConnect*i);
440 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
441 "ModeLaplace3DQ1::makeStiffness(): InsertGlobalValues() returned error code " << info);
442 }
443
444 // Define the elementary matrix
445 double hx = Lx/nX;
446 double hy = Ly/nY;
447 double hz = Lz/nZ;
448
449 double *kel = new double[dofEle*dofEle];
450
451 kel[0] = (hx*hz/hy + hy*hz/hx + hx*hy/hz)/9.0;
452 kel[1] = (hx*hz/hy - 2.0*hy*hz/hx + hx*hy/hz)/18.0;
453 kel[2] = (-2.0*hx*hz/hy - 2.0*hy*hz/hx + hx*hy/hz)/36.0;
454 kel[3] = (-2.0*hx*hz/hy + hy*hz/hx + hx*hy/hz)/18.0;
455 kel[4] = (hx*hz/hy + hy*hz/hx - 2.0*hx*hy/hz)/18.0;
456 kel[5] = (hx*hz/hy - 2.0*hy*hz/hx - 2.0*hx*hy/hz)/36.0;
457 kel[6] = - (hx*hz/hy + hy*hz/hx + hx*hy/hz)/36.0;
458 kel[7] = (-2.0*hx*hz/hy + hy*hz/hx - 2.0*hx*hy/hz)/36.0;
459
460 kel[ 8] = kel[1]; kel[ 9] = kel[0]; kel[10] = kel[3]; kel[11] = kel[2];
461 kel[12] = kel[5]; kel[13] = kel[4]; kel[14] = kel[7]; kel[15] = kel[6];
462
463 kel[16] = kel[2]; kel[17] = kel[3]; kel[18] = kel[0]; kel[19] = kel[1];
464 kel[20] = kel[6]; kel[21] = kel[7]; kel[22] = kel[4]; kel[23] = kel[5];
465
466 kel[24] = kel[3]; kel[25] = kel[2]; kel[26] = kel[1]; kel[27] = kel[0];
467 kel[28] = kel[7]; kel[29] = kel[6]; kel[30] = kel[5]; kel[31] = kel[4];
468
469 kel[32] = kel[4]; kel[33] = kel[5]; kel[34] = kel[6]; kel[35] = kel[7];
470 kel[36] = kel[0]; kel[37] = kel[1]; kel[38] = kel[2]; kel[39] = kel[3];
471
472 kel[40] = kel[5]; kel[41] = kel[4]; kel[42] = kel[7]; kel[43] = kel[6];
473 kel[44] = kel[1]; kel[45] = kel[0]; kel[46] = kel[3]; kel[47] = kel[2];
474
475 kel[48] = kel[6]; kel[49] = kel[7]; kel[50] = kel[4]; kel[51] = kel[5];
476 kel[52] = kel[2]; kel[53] = kel[3]; kel[54] = kel[0]; kel[55] = kel[1];
477
478 kel[56] = kel[7]; kel[57] = kel[6]; kel[58] = kel[5]; kel[59] = kel[4];
479 kel[60] = kel[3]; kel[61] = kel[2]; kel[62] = kel[1]; kel[63] = kel[0];
480
481 // Assemble the matrix
482 int *indices = new int[dofEle];
483 int numEntries;
484 int j;
485 for (i=0; i<numEle; ++i) {
486 for (j=0; j<dofEle; ++j) {
487 if (elemTopo[dofEle*i + j] == -1)
488 continue;
489 if (Map->LID(elemTopo[dofEle*i+j]) == -1)
490 continue;
491 numEntries = 0;
492 int k;
493 for (k=0; k<dofEle; ++k) {
494 if (elemTopo[dofEle*i+k] == -1)
495 continue;
496 indices[numEntries] = elemTopo[dofEle*i+k];
497 values[numEntries] = kel[dofEle*j + k];
498 numEntries += 1;
499 }
500 int info = K->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
501 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
502 "ModeLaplace3DQ1::makeStiffness(): SumIntoGlobalValues() returned error code " << info);
503 }
504 }
505
506 delete[] kel;
507 delete[] values;
508 delete[] indices;
509
510 int info = K->FillComplete();
511 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
512 "ModeLaplace3DQ1::makeStiffness(): FillComplete() returned error code " << info);
513 info = K->OptimizeStorage();
514 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
515 "ModeLaplace3DQ1::makeStiffness(): OptimizeStorage() returned error code " << info);
516
517}
518
519
520void ModeLaplace3DQ1::makeMass(int *elemTopo, int numEle, int *connectivity,
521 int *numNz) {
522
523 // Create Epetra_Matrix for mass
524 M = new Epetra_CrsMatrix(Copy, *Map, numNz);
525
526 int i;
527 int localSize = Map->NumMyElements();
528
529 double *values = new double[maxConnect];
530 for (i=0; i<maxConnect; ++i)
531 values[i] = 0.0;
532 for (i=0; i<localSize; ++i) {
533 int info = M->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity + maxConnect*i);
534 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
535 "ModeLaplace3DQ1::makeMass(): InsertGlobalValues() returned error code " << info);
536 }
537
538 // Define the elementary matrix
539 double hx = Lx/nX;
540 double hy = Ly/nY;
541 double hz = Lz/nZ;
542
543 double *mel = new double[dofEle*dofEle];
544
545 mel[0] = hx*hy*hz/27.0; mel[1] = hx*hy*hz/54.0; mel[2] = hx*hy*hz/108.0; mel[3] = hx*hy*hz/54.0;
546 mel[4] = hx*hy*hz/54.0; mel[5] = hx*hy*hz/108.0; mel[6]= hx*hy*hz/216.0; mel[7] =hx*hy*hz/108.0;
547
548 mel[ 8] = mel[1]; mel[ 9] = mel[0]; mel[10] = mel[3]; mel[11] = mel[2];
549 mel[12] = mel[5]; mel[13] = mel[4]; mel[14] = mel[7]; mel[15] = mel[6];
550
551 mel[16] = mel[2]; mel[17] = mel[3]; mel[18] = mel[0]; mel[19] = mel[1];
552 mel[20] = mel[6]; mel[21] = mel[7]; mel[22] = mel[4]; mel[23] = mel[5];
553
554 mel[24] = mel[3]; mel[25] = mel[2]; mel[26] = mel[1]; mel[27] = mel[0];
555 mel[28] = mel[7]; mel[29] = mel[6]; mel[30] = mel[5]; mel[31] = mel[4];
556
557 mel[32] = mel[4]; mel[33] = mel[5]; mel[34] = mel[6]; mel[35] = mel[7];
558 mel[36] = mel[0]; mel[37] = mel[1]; mel[38] = mel[2]; mel[39] = mel[3];
559
560 mel[40] = mel[5]; mel[41] = mel[4]; mel[42] = mel[7]; mel[43] = mel[6];
561 mel[44] = mel[1]; mel[45] = mel[0]; mel[46] = mel[3]; mel[47] = mel[2];
562
563 mel[48] = mel[6]; mel[49] = mel[7]; mel[50] = mel[4]; mel[51] = mel[5];
564 mel[52] = mel[2]; mel[53] = mel[3]; mel[54] = mel[0]; mel[55] = mel[1];
565
566 mel[56] = mel[7]; mel[57] = mel[6]; mel[58] = mel[5]; mel[59] = mel[4];
567 mel[60] = mel[3]; mel[61] = mel[2]; mel[62] = mel[1]; mel[63] = mel[0];
568
569 // Assemble the matrix
570 int *indices = new int[dofEle];
571 int numEntries;
572 int j;
573 for (i=0; i<numEle; ++i) {
574 for (j=0; j<dofEle; ++j) {
575 if (elemTopo[dofEle*i + j] == -1)
576 continue;
577 if (Map->LID(elemTopo[dofEle*i+j]) == -1)
578 continue;
579 numEntries = 0;
580 int k;
581 for (k=0; k<dofEle; ++k) {
582 if (elemTopo[dofEle*i+k] == -1)
583 continue;
584 indices[numEntries] = elemTopo[dofEle*i+k];
585 values[numEntries] = mel[dofEle*j + k];
586 numEntries += 1;
587 }
588 int info = M->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
589 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
590 "ModeLaplace3DQ1::makeMass(): SumIntoGlobalValues() returned error code " << info);
591 }
592 }
593
594 delete[] mel;
595 delete[] values;
596 delete[] indices;
597
598 int info = M->FillComplete();
599 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
600 "ModeLaplace3DQ1::makeMass(): FillComplete() returned error code " << info);
601 info = M->OptimizeStorage();
602 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
603 "ModeLaplace3DQ1::makeMass(): OptimizeStorage() returned error code " << info);
604
605}
606
607
608double ModeLaplace3DQ1::getFirstMassEigenValue() const {
609
610 return Lx/(3.0*nX)*(2.0-cos(M_PI/nX))*Ly/(3.0*nY)*(2.0-cos(M_PI/nY))*
611 Lz/(3.0*nZ)*(2.0-cos(M_PI/nZ));
612
613}
614
615
616int ModeLaplace3DQ1::eigenCheck(const Epetra_MultiVector &Q, double *lambda,
617 double *normWeight) const {
618
619 int info = 0;
620 int qc = Q.NumVectors();
621 int myPid = MyComm.MyPID();
622
623 cout.precision(2);
624 cout.setf(ios::scientific, ios::floatfield);
625
626 // Check orthonormality of eigenvectors
627 double tmp = myVerify.errorOrthonormality(&Q, M);
628 if (myPid == 0)
629 cout << " Maximum coefficient in matrix Q^T M Q - I = " << tmp << endl;
630
631 // Print out norm of residuals
632 myVerify.errorEigenResiduals(Q, lambda, K, M, normWeight);
633
634 // Check the eigenvalues
635 int numX = (int) ceil(sqrt(Lx*Lx*lambda[qc-1]/M_PI/M_PI));
636 numX = (numX > nX) ? nX : numX;
637 int numY = (int) ceil(sqrt(Ly*Ly*lambda[qc-1]/M_PI/M_PI));
638 numY = (numY > nY) ? nY : numY;
639 int numZ = (int) ceil(sqrt(Lz*Lz*lambda[qc-1]/M_PI/M_PI));
640 numZ = (numZ > nZ) ? nZ : numZ;
641 int newSize = (numX-1)*(numY-1)*(numZ-1);
642 double *discrete = new (nothrow) double[2*newSize];
643 if (discrete == 0) {
644 return -1;
645 }
646 double *continuous = discrete + newSize;
647
648 double hx = Lx/nX;
649 double hy = Ly/nY;
650 double hz = Lz/nZ;
651
652 int i, j, k;
653 for (k = 1; k < numZ; ++k) {
654 for (j = 1; j < numY; ++j) {
655 for (i = 1; i < numX; ++i) {
656 int pos = i-1 + (j-1)*(numX-1) + (k-1)*(numX-1)*(numY-1);
657 continuous[pos] = M_PI*M_PI*(i*i/(Lx*Lx) + j*j/(Ly*Ly) + k*k/(Lz*Lz));
658 discrete[pos] = 6.0*(1.0-cos(i*(M_PI/Lx)*hx))/(2.0+cos(i*(M_PI/Lx)*hx))/hx/hx;
659 discrete[pos] += 6.0*(1.0-cos(j*(M_PI/Ly)*hy))/(2.0+cos(j*(M_PI/Ly)*hy))/hy/hy;
660 discrete[pos] += 6.0*(1.0-cos(k*(M_PI/Lz)*hz))/(2.0+cos(k*(M_PI/Lz)*hz))/hz/hz;
661 }
662 }
663 }
664
665 // Sort the eigenvalues in ascending order
666 mySort.sortScalars(newSize, continuous);
667
668 int *used = new (nothrow) int[newSize];
669 if (used == 0) {
670 delete[] discrete;
671 return -1;
672 }
673
674 mySort.sortScalars(newSize, discrete, used);
675
676 int *index = new (nothrow) int[newSize];
677 if (index == 0) {
678 delete[] discrete;
679 delete[] used;
680 return -1;
681 }
682
683 for (i=0; i<newSize; ++i) {
684 index[used[i]] = i;
685 }
686 delete[] used;
687
688 int nMax = myVerify.errorLambda(continuous, discrete, newSize, lambda, qc);
689
690 // Define the exact discrete eigenvectors
691 int localSize = Map->NumMyElements();
692 double *vQ = new (nothrow) double[(nMax+1)*localSize + nMax];
693 if (vQ == 0) {
694 delete[] discrete;
695 delete[] index;
696 info = -1;
697 return info;
698 }
699
700 double *normL2 = vQ + (nMax+1)*localSize;
701 Epetra_MultiVector Qex(View, *Map, vQ, localSize, nMax);
702
703 if ((myPid == 0) && (nMax > 0)) {
704 cout << endl;
705 cout << " --- Relative discretization errors for exact eigenvectors ---" << endl;
706 cout << endl;
707 cout << " Cont. Values Disc. Values Error H^1 norm L^2 norm\n";
708 }
709
710 for (k=1; k < numZ; ++k) {
711 for (j=1; j < numY; ++j) {
712 for (i=1; i < numX; ++i) {
713 int pos = i-1 + (j-1)*(numX-1) + (k-1)*(numX-1)*(numY-1);
714 if (index[pos] < nMax) {
715 double coeff = (2.0 + cos(i*M_PI/Lx*hx))*Lx/6.0;
716 coeff *= (2.0 + cos(j*M_PI/Ly*hy))*Ly/6.0;
717 coeff *= (2.0 + cos(k*M_PI/Lz*hz))*Lz/6.0;
718 coeff = 1.0/sqrt(coeff);
719 int ii;
720 for (ii=0; ii<localSize; ++ii) {
721 Qex.ReplaceMyValue(ii, index[pos], coeff*sin(i*(M_PI/Lx)*x[ii])
722 *sin(j*(M_PI/Ly)*y[ii])*sin(k*(M_PI/Lz)*z[ii]) );
723 }
724 // Compute the L2 norm
725 Epetra_MultiVector shapeInt(View, *Map, vQ + nMax*localSize, localSize, 1);
726 Epetra_MultiVector Qi(View, Qex, index[pos], 1);
727 for (ii=0; ii<localSize; ++ii) {
728 double iX = 4.0*sqrt(2.0/Lx)*sin(i*(M_PI/Lx)*x[ii])/hx*
729 pow(sin(i*(M_PI/Lx)*0.5*hx)/(i*M_PI/Lx), 2.0);
730 double iY = 4.0*sqrt(2.0/Ly)*sin(j*(M_PI/Ly)*y[ii])/hy*
731 pow(sin(j*(M_PI/Ly)*0.5*hy)/(j*M_PI/Ly), 2.0);
732 double iZ = 4.0*sqrt(2.0/Lz)*sin(k*(M_PI/Lz)*z[ii])/hz*
733 pow(sin(k*(M_PI/Lz)*0.5*hz)/(k*M_PI/Lz), 2.0);
734 shapeInt.ReplaceMyValue(ii, 0, iX*iY*iZ);
735 }
736 normL2[index[pos]] = 0.0;
737 Qi.Dot(shapeInt, normL2 + index[pos]);
738 } // if index[pos] < nMax)
739 } // for (i=1; i < numX; ++i)
740 } // for (j=1; j < numY; ++j)
741 } // for (k=1; k < numZ; ++k)
742
743 if (myPid == 0) {
744 for (i = 0; i < nMax; ++i) {
745 double normH1 = continuous[i]*(1.0 - 2.0*normL2[i]) + discrete[i];
746 normL2[i] = 2.0 - 2.0*normL2[i];
747 normH1+= normL2[i];
748 // Print out the result
749 if (myPid == 0) {
750 cout << " ";
751 cout.width(4);
752 cout << i+1 << ". ";
753 cout.setf(ios::scientific, ios::floatfield);
754 cout.precision(8);
755 cout << continuous[i] << " " << discrete[i] << " ";
756 cout.precision(3);
757 cout << fabs(discrete[i] - continuous[i])/continuous[i] << " ";
758 cout << sqrt(fabs(normH1)/(continuous[i]+1.0)) << " ";
759 cout << sqrt(fabs(normL2[i])) << endl;
760 }
761 } // for (i = 0; i < nMax; ++i)
762 } // if (myPid == 0)
763
764 delete[] discrete;
765 delete[] index;
766
767 // Check the angles between exact discrete eigenvectors and computed
768
769 myVerify.errorSubspaces(Q, Qex, M);
770
771 delete[] vQ;
772
773 return info;
774
775}
776
777
778void ModeLaplace3DQ1::memoryInfo() const {
779
780 int myPid = MyComm.MyPID();
781
782 Epetra_RowMatrix *Mat = dynamic_cast<Epetra_RowMatrix *>(M);
783 if ((myPid == 0) && (Mat)) {
784 cout << " Total number of nonzero entries in mass matrix = ";
785 cout.width(15);
786 cout << Mat->NumGlobalNonzeros() << endl;
787 double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
788 memSize += 2*Mat->NumGlobalRows()*sizeof(int);
789 cout << " Memory requested for mass matrix per processor = (EST) ";
790 cout.precision(2);
791 cout.width(6);
792 cout.setf(ios::fixed, ios::floatfield);
793 cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
794 cout << endl;
795 }
796
797 Mat = dynamic_cast<Epetra_RowMatrix *>(K);
798 if ((myPid == 0) && (Mat)) {
799 cout << " Total number of nonzero entries in stiffness matrix = ";
800 cout.width(15);
801 cout << Mat->NumGlobalNonzeros() << endl;
802 double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
803 memSize += 2*Mat->NumGlobalRows()*sizeof(int);
804 cout << " Memory requested for stiffness matrix per processor = (EST) ";
805 cout.precision(2);
806 cout.width(6);
807 cout.setf(ios::fixed, ios::floatfield);
808 cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
809 cout << endl;
810 }
811
812}
813
814
815void ModeLaplace3DQ1::problemInfo() const {
816
817 int myPid = MyComm.MyPID();
818
819 if (myPid == 0) {
820 cout.precision(2);
821 cout.setf(ios::fixed, ios::floatfield);
822 cout << " --- Problem definition ---\n\n";
823 cout << " >> Laplace equation in 3D with homogeneous Dirichlet condition\n";
824 cout << " >> Domain = [0, " << Lx << "] x [0, " << Ly << "] x [0, " << Lz << "]\n";
825 cout << " >> Orthogonal mesh uniform per direction with Q1 elements\n";
826 cout << endl;
827 cout << " Global size = " << Map->NumGlobalElements() << endl;
828 cout << endl;
829 cout << " Number of elements in [0, " << Lx << "] (X-direction): " << nX << endl;
830 cout << " Number of elements in [0, " << Ly << "] (Y-direction): " << nY << endl;
831 cout << " Number of elements in [0, " << Lz << "] (Z-direction): " << nZ << endl;
832 cout << endl;
833 cout << " Number of interior nodes in the X-direction: " << nX-1 << endl;
834 cout << " Number of interior nodes in the Y-direction: " << nY-1 << endl;
835 cout << " Number of interior nodes in the Z-direction: " << nZ-1 << endl;
836 cout << endl;
837 }
838
839}
840
841