Anasazi Version of the Day
Loading...
Searching...
No Matches
ModeLaplace1DQ2.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 "ModeLaplace1DQ2.h"
36#include "Teuchos_Assert.hpp"
37
38
39const int ModeLaplace1DQ2::dofEle = 3;
40const int ModeLaplace1DQ2::maxConnect = 5;
41#ifndef M_PI
42const double ModeLaplace1DQ2::M_PI = 3.14159265358979323846;
43#endif
44
45
46ModeLaplace1DQ2::ModeLaplace1DQ2(const Epetra_Comm &_Comm, double _Lx, int _nX)
47 : myVerify(_Comm),
48 MyComm(_Comm),
49 mySort(),
50 Map(0),
51 K(0),
52 M(0),
53 Lx(_Lx),
54 nX(_nX),
55 x(0)
56 {
57
58 preProcess();
59
60}
61
62
63ModeLaplace1DQ2::~ModeLaplace1DQ2() {
64
65 if (Map)
66 delete Map;
67 Map = 0;
68
69 if (K)
70 delete K;
71 K = 0;
72
73 if (M)
74 delete M;
75 M = 0;
76
77 if (x)
78 delete[] x;
79 x = 0;
80
81}
82
83
84void ModeLaplace1DQ2::preProcess() {
85
86 // Create the distribution of equations across processors
87 makeMap();
88
89 // Count the number of elements touched by this processor
90 bool *isTouched = new bool[nX];
91 int i;
92 for (i=0; i<nX; ++i)
93 isTouched[i] = false;
94
95 int numEle = countElements(isTouched);
96
97 // Create the mesh
98 int *elemTopo = new int[dofEle*numEle];
99 makeMyElementsTopology(elemTopo, isTouched);
100
101 delete[] isTouched;
102
103 // Get the number of nonZeros per row
104 int localSize = Map->NumMyElements();
105 int *numNz = new int[localSize];
106 int *connectivity = new int[localSize*maxConnect];
107 makeMyConnectivity(elemTopo, numEle, connectivity, numNz);
108
109 // Make the stiffness matrix
110 makeStiffness(elemTopo, numEle, connectivity, numNz);
111
112 // Assemble the mass matrix
113 makeMass(elemTopo, numEle, connectivity, numNz);
114
115 // Free some memory
116 delete[] elemTopo;
117 delete[] numNz;
118 delete[] connectivity;
119
120 // Get the geometrical coordinates of the managed nodes
121 double hx = Lx/nX;
122
123 x = new double[localSize];
124
125 for (i=0; i<2*nX-1; ++i) {
126 int node = i;
127 if (Map->LID(node) > -1) {
128 x[Map->LID(node)] = (i+1)*hx*0.5;
129 }
130 }
131
132}
133
134
135void ModeLaplace1DQ2::makeMap() {
136
137 int globalSize = (2*nX - 1);
138 assert(globalSize > MyComm.NumProc());
139
140 // Create a uniform distribution of the unknowns across processors
141 Map = new Epetra_Map(globalSize, 0, MyComm);
142
143}
144
145
146int ModeLaplace1DQ2::countElements(bool *isTouched) {
147
148 // This routine counts and flags the elements that contain the nodes
149 // on this processor.
150
151 int i;
152 int numEle = 0;
153
154 for (i=0; i<nX; ++i) {
155 isTouched[i] = false;
156 int node;
157 node = (i==0) ? -1 : 2*i-1;
158 if ((node > -1) && (Map->LID(node) > -1)) {
159 isTouched[i] = true;
160 numEle += 1;
161 continue;
162 }
163 node = (i==nX-1) ? -1 : 2*i+1;
164 if ((node > -1) && (Map->LID(node) > -1)) {
165 isTouched[i] = true;
166 numEle += 1;
167 continue;
168 }
169 node = 2*i;
170 if ((node > -1) && (Map->LID(node) > -1)) {
171 isTouched[i] = true;
172 numEle += 1;
173 continue;
174 }
175 }
176
177 return numEle;
178
179}
180
181
182void ModeLaplace1DQ2::makeMyElementsTopology(int *elemTopo, bool *isTouched) {
183
184 // Create the element topology for the elements containing nodes for this processor
185 // Note: Put the flag -1 when the node has a Dirichlet boundary condition
186
187 int i;
188 int numEle = 0;
189
190 for (i=0; i<nX; ++i) {
191 if (isTouched[i] == false)
192 continue;
193 elemTopo[dofEle*numEle] = (i==0) ? -1 : 2*i-1;
194 elemTopo[dofEle*numEle+1] = (i==nX-1) ? -1 : 2*i+1;
195 elemTopo[dofEle*numEle+2] = 2*i;
196 numEle += 1;
197 }
198
199}
200
201
202void ModeLaplace1DQ2::makeMyConnectivity(int *elemTopo, int numEle, int *connectivity,
203 int *numNz) {
204
205 // This routine creates the connectivity of each managed node
206 // from the element topology.
207
208 int i, j;
209 int localSize = Map->NumMyElements();
210
211 for (i=0; i<localSize; ++i) {
212 numNz[i] = 0;
213 for (j=0; j<maxConnect; ++j) {
214 connectivity[i*maxConnect + j] = -1;
215 }
216 }
217
218 for (i=0; i<numEle; ++i) {
219 for (j=0; j<dofEle; ++j) {
220 if (elemTopo[dofEle*i+j] == -1)
221 continue;
222 int node = Map->LID(elemTopo[dofEle*i+j]);
223 if (node > -1) {
224 int k;
225 for (k=0; k<dofEle; ++k) {
226 int neighbor = elemTopo[dofEle*i+k];
227 if (neighbor == -1)
228 continue;
229 // Check if this neighbor is already stored
230 int l;
231 for (l=0; l<maxConnect; ++l) {
232 if (neighbor == connectivity[node*maxConnect + l])
233 break;
234 if (connectivity[node*maxConnect + l] == -1) {
235 connectivity[node*maxConnect + l] = neighbor;
236 numNz[node] += 1;
237 break;
238 }
239 } // for (l = 0; l < maxConnect; ++l)
240 } // for (k = 0; k < dofEle; ++k)
241 } // if (node > -1)
242 } // for (j = 0; j < dofEle; ++j)
243 } // for (i = 0; i < numEle; ++i)
244
245}
246
247
248void ModeLaplace1DQ2::makeStiffness(int *elemTopo, int numEle, int *connectivity,
249 int *numNz) {
250
251 // Create Epetra_Matrix for stiffness
252 K = new Epetra_CrsMatrix(Copy, *Map, numNz);
253
254 int i;
255 int localSize = Map->NumMyElements();
256
257 double *values = new double[maxConnect];
258 for (i=0; i<maxConnect; ++i)
259 values[i] = 0.0;
260
261 for (i=0; i<localSize; ++i) {
262 int info = K->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity+maxConnect*i);
263 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
264 "ModeLaplace1DQ2::makeStiffness(): InsertGlobalValues() returned error code " << info);
265 }
266
267 // Define the elementary matrix
268 double *kel = new double[dofEle*dofEle];
269 makeElementaryStiffness(kel);
270
271 // Assemble the matrix
272 int *indices = new int[dofEle];
273 int numEntries;
274 int j;
275 for (i=0; i<numEle; ++i) {
276 for (j=0; j<dofEle; ++j) {
277 if (elemTopo[dofEle*i + j] == -1)
278 continue;
279 if (Map->LID(elemTopo[dofEle*i+j]) == -1)
280 continue;
281 numEntries = 0;
282 int k;
283 for (k=0; k<dofEle; ++k) {
284 if (elemTopo[dofEle*i+k] == -1)
285 continue;
286 indices[numEntries] = elemTopo[dofEle*i+k];
287 values[numEntries] = kel[dofEle*j + k];
288 numEntries += 1;
289 }
290 int info = K->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
291 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
292 "ModeLaplace1DQ2::makeStiffness(): SumIntoGlobalValues() returned error code " << info);
293 }
294 }
295
296 delete[] kel;
297 delete[] values;
298 delete[] indices;
299
300 int info = K->FillComplete();
301 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
302 "ModeLaplace1DQ2::makeStiffness(): FillComplete() returned error code " << info);
303 info = K->OptimizeStorage();
304 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
305 "ModeLaplace1DQ2::makeStiffness(): OptimizeStorage() returned error code " << info);
306
307}
308
309
310void ModeLaplace1DQ2::makeElementaryStiffness(double *kel) const {
311
312 double hx = Lx/nX;
313
314 kel[0] = 7.0/(3.0*hx); kel[1] = 1.0/(3.0*hx); kel[2] = - 8.0/(3.0*hx);
315 kel[3] = 1.0/(3.0*hx); kel[4] = 7.0/(3.0*hx); kel[5] = - 8.0/(3.0*hx);
316 kel[6] = - 8.0/(3.0*hx); kel[7] = - 8.0/(3.0*hx); kel[8] = 16.0/(3.0*hx);
317
318}
319
320
321void ModeLaplace1DQ2::makeMass(int *elemTopo, int numEle, int *connectivity,
322 int *numNz) {
323
324 // Create Epetra_Matrix for mass
325 M = new Epetra_CrsMatrix(Copy, *Map, numNz);
326
327 int i;
328 int localSize = Map->NumMyElements();
329
330 double *values = new double[maxConnect];
331 for (i=0; i<maxConnect; ++i)
332 values[i] = 0.0;
333 for (i=0; i<localSize; ++i) {
334 int info = M->InsertGlobalValues(Map->GID(i), numNz[i], values, connectivity + maxConnect*i);
335 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
336 "ModeLaplace1DQ2::makeMass(): InsertGlobalValues() returned error code " << info);
337 }
338
339 // Define the elementary matrix
340 double *mel = new double[dofEle*dofEle];
341 makeElementaryMass(mel);
342
343 // Assemble the matrix
344 int *indices = new int[dofEle];
345 int numEntries;
346 int j;
347 for (i=0; i<numEle; ++i) {
348 for (j=0; j<dofEle; ++j) {
349 if (elemTopo[dofEle*i + j] == -1)
350 continue;
351 if (Map->LID(elemTopo[dofEle*i+j]) == -1)
352 continue;
353 numEntries = 0;
354 int k;
355 for (k=0; k<dofEle; ++k) {
356 if (elemTopo[dofEle*i+k] == -1)
357 continue;
358 indices[numEntries] = elemTopo[dofEle*i+k];
359 values[numEntries] = mel[dofEle*j + k];
360 numEntries += 1;
361 }
362 int info = M->SumIntoGlobalValues(elemTopo[dofEle*i+j], numEntries, values, indices);
363 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
364 "ModeLaplace1DQ2::makeMass(): SumIntoGlobalValues() returned error code " << info);
365 }
366 }
367
368 delete[] mel;
369 delete[] values;
370 delete[] indices;
371
372 int info = M->FillComplete();
373 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
374 "ModeLaplace1DQ2::makeMass(): FillComplete() returned error code " << info);
375 info = M->OptimizeStorage();
376 TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::runtime_error,
377 "ModeLaplace1DQ2::makeMass(): OptimizeStorage() returned error code " << info);
378}
379
380
381void ModeLaplace1DQ2::makeElementaryMass(double *mel) const {
382
383 double hx = Lx/nX;
384
385 mel[0] = 2.0*hx/15.0; mel[1] = -hx/30.0; mel[2] = hx/15.0;
386 mel[3] = -hx/30.0; mel[4] = 2.0*hx/15.0; mel[5] = hx/15.0;
387 mel[6] = hx/15.0; mel[7] = hx/15.0; mel[8] = 8.0*hx/15.0;
388
389}
390
391
392double ModeLaplace1DQ2::getFirstMassEigenValue() const {
393
394 double hx = Lx/nX;
395
396 // Compute the coefficient alphax
397 double cosi = cos(M_PI*hx/2/Lx);
398 double a = 2.0*cosi;
399 double b = 4.0 + cos(M_PI*hx/Lx);
400 double c = -2.0*cosi;
401 double delta = sqrt(b*b - 4*a*c);
402 double alphax = (-b - delta)*0.5/a;
403
404 double discrete = hx/15.0*(8.0+2*alphax*cosi);
405
406 return discrete;
407
408}
409
410
411int ModeLaplace1DQ2::eigenCheck(const Epetra_MultiVector &Q, double *lambda,
412 double *normWeight) const {
413
414 int info = 0;
415 int qc = Q.NumVectors();
416 int myPid = MyComm.MyPID();
417
418 cout.precision(2);
419 cout.setf(ios::scientific, ios::floatfield);
420
421 // Check orthonormality of eigenvectors
422 double tmp = myVerify.errorOrthonormality(&Q, M);
423 if (myPid == 0)
424 cout << " Maximum coefficient in matrix Q^T M Q - I = " << tmp << endl;
425
426 // Print out norm of residuals
427 myVerify.errorEigenResiduals(Q, lambda, K, M, normWeight);
428
429 // Check the eigenvalues
430 int numX = (int) ceil(sqrt(Lx*Lx*lambda[qc-1]/M_PI/M_PI));
431 numX = (numX > 2*nX) ? 2*nX : numX;
432 int newSize = (numX-1);
433 double *discrete = new (nothrow) double[2*newSize];
434 if (discrete == 0) {
435 return -1;
436 }
437 double *continuous = discrete + newSize;
438
439 double hx = Lx/nX;
440
441 int i;
442 for (i = 1; i < numX; ++i) {
443 continuous[i-1] = (M_PI/Lx)*(M_PI/Lx)*i*i;
444 // Compute the coefficient alphaX
445 double cosi = cos(i*M_PI*hx/2.0/Lx);
446 double a = cosi*(92.0 - 12.0*cos(i*M_PI*hx/Lx));
447 double b = 48.0 + 32.0*cos(i*M_PI*hx/Lx);
448 double c = -160.0*cosi;
449 double delta = sqrt(b*b - 4*a*c);
450 double alphaX = (-b - delta)*0.5/a;
451 alphaX = (alphaX < 0.0) ? (-b + delta)*0.5/a : alphaX;
452 // Compute the discrete eigenvalue
453 discrete[i-1] = 240.0*(1.0 - alphaX*cosi)/( (8.0 + 2*alphaX*cosi)*(3.0*hx*hx) );
454 }
455
456 // Sort the eigenvalues in ascending order
457 mySort.sortScalars(newSize, continuous);
458
459 int *used = new (nothrow) int[newSize];
460 if (used == 0) {
461 delete[] discrete;
462 return -1;
463 }
464
465 mySort.sortScalars(newSize, discrete, used);
466
467 int *index = new (nothrow) int[newSize];
468 if (index == 0) {
469 delete[] discrete;
470 delete[] used;
471 return -1;
472 }
473
474 for (i=0; i<newSize; ++i) {
475 index[used[i]] = i;
476 }
477 delete[] used;
478
479 int nMax = myVerify.errorLambda(continuous, discrete, newSize, lambda, qc);
480
481 // Define the exact discrete eigenvectors
482 int localSize = Map->NumMyElements();
483 double *vQ = new (nothrow) double[(nMax+1)*localSize + nMax];
484 if (vQ == 0) {
485 delete[] discrete;
486 delete[] index;
487 info = -1;
488 return info;
489 }
490
491 double *normL2 = vQ + (nMax+1)*localSize;
492 Epetra_MultiVector Qex(View, *Map, vQ, localSize, nMax);
493
494 if ((myPid == 0) && (nMax > 0)) {
495 cout << endl;
496 cout << " --- Relative discretization errors for exact eigenvectors ---" << endl;
497 cout << endl;
498 cout << " Cont. Values Disc. Values Error H^1 norm L^2 norm\n";
499 }
500
501 for (i=1; i < numX; ++i) {
502 if (index[i-1] < nMax) {
503 // Compute the coefficient alphaX
504 double cosi = cos(i*M_PI*hx/2/Lx);
505 double a = cosi*(92.0 - 12.0*cos(i*M_PI*hx/Lx));
506 double b = 48.0 + 32.0*cos(i*M_PI*hx/Lx);
507 double c = -160.0*cosi;
508 double delta = sqrt(b*b - 4*a*c);
509 double alphaX = (-b - delta)*0.5/a;
510 alphaX = (alphaX < 0.0) ? (-b + delta)*0.5/a : alphaX;
511 int ii;
512 for (ii=0; ii<localSize; ++ii) {
513 if (fabs(x[ii] - floor(x[ii]/hx+0.5)*hx) < 0.25*hx) {
514 Qex.ReplaceMyValue(ii, index[i-1], alphaX*sin(i*(M_PI/Lx)*x[ii]));
515 }
516 else {
517 Qex.ReplaceMyValue(ii, index[i-1], sin(i*(M_PI/Lx)*x[ii]));
518 }
519 }
520 // Normalize Qex against the mass matrix
521 Epetra_MultiVector MQex(View, *Map, vQ + nMax*localSize, localSize, 1);
522 Epetra_MultiVector Qi(View, Qex, index[i-1], 1);
523 M->Apply(Qi, MQex);
524 double mnorm = 0.0;
525 Qi.Dot(MQex, &mnorm);
526 Qi.Scale(1.0/sqrt(mnorm));
527 // Compute the L2 norm
528 Epetra_MultiVector shapeInt(View, *Map, vQ + nMax*localSize, localSize, 1);
529 for (ii=0; ii<localSize; ++ii) {
530 double iX;
531 if (fabs(x[ii] - floor(x[ii]/hx+0.5)*hx) < 0.25*hx)
532 iX = 2.0*sin(i*(M_PI/Lx)*x[ii])/(hx*hx*i*(M_PI/Lx)*i*(M_PI/Lx)*i*(M_PI/Lx))*
533 sqrt(2.0/Lx)*( 3*hx*i*(M_PI/Lx) - 4*sin(i*(M_PI/Lx)*hx) +
534 cos(i*(M_PI/Lx)*hx)*hx*i*(M_PI/Lx) );
535 else
536 iX = 8.0*sin(i*(M_PI/Lx)*x[ii])/(hx*hx*i*(M_PI/Lx)*i*(M_PI/Lx)*i*(M_PI/Lx))*
537 sqrt(2.0/Lx)*( 2*sin(i*(M_PI/Lx)*0.5*hx) -
538 cos(i*(M_PI/Lx)*0.5*hx)*hx*i*(M_PI/Lx));
539 shapeInt.ReplaceMyValue(ii, 0, iX);
540 }
541 Qi.Dot(shapeInt, normL2+index[i-1]);
542 } // if index[i-1] < nMax)
543 } // for (i=1; i < numX; ++i)
544
545 if (myPid == 0) {
546 for (i = 0; i < nMax; ++i) {
547 double normH1 = continuous[i]*(1.0 - 2.0*normL2[i]) + discrete[i];
548 normL2[i] = 2.0 - 2.0*normL2[i];
549 normH1+= normL2[i];
550 // Print out the result
551 if (myPid == 0) {
552 cout << " ";
553 cout.width(4);
554 cout << i+1 << ". ";
555 cout.setf(ios::scientific, ios::floatfield);
556 cout.precision(8);
557 cout << continuous[i] << " " << discrete[i] << " ";
558 cout.precision(3);
559 cout << fabs(discrete[i] - continuous[i])/continuous[i] << " ";
560 cout << sqrt(fabs(normH1)/(continuous[i]+1.0)) << " ";
561 cout << sqrt(fabs(normL2[i])) << endl;
562 }
563 } // for (i = 0; i < nMax; ++i)
564 } // if (myPid == 0)
565
566 delete[] discrete;
567 delete[] index;
568
569 // Check the angles between exact discrete eigenvectors and computed
570
571 myVerify.errorSubspaces(Q, Qex, M);
572
573 delete[] vQ;
574
575 return info;
576
577}
578
579
580void ModeLaplace1DQ2::memoryInfo() const {
581
582 int myPid = MyComm.MyPID();
583
584 Epetra_RowMatrix *Mat = dynamic_cast<Epetra_RowMatrix *>(M);
585 if ((myPid == 0) && (Mat)) {
586 cout << " Total number of nonzero entries in mass matrix = ";
587 cout.width(15);
588 cout << Mat->NumGlobalNonzeros() << endl;
589 double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
590 memSize += 2*Mat->NumGlobalRows()*sizeof(int);
591 cout << " Memory requested for mass matrix per processor = (EST) ";
592 cout.precision(2);
593 cout.width(6);
594 cout.setf(ios::fixed, ios::floatfield);
595 cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
596 cout << endl;
597 }
598
599 Mat = dynamic_cast<Epetra_RowMatrix *>(K);
600 if ((myPid == 0) && (Mat)) {
601 cout << " Total number of nonzero entries in stiffness matrix = ";
602 cout.width(15);
603 cout << Mat->NumGlobalNonzeros() << endl;
604 double memSize = Mat->NumGlobalNonzeros()*(sizeof(double) + sizeof(int));
605 memSize += 2*Mat->NumGlobalRows()*sizeof(int);
606 cout << " Memory requested for stiffness matrix per processor = (EST) ";
607 cout.precision(2);
608 cout.width(6);
609 cout.setf(ios::fixed, ios::floatfield);
610 cout << memSize/1024.0/1024.0/MyComm.NumProc() << " MB " << endl;
611 cout << endl;
612 }
613
614}
615
616
617void ModeLaplace1DQ2::problemInfo() const {
618
619 int myPid = MyComm.MyPID();
620
621 if (myPid == 0) {
622 cout.precision(2);
623 cout.setf(ios::fixed, ios::floatfield);
624 cout << " --- Problem definition ---\n\n";
625 cout << " >> Laplace equation in 1D with homogeneous Dirichlet condition\n";
626 cout << " >> Domain = [0, " << Lx << "]\n";
627 cout << " >> Orthogonal mesh uniform per direction with Q2 elements (3 nodes)\n";
628 cout << endl;
629 cout << " Global size = " << Map->NumGlobalElements() << endl;
630 cout << endl;
631 cout << " Number of elements in [0, " << Lx << "] (X-direction): " << nX << endl;
632 cout << endl;
633 cout << " Number of interior nodes in the X-direction: " << 2*nX-1 << endl;
634 cout << endl;
635 }
636
637}
638
639