Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ModeLaplace1DQ1.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 // This software is a result of the research described in the report
11 //
12 // "A comparison of algorithms for modal analysis in the absence
13 // of a sparse direct method", P. Arbenz, R. Lehoucq, and U. Hetmaniuk,
14 // Sandia National Laboratories, Technical report SAND2003-1028J.
15 //
16 // It is based on the Epetra, AztecOO, and ML packages defined in the Trilinos
17 // framework ( http://trilinos.org/ ).
18 
19 #include "ModeLaplace1DQ1.h"
20 #include "Teuchos_Assert.hpp"
21 
22 
23 const int ModeLaplace1DQ1::dofEle = 2;
24 const int ModeLaplace1DQ1::maxConnect = 3;
25 #ifndef M_PI
26 const double ModeLaplace1DQ1::M_PI = 3.14159265358979323846;
27 #endif
28 
29 
30 ModeLaplace1DQ1::ModeLaplace1DQ1(const Epetra_Comm &_Comm, double _Lx, int _nX)
31  : myVerify(_Comm),
32  MyComm(_Comm),
33  mySort(),
34  Map(0),
35  K(0),
36  M(0),
37  Lx(_Lx),
38  nX(_nX),
39  x(0)
40  {
41 
42  preProcess();
43 
44 }
45 
46 
47 ModeLaplace1DQ1::~ModeLaplace1DQ1() {
48 
49  if (Map)
50  delete Map;
51  Map = 0;
52 
53  if (K)
54  delete K;
55  K = 0;
56 
57  if (M)
58  delete M;
59  M = 0;
60 
61  if (x)
62  delete[] x;
63  x = 0;
64 
65 }
66 
67 
68 void ModeLaplace1DQ1::preProcess() {
69 
70  // Create the distribution of equations across processors
71  makeMap();
72 
73  // Count the number of elements touched by this processor
74  bool *isTouched = new bool[nX];
75  int i;
76  for (i=0; i<nX; ++i)
77  isTouched[i] = false;
78 
79  int numEle = countElements(isTouched);
80 
81  // Create the mesh
82  int *elemTopo = new int[dofEle*numEle];
83  makeMyElementsTopology(elemTopo, isTouched);
84 
85  delete[] isTouched;
86 
87  // Get the number of nonzeros per row
88  int localSize = Map->NumMyElements();
89  int *numNz = new int[localSize];
90  int *connectivity = new int[localSize*maxConnect];
91  makeMyConnectivity(elemTopo, numEle, connectivity, numNz);
92 
93  // Make the stiffness matrix
94  makeStiffness(elemTopo, numEle, connectivity, numNz);
95 
96  // Assemble the mass matrix
97  makeMass(elemTopo, numEle, connectivity, numNz);
98 
99  // Free some memory
100  delete[] elemTopo;
101  delete[] numNz;
102  delete[] connectivity;
103 
104  // Get the geometrical coordinates of the managed nodes
105  double hx = Lx/nX;
106  x = new double[localSize];
107 
108  int globalSize = Map->NumGlobalElements();
109  for (i=0; i<globalSize; ++i) {
110  if (Map->LID(i) > -1) {
111  x[Map->LID(i)] = (i+1)*hx;
112  }
113  }
114 
115 }
116 
117 
118 void ModeLaplace1DQ1::makeMap() {
119 
120  int globalSize = nX - 1;
121  assert(globalSize > MyComm.NumProc());
122 
123  // Create a uniform distribution of the unknowns across processors
124  Map = new Epetra_Map(globalSize, 0, MyComm);
125 
126 }
127 
128 
129 int ModeLaplace1DQ1::countElements(bool *isTouched) {
130 
131  // This routine counts and flags the elements that contain the nodes
132  // on this processor.
133 
134  int i;
135  int numEle = 0;
136 
137  for (i=0; i<nX; ++i) {
138  int node;
139  node = (i==0) ? -1 : i-1;
140  if ((node > -1) && (Map->LID(node) > -1)) {
141  isTouched[i] = true;
142  numEle += 1;
143  continue;
144  }
145  node = (i==nX-1) ? -1 : i;
146  if ((node > -1) && (Map->LID(node) > -1)) {
147  isTouched[i] = true;
148  numEle += 1;
149  continue;
150  }
151  }
152 
153  return numEle;
154 
155 }
156 
157 
158 void ModeLaplace1DQ1::makeMyElementsTopology(int *elemTopo, bool *isTouched) {
159 
160  // Create the element topology for the elements containing nodes for this processor
161  // Note: Put the flag -1 when the node has a Dirichlet boundary condition
162 
163  int i;
164  int numEle = 0;
165 
166  for (i=0; i<nX; ++i) {
167  if (isTouched[i] == false)
168  continue;
169  elemTopo[dofEle*numEle] = (i==0) ? -1 : i-1;
170  elemTopo[dofEle*numEle+1] = (i==nX-1) ? -1 : i;
171  numEle += 1;
172  }
173 
174 }
175 
176 
177 void ModeLaplace1DQ1::makeMyConnectivity(int *elemTopo, int numEle, int *connectivity,
178  int *numNz) {
179 
180  // This routine creates the connectivity of each managed node
181  // from the element topology.
182 
183  int i, j;
184  int localSize = Map->NumMyElements();
185 
186  for (i=0; i<localSize; ++i) {
187  numNz[i] = 0;
188  for (j=0; j<maxConnect; ++j) {
189  connectivity[i*maxConnect + j] = -1;
190  }
191  }
192 
193  for (i=0; i<numEle; ++i) {
194  for (j=0; j<dofEle; ++j) {
195  if (elemTopo[dofEle*i+j] == -1)
196  continue;
197  int node = Map->LID(elemTopo[dofEle*i+j]);
198  if (node > -1) {
199  int k;
200  for (k=0; k<dofEle; ++k) {
201  int neighbor = elemTopo[dofEle*i+k];
202  if (neighbor == -1)
203  continue;
204  // Check if this neighbor is already stored
205  int l;
206  for (l=0; l<maxConnect; ++l) {
207  if (neighbor == connectivity[node*maxConnect + l])
208  break;
209  if (connectivity[node*maxConnect + l] == -1) {
210  connectivity[node*maxConnect + l] = neighbor;
211  numNz[node] += 1;
212  break;
213  }
214  } // for (l = 0; l < maxConnect; ++l)
215  } // for (k = 0; k < dofEle; ++k)
216  } // if (node > -1)
217  } // for (j = 0; j < dofEle; ++j)
218  } // for (i = 0; i < numEle; ++i)
219 
220 }
221 
222 
223 void ModeLaplace1DQ1::makeStiffness(int *elemTopo, int numEle, int *connectivity,
224  int *numNz) {
225 
226  // Create Epetra_Matrix for stiffness
227  K = new Epetra_CrsMatrix(Copy, *Map, numNz);
228 
229  int i;
230  int localSize = Map->NumMyElements();
231 
232  double *values = new double[maxConnect];
233  for (i=0; i<maxConnect; ++i)
234  values[i] = 0.0;
235 
236  for (i=0; i<localSize; ++i) {
237  int info = K->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity+maxConnect*i);
238  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
239  "ModeLaplace1DQ1::makeStiffness(): InsertGlobalValues() returned error code " << info);
240  }
241 
242  // Define the elementary matrix
243  double hx = Lx/nX;
244  double *kel = new double[dofEle*dofEle];
245  kel[0] = 1.0/hx; kel[1] = -1.0/hx;
246  kel[2] = -1.0/hx; kel[3] = 1.0/hx;
247 
248  // Assemble the matrix
249  int *indices = new int[dofEle];
250  int numEntries;
251  int j;
252  for (i=0; i<numEle; ++i) {
253  for (j=0; j<dofEle; ++j) {
254  if (elemTopo[dofEle*i + j] == -1)
255  continue;
256  if (Map->LID(elemTopo[dofEle*i+j]) == -1)
257  continue;
258  numEntries = 0;
259  int k;
260  for (k=0; k<dofEle; ++k) {
261  if (elemTopo[dofEle*i+k] == -1)
262  continue;
263  indices[numEntries] = elemTopo[dofEle*i+k];
264  values[numEntries] = kel[dofEle*j + k];
265  numEntries += 1;
266  }
267  int info = K->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
268  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
269  "ModeLaplace1DQ1::makeStiffness(): SumIntoGlobalValues() returned error code " << info);
270  }
271  }
272 
273  delete[] kel;
274  delete[] values;
275  delete[] indices;
276 
277  int info;
278  info = K->FillComplete();
279  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
280  "ModeLaplace1DQ1::makeStiffness(): FillComplete() returned error code " << info);
281  info = K->OptimizeStorage();
282  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
283  "ModeLaplace1DQ1::makeStiffness(): OptimizeStorage() returned error code " << info);
284 }
285 
286 
287 void ModeLaplace1DQ1::makeMass(int *elemTopo, int numEle, int *connectivity,
288  int *numNz) {
289 
290  // Create Epetra_Matrix for mass
291  M = new Epetra_CrsMatrix(Copy, *Map, numNz);
292 
293  int i;
294  int localSize = Map->NumMyElements();
295 
296  double *values = new double[maxConnect];
297  for (i=0; i<maxConnect; ++i)
298  values[i] = 0.0;
299  for (i=0; i<localSize; ++i) {
300  int info = M->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity + maxConnect*i);
301  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
302  "ModeLaplace1DQ1::makeMass(): InsertGlobalValues() returned error code " << info);
303  }
304 
305  // Define the elementary matrix
306  double hx = Lx/nX;
307 
308  double *mel = new double[dofEle*dofEle];
309  mel[0] = hx/3.0; mel[1] = hx/6.0;
310  mel[2] = hx/6.0; mel[3] = hx/3.0;
311 
312  // Assemble the matrix
313  int *indices = new int[dofEle];
314  int numEntries;
315  int j;
316  for (i=0; i<numEle; ++i) {
317  for (j=0; j<dofEle; ++j) {
318  if (elemTopo[dofEle*i + j] == -1)
319  continue;
320  if (Map->LID(elemTopo[dofEle*i+j]) == -1)
321  continue;
322  numEntries = 0;
323  int k;
324  for (k=0; k<dofEle; ++k) {
325  if (elemTopo[dofEle*i+k] == -1)
326  continue;
327  indices[numEntries] = elemTopo[dofEle*i+k];
328  values[numEntries] = mel[dofEle*j + k];
329  numEntries += 1;
330  }
331  int info = M->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
332  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
333  "ModeLaplace1DQ1::makeMass(): SumIntoGlobalValues() returned error code " << info);
334  }
335  }
336 
337  delete[] mel;
338  delete[] values;
339  delete[] indices;
340 
341  int info = M->FillComplete();
342  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
343  "ModeLaplace1DQ1::makeMass(): FillComplete() returned error code " << info);
344  info = M->OptimizeStorage();
345  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
346  "ModeLaplace1DQ1::makeMass(): OptimizeStorage() returned error code " << info);
347 }
348 
349 
350 double ModeLaplace1DQ1::getFirstMassEigenValue() const {
351 
352  return Lx/(3.0*nX)*(2.0-cos(M_PI/nX));
353 
354 }
355 
356 
357 int ModeLaplace1DQ1::eigenCheck(const Epetra_MultiVector &Q, double *lambda,
358  double *normWeight) const {
359 
360  int info = 0;
361  int qc = Q.NumVectors();
362  int myPid = MyComm.MyPID();
363 
364  cout.precision(2);
365  cout.setf(ios::scientific, ios::floatfield);
366 
367  // Check orthonormality of eigenvectors
368  double tmp = myVerify.errorOrthonormality(&Q, M);
369  if (myPid == 0)
370  cout << " Maximum coefficient in matrix Q^T M Q - I = " << tmp << endl;
371 
372  // Print out norm of residuals
373  myVerify.errorEigenResiduals(Q, lambda, K, M, normWeight);
374 
375  // Check the eigenvalues
376  int numX = (int) ceil(sqrt(Lx*Lx*lambda[qc-1]/M_PI/M_PI));
377  numX = (numX > nX) ? nX : numX;
378  int newSize = (numX-1);
379  double *discrete = new (nothrow) double[2*newSize];
380  if (discrete == 0) {
381  return -1;
382  }
383  double *continuous = discrete + newSize;
384 
385  double hx = Lx/nX;
386 
387  int i;
388  for (i = 1; i < numX; ++i) {
389  continuous[i-1] = (M_PI/Lx)*(M_PI/Lx)*i*i;
390  discrete[i-1] = 6.0*(1.0-cos(i*(M_PI/Lx)*hx))/(2.0+cos(i*(M_PI/Lx)*hx))/hx/hx;
391  }
392 
393  // Sort the eigenvalues in ascending order
394  mySort.sortScalars(newSize, continuous);
395 
396  int *used = new (nothrow) int[newSize];
397  if (used == 0) {
398  delete[] discrete;
399  return -1;
400  }
401 
402  mySort.sortScalars(newSize, discrete, used);
403 
404  int *index = new (nothrow) int[newSize];
405  if (index == 0) {
406  delete[] discrete;
407  delete[] used;
408  return -1;
409  }
410 
411  for (i=0; i<newSize; ++i) {
412  index[used[i]] = i;
413  }
414  delete[] used;
415 
416  int nMax = myVerify.errorLambda(continuous, discrete, newSize, lambda, qc);
417 
418  // Define the exact discrete eigenvectors
419  int localSize = Map->NumMyElements();
420  double *vQ = new (nothrow) double[(nMax+1)*localSize];
421  if (vQ == 0) {
422  delete[] discrete;
423  delete[] index;
424  info = -1;
425  return info;
426  }
427 
428  Epetra_MultiVector Qex(View, *Map, vQ, localSize, nMax);
429 
430  if ((myPid == 0) && (nMax > 0)) {
431  cout << endl;
432  cout << " --- Relative discretization errors for exact eigenvectors ---" << endl;
433  cout << endl;
434  cout << " Cont. Values Disc. Values Error H^1 norm L^2 norm\n";
435  }
436 
437  for (i=1; i < numX; ++i) {
438  if (index[i-1] < nMax) {
439  // Form the exact discrete eigenvector
440  double coeff = (2.0 + cos(i*M_PI/Lx*hx))*Lx/6.0;
441  coeff = 1.0/sqrt(coeff);
442  int ii;
443  for (ii=0; ii<localSize; ++ii) {
444  Qex.ReplaceMyValue(ii, index[i-1], coeff*sin(i*(M_PI/Lx)*x[ii]));
445  }
446  // Compute the L2 norm
447  Epetra_MultiVector shapeInt(View, *Map, vQ + nMax*localSize, localSize, 1);
448  Epetra_MultiVector Qi(View, Qex, index[i-1], 1);
449  for (ii=0; ii<localSize; ++ii) {
450  double iX = 4.0*sqrt(2.0/Lx)*sin(i*(M_PI/Lx)*x[ii])/hx*
451  pow(sin(i*(M_PI/Lx)*0.5*hx)/(i*M_PI/Lx), 2.0);
452  shapeInt.ReplaceMyValue(ii, 0, iX);
453  }
454  double normL2 = 0.0;
455  Qi.Dot(shapeInt, &normL2);
456  double normH1 = continuous[i-1]*(1.0 - 2.0*normL2) + discrete[i-1];
457  normL2 = 2.0 - 2.0*normL2;
458  normH1+= normL2;
459  // Print out the result
460  if (myPid == 0) {
461  cout << " ";
462  cout.width(4);
463  cout << index[i-1] << ". ";
464  cout.setf(ios::scientific, ios::floatfield);
465  cout.precision(8);
466  cout << continuous[i-1] << " " << discrete[i-1] << " ";
467  cout.precision(3);
468  cout << fabs(discrete[i-1] - continuous[i-1])/continuous[i-1] << " ";
469  cout << sqrt(fabs(normH1)/(continuous[i-1]+1.0)) << " ";
470  cout << sqrt(fabs(normL2)) << endl;
471  }
472  }
473  }
474 
475  delete[] discrete;
476  delete[] index;
477 
478  // Check the angles between exact discrete eigenvectors and computed
479 
480  myVerify.errorSubspaces(Q, Qex, M);
481 
482  delete[] vQ;
483 
484  return info;
485 
486 }
487 
488 
489 void ModeLaplace1DQ1::memoryInfo() const {
490 
491  int myPid = MyComm.MyPID();
492 
493  Epetra_RowMatrix *Mat = dynamic_cast<Epetra_RowMatrix *>(M);
494  if ((myPid == 0) && (Mat)) {
495  cout << " Total number of nonzero entries in mass matrix = ";
496  cout.width(15);
497  cout << Mat->NumGlobalNonzeros() << endl;
498  double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
499  memSize += 2*Mat->NumGlobalRows()*sizeof(int);
500  cout << " Memory requested for mass matrix per processor = (EST) ";
501  cout.precision(2);
502  cout.width(6);
503  cout.setf(ios::fixed, ios::floatfield);
504  cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
505  cout << endl;
506  }
507 
508  Mat = dynamic_cast<Epetra_RowMatrix *>(K);
509  if ((myPid == 0) && (Mat)) {
510  cout << " Total number of nonzero entries in stiffness matrix = ";
511  cout.width(15);
512  cout << Mat->NumGlobalNonzeros() << endl;
513  double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
514  memSize += 2*Mat->NumGlobalRows()*sizeof(int);
515  cout << " Memory requested for stiffness matrix per processor = (EST) ";
516  cout.precision(2);
517  cout.width(6);
518  cout.setf(ios::fixed, ios::floatfield);
519  cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
520  cout << endl;
521  }
522 
523 }
524 
525 
526 void ModeLaplace1DQ1::problemInfo() const {
527 
528  int myPid = MyComm.MyPID();
529 
530  if (myPid == 0) {
531  cout.precision(2);
532  cout.setf(ios::fixed, ios::floatfield);
533  cout << " --- Problem definition ---\n\n";
534  cout << " >> Laplace equation in 1D with homogeneous Dirichlet condition\n";
535  cout << " >> Domain = [0, " << Lx << "]\n";
536  cout << " >> Orthogonal mesh uniform per direction with Q1 elements\n";
537  cout << endl;
538  cout << " Global size = " << Map->NumGlobalElements() << endl;
539  cout << endl;
540  cout << " Number of elements in [0, " << Lx << "] (X-direction): " << nX << endl;
541  cout << endl;
542  cout << " Number of interior nodes in the X-direction: " << nX-1 << endl;
543  cout << endl;
544  }
545 
546 }
547 
548 
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual int NumGlobalNonzeros() const =0
virtual int NumGlobalRows() const =0