Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
39 const int ModeLaplace3DQ1::dofEle = 8;
40 const int ModeLaplace3DQ1::maxConnect = 27;
41 #ifndef M_PI
42 const double ModeLaplace3DQ1::M_PI = 3.14159265358979323846;
43 #endif
44 
45 
46 ModeLaplace3DQ1::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 
70 ModeLaplace3DQ1::~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 
99 void 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 
162 void 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 
270 int 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 
341 void 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 
379 void 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 
425 void 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 
520 void 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 
608 double 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 
616 int 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 
778 void 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 
815 void 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 
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual int NumGlobalNonzeros() const =0
virtual int NumGlobalRows() const =0