/[escript]/trunk/finley/src/Mesh_hex8.cpp
ViewVC logotype

Contents of /trunk/finley/src/Mesh_hex8.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4496 - (show annotations)
Mon Jul 15 06:53:44 2013 UTC (6 years ago) by caltinay
File size: 20638 byte(s)
finley (WIP):
-moved all of finley into its namespace
-introduced some shared pointers
-Mesh is now a class
-other bits and pieces...

1
2 /*****************************************************************************
3 *
4 * Copyright (c) 2003-2013 by University of Queensland
5 * http://www.uq.edu.au
6 *
7 * Primary Business: Queensland, Australia
8 * Licensed under the Open Software License version 3.0
9 * http://www.opensource.org/licenses/osl-3.0.php
10 *
11 * Development until 2012 by Earth Systems Science Computational Center (ESSCC)
12 * Development since 2012 by School of Earth Sciences
13 *
14 *****************************************************************************/
15
16
17 /****************************************************************************
18
19 Finley: generates rectangular meshes
20
21 Generates a numElements[0] x numElements[1] x numElements[2] mesh with
22 first order elements (Hex8) in the brick
23 [0,Length[0]] x [0,Length[1]] x [0,Length[2]].
24 order is the desired accuracy of the integration scheme.
25
26 *****************************************************************************/
27
28 #include "RectangularMesh.h"
29
30 namespace finley {
31
32 Mesh* RectangularMesh_Hex8(const int* numElements, const double* Length,
33 const bool* periodic, int order, int reduced_order,
34 bool useElementsOnFace, bool useFullElementOrder,
35 bool optimize)
36 {
37 const int N_PER_E = 1;
38 const int DIM = 3;
39 int i0,i1,i2,k,Nstride0=0, Nstride1=0,Nstride2=0, local_NE0, local_NE1, local_NE2, local_N0=0, local_N1=0, local_N2=0;
40 int totalNECount,faceNECount,NDOF0=0,NDOF1=0,NDOF2=0,NFaceElements=0, NN;
41 int node0, e_offset2, e_offset1, e_offset0=0, offset1=0, offset2=0, offset0=0, global_i0, global_i1, global_i2;
42 const_ReferenceElementSet_ptr refPoints, refContactElements, refFaceElements, refElements;
43 #ifdef Finley_TRACE
44 double time0=timer();
45 #endif
46
47 // get MPI information
48 Esys_MPIInfo *mpiInfo = Esys_MPIInfo_alloc(MPI_COMM_WORLD);
49 if (!noError()) {
50 return NULL;
51 }
52 const int myRank=mpiInfo->rank;
53
54 // set up the global dimensions of the mesh
55 int NE0=std::max(1,numElements[0]);
56 int NE1=std::max(1,numElements[1]);
57 int NE2=std::max(1,numElements[2]);
58 int N0=N_PER_E*NE0+1;
59 int N1=N_PER_E*NE1+1;
60 int N2=N_PER_E*NE2+1;
61
62 // allocate mesh
63 std::stringstream name;
64 name << "Rectangular " << N0 << " x " << N1 << " x " << N2 << " mesh";
65 Mesh* out = new Mesh(name.str(), DIM, mpiInfo);
66 refElements.reset(new ReferenceElementSet(Hex8, order, reduced_order));
67 if (useElementsOnFace) {
68 refFaceElements.reset(new ReferenceElementSet(Hex8Face, order, reduced_order));
69 refContactElements.reset(new ReferenceElementSet(Hex8Face_Contact, order, reduced_order));
70 } else {
71 refFaceElements.reset(new ReferenceElementSet(Rec4, order, reduced_order));
72 refContactElements.reset(new ReferenceElementSet(Rec4_Contact, order, reduced_order));
73 }
74 refPoints.reset(new ReferenceElementSet(Point1, order, reduced_order));
75
76 if (noError()) {
77 out->setPoints(new ElementFile(refPoints, mpiInfo));
78 out->setContactElements(new ElementFile(refContactElements, mpiInfo));
79 out->setFaceElements(new ElementFile(refFaceElements, mpiInfo));
80 out->setElements(new ElementFile(refElements, mpiInfo));
81
82 // work out the largest dimension
83 if (N2==MAX3(N0,N1,N2)) {
84 Nstride0=1;
85 Nstride1=N0;
86 Nstride2=N0*N1;
87 local_NE0=NE0;
88 e_offset0=0;
89 local_NE1=NE1;
90 e_offset1=0;
91 Esys_MPIInfo_Split(mpiInfo,NE2,&local_NE2,&e_offset2);
92 } else if (N1==MAX3(N0,N1,N2)) {
93 Nstride0=N2;
94 Nstride1=N0*N2;
95 Nstride2=1;
96 local_NE0=NE0;
97 e_offset0=0;
98 Esys_MPIInfo_Split(mpiInfo,NE1,&local_NE1,&e_offset1);
99 local_NE2=NE2;
100 e_offset2=0;
101 } else {
102 Nstride0=N1*N2;
103 Nstride1=1;
104 Nstride2=N1;
105 Esys_MPIInfo_Split(mpiInfo,NE0,&local_NE0,&e_offset0);
106 local_NE1=NE1;
107 e_offset1=0;
108 local_NE2=NE2;
109 e_offset2=0;
110 }
111 offset0=e_offset0*N_PER_E;
112 offset1=e_offset1*N_PER_E;
113 offset2=e_offset2*N_PER_E;
114 local_N0=local_NE0>0 ? local_NE0*N_PER_E+1 : 0;
115 local_N1=local_NE1>0 ? local_NE1*N_PER_E+1 : 0;
116 local_N2=local_NE2>0 ? local_NE2*N_PER_E+1 : 0;
117
118 // get the number of surface elements
119 NFaceElements=0;
120 if (!periodic[2] && (local_NE2>0)) {
121 NDOF2=N2;
122 if (offset2==0)
123 NFaceElements+=local_NE1*local_NE0;
124 if (local_NE2+e_offset2 == NE2)
125 NFaceElements+=local_NE1*local_NE0;
126 } else {
127 NDOF2=N2-1;
128 }
129
130 if (!periodic[0] && (local_NE0>0)) {
131 NDOF0=N0;
132 if (e_offset0 == 0)
133 NFaceElements+=local_NE1*local_NE2;
134 if (local_NE0+e_offset0 == NE0)
135 NFaceElements+=local_NE1*local_NE2;
136 } else {
137 NDOF0=N0-1;
138 }
139 if (!periodic[1] && (local_NE1>0)) {
140 NDOF1=N1;
141 if (e_offset1 == 0)
142 NFaceElements+=local_NE0*local_NE2;
143 if (local_NE1+e_offset1 == NE1)
144 NFaceElements+=local_NE0*local_NE2;
145 } else {
146 NDOF1=N1-1;
147 }
148 }
149
150 // allocate tables
151 if (noError()) {
152 out->Nodes->allocTable(local_N0*local_N1*local_N2);
153 out->Elements->allocTable(local_NE0*local_NE1*local_NE2);
154 out->FaceElements->allocTable(NFaceElements);
155 }
156
157 if (noError()) {
158 // create nodes
159 #pragma omp parallel for private(i0,i1,i2,k,global_i0,global_i1,global_i2)
160 for (i2=0;i2<local_N2;i2++) {
161 for (i1=0;i1<local_N1;i1++) {
162 for (i0=0;i0<local_N0;i0++) {
163 k=i0+local_N0*i1+local_N0*local_N1*i2;
164 global_i0=i0+offset0;
165 global_i1=i1+offset1;
166 global_i2=i2+offset2;
167 out->Nodes->Coordinates[INDEX2(0,k,DIM)]=DBLE(global_i0)/DBLE(N0-1)*Length[0];
168 out->Nodes->Coordinates[INDEX2(1,k,DIM)]=DBLE(global_i1)/DBLE(N1-1)*Length[1];
169 out->Nodes->Coordinates[INDEX2(2,k,DIM)]=DBLE(global_i2)/DBLE(N2-1)*Length[2];
170 out->Nodes->Id[k]=Nstride0*global_i0+Nstride1*global_i1+Nstride2*global_i2;
171 out->Nodes->Tag[k]=0;
172 out->Nodes->globalDegreesOfFreedom[k]=Nstride0*(global_i0%NDOF0)
173 +Nstride1*(global_i1%NDOF1)
174 +Nstride2*(global_i2%NDOF2);
175 }
176 }
177 }
178
179 // set the elements
180 NN=out->Elements->numNodes;
181 #pragma omp parallel for private(i0,i1,i2,k,node0)
182 for (i2=0;i2<local_NE2;i2++) {
183 for (i1=0;i1<local_NE1;i1++) {
184 for (i0=0;i0<local_NE0;i0++) {
185 k=i0+local_NE0*i1+local_NE0*local_NE1*i2;
186 node0=Nstride0*N_PER_E*(i0+e_offset0)+Nstride1*N_PER_E*(i1+e_offset1)+Nstride2*N_PER_E*(i2+e_offset2);
187
188 out->Elements->Id[k]=(i0+e_offset0)+NE0*(i1+e_offset1)+NE0*NE1*(i2+e_offset2);
189 out->Elements->Tag[k]=0;
190 out->Elements->Owner[k]=myRank;
191
192 out->Elements->Nodes[INDEX2(0,k,NN)]=node0;
193 out->Elements->Nodes[INDEX2(1,k,NN)]=node0+Nstride0;
194 out->Elements->Nodes[INDEX2(2,k,NN)]=node0+Nstride1+Nstride0;
195 out->Elements->Nodes[INDEX2(3,k,NN)]=node0+Nstride1;
196 out->Elements->Nodes[INDEX2(4,k,NN)]=node0+Nstride2;
197 out->Elements->Nodes[INDEX2(5,k,NN)]=node0+Nstride2+Nstride0;
198 out->Elements->Nodes[INDEX2(6,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
199 out->Elements->Nodes[INDEX2(7,k,NN)]=node0+Nstride2+Nstride1;
200 }
201 }
202 }
203
204 // face elements
205 NN=out->FaceElements->numNodes;
206 totalNECount=NE0*NE1*NE2;
207 faceNECount=0;
208 // these are the quadrilateral elements on boundary 1 (x3=0):
209 if (!periodic[2] && (local_NE2>0)) {
210 // ** elements on boundary 100 (x3=0):
211 if (e_offset2==0) {
212 #pragma omp parallel for private(i0,i1,k,node0)
213 for (i1=0;i1<local_NE1;i1++) {
214 for (i0=0;i0<local_NE0;i0++) {
215 k=i0+local_NE0*i1+faceNECount;
216 node0=Nstride0*N_PER_E*(i0+e_offset0)+Nstride1*N_PER_E*(i1+e_offset1);
217
218 out->FaceElements->Id[k]=(i0+e_offset0)+NE0*(i1+e_offset1)+totalNECount;
219 out->FaceElements->Tag[k]=100;
220 out->FaceElements->Owner[k]=myRank;
221
222 if (useElementsOnFace) {
223 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0;
224 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride1;
225 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride1+Nstride0;
226 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride0;
227 out->FaceElements->Nodes[INDEX2(4,k,NN)]=node0+Nstride2;
228 out->FaceElements->Nodes[INDEX2(5,k,NN)]=node0+Nstride2+Nstride1;
229 out->FaceElements->Nodes[INDEX2(6,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
230 out->FaceElements->Nodes[INDEX2(7,k,NN)]=node0+Nstride2+Nstride0;
231 } else {
232 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0;
233 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride1;
234 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride1+Nstride0;
235 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride0;
236 }
237 }
238 }
239 faceNECount+=local_NE1*local_NE0;
240 }
241 totalNECount+=NE1*NE0;
242
243 // ** elements on boundary 200 (x3=1):
244 if (local_NE2+e_offset2 == NE2) {
245 #pragma omp parallel for private(i0,i1,k,node0)
246 for (i1=0;i1<local_NE1;i1++) {
247 for (i0=0;i0<local_NE0;i0++) {
248 k=i0+local_NE0*i1+faceNECount;
249 node0=Nstride0*N_PER_E*(i0+e_offset0)+Nstride1*N_PER_E*(i1+e_offset1)+Nstride2*N_PER_E*(NE2-1);
250
251 out->FaceElements->Id[k]=(i0+e_offset0)+NE0*(i1+e_offset1)+totalNECount;
252 out->FaceElements->Tag[k]=200;
253 out->FaceElements->Owner[k]=myRank;
254 if (useElementsOnFace) {
255 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0+Nstride2;
256 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride2+ Nstride0;
257 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
258 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride2+Nstride1;
259
260 out->FaceElements->Nodes[INDEX2(4,k,NN)]=node0;
261 out->FaceElements->Nodes[INDEX2(5,k,NN)]=node0+Nstride0;
262 out->FaceElements->Nodes[INDEX2(6,k,NN)]=node0+ Nstride1+Nstride0;
263 out->FaceElements->Nodes[INDEX2(7,k,NN)]=node0+ Nstride1;
264 } else {
265 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0+Nstride2;
266 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride2 +Nstride0;
267 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
268 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride2+Nstride1;
269 }
270 }
271 }
272 faceNECount+=local_NE1*local_NE0;
273 }
274 totalNECount+=NE1*NE0;
275 }
276 if (!periodic[0] && (local_NE0>0)) {
277 // ** elements on boundary 001 (x1=0):
278 if (e_offset0 == 0) {
279 #pragma omp parallel for private(i1,i2,k,node0)
280 for (i2=0;i2<local_NE2;i2++) {
281 for (i1=0;i1<local_NE1;i1++) {
282 k=i1+local_NE1*i2+faceNECount;
283 node0=Nstride1*N_PER_E*(i1+e_offset1)+Nstride2*N_PER_E*(i2+e_offset2);
284 out->FaceElements->Id[k]=(i1+e_offset1)+NE1*(i2+e_offset2)+totalNECount;
285 out->FaceElements->Tag[k]=1;
286 out->FaceElements->Owner[k]=myRank;
287
288 if (useElementsOnFace) {
289 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0;
290 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride2;
291 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1;
292 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride1;
293 out->FaceElements->Nodes[INDEX2(4,k,NN)]=node0+Nstride0;
294 out->FaceElements->Nodes[INDEX2(5,k,NN)]=node0+Nstride2+Nstride0;
295 out->FaceElements->Nodes[INDEX2(6,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
296 out->FaceElements->Nodes[INDEX2(7,k,NN)]=node0+Nstride1+Nstride0;
297 } else {
298 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0;
299 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride2;
300 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1;
301 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride1;
302 }
303 }
304 }
305 faceNECount+=local_NE1*local_NE2;
306 }
307 totalNECount+=NE1*NE2;
308 // ** elements on boundary 002 (x1=1):
309 if (local_NE0+e_offset0 == NE0) {
310 #pragma omp parallel for private(i1,i2,k,node0)
311 for (i2=0;i2<local_NE2;i2++) {
312 for (i1=0;i1<local_NE1;i1++) {
313 k=i1+local_NE1*i2+faceNECount;
314 node0=Nstride0*N_PER_E*(NE0-1)+Nstride1*N_PER_E*(i1+e_offset1)+Nstride2*N_PER_E*(i2+e_offset2);
315 out->FaceElements->Id[k]=(i1+e_offset1)+NE1*(i2+e_offset2)+totalNECount;
316 out->FaceElements->Tag[k]=2;
317 out->FaceElements->Owner[k]=myRank;
318
319 if (useElementsOnFace) {
320 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0+Nstride0;
321 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride1+Nstride0;
322 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
323 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride2+Nstride0;
324
325 out->FaceElements->Nodes[INDEX2(4,k,NN)]=node0;
326 out->FaceElements->Nodes[INDEX2(5,k,NN)]=node0+Nstride1;
327 out->FaceElements->Nodes[INDEX2(6,k,NN)]=node0+Nstride2+Nstride1;
328 out->FaceElements->Nodes[INDEX2(7,k,NN)]=node0+Nstride2;
329 } else {
330 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0+Nstride0;
331 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride1+Nstride0;
332 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
333 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride2+Nstride0;
334 }
335 }
336 }
337 faceNECount+=local_NE1*local_NE2;
338 }
339 totalNECount+=NE1*NE2;
340 }
341 if (!periodic[1] && (local_NE1>0)) {
342 // ** elements on boundary 010 (x2=0):
343 if (e_offset1 == 0) {
344 #pragma omp parallel for private(i0,i2,k,node0)
345 for (i2=0;i2<local_NE2;i2++) {
346 for (i0=0;i0<local_NE0;i0++) {
347 k=i0+local_NE0*i2+faceNECount;
348 node0=Nstride0*N_PER_E*(i0+e_offset0)+Nstride2*N_PER_E*(i2+e_offset2);
349
350 out->FaceElements->Id[k]=(i2+e_offset2)+NE2*(e_offset0+i0)+totalNECount;
351 out->FaceElements->Tag[k]=10;
352 out->FaceElements->Owner[k]=myRank;
353 if (useElementsOnFace) {
354 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0;
355 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride0;
356 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride0;
357 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride2;
358
359 out->FaceElements->Nodes[INDEX2(4,k,NN)]=node0+Nstride1;
360 out->FaceElements->Nodes[INDEX2(5,k,NN)]=node0+Nstride1+Nstride0;
361 out->FaceElements->Nodes[INDEX2(6,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
362 out->FaceElements->Nodes[INDEX2(7,k,NN)]=node0+Nstride2+Nstride1;
363 } else {
364 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0;
365 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride0;
366 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride0;
367 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride2;
368 }
369 }
370 }
371 faceNECount+=local_NE0*local_NE2;
372 }
373 totalNECount+=NE0*NE2;
374 // ** elements on boundary 020 (x2=1):
375 if (local_NE1+e_offset1 == NE1) {
376 #pragma omp parallel for private(i0,i2,k,node0)
377 for (i2=0;i2<local_NE2;i2++) {
378 for (i0=0;i0<local_NE0;i0++) {
379 k=i0+local_NE0*i2+faceNECount;
380 node0=Nstride0*N_PER_E*(i0+e_offset0)+Nstride1*N_PER_E*(NE1-1)+Nstride2*N_PER_E*(i2+e_offset2);
381
382 out->FaceElements->Id[k]=(i2+e_offset2)+NE2*(i0+e_offset0)+totalNECount;
383 out->FaceElements->Tag[k]=20;
384 out->FaceElements->Owner[k]=myRank;
385
386 if (useElementsOnFace) {
387 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0+Nstride1;
388 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride2+Nstride1;
389 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
390 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride1+Nstride0;
391
392 out->FaceElements->Nodes[INDEX2(4,k,NN)]=node0;
393 out->FaceElements->Nodes[INDEX2(5,k,NN)]=node0+Nstride2;
394 out->FaceElements->Nodes[INDEX2(6,k,NN)]=node0+Nstride2+Nstride0;
395 out->FaceElements->Nodes[INDEX2(7,k,NN)]=node0+Nstride0;
396 } else {
397 out->FaceElements->Nodes[INDEX2(0,k,NN)]=node0+Nstride1;
398 out->FaceElements->Nodes[INDEX2(1,k,NN)]=node0+Nstride2+Nstride1;
399 out->FaceElements->Nodes[INDEX2(2,k,NN)]=node0+Nstride2+Nstride1+Nstride0;
400 out->FaceElements->Nodes[INDEX2(3,k,NN)]=node0+Nstride1+Nstride0;
401 }
402 }
403 }
404 faceNECount+=local_NE0*local_NE2;
405 }
406 totalNECount+=NE0*NE2;
407 }
408 }
409 if (noError()) {
410 // add tag names
411 out->addTagMap("top", 200);
412 out->addTagMap("bottom", 100);
413 out->addTagMap("left", 1);
414 out->addTagMap("right", 2);
415 out->addTagMap("front", 10);
416 out->addTagMap("back", 20);
417 }
418
419 // prepare mesh for further calculations
420 if (noError()) {
421 out->resolveNodeIds();
422 }
423 if (noError()) {
424 out->prepare(optimize);
425 }
426
427 if (!noError()) {
428 delete out;
429 out=NULL;
430 }
431 Esys_MPIInfo_free(mpiInfo);
432 return out;
433 }
434
435 } // namespace finley
436

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision
svn:mergeinfo /branches/lapack2681/finley/src/Mesh_hex8.cpp:2682-2741 /branches/pasowrap/finley/src/Mesh_hex8.cpp:3661-3674 /branches/py3_attempt2/finley/src/Mesh_hex8.cpp:3871-3891 /branches/restext/finley/src/Mesh_hex8.cpp:2610-2624 /branches/ripleygmg_from_3668/finley/src/Mesh_hex8.cpp:3669-3791 /branches/stage3.0/finley/src/Mesh_hex8.cpp:2569-2590 /branches/symbolic_from_3470/finley/src/Mesh_hex8.cpp:3471-3974 /release/3.0/finley/src/Mesh_hex8.cpp:2591-2601 /trunk/finley/src/Mesh_hex8.cpp:4257-4344

  ViewVC Help
Powered by ViewVC 1.1.26