00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "meshRefinement.H"
00027 #include <finiteVolume/fvMesh.H>
00028 #include <OpenFOAM/syncTools.H>
00029 #include <OpenFOAM/Time.H>
00030 #include <autoMesh/refinementSurfaces.H>
00031 #include <meshTools/pointSet.H>
00032 #include <meshTools/faceSet.H>
00033 #include <OpenFOAM/indirectPrimitivePatch.H>
00034 #include <OpenFOAM/OFstream.H>
00035 #include <meshTools/cellSet.H>
00036 #include <meshTools/searchableSurfaces.H>
00037 #include <dynamicMesh/polyMeshGeometry.H>
00038 #include <OpenFOAM/IOmanip.H>
00039
00040
00041
00042 void Foam::meshRefinement::markBoundaryFace
00043 (
00044 const label faceI,
00045 boolList& isBoundaryFace,
00046 boolList& isBoundaryEdge,
00047 boolList& isBoundaryPoint
00048 ) const
00049 {
00050 isBoundaryFace[faceI] = true;
00051
00052 const labelList& fEdges = mesh_.faceEdges(faceI);
00053
00054 forAll(fEdges, fp)
00055 {
00056 isBoundaryEdge[fEdges[fp]] = true;
00057 }
00058
00059 const face& f = mesh_.faces()[faceI];
00060
00061 forAll(f, fp)
00062 {
00063 isBoundaryPoint[f[fp]] = true;
00064 }
00065 }
00066
00067
00068 void Foam::meshRefinement::findNearest
00069 (
00070 const labelList& meshFaces,
00071 List<pointIndexHit>& nearestInfo,
00072 labelList& nearestSurface,
00073 labelList& nearestRegion,
00074 vectorField& nearestNormal
00075 ) const
00076 {
00077 pointField fc(meshFaces.size());
00078 forAll(meshFaces, i)
00079 {
00080 fc[i] = mesh_.faceCentres()[meshFaces[i]];
00081 }
00082
00083 const labelList allSurfaces(identity(surfaces_.surfaces().size()));
00084
00085 surfaces_.findNearest
00086 (
00087 allSurfaces,
00088 fc,
00089 scalarField(fc.size(), sqr(GREAT)),
00090 nearestSurface,
00091 nearestInfo
00092 );
00093
00094
00095 nearestNormal.setSize(nearestInfo.size());
00096 nearestRegion.setSize(nearestInfo.size());
00097
00098 forAll(allSurfaces, surfI)
00099 {
00100 DynamicList<pointIndexHit> localHits;
00101
00102 forAll(nearestSurface, i)
00103 {
00104 if (nearestSurface[i] == surfI)
00105 {
00106 localHits.append(nearestInfo[i]);
00107 }
00108 }
00109
00110 label geomI = surfaces_.surfaces()[surfI];
00111
00112 pointField localNormals;
00113 surfaces_.geometry()[geomI].getNormal(localHits, localNormals);
00114
00115 labelList localRegion;
00116 surfaces_.geometry()[geomI].getRegion(localHits, localRegion);
00117
00118 label localI = 0;
00119 forAll(nearestSurface, i)
00120 {
00121 if (nearestSurface[i] == surfI)
00122 {
00123 nearestNormal[i] = localNormals[localI];
00124 nearestRegion[i] = localRegion[localI];
00125 localI++;
00126 }
00127 }
00128 }
00129 }
00130
00131
00132 Foam::Map<Foam::label> Foam::meshRefinement::findEdgeConnectedProblemCells
00133 (
00134 const scalarField& perpendicularAngle,
00135 const labelList& globalToPatch
00136 ) const
00137 {
00138
00139 autoPtr<indirectPrimitivePatch> ppPtr
00140 (
00141 meshRefinement::makePatch
00142 (
00143 mesh_,
00144 meshedPatches()
00145 )
00146 );
00147 const indirectPrimitivePatch& pp = ppPtr();
00148
00149
00150
00151
00152
00153 DynamicList<label> candidateFaces(pp.size()/20);
00154
00155 const labelListList& edgeFaces = pp.edgeFaces();
00156
00157 const labelList& cellLevel = meshCutter_.cellLevel();
00158
00159 forAll(edgeFaces, edgeI)
00160 {
00161 const labelList& eFaces = edgeFaces[edgeI];
00162
00163 if (eFaces.size() == 2)
00164 {
00165 label face0 = pp.addressing()[eFaces[0]];
00166 label face1 = pp.addressing()[eFaces[1]];
00167
00168 label cell0 = mesh_.faceOwner()[face0];
00169 label cell1 = mesh_.faceOwner()[face1];
00170
00171 if (cellLevel[cell0] > cellLevel[cell1])
00172 {
00173
00174 const vector& n0 = pp.faceNormals()[eFaces[0]];
00175 const vector& n1 = pp.faceNormals()[eFaces[1]];
00176
00177 if (mag(n0 & n1) < 0.1)
00178 {
00179 candidateFaces.append(face0);
00180 }
00181 }
00182 else if (cellLevel[cell1] > cellLevel[cell0])
00183 {
00184
00185 const vector& n0 = pp.faceNormals()[eFaces[0]];
00186 const vector& n1 = pp.faceNormals()[eFaces[1]];
00187
00188 if (mag(n0 & n1) < 0.1)
00189 {
00190 candidateFaces.append(face1);
00191 }
00192 }
00193 }
00194 }
00195 candidateFaces.shrink();
00196
00197 Info<< "Testing " << returnReduce(candidateFaces.size(), sumOp<label>())
00198 << " faces on edge-connected cells of differing level."
00199 << endl;
00200
00201 if (debug)
00202 {
00203 faceSet fSet(mesh_, "edgeConnectedFaces", candidateFaces);
00204 Pout<< "Writing " << fSet.size()
00205 << " with problematic topology to faceSet "
00206 << fSet.objectPath() << endl;
00207 fSet.write();
00208 }
00209
00210
00211
00212
00213
00214 List<pointIndexHit> nearestInfo;
00215 labelList nearestSurface;
00216 labelList nearestRegion;
00217 vectorField nearestNormal;
00218 findNearest
00219 (
00220 candidateFaces,
00221 nearestInfo,
00222 nearestSurface,
00223 nearestRegion,
00224 nearestNormal
00225 );
00226
00227
00228
00229
00230
00231 Map<label> candidateCells(candidateFaces.size());
00232
00233 faceSet perpFaces(mesh_, "perpendicularFaces", pp.size()/100);
00234
00235 forAll(candidateFaces, i)
00236 {
00237 label faceI = candidateFaces[i];
00238
00239 vector n = mesh_.faceAreas()[faceI];
00240 n /= mag(n);
00241
00242 label region = surfaces_.globalRegion
00243 (
00244 nearestSurface[i],
00245 nearestRegion[i]
00246 );
00247
00248 scalar angle =
00249 perpendicularAngle[region]
00250 / 180.0
00251 * mathematicalConstant::pi;
00252
00253 if (angle >= 0)
00254 {
00255 if (mag(n & nearestNormal[i]) < Foam::sin(angle))
00256 {
00257 perpFaces.insert(faceI);
00258 candidateCells.insert
00259 (
00260 mesh_.faceOwner()[faceI],
00261 globalToPatch[region]
00262 );
00263 }
00264 }
00265 }
00266
00267 if (debug)
00268 {
00269 Pout<< "Writing " << perpFaces.size()
00270 << " faces that are perpendicular to the surface to set "
00271 << perpFaces.objectPath() << endl;
00272 perpFaces.write();
00273 }
00274 return candidateCells;
00275 }
00276
00277
00278
00279
00280
00281 bool Foam::meshRefinement::isCollapsedFace
00282 (
00283 const pointField& points,
00284 const pointField& neiCc,
00285 const scalar minFaceArea,
00286 const scalar maxNonOrtho,
00287 const label faceI
00288 ) const
00289 {
00290 vector s = mesh_.faces()[faceI].normal(points);
00291 scalar magS = mag(s);
00292
00293
00294 if (magS < minFaceArea)
00295 {
00296 return true;
00297 }
00298
00299
00300 const point& ownCc = mesh_.cellCentres()[mesh_.faceOwner()[faceI]];
00301
00302 if (mesh_.isInternalFace(faceI))
00303 {
00304 label nei = mesh_.faceNeighbour()[faceI];
00305 vector d = ownCc - mesh_.cellCentres()[nei];
00306
00307 scalar dDotS = (d & s)/(mag(d)*magS + VSMALL);
00308
00309 if (dDotS < maxNonOrtho)
00310 {
00311 return true;
00312 }
00313 else
00314 {
00315 return false;
00316 }
00317 }
00318 else
00319 {
00320 label patchI = mesh_.boundaryMesh().whichPatch(faceI);
00321
00322 if (mesh_.boundaryMesh()[patchI].coupled())
00323 {
00324 vector d = ownCc - neiCc[faceI-mesh_.nInternalFaces()];
00325
00326 scalar dDotS = (d & s)/(mag(d)*magS + VSMALL);
00327
00328 if (dDotS < maxNonOrtho)
00329 {
00330 return true;
00331 }
00332 else
00333 {
00334 return false;
00335 }
00336 }
00337 else
00338 {
00339
00340
00341 return true;
00342 }
00343 }
00344 }
00345
00346
00347
00348 bool Foam::meshRefinement::isCollapsedCell
00349 (
00350 const pointField& points,
00351 const scalar volFraction,
00352 const label cellI
00353 ) const
00354 {
00355 scalar vol = mesh_.cells()[cellI].mag(points, mesh_.faces());
00356
00357 if (vol/mesh_.cellVolumes()[cellI] < volFraction)
00358 {
00359 return true;
00360 }
00361 else
00362 {
00363 return false;
00364 }
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374 Foam::labelList Foam::meshRefinement::markFacesOnProblemCells
00375 (
00376 const dictionary& motionDict,
00377 const bool removeEdgeConnectedCells,
00378 const scalarField& perpendicularAngle,
00379 const labelList& globalToPatch
00380 ) const
00381 {
00382 const labelList& cellLevel = meshCutter_.cellLevel();
00383 const labelList& pointLevel = meshCutter_.pointLevel();
00384 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
00385
00386
00387
00388 labelList facePatch(mesh_.nFaces(), -1);
00389
00390
00391
00392 boolList isBoundaryPoint(mesh_.nPoints(), false);
00393 boolList isBoundaryEdge(mesh_.nEdges(), false);
00394 boolList isBoundaryFace(mesh_.nFaces(), false);
00395
00396
00397
00398 labelList adaptPatchIDs(meshedPatches());
00399
00400 forAll(adaptPatchIDs, i)
00401 {
00402 label patchI = adaptPatchIDs[i];
00403
00404 const polyPatch& pp = patches[patchI];
00405
00406 label faceI = pp.start();
00407
00408 forAll(pp, j)
00409 {
00410 markBoundaryFace
00411 (
00412 faceI,
00413 isBoundaryFace,
00414 isBoundaryEdge,
00415 isBoundaryPoint
00416 );
00417
00418 faceI++;
00419 }
00420 }
00421
00422
00423 labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
00424 pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
00425 calcNeighbourData(neiLevel, neiCc);
00426
00427
00428
00429 label nBaffleFaces = 0;
00430
00431
00432 label nPrevented = 0;
00433
00434 if (removeEdgeConnectedCells && max(perpendicularAngle) >= 0)
00435 {
00436 Info<< "markFacesOnProblemCells :"
00437 << " Checking for edge-connected cells of highly differing sizes."
00438 << endl;
00439
00440
00441
00442 Map<label> problemCells
00443 (
00444 findEdgeConnectedProblemCells
00445 (
00446 perpendicularAngle,
00447 globalToPatch
00448 )
00449 );
00450
00451
00452 forAllConstIter(Map<label>, problemCells, iter)
00453 {
00454 const cell& cFaces = mesh_.cells()[iter.key()];
00455
00456 forAll(cFaces, i)
00457 {
00458 label faceI = cFaces[i];
00459
00460 if (facePatch[faceI] == -1 && mesh_.isInternalFace(faceI))
00461 {
00462 facePatch[faceI] = getBafflePatch(facePatch, faceI);
00463 nBaffleFaces++;
00464
00465
00466 markBoundaryFace
00467 (
00468 faceI,
00469 isBoundaryFace,
00470 isBoundaryEdge,
00471 isBoundaryPoint
00472 );
00473 }
00474 }
00475 }
00476 Info<< "markFacesOnProblemCells : Marked "
00477 << returnReduce(nBaffleFaces, sumOp<label>())
00478 << " additional internal faces to be converted into baffles"
00479 << " due to "
00480 << returnReduce(problemCells.size(), sumOp<label>())
00481 << " cells edge-connected to lower level cells." << endl;
00482
00483 if (debug)
00484 {
00485 cellSet problemCellSet(mesh_, "problemCells", problemCells.toc());
00486 Pout<< "Writing " << problemCellSet.size()
00487 << " cells that are edge connected to coarser cell to set "
00488 << problemCellSet.objectPath() << endl;
00489 problemCellSet.write();
00490 }
00491 }
00492
00493 syncTools::syncPointList
00494 (
00495 mesh_,
00496 isBoundaryPoint,
00497 orEqOp<bool>(),
00498 false,
00499 false
00500 );
00501
00502 syncTools::syncEdgeList
00503 (
00504 mesh_,
00505 isBoundaryEdge,
00506 orEqOp<bool>(),
00507 false,
00508 false
00509 );
00510
00511 syncTools::syncFaceList
00512 (
00513 mesh_,
00514 isBoundaryFace,
00515 orEqOp<bool>(),
00516 false
00517 );
00518
00519
00520
00521
00522
00523
00524 scalar volFraction = -1;
00525 if (motionDict.found("minVolCollapseRatio"))
00526 {
00527 volFraction = readScalar(motionDict.lookup("minVolCollapseRatio"));
00528 }
00529 const bool checkCollapse = (volFraction > 0);
00530 scalar minArea = -1;
00531 scalar maxNonOrtho = -1;
00532
00533
00534
00535 pointField newPoints;
00536
00537 if (checkCollapse)
00538 {
00539 minArea = readScalar(motionDict.lookup("minArea"));
00540 maxNonOrtho = readScalar(motionDict.lookup("maxNonOrtho"));
00541
00542 Info<< "markFacesOnProblemCells :"
00543 << " Deleting all-anchor surface cells only if"
00544 << "snapping them violates mesh quality constraints:" << nl
00545 << " snapped/original cell volume < " << volFraction << nl
00546 << " face area < " << minArea << nl
00547 << " non-orthogonality > " << maxNonOrtho << nl
00548 << endl;
00549
00550
00551 autoPtr<indirectPrimitivePatch> ppPtr
00552 (
00553 meshRefinement::makePatch
00554 (
00555 mesh_,
00556 adaptPatchIDs
00557 )
00558 );
00559 const indirectPrimitivePatch& pp = ppPtr();
00560 const pointField& localPoints = pp.localPoints();
00561 const labelList& meshPoints = pp.meshPoints();
00562
00563 List<pointIndexHit> hitInfo;
00564 labelList hitSurface;
00565 surfaces_.findNearest
00566 (
00567 surfaces_.getUnnamedSurfaces(),
00568 localPoints,
00569 scalarField(localPoints.size(), sqr(GREAT)),
00570 hitSurface,
00571 hitInfo
00572 );
00573
00574
00575 newPoints = mesh_.points();
00576
00577 forAll(hitInfo, i)
00578 {
00579 if (hitInfo[i].hit())
00580 {
00581 newPoints[meshPoints[i]] = hitInfo[i].hitPoint();
00582 }
00583 }
00584 }
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600 PackedBoolList hasSevenBoundaryAnchorPoints(mesh_.nCells());
00601
00602 labelHashSet nonBoundaryAnchors(mesh_.nCells()/10000);
00603
00604
00605 DynamicList<label> dynFEdges;
00606 DynamicList<label> dynCPoints;
00607
00608 forAll(cellLevel, cellI)
00609 {
00610 const labelList& cPoints = mesh_.cellPoints(cellI, dynCPoints);
00611
00612
00613
00614 label nBoundaryAnchors = 0;
00615 label nNonAnchorBoundary = 0;
00616 label nonBoundaryAnchor = -1;
00617
00618 forAll(cPoints, i)
00619 {
00620 label pointI = cPoints[i];
00621
00622 if (pointLevel[pointI] <= cellLevel[cellI])
00623 {
00624
00625 if (isBoundaryPoint[pointI])
00626 {
00627 nBoundaryAnchors++;
00628 }
00629 else
00630 {
00631
00632 nonBoundaryAnchor = pointI;
00633 }
00634 }
00635 else if (isBoundaryPoint[pointI])
00636 {
00637 nNonAnchorBoundary++;
00638 }
00639 }
00640
00641 if (nBoundaryAnchors == 8)
00642 {
00643 const cell& cFaces = mesh_.cells()[cellI];
00644
00645
00646 label nBfaces = 0;
00647
00648 forAll(cFaces, cFaceI)
00649 {
00650 if (isBoundaryFace[cFaces[cFaceI]])
00651 {
00652 nBfaces++;
00653 }
00654 }
00655
00656
00657
00658
00659
00660
00661
00662 {
00663 if
00664 (
00665 checkCollapse
00666 && !isCollapsedCell(newPoints, volFraction, cellI)
00667 )
00668 {
00669 nPrevented++;
00670
00671
00672
00673
00674
00675
00676 }
00677 else
00678 {
00679
00680 forAll(cFaces, cf)
00681 {
00682 label faceI = cFaces[cf];
00683
00684 if
00685 (
00686 facePatch[faceI] == -1
00687 && mesh_.isInternalFace(faceI)
00688 )
00689 {
00690 facePatch[faceI] = getBafflePatch(facePatch, faceI);
00691 nBaffleFaces++;
00692
00693
00694 markBoundaryFace
00695 (
00696 faceI,
00697 isBoundaryFace,
00698 isBoundaryEdge,
00699 isBoundaryPoint
00700 );
00701 }
00702 }
00703 }
00704 }
00705 }
00706 else if (nBoundaryAnchors == 7)
00707 {
00708
00709 hasSevenBoundaryAnchorPoints.set(cellI, 1u);
00710 nonBoundaryAnchors.insert(nonBoundaryAnchor);
00711 }
00712 }
00713
00714
00715
00716
00717
00718
00719 DynamicList<label> dynPCells;
00720
00721 forAllConstIter(labelHashSet, nonBoundaryAnchors, iter)
00722 {
00723 label pointI = iter.key();
00724
00725 const labelList& pCells = mesh_.pointCells(pointI, dynPCells);
00726
00727
00728 label n = 0;
00729
00730 forAll(pCells, i)
00731 {
00732 if (hasSevenBoundaryAnchorPoints.get(pCells[i]) == 1u)
00733 {
00734 n++;
00735 }
00736 }
00737
00738 if (n > 3)
00739 {
00740
00741 forAll(pCells, i)
00742 {
00743 label cellI = pCells[i];
00744
00745 if (hasSevenBoundaryAnchorPoints.get(cellI) == 1u)
00746 {
00747 if
00748 (
00749 checkCollapse
00750 && !isCollapsedCell(newPoints, volFraction, cellI)
00751 )
00752 {
00753 nPrevented++;
00754
00755
00756
00757
00758
00759
00760
00761
00762 }
00763 else
00764 {
00765 const cell& cFaces = mesh_.cells()[cellI];
00766
00767 forAll(cFaces, cf)
00768 {
00769 label faceI = cFaces[cf];
00770
00771 if
00772 (
00773 facePatch[faceI] == -1
00774 && mesh_.isInternalFace(faceI)
00775 )
00776 {
00777 facePatch[faceI] = getBafflePatch
00778 (
00779 facePatch,
00780 faceI
00781 );
00782 nBaffleFaces++;
00783
00784
00785 markBoundaryFace
00786 (
00787 faceI,
00788 isBoundaryFace,
00789 isBoundaryEdge,
00790 isBoundaryPoint
00791 );
00792 }
00793 }
00794 }
00795 }
00796 }
00797 }
00798 }
00799
00800
00801
00802
00803
00804 syncTools::syncPointList
00805 (
00806 mesh_,
00807 isBoundaryPoint,
00808 orEqOp<bool>(),
00809 false,
00810 false
00811 );
00812
00813 syncTools::syncEdgeList
00814 (
00815 mesh_,
00816 isBoundaryEdge,
00817 orEqOp<bool>(),
00818 false,
00819 false
00820 );
00821
00822 syncTools::syncFaceList
00823 (
00824 mesh_,
00825 isBoundaryFace,
00826 orEqOp<bool>(),
00827 false
00828 );
00829
00830
00831
00832 for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
00833 {
00834 if (facePatch[faceI] == -1)
00835 {
00836 const labelList& fEdges = mesh_.faceEdges(faceI, dynFEdges);
00837 label nFaceBoundaryEdges = 0;
00838
00839 forAll(fEdges, fe)
00840 {
00841 if (isBoundaryEdge[fEdges[fe]])
00842 {
00843 nFaceBoundaryEdges++;
00844 }
00845 }
00846
00847 if (nFaceBoundaryEdges == fEdges.size())
00848 {
00849 if
00850 (
00851 checkCollapse
00852 && !isCollapsedFace
00853 (
00854 newPoints,
00855 neiCc,
00856 minArea,
00857 maxNonOrtho,
00858 faceI
00859 )
00860 )
00861 {
00862 nPrevented++;
00863
00864
00865
00866
00867 }
00868 else
00869 {
00870 facePatch[faceI] = getBafflePatch(facePatch, faceI);
00871 nBaffleFaces++;
00872
00873
00874
00875 }
00876 }
00877 }
00878 }
00879
00880 forAll(patches, patchI)
00881 {
00882 const polyPatch& pp = patches[patchI];
00883
00884 if (pp.coupled())
00885 {
00886 label faceI = pp.start();
00887
00888 forAll(pp, i)
00889 {
00890 if (facePatch[faceI] == -1)
00891 {
00892 const labelList& fEdges = mesh_.faceEdges(faceI, dynFEdges);
00893 label nFaceBoundaryEdges = 0;
00894
00895 forAll(fEdges, fe)
00896 {
00897 if (isBoundaryEdge[fEdges[fe]])
00898 {
00899 nFaceBoundaryEdges++;
00900 }
00901 }
00902
00903 if (nFaceBoundaryEdges == fEdges.size())
00904 {
00905 if
00906 (
00907 checkCollapse
00908 && !isCollapsedFace
00909 (
00910 newPoints,
00911 neiCc,
00912 minArea,
00913 maxNonOrtho,
00914 faceI
00915 )
00916 )
00917 {
00918 nPrevented++;
00919
00920
00921
00922
00923
00924 }
00925 else
00926 {
00927 facePatch[faceI] = getBafflePatch(facePatch, faceI);
00928 nBaffleFaces++;
00929
00930
00931
00932 }
00933 }
00934 }
00935
00936 faceI++;
00937 }
00938 }
00939 }
00940
00941 Info<< "markFacesOnProblemCells : marked "
00942 << returnReduce(nBaffleFaces, sumOp<label>())
00943 << " additional internal faces to be converted into baffles."
00944 << endl;
00945
00946 if (checkCollapse)
00947 {
00948 Info<< "markFacesOnProblemCells : prevented "
00949 << returnReduce(nPrevented, sumOp<label>())
00950 << " internal faces fom getting converted into baffles."
00951 << endl;
00952 }
00953
00954 return facePatch;
00955 }
00956
00957
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119