Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ModeLaplace2DQ2.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 "ModeLaplace2DQ2.h"
36 #include "Teuchos_Assert.hpp"
37 
38 
39 const int ModeLaplace2DQ2::dofEle = 9;
40 const int ModeLaplace2DQ2::maxConnect = 25;
41 #ifndef M_PI
42 const double ModeLaplace2DQ2::M_PI = 3.14159265358979323846;
43 #endif
44 
45 
46 ModeLaplace2DQ2::ModeLaplace2DQ2(const Epetra_Comm &_Comm, double _Lx, int _nX,
47  double _Ly, int _nY)
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  x(0),
59  y(0)
60  {
61 
62  preProcess();
63 
64 }
65 
66 
67 ModeLaplace2DQ2::~ModeLaplace2DQ2() {
68 
69  if (Map)
70  delete Map;
71  Map = 0;
72 
73  if (K)
74  delete K;
75  K = 0;
76 
77  if (M)
78  delete M;
79  M = 0;
80 
81  if (x)
82  delete[] x;
83  x = 0;
84 
85  if (y)
86  delete[] y;
87  y = 0;
88 
89 }
90 
91 
92 void ModeLaplace2DQ2::preProcess() {
93 
94  // Create the distribution of equations across processors
95  makeMap();
96 
97  // Count the number of elements touched by this processor
98  bool *isTouched = new bool[nX*nY];
99  int i, j;
100  for (j = 0; j < nY; ++j)
101  for (i=0; i<nX; ++i)
102  isTouched[i + j*nX] = false;
103 
104  int numEle = countElements(isTouched);
105 
106  // Create the mesh
107  int *elemTopo = new int[dofEle*numEle];
108  makeMyElementsTopology(elemTopo, isTouched);
109 
110  delete[] isTouched;
111 
112  // Get the number of nonZeros per row
113  int localSize = Map->NumMyElements();
114  int *numNz = new int[localSize];
115  int *connectivity = new int[localSize*maxConnect];
116  makeMyConnectivity(elemTopo, numEle, connectivity, numNz);
117 
118  // Make the stiffness matrix
119  makeStiffness(elemTopo, numEle, connectivity, numNz);
120 
121  // Assemble the mass matrix
122  makeMass(elemTopo, numEle, connectivity, numNz);
123 
124  // Free some memory
125  delete[] elemTopo;
126  delete[] numNz;
127  delete[] connectivity;
128 
129  // Get the geometrical coordinates of the managed nodes
130  double hx = Lx/nX;
131  double hy = Ly/nY;
132 
133  x = new double[localSize];
134  y = new double[localSize];
135 
136  for (j=0; j<2*nY-1; ++j) {
137  for (i=0; i<2*nX-1; ++i) {
138  int node = i + j*(2*nX-1);
139  if (Map->LID(node) > -1) {
140  x[Map->LID(node)] = (i+1)*hx*0.5;
141  y[Map->LID(node)] = (j+1)*hy*0.5;
142  }
143  }
144  }
145 
146 }
147 
148 
149 void ModeLaplace2DQ2::makeMap() {
150 
151  int numProc = MyComm.NumProc();
152  int globalSize = (2*nX - 1)*(2*nY - 1);
153  assert(globalSize > numProc);
154 
155 #ifdef _USE_CHACO
156  // Use the partitioner Chaco to distribute the unknowns
157  int *start = new int[globalSize+1];
158  memset(start, 0, (globalSize+1)*sizeof(int));
159 
160  int i, j;
161  for (j=0; j<2*nY-1; ++j) {
162  for (i=0; i<2*nX-1; ++i) {
163  int node = i + j*(2*nX-1);
164  int connect = 1;
165  if (i%2 == 1) {
166  connect *= ((i == 1) || (i == 2*nX-3)) ? 4 : 5;
167  }
168  else {
169  connect *= ((i == 0) || (i == 2*nX-2)) ? 2 : 3;
170  }
171  if (j%2 == 1) {
172  connect *= ((j == 1) || (j == 2*nY-3)) ? 4 : 5;
173  }
174  else {
175  connect *= ((j == 0) || (j == 2*nY-2)) ? 2 : 3;
176  }
177  // Don't count the node itself for Chaco
178  start[node+1] = connect - 1;
179  }
180  }
181 
182  for (i = 0; i < globalSize; ++i)
183  start[i+1] += start[i];
184 
185  int *adjacency = new int[start[globalSize]];
186  memset(adjacency, 0, start[globalSize]*sizeof(int));
187 
188  int *elemTopo = new int[dofEle];
189  for (j=0; j<nY; ++j) {
190  for (i=0; i<nX; ++i) {
191  int middleMiddle = 2*i + 2*j*(2*nX - 1);
192  elemTopo[0] = ((i==0) || (j==0)) ? -1 : middleMiddle - 2*nX;
193  elemTopo[1] = ((i==nX-1) || (j==0)) ? -1 : middleMiddle - 2*nX + 2;
194  elemTopo[2] = ((i==nX-1) || (j==nY-1)) ? -1 : middleMiddle + 2*nX;
195  elemTopo[3] = ((i==0) || (j==nY-1)) ? -1 : middleMiddle + 2*nX - 2;
196  elemTopo[4] = (j==0) ? -1 : middleMiddle - 2*nX + 1;
197  elemTopo[5] = (i==nX-1) ? -1 : middleMiddle + 1;
198  elemTopo[6] = (j==nY-1) ? -1 : middleMiddle + 2*nX - 1;
199  elemTopo[7] = (i==0) ? -1 : middleMiddle - 1;
200  elemTopo[8] = middleMiddle;
201  for (int iD = 0; iD < dofEle; ++iD) {
202  if (elemTopo[iD] == -1)
203  continue;
204  for (int jD = 0; jD < dofEle; ++jD) {
205  int neighbor = elemTopo[jD];
206  // Don't count the node itself for Chaco
207  if ((neighbor == -1) || (iD == jD))
208  continue;
209  // Check if this neighbor is already stored
210  for (int l = start[elemTopo[iD]]; l < start[elemTopo[iD]+1]; ++l) {
211  // Note that Chaco uses a Fortran numbering
212  if (adjacency[l] == neighbor + 1)
213  break;
214  if (adjacency[l] == 0) {
215  // Store the node ID
216  // Note that Chaco uses a Fortran numbering
217  adjacency[l] = elemTopo[jD] + 1;
218  break;
219  }
220  } // for (int l = start[elemTopo[iD]]; l < start[elemTopo[iD]+1]; ++l)
221  } // for (int jD = 0; jD < dofEle; ++jD)
222  } // for (int iD = 0; iD < dofEle; ++iD)
223  }
224  }
225  delete[] elemTopo;
226 
227  int nDir[3];
228  nDir[0] = numProc;
229  nDir[1] = 0;
230  nDir[2] = 0;
231  short int *partition = new short int[globalSize];
232  // Call Chaco to partition the matrix
233  interface(globalSize, start, adjacency, 0, 0, 0, 0, 0, 0, 0,
234  partition, 1, 1, nDir, 0, 1, 1, 1, 250, 1, 0.001, 7654321L);
235  // Define the Epetra_Map
236  int localSize = 0;
237  int myPid = MyComm.MyPID();
238  for (i = 0; i < globalSize; ++i) {
239  if (partition[i] == myPid)
240  localSize += 1;
241  }
242  int *myRows = new int[localSize];
243  localSize = 0;
244  for (i = 0; i < globalSize; ++i) {
245  if (partition[i] == myPid) {
246  myRows[localSize] = i;
247  localSize +=1 ;
248  }
249  }
250  delete[] partition;
251  delete[] adjacency;
252  delete[] start;
253  Map = new Epetra_Map(globalSize, localSize, myRows, 0, MyComm);
254  delete[] myRows;
255 #else
256  // Create a uniform distribution of the unknowns across processors
257  Map = new Epetra_Map(globalSize, 0, MyComm);
258 #endif
259 
260 }
261 
262 
263 int ModeLaplace2DQ2::countElements(bool *isTouched) {
264 
265  // This routine counts and flags the elements that contain the nodes
266  // on this processor.
267 
268  int i, j;
269  int numEle = 0;
270 
271  for (j=0; j<nY; ++j) {
272  for (i=0; i<nX; ++i) {
273  isTouched[i + j*nX] = false;
274  int middleMiddle = 2*i + 2*j*(2*nX - 1);
275  int node;
276  node = ((i==0) || (j==0)) ? -1 : middleMiddle - 2*nX;
277  if ((node > -1) && (Map->LID(node) > -1)) {
278  isTouched[i+j*nX] = true;
279  numEle += 1;
280  continue;
281  }
282  node = ((i==nX-1) || (j==0)) ? -1 : middleMiddle - 2*nX + 2;
283  if ((node > -1) && (Map->LID(node) > -1)) {
284  isTouched[i+j*nX] = true;
285  numEle += 1;
286  continue;
287  }
288  node = ((i==nX-1) || (j==nY-1)) ? -1 : middleMiddle + 2*nX;
289  if ((node > -1) && (Map->LID(node) > -1)) {
290  isTouched[i+j*nX] = true;
291  numEle += 1;
292  continue;
293  }
294  node = ((i==0) || (j==nY-1)) ? -1 : middleMiddle + 2*nX - 2;
295  if ((node > -1) && (Map->LID(node) > -1)) {
296  isTouched[i+j*nX] = true;
297  numEle += 1;
298  continue;
299  }
300  node = (j==0) ? -1 : middleMiddle - 2*nX + 1;
301  if ((node > -1) && (Map->LID(node) > -1)) {
302  isTouched[i+j*nX] = true;
303  numEle += 1;
304  continue;
305  }
306  node = (i==nX-1) ? -1 : middleMiddle + 1;
307  if ((node > -1) && (Map->LID(node) > -1)) {
308  isTouched[i+j*nX] = true;
309  numEle += 1;
310  continue;
311  }
312  node = (j==nY-1) ? -1 : middleMiddle + 2*nX - 1;
313  if ((node > -1) && (Map->LID(node) > -1)) {
314  isTouched[i+j*nX] = true;
315  numEle += 1;
316  continue;
317  }
318  node = (i==0) ? -1 : middleMiddle - 1;
319  if ((node > -1) && (Map->LID(node) > -1)) {
320  isTouched[i+j*nX] = true;
321  numEle += 1;
322  continue;
323  }
324  node = middleMiddle;
325  if ((node > -1) && (Map->LID(node) > -1)) {
326  isTouched[i+j*nX] = true;
327  numEle += 1;
328  continue;
329  }
330  }
331  }
332 
333  return numEle;
334 
335 }
336 
337 
338 void ModeLaplace2DQ2::makeMyElementsTopology(int *elemTopo, bool *isTouched) {
339 
340  // Create the element topology for the elements containing nodes for this processor
341  // Note: Put the flag -1 when the node has a Dirichlet boundary condition
342 
343  int i, j;
344  int numEle = 0;
345 
346  for (j=0; j<nY; ++j) {
347  for (i=0; i<nX; ++i) {
348  if (isTouched[i + j*nX] == false)
349  continue;
350  int middleMiddle = 2*i + 2*j*(2*nX - 1);
351  elemTopo[dofEle*numEle] = ((i==0) || (j==0)) ? -1 : middleMiddle - 2*nX;
352  elemTopo[dofEle*numEle+1] = ((i==nX-1) || (j==0)) ? -1 : middleMiddle - 2*nX + 2;
353  elemTopo[dofEle*numEle+2] = ((i==nX-1) || (j==nY-1)) ? -1 : middleMiddle + 2*nX;
354  elemTopo[dofEle*numEle+3] = ((i==0) || (j==nY-1)) ? -1 : middleMiddle + 2*nX - 2;
355  elemTopo[dofEle*numEle+4] = (j==0) ? -1 : middleMiddle - 2*nX + 1;
356  elemTopo[dofEle*numEle+5] = (i==nX-1) ? -1 : middleMiddle + 1;
357  elemTopo[dofEle*numEle+6] = (j==nY-1) ? -1 : middleMiddle + 2*nX - 1;
358  elemTopo[dofEle*numEle+7] = (i==0) ? -1 : middleMiddle - 1;
359  elemTopo[dofEle*numEle+8] = middleMiddle;
360  numEle += 1;
361  }
362  }
363 
364 }
365 
366 
367 void ModeLaplace2DQ2::makeMyConnectivity(int *elemTopo, int numEle, int *connectivity,
368  int *numNz) {
369 
370  // This routine creates the connectivity of each managed node
371  // from the element topology.
372 
373  int i, j;
374  int localSize = Map->NumMyElements();
375 
376  for (i=0; i<localSize; ++i) {
377  numNz[i] = 0;
378  for (j=0; j<maxConnect; ++j) {
379  connectivity[i*maxConnect + j] = -1;
380  }
381  }
382 
383  for (i=0; i<numEle; ++i) {
384  for (j=0; j<dofEle; ++j) {
385  if (elemTopo[dofEle*i+j] == -1)
386  continue;
387  int node = Map->LID(elemTopo[dofEle*i+j]);
388  if (node > -1) {
389  int k;
390  for (k=0; k<dofEle; ++k) {
391  int neighbor = elemTopo[dofEle*i+k];
392  if (neighbor == -1)
393  continue;
394  // Check if this neighbor is already stored
395  int l;
396  for (l=0; l<maxConnect; ++l) {
397  if (neighbor == connectivity[node*maxConnect + l])
398  break;
399  if (connectivity[node*maxConnect + l] == -1) {
400  connectivity[node*maxConnect + l] = neighbor;
401  numNz[node] += 1;
402  break;
403  }
404  } // for (l = 0; l < maxConnect; ++l)
405  } // for (k = 0; k < dofEle; ++k)
406  } // if (node > -1)
407  } // for (j = 0; j < dofEle; ++j)
408  } // for (i = 0; i < numEle; ++i)
409 
410 }
411 
412 
413 void ModeLaplace2DQ2::makeStiffness(int *elemTopo, int numEle, int *connectivity,
414  int *numNz) {
415 
416  // Create Epetra_Matrix for stiffness
417  K = new Epetra_CrsMatrix(Copy, *Map, numNz);
418 
419  int i;
420  int localSize = Map->NumMyElements();
421 
422  double *values = new double[maxConnect];
423  for (i=0; i<maxConnect; ++i)
424  values[i] = 0.0;
425 
426  for (i=0; i<localSize; ++i) {
427  int info = K->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity+maxConnect*i);
428  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
429  "ModeLaplace2DQ2::makeStiffness(): InsertGlobalValues() returned error code " << info);
430  }
431 
432  // Define the elementary matrix
433  double *kel = new double[dofEle*dofEle];
434  makeElementaryStiffness(kel);
435 
436  // Assemble the matrix
437  int *indices = new int[dofEle];
438  int numEntries;
439  int j;
440  for (i=0; i<numEle; ++i) {
441  for (j=0; j<dofEle; ++j) {
442  if (elemTopo[dofEle*i + j] == -1)
443  continue;
444  if (Map->LID(elemTopo[dofEle*i+j]) == -1)
445  continue;
446  numEntries = 0;
447  int k;
448  for (k=0; k<dofEle; ++k) {
449  if (elemTopo[dofEle*i+k] == -1)
450  continue;
451  indices[numEntries] = elemTopo[dofEle*i+k];
452  values[numEntries] = kel[dofEle*j + k];
453  numEntries += 1;
454  }
455  int info = K->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
456  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
457  "ModeLaplace2DQ2::makeStiffness(): SumIntoGlobalValues() returned error code " << info);
458  }
459  }
460 
461  delete[] kel;
462  delete[] values;
463  delete[] indices;
464 
465  int info = K->FillComplete();
466  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
467  "ModeLaplace2DQ2::makeStiffness(): FillComplete() returned error code " << info);
468  info = K->OptimizeStorage();
469  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
470  "ModeLaplace2DQ2::makeStiffness(): OptimizeStorage() returned error code " << info);
471 
472 }
473 
474 
475 void ModeLaplace2DQ2::makeElementaryStiffness(double *kel) const {
476 
477  int i, j;
478 
479  double hx = Lx/nX;
480  double hy = Ly/nY;
481 
482  for (i=0; i<dofEle; ++i) {
483  for (j=0; j<dofEle; ++j) {
484  kel[j + dofEle*i] = 0.0;
485  }
486  }
487 
488  double gaussP[3], gaussW[3];
489  gaussP[0] = - sqrt(3.0/5.0); gaussP[1] = 0.0; gaussP[2] = - gaussP[0];
490  gaussW[0] = 5.0/9.0; gaussW[1] = 8.0/9.0; gaussW[2] = 5.0/9.0;
491  double jac = hx*hy/4.0;
492  double *qx = new double[dofEle];
493  double *qy = new double[dofEle];
494  for (i=0; i<3; ++i) {
495  double xi = gaussP[i];
496  double wi = gaussW[i];
497  for (j=0; j<3; ++j) {
498  double eta = gaussP[j];
499  double wj = gaussW[j];
500  // Get the shape functions
501  qx[0] = 2.0/hx*(xi-0.5)*0.5*eta*(eta-1.0);
502  qx[1] = 2.0/hx*(xi+0.5)*0.5*eta*(eta-1.0);
503  qx[2] = 2.0/hx*(xi+0.5)*0.5*eta*(eta+1.0);
504  qx[3] = 2.0/hx*(xi-0.5)*0.5*eta*(eta+1.0);
505  qx[4] = 2.0/hx*(-2.0*xi)*0.5*eta*(eta-1.0);
506  qx[5] = 2.0/hx*(xi+0.5)*(eta+1.0)*(1.0-eta);
507  qx[6] = 2.0/hx*(-2.0*xi)*0.5*eta*(eta+1.0);
508  qx[7] = 2.0/hx*(xi-0.5)*(eta+1.0)*(1.0-eta);
509  qx[8] = 2.0/hx*(-2.0*xi)*(eta+1.0)*(1.0-eta);
510  qy[0] = 2.0/hy*0.5*xi*(xi-1.0)*(eta-0.5);
511  qy[1] = 2.0/hy*0.5*xi*(xi+1.0)*(eta-0.5);
512  qy[2] = 2.0/hy*0.5*xi*(xi+1.0)*(eta+0.5);
513  qy[3] = 2.0/hy*0.5*xi*(xi-1.0)*(eta+0.5);
514  qy[4] = 2.0/hy*(xi+1.0)*(1.0-xi)*(eta-0.5);
515  qy[5] = 2.0/hy*0.5*xi*(xi+1.0)*(-2.0*eta);
516  qy[6] = 2.0/hy*(xi+1.0)*(1.0-xi)*(eta+0.5);
517  qy[7] = 2.0/hy*0.5*xi*(xi-1.0)*(-2.0*eta);
518  qy[8] = 2.0/hy*(xi+1.0)*(1.0-xi)*(-2.0*eta);
519  // Add in the elementary matrix
520  int ii, jj;
521  for (ii=0; ii<dofEle; ++ii) {
522  for (jj=ii; jj<dofEle; ++jj) {
523  kel[dofEle*ii + jj] += wi*wj*jac*(qx[ii]*qx[jj] + qy[ii]*qy[jj]);
524  kel[dofEle*jj + ii] = kel[dofEle*ii + jj];
525  }
526  }
527  }
528  }
529  delete[] qx;
530  delete[] qy;
531 
532 }
533 
534 
535 void ModeLaplace2DQ2::makeMass(int *elemTopo, int numEle, int *connectivity,
536  int *numNz) {
537 
538  // Create Epetra_Matrix for mass
539  M = new Epetra_CrsMatrix(Copy, *Map, numNz);
540 
541  int i;
542  int localSize = Map->NumMyElements();
543 
544  double *values = new double[maxConnect];
545  for (i=0; i<maxConnect; ++i)
546  values[i] = 0.0;
547  for (i=0; i<localSize; ++i) {
548  int info = M->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity + maxConnect*i);
549  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
550  "ModeLaplace2DQ2::makeMass(): InsertGlobalValues() returned error code " << info);
551  }
552 
553  // Define the elementary matrix
554  double *mel = new double[dofEle*dofEle];
555  makeElementaryMass(mel);
556 
557  // Assemble the matrix
558  int *indices = new int[dofEle];
559  int numEntries;
560  int j;
561  for (i=0; i<numEle; ++i) {
562  for (j=0; j<dofEle; ++j) {
563  if (elemTopo[dofEle*i + j] == -1)
564  continue;
565  if (Map->LID(elemTopo[dofEle*i+j]) == -1)
566  continue;
567  numEntries = 0;
568  int k;
569  for (k=0; k<dofEle; ++k) {
570  if (elemTopo[dofEle*i+k] == -1)
571  continue;
572  indices[numEntries] = elemTopo[dofEle*i+k];
573  values[numEntries] = mel[dofEle*j + k];
574  numEntries += 1;
575  }
576  int info = M->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
577  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
578  "ModeLaplace2DQ2::makeMass(): SumIntoGlobalValues() returned error code " << info);
579  }
580  }
581 
582  delete[] mel;
583  delete[] values;
584  delete[] indices;
585 
586  int info = M->FillComplete();
587  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
588  "ModeLaplace2DQ2::makeMass(): FillComplete() returned error code " << info);
589  info = M->OptimizeStorage();
590  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
591  "ModeLaplace2DQ2::makeMass(): OptimizeStorage() returned error code " << info);
592 
593 }
594 
595 
596 void ModeLaplace2DQ2::makeElementaryMass(double *mel) const {
597 
598  int i, j;
599 
600  double hx = Lx/nX;
601  double hy = Ly/nY;
602 
603  for (i=0; i<dofEle; ++i) {
604  for (j=0; j<dofEle; ++j) {
605  mel[j + dofEle*i] = 0.0;
606  }
607  }
608 
609  double gaussP[3], gaussW[3];
610  gaussP[0] = - sqrt(3.0/5.0); gaussP[1] = 0.0; gaussP[2] = - gaussP[0];
611  gaussW[0] = 5.0/9.0; gaussW[1] = 8.0/9.0; gaussW[2] = 5.0/9.0;
612  double jac = hx*hy/4.0;
613  double *q = new double[dofEle];
614  for (i=0; i<3; ++i) {
615  double xi = gaussP[i];
616  double wi = gaussW[i];
617  for (j=0; j<3; ++j) {
618  double eta = gaussP[j];
619  double wj = gaussW[j];
620  // Get the shape functions
621  q[0] = 0.5*xi*(xi-1.0)*0.5*eta*(eta-1.0);
622  q[1] = 0.5*xi*(xi+1.0)*0.5*eta*(eta-1.0);
623  q[2] = 0.5*xi*(xi+1.0)*0.5*eta*(eta+1.0);
624  q[3] = 0.5*xi*(xi-1.0)*0.5*eta*(eta+1.0);
625  q[4] = (xi+1.0)*(1.0-xi)*0.5*eta*(eta-1.0);
626  q[5] = 0.5*xi*(xi+1.0)*(eta+1.0)*(1.0-eta);
627  q[6] = (xi+1.0)*(1.0-xi)*0.5*eta*(eta+1.0);
628  q[7] = 0.5*xi*(xi-1.0)*(eta+1.0)*(1.0-eta);
629  q[8] = (xi+1.0)*(1.0-xi)*(eta+1.0)*(1.0-eta);
630  // Add in the elementary matrix
631  int ii, jj;
632  for (ii=0; ii<dofEle; ++ii) {
633  for (jj=ii; jj<dofEle; ++jj) {
634  mel[dofEle*ii + jj] += wi*wj*jac*q[ii]*q[jj];
635  mel[dofEle*jj + ii] = mel[dofEle*ii + jj];
636  }
637  }
638  }
639  }
640  delete[] q;
641 
642 }
643 
644 
645 double ModeLaplace2DQ2::getFirstMassEigenValue() const {
646 
647  double hx = Lx/nX;
648  double hy = Ly/nY;
649 
650  // Compute the coefficient alphay
651  double cosj = cos(M_PI*hy/2/Ly);
652  double a = 2.0*cosj;
653  double b = 4.0 + cos(M_PI*hy/Ly);
654  double c = -2.0*cosj;
655  double delta = sqrt(b*b - 4*a*c);
656  double alphay = (-b - delta)*0.5/a;
657 
658  // Compute the coefficient alphax
659  double cosi = cos(M_PI*hx/2/Lx);
660  a = 2.0*cosi;
661  b = 4.0 + cos(M_PI*hx/Lx);
662  c = -2.0*cosi;
663  delta = sqrt(b*b - 4*a*c);
664  double alphax = (-b - delta)*0.5/a;
665 
666  double discrete = hx/15.0*(8.0+2*alphax*cosi);
667  discrete *= hy/15.0*(8.0+2*alphay*cosj);
668 
669  return discrete;
670 
671 }
672 
673 
674 int ModeLaplace2DQ2::eigenCheck(const Epetra_MultiVector &Q, double *lambda,
675  double *normWeight) const {
676 
677  int info = 0;
678  int qc = Q.NumVectors();
679  int myPid = MyComm.MyPID();
680 
681  cout.precision(2);
682  cout.setf(ios::scientific, ios::floatfield);
683 
684  // Check orthonormality of eigenvectors
685  double tmp = myVerify.errorOrthonormality(&Q, M);
686  if (myPid == 0)
687  cout << " Maximum coefficient in matrix Q^T M Q - I = " << tmp << endl;
688 
689  // Print out norm of residuals
690  myVerify.errorEigenResiduals(Q, lambda, K, M, normWeight);
691 
692  // Check the eigenvalues
693  int numX = (int) ceil(sqrt(Lx*Lx*lambda[qc-1]/M_PI/M_PI));
694  numX = (numX > 2*nX) ? 2*nX : numX;
695  int numY = (int) ceil(sqrt(Ly*Ly*lambda[qc-1]/M_PI/M_PI));
696  numY = (numY > 2*nY) ? 2*nY : numY;
697  int newSize = (numX-1)*(numY-1);
698  double *discrete = new (nothrow) double[2*newSize];
699  if (discrete == 0) {
700  return -1;
701  }
702  double *continuous = discrete + newSize;
703 
704  double hx = Lx/nX;
705  double hy = Ly/nY;
706 
707  int i, j;
708  for (j = 1; j< numY; ++j) {
709  // Compute the coefficient alphay
710  double cosj = cos(j*M_PI*hy/2/Ly);
711  double a = cosj*(92.0 - 12.0*cos(j*M_PI*hy/Ly));
712  double b = 48.0 + 32.0*cos(j*M_PI*hy/Ly);
713  double c = -160.0*cosj;
714  double delta = sqrt(b*b - 4*a*c);
715  double alphay = ((-b - delta)*0.5/a < 0.0) ? (-b + delta)*0.5/a : (-b - delta)*0.5/a;
716  for (i = 1; i < numX; ++i) {
717  int pos = i-1 + (j-1)*(numX-1);
718  continuous[pos] = M_PI*M_PI*(i*i/(Lx*Lx) + j*j/(Ly*Ly));
719  // Compute the coefficient alphax
720  double cosi = cos(i*M_PI*hx/2/Lx);
721  a = cosi*(92.0 - 12.0*cos(i*M_PI*hx/Lx));
722  b = 48.0 + 32.0*cos(i*M_PI*hx/Lx);
723  c = -160.0*cosi;
724  delta = sqrt(b*b - 4*a*c);
725  double alphax = ((-b - delta)*0.5/a < 0.0) ? (-b + delta)*0.5/a : (-b - delta)*0.5/a;
726  // Compute the discrete eigenvalue
727  discrete[pos] = 240.0*(1.0-alphax*cosi)/((8.0+2*alphax*cosi)*(3.0*hx*hx));
728  discrete[pos] += 240.0*(1.0-alphay*cosj)/((8.0+2*alphay*cosj)*(3.0*hy*hy));
729  }
730  }
731 
732  // Sort the eigenvalues in ascending order
733  mySort.sortScalars(newSize, continuous);
734 
735  int *used = new (nothrow) int[newSize];
736  if (used == 0) {
737  delete[] discrete;
738  return -1;
739  }
740 
741  mySort.sortScalars(newSize, discrete, used);
742 
743  int *index = new (nothrow) int[newSize];
744  if (index == 0) {
745  delete[] discrete;
746  delete[] used;
747  return -1;
748  }
749 
750  for (i=0; i<newSize; ++i) {
751  index[used[i]] = i;
752  }
753  delete[] used;
754 
755  int nMax = myVerify.errorLambda(continuous, discrete, newSize, lambda, qc);
756 
757  // Define the exact discrete eigenvectors
758  int localSize = Map->NumMyElements();
759  double *vQ = new (nothrow) double[(nMax+1)*localSize + nMax];
760  if (vQ == 0) {
761  delete[] discrete;
762  delete[] index;
763  info = -1;
764  return info;
765  }
766 
767  double *normL2 = vQ + (nMax+1)*localSize;
768  Epetra_MultiVector Qex(View, *Map, vQ, localSize, nMax);
769 
770  if ((myPid == 0) && (nMax > 0)) {
771  cout << endl;
772  cout << " --- Relative discretization errors for exact eigenvectors ---" << endl;
773  cout << endl;
774  cout << " Cont. Values Disc. Values Error H^1 norm L^2 norm\n";
775  }
776 
777  for (j=1; j < numY; ++j) {
778  for (i=1; i < numX; ++i) {
779  if (index[i-1 + (j-1)*(numX-1)] < nMax) {
780  // Compute the coefficients alphax and alphay
781  double cosj = cos(j*M_PI*hy/2/Ly);
782  double a = cosj*(92.0 - 12.0*cos(j*M_PI*hy/Ly));
783  double b = 48.0 + 32.0*cos(j*M_PI*hy/Ly);
784  double c = -160.0*cosj;
785  double delta = sqrt(b*b - 4*a*c);
786  double alphay = ((-b - delta)*0.5/a < 0.0) ? (-b + delta)*0.5/a : (-b - delta)*0.5/a;
787  double cosi = cos(i*M_PI*hx/2/Lx);
788  a = cosi*(92.0 - 12.0*cos(i*M_PI*hx/Lx));
789  b = 48.0 + 32.0*cos(i*M_PI*hx/Lx);
790  c = -160.0*cosi;
791  delta = sqrt(b*b - 4*a*c);
792  double alphax = ((-b - delta)*0.5/a < 0.0) ? (-b + delta)*0.5/a : (-b - delta)*0.5/a;
793  int ii;
794  for (ii=0; ii<localSize; ++ii) {
795  double coeff = sin(i*(M_PI/Lx)*x[ii])*sin(j*(M_PI/Ly)*y[ii]);
796  if (fabs(x[ii] - floor(x[ii]/hx+0.5)*hx) < 0.25*hx)
797  coeff *= alphax;
798  if (fabs(y[ii] - floor(y[ii]/hy+0.5)*hy) < 0.25*hy)
799  coeff *= alphay;
800  Qex.ReplaceMyValue(ii, index[i-1+(j-1)*(numX-1)], coeff);
801  }
802  // Normalize Qex against the mass matrix
803  Epetra_MultiVector MQex(View, *Map, vQ + nMax*localSize, localSize, 1);
804  Epetra_MultiVector Qi(View, Qex, index[i-1+(j-1)*(numX-1)], 1);
805  M->Apply(Qi, MQex);
806  double mnorm = 0.0;
807  Qi.Dot(MQex, &mnorm);
808  Qi.Scale(1.0/sqrt(mnorm));
809  // Compute the L2 norm
810  Epetra_MultiVector shapeInt(View, *Map, vQ + nMax*localSize, localSize, 1);
811  for (ii=0; ii<localSize; ++ii) {
812  double iX, iY;
813  if (fabs(x[ii] - floor(x[ii]/hx+0.5)*hx) < 0.25*hx)
814  iX = 2.0*sin(i*(M_PI/Lx)*x[ii])/(hx*hx*i*(M_PI/Lx)*i*(M_PI/Lx)*i*(M_PI/Lx))*
815  sqrt(2.0/Lx)*( 3*hx*i*(M_PI/Lx) - 4*sin(i*(M_PI/Lx)*hx) +
816  cos(i*(M_PI/Lx)*hx)*hx*i*(M_PI/Lx) );
817  else
818  iX = 8.0*sin(i*(M_PI/Lx)*x[ii])/(hx*hx*i*(M_PI/Lx)*i*(M_PI/Lx)*i*(M_PI/Lx))*
819  sqrt(2.0/Lx)*( 2*sin(i*(M_PI/Lx)*0.5*hx) -
820  cos(i*(M_PI/Lx)*0.5*hx)*hx*i*(M_PI/Lx));
821  if (fabs(y[ii] - floor(y[ii]/hy+0.5)*hy) < 0.25*hy)
822  iY = 2.0*sin(j*(M_PI/Ly)*y[ii])/(hy*hy*j*(M_PI/Ly)*j*(M_PI/Ly)*j*(M_PI/Ly))*
823  sqrt(2.0/Ly)*( 3*hy*j*(M_PI/Ly) - 4*sin(j*(M_PI/Ly)*hy) +
824  cos(j*(M_PI/Ly)*hy)*hy*j*(M_PI/Ly) );
825  else
826  iY = 8.0*sin(j*(M_PI/Ly)*y[ii])/(hy*hy*j*(M_PI/Ly)*j*(M_PI/Ly)*j*(M_PI/Ly))*
827  sqrt(2.0/Ly)*( 2*sin(j*(M_PI/Ly)*0.5*hy) -
828  cos(j*(M_PI/Ly)*0.5*hy)*hy*j*(M_PI/Ly));
829  shapeInt.ReplaceMyValue(ii, 0, iX*iY);
830  }
831  Qi.Dot(shapeInt, normL2 + index[i-1+(j-1)*(numX-1)]);
832  } // if index[i-1+(j-1)*(numX-1)] < nMax)
833  } // for (i=1; i < numX; ++i)
834  } // for (j=1; j < numY; ++j)
835 
836  if (myPid == 0) {
837  for (i = 0; i < nMax; ++i) {
838  double normH1 = continuous[i]*(1.0 - 2.0*normL2[i]) + discrete[i];
839  normL2[i] = 2.0 - 2.0*normL2[i];
840  normH1+= normL2[i];
841  // Print out the result
842  if (myPid == 0) {
843  cout << " ";
844  cout.width(4);
845  cout << i+1 << ". ";
846  cout.setf(ios::scientific, ios::floatfield);
847  cout.precision(8);
848  cout << continuous[i] << " " << discrete[i] << " ";
849  cout.precision(3);
850  cout << fabs(discrete[i] - continuous[i])/continuous[i] << " ";
851  cout << sqrt(fabs(normH1)/(continuous[i]+1.0)) << " ";
852  cout << sqrt(fabs(normL2[i])) << endl;
853  }
854  } // for (i = 0; i < nMax; ++i)
855  } // if (myPid == 0)
856 
857  delete[] discrete;
858  delete[] index;
859 
860  // Check the angles between exact discrete eigenvectors and computed
861 
862  myVerify.errorSubspaces(Q, Qex, M);
863 
864  delete[] vQ;
865 
866  return info;
867 
868 }
869 
870 
871 void ModeLaplace2DQ2::memoryInfo() const {
872 
873  int myPid = MyComm.MyPID();
874 
875  Epetra_RowMatrix *Mat = dynamic_cast<Epetra_RowMatrix *>(M);
876  if ((myPid == 0) && (Mat)) {
877  cout << " Total number of nonzero entries in mass matrix = ";
878  cout.width(15);
879  cout << Mat->NumGlobalNonzeros() << endl;
880  double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
881  memSize += 2*Mat->NumGlobalRows()*sizeof(int);
882  cout << " Memory requested for mass matrix per processor = (EST) ";
883  cout.precision(2);
884  cout.width(6);
885  cout.setf(ios::fixed, ios::floatfield);
886  cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
887  cout << endl;
888  }
889 
890  Mat = dynamic_cast<Epetra_RowMatrix *>(K);
891  if ((myPid == 0) && (Mat)) {
892  cout << " Total number of nonzero entries in stiffness matrix = ";
893  cout.width(15);
894  cout << Mat->NumGlobalNonzeros() << endl;
895  double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
896  memSize += 2*Mat->NumGlobalRows()*sizeof(int);
897  cout << " Memory requested for stiffness matrix per processor = (EST) ";
898  cout.precision(2);
899  cout.width(6);
900  cout.setf(ios::fixed, ios::floatfield);
901  cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
902  cout << endl;
903  }
904 
905 }
906 
907 
908 void ModeLaplace2DQ2::problemInfo() const {
909 
910  int myPid = MyComm.MyPID();
911 
912  if (myPid == 0) {
913  cout.precision(2);
914  cout.setf(ios::fixed, ios::floatfield);
915  cout << " --- Problem definition ---\n\n";
916  cout << " >> Laplace equation in 2D with homogeneous Dirichlet condition\n";
917  cout << " >> Domain = [0, " << Lx << "] x [0, " << Ly << "]\n";
918  cout << " >> Orthogonal mesh uniform per direction with Q2 elements (9 nodes)\n";
919  cout << endl;
920  cout << " Global size = " << Map->NumGlobalElements() << endl;
921  cout << endl;
922  cout << " Number of elements in [0, " << Lx << "] (X-direction): " << nX << endl;
923  cout << " Number of elements in [0, " << Ly << "] (Y-direction): " << nY << endl;
924  cout << endl;
925  cout << " Number of interior nodes in the X-direction: " << 2*nX-1 << endl;
926  cout << " Number of interior nodes in the Y-direction: " << 2*nY-1 << endl;
927  cout << endl;
928  }
929 
930 }
931 
932 
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual int NumGlobalNonzeros() const =0
virtual int NumGlobalRows() const =0