Anasazi Version of the Day
Loading...
Searching...
No Matches
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
23const int ModeLaplace1DQ1::dofEle = 2;
24const int ModeLaplace1DQ1::maxConnect = 3;
25#ifndef M_PI
26const double ModeLaplace1DQ1::M_PI = 3.14159265358979323846;
27#endif
28
29
30ModeLaplace1DQ1::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
47ModeLaplace1DQ1::~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
68void 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
118void 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
129int 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
158void 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
177void 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
223void 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
287void 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
350double ModeLaplace1DQ1::getFirstMassEigenValue() const {
351
352 return Lx/(3.0*nX)*(2.0-cos(M_PI/nX));
353
354}
355
356
357int 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
489void 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
526void 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