diff --git a/applications/test/syncTools/missing_cell/Allclean b/applications/test/syncTools/missing_cell/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..b44c686537f5c140c2a58cecbb816c6ee6e05332 --- /dev/null +++ b/applications/test/syncTools/missing_cell/Allclean @@ -0,0 +1,11 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +cleanCase + +# Remove surface and features +rm -rf constant/triSurface + +#------------------------------------------------------------------------------ diff --git a/applications/test/syncTools/missing_cell/Allrun b/applications/test/syncTools/missing_cell/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..740433838365032766c54cacfa2601daf54b91df --- /dev/null +++ b/applications/test/syncTools/missing_cell/Allrun @@ -0,0 +1,27 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + +#- Generate 2x2x1 cells +runApplication blockMesh + +#- Remove cell0 +runApplication topoSet +runApplication subsetMesh c0 -patch exposed0 -overwrite + +#- Put exposed faces (2) into separate patches +runApplication -s face topoSet +runApplication createPatch -overwrite + +#- Decompose - creates one processor without any faces in patches +runApplication decomposePar + +#- Extract inter-patch points. Should include processor that does not +#- have faces on patch ... +mkdir -p constant/triSurface +runParallel surfaceMeshExtract \ + -patches '(exposed0 exposed1)' -featureAngle 180 \ + constant/triSurface/blockMesh.obj + +#------------------------------------------------------------------------------ diff --git a/applications/test/syncTools/missing_cell/README.txt b/applications/test/syncTools/missing_cell/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..776e9a7483b2a6a19dd0adbb598cd16dc55a3579 --- /dev/null +++ b/applications/test/syncTools/missing_cell/README.txt @@ -0,0 +1,7 @@ +- 2x2x1 mesh +- remove one cell, exposing two faces +- move exposed faces into two patches +- decompose onto 3 +- run surfaceMeshExtract -featureAngle 180 +- should also mark points on the processor that has no + faces but is coupled diff --git a/applications/test/syncTools/missing_cell/constant/transportProperties b/applications/test/syncTools/missing_cell/constant/transportProperties new file mode 100644 index 0000000000000000000000000000000000000000..81751433add7024256d4bef17106be60be2f9d59 --- /dev/null +++ b/applications/test/syncTools/missing_cell/constant/transportProperties @@ -0,0 +1,21 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object transportProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +nu 0.01; + + +// ************************************************************************* // diff --git a/applications/test/syncTools/missing_cell/system/blockMeshDict b/applications/test/syncTools/missing_cell/system/blockMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..b0b42b9b088166d3f044ab8747d08382b7bf91ec --- /dev/null +++ b/applications/test/syncTools/missing_cell/system/blockMeshDict @@ -0,0 +1,88 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +vertices +( + //- Single block + (0 0 0) + (2 0 0) + (2 2 0) + (0 2 0) + (0 0 2) + (2 0 2) + (2 2 2) + (0 2 2) +); + +blocks +( + hex (0 1 2 3 4 5 6 7) (2 2 1) simpleGrading (1 1 1) +); + +edges +( +); + +boundary +( + topWall + { + type wall; + faces + ( + (3 7 6 2) + ); + } + bottomWall + { + type wall; + faces + ( + (1 5 4 0) + ); + } + fixedWalls + { + type wall; + faces + ( + (0 4 7 3) + (2 6 5 1) + ); + } + frontAndBack + { + type patch; + faces + ( + (0 3 2 1) + (4 5 6 7) + ); + } + exposed0 + { + type patch; + faces (); + } +); + +mergePatchPairs +( +); + +// ************************************************************************* // diff --git a/applications/test/syncTools/missing_cell/system/controlDict b/applications/test/syncTools/missing_cell/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..67583ffe687146b8c60f6fe72ecd6e53e3193931 --- /dev/null +++ b/applications/test/syncTools/missing_cell/system/controlDict @@ -0,0 +1,48 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +application icoFoam; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 0.5; + +deltaT 0.005; + +writeControl timeStep; + +writeInterval 20; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 16; + +writeCompression off; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable true; + +// ************************************************************************* // diff --git a/applications/test/syncTools/missing_cell/system/createPatchDict b/applications/test/syncTools/missing_cell/system/createPatchDict new file mode 100644 index 0000000000000000000000000000000000000000..2b8eb0d7041807418b750e116f98a19adf55b1b2 --- /dev/null +++ b/applications/test/syncTools/missing_cell/system/createPatchDict @@ -0,0 +1,44 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object createPatchDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +pointSync false; + +// Patches to create. +patches +( + // Example of creating mapped patches using geometric matching + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { + // Name of new patch + name exposed1; + + // Dictionary to construct new patch from + patchInfo + { + type patch; + } + + // How to select the faces: + // - set : specify faceSet in 'set' + // - patches : specify names in 'patches' + // - autoPatch : attempts automatic patching of the specified + // candidates in 'patches'. + constructFrom set; + set exposed0; + } +); + +// ************************************************************************* // diff --git a/applications/test/syncTools/missing_cell/system/decomposeParDict b/applications/test/syncTools/missing_cell/system/decomposeParDict new file mode 100644 index 0000000000000000000000000000000000000000..2eb5272d0db72448a16bd13e8c7a7a4cc5c5029a --- /dev/null +++ b/applications/test/syncTools/missing_cell/system/decomposeParDict @@ -0,0 +1,24 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + note "mesh decomposition control dictionary"; + object decomposeParDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- The total number of domains (mandatory) +numberOfSubdomains 3; + +//- The decomposition method (mandatory) +method scotch; + +// ************************************************************************* // diff --git a/applications/test/syncTools/missing_cell/system/fvSchemes b/applications/test/syncTools/missing_cell/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..51748f98addb1124e4052f9f06e625d4b83c752c --- /dev/null +++ b/applications/test/syncTools/missing_cell/system/fvSchemes @@ -0,0 +1,51 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +ddtSchemes +{ + default Euler; +} + +gradSchemes +{ + default Gauss linear; + grad(p) Gauss linear; +} + +divSchemes +{ + default none; + div(phi,U) Gauss linear; +} + +laplacianSchemes +{ + default Gauss linear orthogonal; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default orthogonal; +} + + +// ************************************************************************* // diff --git a/applications/test/syncTools/missing_cell/system/fvSolution b/applications/test/syncTools/missing_cell/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..e19b1d15604c8dce018e3fc4af17f77ddd37a135 --- /dev/null +++ b/applications/test/syncTools/missing_cell/system/fvSolution @@ -0,0 +1,52 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ + p + { + solver PCG; + preconditioner DIC; + tolerance 1e-06; + relTol 0.05; + } + + pFinal + { + $p; + relTol 0; + } + + U + { + solver smoothSolver; + smoother symGaussSeidel; + tolerance 1e-05; + relTol 0; + } +} + +PISO +{ + nCorrectors 2; + nNonOrthogonalCorrectors 0; + pRefCell 0; + pRefValue 0; +} + + +// ************************************************************************* // diff --git a/applications/test/syncTools/missing_cell/system/topoSetDict b/applications/test/syncTools/missing_cell/system/topoSetDict new file mode 100644 index 0000000000000000000000000000000000000000..b58c9dc308435af3c38727a1dab3c06544970129 --- /dev/null +++ b/applications/test/syncTools/missing_cell/system/topoSetDict @@ -0,0 +1,48 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object topoSetDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +actions +( + { + name c0; + type cellSet; + action new; + source labelToCell; + value (0); + } + { + name c0; + type cellSet; + action invert; + } + + { + name exposed0; + type faceSet; + action new; + source patchToFace; + patch exposed0; + } + { + name exposed0; + type faceSet; + action subset; + source boxToFace; + box (-100 1 -100)(100 100 100); + } +); + +// ************************************************************************* // diff --git a/applications/utilities/mesh/generation/extrude/extrudeMesh/extrudeMesh.C b/applications/utilities/mesh/generation/extrude/extrudeMesh/extrudeMesh.C index aed6edfbea3609967611fb628c3db5cd2bb4cb1d..9023c4f1642f518de12e59fed5189616434f484c 100644 --- a/applications/utilities/mesh/generation/extrude/extrudeMesh/extrudeMesh.C +++ b/applications/utilities/mesh/generation/extrude/extrudeMesh/extrudeMesh.C @@ -99,21 +99,21 @@ label findPatchID(const polyBoundaryMesh& patches, const word& name) } -labelList patchFaces(const polyBoundaryMesh& patches, const wordList& names) +labelList patchFaces(const polyBoundaryMesh& patches, const wordRes& names) { + const labelList patchIDs(patches.indices(names)); + label n = 0; - forAll(names, i) + for (label patchi : patchIDs) { - const polyPatch& pp = patches[findPatchID(patches, names[i])]; - - n += pp.size(); + n += patches[patchi].size(); } labelList faceLabels(n); n = 0; - forAll(names, i) + for (label patchi : patchIDs) { - const polyPatch& pp = patches[findPatchID(patches, names[i])]; + const polyPatch& pp = patches[patchi]; forAll(pp, j) { @@ -128,24 +128,25 @@ labelList patchFaces(const polyBoundaryMesh& patches, const wordList& names) void zoneFaces ( const faceZoneMesh& fzs, - const wordList& names, + const wordRes& names, labelList& faceLabels, bitSet& faceFlip ) { + const labelList zoneIDs(fzs.indices(names)); + label n = 0; - forAll(names, i) + for (label zonei : zoneIDs) { - const auto& pp = fzs[fzs.findZoneID(names[i])]; - n += pp.size(); + n += fzs[zonei].size(); } faceLabels.setSize(n); faceFlip.setSize(n); n = 0; - forAll(names, i) + for (label zonei : zoneIDs) { - const auto& pp = fzs[fzs.findZoneID(names[i])]; + const auto& pp = fzs[zonei]; const boolList& ppFlip = pp.flipMap(); forAll(pp, i) { @@ -345,8 +346,8 @@ int main(int argc, char *argv[]) sourceCaseDir = sourceCaseDir/("processor" + Foam::name(Pstream::myProcNo())); } - wordList sourcePatches; - wordList sourceFaceZones; + wordRes sourcePatches; + wordRes sourceFaceZones; if ( dict.readIfPresent @@ -868,13 +869,13 @@ int main(int argc, char *argv[]) frontPatchFaces = patchFaces ( meshFromSurface().boundaryMesh(), - wordList(1, frontPatchName) + wordRes(1, frontPatchName) ); backPatchName = "otherSide"; backPatchFaces = patchFaces ( meshFromSurface().boundaryMesh(), - wordList(1, backPatchName) + wordRes(1, backPatchName) ); } diff --git a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C index 2002149f2255a6b077bd4c902ce178367b7242bc..2cec08501cc23bd6a86e5867285be78065ceffdb 100644 --- a/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C +++ b/applications/utilities/mesh/generation/snappyHexMesh/snappyHexMesh.C @@ -825,6 +825,17 @@ int main(int argc, char *argv[]) #include "setSystemMeshDictionaryIO.H" const IOdictionary meshDict(dictIO); + // Overall mesh generation mode + const meshRefinement::MeshType meshType + ( + meshRefinement::MeshTypeNames.getOrDefault + ( + "type", + meshDict, + meshRefinement::CASTELLATED + ) + ); + // all surface geometry const dictionary& geometryDict = @@ -1339,6 +1350,7 @@ int main(int argc, char *argv[]) shells, // for volume (inside/outside) refinement limitShells, // limit of volume refinement labelList(), // initial faces to test + meshType, // how to operate dryRun ); diff --git a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C index 1a195e360067a55c75931ae294c340663fd467d1..1b195acc0322956076116ac4dd7f71335a82c787 100644 --- a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C +++ b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2023 OpenCFD Ltd. + Copyright (C) 2016-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -220,7 +220,7 @@ PtrList<FieldType> subsetFields const pointMesh& pMesh ) { - const fvMesh& baseMesh = subsetter.baseMesh(); + //const fvMesh& baseMesh = subsetter.baseMesh(); const UPtrList<const IOobject> fieldObjects ( @@ -247,8 +247,8 @@ PtrList<FieldType> subsetFields IOobject ( io.name(), - baseMesh.time().timeName(), - baseMesh, + pMesh.thisDb().time().timeName(), + pMesh.thisDb(), IOobjectOption::MUST_READ, IOobjectOption::NO_WRITE, IOobjectOption::NO_REGISTER @@ -382,6 +382,8 @@ int main(int argc, char *argv[]) #include "createTime.H" #include "createNamedMesh.H" + // Make sure pointMesh gets constructed/read as well + (void)pointMesh::New(mesh, IOobject::READ_IF_PRESENT); // arg[1] = word (cellSet) or wordRes (cellZone) // const word selectionName = args[1]; @@ -583,7 +585,7 @@ int main(int argc, char *argv[]) // Read point fields and subset // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - const pointMesh& pMesh = pointMesh::New(mesh); + const pointMesh& pMesh = pointMesh::New(mesh, IOobject::READ_IF_PRESENT); #undef createSubsetFields #define createSubsetFields(FieldType, Variable) \ @@ -663,6 +665,18 @@ int main(int argc, char *argv[]) subsetter.subMesh().write(); processorMeshes::removeFiles(subsetter.subMesh()); + auto* subPointMeshPtr = + subsetter.subMesh().thisDb().findObject<pointMesh> + ( + pointMesh::typeName + ); + if (subPointMeshPtr) + { + pointMesh& subPointMesh = const_cast<pointMesh&>(*subPointMeshPtr); + subPointMesh.setInstance(subsetter.subMesh().facesInstance()); + subPointMesh.write(); + } + // Volume fields for (const auto& fld : vScalarFlds) { fld.write(); } diff --git a/applications/utilities/parallelProcessing/decomposePar/decomposePar.C b/applications/utilities/parallelProcessing/decomposePar/decomposePar.C index df9c6d9ce26e724e70d30bde22ac4ed68fa15b7d..43222468845d083d27f36ed94df32ce6d54a8ae9 100644 --- a/applications/utilities/parallelProcessing/decomposePar/decomposePar.C +++ b/applications/utilities/parallelProcessing/decomposePar/decomposePar.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2016-2022 OpenCFD Ltd. + Copyright (C) 2016-2022,2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -666,6 +666,9 @@ int main(int argc, char *argv[]) ), decompDictFile ); + // Make sure pointMesh gets read as well + (void)pointMesh::New(mesh, IOobject::READ_IF_PRESENT); + // Decompose the mesh if (!decomposeFieldsOnly) @@ -785,6 +788,7 @@ int main(int argc, char *argv[]) PtrList<labelIOList> cellProcAddressingList(mesh.nProcs()); PtrList<labelIOList> boundaryProcAddressingList(mesh.nProcs()); PtrList<labelIOList> pointProcAddressingList(mesh.nProcs()); + PtrList<labelIOList> pointBoundaryProcAddressingList(mesh.nProcs()); PtrList<fvFieldDecomposer> fieldDecomposerList(mesh.nProcs()); PtrList<pointFieldDecomposer> pointFieldDecomposerList @@ -869,7 +873,10 @@ int main(int argc, char *argv[]) // Point fields // ~~~~~~~~~~~~ - const pointMesh& pMesh = pointMesh::New(mesh); + + // Read decomposed pointMesh + const pointMesh& pMesh = + pointMesh::New(mesh, IOobject::READ_IF_PRESENT); pointFieldDecomposer::fieldsCache pointFieldCache; @@ -1138,7 +1145,34 @@ int main(int argc, char *argv[]) pointProcAddressingList ); - const pointMesh& procPMesh = pointMesh::New(procMesh); + const pointMesh& procPMesh = + pointMesh::New(procMesh, IOobject::READ_IF_PRESENT); + + if (!pointBoundaryProcAddressingList.set(proci)) + { + pointBoundaryProcAddressingList.set + ( + proci, + autoPtr<labelIOList>::New + ( + IOobject + ( + "boundaryProcAddressing", + procMesh.facesInstance(), + polyMesh::meshSubDir + /pointMesh::meshSubDir, + procPMesh.thisDb(), + IOobject::READ_IF_PRESENT, + IOobject::NO_WRITE, + IOobject::NO_REGISTER + ), + boundaryProcAddressing + ) + ); + } + const auto& pointBoundaryProcAddressing = + pointBoundaryProcAddressingList[proci]; + if (!pointFieldDecomposerList.set(proci)) { @@ -1150,7 +1184,7 @@ int main(int argc, char *argv[]) pMesh, procPMesh, pointProcAddressing, - boundaryProcAddressing + pointBoundaryProcAddressing ) ); } @@ -1162,6 +1196,12 @@ int main(int argc, char *argv[]) if (times.size() == 1) { + // Early deletion + pointBoundaryProcAddressingList.set + ( + proci, + nullptr + ); pointProcAddressingList.set(proci, nullptr); pointFieldDecomposerList.set(proci, nullptr); } diff --git a/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C b/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C index 2158e2a19e45b638270f05a9d76332919b247db2..c3d8ca5f8d94b507b2da4419defa9bcd96efbf48 100644 --- a/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C +++ b/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C @@ -44,6 +44,12 @@ License #include "decompositionModel.H" #include "hexRef8Data.H" +// For handling pointMeshes with additional patches +#include "pointMesh.H" +#include "meshPointPatch.H" +#include "processorPointPatch.H" +#include "DynamicField.H" + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::domainDecomposition::mark @@ -740,6 +746,101 @@ bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets) procMesh.write(); + // Add pointMesh if it was available + const auto* pMeshPtr = + thisDb().cfindObject<pointMesh>(pointMesh::typeName); + if (pMeshPtr) + { + const auto& pMesh = *pMeshPtr; + const auto& pMeshBoundary = pMesh.boundary(); + + + // 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring + // any additional patches + const auto& procPointMesh = pointMesh::New(procMesh); + + pointBoundaryMesh& procBoundary = + const_cast<pointBoundaryMesh&>(procPointMesh.boundary()); + + + // 2. Explicitly add subsetted meshPointPatches + forAll(pMeshBoundary, patchi) + { + const auto* mppPtr = isA<meshPointPatch>(pMeshBoundary[patchi]); + if (mppPtr && (procBoundary.findPatchID(mppPtr->name()) == -1)) + { + const auto& mpp = *mppPtr; + + DynamicList<label> procMeshPoints(mpp.size()); + DynamicField<vector> procNormals(mpp.size()); + forAll(mpp.meshPoints(), i) + { + const label pointi = mpp.meshPoints()[i]; + const label procPointi = pointLookup[pointi]; + if (procPointi != -1) + { + procMeshPoints.append(procPointi); + procNormals.append(mpp.pointNormals()[i]); + } + } + + procBoundary.push_back + ( + new meshPointPatch + ( + mpp.name(), + procMeshPoints, + procNormals, + procBoundary.size(), + procBoundary, + meshPointPatch::typeName + ) + ); + } + } + + // 3. Shuffle new patches before any processor patches + labelList oldToNew(procBoundary.size()); + label newPatchi = 0; + forAll(procBoundary, patchi) + { + if (!isA<processorPointPatch>(procBoundary[patchi])) + { + oldToNew[patchi] = newPatchi; + newPatchi++; + } + } + + // decomposed-to-undecomposed patch numbering + labelList boundaryProcAddressing(identity(newPatchi)); + boundaryProcAddressing.setSize(procBoundary.size(), -1); + + forAll(procBoundary, patchi) + { + if (isA<processorPointPatch>(procBoundary[patchi])) + { + oldToNew[patchi] = newPatchi++; + } + } + procBoundary.reorder(oldToNew, true); + + // Write pointMesh/boundary + procBoundary.write(); + + // Write pointMesh/boundaryProcAddressing + IOobject ioAddr + ( + "boundaryProcAddressing", + procMesh.facesInstance(), + polyMesh::meshSubDir/pointMesh::meshSubDir, + procPointMesh.thisDb(), + IOobject::NO_READ, + IOobject::NO_WRITE, + IOobject::NO_REGISTER + ); + IOListRef<label>(ioAddr, boundaryProcAddressing).write(); + } + // Write points if pointsInstance differing from facesInstance if (facesInstancePointsPtr_) { diff --git a/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C b/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C index 4d2910373d9c06e24d5444dee3ef0ff928fbe6c3..0e8f7f7b39cddf1a346702878af331a307517393 100644 --- a/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C +++ b/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C @@ -427,24 +427,18 @@ int main(int argc, char *argv[]) { Info<< "Reconstructing point fields" << nl << endl; - const pointMesh& pMesh = pointMesh::New(mesh); - PtrList<pointMesh> pMeshes(procMeshes.meshes().size()); - - forAll(pMeshes, proci) - { - pMeshes.set - ( - proci, - new pointMesh(procMeshes.meshes()[proci]) - ); - } + const pointMesh& pMesh = pointMesh::New + ( + mesh, + IOobject::READ_IF_PRESENT + ); pointFieldReconstructor reconstructor ( pMesh, - pMeshes, + procMeshes.pointMeshes(), procMeshes.pointProcAddressing(), - procMeshes.boundaryProcAddressing() + procMeshes.pointMeshBoundaryProcAddressing() ); reconstructor.reconstructAllFields(objects, selectedFields); diff --git a/applications/utilities/surface/surfaceMeshExtract/Make/options b/applications/utilities/surface/surfaceMeshExtract/Make/options index 5ae72ebd31bdf7500846ee0dca7a4c123ff4fb43..09d94545a79d41316204b2dad2085ce4c5c22b21 100644 --- a/applications/utilities/surface/surfaceMeshExtract/Make/options +++ b/applications/utilities/surface/surfaceMeshExtract/Make/options @@ -1,7 +1,9 @@ EXE_INC = \ -I$(LIB_SRC)/surfMesh/lnInclude \ + -I$(LIB_SRC)/fileFormats/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude EXE_LIBS = \ -lsurfMesh \ + -lfileFormats \ -lmeshTools diff --git a/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C b/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C index 3387ad26411d3504e2bbd384a540e8dec8a2488f..6f276914579981810a6e6fe31eb2ca43f0a6725d 100644 --- a/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C +++ b/applications/utilities/surface/surfaceMeshExtract/surfaceMeshExtract.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2017-2023 OpenCFD Ltd. + Copyright (C) 2017-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -34,13 +34,39 @@ Description Extract patch or faceZone surfaces from a polyMesh. Depending on output surface format triangulates faces. - Region numbers on faces no guaranteed to be the same as the patch indices. + Region numbers on faces not guaranteed to be the same as the patch indices. Optionally only extracts named patches. + Optionally filters out points on faceZones, feature-edges and + featurePoints and generates pointPatches + for these - written to pointMesh/boundary. + If run in parallel, processor patches get filtered out by default and the mesh is merged (based on topology). +Usage + \b surfaceMeshExtract [OPTION] \<surfacefile\> + + Options: + - \par -patches NAME | LIST + Specify single patch or multiple patches (name or regex) to extract + + - \par -faceZones NAME | LIST + Specify single zone or multiple face zones (name or regex) to extract + + - \par -exclude-patches NAME | LIST + Exclude single or multiple patches (name or regex) from extraction + + - \par -excludeProcPatches + Exclude processor patches (default if parallel) + + - \par -featureAngle \<angle\> + Extract feature edges/points and put into separate point-patches + + - \par -extractZonePoints + Extract all face zone points and put into separate point-patches + \*---------------------------------------------------------------------------*/ #include "MeshedSurface.H" @@ -48,6 +74,7 @@ Description #include "argList.H" #include "Time.H" #include "polyMesh.H" +#include "pointMesh.H" #include "emptyPolyPatch.H" #include "processorPolyPatch.H" #include "ListListOps.H" @@ -56,11 +83,79 @@ Description #include "globalMeshData.H" #include "globalIndex.H" #include "timeSelector.H" +#include "meshPointPatch.H" +#include "unitConversion.H" +#include "dummyTransform.H" +#include "syncTools.H" +#include "processorPointPatch.H" +#include "pointMeshTools.H" +#include "OBJstream.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +void writeOBJ +( + const fileName& path, + const pointPatch& pp +) +{ + const meshPointPatch& ppp = refCast<const meshPointPatch>(pp); + const polyMesh& mesh = ppp.boundaryMesh().mesh().mesh(); + + // Count constraints + label maxConstraint = 0; + const auto& constraints = ppp.constraints(); + forAll(constraints, i) + { + maxConstraint = max(maxConstraint, constraints[i].first()); + } + reduce(maxConstraint, maxOp<label>()); + + const pointField localPoints(mesh.points(), ppp.meshPoints()); + + if (maxConstraint == 3) + { + OBJstream os + ( + path + / ppp.name()+"_fixedPoints.obj" + ); + os.write(localPoints); + Info<< "Written pointPatch " << ppp.name() << " to " << os.name() + << endl; + } + else if (maxConstraint == 2) + { + OBJstream os + ( + path + / ppp.name()+"_slidingPoints.obj" + ); + forAll(localPoints, i) + { + os.write(localPoints[i], constraints[i].second()); + } + Info<< "Written pointPatch " << ppp.name() << " to " << os.name() + << " as coordinates and normals" + << endl; + } + else if (maxConstraint == 1) + { + OBJstream os + ( + path + / ppp.name()+"_surfacePoints.obj" + ); + os.write(localPoints); + Info<< "Written pointPatch " << ppp.name() << " to " << os.name() + << " as coordinates" + << endl; + } +} + + labelList getSelectedPatches ( const polyBoundaryMesh& patches, @@ -107,6 +202,286 @@ labelList getSelectedPatches } +label addMeshPointPatches +( + const polyMesh& mesh, + const pointMesh& pMesh, + + const uindirectPrimitivePatch& allBoundary, + const labelUList& faceToZone, + const surfZoneIdentifierList& surfZones, + const labelList& faceZoneToCompactZone, + + const scalar edgeFeatureAngle, + const scalar pointFeatureAngle, + const bool verbose = true, + const bool writePoints = false +) +{ + const auto& pointBm = pMesh.boundary(); + const auto& fzs = mesh.faceZones(); + const label nPointPatches = pointBm.size(); + const pointField& points = mesh.points(); + + + // Feature edge(points) internal to a zone + labelListList zoneToMeshPoints; + List<pointConstraintList> zoneToConstraints; + + // Feature edge(points) in between zones + labelList twoZoneMeshPoints; + pointConstraintList twoZoneConstraints; + + // Feature points on > 2 zones + labelList multiZoneMeshPoints; + pointConstraintList multiZoneConstraints; + + pointMeshTools::featurePointsEdges + ( + mesh, + allBoundary, + // Per boundary face to zone + faceToZone, + // Number of zones + surfZones.size(), + edgeFeatureAngle, + //const scalar pointFeatureAngle, //not yet done + + // Feature edge(points) internal to a zone + zoneToMeshPoints, + zoneToConstraints, + + // Feature edge(points) in between zones + twoZoneMeshPoints, + twoZoneConstraints, + + // Feature points on > 2 zones + multiZoneMeshPoints, + multiZoneConstraints + ); + + + // Add per-zone patches + if (faceZoneToCompactZone.size()) + { + // Calculate point normals consistent across whole patch + const pointField pointNormals + ( + PatchTools::pointNormals + ( + mesh, + allBoundary + ) + ); + + forAll(faceZoneToCompactZone, zonei) + { + const label compacti = faceZoneToCompactZone[zonei]; + if (compacti != -1) + { + const word patchName(surfZones[compacti].name()); + + if (pointBm.findPatchID(patchName) == -1) + { + // Extract the points originating from the faceZone. Can + // - re-call featurePointsEdges with 0 feature angle so + // all points go into the feature edges + // - mark using faceToZone the correct points + // - or assume the whole faceZone was extracted: + const uindirectPrimitivePatch fzPatch + ( + UIndirectList<face> + ( + mesh.faces(), + fzs[zonei].addressing() + ), + points + ); + const auto& mp = fzPatch.meshPoints(); + + const vector nullVector(vector::uniform(0)); + + // Extract pointNormal (or 0) on all patch/connected points + vectorField meshPointNormals(mesh.nPoints(), nullVector); + for (const label pointi : mp) + { + const label allPointi = + allBoundary.meshPointMap()[pointi]; + meshPointNormals[pointi] = pointNormals[allPointi]; + } + syncTools::syncPointList + ( + mesh, + meshPointNormals, + maxMagSqrEqOp<vector>(), + nullVector + ); + + // Extract indices with non-zero pointNormal + DynamicList<label> meshPoints(mp.size()); + forAll(meshPointNormals, pointi) + { + if (meshPointNormals[pointi] != nullVector) + { + meshPoints.append(pointi); + } + } + + const_cast<pointBoundaryMesh&>(pointBm).push_back + ( + new meshPointPatch + ( + patchName, + meshPoints, + vectorField(meshPointNormals, meshPoints), + pointBm.size(), + pointBm, + meshPointPatch::typeName + ) + ); + + if (verbose) + { + const auto& ppp = pointBm.last(); + Info<< "Added zone pointPatch " << ppp.name() + << " with " + << returnReduce(meshPoints.size(), sumOp<label>()) + << " points" << endl; + } + if (writePoints) + { + writeOBJ(mesh.path(), pointBm.last()); + } + } + } + } + } + + + // Add per-patch feature-edges + forAll(zoneToMeshPoints, zonei) + { + const label nPoints = + returnReduce(zoneToMeshPoints[zonei].size(), sumOp<label>()); + + const word patchName(surfZones[zonei].name() + "Edges"); + + if (nPoints && (pointBm.findPatchID(patchName) == -1)) + { + const_cast<pointBoundaryMesh&>(pointBm).push_back + ( + new meshPointPatch + ( + patchName, + zoneToMeshPoints[zonei], + zoneToConstraints[zonei], + pointBm.size(), + pointBm, + meshPointPatch::typeName + ) + ); + + if (verbose) + { + const auto& ppp = pointBm.last(); + Info<< "Added feature-edges pointPatch " << ppp.name() + << " with " << nPoints << " points" << endl; + } + if (writePoints) + { + writeOBJ(mesh.path(), pointBm.last()); + } + } + } + + + // Add inter-patch points + + const word allEdgePatchName("boundaryEdges"); + const label nPatchEdgePoints = + returnReduce(twoZoneMeshPoints.size(), sumOp<label>()); + if (nPatchEdgePoints && (pointBm.findPatchID(allEdgePatchName) == -1)) + { + const_cast<pointBoundaryMesh&>(pointBm).push_back + ( + new meshPointPatch + ( + allEdgePatchName, + twoZoneMeshPoints, + twoZoneConstraints, + pointBm.size(), + pointBm, + meshPointPatch::typeName + ) + ); + + if (verbose) + { + const auto& ppp = pointBm.last(); + Info<< "Added inter-patch pointPatch " << ppp.name() + << " with " << nPatchEdgePoints << " points" << endl; + } + if (writePoints) + { + writeOBJ(mesh.path(), pointBm.last()); + } + } + + + const word allPointPatchName("boundaryPoints"); + const label nMultiPoints = + returnReduce(multiZoneMeshPoints.size(), sumOp<label>()); + if (nMultiPoints && (pointBm.findPatchID(allPointPatchName) == -1)) + { + const_cast<pointBoundaryMesh&>(pointBm).push_back + ( + new meshPointPatch + ( + allPointPatchName, + multiZoneMeshPoints, + multiZoneConstraints, + pointBm.size(), + pointBm, + meshPointPatch::typeName + ) + ); + + if (verbose) + { + const auto& ppp = pointBm.last(); + Info<< "Added multi-patch pointPatch " << ppp.name() + << " with " << nMultiPoints << " points" << endl; + } + if (writePoints) + { + writeOBJ(mesh.path(), pointBm.last()); + } + } + + + // Shuffle into order + labelList oldToNew(pointBm.size()); + label newPatchi = 0; + forAll(pointBm, patchi) + { + if (!isA<processorPointPatch>(pointBm[patchi])) + { + oldToNew[patchi] = newPatchi++; + } + } + forAll(pointBm, patchi) + { + if (isA<processorPointPatch>(pointBm[patchi])) + { + oldToNew[patchi] = newPatchi++; + } + } + const_cast<pointBoundaryMesh&>(pointBm).reorder(oldToNew, true); + + return pointBm.size() - nPointPatches; +} + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) @@ -114,8 +489,6 @@ int main(int argc, char *argv[]) argList::addNote ( "Extract patch or faceZone surfaces from a polyMesh." - " The name is historical, it only triangulates faces" - " when the output format requires it." ); timeSelector::addOptions(); @@ -153,6 +526,22 @@ int main(int argc, char *argv[]) true // mark as an advanced option ); argList::addOptionCompat("exclude-patches", {"excludePatches", 2306}); + argList::addOption + ( + "featureAngle", + "angle", + "Auto-extract feature edges/points and put into separate point-patches" + ); + argList::addBoolOption + ( + "extractZonePoints", + "Extract point-patches for selected faceZones" + ); + argList::addBoolOption + ( + "writeOBJ", + "Write added pointPatch points to .obj files" + ); #include "setRootCase.H" #include "createTime.H" @@ -200,9 +589,37 @@ int main(int argc, char *argv[]) << nl << endl; } + scalar featureAngle = 180.0; + const bool specifiedFeature = args.readIfPresent + ( + "featureAngle", + featureAngle + ); + + const bool extractZonePoints = args.found("extractZonePoints"); + const bool writeOBJ = args.found("writeOBJ"); + Info<< "Reading mesh from time " << runTime.value() << endl; #include "createNamedPolyMesh.H" + if (specifiedFeature) + { + Info<< "Detecting all sharp (>" << featureAngle + << " degrees) patch edges." << nl << endl; + + if (extractZonePoints) + { + Info<< "Extracting all faceZone points as pointPatches." + << nl << endl; + } + + //#include "createNamedPointMesh.H" + // Do not read constant/pointMesh - construct from polyMesh only + Info<< "Create pointMesh for time = " + << runTime.timeName() << Foam::nl << Foam::endl; + (void)pointMesh::New(mesh); + } + // User specified times instantList timeDirs = timeSelector::select0(runTime, args); @@ -249,7 +666,7 @@ int main(int argc, char *argv[]) // Construct table of patches to include. const polyBoundaryMesh& bMesh = mesh.boundaryMesh(); - labelList patchIds = + const labelList patchIds = ( (includePatches.size() || excludePatches.size()) ? getSelectedPatches(bMesh, includePatches, excludePatches) @@ -276,7 +693,13 @@ int main(int argc, char *argv[]) // Mesh face and compact zone indx DynamicList<label> faceLabels; DynamicList<label> compactZones; + // Per compact 'zone' index the name and location + surfZoneIdentifierList surfZones; + // Per local patch to compact 'zone' index (or -1) + labelList patchToCompactZone(bMesh.size(), -1); + // Per local faceZone to compact 'zone' index (or -1) + labelList faceZoneToCompactZone(bMesh.size(), -1); { // Collect sizes. Hash on names to handle local-only patches (e.g. // processor patches) @@ -317,9 +740,18 @@ int main(int argc, char *argv[]) Pstream::broadcast(compactZoneID); + // Zones + surfZones.resize_nocopy(compactZoneID.size()); + forAllConstIters(compactZoneID, iter) + { + surfZones[*iter] = surfZoneIdentifier(iter.key(), *iter); + Info<< "surfZone " << *iter + << " : " << surfZones[*iter].name() + << endl; + } + + // Rework HashTable into labelList just for speed of conversion - labelList patchToCompactZone(bMesh.size(), -1); - labelList faceZoneToCompactZone(bMesh.size(), -1); forAllConstIters(compactZoneID, iter) { label patchi = bMesh.findPatchID(iter.key()); @@ -362,7 +794,7 @@ int main(int argc, char *argv[]) // Addressing engine for all faces - uindirectPrimitivePatch allBoundary + const uindirectPrimitivePatch allBoundary ( UIndirectList<face>(mesh.faces(), faceLabels), mesh.points() @@ -400,7 +832,7 @@ int main(int argc, char *argv[]) // Gather all ZoneIDs List<labelList> gatheredZones(Pstream::nProcs()); - gatheredZones[Pstream::myProcNo()].transfer(compactZones); + gatheredZones[Pstream::myProcNo()] = compactZones; Pstream::gatherList(gatheredZones); // On master combine all points, faces, zones @@ -428,16 +860,6 @@ int main(int argc, char *argv[]) gatheredZones.clear(); - // Zones - surfZoneIdentifierList surfZones(compactZoneID.size()); - forAllConstIters(compactZoneID, iter) - { - surfZones[*iter] = surfZoneIdentifier(iter.key(), *iter); - Info<< "surfZone " << *iter - << " : " << surfZones[*iter].name() - << endl; - } - UnsortedMeshedSurface<face> unsortedFace ( std::move(allPoints), @@ -464,6 +886,39 @@ int main(int argc, char *argv[]) sortedFace.write(globalCasePath); } + + + if (specifiedFeature) + { + // Add edge patches + const auto& pMesh = pointMesh::New(mesh); + + const label nAdded = addMeshPointPatches + ( + mesh, + pMesh, + + allBoundary, // all patches together + compactZones, // originating compactZone + surfZones, // per compactZone the index + ( + extractZonePoints + ? faceZoneToCompactZone // per faceZone the compactZone + : labelList::null() + ), + + featureAngle, + featureAngle, + + true, + writeOBJ + ); + + if (nAdded) + { + pMesh.boundary().write(); + } + } } Info<< "End\n" << endl; diff --git a/etc/caseDicts/annotated/extrudeMeshDict b/etc/caseDicts/annotated/extrudeMeshDict index 6832d739bb120399487b474470cc1d0447f8a331..a6ce6d7303f0d1337901258b085675f65da59946 100644 --- a/etc/caseDicts/annotated/extrudeMeshDict +++ b/etc/caseDicts/annotated/extrudeMeshDict @@ -26,6 +26,7 @@ constructFrom patch; // If construct from patch/mesh: sourceCase "<case>"; // and one of sourcePatches or sourceFaceZones (but not both): +// (note: wildcards allowed) sourceFaceZones (someFacesZone); sourcePatches (movingWall); diff --git a/etc/caseDicts/annotated/snappyHexMeshDict b/etc/caseDicts/annotated/snappyHexMeshDict index c45b2bfa65ee8a3d5d418466321bf9bb533dc91f..1cd48e0f394840113d10801a30f6a3424607d10a 100644 --- a/etc/caseDicts/annotated/snappyHexMeshDict +++ b/etc/caseDicts/annotated/snappyHexMeshDict @@ -14,6 +14,12 @@ FoamFile } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Type of mesh generation: +// - castellated (default) +// - castellatedBufferLayer +//type castellatedBufferLayer; + + // Which of the steps to run castellatedMesh true; snap true; @@ -267,6 +273,10 @@ castellatedMeshControls // these can be done with feature edge snapping (so can leave // level (0 0)) //curvatureLevel (10 0 10 -1); + + // Optional disabling of buffer layer addition (if switched on by + // type = castellatedBufferLayer) + addBufferLayers false; } } @@ -605,6 +615,18 @@ snapControls //- Attract points only to the surface they originate from. Default // false. This can improve snapping of intersecting surfaces. // strictRegionSnap true; + + + // Choice of mesh motion algorithm to inflate layers (only used for mode + // castellatedBufferLayer) + + //solver displacementPointSmoothing; + //displacementPointSmoothingCoeffs + //{ + // // Use laplacian to untangle problem areas + // pointSmoother laplacian; + // nPointSmootherIter 10; + //} } // Settings for the layer addition. diff --git a/etc/caseDicts/annotated/topoSetSourcesDict b/etc/caseDicts/annotated/topoSetSourcesDict index 58727baa7e3fa6a61731f581188855d5fc2058ea..9021d8d94dbd99ee20bd18aae05de0ebd49cacdd 100644 --- a/etc/caseDicts/annotated/topoSetSourcesDict +++ b/etc/caseDicts/annotated/topoSetSourcesDict @@ -501,6 +501,15 @@ pointSet_doc } + //- All points of pointpatch + { + source patchToPoint; + patches ("patch.*"); + // or + patch somePatch; + } + + //- Copy elements from pointSet { source pointToPoint; diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index f8df675d93d013772900428798bb6ff33d568eb8..b19173cddc1f881a3ce7d63b9ba4e533f3c76ec7 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -715,10 +715,15 @@ pointMeshMapper = $(pointMesh)/pointMeshMapper $(pointMeshMapper)/pointMapper.C $(pointMeshMapper)/pointPatchMapper.C +pointMeshTools = $(pointMesh)/pointMeshTools +$(pointMeshTools)/pointMeshTools.C + pointPatches = $(pointMesh)/pointPatches $(pointPatches)/pointPatch/pointPatch.C +$(pointPatches)/pointPatch/pointPatchNew.C $(pointPatches)/facePointPatch/facePointPatch.C $(pointPatches)/facePointPatch/facePointPatchNew.C +$(pointPatches)/meshPointPatch/meshPointPatch.C basicPointPatches = $(pointPatches)/basic $(basicPointPatches)/coupled/coupledPointPatch.C @@ -792,6 +797,7 @@ $(Fields)/fieldTypes.C pointPatchFields = fields/pointPatchFields $(pointPatchFields)/pointPatchField/pointPatchFieldBase.C $(pointPatchFields)/pointPatchField/pointPatchFields.C +$(pointPatchFields)/pointPatchField/pointConstraint/pointConstraint.C basicPointPatchFields = $(pointPatchFields)/basic $(basicPointPatchFields)/calculated/calculatedPointPatchFields.C diff --git a/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraint.C b/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraint.C new file mode 100644 index 0000000000000000000000000000000000000000..d1ab3d47ffd7b1f55768ca45a446170fe96180e6 --- /dev/null +++ b/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraint.C @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "pointConstraint.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + const char* const pTraits<pointConstraint>::typeName = "pointConstraint"; +} + +// ************************************************************************* // diff --git a/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraint.H b/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraint.H index 932e44ed9a9356d692bcc4c3d7ea115d666c210c..d9adbf158213549ea1265357085bfe0c45cab0aa 100644 --- a/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraint.H +++ b/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraint.H @@ -73,6 +73,9 @@ public: //- Construct from components inline pointConstraint(const Tuple2<label, vector>&); + //- Construct from components + inline pointConstraint(const label count, const vector& n); + //- Construct from Istream inline pointConstraint(Istream&); @@ -97,8 +100,19 @@ public: }; +//! List of pointConstraint +typedef List<pointConstraint> pointConstraintList; + + // * * * * * * * * * * * * * * * * * Traits * * * * * * * * * * * * * * * * // +//- Template specialisation for pTraits\<pointConstraint\> to enable IO +template<> +struct pTraits<pointConstraint> +{ + static const char* const typeName; +}; + //- Contiguous data for pointConstraint template<> struct is_contiguous<pointConstraint> : std::true_type {}; diff --git a/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraintI.H b/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraintI.H index c6c1b74dfbcd500460168139a3a08066d39cbf70..324165fe333da25c4738d6f8af65477a63c0a259 100644 --- a/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraintI.H +++ b/src/OpenFOAM/fields/pointPatchFields/pointPatchField/pointConstraint/pointConstraintI.H @@ -39,6 +39,16 @@ inline Foam::pointConstraint::pointConstraint(const Tuple2<label, vector>& pc) {} +inline Foam::pointConstraint::pointConstraint +( + const label count, + const vector& n +) +: + Tuple2<label, vector>(count, n) +{} + + inline Foam::pointConstraint::pointConstraint(Istream& is) : Tuple2<label, vector>(is) diff --git a/src/OpenFOAM/include/createNamedPointMesh.H b/src/OpenFOAM/include/createNamedPointMesh.H new file mode 100644 index 0000000000000000000000000000000000000000..7c1c4265b7fc200331afe908c073f1a8c9ead467 --- /dev/null +++ b/src/OpenFOAM/include/createNamedPointMesh.H @@ -0,0 +1,10 @@ +Foam::Info + << "Create pointMesh for time = " + << runTime.timeName() << Foam::nl << Foam::endl; + +// Register pointMesh on the database +const Foam::pointMesh& pMesh = pointMesh::New +( + mesh, + Foam::IOobject::READ_IF_PRESENT +); diff --git a/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.C b/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.C index 266583000abf2c357680f7c3805c5bdd6c7b6d4a..97990194a2091f524c1b71f76987d1ea9820d013 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.C +++ b/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2018-2023 OpenCFD Ltd. + Copyright (C) 2018-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -33,9 +33,74 @@ License #include "PstreamBuffers.H" #include "lduSchedule.H" #include "globalMeshData.H" +#include "processorPointPatch.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(pointBoundaryMesh, 0); +} // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +bool Foam::pointBoundaryMesh::hasGroupIDs() const +{ + if (groupIDsPtr_) + { + // Use existing cache + return !groupIDsPtr_->empty(); + } + + const auto& patches = *this; + + for (const auto& p : patches) + { + if (!p.inGroups().empty()) + { + return true; + } + } + + return false; +} + + +void Foam::pointBoundaryMesh::calcGroupIDs() const +{ + if (groupIDsPtr_) + { + return; // Or FatalError + } + + groupIDsPtr_.emplace(16); + auto& groupLookup = *groupIDsPtr_; + + const auto& patches = *this; + + forAll(patches, patchi) + { + for (const word& groupName : patches[patchi].inGroups()) + { + groupLookup(groupName).push_back(patchi); + } + } + + // Remove groups that clash with patch names + forAll(patches, patchi) + { + if (groupLookup.erase(patches[patchi].name())) + { + WarningInFunction + << "Removed group '" << patches[patchi].name() + << "' which clashes with patch " << patchi + << " of the same name." + << endl; + } + } +} + + void Foam::pointBoundaryMesh::addPatches(const polyBoundaryMesh& pbm) { // Set boundary patches @@ -43,7 +108,7 @@ void Foam::pointBoundaryMesh::addPatches(const polyBoundaryMesh& pbm) patches.resize_null(pbm.size()); - forAll(patches, patchi) + forAll(pbm, patchi) { // NB: needs ptr() to get *pointPatch instead of *facePointPatch patches.set(patchi, facePointPatch::New(pbm[patchi], *this).ptr()); @@ -60,21 +125,301 @@ Foam::pointBoundaryMesh::pointBoundaryMesh ) : pointPatchList(), + regIOobject + ( + IOobject + ( + "boundary", + //m.thisDb().time().findInstance(m.meshDir(), "boundary"), + pbm.mesh().facesInstance(), + polyMesh::meshSubDir/pointMesh::meshSubDir, + m.thisDb(), + IOobject::NO_READ, + IOobject::NO_WRITE, + false // Avoid conflict with polyMesh/boundary + ) + ), mesh_(m) { addPatches(pbm); + + if (debug) + { + pointPatchList& Patches = *this; + + Pout<< "pointBoundaryMesh::pointBoundaryMesh" + << "(const pointMesh&, const polyBoundaryMesh&): " + << "constructed pointBoundaryMesh:" << endl; + Pout<< incrIndent; + for (const auto& pp : Patches) + { + Pout<< indent + << "index:" << pp.index() << " patch:" << pp.name() + << " type:" << pp.type() << endl; + } + Pout<< decrIndent; + } +} + + +Foam::pointBoundaryMesh::pointBoundaryMesh +( + const IOobject& io, + const pointMesh& m, + const polyBoundaryMesh& pbm +) +: + pointPatchList(), + regIOobject + ( + IOobject + ( + "boundary", + io.instance(), + polyMesh::meshSubDir/pointMesh::meshSubDir, + io.db(), + io.readOpt(), + io.writeOpt(), + false //io.registerObject() // or always set to false? + ) + ), + mesh_(m) +{ + pointPatchList& Patches = *this; + + if (isReadRequired() || (isReadOptional() && headerOk())) + { + if (readOpt() == IOobject::MUST_READ_IF_MODIFIED) + { + WarningInFunction + << "Specified IOobject::MUST_READ_IF_MODIFIED but class" + << " does not support automatic rereading." + << endl; + } + + if (debug) + { + Pout<< "pointBoundaryMesh::pointBoundaryMesh" + << "(const IOobject&, const pointMesh&," + << " const polyBoundaryMesh&): " + << "Constructing from boundary file " << objectRelPath() + << endl; + } + + // Read pointPatchList + Istream& is = readStream(typeName); + + PtrList<entry> patchEntries(is); + Patches.setSize(patchEntries.size()); + + forAll(Patches, patchi) + { + // Try construct-from-dictionary first + const word& name = patchEntries[patchi].keyword(); + + autoPtr<pointPatch> pPtr + ( + pointPatch::New + ( + name, + patchEntries[patchi].dict(), + patchi, + *this + ) + ); + + if (!pPtr) + { + const label polyPatchi = pbm.findPatchID(name, false); + // Try as facePointPatch from polyPatch + pPtr = facePointPatch::New(pbm[polyPatchi], *this); + pPtr->index() = patchi; + } + + Patches.set(patchi, pPtr); + } + + // Check state of IOstream + is.check + ( + "pointBoundaryMesh::pointBoundaryMesh" + "(const IOobject&, const pointMesh&," + " const polyBoundaryMesh&)" + ); + + close(); + } + else + { + if (debug) + { + Pout<< "pointBoundaryMesh::pointBoundaryMesh" + << "(const IOobject&, const pointMesh&," + << " const polyBoundaryMesh&): " + << "Constructing from polyBoundaryMesh only" + << endl; + } + + addPatches(pbm); + } + + + if (debug) + { + Pout<< "pointBoundaryMesh::pointBoundaryMesh" + << "(const IOobject&, const pointMesh&, const polyBoundaryMesh&): " + << "constructed pointBoundaryMesh:" << endl; + Pout<< incrIndent; + for (const auto& pp : Patches) + { + Pout<< indent + << "index:" << pp.index() << " patch:" << pp.name() + << " type:" << pp.type() << endl; + } + Pout<< decrIndent; + } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +Foam::label Foam::pointBoundaryMesh::nNonProcessor() const +{ + const pointPatchList& patches = *this; + + label count = 0; + + for (const auto& p : patches) + { + if (isA<processorPointPatch>(p)) + { + break; + } + + ++count; + } + + return count; +} + + +Foam::label Foam::pointBoundaryMesh::nProcessorPatches() const +{ + const pointPatchList& patches = *this; + + label count = 0; + + for (const auto& p : patches) + { + if (isA<processorPointPatch>(p)) + { + ++count; + } + } + + return count; +} + + +Foam::wordList Foam::pointBoundaryMesh::names() const +{ + return PtrListOps::get<word>(*this, nameOp<pointPatch>()); +} + + +Foam::wordList Foam::pointBoundaryMesh::types() const +{ + return PtrListOps::get<word>(*this, typeOp<pointPatch>()); +} + + +Foam::wordList Foam::pointBoundaryMesh::physicalTypes() const +{ + return + PtrListOps::get<word> + ( + *this, + [](const pointPatch& p) { return p.physicalType(); } + ); +} + + +const Foam::HashTable<Foam::labelList>& +Foam::pointBoundaryMesh::groupPatchIDs() const +{ + if (!groupIDsPtr_) + { + calcGroupIDs(); + } + + return *groupIDsPtr_; +} + + Foam::labelList Foam::pointBoundaryMesh::indices ( const wordRe& matcher, const bool useGroups ) const { - return mesh().boundaryMesh().indices(matcher, useGroups); + if (matcher.empty()) + { + return labelList(); + } + + // Only check groups if requested and they exist + const bool checkGroups = (useGroups && this->hasGroupIDs()); + + labelHashSet ids(0); + + if (matcher.isPattern()) + { + if (checkGroups) + { + const auto& groupLookup = groupPatchIDs(); + forAllConstIters(groupLookup, iter) + { + if (matcher(iter.key())) + { + // Add patch ids associated with the group + ids.insert(iter.val()); + } + } + } + + if (ids.empty()) + { + return PtrListOps::findMatching(*this, matcher); + } + else + { + ids.insert(PtrListOps::findMatching(*this, matcher)); + } + } + else + { + // Literal string. + // Special version of above for reduced memory footprint. + + const label patchId = PtrListOps::firstMatching(*this, matcher); + + if (patchId >= 0) + { + return labelList(one{}, patchId); + } + else if (checkGroups) + { + const auto iter = groupPatchIDs().cfind(matcher); + + if (iter.good()) + { + // Hash ids associated with the group + ids.insert(iter.val()); + } + } + } + + return ids.sortedToc(); } @@ -84,7 +429,43 @@ Foam::labelList Foam::pointBoundaryMesh::indices const bool useGroups ) const { - return mesh().boundaryMesh().indices(matcher, useGroups); + if (matcher.empty()) + { + return labelList(); + } + else if (matcher.size() == 1) + { + return this->indices(matcher.front(), useGroups); + } + + labelHashSet ids(0); + + // Only check groups if requested and they exist + if (useGroups && this->hasGroupIDs()) + { + ids.reserve(this->size()); + + const auto& groupLookup = groupPatchIDs(); + forAllConstIters(groupLookup, iter) + { + if (matcher(iter.key())) + { + // Add patch ids associated with the group + ids.insert(iter.val()); + } + } + } + + if (ids.empty()) + { + return PtrListOps::findMatching(*this, matcher); + } + else + { + ids.insert(PtrListOps::findMatching(*this, matcher)); + } + + return ids.sortedToc(); } @@ -95,13 +476,91 @@ Foam::labelList Foam::pointBoundaryMesh::indices const bool useGroups ) const { - return mesh().boundaryMesh().indices(select, ignore, useGroups); + //return mesh().boundaryMesh().indices(select, ignore, useGroups); + if (ignore.empty()) + { + return this->indices(select, useGroups); + } + + const wordRes::filter matcher(select, ignore); + + labelHashSet ids(0); + + // Only check groups if requested and they exist + if (useGroups && this->hasGroupIDs()) + { + ids.reserve(this->size()); + + const auto& groupLookup = groupPatchIDs(); + forAllConstIters(groupLookup, iter) + { + if (matcher(iter.key())) + { + // Add patch ids associated with the group + ids.insert(iter.val()); + } + } + } + + if (ids.empty()) + { + return PtrListOps::findMatching(*this, matcher); + } + else + { + ids.insert(PtrListOps::findMatching(*this, matcher)); + } + + return ids.sortedToc(); } -Foam::label Foam::pointBoundaryMesh::findPatchID(const word& patchName) const +Foam::label Foam::pointBoundaryMesh::findPatchID +( + const word& patchName, + bool allowNotFound +) const { - return mesh().boundaryMesh().findPatchID(patchName); + //return mesh().boundaryMesh().findPatchID(patchName); + if (patchName.empty()) + { + return -1; + } + + const label patchId = PtrListOps::firstMatching(*this, patchName); + + if (patchId >= 0) + { + return patchId; + } + + if (!allowNotFound) + { + FatalErrorInFunction + << "Patch '" << patchName << "' not found. " + << "Available patch names"; + + if (polyMesh::defaultRegion != mesh_.name()) + { + FatalError + << " in region '" << mesh_.name() << "'"; + } + + FatalError + << " include: " << names() << endl + << exit(FatalError); + } + + // Patch not found + if (debug) + { + Pout<< "label pointBoundaryMesh::findPatchID(const word&) const" + << " Patch named " << patchName << " not found. " + << "Available patch names: " << names() << endl; + } + + // Not found, return -1 + return -1; } @@ -243,4 +702,80 @@ void Foam::pointBoundaryMesh::updateMesh() } +void Foam::pointBoundaryMesh::reorder +( + const labelUList& oldToNew, + const bool validBoundary +) +{ + // Change order of patches + pointPatchList::reorder(oldToNew); + + // Adapt indices + pointPatchList& patches = *this; + + forAll(patches, patchi) + { + patches[patchi].index() = patchi; + } + + // Clear group-to-patch addressing. Note: could re-calculate + groupIDsPtr_.reset(nullptr); + + if (validBoundary) + { + updateMesh(); + } + + if (debug) + { + pointPatchList& Patches = *this; + + Pout<< "pointBoundaryMesh::reorder" + << "(const labelUList&, const bool): " + << "reordered pointBoundaryMesh:" << endl; + Pout<< incrIndent; + for (const auto& pp : Patches) + { + Pout<< indent + << "index:" << pp.index() << " patch:" << pp.name() + << " type:" << pp.type() << endl; + } + Pout<< decrIndent; + } +} + + +bool Foam::pointBoundaryMesh::writeData(Ostream& os) const +{ + const pointPatchList& patches = *this; + + os << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl; + + forAll(patches, patchi) + { + os << indent << patches[patchi].name() << nl + << indent << token::BEGIN_BLOCK << nl + << incrIndent << patches[patchi] << decrIndent + << indent << token::END_BLOCK << endl; + } + + os << decrIndent << token::END_LIST; + + // Check state of IOstream + os.check("pointBoundaryMesh::writeData(Ostream& os) const"); + + return os.good(); +} + + +//bool Foam::pointBoundaryMesh::writeObject +//( +// IOstreamOption +//) const +//{ +// return regIOobject::writeObject(fmt, ver, IOstream::UNCOMPRESSED); +//} + + // ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.H b/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.H index 588245038b895debf9b0442310829ec6c6f76b6e..561d75e1725e21f4001f9d5db894ec13b1be8162 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.H +++ b/src/OpenFOAM/meshes/pointMesh/pointBoundaryMesh/pointBoundaryMesh.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2013 OpenFOAM Foundation - Copyright (C) 2018-2023 OpenCFD Ltd. + Copyright (C) 2018-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -39,6 +39,7 @@ SourceFiles #define Foam_pointBoundaryMesh_H #include "pointPatch.H" +#include "regIOobject.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -56,19 +57,29 @@ class wordRes; class pointBoundaryMesh : - public pointPatchList + public pointPatchList, + public regIOobject { // Private Data //- Reference to mesh const pointMesh& mesh_; + //- Demand-driven: list of patch ids per group + mutable autoPtr<HashTable<labelList>> groupIDsPtr_; + // Private Member Functions //- Calculate geometry for the patches (transformation tensors etc.) void calcGeometry(); + //- Some patches have inGroup entries + bool hasGroupIDs() const; + + //- Calculate group name to patch ids lookup + void calcGroupIDs() const; + //- Assign facePointPatches corresponding to the given polyBoundaryMesh void addPatches(const polyBoundaryMesh& pbm); @@ -85,11 +96,27 @@ public: friend class pointMesh; + //- Runtime type information + TypeName("pointBoundaryMesh"); + + // Constructors //- Construct from polyBoundaryMesh pointBoundaryMesh(const pointMesh&, const polyBoundaryMesh&); + //- Construct from IOobject and polyBoundaryMesh + pointBoundaryMesh + ( + const IOobject& io, + const pointMesh&, + const polyBoundaryMesh& + ); + + + //- Destructor + virtual ~pointBoundaryMesh() = default; + // Member Functions @@ -99,6 +126,21 @@ public: return mesh_; } + //- The number of patches before the first processor patch. + label nNonProcessor() const; + + //- The number of processorPointPatch patches + label nProcessorPatches() const; + + //- Return a list of patch names + wordList names() const; + + //- Return a list of patch types + wordList types() const; + + //- Return a list of physical types + wordList physicalTypes() const; + //- Return (sorted) patch indices for all matches. // A no-op (returns empty list) for an empty matcher labelList indices(const wordRe& matcher, const bool useGroups) const; @@ -121,14 +163,31 @@ public: //- Find patch index given a name // A no-op (returns -1) for an empty patchName - label findPatchID(const word& patchName) const; + label findPatchID + ( + const word& patchName, + const bool allowNotFound = true + ) const; + + //- The patch indices per patch group + const HashTable<labelList>& groupPatchIDs() const; - //- Correct polyBoundaryMesh after moving points + //- Correct pointBoundaryMesh after moving points void movePoints(const pointField&); - //- Correct polyBoundaryMesh after topology update + //- Correct pointBoundaryMesh after topology update void updateMesh(); + //- Reorders patches. Ordering does not have to be done in + // ascending or descending order. Reordering has to be unique. + // (is shuffle) If validBoundary calls updateMesh() + // after reordering to recalculate data (so call needs to be parallel + // sync in that case) + void reorder(const labelUList& oldToNew, const bool validBoundary); + + //- writeData member function required by regIOobject + virtual bool writeData(Ostream&) const; + // Housekeeping diff --git a/src/OpenFOAM/meshes/pointMesh/pointMesh.C b/src/OpenFOAM/meshes/pointMesh/pointMesh.C index 3f36c56332a6f6130742e649b9b97a357f2fcd32..7d5d74ab8ffbe059ec4106a4be182d8a6e6d2f3b 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointMesh.C +++ b/src/OpenFOAM/meshes/pointMesh/pointMesh.C @@ -40,6 +40,8 @@ namespace Foam defineTypeNameAndDebug(pointMesh, 0); } +Foam::word Foam::pointMesh::meshSubDir = "pointMesh"; + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // @@ -89,8 +91,66 @@ Foam::pointMesh::pointMesh(const polyMesh& pMesh) } +Foam::pointMesh::pointMesh(const polyMesh& pMesh, const IOobject& io) +: + MeshObject<polyMesh, Foam::UpdateableMeshObject, pointMesh>(pMesh), + GeoMesh<polyMesh>(pMesh), + boundary_(io, *this, pMesh.boundaryMesh()) +{ + if (debug) + { + Pout<< "pointMesh::pointMesh(const polyMesh&): " + << "Constructing from IO " << io.objectRelPath() + << endl; + } + + // Calculate the geometry for the patches (transformation tensors etc.) + boundary_.calcGeometry(); +} + + +Foam::pointMesh::pointMesh +( + const polyMesh& pMesh, + const IOobjectOption::readOption rOpt +) +: + pointMesh + ( + pMesh, + IOobject + ( + pMesh.name(), // polyMesh region + pMesh.facesInstance(), // polyMesh topology instance + pMesh.time(), + rOpt, + Foam::IOobject::NO_WRITE + ) + ) +{} + + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +void Foam::pointMesh::setInstance +( + const fileName& inst, + const IOobjectOption::writeOption wOpt +) +{ + if (debug) + { + Pout<< "pointMesh::setInstance(): " + << "Setting instance to " << inst << endl; + } + this->writeOpt(wOpt); + this->instance() = inst; + + boundary_.writeOpt(wOpt); + boundary_.instance() = inst; +} + + bool Foam::pointMesh::movePoints() { if (debug) @@ -119,4 +179,19 @@ void Foam::pointMesh::updateMesh(const mapPolyMesh& mpm) } +bool Foam::pointMesh::writeObject +( + IOstreamOption streamOpt, + const bool writeOnProc +) const +{ + if (debug) + { + Pout<< "pointMesh::writeObject(IOstreamOption, const bool): " + << "Writing to " << boundary_.objectRelPath() << endl; + } + return boundary_.writeObject(streamOpt, writeOnProc); +} + + // ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointMesh.H b/src/OpenFOAM/meshes/pointMesh/pointMesh.H index 58462132078c368185b71681c61b17bd3ce6a2bf..8aaeb4f698c29acc8b6445972402e5e1c527b401 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointMesh.H +++ b/src/OpenFOAM/meshes/pointMesh/pointMesh.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2013 OpenFOAM Foundation - Copyright (C) 2021-2023 OpenCFD Ltd. + Copyright (C) 2021-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -96,12 +96,26 @@ public: // Declare name of the class and its debug switch ClassName("pointMesh"); + //- Return the mesh sub-directory name (usually "pointMesh") + static word meshSubDir; + // Constructors //- Construct from polyMesh explicit pointMesh(const polyMesh& pMesh); + //- Construct from polyMesh and IOobject (used when reading boundary) + explicit pointMesh(const polyMesh& pMesh, const IOobject& io); + + //- Construct from polyMesh and readOpt. Takes instance, time etc + //- from polyMesh. Used when reading boundary. + explicit pointMesh + ( + const polyMesh& pMesh, + const IOobjectOption::readOption rOpt + ); + //- Destructor ~pointMesh() = default; @@ -151,6 +165,13 @@ public: return GeoMesh<polyMesh>::mesh_.time(); } + //- Set the instance for mesh files + void setInstance + ( + const fileName& instance, + const IOobjectOption::writeOption wOpt = IOobject::AUTO_WRITE + ); + // Volume Mesh @@ -181,6 +202,16 @@ public: { return &pm == this; } + + + // Write + + //- Write + virtual bool writeObject + ( + IOstreamOption streamOpt, + const bool writeOnProc = true + ) const; }; diff --git a/src/OpenFOAM/meshes/pointMesh/pointMeshTools/pointMeshTools.C b/src/OpenFOAM/meshes/pointMesh/pointMeshTools/pointMeshTools.C new file mode 100644 index 0000000000000000000000000000000000000000..c49189a46e40ddf34e8828db282f2deb472edbf5 --- /dev/null +++ b/src/OpenFOAM/meshes/pointMesh/pointMeshTools/pointMeshTools.C @@ -0,0 +1,542 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "pointMeshTools.H" +#include "syncTools.H" +#include "PatchTools.H" +#include "dummyTransform.H" +#include "unitConversion.H" +//#include "OFstream.H" + +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +void Foam::pointMeshTools::featurePointsEdges +( + const polyMesh& mesh, + + const uindirectPrimitivePatch& allBoundary, + + // Per boundary face to zone + const labelUList& faceToZone, + // Number of zones + const label nZones, + + const scalar edgeFeatureAngle, + //const scalar pointFeatureAngle, //not yet done + + // Feature edge(points) internal to a zone + labelListList& zoneToMeshPoints, + List<pointConstraintList>& zoneToConstraints, + + // Feature edge(points) in between zones + labelList& twoZoneMeshPoints, + pointConstraintList& twoZoneConstraints, + + // Feature points on > 2 zones + labelList& multiZoneMeshPoints, + pointConstraintList& multiZoneConstraints +) +{ + // Analyses edges on mesh faces and splits them up according to topology + // and geometry: + // - edges in between faces on same zone but making a feature angle + // - edges in between faces on two different zones + // - points on faces on > 2 zones + + + const globalMeshData& globalData = mesh.globalData(); + const indirectPrimitivePatch& cpp = globalData.coupledPatch(); + const mapDistribute& map = globalData.globalEdgeSlavesMap(); + const auto& mp = allBoundary.meshPoints(); + + const vector nullVector(vector::uniform(0)); + const auto assignNonNull = [&](vector& x, const vector& y) + { + if (x == nullVector && y != nullVector) + { + x = y; + } + }; + + // Calculate parallel-consistent point normals (as unweighted average + // of faceNormals). Note: only valid on patch points, not on mesh points + // that are coupled to these. + const pointField pointNormals + ( + PatchTools::pointNormals + ( + mesh, + allBoundary + ) + ); + + + // Find correspondence between allBoundary and coupled edges + labelList allEdges; + labelList coupledEdges; + bitSet sameEdgeOrientation; + PatchTools::matchEdges + ( + allBoundary, + cpp, + allEdges, + coupledEdges, + sameEdgeOrientation + ); + + + + // To construct the patches we need to know per edge: + // - patch on either side (if topological feature edge) + // - faceNormal on either side (if feature angle) + // We need to know per point: + // - patches on all connected faces + // - faceNormals on all connected faces? And compare to average? + // or edge normals on all connected edges + + + typedef Tuple2<label, vector> PN; + const PN nullPN(-1, nullVector); + + + + // Point-based analysis + // ~~~~~~~~~~~~~~~~~~~~ + + // Collect per (mesh)point the zones (1, 2 or >2). Note: per mesh to + // make it easier to sync. See edge-based code below where we explicitly + // have to transfer from patch-edge to mesh-point etc. Note sure which one + // fits better.... + // State: + // (-1, -1) : initial state + // (-2, -2) : more than 2 zones + // (>=0, >=0) : zones from connected faces + labelPairList pointToZones(mesh.nPoints(), labelPair(-1, -1)); + { + // Combine zones. + const auto combineZones = [&](labelPair& x, const labelPair& y) + { + if (x == labelPair(-2, -2)) + { + // Already marked as having >2 zones + } + else if (y == labelPair(-2, -2)) + { + x = y; + } + else + { + // Find first free slot + if (x[0] == -1) + { + if (y[0] != -1) + { + x[0] = y[0]; + } + else + { + x[0] = y[1]; + } + } + else if (x[1] == -1) + { + if (y[0] != -1 && y[0] != x[0]) + { + x[1] = y[0]; + } + else if (y[1] != -1 && y[1] != x[1]) + { + x[1] = y[1]; + } + } + else + { + // Both x slots filled. See if y adds a 3rd element + if (y[0] != -1 && y[0] != x[0] && y[0] != x[1]) + { + x = labelPair(-2, -2); + } + else if (y[1] != -1 && y[1] != x[0] && y[1] != x[1]) + { + x = labelPair(-2, -2); + } + } + } + }; + + + forAll(allBoundary, facei) + { + const auto& f = allBoundary[facei]; + const label zonei = faceToZone[facei]; + for (const label pointi : f) + { + auto& pZones = pointToZones[pointi]; + + if (pZones != labelPair(-2, -2) && !pZones.contains(zonei)) + { + if (pZones.first() == -1) + { + pZones.first() = zonei; + } + else if (pZones.second() == -1) + { + pZones.second() = zonei; + } + else + { + // Mark as >2 zones + pZones = labelPair(-2, -2); + } + } + } + } + + syncTools::syncPointList + ( + mesh, + pointToZones, + combineZones, + labelPair(-1, -1), + dummyTransform() + ); + } + + + + + // Edge-based analysis + // ~~~~~~~~~~~~~~~~~~~~ + + // 1. Local analysis + + List<Pair<PN>> allEdgeToFaces + ( + allBoundary.nEdges(), + Pair<PN>(nullPN, nullPN) + ); + { + const auto& edgeFaces = allBoundary.edgeFaces(); + const auto& faceNormals = allBoundary.faceNormals(); + + forAll(edgeFaces, edgei) + { + const auto& eFaces = edgeFaces[edgei]; + const vector& n0 = faceNormals[eFaces[0]]; + const label zone0 = faceToZone[eFaces[0]]; + if (eFaces.size() == 1) + { + allEdgeToFaces[edgei] = Pair<PN>(PN(zone0, n0), nullPN); + } + else + { + const vector& n1 = faceNormals[eFaces[1]]; + const label zone1 = faceToZone[eFaces[1]]; + allEdgeToFaces[edgei] = Pair<PN> + ( + PN(zone0, n0), + PN(zone1, n1) + ); + } + } + } + + + // 2. Sync across coupled patches + + { + // Combine pair of normals + const auto vectorPairMax = [&](Pair<PN>& x, const Pair<PN>& y) + { + if (x[0] == nullPN) + { + if (y[0] != nullPN) + { + x[0] = y[0]; + } + else + { + x[0] = y[1]; + } + } + else if (x[1] == nullPN) + { + if (y[0] != nullPN && y[0] != x[0]) + { + x[1] = y[0]; + } + else + { + x[1] = y[1]; + } + } + }; + + List<Pair<PN>> cppEdgeData + ( + map.constructSize(), + Pair<PN>(nullPN, nullPN) + ); + UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges) = + UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges); + + globalData.syncData + ( + cppEdgeData, + globalData.globalEdgeSlaves(), + globalData.globalEdgeTransformedSlaves(), + map, + globalData.globalTransforms(), + vectorPairMax, + dummyTransform() + ); + + UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges) = + UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges); + } + + + // Now we have all the per-patch edge information + // - do inter-patch edges + // - do feature-angle edges + // Store on mesh points + + const auto assignNonNullPN = [&](PN& x, const PN& y) + { + if (x.second() == nullVector && y.second() != nullVector) + { + x = y; + } + }; + + + const scalar featEdgeCos = Foam::cos(degToRad(edgeFeatureAngle)); + + + //OFstream os("allBoundary.obj"); + //Pout<< "Dumping feature edges to " << os.name() << endl; + //OFstream interOs("interZoneBoundary.obj"); + //Pout<< "Dumping inter-zone edges to " << os.name() << endl; + + // Storing the normal for points that are on inter-patch edges + vectorField patchEdgeNormal(mesh.nPoints(), nullVector); + // Storing the constraint for points that are on patch-internal feat edges + List<PN> featEdgeNormal(mesh.nPoints(), nullPN); + + // Use point-based sync + { + forAll(allEdgeToFaces, edgei) + { + const edge& e = allBoundary.edges()[edgei]; + const label mp0 = mp[e[0]]; + const label mp1 = mp[e[1]]; + + const Pair<PN>& facesInfo = allEdgeToFaces[edgei]; + + if (facesInfo[1] == nullPN) + { + // Real boundary edge. On single patch only so no need + // to put in separate point patch ... (? tbd) + } + else + { + const label zone0 = facesInfo[0].first(); + const label zone1 = facesInfo[1].first(); + + const point& p0 = allBoundary.points()[mp0]; + const point& p1 = allBoundary.points()[mp1]; + vector eVec(p1-p0); + eVec.normalise(); + + if (zone0 != zone1) + { + // Inter-patch. TBD: check for feature angle as well? + + //patchEdgeNormal[mp0] = pointNormals[e[0]]; + //patchEdgeNormal[mp1] = pointNormals[e[1]]; + + patchEdgeNormal[mp0] = eVec; + patchEdgeNormal[mp1] = eVec; + } + else + { + // Same patch - check for feature angle + + const vector& n0 = facesInfo[0].second(); + const vector& n1 = facesInfo[1].second(); + + if ((n0 & n1) < featEdgeCos) + { + //Pout<< "** feature edge:" << edgei + // << " points:" << allBoundary.points()[mp0] + // << allBoundary.points()[mp1] + // << nl + // << " faceNormal0:" << n0 + // << " faceNormal1:" << n1 << nl + // << " zone0:" << zone0 + // << " zone1:" << zone1 << nl + // << " pointNormals0:" << pointNormals[e[0]] + // << " pointNormals1:" << pointNormals[e[1]] + // << nl + // << endl; + + if (patchEdgeNormal[mp0] == nullVector) + { + //featEdgeNormal[mp0] = PN + //( + // zone0, // zone + // pointNormals[e[0]] + //); + featEdgeNormal[mp0].first() = zone0; + // Assign edge direction. TBD: average & parallel + featEdgeNormal[mp0].second() = eVec; + } + if (patchEdgeNormal[mp1] == nullVector) + { + //featEdgeNormal[mp1] = PN + //( + // zone1, // zone + // pointNormals[e[1]] + //); + featEdgeNormal[mp1].first() = zone1; + // Assign edge direction. TBD: average & parallel + featEdgeNormal[mp1].second() = eVec; + } + } + } + } + } + + syncTools::syncPointList + ( + mesh, + patchEdgeNormal, + assignNonNull, + nullVector + ); + syncTools::syncPointList + ( + mesh, + featEdgeNormal, + assignNonNullPN, + nullPN, + dummyTransform() + ); + } + + // Make sure that inter-patch points are not also in feature-edge + // points. Note: not absolutely necessary since all inter-patch points + // will also be in the 'normal' facePointPatches. + + DynamicList<label> dynMultiZoneMeshPoints(allBoundary.nPoints()); + DynamicList<pointConstraint> dynMultiZoneConstraints(allBoundary.nPoints()); + forAll(pointToZones, pointi) + { + if (pointToZones[pointi] == labelPair(-2, -2)) + { + dynMultiZoneMeshPoints.append(pointi); + // Note: pointConstraint just a slip constraint for now + dynMultiZoneConstraints.append + ( + pointConstraint + ( + 3, // feature point + Zero //meshPointNormals[pointi] + ) + ); + // Unmark as feature angle point + patchEdgeNormal[pointi] = nullVector; + featEdgeNormal[pointi] = nullPN; + } + } + multiZoneMeshPoints = std::move(dynMultiZoneMeshPoints); + multiZoneConstraints = std::move(dynMultiZoneConstraints); + + + DynamicList<label> dynTwoZoneMeshPoints(allBoundary.nPoints()); + DynamicList<pointConstraint> dynTwoZoneConstraints(allBoundary.nPoints()); + forAll(patchEdgeNormal, pointi) + { + if (patchEdgeNormal[pointi] != nullVector) + { + dynTwoZoneMeshPoints.append(pointi); + // Note: pointConstraint just a slip constraint for now + dynTwoZoneConstraints.append + ( + pointConstraint + ( + 2, // feature edge + patchEdgeNormal[pointi] + ) + ); + + // Unmark as feature angle point + featEdgeNormal[pointi] = nullPN; + } + } + twoZoneMeshPoints = std::move(dynTwoZoneMeshPoints); + twoZoneConstraints = std::move(dynTwoZoneConstraints); + + + // Sort featEdgeNormal according to zone + zoneToMeshPoints.resize_nocopy(nZones); + zoneToConstraints.resize_nocopy(nZones); + { + labelList sizes(nZones, 0); + forAll(featEdgeNormal, pointi) + { + const auto& pInfo = featEdgeNormal[pointi]; + if (pInfo != nullPN) + { + const label zonei = pInfo.first(); + sizes[zonei]++; + } + } + forAll(zoneToMeshPoints, zonei) + { + zoneToMeshPoints[zonei].setSize(sizes[zonei]); + zoneToConstraints[zonei].setSize(sizes[zonei]); + } + sizes = 0; + forAll(featEdgeNormal, pointi) + { + const auto& pInfo = featEdgeNormal[pointi]; + if (pInfo != nullPN) + { + const label zonei = pInfo.first(); + const label index = sizes[zonei]++; + + zoneToMeshPoints[zonei][index] = pointi; + zoneToConstraints[zonei][index] = + pointConstraint(2, pInfo.second()); // constrained to slide + } + } + } +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointMeshTools/pointMeshTools.H b/src/OpenFOAM/meshes/pointMesh/pointMeshTools/pointMeshTools.H new file mode 100644 index 0000000000000000000000000000000000000000..cb5d87dc8a551588333eff49120c8084f08c1345 --- /dev/null +++ b/src/OpenFOAM/meshes/pointMesh/pointMeshTools/pointMeshTools.H @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::polyMeshTools + +Description + Collection of static functions operating on pointMesh. + +SourceFiles + pointMeshTools.C + +\*---------------------------------------------------------------------------*/ + +#ifndef Foam_pointMeshTools_H +#define Foam_pointMeshTools_H + +#include "pointMesh.H" +#include "pointConstraint.H" +#include "uindirectPrimitivePatch.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class pointMeshTools Declaration +\*---------------------------------------------------------------------------*/ + +class pointMeshTools +{ +public: + + //- Analyse patch for feature edges, feature points. Handles points + //- not being on a face of patch but coupled to it. + static void featurePointsEdges + ( + const polyMesh& mesh, + + const uindirectPrimitivePatch& boundary, + // Per boundary face to zone + const labelUList& faceToZone, + // Number of zones + const label nZones, + + const scalar edgeFeatureAngle, + //const scalar pointFeatureAngle, //not yet done + + // Feature edge(points) internal to a zone + labelListList& zoneToMeshPoints, + List<pointConstraintList>& zoneToConstraints, + + // Feature edge(points) in between zones + labelList& twoZoneMeshPoints, + pointConstraintList& twoZoneConstraints, + + // Feature points on > 2 zones + labelList& multiZoneMeshPoints, + pointConstraintList& multiZoneConstraints + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/basic/generic/genericPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/basic/generic/genericPointPatch.H index fe01c486bde117149f8a8b2027a437075c2dea5f..1ff942519f780afc3efd2094df683e57182a8364 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/basic/generic/genericPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/basic/generic/genericPointPatch.H @@ -72,6 +72,39 @@ public: : facePointPatch(patch, bm) {} + + //- Construct given the original patch and a map + genericPointPatch + ( + const genericPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) + : + facePointPatch(patch, bm, index, mapAddressing, reversePointMap) + {} + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<genericPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } }; diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.C index ccccd2eb51e23c8ac2b161c0977aa0e9a557d269..479c7233c7fca3f7c9b9455af4ef4dd51fd81bf1 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.C @@ -91,6 +91,20 @@ Foam::cyclicPointPatch::cyclicPointPatch {} +Foam::cyclicPointPatch::cyclicPointPatch +( + const cyclicPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + coupledFacePointPatch(patch, bm, index, mapAddressing, reversePointMap), + cyclicPolyPatch_(refCast<const cyclicPolyPatch>(patch.patch())) +{} + + // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // Foam::cyclicPointPatch::~cyclicPointPatch() diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.H index 493c0dc9d5f2b596c9688e5d6846e05a3f05e1b0..e40fd90e64b9922798cce6c67cc765859ce5ec11 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclic/cyclicPointPatch.H @@ -105,6 +105,36 @@ public: const pointBoundaryMesh& bm ); + //- Construct given the original patch and a map + cyclicPointPatch + ( + const cyclicPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<cyclicPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + //- Destructor virtual ~cyclicPointPatch(); diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclicSlip/cyclicSlipPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclicSlip/cyclicSlipPointPatch.H index 7b8d8ec754d5244d764f6c80e91e86d9af136360..d9f6be76df81ee51b026ad9bd55cde4009f11146 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclicSlip/cyclicSlipPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/cyclicSlip/cyclicSlipPointPatch.H @@ -73,6 +73,39 @@ public: cyclicPointPatch(patch, bm) {} + //- Construct given the original patch and a map + cyclicSlipPointPatch + ( + const cyclicSlipPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) + : + cyclicPointPatch(patch, bm, index, mapAddressing, reversePointMap) + {} + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<cyclicSlipPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + //- Destructor virtual ~cyclicSlipPointPatch() = default; diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/empty/emptyPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/empty/emptyPointPatch.H index 629cb53f9ac22b3c620b96c30feea11750526d92..6e4a41fe5d1e41d7fa96fdd3f172aeb9eff8f636 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/empty/emptyPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/empty/emptyPointPatch.H @@ -72,6 +72,39 @@ public: facePointPatch(patch, bm) {} + //- Construct given the original patch and a map + emptyPointPatch + ( + const emptyPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) + : + facePointPatch(patch, bm, index, mapAddressing, reversePointMap) + {} + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<emptyPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + // Member Functions diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/nonuniformTransformCyclic/nonuniformTransformCyclicPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/nonuniformTransformCyclic/nonuniformTransformCyclicPointPatch.H index 215d66170b539a755e3e84fbbd5907f97b53b235..8721152ad715a943cb3f0d3218a2380b378e27ad 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/nonuniformTransformCyclic/nonuniformTransformCyclicPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/nonuniformTransformCyclic/nonuniformTransformCyclicPointPatch.H @@ -73,6 +73,40 @@ public: cyclicPointPatch(patch, bm) {} + //- Construct given the original patch and a map + nonuniformTransformCyclicPointPatch + ( + const nonuniformTransformCyclicPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) + : + cyclicPointPatch(patch, bm, index, mapAddressing, reversePointMap) + {} + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>:: + NewFrom<nonuniformTransformCyclicPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + // Destructor diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.C index 2190e44f8407add2d9ab9402699a0b421308c183..b81fab03d566f3b6119def2d7a1fe087e7963d17 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.C @@ -117,4 +117,20 @@ Foam::processorPointPatch::processorPointPatch {} +Foam::processorPointPatch::processorPointPatch +( + const processorPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + coupledFacePointPatch(patch, bm, index, mapAddressing, reversePointMap), + procPolyPatch_(refCast<const processorPolyPatch>(patch.patch())) +{ + //? map reverseMeshPoints_ or leave demand-driven +} + + // ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.H index df6a488b417bd9645b22800978697affab758cbc..2c59c5c9f357112ae07c81f909a183edcfeb2506 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processor/processorPointPatch.H @@ -111,6 +111,36 @@ public: const pointBoundaryMesh& bm ); + //- Construct given the original patch and a map + processorPointPatch + ( + const processorPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<processorPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + //- Destructor virtual ~processorPointPatch() = default; diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.C index c195173f03926c5450aeef9e2873a5dd60f74226..0b933a27575c47bb3e585361d4b0c17b99bffe33 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.C @@ -59,6 +59,20 @@ processorCyclicPointPatch::processorCyclicPointPatch {} +Foam::processorCyclicPointPatch::processorCyclicPointPatch +( + const processorCyclicPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + processorPointPatch(patch, bm, index, mapAddressing, reversePointMap), + procCycPolyPatch_(refCast<const processorCyclicPolyPatch>(patch.patch())) +{} + + // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // processorCyclicPointPatch::~processorCyclicPointPatch() diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.H index c24d0324544db53466717ce7562b909d6b5d49bf..1132df269ef4f6c02b401a749486181ada3f97d5 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/processorCyclic/processorCyclicPointPatch.H @@ -89,6 +89,36 @@ public: const pointBoundaryMesh& bm ); + //- Construct given the original patch and a map + processorCyclicPointPatch + ( + const processorCyclicPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<processorCyclicPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + //- Destructor virtual ~processorCyclicPointPatch(); diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetry/symmetryPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetry/symmetryPointPatch.H index d1dccb9125e6b8364d1e0d25e4e2f373e17fc956..6061b2aa8265c598b0b6d4b22f17e49288109642 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetry/symmetryPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetry/symmetryPointPatch.H @@ -75,6 +75,38 @@ public: facePointPatch(patch, bm) {} + //- Construct given the original patch and a map + symmetryPointPatch + ( + const symmetryPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ): + facePointPatch(patch, bm, index, mapAddressing, reversePointMap) + {} + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<symmetryPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + // Member Functions diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.C index 57e66e7cc467fb3fae03d7eb2278c1b11efef341..52bfbfe9f010aeff616e339789e7d4b197f9fb34 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.C @@ -58,6 +58,23 @@ Foam::symmetryPlanePointPatch::symmetryPlanePointPatch {} +Foam::symmetryPlanePointPatch::symmetryPlanePointPatch +( + const symmetryPlanePointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + facePointPatch(patch, bm, index, mapAddressing, reversePointMap), + symmetryPlanePolyPatch_ + ( + refCast<const symmetryPlanePolyPatch>(patch.patch()) + ) +{} + + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // void Foam::symmetryPlanePointPatch::applyConstraint diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.H index cbca7e1f3c86f2ed92bac7587e98b5ab55f34063..869a8725709bf5d9761e859063bf63ed873c75ba 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/symmetryPlane/symmetryPlanePointPatch.H @@ -74,6 +74,36 @@ public: const pointBoundaryMesh& bm ); + //- Construct given the original patch and a map + symmetryPlanePointPatch + ( + const symmetryPlanePointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<symmetryPlanePointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + // Member Functions diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.C index 13989369045ffb8034e3f5f2c6c74800a9ab2921..84b1181045b43884361a44faa5853fdf7b2f1bf6 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.C @@ -58,6 +58,20 @@ Foam::wedgePointPatch::wedgePointPatch {} +Foam::wedgePointPatch::wedgePointPatch +( + const wedgePointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + facePointPatch(patch, bm, index, mapAddressing, reversePointMap), + wedgePolyPatch_(refCast<const wedgePolyPatch>(patch.patch())) +{} + + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // void Foam::wedgePointPatch::applyConstraint diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.H index e0100939cd68d5db63019cc5845c8ae0c0253e8e..a21513d04f8d23b1d294ae8153c2d9d8be9c5874 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/constraint/wedge/wedgePointPatch.H @@ -74,6 +74,36 @@ public: const pointBoundaryMesh& bm ); + //- Construct given the original patch and a map + wedgePointPatch + ( + const wedgePointPatch& pp, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<wedgePointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + // Member Functions diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.C index 40ab33cdd97714dfa3fc48b28da589a2918f9a6e..0dcb653a0523663cd7f7d61a5971f79cf4d0ca67 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.C @@ -50,4 +50,19 @@ Foam::coupledFacePointPatch::coupledFacePointPatch {} +Foam::coupledFacePointPatch::coupledFacePointPatch +( + const coupledFacePointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + facePointPatch(patch, bm, index, mapAddressing, reversePointMap), + coupledPointPatch(bm), + coupledPolyPatch_(refCast<const coupledPolyPatch>(patch.patch())) +{} + + // ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.H index e3701771b458f868aaf1f2507bd04057b4205ea1..34724847dd21927a9d9dfd4b4f21913a3b77eeb8 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/coupled/coupledFacePointPatch.H @@ -91,6 +91,16 @@ public: const pointBoundaryMesh& bm ); + //- Construct given the original patch and a map + coupledFacePointPatch + ( + const coupledFacePointPatch& pp, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + //- Destructor virtual ~coupledFacePointPatch() = default; diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/wall/wallPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/wall/wallPointPatch.H index a69065029fa195e4f1ebb7110cdc3545f62ed68a..bc7b4c0fd0145ee97e8bf472d0fad3d6771af00a 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/wall/wallPointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/derived/wall/wallPointPatch.H @@ -71,6 +71,39 @@ public: : facePointPatch(patch, bm) {} + + //- Construct given the original patch and a map + wallPointPatch + ( + const wallPointPatch& patch, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) + : + facePointPatch(patch, bm, index, mapAddressing, reversePointMap) + {} + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<wallPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } }; diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.C index 1025a998fc9f1c1a190201313c728fde364f9191..594061a96f86db8e35047afbb09e93920837fa85 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.C @@ -84,9 +84,30 @@ Foam::facePointPatch::facePointPatch const pointBoundaryMesh& bm ) : - pointPatch(bm), + pointPatch(p.name(), p.index(), bm, p.physicalType(), p.inGroups()), polyPatch_(p) {} +Foam::facePointPatch::facePointPatch +( + const facePointPatch& pp, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + pointPatch + ( + pp.name(), + index, + bm, + pp.physicalType(), + pp.inGroups() + ), + polyPatch_(pp.patch()) +{} + + // ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.H index efb6c4789956a1af827230db19a9487f4351a1f7..a988d533116e8c38d9ac482fd613296240ed810c 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/facePointPatch/facePointPatch.H @@ -128,6 +128,36 @@ public: const pointBoundaryMesh& pm ); + //- Construct given the original patch and a map + facePointPatch + ( + const facePointPatch& pp, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<facePointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + // Selectors diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/meshPointPatch/meshPointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/meshPointPatch/meshPointPatch.C new file mode 100644 index 0000000000000000000000000000000000000000..2e9c845c75cd2eacec46fd6aa351bed7b4938b4f --- /dev/null +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/meshPointPatch/meshPointPatch.C @@ -0,0 +1,235 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2016 OpenFOAM Foundation + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "meshPointPatch.H" +#include "addToRunTimeSelectionTable.H" +#include "pointMesh.H" +#include "pointConstraint.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +defineTypeNameAndDebug(meshPointPatch, 0); + +//- Needs run-time selection table on pointPatch, not facePointPatch +addToRunTimeSelectionTable +( + pointPatch, + meshPointPatch, + dictionary +); + +static List<pointConstraint> makeConstraints(const vectorField& normals) +{ + List<pointConstraint> cs(normals.size()); + + forAll(cs, i) + { + cs[i].applyConstraint(normals[i]); + } + return cs; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::meshPointPatch::meshPointPatch +( + const word& name, + const labelUList& meshPoints, + const List<pointConstraint>& constraints, + const label index, + const pointBoundaryMesh& bm, + const word& patchType +) +: + pointPatch(name, index, bm, word::null, wordList()), + meshPoints_(meshPoints), + constraints_(constraints) +{ + if (meshPoints_.size() != constraints_.size()) + { + FatalErrorInFunction << "patch " << name + << " size of meshPoints " << meshPoints_.size() + << " differs from size of constraints " << constraints_.size() + << exit(FatalError); + } +} + + +Foam::meshPointPatch::meshPointPatch +( + const word& name, + const labelUList& meshPoints, + const vectorField& pointNormals, + const label index, + const pointBoundaryMesh& bm, + const word& patchType +) +: + pointPatch(name, index, bm, word::null, wordList()), + meshPoints_(meshPoints), + constraints_(makeConstraints(pointNormals)) +{ + if (meshPoints_.size() != pointNormals.size()) + { + FatalErrorInFunction << "patch " << name + << " size of meshPoints " << meshPoints_.size() + << " differs from size of pointNormals " << pointNormals.size() + << exit(FatalError); + } +} + + +Foam::meshPointPatch::meshPointPatch +( + const word& name, + const dictionary& dict, + const label index, + const pointBoundaryMesh& bm, + const word& patchType +) +: + pointPatch(name, dict, index, bm), + meshPoints_(dict.get<labelList>("meshPoints")), + constraints_(dict.get<List<pointConstraint>>("constraints")) +{} + + +Foam::meshPointPatch::meshPointPatch +( + const meshPointPatch& pp, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap +) +: + meshPointPatch + ( + pp.name(), + labelList(reversePointMap, labelList(pp.meshPoints(), mapAddressing)), + List<pointConstraint>(pp.constraints(), mapAddressing), + index, + bm, + pp.type() + ) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::meshPointPatch::movePoints(PstreamBuffers&, const pointField& p) +{ + localPointsPtr_.reset(nullptr); + + // Recalculate the point normals? Something like + //if (owner()) + //{ + // const SubList<face> subFaces + // ( + // mesh.faces(), + // mesh.nBoundaryFaces(), + // mesh.nInternalFaces() + // ); + // const primitivePatch pp(subFaces, mesh.points()); + // + // + // for (const label pointi : meshPoints()) + // { + // const auto fnd(pp.meshPointMap().find(pointi)); + // if (fnd) + // { + // const label patchPointi = fnd(); + // // Determine point patch equiv + // + // const auto& point + // + // + +} + + +void Foam::meshPointPatch::updateMesh(PstreamBuffers&) +{ + localPointsPtr_.reset(nullptr); + pointNormalsPtr_.reset(nullptr); + // Do what to constraints_? Don't know what the new mesh points are +} + + +const Foam::pointField& Foam::meshPointPatch::localPoints() const +{ + if (!localPointsPtr_) + { + localPointsPtr_.reset + ( + new pointField + ( + boundaryMesh().mesh().mesh().points(), + meshPoints() + ) + ); + } + return localPointsPtr_(); +} + + +const Foam::vectorField& Foam::meshPointPatch::pointNormals() const +{ + if (!pointNormalsPtr_) + { + pointNormalsPtr_.reset(new vectorField(size())); + vectorField& pointNormals = pointNormalsPtr_(); + forAll(constraints_, i) + { + pointNormals[i] = constraints_[i].second(); + } + } + return pointNormalsPtr_(); +} + + +void Foam::meshPointPatch::write(Ostream& os) const +{ + pointPatch::write(os); + meshPoints().writeEntry("meshPoints", os); + constraints().writeEntry("constraints", os); +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/meshPointPatch/meshPointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/meshPointPatch/meshPointPatch.H new file mode 100644 index 0000000000000000000000000000000000000000..54853d74386ac03f0c404ac8122d87f33c4a404d --- /dev/null +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/meshPointPatch/meshPointPatch.H @@ -0,0 +1,213 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2016 OpenFOAM Foundation + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::meshPointPatch + +Description + pointPatch with explicitly provided points instead of using the points + of a polyPatch. + + Note: does not constrain displacement - is not a constraint patch. + +SourceFiles + meshPointPatch.C + +\*---------------------------------------------------------------------------*/ + +#ifndef meshPointPatch_H +#define meshPointPatch_H + +#include "pointPatch.H" +#include "polyPatch.H" +#include "autoPtr.H" +#include "patchIdentifier.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class meshPointPatch Declaration +\*---------------------------------------------------------------------------*/ + +class meshPointPatch +: + public pointPatch +{ +private: + + // Private Member Functions + + //- No copy construct + meshPointPatch(const meshPointPatch&) = delete; + + //- No copy assignment + void operator=(const meshPointPatch&) = delete; + + +protected: + + // Protected Member Data + + //- Explicit mesh points + const labelList meshPoints_; + + const List<pointConstraint> constraints_; + + //- Demand-driven local points + mutable autoPtr<pointField> localPointsPtr_; + + //- Demand-driven local normals (assumes constructed with pointNormals + // or normal-only-constraint) + mutable autoPtr<pointField> pointNormalsPtr_; + + + // Protected Member Functions + + //- Correct patches after moving points + virtual void movePoints(PstreamBuffers&, const pointField&); + + //- Update of the patch topology + virtual void updateMesh(PstreamBuffers&); + + +public: + + //- Runtime type information + TypeName("meshPoint"); + + + // Constructors + + //- Construct from components + meshPointPatch + ( + const word& name, + const labelUList& meshPoints, + const List<pointConstraint>& constraints, + const label index, + const pointBoundaryMesh& bm, + const word& patchType + ); + + //- Construct from single-constraint (i.e. slip, provided normals) + meshPointPatch + ( + const word& name, + const labelUList& meshPoints, + const vectorField& pointNormals, + const label index, + const pointBoundaryMesh& bm, + const word& patchType + ); + + //- Construct from dictionary + meshPointPatch + ( + const word& name, + const dictionary& dict, + const label index, + const pointBoundaryMesh& bm, + const word& patchType + ); + + //- Construct given the original patch and a map + meshPointPatch + ( + const meshPointPatch& pp, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ); + + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const + { + return autoPtr<pointPatch>::NewFrom<meshPointPatch> + ( + *this, + bm, + index, + mapAddressing, + reversePointMap + ); + } + + + //- Destructor + virtual ~meshPointPatch() = default; + + + // Member Functions + + //- Return size + virtual label size() const + { + return meshPoints().size(); + } + + //- Return mesh points + virtual const labelList& meshPoints() const + { + return meshPoints_; + } + + //- Return constraints + virtual const List<pointConstraint>& constraints() const + { + return constraints_; + } + + //- Return pointField of points in patch + virtual const pointField& localPoints() const; + + //- Return point unit normals. Assumes single constraint + virtual const vectorField& pointNormals() const; + + //- Write the pointPatch data as a dictionary + virtual void write(Ostream&) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.C index 39bc76279354e5754132d3baace7e19f6d87899a..9e462b02ffb2d7ecf785b81957a2a952b498a391 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.C +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.C @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2012 OpenFOAM Foundation + Copyright (C) 2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -31,7 +32,33 @@ License namespace Foam { -defineTypeNameAndDebug(pointPatch, 0); + defineTypeNameAndDebug(pointPatch, 0); + +// int pointPatch::disallowGenericPointPatch +// ( +// debug::debugSwitch("disallowGenericPointPatch", 0) +// ); + + defineRunTimeSelectionTable(pointPatch, dictionary); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::pointPatch::write(Ostream& os) const +{ + os.writeKeyword("type") << type() << token::END_STATEMENT << nl; + patchIdentifier::write(os); +} + + +// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // + +Foam::Ostream& Foam::operator<<(Ostream& os, const pointPatch& p) +{ + p.write(os); + os.check("Ostream& operator<<(Ostream& os, const pointPatch& p"); + return os; } diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.H b/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.H index 22b6e1943836eec073d64710ea03231bcee92a78..6af214b3192ee84b4e2d4bfccb03a461641f79c4 100644 --- a/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.H +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatch.H @@ -38,6 +38,7 @@ SourceFiles #ifndef Foam_pointPatch_H #define Foam_pointPatch_H +#include "patchIdentifier.H" #include "labelList.H" #include "vectorField.H" #include "pointField.H" @@ -54,6 +55,8 @@ class pointConstraint; class pointPatch; class PstreamBuffers; +Ostream& operator<<(Ostream&, const pointPatch&); + //- Store lists of pointPatch as a PtrList typedef PtrList<pointPatch> pointPatchList; @@ -62,6 +65,8 @@ typedef PtrList<pointPatch> pointPatchList; \*---------------------------------------------------------------------------*/ class pointPatch +: + public patchIdentifier { // Private Data @@ -114,14 +119,90 @@ public: TypeName("basePatch"); + // Declare run-time constructor selection tables + + declareRunTimeSelectionTable + ( + autoPtr, + pointPatch, + dictionary, + ( + const word& name, + const dictionary& dict, + const label index, + const pointBoundaryMesh& bm, + const word& patchType + ), + (name, dict, index, bm, patchType) + ); + + // Constructor - //- Construct from boundary mesh - explicit pointPatch(const pointBoundaryMesh& bm) + //- Construct from components + explicit pointPatch + ( + const word& name, + const label index, + const pointBoundaryMesh& bm, + const word& physicalType, + const wordList& inGroups + ) + : + patchIdentifier(name, index, physicalType, inGroups), + boundaryMesh_(bm) + {} + + //- Construct from dictionary + explicit pointPatch + ( + const word& name, + const dictionary& dict, + const label index, + const pointBoundaryMesh& bm + ) + : + patchIdentifier(name, dict, index), + boundaryMesh_(bm) + {} + + //- Construct given the original patch and a map + explicit pointPatch + ( + const pointPatch& pp, + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) : + patchIdentifier(pp.name(), index, pp.physicalType(), pp.inGroups()), boundaryMesh_(bm) {} + //- Construct and return a subset clone, + //- resetting the point list and boundary mesh + virtual autoPtr<pointPatch> clone + ( + const pointBoundaryMesh& bm, + const label index, + const labelUList& mapAddressing, + const labelUList& reversePointMap + ) const = 0; + + + // Selectors + + //- Return a pointer to a new patch created on freestore. Returns + //- null if not found + static autoPtr<pointPatch> New + ( + const word& name, + const dictionary& dict, + const label index, + const pointBoundaryMesh& + ); + //- Destructor virtual ~pointPatch() = default; @@ -129,15 +210,9 @@ public: // Member Functions - //- Return name - virtual const word& name() const = 0; - //- Return size virtual label size() const = 0; - //- Return the index of this patch in the pointBoundaryMesh - virtual label index() const = 0; - //- Return boundaryMesh reference const pointBoundaryMesh& boundaryMesh() const { @@ -172,6 +247,14 @@ public: pointConstraint& ) const {} + + //- Write the pointPatch data as a dictionary + virtual void write(Ostream&) const; + + + // Ostream Operator + + friend Ostream& operator<<(Ostream&, const pointPatch&); }; diff --git a/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatchNew.C b/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatchNew.C new file mode 100644 index 0000000000000000000000000000000000000000..ce57b873a01618de10b75cdaecb96a7b420cac6e --- /dev/null +++ b/src/OpenFOAM/meshes/pointMesh/pointPatches/pointPatch/pointPatchNew.C @@ -0,0 +1,56 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2016 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "pointPatch.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::pointPatch> Foam::pointPatch::New +( + const word& name, + const dictionary& dict, + const label index, + const pointBoundaryMesh& bm +) +{ + // Similar to polyPatchNew but no support for generic since we want it + // to fall through to the construct-from-polyPatch + DebugInFunction << "Constructing pointPatch" << endl; + + const word patchType(dict.lookup("type")); + //dict.readIfPresent("geometricType", patchType); + + auto* ctorPtr = dictionaryConstructorTable(patchType); + + if (!ctorPtr) + { + return nullptr; + } + + return autoPtr<pointPatch>(ctorPtr(name, dict, index, bm, patchType)); +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C index 3ece63c5e75cc346059f056108ce55dd8514e397..c3e9cd5d6a0c956346be431c386d89f184a2d649 100644 --- a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C +++ b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C @@ -1418,6 +1418,9 @@ void Foam::polyBoundaryMesh::reorder patches[patchi].index() = patchi; } + // Clear group-to-patch addressing. Note: could re-calculate + groupIDsPtr_.reset(nullptr); + if (validBoundary) { updateMesh(); diff --git a/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/symmetryPlane/symmetryPlanePolyPatch.C b/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/symmetryPlane/symmetryPlanePolyPatch.C index b71af44be2f36941f2bd0782699728c53cac8624..eda279c964807930fb2ffd58ac73d769a7e220f4 100644 --- a/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/symmetryPlane/symmetryPlanePolyPatch.C +++ b/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/symmetryPlane/symmetryPlanePolyPatch.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2013-2015 OpenFOAM Foundation - Copyright (C) 2022 OpenCFD Ltd. + Copyright (C) 2022,2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -49,8 +49,12 @@ void Foam::symmetryPlanePolyPatch::calcGeometry(PstreamBuffers&) { if (returnReduceOr(size())) { - const vectorField& nf = faceNormals(); - n_ = gAverage(nf); + // Instead of using the average unit-normal use an area weighted + // average instead. This avoids problem when adding zero-sized + // faces since these have a calculated area vector of (0 0 0) + const auto& areas = faceAreas(); + + n_ = gSum(areas).normalise(ROOTVSMALL); if (debug) { @@ -60,22 +64,30 @@ void Foam::symmetryPlanePolyPatch::calcGeometry(PstreamBuffers&) // Check the symmetry plane is planar - forAll(nf, facei) + forAll(areas, facei) { - if (magSqr(n_ - nf[facei]) > SMALL) + const scalar a = mag(areas[facei]); + + // Calculate only if non-zero area + if (a > ROOTVSMALL) { - FatalErrorInFunction - << "Symmetry plane '" << name() << "' is not planar." - << endl - << "At local face at " - << primitivePatch::faceCentres()[facei] - << " the normal " << nf[facei] - << " differs from the average normal " << n_ - << " by " << magSqr(n_ - nf[facei]) << endl - << "Either split the patch into planar parts" - << " or use the " << symmetryPolyPatch::typeName - << " patch type" - << exit(FatalError); + const vector nf(areas[facei]/a); + + if (magSqr(n_ - nf) > SMALL) + { + FatalErrorInFunction + << "Symmetry plane '" << name() + << "' is not planar." << endl + << "At local face at " + << primitivePatch::faceCentres()[facei] + << " the normal " << nf + << " differs from the average normal " << n_ + << " by " << magSqr(n_ - nf) << endl + << "Either split the patch into planar parts" + << " or use the " << symmetryPolyPatch::typeName + << " patch type" + << exit(FatalError); + } } } } diff --git a/src/dynamicMesh/Make/files b/src/dynamicMesh/Make/files index 4f5379232b79b394000d0ea90544989d017da3f6..54b5f28d80b3dc9ee8583b690c0351fce9265d0c 100644 --- a/src/dynamicMesh/Make/files +++ b/src/dynamicMesh/Make/files @@ -101,6 +101,7 @@ motionSolvers/displacement/displacement/displacementMotionSolver.C motionSolvers/displacement/interpolation/displacementInterpolationMotionSolver.C motionSolvers/displacement/layeredSolver/displacementLayeredMotionMotionSolver.C motionSolvers/displacement/layeredSolver/pointEdgeStructuredWalk.C +motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.C motionSolvers/componentDisplacement/componentDisplacementMotionSolver.C motionSolvers/velocity/velocityMotionSolver.C motionSolvers/velocity/velocityDisplacement/velocityDisplacementMotionSolver.C @@ -111,6 +112,23 @@ motionSolvers/displacement/codedPoints0/codedPoints0MotionSolver.C motionSolvers/displacement/solidBody/pointPatchFields/derived/solidBodyMotionDisplacement/solidBodyMotionDisplacementPointPatchVectorField.C +pointSmoothing = motionSolvers/displacement/pointSmoothing +$(pointSmoothing)/displacementPointSmoothingMotionSolver.C +/* +$(pointSmoothing)/displacementPointSmoothingMotionSolver2.C +$(pointSmoothing)/displacementPointSmoothingMotionSolver3.C +*/ +$(pointSmoothing)/hexMeshSmootherMotionSolver.C +$(pointSmoothing)/displacementSmartPointSmoothingMotionSolver.C + +pointSmoothers = $(pointSmoothing)/pointSmoothers +$(pointSmoothers)/pointSmoother/pointSmoother.C +$(pointSmoothers)/equipotentialPointSmoother/equipotentialPointSmoother.C +$(pointSmoothers)/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.C +$(pointSmoothers)/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.C +$(pointSmoothers)/laplacianPointSmoother/laplacianPointSmoother.C +$(pointSmoothers)/laplacianPointSmoother/laplacianConstraintPointSmoother.C + createShellMesh/createShellMesh.C extrudePatchMesh/extrudePatchMesh.C diff --git a/src/dynamicMesh/motionSolvers/displacement/displacement/displacementMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/displacement/displacementMotionSolver.C index 00fa9ae49daee2e2d9cd94da2bd7f94f8591ddec..9f8c33aa55eadf29904355995ecc18a53ea889c5 100644 --- a/src/dynamicMesh/motionSolvers/displacement/displacement/displacementMotionSolver.C +++ b/src/dynamicMesh/motionSolvers/displacement/displacement/displacementMotionSolver.C @@ -57,7 +57,7 @@ Foam::displacementMotionSolver::displacementMotionSolver IOobject::MUST_READ, IOobject::AUTO_WRITE ), - pointMesh::New(mesh) + pointMesh::New(mesh, Foam::IOobject::READ_IF_PRESENT) ) {} diff --git a/src/dynamicMesh/motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.C new file mode 100644 index 0000000000000000000000000000000000000000..cca0664ac9bd0e4733bcfc053c3bbe1b709b7651 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.C @@ -0,0 +1,271 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*----------------------------------------------------------------------------*/ + +#include "multiDisplacementMotionSolver.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(multiDisplacementMotionSolver, 0); + + addToRunTimeSelectionTable + ( + motionSolver, + multiDisplacementMotionSolver, + dictionary + ); + + addToRunTimeSelectionTable + ( + displacementMotionSolver, + multiDisplacementMotionSolver, + displacement + ); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::multiDisplacementMotionSolver::multiDisplacementMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict +) +: + displacementMotionSolver(mesh, dict, typeName), + curPoints_(mesh.points()) +{ + // Make pointDisplacement is not registered since all lower levels + // have a pointDisplacement as well. + pointDisplacement().checkOut(); + + label i = 0; + + const dictionary& solverDict = dict.subDict("solvers"); + + motionSolvers_.setSize(solverDict.size()); + + for (const entry& dEntry : solverDict) + { + if (dEntry.isDict()) + { + IOobject io(dict); + io.readOpt(IOobject::NO_READ); + io.writeOpt(IOobject::AUTO_WRITE); + io.rename(dEntry.dict().dictName()); + + IOdictionary IOsolverDict + ( + io, + dEntry.dict() + ); + + auto* msPtr = motionSolver::New(mesh, IOsolverDict).ptr(); + + motionSolvers_.set + ( + i, + dynamic_cast<displacementMotionSolver*>(msPtr) + ); + + // Avoid conflicts with multiple registrations + motionSolvers_[i].pointDisplacement().checkOut(); + + i++; + } + } + motionSolvers_.setSize(i); + + if (i == 0) + { + FatalErrorInFunction << "No displacementMotionSolvers in dictionary " + << dict << exit(FatalError); + } + + // Re-register so only our 'pointDisplacement' is on the database. + pointDisplacement().checkIn(); +} + + +Foam::multiDisplacementMotionSolver:: +multiDisplacementMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 +) +: + displacementMotionSolver(mesh, dict, pointDisplacement, points0, typeName), + curPoints_(mesh.points()) +{ + // Make pointDisplacement is not registered since all lower levels + // have a pointDisplacement as well. + this->pointDisplacement().checkOut(); + + label i = 0; + + const dictionary& solverDict = dict.subDict("solvers"); + + motionSolvers_.setSize(solverDict.size()); + + for (const entry& dEntry : solverDict) + { + if (dEntry.isDict()) + { + IOobject io(dict); + io.readOpt(IOobject::NO_READ); + io.writeOpt(IOobject::AUTO_WRITE); + io.rename(dEntry.dict().dictName()); + + IOdictionary IOsolverDict + ( + io, + dEntry.dict() + ); + + auto msPtr = displacementMotionSolver::New + ( + dEntry.keyword(), + mesh, + IOsolverDict, + pointDisplacement, + points0 + ); + + // Avoid conflicts with multiple registrations + msPtr->pointDisplacement().checkOut(); + + motionSolvers_.set(i++, msPtr); + } + } + motionSolvers_.setSize(i); + + if (i == 0) + { + FatalErrorInFunction << "No displacementMotionSolvers in dictionary " + << dict << exit(FatalError); + } + + // Re-register so only our 'pointDisplacement' is on the database. + this->pointDisplacement().checkIn(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::tmp<Foam::pointField> +Foam::multiDisplacementMotionSolver::curPoints() const +{ + return curPoints_; +} + + +void Foam::multiDisplacementMotionSolver::solve() +{ + if (!motionSolvers_.size()) + { + return; + } + + // Bit tricky: + // - make sure only one copy of pointDisplacement is registered. This is + // for if cellDisplacement tries to look up the pointDisplacement it + // looks up its version. Or maybe we always should use our own version + // only? + // - copy the last set of calculated points into our copy (curPoints_) + // - move the mesh to update the faceCentres, cellCentres etc. This assumes + // that we can call movePoints() multiple times inside a time step. + // (note that this is supported in pimpleFoam with the + // moveMeshOuterCorrectors option) + + pointDisplacement().checkOut(); + + // Doing first motion solver + motionSolvers_[0].pointDisplacement().checkIn(); + // Take over my bc values + motionSolvers_[0].pointDisplacement() == pointDisplacement(); + + motionSolvers_[0].solve(); + motionSolvers_[0].pointDisplacement().checkOut(); + + // Update my values + curPoints_ = motionSolvers_[0].curPoints(); + pointDisplacement() == motionSolvers_[0].pointDisplacement(); + + for (label i = 1; i < motionSolvers_.size(); i++) + { + // Doing other motion solvers using new locations/face/cellCentres etc. + const_cast<polyMesh&>(mesh()).movePoints(curPoints_); + motionSolvers_[i].pointDisplacement().checkIn(); + + // Take over my bc values + motionSolvers_[i].pointDisplacement() == pointDisplacement(); + + motionSolvers_[i].solve(); + motionSolvers_[i].pointDisplacement().checkOut(); + + // Update my values + curPoints_ = motionSolvers_[i].curPoints(); + pointDisplacement() == motionSolvers_[i].pointDisplacement(); + } + + pointDisplacement().checkIn(); + + // Push my pointDisplacement onto all motionSolvers + for (auto& ms : motionSolvers_) + { + ms.pointDisplacement() == pointDisplacement(); + } +} + + +void Foam::multiDisplacementMotionSolver::movePoints +( + const pointField& newPoints +) +{ + curPoints_ = newPoints; + for (auto& ms : motionSolvers_) + { + ms.movePoints(newPoints); + } +} + + +void Foam::multiDisplacementMotionSolver::updateMesh(const mapPolyMesh& mpm) +{ + for (auto& ms : motionSolvers_) + { + ms.updateMesh(mpm); + } +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.H b/src/dynamicMesh/motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.H new file mode 100644 index 0000000000000000000000000000000000000000..291ab6265fb186b8b245b1a528b8007fd2440ae1 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/multiDisplacement/multiDisplacementMotionSolver.H @@ -0,0 +1,170 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::multiDisplacementMotionSolver + +Group + grpMeshMotionSolvers + +Description + Mesh motion solver for a polyMesh. Applies multiple (displacement) motion + solvers in order. + + Not very efficient : all displacementMotionSolvers store a copy + of the initial points (points0) and the displacement (pointDisplacement + or also cellDisplacement). + Used to combine large-scale, implicit displacement smoothing (e.g. + displacementLaplacian) with point smoothing. + +Usage + Example of the dynamicMeshDict specification: + \verbatim + motionSolver multiDisplacement; + solvers + { + // Solve finite volume laplacian to efficiently smooth displacement + // (not point locations) + displacementLaplacian + { + motionSolver displacementLaplacian; + diffusivity uniform; + } + + // Apply few iterations of smoothing of point locations + displacementPointSmoothing + { + motionSolver displacementPointSmoothing; + pointSmoother laplacian; + nPointSmootherIter 10; + } + } + \endverbatim + +Note + When using displacementLaplacian: the default behaviour for the + cellDisplacement is to apply fixed value boundary conditions (by averaging + point values) only to those pointDisplacement boundary conditions that + are fixed value. Quite a few point boundary conditions (e.g. surfaceSlip, + edgeSlip) are not so require an explicitly provided cellDisplacement + field with 'cellMotion' boundary conditions for those patches. + +SourceFiles + isplacementMultiMotionSolver.C +\*----------------------------------------------------------------------------*/ + +#ifndef Foam_multiDisplacementMotionSolver_H +#define Foam_multiDisplacementMotionSolver_H + +#include "displacementMotionSolver.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class multiDisplacementMotionSolver Declaration +\*---------------------------------------------------------------------------*/ + +class multiDisplacementMotionSolver +: + public displacementMotionSolver +{ + // Private data + + //- Current points + pointField curPoints_; + + //- List of motion solvers + PtrList<displacementMotionSolver> motionSolvers_; + + + // Private Member Functions + + //- No copy construct + multiDisplacementMotionSolver + ( + const multiDisplacementMotionSolver& + ) = delete; + + //- No copy assignment + void operator=(const multiDisplacementMotionSolver&) = delete; + + +public: + + //- Runtime type information + TypeName("multiDisplacement"); + + + // Constructors + + //- Construct from polyMesh and IOdictionary + multiDisplacementMotionSolver + ( + const polyMesh&, + const IOdictionary& + ); + + //- Construct from components + multiDisplacementMotionSolver + ( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 + ); + + + //- Destructor + ~multiDisplacementMotionSolver() = default; + + + // Member Functions + + //- Provide current points for motion + virtual tmp<pointField> curPoints() const; + + //- Solve for motion + virtual void solve(); + + //- Update local data for geometry changes + virtual void movePoints(const pointField&); + + //- Update local data for topology changes + virtual void updateMesh(const mapPolyMesh&); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.C new file mode 100644 index 0000000000000000000000000000000000000000..abb52d5cfa401c0a287cf4be75372a093ce73553 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.C @@ -0,0 +1,434 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "displacementPointSmoothingMotionSolver.H" +#include "addToRunTimeSelectionTable.H" +#include "syncTools.H" +#include "pointConstraints.H" +#include "motionSmootherAlgo.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(displacementPointSmoothingMotionSolver, 0); + + addToRunTimeSelectionTable + ( + motionSolver, + displacementPointSmoothingMotionSolver, + dictionary + ); + + addToRunTimeSelectionTable + ( + displacementMotionSolver, + displacementPointSmoothingMotionSolver, + displacement + ); +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::displacementPointSmoothingMotionSolver::markAffectedFaces +( + const labelHashSet& changedFaces, + labelHashSet& affectedFaces +) +{ + PackedBoolList affectedPoints(mesh().nPoints(), false); + + forAllConstIter(labelHashSet, changedFaces, iter) + { + const label faceI(iter.key()); + + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + affectedPoints[pointI] = true; + } + } + + syncTools::syncPointList + ( + mesh(), + affectedPoints, + orEqOp<unsigned int>(), + 0U + ); + + forAll(affectedPoints, pointI) + { + if (affectedPoints[pointI]) + { + const labelList& pCells(mesh().pointCells()[pointI]); + + forAll(pCells, pointCellI) + { + const label cellI(pCells[pointCellI]); + + const labelList& cFaces(mesh().cells()[cellI]); + + affectedFaces.insert(cFaces); + } + } + } +} + + +bool Foam::displacementPointSmoothingMotionSolver::relax() +{ + if + ( + (relaxationFactors_.size() == 0) + || (relaxationFactors_.size() == 1 && relaxationFactors_[0] == 1.0) + ) + { + relaxedPoints_ = points0() + pointDisplacement().internalField(); + return true; + } + + + const pointField oldRelaxedPoints(relaxedPoints_); + + labelHashSet affectedFaces(facesToMove_); + + // Create a list of relaxation levels + // -1 indicates a point which is not to be moved + // 0 is the starting value for a moving point + labelList relaxationLevel(mesh().nPoints(), -1); + forAllConstIter(labelHashSet, affectedFaces, iter) + { + const label faceI(iter.key()); + + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + relaxationLevel[pointI] = 0; + } + } + + syncTools::syncPointList + ( + mesh(), + relaxationLevel, + maxEqOp<label>(), + label(-1) + ); + + // Loop whilst relaxation levels are being incremented + bool complete(false); + while (!complete) + { + //scalar nAffectedFaces(affectedFaces.size()); + //reduce(nAffectedFaces, sumOp<scalar>()); + //Info << " Moving " << nAffectedFaces << " faces" << endl; + + // Move the points + forAll(relaxationLevel, pointI) + { + if (relaxationLevel[pointI] >= 0) + { + const scalar x + ( + relaxationFactors_[relaxationLevel[pointI]] + ); + + relaxedPoints_[pointI] = + (1 - x)*oldRelaxedPoints[pointI] + + x*(points0()[pointI] + pointDisplacement()[pointI]); + } + } + + // Get a list of changed faces + labelHashSet markedFaces; + markAffectedFaces(affectedFaces, markedFaces); + labelList markedFacesList(markedFaces.toc()); + + // Update the geometry + meshGeometry_.correct(relaxedPoints_, markedFacesList); + + // Check the modified face quality + markedFaces.clear(); + motionSmootherAlgo::checkMesh + ( + false, + meshQualityDict_, + meshGeometry_, + relaxedPoints_, + markedFacesList, + markedFaces + ); + + // Mark the affected faces + affectedFaces.clear(); + markAffectedFaces(markedFaces, affectedFaces); + + // Increase relaxation and check convergence + PackedBoolList pointsToRelax(mesh().nPoints(), false); + complete = true; + forAllConstIter(labelHashSet, affectedFaces, iter) + { + const label faceI(iter.key()); + + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + pointsToRelax[pointI] = true; + } + } + + forAll(pointsToRelax, pointI) + { + if + ( + pointsToRelax[pointI] + && (relaxationLevel[pointI] < relaxationFactors_.size() - 1) + ) + { + ++ relaxationLevel[pointI]; + + complete = false; + } + } + + // Synchronise relaxation levels + syncTools::syncPointList + ( + mesh(), + relaxationLevel, + maxEqOp<label>(), + label(0) + ); + + // Synchronise completion + reduce(complete, andOp<bool>()); + } + + // Check for convergence + bool converged(true); + forAll(mesh().faces(), faceI) + { + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + if (relaxationLevel[pointI] > 0) + { + facesToMove_.insert(faceI); + + converged = false; + + break; + } + } + } + + // Syncronise convergence + reduce(converged, andOp<bool>()); + + //if (converged) + //{ + // Info<< "... Converged" << endl << endl; + //} + //else + //{ + // Info<< "... Not converged" << endl << endl; + //} + + return converged; +} + + +void Foam::displacementPointSmoothingMotionSolver::setFacesToMove +( + const dictionary& dict +) +{ + if (dict.getOrDefault<bool>("moveInternalFaces", true)) + { + facesToMove_.resize(2*mesh().nFaces()); + forAll(mesh().faces(), faceI) + { + facesToMove_.insert(faceI); + } + } + else + { + facesToMove_.resize(2*(mesh().nBoundaryFaces())); + for + ( + label faceI = mesh().nInternalFaces(); + faceI < mesh().nFaces(); + ++ faceI + ) + { + facesToMove_.insert(faceI); + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::displacementPointSmoothingMotionSolver:: +displacementPointSmoothingMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict +) +: + displacementMotionSolver(mesh, dict, typeName), + meshGeometry_(mesh), + pointSmoother_(pointSmoother::New(mesh, coeffDict())), + nPointSmootherIter_ + ( + readLabel(coeffDict().lookup("nPointSmootherIter")) + ), + relaxedPoints_(mesh.points()) +{ + if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_)) + { + meshQualityDict_ = coeffDict().subDict("meshQuality"); + } + setFacesToMove(coeffDict()); +} + + +Foam::displacementPointSmoothingMotionSolver:: +displacementPointSmoothingMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 +) +: + displacementMotionSolver(mesh, dict, pointDisplacement, points0, typeName), + meshGeometry_(mesh), + pointSmoother_ + ( + pointSmoother::New + ( + mesh, + coeffDict() + ) + ), + nPointSmootherIter_ + ( + readLabel(coeffDict().lookup("nPointSmootherIter")) + ), + relaxedPoints_(mesh.points()) +{ + if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_)) + { + meshQualityDict_ = coeffDict().subDict("meshQuality"); + } + setFacesToMove(coeffDict()); +} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +Foam::tmp<Foam::pointField> +Foam::displacementPointSmoothingMotionSolver::curPoints() const +{ + //Note: twoDCorrect already done by ::solve + + return relaxedPoints_; +} + + +void Foam::displacementPointSmoothingMotionSolver::solve() +{ + //Pout<< "time:" << mesh().time().timeName() + // << " mesh faceCentres:" << gAverage(mesh().faceCentres()) + // << " mesh cellCentres:" << gAverage(mesh().cellCentres()) + // << endl; + + movePoints(curPoints()); + + // Update values on pointDisplacement + pointDisplacement().boundaryFieldRef().updateCoeffs(); + + // Extend: face-to-point-to-cell-to-faces + labelHashSet affectedFaces; + markAffectedFaces(facesToMove_, affectedFaces); + + for(label i = 0; i < nPointSmootherIter_; i ++) + { + meshGeometry_.correct + ( + points0() + pointDisplacement().internalField(), + affectedFaces.toc() + ); + //Pout<< "iter:" << i + // << " faceCentres:" << gAverage(meshGeometry_.faceCentres()) + // << " cellCentres:" << gAverage(meshGeometry_.cellCentres()) + // << endl; + + pointSmoother_->update + ( + affectedFaces.toc(), + points0(), + points0() + pointDisplacement().internalField(), + meshGeometry_, + pointDisplacement() + ); + } + + relax(); + + twoDCorrectPoints(relaxedPoints_); + + // Update pointDisplacement for actual relaxedPoints. Keep fixed-value + // bcs. + pointDisplacement().primitiveFieldRef() = relaxedPoints_-points0(); + + // Adhere to multi-point constraints + const pointConstraints& pcs = + pointConstraints::New(pointDisplacement().mesh()); + pcs.constrainDisplacement(pointDisplacement(), false); + + // Update relaxedPoints to take constraints into account + relaxedPoints_ = points0() + pointDisplacement().internalField(); +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.H new file mode 100644 index 0000000000000000000000000000000000000000..8dd60c5528f3f8ce198be8c97b6d5996ffd81efa --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.H @@ -0,0 +1,149 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::displacementPointSmoothingMotionSolver + +Description + Quality-based under-relaxation for run-time selectable point smoothing. + +SourceFiles + displacementPointSmoothingMotionSolver.C + +\*---------------------------------------------------------------------------*/ + +#ifndef displacementPointSmoothingMotionSolver_H +#define displacementPointSmoothingMotionSolver_H + +#include "displacementMotionSolver.H" +#include "pointSmoother.H" +#include "polyMeshGeometry.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class displacementPointSmoothingMotionSolver Declaration +\*---------------------------------------------------------------------------*/ + +class displacementPointSmoothingMotionSolver +: + public displacementMotionSolver +{ +protected: + + // Protected Data + + //- Part-updatable mesh geometry + polyMeshGeometry meshGeometry_; + + //- Point smoothing method + autoPtr<pointSmoother> pointSmoother_; + + //- Number of point smoother iterations per timestep + const label nPointSmootherIter_; + + + // Mesh quality based relaxation of smoothed position + + //- Relaxation factors to use in each iteration + scalarList relaxationFactors_; + + //- Relaxed point field + pointField relaxedPoints_; + + //- Set of the faces which are to be moved + labelHashSet facesToMove_; + + //- Mesh quality dictionary + dictionary meshQualityDict_; + + + // Private Member Functions + + //- Mark affected faces + void markAffectedFaces + ( + const labelHashSet& changedFaces, + labelHashSet& affectedFaces + ); + + //- Relax the points + bool relax(); + + //- Set all the faces to be moved + void virtual setFacesToMove(const dictionary&); + + +public: + + //- Runtime type information + TypeName("displacementPointSmoothing"); + + + // Constructors + + //- Construct from a polyMesh and an IOdictionary + displacementPointSmoothingMotionSolver + ( + const polyMesh&, + const IOdictionary& + ); + + //- Construct from components + displacementPointSmoothingMotionSolver + ( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 + ); + + + //- Destructor + virtual ~displacementPointSmoothingMotionSolver() = default; + + + // Member Functions + + //- Return point location obtained from the current motion field + virtual tmp<pointField> curPoints() const; + + //- Solve for motion + virtual void solve(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.C new file mode 100644 index 0000000000000000000000000000000000000000..88aa458a69f27ef4e005e7ea2a94177ee7542f8e --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.C @@ -0,0 +1,746 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "displacementSmartPointSmoothingMotionSolver.H" +#include "addToRunTimeSelectionTable.H" +#include "syncTools.H" +#include "pointConstraints.H" +#include "motionSmootherAlgo.H" + +//#include "fvMesh.H" +//#include "fvGeometryScheme.H" +#include "OBJstream.H" +#include "emptyPointPatchFields.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(displacementSmartPointSmoothingMotionSolver, 0); + + addToRunTimeSelectionTable + ( + motionSolver, + displacementSmartPointSmoothingMotionSolver, + dictionary + ); + + addToRunTimeSelectionTable + ( + displacementMotionSolver, + displacementSmartPointSmoothingMotionSolver, + displacement + ); +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::displacementSmartPointSmoothingMotionSolver::markAffectedFaces +( + const labelHashSet& changedFaces, + labelHashSet& affectedFaces +) +{ + PackedBoolList affectedPoints(mesh().nPoints(), false); + + forAllConstIter(labelHashSet, changedFaces, iter) + { + const label faceI(iter.key()); + + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + affectedPoints[pointI] = true; + } + } + + syncTools::syncPointList + ( + mesh(), + affectedPoints, + orEqOp<unsigned int>(), + 0U + ); + + forAll(affectedPoints, pointI) + { + if (affectedPoints[pointI]) + { + const labelList& pCells(mesh().pointCells()[pointI]); + + forAll(pCells, pointCellI) + { + const label cellI(pCells[pointCellI]); + + const labelList& cFaces(mesh().cells()[cellI]); + + affectedFaces.insert(cFaces); + } + } + } +} + + +bool Foam::displacementSmartPointSmoothingMotionSolver::relax() +{ + if + ( + (relaxationFactors_.size() == 0) + || (relaxationFactors_.size() == 1 && relaxationFactors_[0] == 1.0) + ) + { + relaxedPoints_ = points0() + pointDisplacement().internalField(); + return true; + } + + + const pointField oldRelaxedPoints(relaxedPoints_); + + labelHashSet affectedFaces(facesToMove_); + + // Create a list of relaxation levels + // -1 indicates a point which is not to be moved + // 0 is the starting value for a moving point + labelList relaxationLevel(mesh().nPoints(), -1); + forAllConstIter(labelHashSet, affectedFaces, iter) + { + const label faceI(iter.key()); + + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + relaxationLevel[pointI] = 0; + } + } + + syncTools::syncPointList + ( + mesh(), + relaxationLevel, + maxEqOp<label>(), + label(-1) + ); + + // Loop whilst relaxation levels are being incremented + bool complete(false); + while (!complete) + { + //scalar nAffectedFaces(affectedFaces.size()); + //reduce(nAffectedFaces, sumOp<scalar>()); + //Info << " Moving " << nAffectedFaces << " faces" << endl; + + // Move the points + forAll(relaxationLevel, pointI) + { + if (relaxationLevel[pointI] >= 0) + { + const scalar x + ( + relaxationFactors_[relaxationLevel[pointI]] + ); + + relaxedPoints_[pointI] = + (1 - x)*oldRelaxedPoints[pointI] + + x*(points0()[pointI] + pointDisplacement()[pointI]); + } + } + + // Get a list of changed faces + labelHashSet markedFaces; + markAffectedFaces(affectedFaces, markedFaces); + labelList markedFacesList(markedFaces.toc()); + + // Update the geometry + meshGeometry_.correct(relaxedPoints_, markedFacesList); + + // Check the modified face quality + if (false) + { + // Use snappyHexMesh compatible checks + markedFaces.clear(); + motionSmootherAlgo::checkMesh + ( + false, + meshQualityDict_, + meshGeometry_, + relaxedPoints_, + markedFacesList, + markedFaces + ); + + // Mark the affected faces + affectedFaces.clear(); + markAffectedFaces(markedFaces, affectedFaces); + } + else + { + // Use pointSmoother specific + tmp<scalarField> tfaceQ + ( + pointUntangler_->faceQuality + ( + relaxedPoints_, + meshGeometry_.faceCentres(), + meshGeometry_.faceAreas(), + meshGeometry_.cellCentres(), + meshGeometry_.cellVolumes() + ) + ); + + if (debug) + { + MinMax<scalar> range(gMinMax(tfaceQ())); + Pout<< " min:" << range.min() << nl + << " max:" << range.max() << endl; + } + + labelList order; + Foam::sortedOrder(tfaceQ(), order); + + label nUntangle = 0; + forAll(order, i) + { + if (tfaceQ()[order[i]] > untangleQ_) + { + nUntangle = i; + break; + } + } + + affectedFaces = labelList(SubList<label>(order, nUntangle)); + } + + // Increase relaxation and check convergence + PackedBoolList pointsToRelax(mesh().nPoints(), false); + complete = true; + forAllConstIter(labelHashSet, affectedFaces, iter) + { + const label faceI(iter.key()); + + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + pointsToRelax[pointI] = true; + } + } + + forAll(pointsToRelax, pointI) + { + if + ( + pointsToRelax[pointI] + && (relaxationLevel[pointI] < relaxationFactors_.size() - 1) + ) + { + ++ relaxationLevel[pointI]; + + complete = false; + } + } + + // Synchronise relaxation levels + syncTools::syncPointList + ( + mesh(), + relaxationLevel, + maxEqOp<label>(), + label(0) + ); + + // Synchronise completion + reduce(complete, andOp<bool>()); + } + + // Check for convergence + bool converged(true); + forAll(mesh().faces(), faceI) + { + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + if (relaxationLevel[pointI] > 0) + { + facesToMove_.insert(faceI); + + converged = false; + + break; + } + } + } + + // Syncronise convergence + reduce(converged, andOp<bool>()); + + //if (converged) + //{ + // Info<< "... Converged" << endl << endl; + //} + //else + //{ + // Info<< "... Not converged" << endl << endl; + //} + + return converged; +} + + +void Foam::displacementSmartPointSmoothingMotionSolver::setFacesToMove +( + const dictionary& dict +) +{ + if (dict.getOrDefault<bool>("moveInternalFaces", true)) + { + facesToMove_.resize(2*mesh().nFaces()); + forAll(mesh().faces(), faceI) + { + facesToMove_.insert(faceI); + } + } + else + { + facesToMove_.resize(2*(mesh().nBoundaryFaces())); + for + ( + label faceI = mesh().nInternalFaces(); + faceI < mesh().nFaces(); + ++ faceI + ) + { + facesToMove_.insert(faceI); + } + } +} + + +void Foam::displacementSmartPointSmoothingMotionSolver::emptyCorrectPoints +( + pointVectorField& pointDisplacement +) +{ + // Assume empty point patches are already in correct location + // so knock out any off-plane displacement. + auto& fld = pointDisplacement.primitiveFieldRef(); + for (const auto& ppf : pointDisplacement.boundaryField()) + { + if (isA<emptyPointPatchVectorField>(ppf)) + { + const auto& mp = ppf.patch().meshPoints(); + forAll(mp, i) + { + pointConstraint pc; + ppf.patch().applyConstraint(i, pc); + fld[mp[i]] = pc.constrainDisplacement(fld[mp[i]]); + } + } + } + + pointField wantedPoints(points0() + fld); + twoDCorrectPoints(wantedPoints); + fld = wantedPoints-points0(); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::displacementSmartPointSmoothingMotionSolver:: +displacementSmartPointSmoothingMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict +) +: + displacementMotionSolver(mesh, dict, typeName), + meshGeometry_(mesh), + pointUntangler_ + ( + pointSmoother::New + ( + coeffDict().get<word>("untangler"), + mesh, + coeffDict() + ) + ), + untangleQ_(coeffDict().get<scalar>("untangleQ")), + minQ_(coeffDict().get<scalar>("minQ")), + pointSmoother_(pointSmoother::New(mesh, coeffDict())), + nPointSmootherIter_ + ( + readLabel(coeffDict().lookup("nPointSmootherIter")) + ), + relaxedPoints_(mesh.points()) +{ + if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_)) + { + meshQualityDict_ = coeffDict().subDict("meshQuality"); + } + setFacesToMove(coeffDict()); +} + + +Foam::displacementSmartPointSmoothingMotionSolver:: +displacementSmartPointSmoothingMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 +) +: + displacementMotionSolver(mesh, dict, pointDisplacement, points0, typeName), + meshGeometry_(mesh), + pointUntangler_ + ( + pointSmoother::New + ( + coeffDict().get<word>("untangler"), + mesh, + coeffDict() + ) + ), + untangleQ_(coeffDict().get<scalar>("untangleQ")), + minQ_(coeffDict().get<scalar>("minQ")), + pointSmoother_ + ( + pointSmoother::New + ( + mesh, + coeffDict() + ) + ), + nPointSmootherIter_ + ( + readLabel(coeffDict().lookup("nPointSmootherIter")) + ), + relaxedPoints_(mesh.points()) +{ + if (coeffDict().readIfPresent("relaxationFactors", relaxationFactors_)) + { + meshQualityDict_ = coeffDict().subDict("meshQuality"); + } + setFacesToMove(coeffDict()); +} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +Foam::tmp<Foam::pointField> +Foam::displacementSmartPointSmoothingMotionSolver::curPoints() const +{ + //Note: twoDCorrect already done by ::solve + + return relaxedPoints_; +} + + +void Foam::displacementSmartPointSmoothingMotionSolver::solve() +{ + movePoints(curPoints()); + + // Update values on pointDisplacement. Note: should also evaluate? Since + // e.g. cellMotionBC uses pointDisplacement value. + pointDisplacement().boundaryFieldRef().updateCoeffs(); + + + fileName debugDir; + if (debug & 2) + { + debugDir = mesh().time().timePath(); + mkDir(debugDir); + OBJstream os(debugDir/"bc.obj"); + + const pointField wantedPoints + ( + points0() + + pointDisplacement().internalField() + ); + const auto& pbm = pointDisplacement().mesh().boundary(); + for (const auto& ppp : pbm) + { + if (!isA<emptyPointPatch>(ppp)) + { + const auto& mp = ppp.meshPoints(); + for (const label pointi : mp) + { + os.write + ( + linePointRef + ( + points0()[pointi], + wantedPoints[pointi] + ) + ); + } + } + } + Pout<< "Written " << os.nVertices() << " initial displacements to " + << os.name() << endl; + } + + + // Extend: face-to-point-to-cell-to-faces + labelHashSet affectedFaces; + markAffectedFaces(facesToMove_, affectedFaces); + + + for(label i = 0; i < nPointSmootherIter_; i ++) + { + const pointField wantedPoints + ( + points0() + + pointDisplacement().internalField() + ); + + meshGeometry_.correct + ( + wantedPoints, + affectedFaces.toc() + ); + + //{ + // // Debugging: check meshGeometry consistent with fvGeometryScheme + // const auto& geom = + // reinterpret_cast<const fvMesh&>(mesh()).geometry(); + // pointField faceCentres(mesh().nFaces()); + // vectorField faceAreas(mesh().nFaces()); + // pointField cellCentres(mesh().nCells()); + // scalarField cellVolumes(mesh().nCells()); + // geom.updateGeom + // ( + // wantedPoints, + // mesh().points(), // old points + // faceCentres, + // faceAreas, + // cellCentres, + // cellVolumes + // ); + // forAll(faceCentres, facei) + // { + // const point& meshFc = mesh().faceCentres()[facei]; + // const point& meshGeomFc = meshGeometry_.faceCentres()[facei]; + // const point& updatedFc = faceCentres[facei]; + // + // if (updatedFc != meshGeomFc) + // { + // const face& f = mesh().faces()[facei]; + // + // Pout<< "At face:" << facei << nl + // << " old :" << meshFc << nl + // << " new :" << updatedFc << nl + // << " polyMeshGeom:" << meshGeomFc << nl + // << " oldPoints :" + // << UIndirectList<point>(mesh().points(), f) << nl + // << " wantedPoints:" + // << UIndirectList<point>(wantedPoints, f) << nl + // << endl; + // } + // } + //} + + // Get measure of face quality + tmp<scalarField> tfaceQ + ( + pointUntangler_->faceQuality + ( + wantedPoints, + meshGeometry_.faceCentres(), + meshGeometry_.faceAreas(), + meshGeometry_.cellCentres(), + meshGeometry_.cellVolumes() + ) + ); + + + if (debug) + { + MinMax<scalar> range(gMinMax(tfaceQ())); + Pout<< " min:" << range.min() << nl + << " max:" << range.max() << endl; + } + + labelList order; + Foam::sortedOrder(tfaceQ(), order); + + label nUntangle = 0; + forAll(order, i) + { + if (tfaceQ()[order[i]] > untangleQ_) + { + nUntangle = i; + break; + } + } + label nLow = 0; + forAll(order, i) + { + if (tfaceQ()[order[i]] > minQ_) + { + nLow = i; + break; + } + } + + + if (debug) + { + Pout<< " nUntangle:" << returnReduce(nUntangle, sumOp<label>()) + << nl + << " nLow :" << returnReduce(nLow, sumOp<label>()) + << nl; + } + + + if (returnReduce(nUntangle, sumOp<label>())) + { + // Start untangling + labelList lowQFaces(SubList<label>(order, nUntangle)); + //{ + // // Grow set (non parallel) + // bitSet isMarkedFace(mesh().nFaces()); + // for (const label facei : lowQFaces) + // { + // for (const label pointi : mesh().faces()[facei]) + // { + // isMarkedFace.set(mesh().pointFaces()[pointi]); + // } + // } + // lowQFaces = isMarkedFace.sortedToc(); + //} + + //Pout<< " untangling " + // << returnReduce(lowQFaces.size(), sumOp<label>()) + // << " faces" << endl; + pointUntangler_->update + ( + lowQFaces, + points0(), + wantedPoints, + meshGeometry_, + pointDisplacement() + //false // ! do NOT apply bcs, constraints + ); + + // Keep points on empty patches. Note: since pointConstraints + // does not implement constraints on emptyPointPatches and + // emptyPointPatchField does not either. + emptyCorrectPoints(pointDisplacement()); + + if (debug & 2) + { + OBJstream os(debugDir/"untangle_" + Foam::name(i) + ".obj"); + + const pointField wantedPoints + ( + points0() + + pointDisplacement().internalField() + ); + forAll(wantedPoints, pointi) + { + os.write + ( + linePointRef + ( + points0()[pointi], + wantedPoints[pointi] + ) + ); + } + Pout<< "Written " << os.nVertices() << " wanted untangle to " + << os.name() << endl; + } + } + else if (returnReduce(nLow, sumOp<label>())) + { + labelList lowQFaces(SubList<label>(order, nLow)); + //{ + // // Grow set (non parallel) + // bitSet isMarkedFace(mesh().nFaces()); + // for (const label facei : lowQFaces) + // { + // for (const label pointi : mesh().faces()[facei]) + // { + // isMarkedFace.set(mesh().pointFaces()[pointi]); + // } + // } + // lowQFaces = isMarkedFace.sortedToc(); + //} + + //Pout<< " smoothing " + // << returnReduce(lowQFaces.size(), sumOp<label>()) + // << " faces" << endl; + + pointSmoother_->update + ( + lowQFaces, + points0(), + wantedPoints, + meshGeometry_, + pointDisplacement() + ); + // Keep points on empty patches + emptyCorrectPoints(pointDisplacement()); + } + else + { + //Pout<< "** converged" << endl; + break; + } + } + + + relax(); + //relaxedPoints_ = points0() + pointDisplacement().internalField(); + + twoDCorrectPoints(relaxedPoints_); + + // Update pointDisplacement for actual relaxedPoints. Keep fixed-value + // bcs. + pointDisplacement().primitiveFieldRef() = relaxedPoints_-points0(); + + // Adhere to multi-point constraints. Does correctBoundaryConditions + + // multi-patch issues. + const pointConstraints& pcs = + pointConstraints::New(pointDisplacement().mesh()); + pcs.constrainDisplacement(pointDisplacement(), false); +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.H new file mode 100644 index 0000000000000000000000000000000000000000..c0e3fd68d8653c8ee07cca4809b6df73a1eee948 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.H @@ -0,0 +1,193 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::displacementSmartPointSmoothingMotionSolver + +Description + Quality-based under-relaxation for run-time selectable point smoothing. WIP. + +Usage + \table + Property | Description | Required | Default value + untangler | pointSmoother for untangling | yes | + untangleQ | quality below which untangling is applied | yes | + + pointSmoother | pointSmoother in 'normal' mode | yes + minQ | quality below which pointSmoother is applied | yes + nPointSmootherIter | max number of iterations + \endtable + + Example of the motion solver specification in dynamicMeshDict: + \verbatim + motionSolver displacementSmartPointSmoothing; + displacementSmartPointSmoothingCoeffs + { + //- Overall max number of smoothing iterations + nPointSmootherIter 10; + + //- If any faces have quality below untangleQ apply untangler + untangleQ 0.001; + untangler laplacian; + + //- If any faces have quality below minQ apply 'normal' smoother + minQ 0.9; + pointSmoother geometricElementTransform; + transformationParameter 0.667; + } + \endverbatim + +SourceFiles + displacementSmartPointSmoothingMotionSolver.C + +\*---------------------------------------------------------------------------*/ + +#ifndef displacementSmartPointSmoothingMotionSolver_H +#define displacementSmartPointSmoothingMotionSolver_H + +#include "displacementMotionSolver.H" +#include "pointSmoother.H" +#include "polyMeshGeometry.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class displacementSmartPointSmoothingMotionSolver Declaration +\*---------------------------------------------------------------------------*/ + +class displacementSmartPointSmoothingMotionSolver +: + public displacementMotionSolver +{ +protected: + + // Protected Data + + //- Part-updatable mesh geometry + polyMeshGeometry meshGeometry_; + + //- Point untangler method + autoPtr<pointSmoother> pointUntangler_; + + //- Minimum allowed quality + const scalar untangleQ_; + + //- Minimum allowed quality + const scalar minQ_; + + //- Point smoothing method + autoPtr<pointSmoother> pointSmoother_; + + //- Number of point smoother iterations per timestep + const label nPointSmootherIter_; + + + // Mesh quality based relaxation of smoothed position + + //- Relaxation factors to use in each iteration + scalarList relaxationFactors_; + + //- Relaxed point field + pointField relaxedPoints_; + + //- Set of the faces which are to be moved + labelHashSet facesToMove_; + + //- Mesh quality dictionary + dictionary meshQualityDict_; + + + // Private Member Functions + + //- Mark affected faces + void markAffectedFaces + ( + const labelHashSet& changedFaces, + labelHashSet& affectedFaces + ); + + //- Relax the points + bool relax(); + + //- Set all the faces to be moved + void virtual setFacesToMove(const dictionary&); + + //- Handle 2D & empty bcs. Assume in both cases the starting mesh + // - has all edges aligned with 3rd dimension + // - is on planes of the empty patches + void emptyCorrectPoints(pointVectorField& pointDisplacement); + + +public: + + //- Runtime type information + TypeName("displacementSmartPointSmoothing"); + + + // Constructors + + //- Construct from a polyMesh and an IOdictionary + displacementSmartPointSmoothingMotionSolver + ( + const polyMesh&, + const IOdictionary& + ); + + //- Construct from components + displacementSmartPointSmoothingMotionSolver + ( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 + ); + + + //- Destructor + virtual ~displacementSmartPointSmoothingMotionSolver() = default; + + + // Member Functions + + //- Return point location obtained from the current motion field + virtual tmp<pointField> curPoints() const; + + //- Solve for motion + virtual void solve(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C new file mode 100644 index 0000000000000000000000000000000000000000..78ccdaa6aaed73c30bdd16f834dc356c9ef50c16 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C @@ -0,0 +1,1291 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021,2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "hexMeshSmootherMotionSolver.H" +#include "addToRunTimeSelectionTable.H" +#include "syncTools.H" +#include "pointConstraints.H" +#include "unitConversion.H" +#include "OBJstream.H" +#include "PatchTools.H" +//#include "geometricElementTransformPointSmoother.H" +#include "pointList.H" +#include "vectorList.H" +#include "meshPointPatch.H" +#include "pointSmoother.H" +#include "fvMesh.H" +#include "fvGeometryScheme.H" +#include "emptyPointPatchFields.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(hexMeshSmootherMotionSolver, 0); + + addToRunTimeSelectionTable + ( + motionSolver, + hexMeshSmootherMotionSolver, + dictionary + ); + + addToRunTimeSelectionTable + ( + displacementMotionSolver, + hexMeshSmootherMotionSolver, + displacement + ); +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::labelList Foam::hexMeshSmootherMotionSolver::nonConstraintPatches +( + const polyMesh& mesh +) +{ + // Get list of all non-constraint patches. These are the ones where + // laplacian smoothing is applied. + + const auto& pbm = mesh.boundaryMesh(); + + DynamicList<label> patchIDs(pbm.size()); + for (const auto& pp : pbm) + { + if (!polyPatch::constraintType(pp.type())) + { + patchIDs.append(pp.index()); + } + } + return patchIDs; +} + + +Foam::autoPtr<Foam::indirectPrimitivePatch> +Foam::hexMeshSmootherMotionSolver::makePatch +( + const polyMesh& mesh, + const labelList& patchIDs, + const labelList& zoneIDs, + const pointField& points0 +) +{ + // Mark all faces + bitSet isPatchFace(mesh.nFaces()); + + // Mark all boundary faces (or just patchIDs?) + for (const label patchi : patchIDs) + { + const polyPatch& pp = mesh.boundaryMesh()[patchi]; + isPatchFace.set(pp.range()); + } + + const auto& fzs = mesh.faceZones(); + for (const label zonei : zoneIDs) + { + isPatchFace.set(fzs[zonei]); + } + + syncTools::syncFaceList(mesh, isPatchFace, orEqOp<unsigned int>()); + + const labelList patchFaces(isPatchFace.sortedToc()); + + return autoPtr<indirectPrimitivePatch>::New + ( + IndirectList<face>(mesh.faces(), patchFaces), + points0 + ); +} + + +void Foam::hexMeshSmootherMotionSolver::checkMesh +( + const pointField& currentPoints, + const vectorField& fCtrs, + const vectorField& fAreas, + const vectorField& cellCtrs, + const scalarField& cellVols, + labelHashSet& markedFaces, + bitSet& markedPoints +) const +{ + // Replacement for motionSmootherAlgo::checkMesh. Adds to markedFaces + // any faces that are insufficient quality + + + markedFaces.clear(); + markedPoints = false; + + + /* + + tmp<scalarField> tminCellQ + ( + pointSmoothers::geometricElementTransformPointSmoother::cellQuality + ( + mesh(), + currentPoints + ) + ); + const scalarField& minCellQ = tminCellQ(); + + markedPoints.setSize(mesh().nPoints()); + + labelHashSet set; + DynamicList<label> storage; + + for (label facei = 0; facei < mesh().nFaces(); facei++) + { + const label own = mesh().faceOwner()[facei]; + if (minCellQ[own] < VSMALL) + { + markedFaces.insert(facei); + markedPoints.set(mesh().cellPoints(own, set, storage)); + } + else if + ( + mesh().isInternalFace(facei) + && minCellQ[mesh().faceNeighbour()[facei]] < VSMALL + ) + { + markedFaces.insert(facei); + markedPoints.set + ( + mesh().cellPoints(mesh().faceNeighbour()[facei], set, storage) + ); + } + } + */ + + // Get measure of face quality + tmp<scalarField> tfaceQ + ( + pointSmoother_->faceQuality + ( + currentPoints, + fCtrs, + fAreas, + cellCtrs, + cellVols + ) + ); + const auto& faceQ = tfaceQ(); + + markedPoints.setSize(mesh().nPoints()); + forAll(faceQ, facei) + { + if (faceQ[facei] < VSMALL) + { + markedFaces.insert(facei); + markedPoints.set(mesh().faces()[facei]); + } + } + + + syncTools::syncPointList + ( + mesh(), + markedPoints, + orEqOp<unsigned int>(), + 0U + ); + + // Par sync. TBD. + { + bitSet isMarkedFace(mesh().nFaces()); + isMarkedFace.set(markedFaces.toc()); + syncTools::syncFaceList + ( + mesh(), + isMarkedFace, + orEqOp<unsigned int>() + ); + markedFaces.insert(isMarkedFace.toc()); + } +} + + +//void Foam::hexMeshSmootherMotionSolver::constrainDisplacement +//( +// pointField& points +//) const +//{ +// // Make sure the points obey the boundary conditions +// // on pointDisplacement +// +// // Update pointDisplacement for suppled points +// pointDisplacement_.primitiveFieldRef() = points-points0(); +// const pointConstraints& pcs = +// pointConstraints::New(pointDisplacement_.mesh()); +// pcs.constrainDisplacement(pointDisplacement_, false); +//// pointDisplacement_.correctBoundaryConditions(); +// points = points0()+pointDisplacement(); +//} + + +bool Foam::hexMeshSmootherMotionSolver::relax +( + const scalarList& relaxationFactors, + const bitSet& pointsToRelax, + const pointField& initialPoints, + const pointField& wantedPoints, + pointField& relaxedPoints, + labelList& relaxationLevel +) const +{ + // Find relaxation level that makes mesh quality acceptable. Gets given + // initial set of mesh points + + relaxedPoints = wantedPoints; + + { + vectorField fCtrs(mesh().nFaces()); + vectorField fAreas(mesh().nFaces()); + vectorField cellCtrs(mesh().nCells()); + scalarField cellVols(mesh().nCells()); + + // Calculate mesh quantities with new locations + const auto& geom = + reinterpret_cast<const fvMesh&>(mesh()).geometry(); + geom.updateGeom + ( + relaxedPoints, + mesh().points(), // old points (for avoiding recalculation) + fCtrs, + fAreas, + cellCtrs, + cellVols + ); + + // Check the modified face quality. Marks faces with insufficient + // quality. + labelHashSet markedFaces; + bitSet markedPoints; + checkMesh + ( + relaxedPoints, + fCtrs, + fAreas, + cellCtrs, + cellVols, + markedFaces, + markedPoints + ); + if (debug) + { + Pout<< "** hexMeshSmootherMotionSolver::relax : errorfaces:" + << markedFaces.size() + << " errorpoints:" << markedPoints.count() << endl; + } + } + + + // Create a list of relaxation levels + // -1 indicates a point which is not to be moved + // 0 is the starting value for a moving point + relaxationLevel.setSize(mesh().nPoints()); + relaxationLevel = -1; + for (const label pointi : pointsToRelax) + { + relaxationLevel[pointi] = 0; + } + + syncTools::syncPointList + ( + mesh(), + relaxationLevel, + maxEqOp<label>(), + label(-1) + ); + + vectorField fCtrs(mesh().nFaces()); + vectorField fAreas(mesh().nFaces()); + vectorField cellCtrs(mesh().nCells()); + scalarField cellVols(mesh().nCells()); + + // Loop whilst relaxation levels are being incremented + bool complete(false); + while (!complete) + { + //Info<< " Moving " + // << countZeroOrPos(relaxationFactors.size(), relaxationLevel) + // << " points" << endl; + + // Calculate current points (relaxationLevel >= 0) + forAll(relaxationLevel, pointi) + { + if (relaxationLevel[pointi] >= 0) + { + const scalar x + ( + relaxationFactors[relaxationLevel[pointi]] + ); + + relaxedPoints[pointi] = + (1 - x)*initialPoints[pointi] + + x*wantedPoints[pointi]; + } + } + + // Make sure the relaxed points still obey the boundary conditions + // on pointDisplacement. Note: could do this afterwards but better + // as soon as possible so we pick it up in the checkMesh + //constrainDisplacement(relaxedPoints); + + + // Calculate mesh quantities with new locations + const auto& geom = + reinterpret_cast<const fvMesh&>(mesh()).geometry(); + geom.updateGeom + ( + relaxedPoints, + mesh().points(), // old points + fCtrs, + fAreas, + cellCtrs, + cellVols + ); + + // Check the modified face quality. Marks faces with insufficient + // quality. + labelHashSet markedFaces; + bitSet markedPoints; + checkMesh + ( + relaxedPoints, + fCtrs, + fAreas, + cellCtrs, + cellVols, + markedFaces, + markedPoints + ); + //Pout<< " checkMesh : errorfaces:" << markedFaces.size() + // << " errorpoints:" << markedPoints.count() << endl; + + complete = true; + for (const label pointi : markedPoints) + { + if (relaxationLevel[pointi] < relaxationFactors.size() - 1) + { + ++relaxationLevel[pointi]; + complete = false; + } + } + + //Info<< " After adjustment:" + // << countZeroOrPos(relaxationFactors.size(), relaxationLevel) + // << " points relaxed" << endl; + + + // Synchronise convergence + reduce(complete, andOp<bool>()); + + // Synchronise relaxation levels + syncTools::syncPointList + ( + mesh(), + relaxationLevel, + maxEqOp<label>(), + label(0) + ); + } + + // Check for convergence + const label count(countPos(relaxationLevel)); + const bool converged(count == 0); + + //if (converged) + //{ + // Info<< "... Converged" << endl << endl; + //} + //else + //{ + // Info<< "... Not converged" << endl << endl; + //} + + return converged; +} +Foam::label Foam::hexMeshSmootherMotionSolver::countPos +( + const labelList& elems +) const +{ + label n = 0; + for (const label elem : elems) + { + if (elem > 0) + { + n++; + } + } + return returnReduce(n, sumOp<label>()); +} + + +Foam::labelList Foam::hexMeshSmootherMotionSolver::countZeroOrPos +( + const label size, + const labelList& elems +) const +{ + labelList n(size, 0); + for (const label elem : elems) + { + if (elem >= 0) + { + n[elem]++; + } + } + Pstream::listCombineGather(n, plusEqOp<label>()); + Pstream::broadcast(n); + return n; +} + + +void Foam::hexMeshSmootherMotionSolver::select +( + const labelUList& lst, + const label val, + bitSet& isVal +) const +{ + isVal.set(lst.size()); + isVal = false; + forAll(lst, i) + { + isVal[i] = (lst[i] == val); + } +} + + +void Foam::hexMeshSmootherMotionSolver::laplaceSmooth +( + const label type, + const pointField& initialPoints, + pointField& newPoints +) const +{ + if (initialPoints.size() != mesh().nPoints()) + { + FatalErrorInFunction << "mesh().nPoints:" << mesh().nPoints() + << " initial:" << initialPoints.size() << exit(FatalError); + } + + newPoints.setSize(initialPoints.size()); + newPoints = Zero; + labelList n(initialPoints.size(), 0); + + DynamicList<label> storage; + forAll(pointTypes_, pointi) + { + if (pointTypes_[pointi] == INTERIOR) + { + const labelList& pPoints = mesh().pointPoints(pointi, storage); + for (const label otherPointi : pPoints) + { + if (isMasterPoint_[otherPointi]) + { + newPoints[pointi] += initialPoints[otherPointi]; + n[pointi]++; + } + } + //Pout<< "Moving internal point " << initialPoints[pointi] + // << " to average " << newPoints[pointi]/n[pointi] + // << " of " << n[pointi] << " points" << endl; + } + } + + // Combine + syncTools::syncPointList + ( + mesh(), + n, + plusEqOp<label>(), + 0 + ); + syncTools::syncPointList + ( + mesh(), + newPoints, + plusEqOp<vector>(), + vector::zero + ); + forAll(newPoints, pointi) + { + if (n[pointi] == 0) + { + // This can happen if not interior point + newPoints[pointi] = initialPoints[pointi]; + //Pout<< "Not Moving boundary point " << newPoints[pointi] << endl; + } + else + { + newPoints[pointi] /= n[pointi]; + //Pout<< "Moving internal point " << initialPoints[pointi] + // << " to " << newPoints[pointi] << endl; + } + } +} +void Foam::hexMeshSmootherMotionSolver::featLaplaceSmooth +( + const indirectPrimitivePatch& pp, + const pointField& initialPoints, + pointField& newPoints +) const +{ + if (initialPoints.size() != pp.nPoints()) + { + FatalErrorInFunction << "pp.nPoints:" << pp.nPoints() + << " initial:" << initialPoints.size() << exit(FatalError); + } + + newPoints.setSize(pp.nPoints()); + newPoints = Zero; + labelList n(pp.nPoints(), 0); + + const edgeList& edges = pp.edges(); + const labelListList& pointEdges = pp.pointEdges(); + const labelList& meshPoints = pp.meshPoints(); + + forAll(pointEdges, pointi) + { + const label myConstraint = pointTypes_[meshPoints[pointi]]; + if (myConstraint != INTERIOR) // pp points should never be interior + { + const labelList& pEdges = pointEdges[pointi]; + //Pout<< "For boundary point:" << initialPoints[pointi] + // << endl; + + for (const label edgei : pEdges) + { + const label otherPointi = edges[edgei].otherVertex(pointi); + const label otherMeshPointi = meshPoints[otherPointi]; + const label otherConstraint = pointTypes_[otherMeshPointi]; + + if + ( + (otherConstraint != INTERIOR) // Should not happen + && (myConstraint <= otherConstraint) + && isMasterPoint_[otherMeshPointi] + ) + { + //Pout<< " summing boundary point:" + // << initialPoints[otherPointi] << endl; + + newPoints[pointi] += initialPoints[otherPointi]; + n[pointi]++; + } + } + } + } + + // Combine + syncTools::syncPointList + ( + mesh(), + meshPoints, + n, + plusEqOp<label>(), + 0 + ); + syncTools::syncPointList + ( + mesh(), + meshPoints, + newPoints, + plusEqOp<vector>(), + vector::zero + ); + + forAll(newPoints, pointi) + { + if (n[pointi] == 0) + { + // This can happen if surface point surrounded by feature points + // only. + newPoints[pointi] = initialPoints[pointi]; + //Pout<< "Not Moving boundary point " << newPoints[pointi] << endl; + } + else + { + newPoints[pointi] /= n[pointi]; + //Pout<< "Moving surface point " << initialPoints[pointi] + // << " to average " << newPoints[pointi] + // << " of " << n[pointi] << " points" << endl; + } + } +} +void Foam::hexMeshSmootherMotionSolver::snapBoundaryPoints +( + const scalar scale, + const pointField& initialPoints, + pointField& newPoints +) const +{ + if (initialPoints.size() != pointDisplacement_.mesh().size()) + { + FatalErrorInFunction + << "mesh.nPoints():" << pointDisplacement_.mesh().size() + << " initial:" << initialPoints.size() << exit(FatalError); + } + const indirectPrimitivePatch& bnd0 = bnd0Ptr_(); + const labelList& mp = bnd0.meshPoints(); + + // Save old point location + const vectorField bndPoints(initialPoints, mp); + + // Update pointDisplacement_ to be consistent with mesh points being set to + // initialPoints. This makes sure that the snapping is done using the + // initialPoints as starting point + pointDisplacement_.primitiveFieldRef() = initialPoints-points0(); + // 'snap' using boundary conditions + pointDisplacement_.correctBoundaryConditions(); + + // Calculate new position + newPoints = points0() + pointDisplacement().internalField(); + + if (scale < 1.0) + { + // Underrelax + vectorField d(newPoints, mp); + d -= bndPoints; + d *= scale; + d += bndPoints; + UIndirectList<point>(newPoints, mp) = d; + } +} + +//void Foam::hexMeshSmootherMotionSolver::writeOBJ +//( +// const fileName& name, +// const pointField& p0, +// const pointField& p1 +//) const +//{ +// OBJstream os(mesh().time().path()/name); +// forAll(p0, pointi) +// { +// os.write(linePointRef(p0[pointi], p1[pointi])); +// } +// Pout<< "Dumped to " << os.name() << endl; +//} +//void Foam::hexMeshSmootherMotionSolver::writeOBJ +//( +// const fileName& name, +// const UIndirectList<face>& pp, +// const pointField& points +//) const +//{ +// const faceList fcs(pp); +// +// OBJstream os(mesh().time().path()/name); +// os.write(fcs, points, false); +// Pout<< "Dumped faces to " << os.name() << endl; +//} + + +void Foam::hexMeshSmootherMotionSolver::emptyCorrectPoints +( + pointVectorField& pointDisplacement +) const +{ + // Assume empty point patches are already in correct location + // so knock out any off-plane displacement. + auto& fld = pointDisplacement.primitiveFieldRef(); + for (const auto& ppf : pointDisplacement.boundaryField()) + { + if (isA<emptyPointPatchVectorField>(ppf)) + { + const auto& mp = ppf.patch().meshPoints(); + forAll(mp, i) + { + pointConstraint pc; + ppf.patch().applyConstraint(i, pc); + fld[mp[i]] = pc.constrainDisplacement(fld[mp[i]]); + } + } + } + + pointField wantedPoints(points0() + fld); + twoDCorrectPoints(wantedPoints); + fld = wantedPoints-points0(); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::hexMeshSmootherMotionSolver:: +hexMeshSmootherMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict +) +: + displacementMotionSolver(mesh, dict, typeName), + pointSmoother_(pointSmoother::New(mesh, coeffDict())), + nPointSmootherIter_ + ( + readLabel(coeffDict().lookup("nPointSmootherIter")) + ), + relaxationFactors_(coeffDict().lookup("relaxationFactors")), + relaxationLevel_(mesh.nPoints(), 0), + relaxedPoints_(mesh.points()), + //surfacesDict_(coeffDict().subDict("geometry")), + //featureAngle_(coeffDict().get<scalar>("featureAngle")), + //snapPatches_ + //( + // mesh.boundaryMesh().patchSet + // ( + // coeffDict().get<wordRes>("patches") + // ).sortedToc() + //), + //snapZones_ + //( + // mesh.faceZones().indices + // ( + // coeffDict().get<wordRes>("faceZones") + // ) + //), + snapScale_(Function1<scalar>::New("snapScale", coeffDict())), + isMasterPoint_(syncTools::getMasterPoints(mesh)), + // Create big primitivePatch for all outside and any features on it + //bnd0Ptr_(makePatch(mesh, snapPatches_, snapZones_, points0())) + bnd0Ptr_ + ( + makePatch + ( + mesh, + nonConstraintPatches(mesh), + labelList::null(), + points0() + ) + ) +{ +// findSurfaces(); +// +// // Do multi-patch constraints +// // ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// const scalar featureEdgeCos(Foam::cos(featureAngle_)); +// const scalar featurePointCos(featureEdgeCos); +// +// const indirectPrimitivePatch& bnd0 = bnd0Ptr_(); +// +// calcConstraints +// ( +// featureEdgeCos, +// featurePointCos, +// bnd0, +// bnd0EdgeConstraints_, +// bnd0PointConstraints_ +// ); + + const pointMesh& pMesh = pointMesh::New(mesh, IOobject::READ_IF_PRESENT); + + pointTypes_.setSize(pMesh.size()); + pointTypes_ = INTERIOR; + + for (const auto& pp : pMesh.boundary()) + { + if (!isA<meshPointPatch>(pp)) + { + const auto& mp = pp.meshPoints(); + UIndirectList<label>(pointTypes_, mp) = pointType::SURFACE; + } + } + + // Override with any explicit constraint boundaries + for (const auto& pp : pMesh.boundary()) + { + const auto* meshPointPtr = isA<meshPointPatch>(pp); + if (meshPointPtr) + { + const auto& constraints = meshPointPtr->constraints(); + const auto& mp = meshPointPtr->meshPoints(); + + forAll(mp, i) + { + pointTypes_[mp[i]] = pointType(constraints[i].first()); + } + } + } + + // Make sure coupled points agree. Max constraint wins. + syncTools::syncPointList + ( + mesh, + pointTypes_, + maxEqOp<label>(), + 0 + ); + + bitSet isVal; + select(pointTypes_, POINT, isVal); + const label nFeatPoint = returnReduce(isVal.count(), sumOp<label>()); + select(pointTypes_, EDGE, isVal); + const label nFeatEdge = returnReduce(isVal.count(), sumOp<label>()); + select(pointTypes_, SURFACE, isVal); + const label nSurface = returnReduce(isVal.count(), sumOp<label>()); + select(pointTypes_, INTERIOR, isVal); + const label nInternal = returnReduce(isVal.count(), sumOp<label>()); + Info<< "Attraction:" << nl + << " feature point:" << nFeatPoint << nl + << " feature edge :" << nFeatEdge << nl + << " surface :" << nSurface << nl + << " none :" << nInternal + << endl; +} + + +Foam::hexMeshSmootherMotionSolver:: +hexMeshSmootherMotionSolver +( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 +) +: + displacementMotionSolver(mesh, dict, pointDisplacement, points0, typeName), + pointSmoother_(pointSmoother::New(mesh, coeffDict())), + //pointSmoother_ + //( + // pointSmoother::New + // ( + // coeffDict(), + // displacementMotionSolver::pointDisplacement() + // ) + //), + nPointSmootherIter_ + ( + readLabel(coeffDict().lookup("nPointSmootherIter")) + ), + relaxationFactors_(coeffDict().lookup("relaxationFactors")), + relaxationLevel_(mesh.nPoints(), 0), + relaxedPoints_(mesh.points()), + //surfacesDict_(coeffDict().subDict("geometry")), + //featureAngle_(coeffDict().get<scalar>("featureAngle")), + //snapPatches_ + //( + // mesh.boundaryMesh().patchSet + // ( + // coeffDict().get<wordReList>("patches") + // ).sortedToc() + //), + //snapZones_ + //( + // mesh.faceZones().indices + // ( + // coeffDict().get<wordRes>("faceZones") + // ) + //), + snapScale_(Function1<scalar>::New("snapScale", coeffDict())), + isMasterPoint_(syncTools::getMasterPoints(mesh)), + // Create big primitivePatch for all outside and any features on it + //bnd0Ptr_(makePatch(mesh, snapPatches_, snapZones_, points0)) + bnd0Ptr_ + ( + makePatch + ( + mesh, + nonConstraintPatches(mesh), + labelList::null(), + points0 + ) + ) +{ +// findSurfaces(); +// +// const scalar featureEdgeCos(Foam::cos(featureAngle_)); +// const scalar featurePointCos(featureEdgeCos); +// +// const indirectPrimitivePatch& bnd0 = bnd0Ptr_(); +// +// calcConstraints +// ( +// featureEdgeCos, +// featurePointCos, +// bnd0, +// bnd0EdgeConstraints_, +// bnd0PointConstraints_ +// ); + + const pointMesh& pMesh = pointMesh::New(mesh, IOobject::READ_IF_PRESENT); + + pointTypes_.setSize(mesh.nPoints()); + pointTypes_ = INTERIOR; + + for (const auto& pp : pMesh.boundary()) + { + if (!isA<meshPointPatch>(pp) && !pp.coupled()) + { + const auto& mp = pp.meshPoints(); + UIndirectList<label>(pointTypes_, mp) = pointType::SURFACE; + } + } + + // Override with any explicit constraint boundaries + for (const auto& pp : pMesh.boundary()) + { + const auto* meshPointPtr = isA<meshPointPatch>(pp); + if (meshPointPtr) + { + const auto& constraints = meshPointPtr->constraints(); + const auto& mp = meshPointPtr->meshPoints(); + + forAll(mp, i) + { + pointTypes_[mp[i]] = pointType(constraints[i].first()); + } + } + } + + // Make sure coupled points agree. Max constraint wins. + syncTools::syncPointList + ( + mesh, + pointTypes_, + maxEqOp<label>(), + 0 + ); + + bitSet isVal; + select(pointTypes_, POINT, isVal); + const label nFeatPoint = returnReduce(isVal.count(), sumOp<label>()); + select(pointTypes_, EDGE, isVal); + const label nFeatEdge = returnReduce(isVal.count(), sumOp<label>()); + select(pointTypes_, SURFACE, isVal); + const label nSurface = returnReduce(isVal.count(), sumOp<label>()); + select(pointTypes_, INTERIOR, isVal); + const label nInternal = returnReduce(isVal.count(), sumOp<label>()); + Info<< "Attraction:" << nl + << " feature point:" << nFeatPoint << nl + << " feature edge :" << nFeatEdge << nl + << " surface :" << nSurface << nl + << " none :" << nInternal + << endl; +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::hexMeshSmootherMotionSolver:: +~hexMeshSmootherMotionSolver() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +Foam::tmp<Foam::pointField> +Foam::hexMeshSmootherMotionSolver::curPoints() const +{ + //Note: twoDCorrect already done by ::solve + return relaxedPoints_; +} + + +void Foam::hexMeshSmootherMotionSolver::solve() +{ + // Update any internal storage for current state + movePoints(mesh().points()); + + // No updating of bc since we don't want to do snapping yet - is done + // later on + //pointDisplacement().boundaryFieldRef().updateCoeffs(); + + const indirectPrimitivePatch& bnd0 = bnd0Ptr_(); + const labelList& mp = bnd0.meshPoints(); + + // Points on boundary + bitSet isBndPoint(mesh().nPoints(), false); + isBndPoint.set(mp); + + // Points not on boundary + bitSet isInternalPoint; + select(pointTypes_, INTERIOR, isInternalPoint); + + + const pointField& initialPoints = mesh().points(); + + // Wanted locations - starts off from current mesh points. Note : could + // use relaxedPoints_ but this should be equal to current mesh points unless + // we have multiple motion solvers ... + pointField movedPoints(initialPoints); + + + // -1 indicates a point which is not to be moved + // 0 is the starting value for a moving point + const label nRelaxed = countPos(relaxationLevel_); + //Pout<< "Starting relaxed:" << nRelaxed << endl; + + if (nRelaxed > 0) + { + // MeshSmoother::snapSmoothing() + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // - set initialPoint from relaxedPoint + // - smooth internal points + // - and relax point motion (= adapt relaxationLevel_) + // - snap boundary points + // - and relax point motion (= adapt relaxationLevel_) + // - mark all points that are not snapped (i.e. snapped but relaxed) + // - smooth all boundary points (using features) + // - and relax point motion (= adapt relaxationLevel_) + + // Laplace smoothing of interior (=unconstrained) points + laplaceSmooth(INTERIOR, initialPoints, movedPoints); + + // Apply constraints + //constrainDisplacement(movedPoints); + + // Determine relaxation level to move points + relax + ( + relaxationFactors_, + isInternalPoint, + initialPoints, // starting location + movedPoints, // wanted location + relaxedPoints_, // inbetween location without errors + relaxationLevel_ + ); + //Pout<< "After laplaceSmooth:" + // << countZeroOrPos(relaxationFactors_.size(), relaxationLevel_) + // << endl; + //writeOBJ + //( + // "laplaceSmooth_relax_" + mesh().time().timeName() + ".obj", + // bnd0, + // relaxedPoints_ + //); + + + // Snap boundary points + const scalar scale = snapScale_->value(mesh().time().timeIndex()); + if (scale > 0) + { + // snap to surface (=apply boundary conditions) + snapBoundaryPoints(scale, initialPoints, movedPoints); + + // Apply constraints + //constrainDisplacement(movedPoints); + + relax + ( + relaxationFactors_, + isBndPoint, + initialPoints, + movedPoints, + relaxedPoints_, + relaxationLevel_ + ); + //Pout<< "After snapping:" + // << countZeroOrPos(relaxationFactors_.size(), relaxationLevel_) + // << endl; + //writeOBJ("snap_relax.obj", initialPoints, relaxedPoints_); + + // Now relaxedPoints_ with relaxationLevel_ 0 are perfectly snapped + // (only applicable for bnd0 points) + } + + // Laplace smoothing of (now snapped&relaxed) boundary points. Use + // average of surrounding boundary points of same type only + pointField bndMovedPoints; + featLaplaceSmooth + ( + bnd0, + pointField(relaxedPoints_, mp), + bndMovedPoints + ); + UIndirectList<point>(movedPoints, mp) = bndMovedPoints; + + // Apply constraints + //constrainDisplacement(movedPoints); + //writeOBJ("featLaplaceSmooth.obj", initialPoints, movedPoints); + + relax + ( + relaxationFactors_, + isBndPoint, + initialPoints, + movedPoints, + relaxedPoints_, + relaxationLevel_ + ); + } + else + { + // MeshSmoother::GETMeSmoothing() + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // - set initialPoint from relaxedPoint + // - smooth all boundary points (using features) + // - and relax point motion (= adapt relaxationLevel_) + // - snap boundary points + // - and relax point motion (= adapt relaxationLevel_) + // - do all points GETMe + // - and relax point motion (= adapt relaxationLevel_) + + + // Laplace smoothing of boundary points. Use average of + // surrounding boundary points of same type only. TBD: make consistent + // wrt coupled points not on boundary patch. + pointField bndMovedPoints; + featLaplaceSmooth + ( + bnd0, + pointField(relaxedPoints_, mp), + bndMovedPoints + ); + UIndirectList<point>(movedPoints, mp) = bndMovedPoints; + //writeOBJ + //( + // "featLaplaceSmooth_unconstrain_" + // + mesh().time().timeName() + // + ".obj", + // pointField(initialPoints, mp), + // bndMovedPoints + //); + + // Apply constraints + //constrainDisplacement(movedPoints); + + relax + ( + relaxationFactors_, + isBndPoint, + initialPoints, + movedPoints, + relaxedPoints_, + relaxationLevel_ + ); + //writeOBJ + //( + // "featLaplaceSmooth_relax" + // + mesh().time().timeName() + // + ".obj", + // initialPoints, + // relaxedPoints_ + //); + + // Snap boundary points + const scalar scale = snapScale_->value(mesh().time().timeIndex()); + if (scale > 0) + { + // snap to surface (=apply boundary conditions) + snapBoundaryPoints(scale, relaxedPoints_, movedPoints); + + // Apply constraints + //constrainDisplacement(movedPoints); + //writeOBJ("snap.obj", initialPoints, movedPoints); + + relax + ( + relaxationFactors_, + isBndPoint, + initialPoints, + movedPoints, + relaxedPoints_, + relaxationLevel_ + ); + //writeOBJ("snap_relax.obj", initialPoints, relaxedPoints_); + } + + vectorField fCtrs(mesh().nFaces()); + vectorField fAreas(mesh().nFaces()); + vectorField cellCtrs(mesh().nCells()); + scalarField cellVols(mesh().nCells()); + + movedPoints = relaxedPoints_; + + for(label i = 0; i < nPointSmootherIter_; i ++) + { + // Starting from current points do smoothing + // Calculate mesh quantities with new locations + + const auto& geom = + reinterpret_cast<const fvMesh&>(mesh()).geometry(); + geom.updateGeom + ( + movedPoints, + mesh().points(), // old points + fCtrs, + fAreas, + cellCtrs, + cellVols + ); + + //- Smooth point positions (returned as pointDisplacement w.r.t. + // points0) + pointSmoother_->update + ( + identity(mesh().nFaces()), + points0(), + movedPoints, + fCtrs, + fAreas, + cellCtrs, + cellVols, + pointDisplacement_ + ); + // Keep points on empty patches + emptyCorrectPoints(pointDisplacement()); + + // Update moving points + movedPoints = points0() + pointDisplacement().internalField(); + + //// snap to surface (=apply boundary conditions) + //snapBoundaryPoints(scale, movedPoints, movedPoints); + } + + // snap to surface (=apply boundary conditions) + //snapBoundaryPoints(scale, movedPoints, movedPoints); + + //writeOBJ + //( + // "GETMeSmoothing_snapped_" + // + mesh().time().timeName() + // + ".obj", + // pointField(initialPoints, mp), + // pointField(movedPoints, mp) + //); + + relax + ( + relaxationFactors_, + bitSet(mesh().nPoints(), true), + initialPoints, + movedPoints, + relaxedPoints_, + relaxationLevel_ + ); + //writeOBJ("GETMeSmoothing_relax.obj", initialPoints, relaxedPoints_); + } +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.H new file mode 100644 index 0000000000000000000000000000000000000000..a71b739fa1886692b9b23bd2944ea99634873520 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.H @@ -0,0 +1,258 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2021 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::hexMeshSmootherMotionSolver + +Description + Implementation of hexMeshSmoother (part of extBlockMesh). WIP. + + See https://github.com/Etudes-NG/extBlockMesh + extBlockMesh Copyright (C) 2014 Etudes-NG + + Quality-based under-relaxation of point smoothing. + +Usage + Example of the motion solver specification in dynamicMeshDict: + \verbatim + motionSolver hexMeshSmoother; + hexMeshSmootherCoeffs + { + //- Number of smoothing iterations + nPointSmootherIter 10; + + //- Smoother to apply + pointSmoother geometricElementTransform; + + //- Any smoother-specific settings + transformationParameter 0.667; + + //- Underrelax boundary condition + snapScale table ((0 0.1) (10 1.0)); + } + +SourceFiles + hexMeshSmootherMotionSolver.C + +\*---------------------------------------------------------------------------*/ + +#ifndef hexMeshSmootherMotionSolver_H +#define hexMeshSmootherMotionSolver_H + +#include "displacementMotionSolver.H" +#include "Function1.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +//class searchableSurfaces; +class pointSmoother; + +/*---------------------------------------------------------------------------*\ + Class hexMeshSmootherMotionSolver Declaration +\*---------------------------------------------------------------------------*/ + +class hexMeshSmootherMotionSolver +: + public displacementMotionSolver +{ +public: + + // Public Data + + //- Enumeration defining the type of attraction + enum pointType + { + INTERIOR = 0, + SURFACE = 1, + EDGE = 2, + POINT = 3 + }; + + +protected: + + // Protected Data + + //- Point smoothing method + autoPtr<pointSmoother> pointSmoother_; + + //- Number of point smoother iterations per timestep + const label nPointSmootherIter_; + + + // Mesh quality based relaxation of smoothed position + + //- Relaxation factors to use in each iteration + const scalarList relaxationFactors_; + + //- Per mesh point (including internal) what type + labelList pointTypes_; + + //- Per mesh point the last used relaxation factor + labelList relaxationLevel_; + + //- Relaxed point field + pointField relaxedPoints_; + + + ////- Patches that are to be snapped + //const labelList snapPatches_; + // + ////- FaceZones that are to be snapped + //const labelList snapZones_; + + //- Scaling for snapping + const autoPtr<Function1<scalar>> snapScale_; + + //- Cached per-point coupled status. For guaranteeing contributions + // of coupled points only done once + const bitSet isMasterPoint_; + + //- Create big primitivePatch for all outside and any features on it + const autoPtr<indirectPrimitivePatch> bnd0Ptr_; + + + // Private Member Functions + + //- Collect all non-constraint (i.e. no processor, cyclic, empty etc) + //- patches + static labelList nonConstraintPatches(const polyMesh& mesh); + + //- Create single patch of all supplied faces + static autoPtr<indirectPrimitivePatch> makePatch + ( + const polyMesh& mesh, + const labelList& patchIDs, + const labelList& zoneIDs, + const pointField& points0 + ); + + //- Check with current points + void checkMesh + ( + const pointField& currentPoints, + const vectorField& fCtrs, + const vectorField& fAreas, + const vectorField& cellCtrs, + const scalarField& cellVols, + labelHashSet& markedFaces, + bitSet& markedPoints + ) const; + + //- Apply current constraints (from pointDisplacement) to supplied + // locations + void constrainDisplacement(pointField& points) const; + + //- Relax the points (supplied in pointDisplacement) + bool relax + ( + const scalarList& relaxationFactors, + const bitSet& pointsToRelax, + const pointField& initialPoints, + const pointField& wantedPoints, + pointField& relaxedPoints, + labelList& relaxationLevel + ) const; + label countPos(const labelList& elems) const; + labelList countZeroOrPos(const label size, const labelList& lst) const; + + //- Helper: set in bitSet all elements with a certain value + void select(const labelUList&, const label val, bitSet& isVal) const; + + void laplaceSmooth + ( + const label type, + const pointField& initialPoints, + pointField& newPoints + ) const; + void featLaplaceSmooth + ( + const indirectPrimitivePatch& pp, + const pointField& initialPoints, + pointField& newPoints + ) const; + // Snap points using boundary evaluation ... + void snapBoundaryPoints + ( + const scalar scale, + const pointField& initialPoints, + pointField& newPoints + ) const; + + //- Keep points on empty patches + void emptyCorrectPoints(pointVectorField& pointDisplacement) const; + + +public: + + //- Runtime type information + TypeName("hexMeshSmoother"); + + + // Constructors + + //- Construct from a polyMesh and an IOdictionary + hexMeshSmootherMotionSolver + ( + const polyMesh&, + const IOdictionary& + ); + + //- Construct from components + hexMeshSmootherMotionSolver + ( + const polyMesh& mesh, + const IOdictionary& dict, + const pointVectorField& pointDisplacement, + const pointIOField& points0 + ); + + + //- Destructor + virtual ~hexMeshSmootherMotionSolver(); + + + // Member Functions + + //- Return point location obtained from the current motion field + virtual tmp<pointField> curPoints() const; + + //- Solve for motion + virtual void solve(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/equipotentialPointSmoother/equipotentialPointSmoother.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/equipotentialPointSmoother/equipotentialPointSmoother.C new file mode 100644 index 0000000000000000000000000000000000000000..6eac2e9765af5ee66a6d9c680e803a8c73b477c4 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/equipotentialPointSmoother/equipotentialPointSmoother.C @@ -0,0 +1,148 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. +\*---------------------------------------------------------------------------*/ + +#include "equipotentialPointSmoother.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace pointSmoothers +{ + defineTypeNameAndDebug(equipotentialPointSmoother, 0); + addToRunTimeSelectionTable + ( + pointSmoother, + equipotentialPointSmoother, + dictionary + ); +} +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::pointSmoothers::equipotentialPointSmoother::equipotentialPointSmoother +( + const polyMesh& mesh, + const dictionary& dict +) +: + pointSmoother(mesh, dict) +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::pointSmoothers::equipotentialPointSmoother::calculate +( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement +) const +{ + // Number of points used in each average + scalarField weights(mesh().nPoints(), 0); + + // Reset the displacements which are about to be calculated + reset(facesToMove, weights, pointDisplacement); + + // Sum the non-internal face displacements + forAll(facesToMove, faceToMoveI) + { + const label faceI(facesToMove[faceToMoveI]); + + if (!isInternalOrProcessorFace(faceI)) + { + const face& fPoints(mesh().faces()[faceI]); + + const scalar area(mag(mesh().faceAreas()[faceI])); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + pointDisplacement[pointI] += + area + *( + faceCentres[faceI] + - oldPoints[pointI] + ); + + weights[pointI] += area; + } + } + } + + // Sum the internal face displacements + forAll(facesToMove, faceToMoveI) + { + const label faceI(facesToMove[faceToMoveI]); + + if (isInternalOrProcessorFace(faceI)) + { + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + if (weights[pointI] < SMALL) + { + const labelList& pCells(mesh().pointCells()[pointI]); + + forAll(pCells, pCellI) + { + const label cellI(pCells[pCellI]); + + const scalar volume(mesh().cellVolumes()[cellI]); + + pointDisplacement[pointI] += + volume + *( + cellCentres[cellI] + - oldPoints[pointI] + ); + + weights[pointI] += volume; + } + } + } + } + } + + // Average + average(facesToMove, weights, pointDisplacement); +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/equipotentialPointSmoother/equipotentialPointSmoother.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/equipotentialPointSmoother/equipotentialPointSmoother.H new file mode 100644 index 0000000000000000000000000000000000000000..2ec69312f49e67068f800507c322b47158ec2635 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/equipotentialPointSmoother/equipotentialPointSmoother.H @@ -0,0 +1,105 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::equipotentialPointSmoother + +Description + Equipotential point smoothing. Points are moved towards the centroid of the + surrounding cell volumes. This method tends to equilise cell volumes, and + can generate distorted cells around refinement patterns. + +SourceFiles + equipotentialPointSmoother.C + +\*---------------------------------------------------------------------------*/ + +#ifndef equipotentialPointSmoother_H +#define equipotentialPointSmoother_H + +#include "pointSmoother.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace pointSmoothers +{ + +/*---------------------------------------------------------------------------*\ + Class equipotentialPointSmoother Declaration +\*---------------------------------------------------------------------------*/ + +class equipotentialPointSmoother +: + public pointSmoother +{ +public: + + //- Runtime type information + TypeName("equipotential"); + + + // Constructors + + //- Construct from a dictionary and a polyMesh + equipotentialPointSmoother + ( + const polyMesh& mesh, + const dictionary& dict + ); + + + //- Destructor + virtual ~equipotentialPointSmoother() = default; + + + // Member Functions + + //- Calculate the point displacements + virtual void calculate + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace pointSmoothers +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.C new file mode 100644 index 0000000000000000000000000000000000000000..558f1a5286ad09d4c430494ac6c889b699cfa16d --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.C @@ -0,0 +1,292 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "cellPointConnectivity.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(cellPointConnectivity, 0); +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::cellPointConnectivity::generateCellPointConnectivity(label cellI) +{ + const cell& cFaceLabels(mesh_.cells()[cellI]); + const labelList cPointLabels(cFaceLabels.labels(mesh_.faces())); + const edgeList cEdges(cFaceLabels.edges(mesh_.faces())); + + // Generate a sorted list of points and corresponding point indices + labelPairList pointLabelPointIndices(cPointLabels.size()); + forAll(cPointLabels, pointI) + { + pointLabelPointIndices[pointI] = + labelPair(cPointLabels[pointI], pointI); + } + sort(pointLabelPointIndices); + + // Generate a sorted list of edge labels and corresponding edge indices + // Negative values indicate an edge which runs in an opposite direction to + // the face node listing + labelListList edgeLabelsEdgeIndices + ( + 2*cEdges.size(), + labelList(3, label(-1)) + ); + forAll(cEdges, cEdgeI) + { + edgeLabelsEdgeIndices[2*cEdgeI][0] = cEdges[cEdgeI][0]; + edgeLabelsEdgeIndices[2*cEdgeI][1] = cEdges[cEdgeI][1]; + edgeLabelsEdgeIndices[2*cEdgeI][2] = cEdgeI; + + edgeLabelsEdgeIndices[2*cEdgeI+1][0] = cEdges[cEdgeI][1]; + edgeLabelsEdgeIndices[2*cEdgeI+1][1] = cEdges[cEdgeI][0]; + edgeLabelsEdgeIndices[2*cEdgeI+1][2] = - cEdgeI - 1; + } + sort(edgeLabelsEdgeIndices); + + // Generate a sorted list of edge labels and correspoinding face indices + labelListList edgeLabelsFaceIndices; + forAll(cFaceLabels, cFaceI) + { + const face& cFace(mesh_.faces()[cFaceLabels[cFaceI]]); + + const bool owner(mesh_.faceOwner()[cFaceLabels[cFaceI]] == cellI); + + const label cFaceNEdges(cFace.size()); + forAll(cFace, cFaceEdgeI) + { + edgeLabelsFaceIndices.append(labelList(3, label(-1))); + edgeLabelsFaceIndices.last()[0] = + cFace[(cFaceEdgeI + owner) % cFaceNEdges]; + edgeLabelsFaceIndices.last()[1] = + cFace[(cFaceEdgeI + !owner) % cFaceNEdges]; + edgeLabelsFaceIndices.last()[2] = cFaceI; + } + } + sort(edgeLabelsFaceIndices); + + // Assemble lists of edge-face and cell-face connectivities + // Negative values indicate an edge which runs in an opposite direction to + // the face node listing + labelListList edgeFaceIndices(cEdges.size()); + labelListList faceEdgeIndices(cFaceLabels.size()); + forAll(edgeLabelsFaceIndices, I) + { + const label edgeLabelsEdgeIndex(edgeLabelsEdgeIndices[I][2]); + const label absCellEdgeEdgeIndex + ( + edgeLabelsEdgeIndex >= 0 + ? edgeLabelsEdgeIndex + : - edgeLabelsEdgeIndex - 1 + ); + const label absCellEdgeFaceIndex(edgeLabelsFaceIndices[I][2]); + const label edgeLabelsFaceIndex + ( + edgeLabelsEdgeIndex >= 0 + ? absCellEdgeFaceIndex + : - absCellEdgeFaceIndex - 1 + ); + + edgeFaceIndices[absCellEdgeEdgeIndex].append(edgeLabelsFaceIndex); + faceEdgeIndices[absCellEdgeFaceIndex].append(edgeLabelsEdgeIndex); + } + + // Generate a list of point labels and face index pairs + labelListList pointLabelEdgeIndexFaceIndexPairs; + forAll(cEdges, edgeI) + { + const labelPair pointIndices(cEdges[edgeI]); + + const labelPair faceIndices + ( + edgeFaceIndices[edgeI][0], + edgeFaceIndices[edgeI][1] + ); + const labelPair absFaceIndices + ( + faceIndices[0] >= 0 ? faceIndices[0] : - faceIndices[0] - 1, + faceIndices[1] >= 0 ? faceIndices[1] : - faceIndices[1] - 1 + ); + + const bool order(faceIndices[0] > faceIndices[1]); + + pointLabelEdgeIndexFaceIndexPairs.append(labelList(4, label(-1))); + pointLabelEdgeIndexFaceIndexPairs.last()[0] = pointIndices[0]; + pointLabelEdgeIndexFaceIndexPairs.last()[1] = edgeI; + pointLabelEdgeIndexFaceIndexPairs.last()[2] = absFaceIndices[order]; + pointLabelEdgeIndexFaceIndexPairs.last()[3] = absFaceIndices[!order]; + + pointLabelEdgeIndexFaceIndexPairs.append(labelList(4, label(-1))); + pointLabelEdgeIndexFaceIndexPairs.last()[0] = pointIndices[1]; + pointLabelEdgeIndexFaceIndexPairs.last()[1] = edgeI; + pointLabelEdgeIndexFaceIndexPairs.last()[2] = absFaceIndices[!order]; + pointLabelEdgeIndexFaceIndexPairs.last()[3] = absFaceIndices[order]; + } + sort(pointLabelEdgeIndexFaceIndexPairs); + + // Assemble a list of point face pairs from the sorted lists + labelListList pointEdgeIndices(cPointLabels.size()); + List<List<Pair<label> > > pointFaceIndexPairs(cPointLabels.size()); + { + label I(0); + label pointLabelOld(pointLabelEdgeIndexFaceIndexPairs[0][0]); + forAll + ( + pointLabelEdgeIndexFaceIndexPairs, + pointLabelEdgeIndexFaceIndexPairI + ) + { + const labelList& pointLabelEdgeIndexFaceIndexPair + ( + pointLabelEdgeIndexFaceIndexPairs + [ + pointLabelEdgeIndexFaceIndexPairI + ] + ); + + if (pointLabelOld != pointLabelEdgeIndexFaceIndexPair[0]) + { + I ++; + pointLabelOld = pointLabelEdgeIndexFaceIndexPair[0]; + } + + const label pointI(pointLabelPointIndices[I][1]); + + pointEdgeIndices[pointI].append + ( + pointLabelEdgeIndexFaceIndexPair[1] + ); + + pointFaceIndexPairs[pointI].append + ( + labelPair + ( + pointLabelEdgeIndexFaceIndexPair[2], + pointLabelEdgeIndexFaceIndexPair[3] + ) + ); + } + } + + // Order the point face pairs and assemble a list of point face indices + labelListList pointFaceIndices(cPointLabels.size()); + forAll(pointFaceIndexPairs, pointI) + { + labelPairList& faceIndexPairs(pointFaceIndexPairs[pointI]); + + pointFaceIndices[pointI].append(faceIndexPairs[0][0]); + + for (label pairI = 1; pairI < faceIndexPairs.size(); pairI ++) + { + for (label pairJ = pairI; pairJ < faceIndexPairs.size(); ++ pairJ) + { + if (faceIndexPairs[pairI-1][1] == faceIndexPairs[pairJ][0]) + { + Swap + ( + pointEdgeIndices[pointI][pairI], + pointEdgeIndices[pointI][pairJ] + ); + + Swap + ( + faceIndexPairs[pairI], + faceIndexPairs[pairJ] + ); + + break; + } + } + pointFaceIndices[pointI].append(faceIndexPairs[pairI][0]); + } + } + + // convert to global indices + forAll(cPointLabels, pointI) + { + labelList& edgeIndices(pointEdgeIndices[pointI]); + labelList& faceIndices(pointFaceIndices[pointI]); + + const label nPointFaces(faceIndices.size()); + + cellPointPoints_[cellI][pointI].resize(nPointFaces); + + forAll(edgeIndices, edgeI) + { + cellPointPoints_[cellI][pointI][edgeI] = + cEdges[edgeIndices[edgeI]] + [ + cEdges[edgeIndices[edgeI]][0] == cPointLabels[pointI] + ]; + } + + cellPointFaces_[cellI][pointI].resize(nPointFaces); + + forAll(faceIndices, faceI) + { + cellPointFaces_[cellI][pointI][faceI] = + cFaceLabels + [ + faceIndices[faceI] + ]; + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::cellPointConnectivity::cellPointConnectivity(const polyMesh& mesh) +: + MoveableMeshObject<polyMesh>(typeName, mesh), + mesh_(mesh), + cellPointPoints_(mesh.nCells()), + cellPointFaces_(mesh.nCells()) +{ + forAll(mesh.cells(), cellI) + { + const label nPoints(mesh.cellPoints()[cellI].size()); + + cellPointPoints_[cellI].resize(nPoints); + cellPointFaces_[cellI].resize(nPoints); + + generateCellPointConnectivity(cellI); + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::cellPointConnectivity::~cellPointConnectivity() +{} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.H new file mode 100644 index 0000000000000000000000000000000000000000..1c850a0e9c113591fe63358160894216478636ec --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/cellPointConnectivity/cellPointConnectivity.H @@ -0,0 +1,139 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::cellPointConnectivity + +Description + This class provides ordered connectivity for each point of each cell. Lists + are available of the points and faces surrounding each point of a cell. The + lists are ordered so that the connected points describe a polygonal cone. + For a convex cell, any three sequantial cone edges form a positive basis. + +SourceFiles + cellPointConnectivity.C + +\*---------------------------------------------------------------------------*/ + +#ifndef cellPointConnectivity_H +#define cellPointConnectivity_H + +#include "polyMesh.H" +#include "MeshObject.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class cellPointConnectivity Declaration +\*---------------------------------------------------------------------------*/ + +class cellPointConnectivity +: + public MoveableMeshObject<polyMesh> +{ + // Private data + + //- Reference to the polyMesh + const polyMesh& mesh_; + + //- Lists of point-point connections + labelListListList cellPointPoints_; + + //- Lists of point-face connections + labelListListList cellPointFaces_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + cellPointConnectivity(const cellPointConnectivity&); + + //- Disallow default bitwise assignment + void operator=(const cellPointConnectivity&); + + //- Generate the connectivity + void generateCellPointConnectivity(label cellI); + + +public: + + // Run-time type information + TypeName("cellPointConnectivity"); + + + // Constructors + + //- Construct an IOobject and a polymesh + cellPointConnectivity(const polyMesh&); + + + //- Destructor + ~cellPointConnectivity(); + + + // Member Functions + + // Access + + //- Access the point-point connections + const labelListListList& cellPointPoints() const + { + return cellPointPoints_; + } + + //- Access the point-face connections + const labelListListList& cellPointFaces() const + { + return cellPointFaces_; + } + + // Edit + + //- No action required on move points + virtual bool movePoints() + { + return true; + } + + //- Dummy write for regIOobject + virtual bool writeData(Ostream&) const + { + return true; + } +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.C new file mode 100644 index 0000000000000000000000000000000000000000..42ee536d7ac1c9ed8e1502065ff2e012062c081d --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.C @@ -0,0 +1,479 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "geometricElementTransformPointSmoother.H" +#include "cellPointConnectivity.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace pointSmoothers +{ + defineTypeNameAndDebug(geometricElementTransformPointSmoother, 0); + addToRunTimeSelectionTable + ( + pointSmoother, + geometricElementTransformPointSmoother, + dictionary + ); +} +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::scalar +Foam::pointSmoothers::geometricElementTransformPointSmoother::cellQuality +( + const polyMesh& mesh, + const pointField& currentPoints, + const cellPointConnectivity& connectivity, + const label celli +) +{ + const cell& cFaces = mesh.cells()[celli]; + const labelList cPoints(cFaces.labels(mesh.faces())); + + // Calculate a transformed point for each cell point + + scalar cellQ = 0.0; + label nTets = 0; + + forAll(cPoints, cPointi) + { + const label pointi(cPoints[cPointi]); + const point& pt = currentPoints[pointi]; + const labelList& pPoints + ( + connectivity.cellPointPoints()[celli][cPointi] + ); + if (pPoints.size() != 3) + { + WarningInFunction<< "Cell:" << celli + << " point:" << pointi + << " connected points:" << pPoints << endl; + } + else + { + const Tensor<scalar> mA + ( + currentPoints[pPoints[0]] - pt, + currentPoints[pPoints[1]] - pt, + currentPoints[pPoints[2]] - pt + ); + const scalar sigma(det(mA)); + + if (sigma < ROOTVSMALL) + { + return 0; + } + + // 3 * pow(sigma, 2.0/3.0)/magSqr(mA) + const scalar tetQ = + scalar(3) * Foam::cbrt(Foam::sqr(sigma)) / magSqr(mA); + cellQ += tetQ; + nTets++; + } + } + + return cellQ/nTets; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::pointSmoothers::geometricElementTransformPointSmoother:: +geometricElementTransformPointSmoother +( + const polyMesh& mesh, + const dictionary& dict +) +: + pointSmoother(mesh, dict), + transformationParameter_ + ( + readScalar(dict.lookup("transformationParameter")) + ) +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::pointSmoothers::geometricElementTransformPointSmoother::calculate +( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement +) const +{ + // Lookup or generate the cell-point connectivity/ + const cellPointConnectivity& connectivity = + MeshObject<polyMesh, MoveableMeshObject, cellPointConnectivity>::New + ( + mesh() + ); + + // Number of points used in each average + labelField counts(mesh().nPoints(), -1); + + // Reset the displacements which are about to be calculated + reset(facesToMove, counts, pointDisplacement); + + // Identify the cells which are to be moved + labelHashSet cellsToMove(facesToMove.size()*2/3); + forAll(facesToMove, faceToMoveI) + { + const label faceI(facesToMove[faceToMoveI]); + + cellsToMove.insert(mesh().faceOwner()[faceI]); + + if (mesh().isInternalFace(faceI)) + { + cellsToMove.insert(mesh().faceNeighbour()[faceI]); + } + } + + // Transformed point field + pointField transformedPoints(currentPoints); + + // Calculate the internal transformations + forAllConstIter(labelHashSet, cellsToMove, iter) + { + const label cellI(iter.key()); + + const cell& cFaces + ( + mesh().cells()[cellI] + ); + const labelList cPoints + ( + cFaces.labels(mesh().faces()) + ); + const edgeList cEdges + ( + cFaces.edges(mesh().faces()) + ); + + // Calculate a transformed point for each cell point + forAll(cPoints, cPointI) + { + const label pointI(cPoints[cPointI]); + + if (counts[pointI] == -1) continue; + + const labelList& pPoints + ( + connectivity.cellPointPoints()[cellI][cPointI] + ); + const labelList& pFaces + ( + connectivity.cellPointFaces()[cellI][cPointI] + ); + const label nPPoints(pPoints.size()); + + // Initial guess of the dual face centre + vector dualAverage(vector::zero); + forAll(pPoints, pPointI) + { + dualAverage += + currentPoints[pPoints[pPointI]] + + faceCentres[pFaces[pPointI]]; + } + dualAverage /= 2*nPPoints; + + // Calculate the dual face centre and normal + vector dualNormal(vector::zero); + forAll(pPoints, pPointI) + { + const label nextPPointI((pPointI + 1) % nPPoints); + + point edgeCentre + ( + 0.5 + *( + currentPoints[pPoints[pPointI]] + + currentPoints[pointI] + ) + ); + point nextFaceCentre + ( + faceCentres[pFaces[nextPPointI]] + ); + point nextEdgeCentre + ( + 0.5 + *( + currentPoints[pPoints[nextPPointI]] + + currentPoints[pointI] + ) + ); + + dualNormal += + (nextFaceCentre - edgeCentre) + ^(edgeCentre - dualAverage); + dualNormal += + (nextEdgeCentre - nextFaceCentre) + ^(nextFaceCentre - dualAverage); + } + vector dualNormalHat(dualNormal/max(mag(dualNormal), ROOTVSMALL)); + + scalar sumA(0); + vector sumAc(vector::zero); + forAll(pPoints, pPointI) + { + const label nextPPointI((pPointI + 1) % nPPoints); + + point edgeCentre + ( + 0.5 + *( + currentPoints[pPoints[pPointI]] + + currentPoints[pointI] + ) + ); + point nextFaceCentre + ( + faceCentres[pFaces[nextPPointI]] + ); + point nextEdgeCentre + ( + 0.5 + *( + currentPoints[pPoints[nextPPointI]] + + currentPoints[pointI] + ) + ); + + vector c1 = edgeCentre + nextFaceCentre + dualAverage; + vector c2 = nextFaceCentre + nextEdgeCentre + dualAverage; + + vector n1 = + (nextFaceCentre - edgeCentre) + ^(edgeCentre - dualAverage); + vector n2 = + (nextEdgeCentre - nextFaceCentre) + ^(nextFaceCentre - dualAverage); + + scalar a1 = n1 & dualNormalHat; + scalar a2 = n2 & dualNormalHat; + + sumA += a1 + a2; + sumAc += a1*c1 + a2*c2; + } + + const vector dualCentre(sumAc/max(sumA, ROOTVSMALL)/3); + + // Calculate the transformed point + transformedPoints[pointI] = + dualCentre + + transformationParameter_ + *dualNormal/sqrt(max(mag(dualNormal), ROOTVSMALL)); + } + + // Length scale + scalar lengthScale(0), transformedLengthScale(0); + forAll(cEdges, cEdgeI) + { + lengthScale += + cEdges[cEdgeI].mag(currentPoints); + transformedLengthScale += + cEdges[cEdgeI].mag(transformedPoints); + } + lengthScale /= cEdges.size(); + transformedLengthScale /= cEdges.size(); + + const scalar lengthScaleRatio = + ( + (transformedLengthScale > SMALL) + ? lengthScale/transformedLengthScale + : scalar(0) + ); + + // Add the displacement to the average + forAll(cPoints, cPointI) + { + const label pointI(cPoints[cPointI]); + + if (counts[pointI] == -1) continue; + + const vector newPoint + ( + cellCentres[cellI] + + lengthScaleRatio + *( + transformedPoints[pointI] + - cellCentres[cellI] + ) + ); + + ++ counts[pointI]; + + pointDisplacement[pointI] += newPoint - oldPoints[pointI]; + } + } + + // Reset all the boundary faces + reset(facesToMove, counts, pointDisplacement, false); + + // Calculate the boundary transformations + forAll(facesToMove, faceToMoveI) + { + const label faceI(facesToMove[faceToMoveI]); + + if (!isInternalOrProcessorFace(faceI)) + { + const labelList& fPoints(mesh().faces()[faceI]); + + // Face normal + vector faceNormalHat(faceAreas[faceI]); + faceNormalHat /= max(SMALL, mag(faceNormalHat)); + + // Calculate a transformed point for each face point + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + const label fPointIPrev + ( + (fPointI - 1 + fPoints.size()) % fPoints.size() + ); + const label fPointINext + ( + (fPointI + 1) % fPoints.size() + ); + + const vector dualCentre + ( + currentPoints[pointI]/2 + + ( + currentPoints[fPoints[fPointINext]] + + currentPoints[fPoints[fPointIPrev]] + )/4 + ); + const vector dualNormal + ( + ( + currentPoints[fPoints[fPointINext]] + - currentPoints[fPoints[fPointIPrev]] + )/2 + ^faceNormalHat + ); + + transformedPoints[pointI] = + dualCentre + + transformationParameter_ + *dualNormal/sqrt(max(mag(dualNormal), ROOTVSMALL)); + } + + // Length scale + scalar lengthScale(0), transformedLengthScale(0); + forAll(fPoints, fPointI) + { + const label fPointINext((fPointI + 1)%fPoints.size()); + + const label pointI(fPoints[fPointI]); + const label pointINext(fPoints[fPointINext]); + + lengthScale += mag + ( + currentPoints[pointINext] - currentPoints[pointI] + ); + transformedLengthScale += mag + ( + transformedPoints[pointINext] - transformedPoints[pointI] + ); + } + lengthScale /= fPoints.size(); + transformedLengthScale /= fPoints.size(); + + const scalar lengthScaleRatio + ( + (transformedLengthScale > SMALL) + ? lengthScale/transformedLengthScale + : scalar(0) + ); + + // Add the displacement to the average + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + const vector newPoint + ( + faceCentres[faceI] + + lengthScaleRatio + *( + transformedPoints[pointI] + - faceCentres[faceI] + ) + ); + + ++ counts[pointI]; + + pointDisplacement[pointI] += newPoint - oldPoints[pointI]; + } + } + } + + // Average + average(facesToMove, counts, pointDisplacement); +} + + +Foam::tmp<Foam::scalarField> +Foam::pointSmoothers::geometricElementTransformPointSmoother::cellQuality +( + const polyMesh& mesh, + const pointField& currentPoints +) +{ + const cellPointConnectivity& connectivity = + MeshObject<polyMesh, MoveableMeshObject, cellPointConnectivity>::New + ( + mesh + ); + + tmp<scalarField> tfld(tmp<scalarField>::New(mesh.nCells())); + scalarField& fld = tfld.ref(); + + forAll(fld, celli) + { + fld[celli] = cellQuality(mesh, currentPoints, connectivity, celli); + } + + return tfld; +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.H new file mode 100644 index 0000000000000000000000000000000000000000..53b5332382fead717ebda5f1d6ffdfe66bf93ded --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/geometricElementTransformPointSmoother/geometricElementTransformPointSmoother.H @@ -0,0 +1,149 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::pointSmoothers::geometricElementTransformPointSmoother + +Description + Geometric Element Transformation Method (GETMe) point smoother. Points are + moved in a direction normal to the face of the dual element. This tends to + orthogonalise elements. This method can "push" as well as "pull". + + The original references for this method only formulate it for a limited + variety of specific polyhedra. This version is written for arbitrary + polyhedra, and most closely follows the following reference: + + \verbatim + "Fast smoothing of mixed volume meshes based on the effective geometric + element transformation method" + Dimitris Vartziotis, Joachim Wipper, + Comput. Methods Appl. Mech. Engrg. 201-204 (2012) 65-81 + \endverbatim + + This implementation does not include the various specific measures employed + in the referred article to improve the quality of types of irregular + polyhedra. It also does not use the same quality criteria as these are only + suitable for cell vertices with exactly three connecting edges. + +SourceFiles + geometricElementTransformPointSmoother.C + +\*---------------------------------------------------------------------------*/ + +#ifndef geometricElementTransformPointSmoother_H +#define geometricElementTransformPointSmoother_H + +#include "pointSmoother.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class cellPointConnectivity; + +namespace pointSmoothers +{ + +/*---------------------------------------------------------------------------*\ + Class geometricElementTransformPointSmoother Declaration +\*---------------------------------------------------------------------------*/ + +class geometricElementTransformPointSmoother +: + public pointSmoother +{ +private: + + // Private Data + + //- Transformation parameter + const scalar transformationParameter_; + + + // Private Member Functions + + static scalar cellQuality + ( + const polyMesh& mesh, + const pointField& currentPoints, + const cellPointConnectivity& connectivity, + const label celli + ); + + +public: + + //- Runtime type information + TypeName("geometricElementTransform"); + + + // Constructors + + //- Construct from a dictionary and a mesh + geometricElementTransformPointSmoother + ( + const polyMesh& mesh, + const dictionary& dict + ); + + + //- Destructor + virtual ~geometricElementTransformPointSmoother() = default; + + + // Member Functions + + //- Calculate the point displacements + virtual void calculate + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement + ) const; + + static tmp<scalarField> cellQuality + ( + const polyMesh& mesh, + const pointField& currentPoints + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace pointSmoothers +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianConstraintPointSmoother.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianConstraintPointSmoother.C new file mode 100644 index 0000000000000000000000000000000000000000..126f3dc969daca867a8fc808edbb6c5bd7118956 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianConstraintPointSmoother.C @@ -0,0 +1,164 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "laplacianConstraintPointSmoother.H" +#include "addToRunTimeSelectionTable.H" +#include "meshPointPatch.H" +#include "processorPointPatch.H" +#include "pointConstraint.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace pointSmoothers +{ + defineTypeNameAndDebug(laplacianConstraintPointSmoother, 0); + addToRunTimeSelectionTable + ( + pointSmoother, + laplacianConstraintPointSmoother, + dictionary + ); +} +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::pointSmoothers::laplacianConstraintPointSmoother:: +laplacianConstraintPointSmoother +( + const polyMesh& mesh, + const dictionary& dict +) +: + pointSmoother(mesh, dict) +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::pointSmoothers::laplacianConstraintPointSmoother::calculate +( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement +) const +{ + // Get pointMesh so we can get at the constraints + const auto& pMesh = pointMesh::New(mesh()); + + // Number of points used in each average + labelField counts(mesh().nPoints(), 0); + + // Reset the displacements which are about to be calculated + reset(facesToMove, counts, pointDisplacement); + + // Get affected points + const bitSet isMovingPoint(pointsToMove(facesToMove, true)); + + + // Set constraints: + // - internal points : 0 + // - normal boundary points : 1 + // - meshPointPatch : 1 (surface) + // 2 (feat-edge) + // 3 (feat-point) + labelList nConstraints(mesh().nPoints(), Zero); + + for (const auto& pp : pMesh.boundary()) + { + const auto& mp = pp.meshPoints(); + const auto* mppPtr = isA<meshPointPatch>(pp); + if (mppPtr) + { + const auto& pc = mppPtr->constraints(); + forAll(mp, i) + { + nConstraints[mp[i]] = pc[i].first(); + } + } + else //if (!isA<processorPointPatch>(pp)) // what about cyclic? AMI? + { + forAll(mp, i) + { + // Indirectly detect any constraint + pointConstraint pc; + pp.applyConstraint(i, pc); + nConstraints[mp[i]] = pc.first(); + } + } + } + + + // Average from equally constrained points + + const auto& edges = mesh().edges(); + const auto& pointEdges = mesh().pointEdges(); + forAll(pointEdges, pointi) + { + if (isMovingPoint[pointi]) + { + const auto& pEdges = pointEdges[pointi]; + for (const label edgei : pEdges) + { + const label otherPointi = edges[edgei].otherVertex(pointi); + if (nConstraints[otherPointi] >= nConstraints[pointi]) + { + pointDisplacement[pointi] += + currentPoints[otherPointi] + - oldPoints[pointi]; + + ++ counts[pointi]; + } + } + } + } + + // Average + average(facesToMove, counts, pointDisplacement); + + + // Make sure to set any unconnected points (or boundary feature points) + // since otherwise they never see the effect of the boundary conditions + forAll(counts, pointi) + { + if (isMovingPoint[pointi] && !counts[pointi]) + { + pointDisplacement[pointi] = currentPoints[pointi]-oldPoints[pointi]; + } + } +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianConstraintPointSmoother.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianConstraintPointSmoother.H new file mode 100644 index 0000000000000000000000000000000000000000..ebe348e33cd99cb26b643795ff3e4af9d420d86e --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianConstraintPointSmoother.H @@ -0,0 +1,105 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::laplacianConstraintPointSmoother + +Description + Laplacian point smoothing. Points are moved towards the average of the + surrounding points. In case of constraints (boundary points) only + use average of equal or higher constrained points. + +SourceFiles + laplacianConstraintPointSmoother.C + +\*---------------------------------------------------------------------------*/ + +#ifndef laplacianConstraintPointSmoother_H +#define laplacianConstraintPointSmoother_H + +#include "pointSmoother.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace pointSmoothers +{ + +/*---------------------------------------------------------------------------*\ + Class laplacianConstraintPointSmoother Declaration +\*---------------------------------------------------------------------------*/ + +class laplacianConstraintPointSmoother +: + public pointSmoother +{ +public: + + //- Runtime type information + TypeName("laplacianConstraint"); + + + // Constructors + + //- Construct from a dictionary and a polyMesh + laplacianConstraintPointSmoother + ( + const polyMesh& mesh, + const dictionary& dict + ); + + + //- Destructor + virtual ~laplacianConstraintPointSmoother() = default; + + + // Member Functions + + //- Calculate the point displacement + virtual void calculate + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace pointSmoothers +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianPointSmoother.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianPointSmoother.C new file mode 100644 index 0000000000000000000000000000000000000000..c07cc84eda23fc3204ec7037e217bdc97481e11a --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianPointSmoother.C @@ -0,0 +1,139 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "laplacianPointSmoother.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace pointSmoothers +{ + defineTypeNameAndDebug(laplacianPointSmoother, 0); + addToRunTimeSelectionTable + ( + pointSmoother, + laplacianPointSmoother, + dictionary + ); +} +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::pointSmoothers::laplacianPointSmoother::laplacianPointSmoother +( + const polyMesh& mesh, + const dictionary& dict +) +: + pointSmoother(mesh, dict) +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::pointSmoothers::laplacianPointSmoother::calculate +( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement +) const +{ + // Number of points used in each average + labelField counts(mesh().nPoints(), 0); + + // Reset the displacements which are about to be calculated + reset(facesToMove, counts, pointDisplacement); + + // Sum the non-internal face displacements + forAll(facesToMove, faceToMoveI) + { + const label faceI(facesToMove[faceToMoveI]); + + if (!isInternalOrProcessorFace(faceI)) + { + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + pointDisplacement[pointI] += + faceCentres[faceI] + - oldPoints[pointI]; + + ++ counts[pointI]; + } + } + } + + // Sum the internal face displacements + forAll(facesToMove, faceToMoveI) + { + const label faceI(facesToMove[faceToMoveI]); + + if (isInternalOrProcessorFace(faceI)) + { + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + if (counts[pointI] == 0) + { + const labelList& pCells(mesh().pointCells()[pointI]); + + forAll(pCells, pCellI) + { + const label cellI(pCells[pCellI]); + + pointDisplacement[pointI] += + cellCentres[cellI] + - oldPoints[pointI]; + + ++ counts[pointI]; + } + } + } + } + } + + // Average + average(facesToMove, counts, pointDisplacement); +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianPointSmoother.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianPointSmoother.H new file mode 100644 index 0000000000000000000000000000000000000000..500e6aa71a59e278a0843ded97b99666865ef676 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/laplacianPointSmoother/laplacianPointSmoother.H @@ -0,0 +1,105 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::laplacianPointSmoother + +Description + Laplacian point smoothing (or rather Lloyds). Points are moved towards + the average of the surrounding cell centres (or average of boundary + face centres for points on boundary) + +SourceFiles + laplacianPointSmoother.C + +\*---------------------------------------------------------------------------*/ + +#ifndef laplacianPointSmoother_H +#define laplacianPointSmoother_H + +#include "pointSmoother.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace pointSmoothers +{ + +/*---------------------------------------------------------------------------*\ + Class laplacianPointSmoother Declaration +\*---------------------------------------------------------------------------*/ + +class laplacianPointSmoother +: + public pointSmoother +{ +public: + + //- Runtime type information + TypeName("laplacian"); + + + // Constructors + + //- Construct from a dictionary and a polyMesh + laplacianPointSmoother + ( + const polyMesh& mesh, + const dictionary& dict + ); + + + //- Destructor + virtual ~laplacianPointSmoother() = default; + + + // Member Functions + + //- Calculate the point displacement + virtual void calculate + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace pointSmoothers +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmoother.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmoother.C new file mode 100644 index 0000000000000000000000000000000000000000..ed6eee487e00def8364f191a36d557fb444e1c1a --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmoother.C @@ -0,0 +1,300 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "pointSmoother.H" +#include "pointConstraints.H" +#include "polyMeshTools.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(pointSmoother, 0); + defineRunTimeSelectionTable(pointSmoother, dictionary); +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +bool Foam::pointSmoother::isInternalOrProcessorFace(const label faceI) const +{ + if (mesh().isInternalFace(faceI)) + { + return true; + } + + if + ( + processorPatchIDs_ + [ + mesh().boundaryMesh().patchID() + [ + faceI - mesh().nInternalFaces() + ] + ] + ) + { + return true; + } + + return false; +} + + +Foam::autoPtr<Foam::PackedBoolList> Foam::pointSmoother::pointsToMove +( + const labelList& facesToMove, + const bool moveInternalFaces +) const +{ + autoPtr<PackedBoolList> markerPtr + ( + new PackedBoolList(mesh().nPoints(), false) + ); + + PackedBoolList& marker(markerPtr()); + + forAll(facesToMove, faceToMoveI) + { + const label faceI(facesToMove[faceToMoveI]); + + if (moveInternalFaces || !isInternalOrProcessorFace(faceI)) + { + const face& fPoints(mesh().faces()[faceI]); + + forAll(fPoints, fPointI) + { + const label pointI(fPoints[fPointI]); + + marker[pointI] = true; + } + } + } + + syncTools::syncPointList + ( + mesh(), + marker, + orEqOp<unsigned int>(), + 0U + ); + + return markerPtr; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::pointSmoother::pointSmoother +( + const polyMesh& mesh, + const dictionary& dict +) +: + mesh_(mesh) +{ + for (const auto& pp : mesh.boundaryMesh()) + { + if (isA<processorPolyPatch>(pp)) + { + processorPatchIDs_.insert(pp.index()); + } + } +} + + +// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::pointSmoother> +Foam::pointSmoother::New +( + const word& pointSmootherType, + const polyMesh& mesh, + const dictionary& dict +) +{ + Info<< "Selecting pointSmoother type " << pointSmootherType << endl; + + auto cstrIter = dictionaryConstructorTablePtr_->find(pointSmootherType); + + if (cstrIter == dictionaryConstructorTablePtr_->end()) + { + FatalErrorIn("pointSmoother::New") + << "Unknown " << typeName << " type " + << pointSmootherType << endl << endl + << "Valid " << typeName << " types are : " << endl + << dictionaryConstructorTablePtr_->sortedToc() + << exit(FatalError); + } + + return cstrIter()(mesh, dict); +} + + +Foam::autoPtr<Foam::pointSmoother> +Foam::pointSmoother::New +( + const polyMesh& mesh, + const dictionary& dict +) +{ + word pointSmootherType(dict.lookup(typeName)); + + return New(pointSmootherType, mesh, dict); +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::pointSmoother::~pointSmoother() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::pointSmoother::update +( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + pointVectorField& pointDisplacement, + const bool correctBCs +) const +{ + // Apply point smoothing (without boundary conditions!) + calculate + ( + facesToMove, + oldPoints, + currentPoints, + faceCentres, + faceAreas, + cellCentres, + cellVolumes, + pointDisplacement.ref() + ); + + // Note: do not want to apply boundary conditions whilst smoothing so + // disable for now + //// Take over boundary values + //for (auto& ppf : pointDisplacement.boundaryFieldRef()) + //{ + // ppf.operator==(ppf.patchInternalField()); + //} + + if (correctBCs) + { + // Apply (multi-)patch constraints + pointConstraints::New + ( + pointDisplacement().mesh() + ).constrainDisplacement(pointDisplacement); + } +} + + +Foam::tmp<Foam::scalarField> Foam::pointSmoother::faceQuality +( + const pointField& points, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes +) const +{ + // See e.g. + // - src/functionObjects/field/stabilityBlendingFactor/ + // stabilityBlendingFactor.H + // - maybe add function to motionSmootherCheck to return value instead + // of yes/no for invalid? + // - for now just look at non-ortho + + tmp<scalarField> tortho + ( + polyMeshTools::faceOrthogonality + ( + mesh(), + faceAreas, + cellCentres + ) + ); + + //return max(tortho, scalar(0.0)); + return tortho; +} + + +Foam::tmp<Foam::scalarField> Foam::pointSmoother::cellQuality +( + const pointField& points, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes +) const +{ + // Get face-based non-ortho + tmp<scalarField> tfaceOrtho + ( + faceQuality + ( + points, + faceCentres, + faceAreas, + cellCentres, + cellVolumes + ) + ); + const auto& faceOrtho = tfaceOrtho(); + + // Min over cells + tmp<scalarField> tortho(new scalarField(mesh().nCells(), GREAT)); + auto& ortho = tortho.ref(); + + const auto& own = mesh().faceOwner(); + const auto& nei = mesh().faceNeighbour(); + + forAll(own, facei) + { + auto& o = ortho[own[facei]]; + o = min(o, faceOrtho[facei]); + } + for (label facei = 0; facei < mesh().nInternalFaces(); facei++) + { + auto& o = ortho[nei[facei]]; + o = min(o, faceOrtho[facei]); + } + + return tortho; +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmoother.H b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmoother.H new file mode 100644 index 0000000000000000000000000000000000000000..4b4b356060391cb71e9c4e668cb2047288f538f7 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmoother.H @@ -0,0 +1,279 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::pointSmoother + +Description + Abstract base class for point smoothing methods. Handles parallel + communication via reset and average functions. + +SourceFiles + pointSmoother.C + pointSmootherTemplates.C + +\*---------------------------------------------------------------------------*/ + +#ifndef pointSmoother_H +#define pointSmoother_H + +#include "polyMeshGeometry.H" +#include "runTimeSelectionTables.H" +#include "PackedBoolList.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class pointSmoother Declaration +\*---------------------------------------------------------------------------*/ + +class pointSmoother +{ +private: + + // Private data + + //- Reference to the polyMesh + const polyMesh& mesh_; + + //- Set of the processor patch indices + labelHashSet processorPatchIDs_; + + + // Private Member Functions + + //- Disallow default bitwise copy construct + pointSmoother(const pointSmoother&); + + //- Disallow default bitwise assignment + void operator=(const pointSmoother&); + + +protected: + + // Protected Member Functions + + //- Test if the given face is internal or on a processor boundary + bool isInternalOrProcessorFace(const label faceI) const; + + //- Get a boolean list of the points to be moved + autoPtr<PackedBoolList> pointsToMove + ( + const labelList& facesToMove, + const bool moveInternalFaces + ) const; + + //- Reset the relevant weights and displacements to zero + template <class weightType> + void reset + ( + const labelList& facesToMove, + Field<weightType>& weights, + vectorField& pointDisplacement, + const bool resetInternalFaces = true + ) const; + + //- Average the displacements using the weights provided + template <class weightType> + void average + ( + const labelList& facesToMove, + Field<weightType>& weights, + vectorField& pointDisplacement + ) const; + + +public: + + //- Runtime type information + TypeName("pointSmoother"); + + + // Declare run-time constructor selection table + declareRunTimeSelectionTable + ( + autoPtr, + pointSmoother, + dictionary, + (const polyMesh& mesh, const dictionary& dict), + (mesh, dict) + ); + + + // Constructors + + //- Construct from a dictionary and a point displacement field + pointSmoother(const polyMesh& mesh, const dictionary&); + + + // Selector + + //- Construct given type + static autoPtr<pointSmoother> New + ( + const word& pointSmootherType, + const polyMesh& mesh, + const dictionary& dict + ); + + //- Construct with type looked up from dictionary + static autoPtr<pointSmoother> New + ( + const polyMesh& mesh, + const dictionary& dict + ); + + + //- Destructor + virtual ~pointSmoother(); + + + // Member Functions + + // Access the mesh + const polyMesh& mesh() const + { + return mesh_; + } + + //- Update the point displacements and apply constraints + void update + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + pointVectorField& pointDisplacement, + const bool correctBCs = true + ) const; + + //- Update the point displacements and apply constraints + void update + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const polyMeshGeometry& meshGeometry, + pointVectorField& pointDisplacement, + const bool correctBCs = true + ) const + { + update + ( + facesToMove, + oldPoints, + currentPoints, + meshGeometry.faceCentres(), + meshGeometry.faceAreas(), + meshGeometry.cellCentres(), + meshGeometry.cellVolumes(), + pointDisplacement, + correctBCs + ); + } + + //- Calculate the point displacement + virtual void calculate + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes, + vectorField& pointDisplacement + ) const = 0; + + //- Update the point displacements + virtual void calculate + ( + const labelList& facesToMove, + const pointField& oldPoints, + const pointField& currentPoints, + const polyMeshGeometry& meshGeometry, + vectorField& pointDisplacement + ) const + { + calculate + ( + facesToMove, + oldPoints, + currentPoints, + meshGeometry.faceCentres(), + meshGeometry.faceAreas(), + meshGeometry.cellCentres(), + meshGeometry.cellVolumes(), + pointDisplacement + ); + } + + //- Check element quality: 1 = best, 0 = invalid. (also negative?) + //- Topology from mesh, point locations supplied. + //- Move to motionSolver level? + virtual tmp<scalarField> faceQuality + ( + const pointField& points, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes + ) const; + + //- Check element quality: 1 = best, 0 = invalid. + //- Topology from mesh, point locations supplied. + //- Move to motionSolver level? + virtual tmp<scalarField> cellQuality + ( + const pointField& points, + const pointField& faceCentres, + const vectorField& faceAreas, + const pointField& cellCentres, + const scalarField& cellVolumes + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "pointSmootherTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmootherTemplates.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmootherTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..1e74e6943ef1be9d27ddf34942ff0b2d998f1da0 --- /dev/null +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/pointSmoothers/pointSmoother/pointSmootherTemplates.C @@ -0,0 +1,105 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "pointSmoother.H" +#include "syncTools.H" + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +template <class weightType> +void Foam::pointSmoother::reset +( + const labelList& facesToMove, + Field<weightType>& weights, + vectorField& pointDisplacement, + const bool resetInternalFaces +) const +{ + autoPtr<PackedBoolList> resetPointsPtr + ( + pointsToMove(facesToMove, resetInternalFaces) + ); + + const PackedBoolList& resetPoints(resetPointsPtr); + + forAll(resetPoints, pointI) + { + if (resetPoints[pointI]) + { + weights[pointI] = pTraits<weightType>::zero; + pointDisplacement[pointI] = vector::zero; + } + } +} + + +template <class weightType> +void Foam::pointSmoother::average +( + const labelList& facesToMove, + Field<weightType>& weights, + vectorField& pointDisplacement +) const +{ + syncTools::syncPointList + ( + mesh(), + weights, + plusEqOp<weightType>(), + pTraits<weightType>::zero + ); + + syncTools::syncPointList + ( + mesh(), + pointDisplacement, + plusEqOp<vector>(), + vector::zero + ); + + autoPtr<PackedBoolList> averagePointsPtr + ( + pointsToMove(facesToMove, true) + ); + + const PackedBoolList& averagePoints(averagePointsPtr); + + forAll(averagePoints, pointI) + { + if + ( + averagePoints[pointI] + && weights[pointI] != pTraits<weightType>::zero + ) + { + pointDisplacement[pointI] /= weights[pointI]; + } + } +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C index c369d7246ebb6e674018d8d98ed7134bd171211b..4d3d5f5454e5955a8dad0be75b536ae31593693c 100644 --- a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C +++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2015-2022 OpenCFD Ltd. + Copyright (C) 2015-2022,2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -46,8 +46,8 @@ namespace Foam { defineTypeNameAndDebug(addPatchCellLayer, 0); - // Reduction class to get minimum value over face. - class minEqOpFace + // Reduction class to get maximum value over coupled face. + class combineEqOpFace { public: @@ -57,10 +57,18 @@ namespace Foam { if (y.size()) { + if (x.size() != y.size()) + { + FatalErrorInFunction + << "face x:" << flatOutput(x) + << " face y:" << flatOutput(y) + << exit(FatalError); + } + label j = 0; forAll(x, i) { - x[i] = min(x[i], y[j]); + x[i] = max(x[i], y[j]); j = y.rcIndex(j); } @@ -78,7 +86,6 @@ namespace Foam } } }; - } @@ -464,6 +471,7 @@ void Foam::addPatchCellLayer::setFaceProps { patchi = mesh.boundaryMesh().whichPatch(facei); zonei = mesh.faceZones().whichZone(facei); + zoneFlip = false; if (zonei != -1) { label index = mesh.faceZones()[zonei].whichFace(facei); @@ -548,61 +556,61 @@ void Foam::addPatchCellLayer::setFaceProps } -void Foam::addPatchCellLayer::findZoneFace -( - const bool useInternalFaces, - const bool useBoundaryFaces, - - const polyMesh& mesh, - const indirectPrimitivePatch& pp, - const label ppEdgeI, - const labelUIndList& excludeFaces, - const labelList& meshFaces, - - label& inflateFaceI, - label& patchI, - label& zoneI, - bool& zoneFlip -) -{ - inflateFaceI = -1; - patchI = -1; - zoneI = -1; - zoneFlip = false; - - forAll(meshFaces, k) - { - label faceI = meshFaces[k]; - - if - ( - !excludeFaces.found(faceI) - && ( - (mesh.isInternalFace(faceI) && useInternalFaces) - || (!mesh.isInternalFace(faceI) && useBoundaryFaces) - ) - ) - { - setFaceProps - ( - mesh, - pp, - ppEdgeI, - faceI, - - patchI, - zoneI, - zoneFlip, - inflateFaceI - ); - - if (zoneI != -1 || patchI != -1) - { - break; - } - } - } -} +//void Foam::addPatchCellLayer::findZoneFace +//( +// const bool useInternalFaces, +// const bool useBoundaryFaces, +// +// const polyMesh& mesh, +// const indirectPrimitivePatch& pp, +// const label ppEdgeI, +// const labelUIndList& excludeFaces, +// const labelList& meshFaces, +// +// label& inflateFaceI, +// label& patchI, +// label& zoneI, +// bool& zoneFlip +//) +//{ +// inflateFaceI = -1; +// patchI = -1; +// zoneI = -1; +// zoneFlip = false; +// +// forAll(meshFaces, k) +// { +// label faceI = meshFaces[k]; +// +// if +// ( +// !excludeFaces.found(faceI) +// && ( +// (mesh.isInternalFace(faceI) && useInternalFaces) +// || (!mesh.isInternalFace(faceI) && useBoundaryFaces) +// ) +// ) +// { +// setFaceProps +// ( +// mesh, +// pp, +// ppEdgeI, +// faceI, +// +// patchI, +// zoneI, +// zoneFlip, +// inflateFaceI +// ); +// +// if (zoneI != -1 || patchI != -1) +// { +// break; +// } +// } +// } +//} // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // @@ -611,11 +619,13 @@ void Foam::addPatchCellLayer::findZoneFace Foam::addPatchCellLayer::addPatchCellLayer ( const polyMesh& mesh, - const bool addToMesh + const bool addToMesh, + const bool extrude ) : mesh_(mesh), addToMesh_(addToMesh), + extrude_(extrude), addedPoints_(0), layerFaces_(0) {} @@ -642,7 +652,7 @@ Foam::labelListList Foam::addPatchCellLayer::addedCells for (label i = 0; i < faceLabels.size()-1; i++) { - added[i] = mesh.faceNeighbour()[faceLabels[i]]; + added[i] = mesh.faceOwner()[faceLabels[i+1]]; } } } @@ -660,9 +670,11 @@ Foam::labelListList Foam::addPatchCellLayer::globalEdgeFaces ( const polyMesh& mesh, const globalIndex& globalFaces, - const indirectPrimitivePatch& pp + const indirectPrimitivePatch& pp, + const bitSet& ppFlip ) { + // Precalculate mesh edges for pp.edges. const labelList meshEdges(pp.meshEdges(mesh.edges(), mesh.pointEdges())); @@ -672,21 +684,32 @@ Foam::labelListList Foam::addPatchCellLayer::globalEdgeFaces const labelListList& edgeFaces = pp.edgeFaces(); + DynamicList<label> faceIDs; + forAll(edgeFaces, edgeI) { - label meshEdgeI = meshEdges[edgeI]; - - const labelList& eFaces = edgeFaces[edgeI]; - // Store face and processor as unique tag. - labelList& globalEFaces = globalEdgeFaces[meshEdgeI]; - globalEFaces.setSize(eFaces.size()); - forAll(eFaces, i) + faceIDs.clear(); + for (const label patchFacei : edgeFaces[edgeI]) { - globalEFaces[i] = globalFaces.toGlobal(pp.addressing()[eFaces[i]]); + const label facei = pp.addressing()[patchFacei]; + + // Ignore if ppFlip is on the other side of the (coupled) boundary + if + ( + ppFlip.empty() + || !ppFlip[patchFacei] + || mesh.isInternalFace(facei) + ) + { + faceIDs.append(globalFaces.toGlobal(facei)); + } } + + globalEdgeFaces[meshEdges[edgeI]] = std::move(faceIDs); } + // Synchronise across coupled edges. syncTools::syncEdgeList ( @@ -701,6 +724,17 @@ Foam::labelListList Foam::addPatchCellLayer::globalEdgeFaces } +Foam::labelListList Foam::addPatchCellLayer::globalEdgeFaces +( + const polyMesh& mesh, + const globalIndex& globalFaces, + const indirectPrimitivePatch& pp +) +{ + return globalEdgeFaces(mesh, globalFaces, pp, bitSet::null()); +} + + void Foam::addPatchCellLayer::markPatchEdges ( const polyMesh& mesh, @@ -799,6 +833,11 @@ void Foam::addPatchCellLayer::globalEdgeInfo } + bitSet isPpFace(mesh.nFaces()); + isPpFace.set(pp.addressing()); + // Note: no need to sync isPpFace since does not include processor patches + + const faceZoneMesh& fzs = mesh.faceZones(); // Extract zone info into mesh face indexing for ease of addressing @@ -839,6 +878,11 @@ void Foam::addPatchCellLayer::globalEdgeInfo for (const label facei : isInternalOrCoupled) { + if (isPpFace[facei]) + { + continue; + } + const face& f = mesh.faces()[facei]; label prevPointi = f.last(); @@ -891,9 +935,6 @@ void Foam::addPatchCellLayer::globalEdgeInfo const polyBoundaryMesh& patches = mesh.boundaryMesh(); - bitSet isPpFace(mesh.nFaces()); - isPpFace.set(pp.addressing()); - // Note: no need to sync ppFace since does not include processor patches for (const polyPatch& pp : patches) { @@ -1128,6 +1169,8 @@ void Foam::addPatchCellLayer::calcExtrudeInfo edgePatchID.setSize(pp.nEdges()); edgePatchID = -1; nPatches = patches.size(); + nbrProcToPatch.clear(); + patchToNbrProc.clear(); edgeZoneID.setSize(pp.nEdges()); edgeZoneID = -1; edgeFlip.setSize(pp.nEdges()); @@ -1487,7 +1530,7 @@ void Foam::addPatchCellLayer::setRefinement << abort(FatalError); } } - else + else if (debug) { // Maybe check for adding to neighbour of boundary faces? How about // coupled faces where the faceZone flipMap is negated @@ -1605,13 +1648,7 @@ void Foam::addPatchCellLayer::setRefinement // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bitSet isBlockedFace(mesh_.nFaces()); - forAll(nFaceLayers, patchFacei) - { - if (nFaceLayers[patchFacei] > 0) - { - isBlockedFace.set(pp.addressing()[patchFacei]); - } - } + isBlockedFace.set(pp.addressing()); // Some storage for edge-face-addressing. DynamicList<label> ef; @@ -1839,191 +1876,50 @@ void Foam::addPatchCellLayer::setRefinement // Also mark any affected cells. We could transport the duplicated point // itself but since it is a processor-local index only we only transport // a boolean. - - // Per face, per index in face either labelMax or a valid index. Note: + // Per face, per index in face either -1 or a valid index. Note: // most faces are not affected in which case the face will be zero size - // and only have a nullptr and a size. + // and only have a nullptr and a size. Note: we do not actually use the + // value of the index - it might be a remote patch point so not make any + // sense. All we want to know is whether it is -1 or not. faceList baseFaces(mesh_.nFaces()); - bitSet isAffectedCell(mesh_.nCells()); { - const faceList& localFaces = pp.localFaces(); - forAll(localFaces, patchFacei) + bitSet isDupPatchPoint(pp.nPoints()); + forAll(nPointLayers, patchPointi) { - const face& f = localFaces[patchFacei]; - forAll(f, fp) + if (nPointLayers[patchPointi] > 0) { - const label patchPointi = f[fp]; - if (nPointLayers[patchPointi] > 0) - { - const label meshFacei = pp.addressing()[patchFacei]; - face& baseF = baseFaces[meshFacei]; - // Initialise to labelMax if not yet sized - baseF.setSize(f.size(), labelMax); - baseF[fp] = pp.meshPoints()[patchPointi]; - - if (ppFlip[patchFacei]) - { - // Neighbour stays. Affected points on the owner side. - const label celli = mesh_.faceOwner()[meshFacei]; - isAffectedCell.set(celli); - } - else if (mesh_.isInternalFace(meshFacei)) - { - // Owner unaffected. Unaffected points on neighbour side - const label celli = mesh_.faceNeighbour()[meshFacei]; - isAffectedCell.set(celli); - } - } + isDupPatchPoint.set(patchPointi); } } - } - - // Transport affected side across faces. Could do across edges: say we have - // a loose cell edge-(but not face-)connected to face-to-be-extruded do - // we want it to move with the extrusion or stay connected to the original? - // For now just keep it connected to the original. - { - // Work space - Map<label> minPointValue; - faceList oldBoundaryFaces(mesh_.nBoundaryFaces()); - - while (true) + // Knock out point if not all local faces using it are extruded + // Guess not needed since done outside of routine already. + forAll(nFaceLayers, patchFacei) { - bitSet newIsAffectedCell(mesh_.nCells()); - - label nChanged = 0; - for (const label celli : isAffectedCell) + if (nFaceLayers[patchFacei] == 0) { - const cell& cFaces = mesh_.cells()[celli]; - - // 1. Determine marked base points. Inside a single cell all - // faces use the same 'instance' of a point. - minPointValue.clear(); - for (const label facei : cFaces) - { - const face& baseF = baseFaces[facei]; - const face& f = mesh_.faces()[facei]; - - if (baseF.size()) - { - forAll(f, fp) - { - if (baseF[fp] != labelMax) - { - // Could check here for inconsistent patchPoint - // e.g. cell using both sides of a - // face-to-be-extruded. Is not possible! - minPointValue.insert(f[fp], baseF[fp]); - } - } - } - } - - //Pout<< "For cell:" << celli - // << " at:" << mesh_.cellCentres()[celli] - // << " have minPointValue:" << minPointValue - // << endl; - - // 2. Transport marked points on all cell points - for (const label facei : cFaces) + const face& f = pp.localFaces()[patchFacei]; + for (const label patchPointi : f) { - const face& f = mesh_.faces()[facei]; - face& baseF = baseFaces[facei]; - - const label oldNChanged = nChanged; - forAll(f, fp) - { - const auto fnd = minPointValue.find(f[fp]); - if (fnd.good()) - { - baseF.setSize(f.size(), labelMax); - if (baseF[fp] == labelMax) - { - baseF[fp] = fnd(); - nChanged++; - - //Pout<< "For cell:" << celli - // << " at:" << mesh_.cellCentres()[celli] - // << " on face:" << facei - // << " points:" - // << UIndirectList<point>(mesh_.points(), f) - // << " now have baseFace:" << baseF - // << endl; - } - } - } - - if (!isBlockedFace(facei) && nChanged > oldNChanged) + if (isDupPatchPoint[patchPointi]) { - // Mark neighbouring cells - const label own = mesh_.faceOwner()[facei]; - if (!isAffectedCell[own]) - { - newIsAffectedCell.set(own); - } - if (mesh_.isInternalFace(facei)) - { - const label nei = mesh_.faceNeighbour()[facei]; - if (!isAffectedCell[nei]) - { - newIsAffectedCell.set(nei); - } - } + isDupPatchPoint.unset(patchPointi); } } } + } - if (debug) - { - Pout<< "isAffectedCell:" << isAffectedCell.count() << endl; - Pout<< "newIsAffectedCell:" << newIsAffectedCell.count() - << endl; - Pout<< "nChanged:" << nChanged << endl; - } - - if (!returnReduceOr(nChanged)) - { - break; - } - - - // Transport minimum across coupled faces - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - SubList<face> l - ( - baseFaces, - mesh_.nBoundaryFaces(), - mesh_.nInternalFaces() - ); - oldBoundaryFaces = l; - syncTools::syncBoundaryFaceList - ( - mesh_, - l, - minEqOpFace(), - Foam::dummyTransform() // dummy transformation - ); - - forAll(l, bFacei) - { - // Note: avoid special handling of comparing zero-sized faces - // (see face::operator==). Review. - const labelUList& baseVts = l[bFacei]; - const labelUList& oldVts = oldBoundaryFaces[bFacei]; - if (baseVts != oldVts) - { - const label facei = mesh_.nInternalFaces()+bFacei; - const label own = mesh_.faceOwner()[facei]; - if (!isAffectedCell[own]) - { - newIsAffectedCell.set(own); - } - } - } + findDuplicatedPoints + ( + mesh_, + pp, + ppFlip, // optional orientation on top of pp + isBlockedFace, // any mesh faces not to be traversed. + // Usually pp.addressing() + isDupPatchPoint, + extrude_, - isAffectedCell = newIsAffectedCell; - } + baseFaces + ); } @@ -2120,13 +2016,13 @@ void Foam::addPatchCellLayer::setRefinement } else if (!ppFlip[patchFacei]) { - // Normal: extrude from owner face + // Normal: extrude from owner side extrudeCelli = mesh_.faceOwner()[meshFacei]; extrudeZonei = mesh_.cellZones().whichZone(extrudeCelli); } else if (mesh_.isInternalFace(meshFacei)) { - // Extrude from neighbour face (if internal). Might be + // Extrude from neighbour side (if internal). Might be // that it is a coupled face and the other side is // extruded extrudeCelli = mesh_.faceNeighbour()[meshFacei]; @@ -2164,8 +2060,9 @@ void Foam::addPatchCellLayer::setRefinement - // Create faces on top of the original patch faces. - // These faces are created from original patch faces outwards so in order + // Create faces from the original patch faces. + // These faces are created from original patch faces outwards (or inwards) + // so in order // of increasing cell number. So orientation should be same as original // patch face for them to have owner<neighbour. @@ -2214,74 +2111,97 @@ void Foam::addPatchCellLayer::setRefinement // << endl; // Get new neighbour - label own = addedCells[patchFacei][i]; - label nei; - label patchi; - label zoneI = -1; - bool flip = false; + label own; + label nei = -1; + label patchi = -1; + label zonei = -1; + bool zoneFlip = false; bool fluxFlip = false; if (i == addedCells[patchFacei].size()-1) { - // Top layer so is either patch face or connects to - // the other cell - patchi = patchID[patchFacei]; - if (patchi == -1) - { - // Internal face - nei = - ( - !ppFlip[patchFacei] - ? mesh_.faceNeighbour()[meshFacei] - : mesh_.faceOwner()[meshFacei] - ); + // Last layer so + // - extrude : original patch or other cell + // - intrude : original cell - if (ppFlip[patchFacei]) + if (extrude_) + { + patchi = patchID[patchFacei]; + zonei = mesh_.faceZones().whichZone(meshFacei); + if (zonei != -1) { - newFace = newFace.reverseFace(); + const faceZone& fz = mesh_.faceZones()[zonei]; + zoneFlip = fz.flipMap()[fz.whichFace(meshFacei)]; + } + if (patchi == -1) + { + // Internal face between added cell and original + // neighbour / owner + own = + ( + !ppFlip[patchFacei] + ? mesh_.faceNeighbour()[meshFacei] + : mesh_.faceOwner()[meshFacei] + ); + nei = addedCells[patchFacei][i]; + if (ppFlip[patchFacei]) + { + newFace = newFace.reverseFace(); + if (zonei != -1) + { + zoneFlip = !zoneFlip; + } + fluxFlip = true; + } + } + else + { + // Boundary face + own = addedCells[patchFacei][i]; } - //Pout<< "** adding top (internal) face:" - // << " at:" << mesh_.faceCentres()[meshFacei] - // << " own:" << own << " nei:" << nei - // << " patchi:" << patchi - // << " newFace:" << newFace - // << endl; } else { - nei = -1; - } - zoneI = mesh_.faceZones().whichZone(meshFacei); - if (zoneI != -1) - { - const faceZone& fz = mesh_.faceZones()[zoneI]; - flip = fz.flipMap()[fz.whichFace(meshFacei)]; + // Intrude : face connects to original cell + //if (patchID[patchFacei] == -1) + { + // Internal face between added cell and original + // owner / neighbour. TBD: what if ppFlip set on + // boundary face (so with no neighbour) + own = + ( + !ppFlip[patchFacei] + ? mesh_.faceOwner()[meshFacei] + : mesh_.faceNeighbour()[meshFacei] + ); + nei = addedCells[patchFacei][i]; + if (ppFlip[patchFacei]) + { + // Since neighbour now owns the face flip it + newFace = newFace.reverseFace(); + if (zonei != -1) + { + zoneFlip = !zoneFlip; + } + fluxFlip = true; + } + } } } else { // Internal face between layer i and i+1 + own = addedCells[patchFacei][i]; nei = addedCells[patchFacei][i+1]; - patchi = -1; - } - if (nei != -1 && nei < own) - { - // Wrongly oriented internal face - newFace = newFace.reverseFace(); - std::swap(own, nei); - flip = !flip; - fluxFlip = true; - - //Pout<< "Flipped newFace:" - // << newFace.unitNormal(meshMod.points()) - // << " own:" << own - // << " nei:" << nei - // << endl; + if (ppFlip[patchFacei]) + { + // Since neighbour now owns the face flip it + newFace = newFace.reverseFace(); + fluxFlip = true; + } } - - layerFaces_[patchFacei][i+1] = meshMod.setAction ( polyAddFace @@ -2294,8 +2214,8 @@ void Foam::addPatchCellLayer::setRefinement (addToMesh_ ? meshFacei : -1), // master face fluxFlip, // flux flip patchi, // patch for face - zoneI, // zone for face - flip // face zone flip + zonei, // zone for face + zoneFlip // face zone flip ) ); @@ -2307,13 +2227,14 @@ void Foam::addPatchCellLayer::setRefinement // << " n:" << newFace.unitNormal(meshMod.points()) // << " own:" << own << " nei:" << nei // << " patchi:" << patchi + // << " zonei:" << zonei // << endl; } } } // - // Modify owner faces to have addedCells as neighbour + // Modify original face to have addedCells as neighbour // if (addToMesh_) @@ -2322,41 +2243,110 @@ void Foam::addPatchCellLayer::setRefinement { if (addedCells[patchFacei].size()) { - label meshFacei = pp.addressing()[patchFacei]; + const label meshFacei = pp.addressing()[patchFacei]; layerFaces_[patchFacei][0] = meshFacei; const face& f = pp[patchFacei]; - const label own = - ( - !ppFlip[patchFacei] - ? mesh_.faceOwner()[meshFacei] - : mesh_.faceNeighbour()[meshFacei] - ); - const label nei = addedCells[patchFacei][0]; + if (extrude_) + { + const label own = + ( + !ppFlip[patchFacei] + ? mesh_.faceOwner()[meshFacei] + : mesh_.faceNeighbour()[meshFacei] + ); + const label nei = addedCells[patchFacei][0]; - meshMod.setAction - ( - polyModifyFace + meshMod.setAction ( - (ppFlip[patchFacei] ? f.reverseFace() : f),// verts - meshFacei, // label of face - own, // owner - nei, // neighbour - ppFlip[patchFacei], // face flip - -1, // patch for face - true, //false, // remove from zone - -1, //zoneI, // zone for face - false // face flip in zone - ) - ); + polyModifyFace + ( + (ppFlip[patchFacei] ? f.reverseFace() : f),// verts + meshFacei, // label of face + own, // owner + nei, // neighbour + ppFlip[patchFacei], // face flip + -1, // patch for face + true, //false, // remove from zone + -1, //zoneI, // zone for face + false // face flip in zone + ) + ); + } + else + { + label patchi; + label zonei; + bool zoneOrient; + setFaceProps + ( + mesh_, + meshFacei, - //Pout<< "Modified bottom face " << meshFacei - // << " at:" << mesh_.faceCentres()[meshFacei] - // << " new own:" << own << " new nei:" << nei - // << " verts:" << meshMod.faces()[meshFacei] - // << " n:" - // << meshMod.faces()[meshFacei].unitNormal(meshMod.points()) + patchi, + zonei, + zoneOrient + ); + + label own; + label nei = -1; + bool flip = false; + if (!ppFlip[patchFacei]) + { + if (patchi == -1) + { + own = mesh_.faceNeighbour()[meshFacei]; + nei = addedCells[patchFacei].first(); + flip = true; + } + else + { + own = addedCells[patchFacei].first(); + } + } + else + { + if (patchi == -1) + { + own = mesh_.faceOwner()[meshFacei]; + nei = addedCells[patchFacei].first(); + } + else + { + own = addedCells[patchFacei].first(); + } + } + + if (zonei != -1 && flip) + { + zoneOrient = !zoneOrient; + } + + meshMod.setAction + ( + polyModifyFace + ( + (flip ? f.reverseFace() : f), // verts + meshFacei, // label of face + own, // owner + nei, // neighbour + flip, // face flip + patchi, // patch for face + false, // remove from zone + zonei, // zone for face + zoneOrient // face flip in zone + ) + ); + } + + //Pout<< "Modified original face " << meshFacei + // << " at:" << mesh_.faceCentres()[meshFacei] + // << " new own:" << meshMod.faceOwner()[meshFacei] + // << " new nei:" << meshMod.faceNeighbour()[meshFacei] + // << " verts:" << meshMod.faces()[meshFacei] + // << " n:" + // << meshMod.faces()[meshFacei].unitNormal(meshMod.points()) // << endl; } } @@ -2472,9 +2462,10 @@ void Foam::addPatchCellLayer::setRefinement // between the same two faces and extrude string into a single face. forAll(pp, patchFacei) { + // Get edges of face in vertex order const labelList& fEdges = faceEdges[patchFacei]; - forAll(fEdges, fp) + forAll(fEdges, i) { // Get string of edges that needs to be extruded as a single face. // Returned as indices in fEdges. @@ -2533,16 +2524,16 @@ void Foam::addPatchCellLayer::setRefinement // because we loop in incrementing order as well we will // always have nbrFacei > patchFacei. - label startEdgei = fEdges[startFp]; + const label startEdgei = fEdges[startFp]; - label meshEdgei = meshEdges[startEdgei]; + const label meshEdgei = meshEdges[startEdgei]; - label numEdgeSideFaces = edgeLayers[startEdgei]; + const label numEdgeSideFaces = edgeLayers[startEdgei]; for (label i = 0; i < numEdgeSideFaces; i++) { - label vEnd = stringedVerts.last(); - label vStart = stringedVerts[0]; + const label vEnd = stringedVerts.last(); + const label vStart = stringedVerts[0]; // calculate number of points making up a face label newFp = 2*stringedVerts.size(); @@ -2573,7 +2564,7 @@ void Foam::addPatchCellLayer::setRefinement { forAll(stringedVerts, stringedI) { - label v = stringedVerts[stringedI]; + const label v = stringedVerts[stringedI]; addVertex ( ( @@ -2590,10 +2581,10 @@ void Foam::addPatchCellLayer::setRefinement { forAll(stringedVerts, stringedI) { - label v = stringedVerts[stringedI]; + const label v = stringedVerts[stringedI]; if (addedPoints_[v].size()) { - label offset = + const label offset = addedPoints_[v].size() - numEdgeSideFaces; addVertex ( @@ -2623,7 +2614,7 @@ void Foam::addPatchCellLayer::setRefinement { if (i == 0 && addedPoints_[vEnd].size()) { - label offset = + const label offset = addedPoints_[vEnd].size() - numEdgeSideFaces; for (label ioff = 0; ioff < offset; ioff++) { @@ -2639,10 +2630,10 @@ void Foam::addPatchCellLayer::setRefinement forAllReverse(stringedVerts, stringedI) { - label v = stringedVerts[stringedI]; + const label v = stringedVerts[stringedI]; if (addedPoints_[v].size()) { - label offset = + const label offset = addedPoints_[v].size() - numEdgeSideFaces; addVertex ( @@ -2672,7 +2663,7 @@ void Foam::addPatchCellLayer::setRefinement { if (i == 0 && addedPoints_[vStart].size()) { - label offset = + const label offset = addedPoints_[vStart].size() - numEdgeSideFaces; for (label ioff = offset-1; ioff >= 0; ioff--) { @@ -2695,7 +2686,7 @@ void Foam::addPatchCellLayer::setRefinement // Walked edges as if owner face was extruded. Reverse // for neighbour face extrusion. - if (ppFlip[patchFacei]) + if (extrude_ == ppFlip[patchFacei]) { newFace = newFace.reverseFace(); } @@ -2797,7 +2788,11 @@ void Foam::addPatchCellLayer::setRefinement { face newFace; - forAll(baseFaces, facei) + // For intrusion correction later on: store displacement of modified + // points so they can be adapted on connected faces. + pointField displacement(mesh_.nPoints(), Zero); + + forAll(mesh_.faces(), facei) { const face& f = mesh_.faces()[facei]; const face& baseF = baseFaces[facei]; @@ -2813,20 +2808,25 @@ void Foam::addPatchCellLayer::setRefinement forAll(f, fp) { const label meshPointi = f[fp]; - if (baseF[fp] != labelMax) + if (baseF[fp] != -1) { - // Duplicated point - const label patchPointi = pp.meshPointMap()[meshPointi]; - const label addedPointi = addedPoints_[patchPointi].last(); - - //Pout<< " For point:" << meshPointi - // << " at:" << mesh_.points()[meshPointi] - // << " at:" << pp.localPoints()[patchPointi] - // << " using addedpoint:" << addedPointi - // << " at:" << meshMod.points()[addedPointi] - // << endl; + // Duplicated point. Might not be present on processor? + //const label patchPointi = pp.meshPointMap()[meshPointi]; + const auto pointFnd = pp.meshPointMap().find(meshPointi); + if (pointFnd) + { + const label patchPointi = pointFnd(); + const label addedPointi = + addedPoints_[patchPointi].last(); + + // Adapt vertices of face + newFace[fp] = addedPointi; - newFace[fp] = addedPointi; + // Store displacement for syncing later on + displacement[meshPointi] = + meshMod.points()[addedPointi] + -mesh_.points()[meshPointi]; + } } } @@ -2879,8 +2879,318 @@ void Foam::addPatchCellLayer::setRefinement zoneFlip // face flip in zone ); } + + + //Pout<< "Adapted point on existing face:" << facei + // << " at:" << mesh_.faceCentres()[facei] + // << " zone:" << zoneID << nl + // << " old:" << f + // << " n:" << newFace.unitNormal(meshMod.points()) + // << " coords:" << UIndirectList<point>(mesh_.points(), f) + // << nl + // << " new:" << newFace + // << " n:" << newFace.unitNormal(meshMod.points()) + // << " coords:" + // << UIndirectList<point>(meshMod.points(), newFace) + // << endl; + } + + if (!extrude_) + { + // Bit tricky: + // - if intruding we're modifying the vertices on existing + // coupled faces (in extrude mode we're adding additional points/ + // faces where we're already doing the right thing) + // - if the other side face is itself not on an extrudePatch + // it will not be adapted so you'll get a coupled point mismatch + // - so send over the new point position (or use some map on + // coupled faces to describe which vertex on the face is changed?) + // - and adapt any point that was marked but not an extrusion point + // - to test: take 2x2 blockMesh and remove one of the cells. Put + // all 3 cells on different processors. Now one of the processors + // will be coupled to extrude/intruded points but itself have + // no patch. + + syncTools::syncPointList + ( + mesh_, + displacement, + maxMagSqrEqOp<vector>(), + vector::zero + ); + + forAll(baseFaces, facei) + { + const face& f = mesh_.faces()[facei]; + const face& baseF = baseFaces[facei]; + + if (isBlockedFace(facei) || baseF.empty()) + { + // Either part of patch or no duplicated points on face + continue; + } + + // Start off from original face + forAll(f, fp) + { + if (baseF[fp] != -1) + { + // Duplicated point. Might not be present on processor? + const label meshPointi = f[fp]; + + if + ( + !pp.meshPointMap().found(meshPointi) + && displacement[meshPointi] != vector::zero + ) + { + const point newPt + ( + mesh_.points()[meshPointi] + + displacement[meshPointi] + ); + meshMod.modifyPoint + ( + meshPointi, + newPt, + mesh_.pointZones().whichZone(meshPointi), + true + ); + + // Unmark as being done + displacement[meshPointi] = Zero; + } + } + } + } } } + + + + //if (debug & 4) + //{ + // Pout<< "Checking whole mesh" << endl; + // pointField fCtrs; + // vectorField fAreas; + // const UList<face>& faces = meshMod.faces(); + // const pointField p(meshMod.points()); + // primitiveMeshTools::makeFaceCentresAndAreas + // ( + // faces, + // p, + // fCtrs, + // fAreas + // ); + // + // const label nCells = max(meshMod.faceOwner())+1; + // + // pointField cellCtrs; + // scalarField cellVols; + // { + // // See primitiveMeshTools::makeCellCentresAndVols + // // Clear the fields for accumulation + // cellCtrs.setSize(nCells, Zero); + // cellVols.setSize(nCells, Zero); + // + // const labelList& own = meshMod.faceOwner(); + // const labelList& nei = meshMod.faceNeighbour(); + // + // Field<solveVector> cEst(nCells, Zero); + // labelField nCellFaces(nCells, Zero); + // + // forAll(own, facei) + // { + // cEst[own[facei]] += solveVector(fCtrs[facei]); + // ++nCellFaces[own[facei]]; + // } + // + // forAll(nei, facei) + // { + // if (nei[facei] == -1) + // { + // continue; + // } + // cEst[nei[facei]] += solveVector(fCtrs[facei]); + // ++nCellFaces[nei[facei]]; + // } + // + // forAll(cEst, celli) + // { + // cEst[celli] /= nCellFaces[celli]; + // } + // + // forAll(own, facei) + // { + // const solveVector fc(fCtrs[facei]); + // const solveVector fA(fAreas[facei]); + // + // // Calculate 3*face-pyramid volume + // solveScalar pyr3Vol = fA & (fc - cEst[own[facei]]); + // + // // Calculate face-pyramid centre + // solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[own[facei]]; + // + // // Accumulate volume-weighted face-pyramid centre + // cellCtrs[own[facei]] += pyr3Vol*pc; + // + // // Accumulate face-pyramid volume + // cellVols[own[facei]] += pyr3Vol; + // } + // + // forAll(nei, facei) + // { + // if (nei[facei] == -1) + // { + // continue; + // } + // + // const solveVector fc(fCtrs[facei]); + // const solveVector fA(fAreas[facei]); + // + // // Calculate 3*face-pyramid volume + // solveScalar pyr3Vol = fA & (cEst[nei[facei]] - fc); + // + // // Calculate face-pyramid centre + // solveVector pc = (3.0/4.0)*fc + (1.0/4.0)*cEst[nei[facei]]; + // + // // Accumulate volume-weighted face-pyramid centre + // cellCtrs[nei[facei]] += pyr3Vol*pc; + // + // // Accumulate face-pyramid volume + // cellVols[nei[facei]] += pyr3Vol; + // } + // + // forAll(cellCtrs, celli) + // { + // if (mag(cellVols[celli]) > VSMALL) + // { + // cellCtrs[celli] /= cellVols[celli]; + // } + // else + // { + // cellCtrs[celli] = cEst[celli]; + // } + // } + // cellVols *= (1.0/3.0); + // } + // cellList cells(nCells); + // { + // const labelList& own = meshMod.faceOwner(); + // const labelList& nei = meshMod.faceNeighbour(); + // + // labelList nFaces(nCells, 0); + // forAll(own, facei) + // { + // nFaces[own[facei]]++; + // } + // forAll(nei, facei) + // { + // if (nei[facei] == -1) + // { + // continue; + // } + // nFaces[nei[facei]]++; + // } + // + // forAll(cells, celli) + // { + // cells[celli].resize_nocopy(nFaces[celli]); + // nFaces[celli] = 0; + // } + // + // forAll(own, facei) + // { + // const label celli = own[facei]; + // cells[celli][nFaces[celli]++] = facei; + // } + // forAll(nei, facei) + // { + // if (nei[facei] == -1) + // { + // continue; + // } + // const label celli = nei[facei]; + // cells[celli][nFaces[celli]++] = facei; + // } + // } + // + // + // scalarField openness; + // { + // const labelList& own = meshMod.faceOwner(); + // const labelList& nei = meshMod.faceNeighbour(); + // + // // Loop through cell faces and sum up the face area vectors for + // // each cell. This should be zero in all vector components + // + // vectorField sumClosed(nCells, Zero); + // vectorField sumMagClosed(nCells, Zero); + // + // forAll(own, facei) + // { + // // Add to owner + // sumClosed[own[facei]] += fAreas[facei]; + // sumMagClosed[own[facei]] += cmptMag(fAreas[facei]); + // } + // + // forAll(nei, facei) + // { + // // Subtract from neighbour + // if (nei[facei] == -1) + // { + // continue; + // } + // + // sumClosed[nei[facei]] -= fAreas[facei]; + // sumMagClosed[nei[facei]] += cmptMag(fAreas[facei]); + // } + // + // + // // Check the sums + // openness.setSize(nCells); + // + // forAll(sumClosed, celli) + // { + // scalar maxOpenness = 0; + // + // for (direction cmpt=0; cmpt<vector::nComponents; cmpt++) + // { + // maxOpenness = max + // ( + // maxOpenness, + // mag(sumClosed[celli][cmpt]) + // /(sumMagClosed[celli][cmpt] + ROOTVSMALL) + // ); + // } + // openness[celli] = maxOpenness; + // + // if (openness[celli] > 1e-9) + // { + // Pout<< "cell:" << celli + // << " at:" << cellCtrs[celli] + // << " openness:" << openness[celli] + // << endl; + // OBJstream os + // ( + // mesh_.time().timePath() + // /"cell_" + Foam::name(celli) + ".obj" + // ); + // faceList cellFaces + // ( + // UIndirectList<face> + // ( + // meshMod.faces(), + // cells[celli] + // ) + // ); + // os.write(cellFaces, mesh_.points(), false); + // Pout<< "Written " << os.nVertices() << " to " + // << os.name() << endl; + // } + // } + // } + //} } @@ -2947,4 +3257,261 @@ void Foam::addPatchCellLayer::updateMesh } +void Foam::addPatchCellLayer::findDuplicatedPoints +( + const polyMesh& mesh, + const indirectPrimitivePatch& pp, + const bitSet& ppFlip, // optional orientation on top of pp + const bitSet& isBlockedFace, // any mesh faces not to be traversed. + // Usually pp.addressing() + const bitSet& isDupPatchPoint, + const bool extrude, + faceList& isDupMeshPoint // per face, per index either -1 + // or some index (value not relevant) +) +{ + if (isBlockedFace.size() != mesh.nFaces()) + { + FatalErrorInFunction << "Incorrect size" << exit(FatalError); + } + if (ppFlip.size() != pp.size() || isDupPatchPoint.size() != pp.nPoints()) + { + FatalErrorInFunction << "Incorrect patch sizes" + << exit(FatalError); + } + + const auto& owner = mesh.faceOwner(); + const auto& neighbour = mesh.faceNeighbour(); + + + // Store per face whether it uses the duplicated point or the original one + // Also mark any affected cells. We could transport the duplicated point + // itself but since it is a processor-local index only we only transport + // a boolean. + + // Per face, per index in face either -1 or a valid index. Note: + // most faces are not affected in which case the face will be zero size + // and only have a nullptr and a size. + isDupMeshPoint.resize_nocopy(mesh.nFaces()); + isDupMeshPoint = face(); + bitSet isAffectedCell(mesh.nCells()); + { + const faceList& localFaces = pp.localFaces(); + forAll(localFaces, patchFacei) + { + const face& f = localFaces[patchFacei]; + forAll(f, fp) + { + const label patchPointi = f[fp]; + if (isDupPatchPoint[patchPointi]) + { + const label meshFacei = pp.addressing()[patchFacei]; + face& baseF = isDupMeshPoint[meshFacei]; + // Initialise to -1 if not yet sized + baseF.setSize(f.size(), -1); + baseF[fp] = pp.meshPoints()[patchPointi]; + + if (extrude == ppFlip[patchFacei]) + { + // either: + // - extrude out of neighbour so new points connect + // to owner + // - or intrude into owner + isAffectedCell.set(owner[meshFacei]); + } + else if (mesh.isInternalFace(meshFacei)) + { + // Owner unaffected. Affected points on neighbour side + isAffectedCell.set(neighbour[meshFacei]); + } + } + } + } + } + + + // Transport affected side across faces. Could do across edges: say we have + // a loose cell edge-(but not face-)connected to face-to-be-extruded do + // we want it to move with the extrusion or stay connected to the original? + // For now just keep it connected to the original. + { + // Work space + Map<label> minPointValue; + + while (true) + { + bitSet newIsAffectedCell(mesh.nCells()); + + label nChanged = 0; + for (const label celli : isAffectedCell) + { + const cell& cFaces = mesh.cells()[celli]; + + // 1. Determine marked base points. Inside a single cell all + // faces (e.g. 3 for hex) use the same 'instance' of a point. + minPointValue.clear(); + for (const label facei : cFaces) + { + const face& baseF = isDupMeshPoint[facei]; + const face& f = mesh.faces()[facei]; + + forAll(baseF, fp) + { + if (baseF[fp] != -1) + { + // Could check here for inconsistent patchPoint + // e.g. cell using both sides of a + // face-to-be-extruded. + + const auto mpm = pp.meshPointMap().find(f[fp]); + if (mpm && !isDupPatchPoint[mpm()]) + { + // Local copy of point is explicitly not + // marked for extrusion so ignore. This + // occasionally happens with point-connected + // faces where one face (& point) does + // extrude but the other face does not + // since pointing in the other direction. + // Should ideally be covered by checking + // across edges, not across points. + } + else + { + minPointValue.insert(f[fp], baseF[fp]); + } + } + } + } + + + // 2. Transport marked points on all cell points + for (const label facei : cFaces) + { + const face& f = mesh.faces()[facei]; + face& baseF = isDupMeshPoint[facei]; + + const label oldNChanged = nChanged; + forAll(f, fp) + { + const auto fnd = minPointValue.find(f[fp]); + if (fnd.good()) + { + const auto mpm = pp.meshPointMap().find(f[fp]); + if (mpm && !isDupPatchPoint[mpm()]) + { + // See above + continue; + } + + baseF.setSize(f.size(), -1); + if (baseF[fp] == -1) + { + baseF[fp] = fnd(); + nChanged++; + } + } + } + + if (!isBlockedFace(facei) && nChanged > oldNChanged) + { + // Mark neighbouring cells. Note that we do NOT check + // for whether cell is already in isAffectedCell but + // always add it. This is because different information + // can come in from the neighbour in different + // iterations. + newIsAffectedCell.set(owner[facei]); + if (mesh.isInternalFace(facei)) + { + newIsAffectedCell.set(neighbour[facei]); + } + } + } + } + + + if (debug) + { + Pout<< "isAffectedCell:" << isAffectedCell.count() << endl; + Pout<< "newIsAffectedCell:" << newIsAffectedCell.count() + << endl; + Pout<< "nChanged:" << nChanged << endl; + } + + + if (!returnReduceOr(nChanged)) + { + break; + } + + + // Transport minimum across coupled faces + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Faces can be either + // - null + // - face with some -1 or >= 0 + // - blocked face (isBlockedFace, should be synced already) + faceList l(mesh.nBoundaryFaces()); + forAll(l, bFacei) + { + const label facei = mesh.nInternalFaces()+bFacei; + + if (isBlockedFace(facei)) + { + // Make sure nothing is transferred. Since isBlockedFace is + // synced both sides should have null + if (l[bFacei].size()) + { + l[bFacei].clear(); + } + } + else + { + l[bFacei] = isDupMeshPoint[facei]; + } + } + + + syncTools::syncBoundaryFaceList + ( + mesh, + l, + combineEqOpFace(), // transport vertex >= 0 + Foam::dummyTransform() // dummy transformation + ); + + // Copy back + forAll(l, bFacei) + { + const label facei = mesh.nInternalFaces()+bFacei; + + if (!isBlockedFace(facei)) + { + // 1. Check if anything changed. Update isAffectedCell. + // Note: avoid special handling of comparing zero-sized + // faces (see face::operator==). Review. + const labelUList& newVts = l[bFacei]; + const labelUList& oldVts = isDupMeshPoint[facei]; + + if (newVts != oldVts) + { + const label own = owner[facei]; + if (!isAffectedCell[own]) + { + newIsAffectedCell.set(own); + } + } + + + // 2. Update isDupMeshPoint + isDupMeshPoint[facei] = l[bFacei]; + } + } + + + isAffectedCell = newIsAffectedCell; + } + } +} + + // ************************************************************************* // diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H index fe59a8f6080b4e613f750a0b203e090a98ced277..35b330e1458c3a82847b30629cd41ae8a1f9f521 100644 --- a/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H +++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/addPatchCellLayer.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2020 OpenCFD Ltd. + Copyright (C) 2020,2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,8 +28,8 @@ Class Foam::addPatchCellLayer Description - Adds layers of cells to outside of polyPatch. Can optionally create - stand-alone extruded mesh (addToMesh=false). + Adds layers of cells to outside (or inside) of polyMesh. Can optionally + create stand-alone extruded mesh (addToMesh=false). Call setRefinement with offset vector for every patch point and number of layers per patch face and number of layers per patch point. @@ -51,24 +51,47 @@ Description \verbatim Was: - a b <- patch of boundary face - +------+------+ - | | | <- original cells - +------+------+ - - Becomes: - - a b <- patch of boundary face - +------+------+ - + +------+ - +------+------+ - +------+------+ - | | | <- original cells - +------+------+ + a b <- patch of boundary face + +------+------+ + | | | <- original cells + +------+------+ + + Extrusion: + + + added added + face cell + ---- ---- + a b <- patch of boundary face + +------+------+ 3 + | | | 2 + + +------+ 2 + | | | 1 + +------+------+ 1 + | | | 0 + +------+------+ 0 <- original boundary faces + | | | <- original cells + +------+------+ + + + + Intrusion: + + face cell + ---- ---- + a b <- patch of boundary face + +------+------+ 0 + | | | 0 + +------+------+ 1 + | | | 1 + + +------+ 2 + | | | 2 + +------+------+ 3 + | | | <- original cells + +------+------+ \endverbatim - - added faces get same patchID as face they are extruded from - 'side' faces (i.e. on the edge of pp) get the patchID/zoneID of the other patch/zone they are connected to (hopefully only 1) @@ -78,10 +101,15 @@ Description \verbatim a b b <- patch of boundary face +------+------+------+ + | | | | | | | | <- cells + | | | | +------+------+------+ + (shown for extrusion mode only): + + ^ ^ <- wanted extrusion vector (none at far right) a | b | b <- patch of boundary face +------+------+------+ @@ -123,7 +151,7 @@ class primitiveMesh; class globalIndex; /*---------------------------------------------------------------------------*\ - Class addPatchCellLayer Declaration + Class addPatchCellLayer Declaration \*---------------------------------------------------------------------------*/ class addPatchCellLayer @@ -136,15 +164,23 @@ class addPatchCellLayer //- Add layers to existing mesh or create new mesh const bool addToMesh_; + //- Add layers to outside of mesh or to inside + const bool extrude_; + + //- For all patchpoints: list of added points (size 0 or nLayers) // First point in list is one nearest to original point in patch, - // last one is the new point on the surface. + // last one is + // - extrude : the new point on the surface + // - intrude : the point connecting to the original cell. labelListList addedPoints_; //- For all patchfaces: list of layer faces. // - empty if no face extruded - // - first face is original boundary face - // - last one is new boundary face. + // - first element is original patch face + // - last element is + // - extrude : the new boundary face + // - intrude : the new internal face to the original cell. labelListList layerFaces_; @@ -226,25 +262,6 @@ class addPatchCellLayer label& inflateFaceI ); - //- Find internal or boundary face to get extrude properties - // from. zoneFlip consistent with ppEdge ordering - static void findZoneFace - ( - const bool useInternalFaces, - const bool useBoundaryFaces, - - const polyMesh& mesh, - const indirectPrimitivePatch& pp, - const label ppEdgeI, - const labelUIndList& excludeFaces, - const labelList& meshFaces, - - label& inflateFaceI, - label& patchI, - label& zoneI, - bool& zoneFlip - ); - //- Mark internal and boundary edges of patch. In mesh edges //- since processor might not have pp but does have edge. static void markPatchEdges @@ -294,7 +311,12 @@ public: // Constructors //- Construct from mesh. - explicit addPatchCellLayer(const polyMesh&, const bool addToMesh=true); + explicit addPatchCellLayer + ( + const polyMesh&, + const bool addToMesh=true, + const bool extrude=true + ); // Member Functions @@ -314,8 +336,13 @@ public: } //- Helper: get added cells per patch face. - // addedCells[patchFace] is list of cells added. Last element is - // the top cells (i.e. the boundary cell) + // addedCells[patchFace] is list of cells added. + // extrude : + // first element : next to original cell + // last element : is the top cell (i.e. the boundary cell) + // intrude : + // first element : top cell + // last element : next to original cell static labelListList addedCells ( const polyMesh&, @@ -328,6 +355,18 @@ public: // Edit + //- Per patch edge the pp faces (in global indices) using it. + // Uses ListOps::uniqueEqOp to remove duplicates. On coupled + // faces only selects the one with the correct orientation/flip + // (assumes the orientation is opposite on a coupled face pair) + static labelListList globalEdgeFaces + ( + const polyMesh&, + const globalIndex& globalFaces, + const indirectPrimitivePatch& pp, + const bitSet& orientation + ); + //- Per patch edge the pp faces (in global indices) using it. // Uses ListOps::uniqueEqOp to remove duplicates. static labelListList globalEdgeFaces @@ -454,6 +493,28 @@ public: const labelList& faceMap, // new to old patch faces const labelList& pointMap // new to old patch points ); + + + + //- Helper: given patch and points on patch that are extruded + // (to slave side or master side) find the affected + // points. Calculates by walking across faces which vertices on + // which face are affected. isDupMeshPoint: + // -1 : unaffected + // >=0 : should use local duplicate of point + // (though it does not tell us whether it should use + // slave side or master side) + static void findDuplicatedPoints + ( + const polyMesh& mesh, + const indirectPrimitivePatch& pp, + const bitSet& ppFlip, // optional orientation on top of pp + const bitSet& isBlockedFace,// any mesh faces not to be + // traversed.Usually pp.addressing() + const bitSet& isDupPatchPoint, + const bool extrude, // which side to extrude + faceList& isDupMeshPoint + ); }; diff --git a/src/finiteVolume/fields/fvPatchFields/derived/scaledFixedValue/scaledFixedValueFvPatchField.H b/src/finiteVolume/fields/fvPatchFields/derived/scaledFixedValue/scaledFixedValueFvPatchField.H index bc8898d43d794d74b9ce7da1706816f56816c581..fb5c4a9c50831315fdd8418e7f5753cdd8a62f47 100644 --- a/src/finiteVolume/fields/fvPatchFields/derived/scaledFixedValue/scaledFixedValueFvPatchField.H +++ b/src/finiteVolume/fields/fvPatchFields/derived/scaledFixedValue/scaledFixedValueFvPatchField.H @@ -37,7 +37,7 @@ Usage \table Property | Description | Required | Default value scale | Time varying scale | yes | - patch | patchField providing the raw patch value | yes | + refValue | patchField providing the raw patch value | yes | \endtable Example of the boundary condition specification to scale a reference diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/averageNeighbour/averageNeighbourFvGeometryScheme.H b/src/finiteVolume/fvMesh/fvGeometryScheme/averageNeighbour/averageNeighbourFvGeometryScheme.H index 578179630104007992b325e068f67cdbe1a311b1..4ddf71443741c2093abc136a8d1d474800f95397 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/averageNeighbour/averageNeighbourFvGeometryScheme.H +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/averageNeighbour/averageNeighbourFvGeometryScheme.H @@ -164,6 +164,23 @@ public: //- Do what is necessary if the mesh has moved virtual void movePoints(); + + //- Calculate geometry quantities using mesh topology and provided + //- points. If oldPoints provided only does local update. Returns + //- true if anything changed, false otherwise + virtual bool updateGeom + ( + const pointField& points, + const refPtr<pointField>& oldPoints, // optional old points + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes + ) const + { + NotImplemented; + return true; + } }; diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.C b/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.C index 867b38a28712d2b1ba2061d168f9bd19d7865748..0a037d445ddf25e880fb9faa480b9739d3ba2b90 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.C +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.C @@ -29,6 +29,7 @@ License #include "addToRunTimeSelectionTable.H" #include "surfaceFields.H" #include "volFields.H" +#include "primitiveMeshTools.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -390,4 +391,36 @@ Foam::basicFvGeometryScheme::nonOrthCorrectionVectors() const } +bool Foam::basicFvGeometryScheme::updateGeom +( + const pointField& points, + const refPtr<pointField>& oldPoints, + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes +) const +{ + primitiveMeshTools::makeFaceCentresAndAreas + ( + mesh_, + points, + faceCentres, + faceAreas + ); + + primitiveMeshTools::makeCellCentresAndVols + ( + mesh_, + faceCentres, + faceAreas, + cellCentres, + cellVolumes + ); + + // Assume something has changed + return true; +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.H b/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.H index b69d43e834eeae9d982262b13563cfabc82475a6..a59b9b0a177f35550079f3404338742d3b70355f 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.H +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/basic/basicFvGeometryScheme.H @@ -93,6 +93,19 @@ public: //- Return non-orthogonality correction vectors virtual tmp<surfaceVectorField> nonOrthCorrectionVectors() const; + + //- Calculate geometry quantities using mesh topology and provided + //- points. If oldPoints provided only does local update. Returns + //- true if anything changed, false otherwise + virtual bool updateGeom + ( + const pointField& points, + const refPtr<pointField>& oldPoints, // optional old points + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes + ) const; }; diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/fvGeometryScheme/fvGeometryScheme.H b/src/finiteVolume/fvMesh/fvGeometryScheme/fvGeometryScheme/fvGeometryScheme.H index 2dd14d27a282ec2685fafd4ece0db9178357b79f..20552e83ed8229d35707c32f484deb3a0b410c5b 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/fvGeometryScheme/fvGeometryScheme.H +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/fvGeometryScheme/fvGeometryScheme.H @@ -160,6 +160,19 @@ public: // const labelHashSet& patchIDs, // const word& defaultPatchDistMethod //) const = 0; + + //- Calculate geometry quantities using mesh topology and provided + //- points. If oldPoints provided only does local update. Returns + //- true if anything changed, false otherwise + virtual bool updateGeom + ( + const pointField& points, + const refPtr<pointField>& oldPoints, // optional old points + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes + ) const = 0; }; diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.C b/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.C index 84c3eb064ae128bf4834af12018f9d51aba0931d..0f64298abc1fa40b31207b7e107f625bf160dbfc 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.C +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.C @@ -456,4 +456,46 @@ void Foam::highAspectRatioFvGeometryScheme::movePoints() } +bool Foam::highAspectRatioFvGeometryScheme::updateGeom +( + const pointField& points, + const refPtr<pointField>& oldPoints, + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes +) const +{ + // Basic + basicFvGeometryScheme::updateGeom + ( + points, + oldPoints, + faceCentres, + faceAreas, + cellCentres, + cellVolumes + ); + + // Average opposite faces + pointField avgFaceCentres; + pointField avgCellCentres; + makeAverageCentres + ( + mesh_, + points, + faceAreas, + mag(faceAreas), + avgFaceCentres, + avgCellCentres + ); + + faceCentres = std::move(avgFaceCentres); + cellCentres = std::move(avgCellCentres); + + // Assume something has changed. + return true; +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.H b/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.H index 1ed2164b4f01cb3c5a7a9090694928847a885e8c..5965b81ca56c98af084ff7f0433ae1dcb97cab00 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.H +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/highAspectRatio/highAspectRatioFvGeometryScheme.H @@ -123,6 +123,19 @@ public: //- Do what is necessary if the mesh has moved virtual void movePoints(); + + //- Calculate geometry quantities using mesh topology and provided + //- points. If oldPoints provided only does local update. Returns + //- true if anything changed, false otherwise + virtual bool updateGeom + ( + const pointField& points, + const refPtr<pointField>& oldPoints, // optional old points + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes + ) const; }; diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.C b/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.C index ce14fbaaf523f6afc3edeacd048db0fce4b1c292..debabcd87d73e0f9ac4c8fe07df642386aa29192 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.C +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.C @@ -47,6 +47,92 @@ namespace Foam // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +void Foam::parallelFvGeometryScheme::adjustGeometry +( + pointField& faceCentres, + vectorField& faceAreas +) const +{ + pointField syncedBCentres; + syncedBCentres = SubField<vector> + ( + faceCentres, + mesh_.nBoundaryFaces(), + mesh_.nInternalFaces() + ); + syncTools::swapBoundaryFaceList + ( + mesh_, + syncedBCentres + ); + + vectorField syncedBAreas; + syncedBAreas = SubField<vector> + ( + faceAreas, + mesh_.nBoundaryFaces(), + mesh_.nInternalFaces() + ); + syncTools::syncBoundaryFaceList + ( + mesh_, + syncedBAreas, + eqOp<vector>(), + transformOriented() + ); + + const auto& pbm = mesh_.boundaryMesh(); + for (const auto& pp : pbm) + { + const auto* ppp = isA<coupledPolyPatch>(pp); + + //if (ppp) + //{ + // Pout<< "For patch:" << ppp->name() + // << " size:" << ppp->size() + // << endl; + // forAll(*ppp, i) + // { + // const label facei = ppp->start()+i; + // Pout<< " Face:" << facei << nl + // << " meshFc:" << faceCentres[facei] << nl + // << " meshFa:" << faceAreas[facei] << nl + // << endl; + // } + //} + + if (ppp && !ppp->owner()) + { + SubField<point> patchFc + ( + faceCentres, + ppp->size(), + ppp->start() + ); + patchFc = SubField<vector> + ( + syncedBCentres, + ppp->size(), + ppp->offset() + ); + + SubField<vector> patchArea + ( + faceAreas, + ppp->size(), + ppp->start() + ); + patchArea = SubField<vector> + ( + syncedBAreas, + ppp->size(), + ppp->offset() + ); + } + } +} + + void Foam::parallelFvGeometryScheme::adjustGeometry() { // Swap face centres and areas @@ -304,5 +390,38 @@ Foam::parallelFvGeometryScheme::nonOrthCorrectionVectors() const } +bool Foam::parallelFvGeometryScheme::updateGeom +( + const pointField& points, + const refPtr<pointField>& oldPoints, + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes +) const +{ + primitiveMeshTools::makeFaceCentresAndAreas + ( + mesh_, + points, + faceCentres, + cellCentres + ); + + // Parallel consistency + adjustGeometry(faceCentres, faceAreas); + + primitiveMeshTools::makeCellCentresAndVols + ( + mesh_, + faceCentres, + faceAreas, + cellCentres, + cellVolumes + ); + + return true; +} + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.H b/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.H index 9fa223f3c9c24a5ceb276747f98d08a7cb6a6995..f85c05d6a01b20057cb3e5b1e6510d9cf123f453 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.H +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/parallel/parallelFvGeometryScheme.H @@ -102,6 +102,13 @@ private: // Private Member Functions + //- Swap processor-face geometry + void adjustGeometry + ( + pointField& faceCentres, + vectorField& faceAreas + ) const; + //- Swap processor-face geometry void adjustGeometry(); @@ -181,6 +188,19 @@ public: //- Return non-orthogonality correction vectors virtual tmp<surfaceVectorField> nonOrthCorrectionVectors() const; + + //- Calculate geometry quantities using mesh topology and provided + //- points. If oldPoints provided only does local update. Returns + //- true if anything changed, false otherwise + virtual bool updateGeom + ( + const pointField& points, + const refPtr<pointField>& oldPoints, // optional old points + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes + ) const; }; diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.C b/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.C index 1898dbe506165d56db5c8b316a88c00238ce5a37..19cd197463c2a561214cd8f765488983065abe5c 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.C +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.C @@ -45,6 +45,68 @@ namespace Foam } +bool Foam::solidBodyFvGeometryScheme::markChanges +( + const pointField& oldPoints, + const pointField& currPoints, + bitSet& isChangedPoint, + bitSet& isChangedFace, + bitSet& isChangedCell +) const +{ + isChangedPoint.setSize(oldPoints.size()); + + // Check for non-identical points + forAll(isChangedPoint, pointi) + { + isChangedPoint.set(pointi, oldPoints[pointi] != currPoints[pointi]); + } + + DebugInfo + << "SBM --- Changed points:" + << returnReduce(isChangedPoint.count(), sumOp<label>()) + << endl; + + // Quick return if no points have moved + if (returnReduceAnd(isChangedPoint.none())) + { + return false; + } + + isChangedFace.setSize(mesh_.nFaces()); + isChangedFace = false; + + isChangedCell.setSize(mesh_.nCells()); + isChangedCell = false; + + const auto& pointFaces = mesh_.pointFaces(); + const auto& own = mesh_.faceOwner(); + const auto& nbr = mesh_.faceNeighbour(); + + // Identify faces and cells attached to moving points + for (const label pointi : isChangedPoint) + { + for (const auto facei : pointFaces[pointi]) + { + isChangedFace.set(facei); + + isChangedCell.set(own[facei]); + if (facei < mesh_.nInternalFaces()) + { + isChangedCell.set(nbr[facei]); + } + } + } + + DebugInfo + << "SBM --- Changed cells:" + << returnReduce(isChangedCell.count(), sumOp<label>()) + << endl; + + return true; +} + + void Foam::solidBodyFvGeometryScheme::setMeshMotionData() { if (!cacheInitialised_ || !cacheMotion_) @@ -67,64 +129,86 @@ void Foam::solidBodyFvGeometryScheme::setMeshMotionData() << abort(FatalError); } - bitSet changedPoints(oldPoints.size()); - - // Check for non-identical points - forAll(changedPoints, pointi) - { - changedPoints.set(pointi, oldPoints[pointi] != currPoints[pointi]); - } - - DebugInfo - << "SBM --- Changed points:" - << returnReduce(changedPoints.count(), sumOp<label>()) - << endl; + //bitSet changedPoints(oldPoints.size()); + // + //// Check for non-identical points + //forAll(changedPoints, pointi) + //{ + // changedPoints.set + // ( + // pointi, + // oldPoints[pointi] != currPoints[pointi] + // ); + //} + // + //DebugInfo + // << "SBM --- Changed points:" + // << returnReduce(changedPoints.count(), sumOp<label>()) + // << endl; + // + //// Quick return if no points have moved + //if (returnReduceAnd(changedPoints.none())) + //{ + // return; + //} + // + //bitSet cellIDs(mesh_.nCells()); + //bitSet faceIDs(mesh_.nFaces()); + // + //const auto& pointFaces = mesh_.pointFaces(); + //const auto& own = mesh_.faceOwner(); + //const auto& nbr = mesh_.faceNeighbour(); + // + //// Identify faces and cells attached to moving points + //for (const label pointi : changedPoints) + //{ + // for (const auto facei : pointFaces[pointi]) + // { + // faceIDs.set(facei); + // + // cellIDs.set(own[facei]); + // if (facei < mesh_.nInternalFaces()) + // { + // cellIDs.set(nbr[facei]); + // } + // } + //} + // + //changedCellIDs_ = cellIDs.toc(); + // + //DebugInfo + // << "SBM --- Changed cells:" + // << returnReduce(changedCellIDs_.size(), sumOp<label>()) + // << endl; + + bitSet isChangedPoint; + bitSet isChangedFace; + bitSet isChangedCell; + const bool changed = markChanges + ( + oldPoints, + currPoints, + isChangedPoint, + isChangedFace, + isChangedCell + ); // Quick return if no points have moved - if (returnReduceAnd(changedPoints.none())) + if (!changed) { return; } - bitSet cellIDs(mesh_.nCells()); - bitSet faceIDs(mesh_.nFaces()); - - const auto& pointFaces = mesh_.pointFaces(); - const auto& own = mesh_.faceOwner(); - const auto& nbr = mesh_.faceNeighbour(); - - // Identify faces and cells attached to moving points - for (const label pointi : changedPoints) - { - for (const auto facei : pointFaces[pointi]) - { - faceIDs.set(facei); - - cellIDs.set(own[facei]); - if (facei < mesh_.nInternalFaces()) - { - cellIDs.set(nbr[facei]); - } - } - } - - changedCellIDs_ = cellIDs.toc(); - - DebugInfo - << "SBM --- Changed cells:" - << returnReduce(changedCellIDs_.size(), sumOp<label>()) - << endl; + changedCellIDs_ = isChangedCell.toc(); // Construct face and patch ID info - const auto changedFaceFlag = faceIDs.values(); - - DynamicList<label> changedFaceIDs(faceIDs.count()); - DynamicList<label> changedPatchIDs(faceIDs.count()); + DynamicList<label> changedFaceIDs(isChangedFace.count()); + DynamicList<label> changedPatchIDs(changedFaceIDs.capacity()); for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei) { - if (changedFaceFlag[facei]) + if (isChangedFace[facei]) { changedFaceIDs.append(facei); changedPatchIDs.append(-1); @@ -138,7 +222,7 @@ void Foam::solidBodyFvGeometryScheme::setMeshMotionData() for (const label meshFacei : pp.range()) { - if (changedFaceFlag[meshFacei]) + if (isChangedFace[meshFacei]) { changedFaceIDs.append(meshFacei); changedPatchIDs.append(patchi); @@ -343,4 +427,82 @@ void Foam::solidBodyFvGeometryScheme::updateMesh(const mapPolyMesh& mpm) } +bool Foam::solidBodyFvGeometryScheme::updateGeom +( + const pointField& points, + const refPtr<pointField>& oldPoints, + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes +) const +{ + if + ( + (faceCentres.size() != mesh_.nFaces()) + || (faceAreas.size() != mesh_.nFaces()) + || (cellCentres.size() != mesh_.nCells()) + || (cellVolumes.size() != mesh_.nCells()) + || !oldPoints + ) + { + // Do all + return basicFvGeometryScheme::updateGeom + ( + points, + oldPoints, + faceCentres, + faceAreas, + cellCentres, + cellVolumes + ); + } + else + { + // Since oldPoints provided assume that face & cell geometry is + // up to date with it + + bitSet isChangedPoint; + bitSet isChangedFace; + bitSet isChangedCell; + const bool changed = markChanges + ( + oldPoints(), + points, + isChangedPoint, + isChangedFace, + isChangedCell + ); + + if (!changed) + { + return false; + } + + // Make face centres and areas consistent with new points + primitiveMeshTools::updateFaceCentresAndAreas + ( + mesh_, + isChangedFace.toc(), + points, + faceCentres, + faceAreas + ); + + primitiveMeshTools::updateCellCentresAndVols + ( + mesh_, + faceCentres, + faceAreas, + isChangedCell.toc(), + mesh_.cells(), + cellCentres, + cellVolumes + ); + + return true; + } +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.H b/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.H index 755f21080bf40c8fc3d88ac8e22307165edb7953..d52bfde28e48d5b362cddfbe2e723cebb09209cb 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.H +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/solidBody/solidBodyFvGeometryScheme.H @@ -94,6 +94,16 @@ class solidBodyFvGeometryScheme // Private Member Functions + //- Detect what geometry has changed. Return true if anything has. + bool markChanges + ( + const pointField& oldPoints, + const pointField& currPoints, + bitSet& isChangedPoint, + bitSet& isChangedFace, + bitSet& isChangedCell + ) const; + //- Set the mesh motion data (point, face IDs) void setMeshMotionData(); @@ -127,6 +137,19 @@ public: //- Update mesh for topology changes virtual void updateMesh(const mapPolyMesh& mpm); + + //- Calculate geometry quantities using mesh topology and provided + //- points. If oldPoints provided only does local update. Returns + //- true if anything changed, false otherwise + virtual bool updateGeom + ( + const pointField& points, + const refPtr<pointField>& oldPoints, // optional old points + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes + ) const; }; diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.C b/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.C index 90c3c4e00f320fefd6712645a42646cb3cfd1a39..186994a50d58c69c8db684b81b2696d81ca58424 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.C +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.C @@ -208,4 +208,35 @@ void Foam::stabilisedFvGeometryScheme::movePoints() } +bool Foam::stabilisedFvGeometryScheme::updateGeom +( + const pointField& points, + const refPtr<pointField>& oldPoints, + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes +) const +{ + makeFaceCentresAndAreas + ( + mesh_, + points, + faceCentres, + faceAreas + ); + + primitiveMeshTools::makeCellCentresAndVols + ( + mesh_, + faceCentres, + faceAreas, + cellCentres, + cellVolumes + ); + + return true; +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.H b/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.H index c367ecf9b188cec160cece3f5cbcc5aa7ab84a7e..a137d334a9bcbe59790a65bc091869885fe38e57 100644 --- a/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.H +++ b/src/finiteVolume/fvMesh/fvGeometryScheme/stabilised/stabilisedFvGeometryScheme.H @@ -112,6 +112,19 @@ public: //- Do what is necessary if the mesh has moved virtual void movePoints(); + + //- Calculate geometry quantities using mesh topology and provided + //- points. If oldPoints provided only does local update. Returns + //- true if anything changed, false otherwise + virtual bool updateGeom + ( + const pointField& points, + const refPtr<pointField>& oldPoints, // optional old points + pointField& faceCentres, + vectorField& faceAreas, + pointField& cellCentres, + scalarField& cellVolumes + ) const; }; diff --git a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C index 2f10400289bc4aacfc5c0910c4de4b4dae6e65aa..839d102a171ffd708b3cd0dd51084d0494c50df8 100644 --- a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C +++ b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C @@ -32,10 +32,16 @@ License #include "cyclicPolyPatch.H" #include "emptyPolyPatch.H" #include "processorPolyPatch.H" +#include "meshPointPatch.H" +#include "processorPointPatch.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // -Foam::word Foam::fvMeshSubset::exposedPatchName("oldInternalFaces"); +namespace Foam +{ + word fvMeshSubset::exposedPatchName("oldInternalFaces"); + defineTypeNameAndDebug(fvMeshSubset, 0); +} // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // @@ -522,6 +528,16 @@ void Foam::fvMeshSubset::reset void Foam::fvMeshSubset::reset(const Foam::zero) { + // Was old pointMesh present? + const auto* basePointMeshPtr = + baseMesh_.thisDb().cfindObject<pointMesh>(pointMesh::typeName); + if (basePointMeshPtr) + { + DebugPout<< "fvMeshSubset::reset(const Foam::zero) :" + << " Detected pointMesh" << endl; + } + + clear(); // Create zero-sized subMesh @@ -574,6 +590,46 @@ void Foam::fvMeshSubset::reset(const Foam::zero) } + // Clone old additional point patches + if (basePointMeshPtr) + { + DebugPout<< "Subsetting pointMesh" << endl; + const auto& basePointMesh = *basePointMeshPtr; + const auto& oldPointBoundary = basePointMesh.boundary(); + + // 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring + // any additional patches + const auto& newSubPointMesh = pointMesh::New(newSubMesh); + + auto& newBoundary = + const_cast<pointBoundaryMesh&>(newSubPointMesh.boundary()); + + // Start off from (poly)patch map + pointPatchMap_ = patchMap_; + + // 2. Explicitly add subsetted meshPointPatches + for (const auto& oldPointPatch : oldPointBoundary) + { + const auto* mppPtr = isA<meshPointPatch>(oldPointPatch); + if (mppPtr && (newBoundary.findPatchID(mppPtr->name()) == -1)) + { + newBoundary.push_back + ( + mppPtr->clone + ( + newBoundary, + newBoundary.size(), + labelList::null(), // map + labelList::null() // map + ) + ); + } + } + + // Extend patchMap with -1 + pointPatchMap_.setSize(newBoundary.size(), -1); + } + // Add the zones subsetZones(); } @@ -586,6 +642,16 @@ void Foam::fvMeshSubset::reset const bool syncPar ) { + // Was old pointMesh present? + const auto* basePointMeshPtr = + baseMesh_.thisDb().cfindObject<pointMesh>(pointMesh::typeName); + if (basePointMeshPtr) + { + DebugPout<< "fvMeshSubset::reset(const bitSet&) :" + << " Detected pointMesh" << endl; + } + + // Clear all old maps and pointers clear(); @@ -1126,6 +1192,8 @@ void Foam::fvMeshSubset::reset // Inserted patch + label newInternalPatchID = -1; + if (wantedPatchID == -1) { label oldInternalSize = boundaryPatchSizes[oldInternalPatchID]; @@ -1159,6 +1227,7 @@ void Foam::fvMeshSubset::reset // the internal faces patchStart += boundaryPatchSizes[oldInternalPatchID]; patchMap_[nNewPatches] = -1; + newInternalPatchID = nNewPatches; ++nNewPatches; } } @@ -1233,6 +1302,98 @@ void Foam::fvMeshSubset::reset // Subset and add any zones subsetZones(); + + + if (basePointMeshPtr) + { + DebugPout<< "Subsetting pointMesh" << endl; + const auto& basePointMesh = *basePointMeshPtr; + const auto& oldPointBoundary = basePointMesh.boundary(); + + // 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring + // any additional patches + const auto& newSubPointMesh = pointMesh::New(subMeshPtr_()); + + pointPatchMap_ = patchMap_; + + auto& newBoundary = + const_cast<pointBoundaryMesh&>(newSubPointMesh.boundary()); + + + // 2. Explicitly add subsetted meshPointPatches + labelList oldToNewPoints(baseMesh_.nPoints(), -1); + forAll(pointMap_, i) + { + oldToNewPoints[pointMap_[i]] = i; + } + + + // Add meshPointPatches + pointPatchMap_.setSize(newBoundary.size(), -1); + + for (const auto& oldPointPatch : oldPointBoundary) + { + const auto* mppPtr = isA<meshPointPatch>(oldPointPatch); + if (mppPtr && (newBoundary.findPatchID(mppPtr->name()) == -1)) + { + const auto& mp = mppPtr->meshPoints(); + DynamicList<label> subPointMap(mp.size()); + forAll(mp, i) + { + const label newPointi = oldToNewPoints[mp[i]]; + if (newPointi != -1) + { + subPointMap.append(i); + } + } + + pointPatchMap_.push_back(mppPtr->index()); + + newBoundary.push_back + ( + mppPtr->clone + ( + newBoundary, + newBoundary.size(), + subPointMap, // map + oldToNewPoints + ) + ); + } + } + + + // 3. rotate into place: + // - global patches (including meshPointPatches) + // - optional 'internalFaces' patch + // - processor patches + labelList oldToNew(newBoundary.size()); + label newPatchi = 0; + forAll(newBoundary, patchi) + { + if + ( + patchi != newInternalPatchID + && !isA<processorPointPatch>(newBoundary[patchi]) + ) + { + oldToNew[patchi] = newPatchi++; + } + } + if (newInternalPatchID != -1) + { + oldToNew[newInternalPatchID] = newPatchi++; + } + forAll(newBoundary, patchi) + { + if (isA<processorPointPatch>(newBoundary[patchi])) + { + oldToNew[patchi] = newPatchi++; + } + } + newBoundary.reorder(oldToNew, true); + inplaceReorder(oldToNew, pointPatchMap_); + } } diff --git a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.H b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.H index bedb48e44345d5c8809e14c33459c65e21dd9eb1..d4ce7781a0a7ad2dd2aedad2926ca783996f15b0 100644 --- a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.H +++ b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.H @@ -102,6 +102,9 @@ class fvMeshSubset //- Patch mapping array labelList patchMap_; + //- PointPatch mapping array + labelList pointPatchMap_; + // Private Member Functions @@ -135,6 +138,10 @@ protected: public: + // Declare name of the class and its debug switch + ClassName("fvMeshSubset"); + + // Static Data Members //- Name for exposed internal faces (default: oldInternalFaces) @@ -225,6 +232,10 @@ public: //- Return patch map inline const labelList& patchMap() const; + //- Return point-patch map. Usually identical to patchMap except if + //- additional patches are added to the pointMesh. + inline const labelList& pointPatchMap() const; + // Edit diff --git a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetI.H b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetI.H index c1bef91d564a504571a5cc351fa6a3e500cfdd06..b2f47f119c6a49eab63285505e0e66eef936a90c 100644 --- a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetI.H +++ b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetI.H @@ -104,4 +104,19 @@ inline const Foam::labelList& Foam::fvMeshSubset::patchMap() const } +inline const Foam::labelList& Foam::fvMeshSubset::pointPatchMap() const +{ + checkHasSubMesh(); + + if (pointPatchMap_.empty()) + { + return patchMap_; + } + else + { + return pointPatchMap_; + } +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetTemplates.C b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetTemplates.C index 7936eaeb1a40962874d890a1d06bc02ad0ca9bdc..5d7ce171606ca4b5e8e8bafebcfe80f69a03f4ac 100644 --- a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetTemplates.C +++ b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubsetTemplates.C @@ -551,7 +551,7 @@ Foam::fvMeshSubset::interpolate ( sf, pointMesh::New(subMesh()), // subsetted point mesh - patchMap(), + pointPatchMap(), pointMap() ); } diff --git a/src/fvMotionSolver/Make/files b/src/fvMotionSolver/Make/files index 426e49f6b6c3feb75eedb70739a76026fa4b4dea..83ff9c248d31c304db5e8569cef549db9d049153 100644 --- a/src/fvMotionSolver/Make/files +++ b/src/fvMotionSolver/Make/files @@ -38,6 +38,8 @@ $(derivedPoint)/angularOscillatingDisplacement/angularOscillatingDisplacementPoi $(derivedPoint)/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C $(derivedPoint)/surfaceDisplacement/surfaceDisplacementPointPatchVectorField.C $(derivedPoint)/waveDisplacement/waveDisplacementPointPatchVectorField.C +$(derivedPoint)/edgeSlipDisplacement/edgeSlipDisplacementPointPatchVectorField.C +$(derivedPoint)/pointAttractionDisplacement/pointAttractionDisplacementPointPatchVectorField.C $(derivedPoint)/timeVaryingMappedFixedValue/timeVaryingMappedFixedValuePointPatchFields.C $(derivedPoint)/uniformInterpolatedDisplacement/uniformInterpolatedDisplacementPointPatchVectorField.C diff --git a/src/fvMotionSolver/fvMotionSolvers/componentDisplacement/componentLaplacian/displacementComponentLaplacianFvMotionSolver.C b/src/fvMotionSolver/fvMotionSolvers/componentDisplacement/componentLaplacian/displacementComponentLaplacianFvMotionSolver.C index 541cc4882baa91673d2e68db748301940330e339..826d7e4b0b937cac8e910d0a20292fe5b2410226 100644 --- a/src/fvMotionSolver/fvMotionSolvers/componentDisplacement/componentLaplacian/displacementComponentLaplacianFvMotionSolver.C +++ b/src/fvMotionSolver/fvMotionSolvers/componentDisplacement/componentLaplacian/displacementComponentLaplacianFvMotionSolver.C @@ -145,6 +145,18 @@ Foam::displacementComponentLaplacianFvMotionSolver::curPoints() const pointDisplacement_ ); + // Evaluate the bcs so they are consistent with the internal field + // Might fight the multi-patch behaviour inside volPointInterpolate + if + ( + pointDisplacement_.boundaryField().size() + != cellDisplacement_.boundaryField().size() + ) + { + pointDisplacement_.correctBoundaryConditions(); + } + + if (pointLocation_) { if (debug) diff --git a/src/fvMotionSolver/fvMotionSolvers/displacement/SBRStress/displacementSBRStressFvMotionSolver.C b/src/fvMotionSolver/fvMotionSolvers/displacement/SBRStress/displacementSBRStressFvMotionSolver.C index c220b6635c808c85e052c7c461e0485b10d10b3d..9c0cf0d2674897405ed3351ab6113af2a41c5eab 100644 --- a/src/fvMotionSolver/fvMotionSolvers/displacement/SBRStress/displacementSBRStressFvMotionSolver.C +++ b/src/fvMotionSolver/fvMotionSolvers/displacement/SBRStress/displacementSBRStressFvMotionSolver.C @@ -160,6 +160,17 @@ Foam::displacementSBRStressFvMotionSolver::curPoints() const pointDisplacement_ ); + // Evaluate the bcs so they are consistent with the internal field + // Might fight the multi-patch behaviour inside volPointInterpolate + if + ( + pointDisplacement_.boundaryField().size() + != cellDisplacement_.boundaryField().size() + ) + { + pointDisplacement_.correctBoundaryConditions(); + } + tmp<pointField> tcurPoints ( points0() + pointDisplacement().primitiveField() @@ -186,6 +197,10 @@ void Foam::displacementSBRStressFvMotionSolver::solve() *diffusivityPtr_->operator()() ); + // Make sure the cellMotion bcs are consistent with the pointDisplacement. + // This makes sure the grad below uses more up-to-date values. + cellDisplacement_.boundaryFieldRef().updateCoeffs(); + volTensorField gradCd("gradCd", fvc::grad(cellDisplacement_)); fv::options& fvOptions(fv::options::New(fvMesh_)); diff --git a/src/fvMotionSolver/fvMotionSolvers/displacement/laplacian/displacementLaplacianFvMotionSolver.C b/src/fvMotionSolver/fvMotionSolvers/displacement/laplacian/displacementLaplacianFvMotionSolver.C index e29a6e486520e1a535267a8e67cd3808b641001a..765c8e2baf1dbfc2fc2660d57fc14f7e9de994bc 100644 --- a/src/fvMotionSolver/fvMotionSolvers/displacement/laplacian/displacementLaplacianFvMotionSolver.C +++ b/src/fvMotionSolver/fvMotionSolvers/displacement/laplacian/displacementLaplacianFvMotionSolver.C @@ -267,6 +267,17 @@ Foam::displacementLaplacianFvMotionSolver::curPoints() const pointDisplacement_ ); + // Evaluate the bcs so they are consistent with the internal field + // Might fight the multi-patch behaviour inside volPointInterpolate + if + ( + pointDisplacement_.boundaryField().size() + != cellDisplacement_.boundaryField().size() + ) + { + pointDisplacement_.correctBoundaryConditions(); + } + if (pointLocation_) { if (debug) @@ -333,6 +344,10 @@ void Foam::displacementLaplacianFvMotionSolver::solve() diffusivity().correct(); pointDisplacement_.boundaryFieldRef().updateCoeffs(); + // Make sure the cellMotion bcs are consistent with the pointDisplacement. + // This makes sure the grad below uses more up-to-date values. + cellDisplacement_.boundaryFieldRef().updateCoeffs(); + fv::options& fvOptions(fv::options::New(fvMesh_)); // We explicitly do NOT want to interpolate the motion inbetween diff --git a/src/fvMotionSolver/fvMotionSolvers/displacement/solidBodyDisplacementLaplacian/solidBodyDisplacementLaplacianFvMotionSolver.C b/src/fvMotionSolver/fvMotionSolvers/displacement/solidBodyDisplacementLaplacian/solidBodyDisplacementLaplacianFvMotionSolver.C index 79ddc0d9beddc825555178727e8b9d4713a4c75f..453931bff87114f1fead6638bbdca705587355e7 100644 --- a/src/fvMotionSolver/fvMotionSolvers/displacement/solidBodyDisplacementLaplacian/solidBodyDisplacementLaplacianFvMotionSolver.C +++ b/src/fvMotionSolver/fvMotionSolvers/displacement/solidBodyDisplacementLaplacian/solidBodyDisplacementLaplacianFvMotionSolver.C @@ -271,6 +271,17 @@ Foam::solidBodyDisplacementLaplacianFvMotionSolver::curPoints() const pointDisplacement_ ); + // Evaluate the bcs so they are consistent with the internal field + // Might fight the multi-patch behaviour inside volPointInterpolate + if + ( + pointDisplacement_.boundaryField().size() + != cellDisplacement_.boundaryField().size() + ) + { + pointDisplacement_.correctBoundaryConditions(); + } + tmp<pointField> tnewPoints ( transformPoints(SBMFPtr_().transformation(), points0()) diff --git a/src/fvMotionSolver/fvMotionSolvers/fvMotionSolver/fvMotionSolverTemplates.C b/src/fvMotionSolver/fvMotionSolvers/fvMotionSolver/fvMotionSolverTemplates.C index 47825b752590178940d38b06bd25430ae5fe3f71..81d6c996011af7abab71266705254dd10838d7c9 100644 --- a/src/fvMotionSolver/fvMotionSolvers/fvMotionSolver/fvMotionSolverTemplates.C +++ b/src/fvMotionSolver/fvMotionSolvers/fvMotionSolver/fvMotionSolverTemplates.C @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2012-2016 OpenFOAM Foundation + Copyright (C) 2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,6 +29,7 @@ License #include "fvMotionSolver.H" #include "fixedValuePointPatchFields.H" #include "cellMotionFvPatchFields.H" +#include "facePointPatch.H" // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // @@ -38,23 +40,33 @@ Foam::wordList Foam::fvMotionSolver::cellMotionBoundaryTypes Boundary& pmUbf ) const { - wordList cmUbf = pmUbf.types(); + wordList cmUbf(fvMesh_.boundary().size()); - // Remove global patches from the end of the list - cmUbf.setSize(fvMesh_.boundary().size()); - - forAll(cmUbf, patchi) + forAll(pmUbf, patchi) { - if (isA<fixedValuePointPatchField<Type>>(pmUbf[patchi])) + const auto& pfld = pmUbf[patchi]; + const auto* fppPtr = isA<facePointPatch>(pfld.patch()); + if (fppPtr) { - cmUbf[patchi] = cellMotionFvPatchField<Type>::typeName; - } + const auto& fpp = *fppPtr; + const label polyPatchi = fpp.patch().index(); - if (debug) - { - Pout<< "Patch:" << fvMesh_.boundary()[patchi].patch().name() - << " pointType:" << pmUbf.types()[patchi] - << " cellType:" << cmUbf[patchi] << endl; + if (isA<fixedValuePointPatchField<Type>>(pfld)) + { + cmUbf[polyPatchi] = cellMotionFvPatchField<Type>::typeName; + } + else + { + // Take over pointPatch type + cmUbf[polyPatchi] = pfld.type(); + } + + if (debug) + { + Pout<< "Patch:" << fvMesh_.boundary()[patchi].patch().name() + << " pointType:" << pfld.type() + << " cellType:" << cmUbf[patchi] << endl; + } } } diff --git a/src/fvMotionSolver/fvPatchFields/derived/cellMotion/cellMotionFvPatchField.H b/src/fvMotionSolver/fvPatchFields/derived/cellMotion/cellMotionFvPatchField.H index b175af60ee7452c8b9b876d994765dd976112479..26505e57d8045944c4a086baf12a2ee4c980f4ee 100644 --- a/src/fvMotionSolver/fvPatchFields/derived/cellMotion/cellMotionFvPatchField.H +++ b/src/fvMotionSolver/fvPatchFields/derived/cellMotion/cellMotionFvPatchField.H @@ -37,7 +37,6 @@ SourceFiles #ifndef cellMotionFvPatchField_H #define cellMotionFvPatchField_H -#include "Random.H" #include "fixedValueFvPatchFields.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/fvMotionSolver/pointPatchFields/derived/edgeSlipDisplacement/edgeSlipDisplacementPointPatchVectorField.C b/src/fvMotionSolver/pointPatchFields/derived/edgeSlipDisplacement/edgeSlipDisplacementPointPatchVectorField.C new file mode 100644 index 0000000000000000000000000000000000000000..5cc1fa769f535dfaad8205f4bd43396c3ec4b1c6 --- /dev/null +++ b/src/fvMotionSolver/pointPatchFields/derived/edgeSlipDisplacement/edgeSlipDisplacementPointPatchVectorField.C @@ -0,0 +1,398 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "edgeSlipDisplacementPointPatchVectorField.H" +#include "addToRunTimeSelectionTable.H" +#include "Time.H" +#include "transformField.H" +#include "displacementMotionSolver.H" +#include "featureEdgeMesh.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::edgeSlipDisplacementPointPatchVectorField::read +( + const objectRegistry& obr, + const dictionary& dict +) +{ + const Time& tm = obr.time(); + + const fileName featFileName(dict.get<fileName>("file", keyType::LITERAL)); + + if (tm.foundObject<edgeMesh>(featFileName)) + { + return; + } + + IOobject extFeatObj + ( + featFileName, // name + tm.constant(), // instance + "extendedFeatureEdgeMesh", // local + obr, // registry + IOobject::MUST_READ, + IOobject::NO_WRITE, + IOobject::REGISTER + ); + + //const fileName fName(typeFilePath<extendedFeatureEdgeMesh>(extFeatObj)); + const fileName fName(extFeatObj.typeFilePath<extendedFeatureEdgeMesh>()); + + if (!fName.empty() && extendedEdgeMesh::canRead(fName)) + { + Info<< "Reading edgeMesh from " << extFeatObj.objectRelPath() << endl; + auto* eMeshPtr = new extendedFeatureEdgeMesh(extFeatObj); + eMeshPtr->store(); + } + else + { + // Try reading as edgeMesh + + IOobject featObj + ( + featFileName, // name + tm.constant(), // instance + "triSurface", // local + obr, // registry + IOobject::MUST_READ, + IOobject::NO_WRITE, + IOobject::REGISTER + ); + + Info<< "Reading edgeMesh from " << featObj.objectRelPath() << endl; + const fileName fName(featObj.typeFilePath<featureEdgeMesh>()); + + if (fName.empty()) + { + FatalIOErrorInFunction(dict) + << "Could not open " << featObj.objectPath() + << exit(FatalIOError); + } + + // Read as edgeMesh + auto* eMeshPtr = new featureEdgeMesh(featObj); + eMeshPtr->store(); + } +} + + +void Foam::edgeSlipDisplacementPointPatchVectorField::calcProjection +( + vectorField& displacement +) const +{ + const polyMesh& mesh = patch().boundaryMesh().mesh()(); + const labelList& meshPoints = patch().meshPoints(); + + //const scalar deltaT = mesh.time().deltaTValue(); + + // Construct large enough vector in direction of projectDir so + // we're guaranteed to hit something. + + //- Per point projection vector: + const scalar projectLen = mesh.bounds().mag(); + + + + // Get fixed points (bit of a hack) + const pointZone* zonePtr = nullptr; + + if (frozenPointsZone_.size() > 0) + { + const pointZoneMesh& pZones = mesh.pointZones(); + + zonePtr = &pZones[frozenPointsZone_]; + + Info<< "edgeSlipDisplacementPointPatchVectorField : Fixing all " + << zonePtr->size() << " points in pointZone " << zonePtr->name() + << endl; + } + + // Get the starting locations from the motionSolver + const pointField& points0 = mesh.lookupObject<displacementMotionSolver> + ( + "dynamicMeshDict" + ).points0(); + + + pointField start(meshPoints.size()); + forAll(start, i) + { + start[i] = points0[meshPoints[i]] + displacement[i]; + } + + const auto& tree = edgeTree(); + + label nNotProjected = 0; + forAll(meshPoints, i) + { + const label meshPointi = meshPoints[i]; + const point& pt = mesh.points()[meshPointi]; + + if (zonePtr && (zonePtr->whichPoint(meshPointi) >= 0)) + { + // Fixed point. Reset to point0 location. + displacement[i] = points0[meshPointi] - pt; + } + else + { + pointIndexHit nearest = tree.findNearest(start[i], sqr(projectLen)); + if (nearest.hit()) + { + displacement[i] = nearest.point() - points0[meshPointi]; + } + else + { + nNotProjected++; + + if (debug) + { + Pout<< " point:" << meshPointi + << " coord:" << pt + << " did not find any surface within " << projectLen + << endl; + } + } + } + } + + reduce(nNotProjected, sumOp<label>()); + + if (nNotProjected > 0) + { + Info<< "edgeSlipDisplacement :" + << " on patch " << patch().name() + << " did not project " << nNotProjected + << " out of " << returnReduce(meshPoints.size(), sumOp<label>()) + << " points." << endl; + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::edgeSlipDisplacementPointPatchVectorField:: +edgeSlipDisplacementPointPatchVectorField +( + const pointPatch& p, + const DimensionedField<vector, pointMesh>& iF +) +: + pointPatchVectorField(p, iF), + velocity_(Zero) +{} + + +Foam::edgeSlipDisplacementPointPatchVectorField:: +edgeSlipDisplacementPointPatchVectorField +( + const pointPatch& p, + const DimensionedField<vector, pointMesh>& iF, + const dictionary& dict +) +: + pointPatchVectorField(p, iF, dict), + velocity_(dict.get<vector>("velocity")), + featFileName_(dict.get<fileName>("file", keyType::LITERAL)), + frozenPointsZone_(dict.getOrDefault("frozenPointsZone", word::null)) +{ + read(this->patch().boundaryMesh().mesh().time(), dict); +} + + +Foam::edgeSlipDisplacementPointPatchVectorField:: +edgeSlipDisplacementPointPatchVectorField +( + const edgeSlipDisplacementPointPatchVectorField& ppf, + const pointPatch& p, + const DimensionedField<vector, pointMesh>& iF, + const pointPatchFieldMapper& +) +: + pointPatchVectorField(p, iF), + velocity_(ppf.velocity_), + featFileName_(ppf.featFileName_), + frozenPointsZone_(ppf.frozenPointsZone_) +{} + + +Foam::edgeSlipDisplacementPointPatchVectorField:: +edgeSlipDisplacementPointPatchVectorField +( + const edgeSlipDisplacementPointPatchVectorField& ppf +) +: + pointPatchVectorField(ppf), + velocity_(ppf.velocity_), + featFileName_(ppf.featFileName_), + frozenPointsZone_(ppf.frozenPointsZone_) +{} + + +Foam::edgeSlipDisplacementPointPatchVectorField:: +edgeSlipDisplacementPointPatchVectorField +( + const edgeSlipDisplacementPointPatchVectorField& ppf, + const DimensionedField<vector, pointMesh>& iF +) +: + pointPatchVectorField(ppf, iF), + velocity_(ppf.velocity_), + featFileName_(ppf.featFileName_), + frozenPointsZone_(ppf.frozenPointsZone_) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::indexedOctree<Foam::treeDataEdge>& +Foam::edgeSlipDisplacementPointPatchVectorField::edgeTree() const +{ + if (!edgeTreePtr_) + { + const Time& tm = this->patch().boundaryMesh().mesh().time(); + const auto& eMesh = tm.lookupObject<edgeMesh>(featFileName_); + + const pointField& points = eMesh.points(); + const edgeList& edges = eMesh.edges(); + + // Calculate bb of all points + treeBoundBox bb(points); + + // Random number generator. Bit dodgy since not exactly random ;-) + Random rndGen(65431); + + // Slightly extended bb. Slightly off-centred just so on symmetric + // geometry there are less face/edge aligned items. + bb.inflate(rndGen, 1e-4, ROOTVSMALL); + + edgeTreePtr_.reset + ( + new indexedOctree<treeDataEdge> + ( + treeDataEdge(edges, points), // All edges + + bb, // overall search domain + 8, // maxLevel + 10, // leafsize + 3.0 // duplicity + ) + ); + } + + return edgeTreePtr_(); +} + + +void Foam::edgeSlipDisplacementPointPatchVectorField::updateCoeffs() +{ + if (this->updated()) + { + return; + } + + const vectorField currentDisplacement(this->patchInternalField()); + + // Calculate displacement to project points onto surface + vectorField displacement(currentDisplacement); + calcProjection(displacement); + + + // offset wrt current displacement + vectorField offset(displacement-currentDisplacement); + + // Clip offset to maximum displacement possible: velocity*timestep + + const Time& tm = this->patch().boundaryMesh().mesh().time(); + const scalar deltaT = tm.deltaTValue(); + const vector clipVelocity = velocity_*deltaT; + + forAll(displacement, i) + { + vector& d = offset[i]; + + const scalar magD(mag(d)); + if (magD > ROOTVSMALL) + { + d /= magD; + d *= min(magD, mag(clipVelocity)); + } + } + + if (debug) + { + Pout<< type() << " :" + << " on patch " << patch().name() + << " of field " << this->internalField().name() + << " projection" + << " min:" << gMin(displacement) + << " max:" << gMaxMagSqr(displacement) + << " average:" << gAverage(displacement) + << endl; + } + + // Get internal field to insert values into + Field<vector>& iF = const_cast<Field<vector>&>(this->primitiveField()); + + setInInternalField(iF, (currentDisplacement+offset)()); + + pointPatchVectorField::updateCoeffs(); +} + + +void Foam::edgeSlipDisplacementPointPatchVectorField::write +( + Ostream& os +) const +{ + pointPatchField<vector>::write(os); + os.writeEntry("file", featFileName_); + os.writeEntryIfDifferent<word> + ( + "frozenPointsZone", + word::null, + frozenPointsZone_ + ); + os.writeEntry("velocity", velocity_); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +makePointPatchTypeField +( + pointPatchVectorField, + edgeSlipDisplacementPointPatchVectorField +); + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/fvMotionSolver/pointPatchFields/derived/edgeSlipDisplacement/edgeSlipDisplacementPointPatchVectorField.H b/src/fvMotionSolver/pointPatchFields/derived/edgeSlipDisplacement/edgeSlipDisplacementPointPatchVectorField.H new file mode 100644 index 0000000000000000000000000000000000000000..d1a8257e7cf534bb6bf866e4d3a10487ecd1a3a1 --- /dev/null +++ b/src/fvMotionSolver/pointPatchFields/derived/edgeSlipDisplacement/edgeSlipDisplacementPointPatchVectorField.H @@ -0,0 +1,198 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::edgeSlipDisplacementPointPatchVectorField + +Description + Displacement follows an edgeMesh. Use in a displacementMotionSolver + as a bc on the pointDisplacement field. + + Needs: + - file : name of edgeMesh. Either: + - .extendedFeatureEdgeMesh (read from constant/extendedFeatureEdgeMesh) + - or .eMesh in or a known format (read from constant/triSurface) + - frozenPointsZone : empty or name of pointZone containing points + that do not move + - velocity : maximum displacement velocity + + +SourceFiles + edgeSlipDisplacementPointPatchVectorField.C + +\*---------------------------------------------------------------------------*/ + +#ifndef edgeSlipDisplacementPointPatchVectorField_H +#define edgeSlipDisplacementPointPatchVectorField_H + +#include "pointPatchFields.H" +#include "extendedFeatureEdgeMesh.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class edgeSlipDisplacementPointPatchVectorField Declaration +\*---------------------------------------------------------------------------*/ + +class edgeSlipDisplacementPointPatchVectorField +: + public pointPatchVectorField +{ +private: + + // Private data + + //- Maximum velocity + const vector velocity_; + + //- file + const fileName featFileName_; + + //- pointZone with frozen points + const word frozenPointsZone_; + + //- Edge searching + mutable autoPtr<indexedOctree<treeDataEdge>> edgeTreePtr_; + + + // Private Member Functions + + //- Calculate displacement (w.r.t. points0()) to project onto surface + void calcProjection(vectorField& displacement) const; + + //- No copy assignment + void operator= + ( + const edgeSlipDisplacementPointPatchVectorField& + ) = delete; + + +protected: + + const indexedOctree<treeDataEdge>& edgeTree() const; + + +public: + + //- Runtime type information + TypeName("edgeSlipDisplacement"); + + + // Constructors + + //- Construct from patch and internal field + edgeSlipDisplacementPointPatchVectorField + ( + const pointPatch&, + const DimensionedField<vector, pointMesh>& + ); + + //- Construct from patch, internal field and dictionary + edgeSlipDisplacementPointPatchVectorField + ( + const pointPatch&, + const DimensionedField<vector, pointMesh>&, + const dictionary& + ); + + //- Construct by mapping given patch field onto a new patch + edgeSlipDisplacementPointPatchVectorField + ( + const edgeSlipDisplacementPointPatchVectorField&, + const pointPatch&, + const DimensionedField<vector, pointMesh>&, + const pointPatchFieldMapper& + ); + + //- Construct as copy + edgeSlipDisplacementPointPatchVectorField + ( + const edgeSlipDisplacementPointPatchVectorField& + ); + + //- Construct and return a clone + virtual autoPtr<pointPatchVectorField> clone() const + { + return autoPtr<pointPatchVectorField> + ( + new edgeSlipDisplacementPointPatchVectorField + ( + *this + ) + ); + } + + //- Construct as copy setting internal field reference + edgeSlipDisplacementPointPatchVectorField + ( + const edgeSlipDisplacementPointPatchVectorField&, + const DimensionedField<vector, pointMesh>& + ); + + //- Construct and return a clone setting internal field reference + virtual autoPtr<pointPatchVectorField> clone + ( + const DimensionedField<vector, pointMesh>& iF + ) const + { + return autoPtr<pointPatchVectorField> + ( + new edgeSlipDisplacementPointPatchVectorField + ( + *this, + iF + ) + ); + } + + // Member Functions + + //- Update the coefficients associated with the patch field + virtual void updateCoeffs(); + + //- Read (& store) geometry. Exposed so point attraction can reuse it. + static void read + ( + const objectRegistry& obr, + const dictionary& dict + ); + + //- Write + virtual void write(Ostream&) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/fvMotionSolver/pointPatchFields/derived/pointAttractionDisplacement/pointAttractionDisplacementPointPatchVectorField.C b/src/fvMotionSolver/pointPatchFields/derived/pointAttractionDisplacement/pointAttractionDisplacementPointPatchVectorField.C new file mode 100644 index 0000000000000000000000000000000000000000..835b1c14859e71bf66e8c00b6d628f296399db81 --- /dev/null +++ b/src/fvMotionSolver/pointPatchFields/derived/pointAttractionDisplacement/pointAttractionDisplacementPointPatchVectorField.C @@ -0,0 +1,324 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "pointAttractionDisplacementPointPatchVectorField.H" +#include "addToRunTimeSelectionTable.H" +#include "Time.H" +#include "transformField.H" +#include "displacementMotionSolver.H" +#include "featureEdgeMesh.H" +#include "edgeSlipDisplacementPointPatchVectorField.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::pointAttractionDisplacementPointPatchVectorField::calcProjection +( + vectorField& displacement +) const +{ + const polyMesh& mesh = patch().boundaryMesh().mesh()(); + const labelList& meshPoints = patch().meshPoints(); + + //const scalar deltaT = mesh.time().deltaTValue(); + + // Construct large enough vector in direction of projectDir so + // we're guaranteed to hit something. + + //- Per point projection vector: + const scalar projectLen = mesh.bounds().mag(); + + + + // Get fixed points (bit of a hack) + const pointZone* zonePtr = nullptr; + + if (frozenPointsZone_.size() > 0) + { + const pointZoneMesh& pZones = mesh.pointZones(); + + zonePtr = &pZones[frozenPointsZone_]; + + Pout<< "pointAttractionDisplacementPointPatchVectorField : Fixing all " + << zonePtr->size() << " points in pointZone " << zonePtr->name() + << endl; + } + + // Get the starting locations from the motionSolver + const pointField& points0 = mesh.lookupObject<displacementMotionSolver> + ( + "dynamicMeshDict" + ).points0(); + + + pointField start(meshPoints.size()); + forAll(start, i) + { + start[i] = points0[meshPoints[i]] + displacement[i]; + } + + const auto& tree = pointTree(); + + label nNotProjected = 0; + forAll(meshPoints, i) + { + const label meshPointi = meshPoints[i]; + const point& pt = mesh.points()[meshPointi]; + + if (zonePtr && (zonePtr->whichPoint(meshPointi) >= 0)) + { + // Fixed point. Reset to point0 location. + displacement[i] = points0[meshPointi] - pt; + } + else + { + pointIndexHit nearest = tree.findNearest(start[i], sqr(projectLen)); + if (nearest.hit()) + { + displacement[i] = nearest.point() - points0[meshPointi]; + } + else + { + nNotProjected++; + + if (debug) + { + Pout<< " point:" << meshPointi + << " coord:" << pt + << " did not find any surface within " << projectLen + << endl; + } + } + } + } + + reduce(nNotProjected, sumOp<label>()); + + if (nNotProjected > 0) + { + Info<< "pointAttractionDisplacement :" + << " on patch " << patch().name() + << " did not project " << nNotProjected + << " out of " << returnReduce(meshPoints.size(), sumOp<label>()) + << " points." << endl; + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::pointAttractionDisplacementPointPatchVectorField:: +pointAttractionDisplacementPointPatchVectorField +( + const pointPatch& p, + const DimensionedField<vector, pointMesh>& iF +) +: + pointPatchVectorField(p, iF), + velocity_(Zero) +{} + + +Foam::pointAttractionDisplacementPointPatchVectorField:: +pointAttractionDisplacementPointPatchVectorField +( + const pointPatch& p, + const DimensionedField<vector, pointMesh>& iF, + const dictionary& dict +) +: + pointPatchVectorField(p, iF, dict), + velocity_(dict.get<vector>("velocity")), + featFileName_(dict.get<fileName>("file", keyType::LITERAL)), + frozenPointsZone_(dict.getOrDefault("frozenPointsZone", word::null)) +{ + // Read&store edge mesh on registry + edgeSlipDisplacementPointPatchVectorField::read + ( + this->patch().boundaryMesh().mesh().time(), + dict + ); +} + + +Foam::pointAttractionDisplacementPointPatchVectorField:: +pointAttractionDisplacementPointPatchVectorField +( + const pointAttractionDisplacementPointPatchVectorField& ppf, + const pointPatch& p, + const DimensionedField<vector, pointMesh>& iF, + const pointPatchFieldMapper& +) +: + pointPatchVectorField(p, iF), + velocity_(ppf.velocity_), + featFileName_(ppf.featFileName_), + frozenPointsZone_(ppf.frozenPointsZone_) +{} + + +Foam::pointAttractionDisplacementPointPatchVectorField:: +pointAttractionDisplacementPointPatchVectorField +( + const pointAttractionDisplacementPointPatchVectorField& ppf +) +: + pointPatchVectorField(ppf), + velocity_(ppf.velocity_), + featFileName_(ppf.featFileName_), + frozenPointsZone_(ppf.frozenPointsZone_) +{} + + +Foam::pointAttractionDisplacementPointPatchVectorField:: +pointAttractionDisplacementPointPatchVectorField +( + const pointAttractionDisplacementPointPatchVectorField& ppf, + const DimensionedField<vector, pointMesh>& iF +) +: + pointPatchVectorField(ppf, iF), + velocity_(ppf.velocity_), + featFileName_(ppf.featFileName_), + frozenPointsZone_(ppf.frozenPointsZone_) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::indexedOctree<Foam::treeDataPoint>& +Foam::pointAttractionDisplacementPointPatchVectorField::pointTree() const +{ + if (!pointTreePtr_) + { + const Time& tm = this->patch().boundaryMesh().mesh().time(); + const auto& eMesh = tm.lookupObject<edgeMesh>(featFileName_); + + const pointField& points = eMesh.points(); + + // Calculate bb of all points + treeBoundBox bb(points); + + // Random number generator. Bit dodgy since not exactly random ;-) + Random rndGen(65431); + + // Slightly extended bb. Slightly off-centred just so on symmetric + // geometry there are less face/edge aligned items. + bb.inflate(rndGen, 1e-4, ROOTVSMALL); + + pointTreePtr_.reset + ( + new indexedOctree<treeDataPoint> + ( + treeDataPoint(points), // All edges + + bb, // overall search domain + 8, // maxLevel + 10, // leafsize + 3.0 // duplicity + ) + ); + } + + return pointTreePtr_(); +} + + +void Foam::pointAttractionDisplacementPointPatchVectorField::updateCoeffs() +{ + if (this->updated()) + { + return; + } + + const vectorField currentDisplacement(this->patchInternalField()); + + // Calculate displacement to project points onto surface + vectorField displacement(currentDisplacement); + calcProjection(displacement); + + + // offset wrt current displacement + vectorField offset(displacement-currentDisplacement); + + // Clip offset to maximum displacement possible: velocity*timestep + + const Time& tm = this->patch().boundaryMesh().mesh().time(); + const scalar deltaT = tm.deltaTValue(); + const vector clipVelocity = velocity_*deltaT; + + forAll(displacement, i) + { + vector& d = offset[i]; + + const scalar magD(mag(d)); + if (magD > ROOTVSMALL) + { + d /= magD; + d *= min(magD, mag(clipVelocity)); + } + } + + // Get internal field to insert values into + Field<vector>& iF = const_cast<Field<vector>&>(this->primitiveField()); + + setInInternalField(iF, (currentDisplacement+offset)()); + + pointPatchVectorField::updateCoeffs(); +} + + +void Foam::pointAttractionDisplacementPointPatchVectorField::write +( + Ostream& os +) const +{ + pointPatchField<vector>::write(os); + os.writeEntry("file", featFileName_); + os.writeEntryIfDifferent<word> + ( + "frozenPointsZone", + word::null, + frozenPointsZone_ + ); + os.writeEntry("velocity", velocity_); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +makePointPatchTypeField +( + pointPatchVectorField, + pointAttractionDisplacementPointPatchVectorField +); + +} // End namespace Foam + +// ************************************************************************* // diff --git a/src/fvMotionSolver/pointPatchFields/derived/pointAttractionDisplacement/pointAttractionDisplacementPointPatchVectorField.H b/src/fvMotionSolver/pointPatchFields/derived/pointAttractionDisplacement/pointAttractionDisplacementPointPatchVectorField.H new file mode 100644 index 0000000000000000000000000000000000000000..cf87d9eb884f29efb450b1e63c1de0ca0b9b6360 --- /dev/null +++ b/src/fvMotionSolver/pointPatchFields/derived/pointAttractionDisplacement/pointAttractionDisplacementPointPatchVectorField.H @@ -0,0 +1,191 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::pointAttractionDisplacementPointPatchVectorField + +Description + Displacement by attraction to nearest point. Use in a + displacementMotionSolver as a bc on the pointDisplacement field. + + Needs: + - file : name of edgeMesh. Either: + - .extendedFeatureEdgeMesh (read from constant/extendedFeatureEdgeMesh) + - or .eMesh in or a known format (read from constant/triSurface) + - frozenPointsZone : empty or name of pointZone containing points + that do not move + - velocity : maximum displacement velocity + + +SourceFiles + pointAttractionDisplacementPointPatchVectorField.C + +\*---------------------------------------------------------------------------*/ + +#ifndef pointAttractionDisplacementPointPatchVectorField_H +#define pointAttractionDisplacementPointPatchVectorField_H + +#include "pointPatchFields.H" +#include "extendedFeatureEdgeMesh.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class pointAttractionDisplacementPointPatchVectorField Declaration +\*---------------------------------------------------------------------------*/ + +class pointAttractionDisplacementPointPatchVectorField +: + public pointPatchVectorField +{ +private: + + // Private data + + //- Maximum velocity + const vector velocity_; + + //- file + const fileName featFileName_; + + //- pointZone with frozen points + const word frozenPointsZone_; + + //- Point searching + mutable autoPtr<indexedOctree<treeDataPoint>> pointTreePtr_; + + + // Private Member Functions + + //- Calculate displacement (w.r.t. points0()) to project onto surface + void calcProjection(vectorField& displacement) const; + + //- No copy assignment + void operator= + ( + const pointAttractionDisplacementPointPatchVectorField& + ) = delete; + + +protected: + + const indexedOctree<treeDataPoint>& pointTree() const; + + +public: + + //- Runtime type information + TypeName("pointAttraction"); + + + // Constructors + + //- Construct from patch and internal field + pointAttractionDisplacementPointPatchVectorField + ( + const pointPatch&, + const DimensionedField<vector, pointMesh>& + ); + + //- Construct from patch, internal field and dictionary + pointAttractionDisplacementPointPatchVectorField + ( + const pointPatch&, + const DimensionedField<vector, pointMesh>&, + const dictionary& + ); + + //- Construct by mapping given patch field onto a new patch + pointAttractionDisplacementPointPatchVectorField + ( + const pointAttractionDisplacementPointPatchVectorField&, + const pointPatch&, + const DimensionedField<vector, pointMesh>&, + const pointPatchFieldMapper& + ); + + //- Construct as copy + pointAttractionDisplacementPointPatchVectorField + ( + const pointAttractionDisplacementPointPatchVectorField& + ); + + //- Construct and return a clone + virtual autoPtr<pointPatchVectorField> clone() const + { + return autoPtr<pointPatchVectorField> + ( + new pointAttractionDisplacementPointPatchVectorField + ( + *this + ) + ); + } + + //- Construct as copy setting internal field reference + pointAttractionDisplacementPointPatchVectorField + ( + const pointAttractionDisplacementPointPatchVectorField&, + const DimensionedField<vector, pointMesh>& + ); + + //- Construct and return a clone setting internal field reference + virtual autoPtr<pointPatchVectorField> clone + ( + const DimensionedField<vector, pointMesh>& iF + ) const + { + return autoPtr<pointPatchVectorField> + ( + new pointAttractionDisplacementPointPatchVectorField + ( + *this, + iF + ) + ); + } + + // Member Functions + + //- Update the coefficients associated with the patch field + virtual void updateCoeffs(); + + //- Write + virtual void write(Ostream&) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/fvMotionSolver/pointPatchFields/derived/surfaceDisplacement/surfaceDisplacementPointPatchVectorField.C b/src/fvMotionSolver/pointPatchFields/derived/surfaceDisplacement/surfaceDisplacementPointPatchVectorField.C index 92c499d62498f5b9cc176fc512a641cd452d16fa..2595f2053e5d38f900b39bd7e834c6df4e48cbfe 100644 --- a/src/fvMotionSolver/pointPatchFields/derived/surfaceDisplacement/surfaceDisplacementPointPatchVectorField.C +++ b/src/fvMotionSolver/pointPatchFields/derived/surfaceDisplacement/surfaceDisplacementPointPatchVectorField.C @@ -55,7 +55,6 @@ void Foam::surfaceDisplacementPointPatchVectorField::calcProjection ) const { const polyMesh& mesh = patch().boundaryMesh().mesh()(); - const pointField& localPoints = patch().localPoints(); const labelList& meshPoints = patch().meshPoints(); //const scalar deltaT = mesh.time().deltaTValue(); @@ -117,16 +116,19 @@ void Foam::surfaceDisplacementPointPatchVectorField::calcProjection forAll(nearest, i) { - if (zonePtr && (zonePtr->whichPoint(meshPoints[i]) >= 0)) + const label meshPointi = meshPoints[i]; + const point& pt = mesh.points()[meshPointi]; + + if (zonePtr && (zonePtr->whichPoint(meshPointi) >= 0)) { // Fixed point. Reset to point0 location. - displacement[i] = points0[meshPoints[i]] - localPoints[i]; + displacement[i] = points0[meshPointi] - pt; } else if (nearest[i].hit()) { displacement[i] = nearest[i].point() - - points0[meshPoints[i]]; + - points0[meshPointi]; } else { @@ -134,8 +136,8 @@ void Foam::surfaceDisplacementPointPatchVectorField::calcProjection if (debug) { - Pout<< " point:" << meshPoints[i] - << " coord:" << localPoints[i] + Pout<< " point:" << meshPointi + << " coord:" << pt << " did not find any surface within " << projectLen << endl; } @@ -207,17 +209,20 @@ void Foam::surfaceDisplacementPointPatchVectorField::calcProjection // 3. Choose either -fixed, nearest, right, left. forAll(displacement, i) { - if (zonePtr && (zonePtr->whichPoint(meshPoints[i]) >= 0)) + const label meshPointi = meshPoints[i]; + const point& pt = mesh.points()[meshPointi]; + + if (zonePtr && (zonePtr->whichPoint(meshPointi) >= 0)) { // Fixed point. Reset to point0 location. - displacement[i] = points0[meshPoints[i]] - localPoints[i]; + displacement[i] = points0[meshPointi] - pt; } else if (nearest[i].hit()) { // Found nearest. displacement[i] = nearest[i].point() - - points0[meshPoints[i]]; + - points0[meshPointi]; } else { @@ -257,7 +262,7 @@ void Foam::surfaceDisplacementPointPatchVectorField::calcProjection { interPt.point()[wedgePlane_] += offset[i]; } - displacement[i] = interPt.point() - points0[meshPoints[i]]; + displacement[i] = interPt.point() - points0[meshPointi]; } else { @@ -265,8 +270,8 @@ void Foam::surfaceDisplacementPointPatchVectorField::calcProjection if (debug) { - Pout<< " point:" << meshPoints[i] - << " coord:" << localPoints[i] + Pout<< " point:" << meshPointi + << " coord:" << pt << " did not find any intersection between" << " ray from " << start[i]-projectVecs[i] << " to " << start[i]+projectVecs[i] << endl; @@ -283,7 +288,7 @@ void Foam::surfaceDisplacementPointPatchVectorField::calcProjection Info<< "surfaceDisplacement :" << " on patch " << patch().name() << " did not project " << nNotProjected - << " out of " << returnReduce(localPoints.size(), sumOp<label>()) + << " out of " << returnReduce(meshPoints.size(), sumOp<label>()) << " points." << endl; } } @@ -318,7 +323,12 @@ surfaceDisplacementPointPatchVectorField velocity_(dict.get<vector>("velocity")), surfacesDict_(dict.subDict("geometry")), projectMode_(projectModeNames_.get("projectMode", dict)), - projectDir_(dict.get<vector>("projectDirection")), + projectDir_ + ( + (projectMode_ == FIXEDNORMAL) + ? dict.get<vector>("projectDirection") + : Zero + ), wedgePlane_(dict.getOrDefault("wedgePlane", -1)), frozenPointsZone_(dict.getOrDefault("frozenPointsZone", word::null)) { @@ -424,12 +434,13 @@ void Foam::surfaceDisplacementPointPatchVectorField::updateCoeffs() const polyMesh& mesh = patch().boundaryMesh().mesh()(); - vectorField currentDisplacement(this->patchInternalField()); + const vectorField currentDisplacement(this->patchInternalField()); // Calculate intersections with surface w.r.t points0. vectorField displacement(currentDisplacement); calcProjection(displacement); + // offset wrt current displacement vectorField offset(displacement-currentDisplacement); @@ -442,21 +453,15 @@ void Foam::surfaceDisplacementPointPatchVectorField::updateCoeffs() { vector& d = offset[i]; - for (direction cmpt = 0; cmpt < vector::nComponents; cmpt++) + const scalar magD(mag(d)); + if (magD > ROOTVSMALL) { - if (d[cmpt] < 0) - { - d[cmpt] = max(d[cmpt], -clipVelocity[cmpt]); - } - else - { - d[cmpt] = min(d[cmpt], clipVelocity[cmpt]); - } + d /= magD; + d *= min(magD, mag(clipVelocity)); } } this->operator==(currentDisplacement+offset); - fixedValuePointPatchVectorField::updateCoeffs(); } @@ -467,9 +472,13 @@ void Foam::surfaceDisplacementPointPatchVectorField::write(Ostream& os) const os.writeEntry("velocity", velocity_); os.writeEntry("geometry", surfacesDict_); os.writeEntry("projectMode", projectModeNames_[projectMode_]); - os.writeEntry("projectDirection", projectDir_); - os.writeEntry("wedgePlane", wedgePlane_); - + os.writeEntryIfDifferent<vector> + ( + "projectDirection", + Zero, + projectDir_ + ); + os.writeEntryIfDifferent<label>("wedgePlane", -1, wedgePlane_); os.writeEntryIfDifferent<word> ( "frozenPointsZone", diff --git a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C index 8d6b096d59d016cb5ee28d84313fa64d140f039b..14f9b9f875e6b27a05aaaf9098460309beb46bf0 100644 --- a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C +++ b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2020-2022 OpenCFD Ltd. + Copyright (C) 2020-2022,2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,6 +32,7 @@ License #include "transformField.H" #include "fvMesh.H" #include "displacementMotionSolver.H" +#include "facePointPatch.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -272,6 +273,16 @@ void Foam::surfaceSlipDisplacementPointPatchVectorField::calcProjection } } + if (scalePtr_) + { + const scalarField s + ( + scalePtr_->value(this->db().time().timeOutputValue()) + ); + + displacement *= s; + } + reduce(nNotProjected, sumOp<label>()); if (nNotProjected > 0) @@ -312,9 +323,24 @@ surfaceSlipDisplacementPointPatchVectorField pointPatchVectorField(p, iF, dict), surfacesDict_(dict.subDict("geometry")), projectMode_(projectModeNames_.get("projectMode", dict)), - projectDir_(dict.get<vector>("projectDirection")), + projectDir_ + ( + (projectMode_ == FIXEDNORMAL) + ? dict.get<vector>("projectDirection") + : Zero + ), wedgePlane_(dict.getOrDefault("wedgePlane", -1)), - frozenPointsZone_(dict.getOrDefault("frozenPointsZone", word::null)) + frozenPointsZone_(dict.getOrDefault("frozenPointsZone", word::null)), + scalePtr_ + ( + PatchFunction1<scalar>::NewIfPresent + ( + refCast<const facePointPatch>(p).patch(), + "scale", + dict, + false // point values + ) + ) {} @@ -332,7 +358,8 @@ surfaceSlipDisplacementPointPatchVectorField projectMode_(ppf.projectMode_), projectDir_(ppf.projectDir_), wedgePlane_(ppf.wedgePlane_), - frozenPointsZone_(ppf.frozenPointsZone_) + frozenPointsZone_(ppf.frozenPointsZone_), + scalePtr_(ppf.scalePtr_.clone(refCast<const facePointPatch>(p).patch())) {} @@ -347,7 +374,14 @@ surfaceSlipDisplacementPointPatchVectorField projectMode_(ppf.projectMode_), projectDir_(ppf.projectDir_), wedgePlane_(ppf.wedgePlane_), - frozenPointsZone_(ppf.frozenPointsZone_) + frozenPointsZone_(ppf.frozenPointsZone_), + scalePtr_ + ( + ppf.scalePtr_.clone + ( + refCast<const facePointPatch>(ppf.patch()).patch() + ) + ) {} @@ -363,7 +397,14 @@ surfaceSlipDisplacementPointPatchVectorField projectMode_(ppf.projectMode_), projectDir_(ppf.projectDir_), wedgePlane_(ppf.wedgePlane_), - frozenPointsZone_(ppf.frozenPointsZone_) + frozenPointsZone_(ppf.frozenPointsZone_), + scalePtr_ + ( + ppf.scalePtr_.clone + ( + refCast<const facePointPatch>(ppf.patch()).patch() + ) + ) {} @@ -397,23 +438,37 @@ Foam::surfaceSlipDisplacementPointPatchVectorField::surfaces() const } -void Foam::surfaceSlipDisplacementPointPatchVectorField::evaluate -( - const Pstream::commsTypes commsType -) +void Foam::surfaceSlipDisplacementPointPatchVectorField::updateCoeffs() { + if (this->updated()) + { + return; + } + vectorField displacement(this->patchInternalField()); // Calculate displacement to project points onto surface calcProjection(displacement); + if (debug) + { + Pout<< type() << " :" + << " on patch " << patch().name() + << " of field " << this->internalField().name() + << " projection" + << " min:" << gMin(displacement) + << " max:" << gMaxMagSqr(displacement) + << " average:" << gAverage(displacement) + << endl; + } + // Get internal field to insert values into Field<vector>& iF = const_cast<Field<vector>&>(this->primitiveField()); //setInInternalField(iF, motionU); setInInternalField(iF, displacement); - pointPatchVectorField::evaluate(commsType); + pointPatchVectorField::updateCoeffs(); } @@ -425,15 +480,24 @@ void Foam::surfaceSlipDisplacementPointPatchVectorField::write pointPatchField<vector>::write(os); os.writeEntry("geometry", surfacesDict_); os.writeEntry("projectMode", projectModeNames_[projectMode_]); - os.writeEntry("projectDirection", projectDir_); - os.writeEntry("wedgePlane", wedgePlane_); - + os.writeEntryIfDifferent<vector> + ( + "projectDirection", + Zero, + projectDir_ + ); + os.writeEntryIfDifferent<label>("wedgePlane", -1, wedgePlane_); os.writeEntryIfDifferent<word> ( "frozenPointsZone", word::null, frozenPointsZone_ ); + + if (scalePtr_) + { + scalePtr_->writeData(os); + } } diff --git a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H index a65d3d791079041503ed5626a7b7dc445c69bf3e..809c6c1c389c6efb59e2d9e17cf11e9aa2099ef4 100644 --- a/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H +++ b/src/fvMotionSolver/pointPatchFields/derived/surfaceSlipDisplacement/surfaceSlipDisplacementPointPatchVectorField.H @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation + Copyright (C) 2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -46,6 +47,8 @@ Description - wedgePlane : -1 or component to knock out of intersection normal - frozenPointsZone : empty or name of pointZone containing points that do not move + - scale : optional scaling factor as PatchFunction1 + SourceFiles surfaceSlipDisplacementPointPatchVectorField.C @@ -57,6 +60,7 @@ SourceFiles #include "pointPatchFields.H" #include "searchableSurfaces.H" +#include "PatchFunction1.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -105,6 +109,9 @@ private: //- pointZone with frozen points const word frozenPointsZone_; + //- Scalar scale factor + autoPtr<PatchFunction1<scalar>> scalePtr_; + //- Demand driven: surface to project mutable autoPtr<searchableSurfaces> surfacesPtr_; @@ -187,11 +194,8 @@ public: //- Surface to follow. Demand loads surfaceNames. const searchableSurfaces& surfaces() const; - //- Update the patch field - virtual void evaluate - ( - const Pstream::commsTypes commsType=Pstream::commsTypes::buffered - ); + //- Update the coefficients associated with the patch field + virtual void updateCoeffs(); //- Write virtual void write(Ostream&) const; diff --git a/src/mesh/snappyHexMesh/Make/files b/src/mesh/snappyHexMesh/Make/files index 28be73f7c19a1518a16812b2bef320e72e9bcffe..50a44505e83dcf427bc01192f08e745cc0439f79 100644 --- a/src/mesh/snappyHexMesh/Make/files +++ b/src/mesh/snappyHexMesh/Make/files @@ -2,6 +2,7 @@ snappyHexMeshDriver/snappyLayerDriver.C snappyHexMeshDriver/snappyLayerDriverSinglePass.C snappyHexMeshDriver/snappySnapDriver.C snappyHexMeshDriver/snappySnapDriverFeature.C +snappyHexMeshDriver/snappySnapDriverBufferLayers.C snappyHexMeshDriver/snappyRefineDriver.C snappyHexMeshDriver/snappyVoxelMeshDriver.C diff --git a/src/mesh/snappyHexMesh/externalDisplacementMeshMover/medialAxisMeshMover.C b/src/mesh/snappyHexMesh/externalDisplacementMeshMover/medialAxisMeshMover.C index 7db914643c1cf8bcf945a0e223fe7f0d25bbcafb..295013ecba66b10efd07182f41cf5dbbd4961be0 100644 --- a/src/mesh/snappyHexMesh/externalDisplacementMeshMover/medialAxisMeshMover.C +++ b/src/mesh/snappyHexMesh/externalDisplacementMeshMover/medialAxisMeshMover.C @@ -1692,6 +1692,22 @@ void Foam::medialAxisMeshMover::calculateDisplacement displacement ); } + + if (str) + { + Info<< typeName + << " : Written " << returnReduce(str().nVertices(), sumOp<label>()) + << " points with too large an extrusion distance to " + << str().name() << endl; + } + if (medialVecStr) + { + Info<< typeName + << " : Written " + << returnReduce(medialVecStr().nVertices(), sumOp<label>()) + << " medial axis vectors on points with too large" + << " an extrusion distance to " << medialVecStr().name() << endl; + } } diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C index 6838f904db6bb303cd657cfe55929dd66ce033ab..758f69f794222ef1574af0387612f1636244650b 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C @@ -75,6 +75,18 @@ namespace Foam } +const Foam::Enum +< + Foam::meshRefinement::MeshType +> +Foam::meshRefinement::MeshTypeNames +({ + { MeshType::CASTELLATED, "castellated" }, + { MeshType::CASTELLATEDBUFFERLAYER, "castellatedBufferLayer" }, + { MeshType::CASTELLATEDBUFFERLAYER2, "castellatedBufferLayer2" } +}); + + const Foam::Enum < Foam::meshRefinement::debugType @@ -1178,56 +1190,90 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::doRemoveCells } +void Foam::meshRefinement::splitFace +( + const face& f, + const labelPair& split, + + face& f0, + face& f1 +) +{ + if (split.find(-1) != -1) + { + FatalErrorInFunction<< "Illegal split " << split + << " on face " << f << exit(FatalError); + } + + label nVerts = split[1]-split[0]; + if (nVerts < 0) + { + nVerts += f.size(); + } + nVerts += 1; + + + // Split into f0, f1 + f0.resize_nocopy(nVerts); + + label fp = split[0]; + forAll(f0, i) + { + f0[i] = f[fp]; + fp = f.fcIndex(fp); + } + + f1.resize_nocopy(f.size()-f0.size()+2); + fp = split[1]; + forAll(f1, i) + { + f1[i] = f[fp]; + fp = f.fcIndex(fp); + } +} + + void Foam::meshRefinement::doSplitFaces ( const labelList& splitFaces, const labelPairList& splits, + const labelPairList& splitPatches, //const List<Pair<point>>& splitPoints, polyTopoChange& meshMod ) const { + face f0, f1; + forAll(splitFaces, i) { - label facei = splitFaces[i]; + const label facei = splitFaces[i]; + const auto& split = splits[i]; + const auto& twoPatches = splitPatches[i]; + const face& f = mesh_.faces()[facei]; // Split as start and end index in face - const labelPair& split = splits[i]; - - label nVerts = split[1]-split[0]; - if (nVerts < 0) - { - nVerts += f.size(); - } - nVerts += 1; - - - // Split into f0, f1 - face f0(nVerts); - - label fp = split[0]; - forAll(f0, i) - { - f0[i] = f[fp]; - fp = f.fcIndex(fp); - } - - face f1(f.size()-f0.size()+2); - fp = split[1]; - forAll(f1, i) - { - f1[i] = f[fp]; - fp = f.fcIndex(fp); - } - + splitFace(f, split, f0, f1); // Determine face properties label own = mesh_.faceOwner()[facei]; label nei = -1; - label patchi = -1; + label patch0 = -1; + label patch1 = -1; if (facei >= mesh_.nInternalFaces()) { - patchi = mesh_.boundaryMesh().whichPatch(facei); + patch0 = + ( + twoPatches[0] != -1 + ? twoPatches[0] + : mesh_.boundaryMesh().whichPatch(facei) + ); + patch1 = + ( + twoPatches[1] != -1 + ? twoPatches[1] + : mesh_.boundaryMesh().whichPatch(facei) + ); } else { @@ -1258,7 +1304,7 @@ void Foam::meshRefinement::doSplitFaces own, // owner nei, // neighbour false, // face flip - patchi, // patch for face + patch0, // patch for face zonei, // zone for face zoneFlip // face flip in zone ); @@ -1272,7 +1318,7 @@ void Foam::meshRefinement::doSplitFaces -1, // master edge facei, // master face false, // face flip - patchi, // patch for face + patch1, // patch for face zonei, // zone for face zoneFlip // face flip in zone ); @@ -1301,6 +1347,7 @@ Foam::label Foam::meshRefinement::splitFacesUndo ( const labelList& splitFaces, const labelPairList& splits, + const labelPairList& splitPatches, const dictionary& motionDict, labelList& duplicateFace, @@ -1327,7 +1374,7 @@ Foam::label Foam::meshRefinement::splitFacesUndo ); // Insert the mesh changes - doSplitFaces(splitFaces, splits, meshMod); + doSplitFaces(splitFaces, splits, splitPatches, meshMod); // Remove any unnecessary fields mesh_.clearOut(); @@ -1687,6 +1734,7 @@ Foam::meshRefinement::meshRefinement const shellSurfaces& shells, const shellSurfaces& limitShells, const labelUList& checkFaces, + const MeshType meshType, const bool dryRun ) : @@ -1698,6 +1746,7 @@ Foam::meshRefinement::meshRefinement features_(features), shells_(shells), limitShells_(limitShells), + meshType_(meshType), dryRun_(dryRun), meshCutter_ ( @@ -1774,6 +1823,7 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance ( const bool keepZoneFaces, const bool keepBaffles, + const labelList& singleProcPoints, const scalarField& cellWeights, decompositionMethod& decomposer, fvMeshDistribute& distributor @@ -1952,6 +2002,40 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance blockedFace[baffle.second()] = false; } + if (returnReduceOr(singleProcPoints.size())) + { + // Modify couples to force all selected points be on the same + // processor + + const polyBoundaryMesh& pbm = mesh_.boundaryMesh(); + + label nPointFaces = 0; + for (const label pointi : singleProcPoints) + { + for (const label facei : mesh_.pointFaces()[pointi]) + { + if (blockedFace[facei]) + { + if + ( + mesh_.isInternalFace(facei) + || pbm[pbm.whichPatch(facei)].coupled() + ) + { + blockedFace[facei] = false; + nPointFaces++; + } + } + } + } + reduce(nPointFaces, sumOp<label>()); + Info<< "Found " << nPointFaces + << " additional point-coupled faces to keep together." << endl; + + nUnblocked += nPointFaces; + } + + distribution = decomposer.decompose ( mesh_, diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H index 7e3b43f9cbb60187d953aef979a333054d991cb3..cc87edc7623c623ec0135b99255e32aa0fa8f6fe 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2023 OpenCFD Ltd. + Copyright (C) 2015-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -91,6 +91,18 @@ public: // Public Data Types + //- Enumeration for how to operate + enum MeshType + { + CASTELLATED, // split-hex refinement, snapping, layer addition + CASTELLATEDBUFFERLAYER, // same but add buffer layers before + // snapping + CASTELLATEDBUFFERLAYER2 // experimental. wip. + }; + + static const Enum<MeshType> MeshTypeNames; + + //- Enumeration for what to debug. Used as a bit-pattern. enum debugType { @@ -179,9 +191,13 @@ private: //- All limit-refinement interaction const shellSurfaces& limitShells_; + //- How to generate mesh + const MeshType meshType_; + //- Are we operating in test mode? const bool dryRun_; + //- Refinement engine hexRef8 meshCutter_; @@ -778,10 +794,12 @@ private: //- Extract those baffles (duplicate) faces that are on the edge // of a baffle region. These are candidates for merging. + // samePatch : include only if both sides on the same patch. List<labelPair> freeStandingBaffles ( const List<labelPair>&, - const scalar freeStandingAngle + const scalar freeStandingAngle, + const bool samePatch ) const; @@ -997,6 +1015,7 @@ public: const shellSurfaces&, // omnidirectional refinement const shellSurfaces&, // limit refinement const labelUList& checkFaces, // initial faces to check + const MeshType meshType, const bool dryRun ); @@ -1062,6 +1081,12 @@ public: return meshCutter_; } + //- Mode of meshing + MeshType meshType() const + { + return meshType_; + } + //- Per start-end edge the index of the surface hit const labelList& surfaceIndex() const; @@ -1098,10 +1123,12 @@ public: // keepZoneFaces : find all faceZones from zoned surfaces and keep // owner and neighbour together // keepBaffles : find all baffles and keep them together + // singleProcPoints : all faces using point are kept together autoPtr<mapDistributePolyMesh> balance ( const bool keepZoneFaces, const bool keepBaffles, + const labelList& singleProcPoints, const scalarField& cellWeights, decompositionMethod& decomposer, fvMeshDistribute& distributor @@ -1366,6 +1393,7 @@ public: //- Merge free-standing baffles void mergeFreeStandingBaffles ( + const bool samePatch, const snapParameters& snapParams, const bool useTopologicalSnapDetection, const bool removeEdgeConnectedCells, @@ -1449,6 +1477,14 @@ public: const List<labelPair>& baffles ); + //- Map baffles after layer addition. Gets new-to-old face map. + static void mapBaffles + ( + const polyMesh& mesh, + const labelList& faceMap, + List<labelPair>& baffles + ); + //- Get per-face information (faceZone, master/slave patch) void getZoneFaces ( @@ -1625,11 +1661,24 @@ public: const refPtr<coordSetWriter>& leakPathFormatter ); + //- Helper: split face into: + // - f0 : split[0] to split[1] + // - f1 : split[1] to split[0] + static void splitFace + ( + const face& f, + const labelPair& split, + + face& f0, + face& f1 + ); + //- Split faces into two void doSplitFaces ( const labelList& splitFaces, const labelPairList& splits, + const labelPairList& splitPatches, polyTopoChange& meshMod ) const; @@ -1639,6 +1688,7 @@ public: ( const labelList& splitFaces, const labelPairList& splits, + const labelPairList& splitPatches, const dictionary& motionDict, labelList& duplicateFace, diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C index 1286200ced72933dbda83cc36ce44a2d02fa5ef2..3afa51b1e3741b43694666cd956d65a883a4ecae 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2014 OpenFOAM Foundation - Copyright (C) 2015-2023 OpenCFD Ltd. + Copyright (C) 2015-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -727,6 +727,49 @@ Foam::List<Foam::labelPair> Foam::meshRefinement::subsetBaffles } +void Foam::meshRefinement::mapBaffles +( + const polyMesh& mesh, + const labelList& faceMap, + List<labelPair>& baffles +) +{ + // Create old-to-new map just for boundary faces. (since multiple faces + // get created from the same baffle face) + labelList reverseFaceMap(mesh.nFaces(), -1); + for + ( + label facei = mesh.nInternalFaces(); + facei < mesh.nFaces(); + facei++ + ) + { + label oldFacei = faceMap[facei]; + if (oldFacei != -1) + { + reverseFaceMap[oldFacei] = facei; + } + } + + + DynamicList<labelPair> newBaffles(baffles.size()); + forAll(baffles, i) + { + const labelPair& p = baffles[i]; + labelPair newBaffle + ( + reverseFaceMap[p[0]], + reverseFaceMap[p[1]] + ); + if (newBaffle[0] != -1 && newBaffle[1] != -1) + { + newBaffles.append(newBaffle); + } + } + baffles = std::move(newBaffles); +} + + void Foam::meshRefinement::getZoneFaces ( const labelList& zoneIDs, @@ -927,7 +970,8 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createZoneBaffles Foam::List<Foam::labelPair> Foam::meshRefinement::freeStandingBaffles ( const List<labelPair>& couples, - const scalar planarAngle + const scalar planarAngle, + const bool samePatch ) const { // Done by counting the number of baffles faces per mesh edge. If edge @@ -1036,8 +1080,11 @@ Foam::List<Foam::labelPair> Foam::meshRefinement::freeStandingBaffles if ( - patches.whichPatch(couple.first()) - == patches.whichPatch(couple.second()) + !samePatch + || ( + patches.whichPatch(couple.first()) + == patches.whichPatch(couple.second()) + ) ) { const labelList& fEdges = mesh_.faceEdges(couple.first()); @@ -2430,15 +2477,24 @@ void Foam::meshRefinement::growCellZone // No blocked faces, limitless gap size const bitSet isBlockedFace(mesh_.nFaces()); - List<scalarList> regionToBlockSize(surfaces_.surfaces().size()); + //List<scalarList> regionToBlockSize(surfaces_.surfaces().size()); + //{ + // forAll(surfaces_.surfaces(), surfi) + // { + // const label geomi = surfaces_.surfaces()[surfi]; + // const auto& s = surfaces_.geometry()[geomi]; + // const label nRegions = s.regions().size(); + // regionToBlockSize[surfi].setSize(nRegions, Foam::sqr(GREAT)); + // } + //} + + //- regionToBlockSize is indexed with cellZone index (>= 0) and region + //- on cellZone (currently always 0) + const auto& czs = mesh_.cellZones(); + List<scalarList> regionToBlockSize(czs.size()); + for (auto& blockSizes : regionToBlockSize) { - forAll(surfaces_.surfaces(), surfi) - { - const label geomi = surfaces_.surfaces()[surfi]; - const auto& s = surfaces_.geometry()[geomi]; - const label nRegions = s.regions().size(); - regionToBlockSize[surfi].setSize(nRegions, Foam::sqr(GREAT)); - } + blockSizes.setSize(1, Foam::sqr(GREAT)); } @@ -4773,6 +4829,7 @@ void Foam::meshRefinement::baffleAndSplitMesh void Foam::meshRefinement::mergeFreeStandingBaffles ( + const bool samePatch, const snapParameters& snapParams, const bool useTopologicalSnapDetection, const bool removeEdgeConnectedCells, @@ -4801,7 +4858,8 @@ void Foam::meshRefinement::mergeFreeStandingBaffles freeStandingBaffles // filter out freestanding baffles ( localPointRegion::findDuplicateFacePairs(mesh_), - planarAngle + planarAngle, + samePatch ) ); diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementProblemCells.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementProblemCells.C index 61fa183e7d7d6c9f20fc73c8f10fefcabe6f856a..f4de036e95c714905e80adcf738dbe0966a98793 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementProblemCells.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementProblemCells.C @@ -1112,8 +1112,9 @@ void Foam::meshRefinement::markFacesOnProblemCellsGeometric *this, globalToMasterPatch, globalToSlavePatch, - snapDist, // attraction pp, + pp.localPoints(), + snapDist, // attraction nearestPoint, nearestNormal ) diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C index cec01d92c7444a28adde9532fe7229279477659b..d8c2ada5e33a22b3176a8cc3af00bcfdd9ec37db 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementRefine.C @@ -2674,6 +2674,7 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance ( false, //keepZoneFaces false, //keepBaffles + labelList::null(), //singleProcPoints cellWeights, decomposer, distributor diff --git a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C index 5b32ac72cfc4335e6eebfa940e49ec108c1275fc..07a648247d64b9caa9cdb7e3bcf422cb3f720a08 100644 --- a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C +++ b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2015-2022 OpenCFD Ltd. + Copyright (C) 2015-2022,2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -208,6 +208,9 @@ Foam::refinementSurfaces::refinementSurfaces labelList globalBlockLevel(surfI, labelMax); labelList globalLeakLevel(surfI, labelMax); + // Supported in buffer-layer mode only + boolList globalBufferLayers(surfI, true); + // Per surface, per region data List<Map<label>> regionMinLevel(surfI); List<Map<label>> regionMaxLevel(surfI); @@ -220,6 +223,7 @@ Foam::refinementSurfaces::refinementSurfaces List<Map<autoPtr<dictionary>>> regionPatchInfo(surfI); List<Map<label>> regionBlockLevel(surfI); List<Map<label>> regionLeakLevel(surfI); + List<Map<label>> regionBufferLayers(surfI); wordHashSet unmatchedKeys(surfacesDict.toc()); @@ -346,7 +350,7 @@ Foam::refinementSurfaces::refinementSurfaces dict.readIfPresent("perpendicularAngle", globalAngle[surfI]); dict.readIfPresent("blockLevel", globalBlockLevel[surfI]); dict.readIfPresent("leakLevel", globalLeakLevel[surfI]); - + dict.readIfPresent("addBufferLayers", globalBufferLayers[surfI]); if (dict.found("regions")) { @@ -499,6 +503,14 @@ Foam::refinementSurfaces::refinementSurfaces { regionLeakLevel[surfI].insert(regionI, l); } + bool s; + if + ( + regionDict.readIfPresent<bool>("addBufferLayers", s) + ) + { + regionBufferLayers[surfI].insert(regionI, s); + } } } } @@ -551,6 +563,8 @@ Foam::refinementSurfaces::refinementSurfaces blockLevel_ = labelMax; leakLevel_.setSize(nRegions); leakLevel_ = labelMax; + addBufferLayers_.setSize(nRegions); + addBufferLayers_ = false; forAll(globalMinLevel, surfI) @@ -582,6 +596,7 @@ Foam::refinementSurfaces::refinementSurfaces } blockLevel_[globalRegionI] = globalBlockLevel[surfI]; leakLevel_[globalRegionI] = globalLeakLevel[surfI]; + addBufferLayers_[globalRegionI] = globalBufferLayers[surfI]; } // Overwrite with region specific information @@ -636,6 +651,11 @@ Foam::refinementSurfaces::refinementSurfaces blockLevel_[globalRegionI] = iter.val(); leakLevel_[globalRegionI] = iter.val(); } + forAllConstIters(regionBufferLayers[surfI], iter) + { + const label globalRegionI = regionOffset_[surfI] + iter.key(); + addBufferLayers_[globalRegionI] = iter.val(); + } } } diff --git a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H index 8f022033584f254f9f5ca46270280fdb1100d7de..6a035f14d0a18a9c5f018ceef5b7fe006b9ffe05 100644 --- a/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H +++ b/src/mesh/snappyHexMesh/refinementSurfaces/refinementSurfaces.H @@ -119,6 +119,9 @@ class refinementSurfaces //- From global region number to patchType PtrList<dictionary> patchInfo_; + //- From global region number to whether to add buffer layers + boolList addBufferLayers_; + //- Are we operating in test mode? const bool dryRun_; @@ -291,6 +294,13 @@ public: return patchInfo_; } + //- From global region number to whether to add buffer layers + // when snapping + const boolList& addBufferLayers() const + { + return addBufferLayers_; + } + // Helper diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.C index 94365fc3670a0a13d312ce33efedc8447a85ebcb..42e2bd77ee3454ae634eb52bc1a13a11bef3f6f8 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.C +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.C @@ -1000,15 +1000,16 @@ void Foam::snappyLayerDriver::handleWarpedFaces void Foam::snappyLayerDriver::setNumLayers ( + meshRefinement& meshRefiner, const labelList& patchToNLayers, const labelList& patchIDs, const indirectPrimitivePatch& pp, labelList& patchNLayers, List<extrudeMode>& extrudeStatus, label& nAddedCells -) const +) { - const fvMesh& mesh = meshRefiner_.mesh(); + const fvMesh& mesh = meshRefiner.mesh(); Info<< nl << "Handling points with inconsistent layer specification ..." << endl; @@ -1181,7 +1182,7 @@ Foam::snappyLayerDriver::makeLayerDisplacementField "pointDisplacement", mesh.time().timeName(), mesh, - IOobject::NO_READ, + IOobject::NO_READ, IOobject::AUTO_WRITE ), pMesh, @@ -1284,6 +1285,7 @@ void Foam::snappyLayerDriver::growNoExtrusion void Foam::snappyLayerDriver::determineSidePatches ( + meshRefinement& meshRefiner, const globalIndex& globalFaces, const labelListList& edgeGlobalFaces, const indirectPrimitivePatch& pp, @@ -1300,7 +1302,7 @@ void Foam::snappyLayerDriver::determineSidePatches // mean that 2 procesors that were only edge-connected now suddenly need // to become face-connected i.e. have a processor patch between them. - fvMesh& mesh = meshRefiner_.mesh(); + fvMesh& mesh = meshRefiner.mesh(); // Determine edgePatchID. Any additional processor boundary gets added to // patchToNbrProc,nbrProcToPatch and nPatches gets set to the new number @@ -1361,7 +1363,7 @@ void Foam::snappyLayerDriver::determineSidePatches // << " between " << Pstream::myProcNo() // << " and " << nbrProci << endl; - label procPatchi = meshRefiner_.appendPatch + label procPatchi = meshRefiner.appendPatch ( mesh, mesh.boundaryMesh().size(), // new patch index @@ -1769,14 +1771,15 @@ void Foam::snappyLayerDriver::calculateLayerThickness // Synchronize displacement among coupled patches. void Foam::snappyLayerDriver::syncPatchDisplacement ( + const fvMesh& mesh, const indirectPrimitivePatch& pp, const scalarField& minThickness, pointField& patchDisp, labelList& patchNLayers, List<extrudeMode>& extrudeStatus -) const +) { - const fvMesh& mesh = meshRefiner_.mesh(); + //const fvMesh& mesh = meshRefiner.mesh(); const labelList& meshPoints = pp.meshPoints(); //label nChangedTotal = 0; @@ -2106,6 +2109,7 @@ void Foam::snappyLayerDriver::getPatchDisplacement // Make sure displacement is equal on both sides of coupled patches. syncPatchDisplacement ( + mesh, pp, minThickness, patchDisp, @@ -2300,6 +2304,7 @@ Foam::label Foam::snappyLayerDriver::truncateDisplacement { syncPatchDisplacement ( + mesh, pp, minThickness, patchDisp, @@ -3358,8 +3363,9 @@ bool Foam::snappyLayerDriver::writeLayerData } -void Foam::snappyLayerDriver::dupFaceZonePoints +Foam::autoPtr<Foam::mapPolyMesh> Foam::snappyLayerDriver::dupFaceZonePoints ( + meshRefinement& meshRefiner, const labelList& patchIDs, // patch indices const labelList& numLayers, // number of layers per patch List<labelPair> baffles, // pairs of baffles (input & updated) @@ -3367,7 +3373,7 @@ void Foam::snappyLayerDriver::dupFaceZonePoints // point) ) { - fvMesh& mesh = meshRefiner_.mesh(); + fvMesh& mesh = meshRefiner.mesh(); // Check outside of baffles for non-manifoldness @@ -3395,6 +3401,7 @@ void Foam::snappyLayerDriver::dupFaceZonePoints // Get number of layers per point from number of layers per patch setNumLayers ( + meshRefiner, numLayers, // per patch the num layers patchIDs, // patches that are being moved *pp, // indirectpatch for all faces moving @@ -3408,6 +3415,7 @@ void Foam::snappyLayerDriver::dupFaceZonePoints // of the patchDisp here. syncPatchDisplacement ( + mesh, *pp, scalarField(patchDisp.size(), Zero), //minThickness, patchDisp, @@ -3474,7 +3482,7 @@ void Foam::snappyLayerDriver::dupFaceZonePoints { label mpi, spi; surfaceZonesInfo::faceZoneType fzType; - bool hasInfo = meshRefiner_.getFaceZoneInfo + bool hasInfo = meshRefiner.getFaceZoneInfo ( mesh.faceZones()[zonei].name(), mpi, @@ -3497,7 +3505,7 @@ void Foam::snappyLayerDriver::dupFaceZonePoints const localPointRegion regionSide(mesh, nonDupBaffles, candidatePoints); - autoPtr<mapPolyMesh> map = meshRefiner_.dupNonManifoldPoints + autoPtr<mapPolyMesh> map = meshRefiner.dupNonManifoldPoints ( regionSide ); @@ -3539,9 +3547,9 @@ void Foam::snappyLayerDriver::dupFaceZonePoints { const_cast<Time&>(mesh.time())++; Info<< "Writing point-duplicate mesh to time " - << meshRefiner_.timeName() << endl; + << meshRefiner.timeName() << endl; - meshRefiner_.write + meshRefiner.write ( meshRefinement::debugType(debug), meshRefinement::writeType @@ -3549,14 +3557,14 @@ void Foam::snappyLayerDriver::dupFaceZonePoints meshRefinement::writeLevel() | meshRefinement::WRITEMESH ), - mesh.time().path()/meshRefiner_.timeName() + mesh.time().path()/meshRefiner.timeName() ); OBJstream str ( mesh.time().path() / "duplicatePoints_" - + meshRefiner_.timeName() + + meshRefiner.timeName() + ".obj" ); Info<< "Writing point-duplicates to " << str.name() << endl; @@ -3572,6 +3580,7 @@ void Foam::snappyLayerDriver::dupFaceZonePoints } } } + return map; } @@ -3721,6 +3730,7 @@ Foam::label Foam::snappyLayerDriver::setPointNumLayers setNumLayers ( + meshRefiner_, numLayers, // per patch the num layers patchIDs, // patches that are being moved pp, // indirectpatch for all faces moving @@ -4017,6 +4027,7 @@ void Foam::snappyLayerDriver::addLayers // that. syncPatchDisplacement ( + mesh, pp, minThickness, patchDisp, @@ -4410,12 +4421,13 @@ void Foam::snappyLayerDriver::addLayers void Foam::snappyLayerDriver::mapFaceZonePoints ( + meshRefinement& meshRefiner, const mapPolyMesh& map, labelPairList& baffles, labelList& pointToMaster -) const +) { - fvMesh& mesh = meshRefiner_.mesh(); + fvMesh& mesh = meshRefiner.mesh(); // Use geometric detection of points-to-be-merged // - detect any boundary face created from a duplicated face (=baffle) @@ -4517,7 +4529,7 @@ void Foam::snappyLayerDriver::mapFaceZonePoints label nNew = Foam::mergePoints ( UIndirectList<point>(mesh.points(), candidates), - meshRefiner_.mergeDistance(), + meshRefiner.mergeDistance(), false, oldToNew ); @@ -4811,6 +4823,7 @@ void Foam::snappyLayerDriver::addLayers labelList pointToMaster; dupFaceZonePoints ( + meshRefiner_, patchIDs, // patch indices numLayers, // number of layers per patch baffles, @@ -4960,7 +4973,7 @@ void Foam::snappyLayerDriver::addLayers << "-------------------" << endl; if (debug) { - Info<< " Layers to add in current iteration : " << nToAdd << endl; + Info<< "Layers to add in current iteration : " << nToAdd << endl; } if (nToAdd == 0) { @@ -4977,6 +4990,7 @@ void Foam::snappyLayerDriver::addLayers labelList inflateFaceID; determineSidePatches ( + meshRefiner_, globalFaces, edgeGlobalFaces, *pp, @@ -5084,7 +5098,7 @@ void Foam::snappyLayerDriver::addLayers const label nTotalAdded = gSum(patchNLayers); if (debug) { - Info<< nl << " Added in current iteration : " << nTotalAdded + Info<< nl << "Added in current iteration : " << nTotalAdded << " out of : " << gSum(deltaNLayers) << endl; } if (nTotalAdded == 0) @@ -5225,7 +5239,7 @@ void Foam::snappyLayerDriver::addLayers // Map baffles, pointToMaster - mapFaceZonePoints(map, baffles, pointToMaster); + mapFaceZonePoints(meshRefiner_, map, baffles, pointToMaster); // Map patch and layer settings labelList newToOldPatchPoints; @@ -5325,6 +5339,7 @@ void Foam::snappyLayerDriver::addLayers ( false, false, + labelList::null(), scalarField(mesh.nCells(), 1.0), decomposer, distributor @@ -5607,6 +5622,7 @@ void Foam::snappyLayerDriver::doLayers ( true, // keepZoneFaces false, + labelList::null(), cellWeights, decomposer, distributor diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.H b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.H index 5a71785bfd85e500b88665d42d112d04f84208cd..384f61ff88085c23236326114350af41c17a9e0b 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.H +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriver.H @@ -248,8 +248,9 @@ private: //- Determine the number of layers per point from the number of // layers per surface. - void setNumLayers + static void setNumLayers ( + meshRefinement& meshRefiner, const labelList& patchToNLayers, const labelList& patchIDs, const indirectPrimitivePatch& pp, @@ -257,7 +258,7 @@ private: labelList& patchNLayers, List<extrudeMode>& extrudeStatus, label& nIdealAddedCells - ) const; + ); //- Determine number of layers per point; include static checks //- on invalid extrusion (e.g. non-manifold) @@ -282,12 +283,6 @@ private: const scalarIOField& minThickness, pointVectorField& displacement ) const; - void mapFaceZonePoints - ( - const mapPolyMesh& map, - labelPairList& baffles, - labelList& pointToMaster - ) const; void updatePatch ( const labelList& patchIDs, @@ -319,15 +314,6 @@ private: List<extrudeMode>& extrudeStatus ) const; - //- Duplicate points on faceZones with layers - void dupFaceZonePoints - ( - const labelList& patchIDs, // patch indices - const labelList& numLayers, // number of layers per patch - List<labelPair> baffles, - labelList& pointToMaster - ); - //- Re-merge points/faces on faceZones. Opposite of //- dupFaceZonePoints above void mergeFaceZonePoints @@ -338,19 +324,6 @@ private: scalarField& faceWantedThickness ); - //- See what zones and patches edges should be extruded into - void determineSidePatches - ( - const globalIndex& globalFaces, - const labelListList& edgeGlobalFaces, - const indirectPrimitivePatch& pp, - - labelList& edgePatchID, - labelList& edgeZoneID, - boolList& edgeFlip, - labelList& inflateFaceID - ); - //- Calculate pointwise wanted and minimum thickness. // thickness: wanted thickness // minthickness: when to give up and not extrude @@ -374,14 +347,15 @@ private: // Extrusion execution //- Synchronize displacement among coupled patches. - void syncPatchDisplacement + static void syncPatchDisplacement ( + const fvMesh& mesh, const indirectPrimitivePatch& pp, const scalarField& minThickness, pointField& patchDisp, labelList& patchNLayers, List<extrudeMode>& extrudeStatus - ) const; + ); //- Get nearest point on surface to snap to void getPatchDisplacement @@ -727,6 +701,41 @@ public: decompositionMethod& decomposer, fvMeshDistribute& distributor ); + + //- Helper: see what zones and patches edges should be extruded into + static void determineSidePatches + ( + meshRefinement& meshRefiner, + const globalIndex& globalFaces, + const labelListList& edgeGlobalFaces, + const indirectPrimitivePatch& pp, + + labelList& edgePatchID, + labelList& edgeZoneID, + boolList& edgeFlip, + labelList& inflateFaceID + ); + + //- Duplicate points on faceZones with layers. Re-used when adding + //- buffer layers. Can be made private again once multi-side + //- layer addition working. + static autoPtr<mapPolyMesh> dupFaceZonePoints + ( + meshRefinement& meshRefiner, + const labelList& patchIDs, // patch indices + const labelList& numLayers, // number of layers per patch + List<labelPair> baffles, + labelList& pointToMaster + ); + + //- Map numbering after adding cell layers + static void mapFaceZonePoints + ( + meshRefinement& meshRefiner, + const mapPolyMesh& map, + labelPairList& baffles, + labelList& pointToMaster + ); }; diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriverSinglePass.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriverSinglePass.C index 0b8c4f977a43402edefa4a066d80e604619a4ebb..c886d777078ed34be7df07b173b6422714e44587 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriverSinglePass.C +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyLayerDriverSinglePass.C @@ -179,6 +179,7 @@ void Foam::snappyLayerDriver::addLayersSinglePass labelList pointToMaster; dupFaceZonePoints ( + meshRefiner_, patchIDs, // patch indices numLayers, // number of layers per patch baffles, @@ -231,6 +232,7 @@ void Foam::snappyLayerDriver::addLayersSinglePass labelList inflateFaceID; determineSidePatches ( + meshRefiner_, globalFaces, edgeGlobalFaces, *pp, @@ -437,7 +439,7 @@ void Foam::snappyLayerDriver::addLayersSinglePass // Map baffles, pointToMaster - mapFaceZonePoints(map, baffles, pointToMaster); + mapFaceZonePoints(meshRefiner_, map, baffles, pointToMaster); } @@ -471,6 +473,7 @@ void Foam::snappyLayerDriver::addLayersSinglePass ( false, false, + labelList::null(), scalarField(mesh.nCells(), 1.0), decomposer, distributor diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C index 8837ce88015c30cd04acb0e678731206460fb6bf..bdb55c6faf16afb367b58550a65a7741606c9d9c 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2015-2023 OpenCFD Ltd. + Copyright (C) 2015-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -49,6 +49,7 @@ License #include "snappyVoxelMeshDriver.H" #include "regionSplit.H" #include "removeCells.H" +#include "addPatchCellLayer.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -2805,8 +2806,23 @@ void Foam::snappyRefineDriver::baffleAndSplitMesh if (!handleSnapProblems) // merge free standing baffles? { + // By default only merge baffles if on same patch. However the patching + // of the castellated mesh is not very accurate. For backwards + // compatibility disable check for new mode only. + const auto mt = meshRefiner_.meshType(); + const bool mergeSameOnly + ( + ( + mt == meshRefinement::CASTELLATEDBUFFERLAYER + || mt == meshRefinement::CASTELLATEDBUFFERLAYER2 + ) + ? false + : true + ); + meshRefiner_.mergeFreeStandingBaffles ( + mergeSameOnly, // whether to merge baffles on different patches snapParams, refineParams.useTopologicalSnapDetection(), false, // perpendicular edge connected cells @@ -2942,9 +2958,24 @@ void Foam::snappyRefineDriver::splitAndMergeBaffles surfFormatter_ ); - // Merge free-standing baffles always + + // By default only merge baffles if on same patch. However the patching + // of the castellated mesh is not very accurate. For backwards + // compatibility disable check for new mode only. + const auto mt = meshRefiner_.meshType(); + const bool mergeSameOnly + ( + ( + mt == meshRefinement::CASTELLATEDBUFFERLAYER + || mt == meshRefinement::CASTELLATEDBUFFERLAYER2 + ) + ? false + : true + ); + meshRefiner_.mergeFreeStandingBaffles ( + mergeSameOnly, snapParams, refineParams.useTopologicalSnapDetection(), handleSnapProblems, @@ -3027,6 +3058,145 @@ void Foam::snappyRefineDriver::splitAndMergeBaffles } +void Foam::snappyRefineDriver::erodeNonManifoldZoneFaces +( + const refinementParameters& refineParams +) +{ + if (dryRun_) + { + return; + } + + addProfiling(merge, "snappyHexMesh::refine::erode"); + Info<< nl + << "Erode non-manifold zone faces" << nl + << "-----------------------------" << nl + << endl; + + auto& mesh = meshRefiner_.mesh(); + auto& fzs = mesh.faceZones(); + + // Detect a faceZone face that: + // - sits on the edge of the faceZone (i.e. has an open edge) + // - has a non-manifold edge + // + // Limitations: + // - analyses across all zones - does not support overlapping zones + // - requires zones to be consistent across processor patches + + bitSet isZoneFace(mesh.nFaces()); + for (const auto& fz : fzs) + { + isZoneFace.set(fz.addressing()); + } + // Unmark non-owner side of processor patches so they don't get double + // counted. + const auto& pbm = mesh.boundaryMesh(); + for (label patchi = pbm.nNonProcessor(); patchi < pbm.size(); patchi++) + { + if (!refCast<const processorPolyPatch>(pbm[patchi]).owner()) + { + isZoneFace.unset(pbm[patchi].range()); + } + } + + + // TBD: replace with mesh.globalData().globalMeshFaceAddr() + const globalIndex globalFaces(mesh.nFaces()); + + label nChanged = 0; + + while (true) + { + const labelList meshFaces(isZoneFace.sortedToc()); + + const indirectPrimitivePatch pp + ( + IndirectList<face> + ( + mesh.faces(), + meshFaces + ), + mesh.points() + ); + + const labelListList edgeGlobalFaces + ( + addPatchCellLayer::globalEdgeFaces + ( + mesh, + globalFaces, + pp + ) + ); + + const label nOldChanged = nChanged; + forAll(pp, patchFacei) + { + // Detect at least one open edge and one non-manifold edge + label nOpen = 0; + label nNonManif = 0; + for (const label edgei : pp.faceEdges()[patchFacei]) + { + if (edgeGlobalFaces[edgei].size() == 1) + { + nOpen++; + } + else if (edgeGlobalFaces[edgei].size() > 2) + { + nNonManif++; + } + } + if (nNonManif > 0 && nOpen > 0) + { + isZoneFace.unset(meshFaces[patchFacei]); + nChanged++; + } + } + + if (returnReduce((nChanged-nOldChanged), sumOp<label>()) == 0) + { + break; + } + } + + + reduce(nChanged, sumOp<label>()); + + if (nChanged) + { + // Filter out eroded faceZone faces + fzs.clearAddressing(); + + for (auto& fz : fzs) + { + DynamicList<label> addressing(fz.size()); + DynamicList<bool> flipMap(fz.size()); + + forAll(fz.addressing(), i) + { + if (isZoneFace[fz.addressing()[i]]) + { + addressing.append(fz.addressing()[i]); + flipMap.append(fz.flipMap()[i]); + } + } + + //Pout<< "** on faceZone:" << fz.name() + // << " from:" << fz.size() + // << " to:" << addressing.size() << endl; + + fz.resetAddressing(addressing, flipMap); + } + } + + Info<< "Eroded " << nChanged + << " free-standing zone faces in = " + << mesh.time().cpuTimeIncrement() << " s." << endl; +} + + void Foam::snappyRefineDriver::addFaceZones ( meshRefinement& meshRefiner, @@ -3555,9 +3725,23 @@ void Foam::snappyRefineDriver::doRefine motionDict ); + // Do something about cells with refined faces on the boundary if (prepareForSnapping) { + const auto mt = meshRefiner_.meshType(); + if + ( + meshRefiner_.mesh().faceZones().size() + && ( + mt == meshRefinement::CASTELLATEDBUFFERLAYER + || mt == meshRefinement::CASTELLATEDBUFFERLAYER2 + ) + ) + { + erodeNonManifoldZoneFaces(refineParams); + } + mergePatchFaces(mergeType, refineParams, motionDict); } @@ -3580,13 +3764,61 @@ void Foam::snappyRefineDriver::doRefine << "---------------------" << nl << endl; + + /* + const bool hasBufferLayer + ( + (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER) + || (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER2) + ); + */ + const bool hasBufferLayer = false; + + labelList singleProcPoints; + + /* + if (hasBufferLayer) + { + //- Needed since buffer layer addition did not handle + //- inter-processor extrusion. Fixed now. This code can be removed. + + // Pick up all points on surfaces with specified buffer layers + const labelList& surfIndex = meshRefiner_.surfaceIndex(); + const auto& addLayers = meshRefiner_.surfaces().addBufferLayers(); + + bitSet isSelected(mesh.nPoints()); + forAll(surfIndex, facei) + { + const label surfi = surfIndex[facei]; + if (surfIndex[facei] != -1) + { + const label globalRegioni = + meshRefiner_.surfaces().globalRegion(surfi, 0); + if (addLayers[globalRegioni]) + { + isSelected.set(mesh.faces()[facei]); + } + } + } + syncTools::syncPointList + ( + mesh, + isSelected, + orEqOp<unsigned int>(), + 0 + ); + singleProcPoints = isSelected.sortedToc(); + } + */ + // Do final balancing. Keep zoned faces on one processor since the // snap phase will convert them to baffles and this only works for // internal faces. meshRefiner_.balance ( true, // keepZoneFaces - false, // keepBaffles + hasBufferLayer, // keepBaffles + singleProcPoints, // keepZonePoints scalarField(mesh.nCells(), 1), // cellWeights decomposer_, distributor_ diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.H b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.H index 17b45f4b0fff3eee0baae6bf0ee824fe66946248..ed6a105956656372123153e58e47015c36105cd1 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.H +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.H @@ -243,6 +243,12 @@ class snappyRefineDriver const dictionary& motionDict ); + //- Erode sticking-out zone faces. Bit heuristic. + void erodeNonManifoldZoneFaces + ( + const refinementParameters& refineParams + ); + //- Merge refined boundary faces (from exposing coarser cell) void mergePatchFaces ( diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.C index b38620a13f0a1f24ce4097181558c9987567bc49..7d19b0aef50325bc8723a13ba445d8d5a0ec712b 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.C +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2015-2022 OpenCFD Ltd. + Copyright (C) 2015-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -50,6 +50,10 @@ Description #include "refinementFeatures.H" #include "weightedPosition.H" #include "profiling.H" +#include "addPatchCellLayer.H" +#include "displacementMotionSolver.H" +#include "snappyLayerDriver.H" +#include "IOmanip.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -1116,6 +1120,7 @@ void Foam::snappySnapDriver::detectNearSurfaces ( const scalar planarCos, const indirectPrimitivePatch& pp, + const pointField& localPoints, const pointField& nearestPoint, const vectorField& nearestNormal, @@ -1124,7 +1129,6 @@ void Foam::snappySnapDriver::detectNearSurfaces { Info<< "Detecting near surfaces ..." << endl; - const pointField& localPoints = pp.localPoints(); const labelList& meshPoints = pp.meshPoints(); const refinementSurfaces& surfaces = meshRefiner_.surfaces(); const fvMesh& mesh = meshRefiner_.mesh(); @@ -1796,8 +1800,9 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurface const meshRefinement& meshRefiner, const labelList& globalToMasterPatch, const labelList& globalToSlavePatch, - const scalarField& snapDist, const indirectPrimitivePatch& pp, + const pointField& localPoints, + const scalarField& snapDist, pointField& nearestPoint, vectorField& nearestNormal ) @@ -1822,7 +1827,6 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurface } - const pointField& localPoints = pp.localPoints(); const refinementSurfaces& surfaces = meshRefiner.surfaces(); const fvMesh& mesh = meshRefiner.mesh(); @@ -2575,6 +2579,22 @@ void Foam::snappySnapDriver::doSnap const snapParameters& snapParams ) { + if (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER2) + { + // Buffer-layer replacement for this routine + + doSnapBufferLayers + ( + snapDict, + motionDict, + mergeType, + featureCos, + planarAngle, + snapParams + ); + return; + } + addProfiling(snap, "snappyHexMesh::snap"); fvMesh& mesh = meshRefiner_.mesh(); @@ -2616,6 +2636,48 @@ void Foam::snappySnapDriver::doSnap + // Get labels of patches where optional buffer layers are added + DynamicList<label> bufPatchIDs; + if (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER) + { + bufPatchIDs.setCapacity(globalToMasterPatch_.size()); + + const auto& addLayers = + meshRefiner_.surfaces().addBufferLayers(); + + // Normal patches + forAll(globalToMasterPatch_, globalRegioni) + { + if (addLayers[globalRegioni]) + { + const label masterP = + globalToMasterPatch_[globalRegioni]; + const label slaveP = + globalToSlavePatch_[globalRegioni]; + + bufPatchIDs.append(masterP); + if (slaveP != masterP) + { + bufPatchIDs.append(slaveP); + } + } + } + + // Temporary patches from faceZones + for (const auto& fz : mesh.faceZones()) + { + label mpI, spI; + surfaceZonesInfo::faceZoneType type; + if (meshRefiner_.getFaceZoneInfo(fz.name(), mpI, spI, type)) + { + bufPatchIDs.appendUniq(mpI); + bufPatchIDs.appendUniq(spI); + } + } + } + + + // faceZones of type internal const labelList internalFaceZones ( @@ -2629,11 +2691,10 @@ void Foam::snappySnapDriver::doSnap ) ); - // Create baffles (pairs of faces that share the same points) // Baffles stored as owner and neighbour face that have been created. + List<labelPair> baffles; { - List<labelPair> baffles; labelList originatingFaceZone; meshRefiner_.createZoneBaffles ( @@ -2643,8 +2704,21 @@ void Foam::snappySnapDriver::doSnap ); } - // Duplicate points on faceZones of type boundary - meshRefiner_.dupNonManifoldBoundaryPoints(); + // Duplicate points on faceZones of type boundary. Renumber baffles + // (probably not necessary - faceIDs should not change) + { + autoPtr<mapPolyMesh> map = meshRefiner_.dupNonManifoldBoundaryPoints(); + if (map) + { + const labelList& reverseFaceMap = map->reverseFaceMap(); + forAll(baffles, i) + { + label f0 = reverseFaceMap[baffles[i].first()]; + label f1 = reverseFaceMap[baffles[i].second()]; + baffles[i] = labelPair(f0, f1); + } + } + } bool doFeatures = false; @@ -2667,7 +2741,7 @@ void Foam::snappySnapDriver::doSnap // Get the labels of added patches. - labelList adaptPatchIDs(meshRefiner_.meshedPatches()); + const labelList adaptPatchIDs(meshRefiner_.meshedPatches()); @@ -2681,7 +2755,6 @@ void Foam::snappySnapDriver::doSnap ) ); - // Distance to attract to nearest feature on surface scalarField snapDist(calcSnapDistance(mesh, snapParams, ppPtr())); @@ -2727,7 +2800,7 @@ void Foam::snappySnapDriver::doSnap << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; // Extract baffles across internal faceZones (for checking mesh quality - // across + // across) labelPairList internalBaffles ( meshRefiner_.subsetBaffles @@ -2750,7 +2823,462 @@ void Foam::snappySnapDriver::doSnap meshMoverPtr() ); - // TBD. Include re-patching? + // Reset moving flag in case we do any topo changes + mesh.moving(false); + + + // Optionally add buffer layers + if (meshRefiner_.meshType() == meshRefinement::CASTELLATEDBUFFERLAYER) + { + ////- merge zone baffles (since current buffer layer insertion + ////- does not handle non-manifold edges ... TBD + //autoPtr<mapPolyMesh> mapPtr = meshRefiner_.mergeZoneBaffles + //( + // true, // internal zones + // false // baffle zones + //); + // + //if (mapPtr) + //{ + // if (debug & meshRefinement::MESH) + // { + // const_cast<Time&>(mesh.time())++; + // Info<< "Writing baffle-merged mesh to time " + // << meshRefiner_.timeName() << endl; + // meshRefiner_.write + // ( + // meshRefinement::debugType(debug), + // meshRefinement::writeType + // ( + // meshRefinement::writeLevel() + // | meshRefinement::WRITEMESH + // ), + // meshRefiner_.timeName() + // ); + // } + //} + + ////- use bufferLayer insertion on internalFaceZones + //Info<< "Adding buffer layers ..." << endl; + // + //{ + // // Remove references to pp + // meshMoverPtr.clear(); + // + // const labelList meshFaces + // ( + // mesh.faceZones().selection + // ( + // internalFaceZones + // ).sortedToc() + // ); + // ppPtr.reset + // ( + // new indirectPrimitivePatch + // ( + // IndirectList<face> + // ( + // mesh.faces(), + // meshFaces + // ), + // mesh.points() + // ) + // ); + // const pointField thickness + // ( + // wantedThickness(ppPtr(), 1e-1) //cellSizeFraction + // * PatchTools::pointNormals(mesh, ppPtr()) + // ); + // + // // Layer mesh modifier + // // - use intrusion, not extrusion + // addPatchCellLayer addLayer(mesh, true, false); + // + // // Do mesh changes : introduce point, faces, cells + // autoPtr<mapPolyMesh> mapPtr = addBufferLayers + // ( + // ppPtr(), + // -thickness, //1e-3, //cellSizeFraction, + // addLayer + // ); + // + // // Update numbering on baffles, pointToMaster. Note: uses + // // geometric tolerance - could be avoided since now we have + // // addPatchCellLayer still intact. However would like to avoid + // // use of addPatchCellLayer altogether. + // if (mapPtr) + // { + // // Invalidate extrusion (face numbering might have changed) + // ppPtr.clear(); + // + // labelList dummyPointToMaster; + // snappyLayerDriver::mapFaceZonePoints + // ( + // meshRefiner_, + // mapPtr(), + // internalBaffles, + // dummyPointToMaster + // ); + // + // if (debug & meshRefinement::MESH) + // { + // const_cast<Time&>(mesh.time())++; + // Info<< "Writing INTERNAL ZONE buffer layer mesh" + // << " to time " << meshRefiner_.timeName() << endl; + // meshRefiner_.write + // ( + // meshRefinement::debugType(debug), + // meshRefinement::writeType + // ( + // meshRefinement::writeLevel() + // | meshRefinement::WRITEMESH + // ), + // meshRefiner_.timeName() + // ); + // } + // } + //} + + ////- re-split zone baffles + //{ + // labelList originatingFaceZone; + // meshRefiner_.createZoneBaffles + // ( + // internalFaceZones, + // baffles, + // originatingFaceZone + // ); + //} + + + Info<< "Adding buffer layers ..." << endl; + + // Remove references to pp + meshMoverPtr.clear(); + // Invalidate extrusion (face numbering might have changed) + ppPtr.clear(); + + // Note: all the way up to addBufferLayers can probably be replaced + // once addPatchCellLayer can add to both sides of faceZone ... + + // Duplicate points on faceZones that layers are added to + labelList pointToMaster; + { + labelList numLayers(mesh.boundaryMesh().size(), 0); + UIndirectList<label>(numLayers, bufPatchIDs) = 1; + + autoPtr<mapPolyMesh> mapPtr = + snappyLayerDriver::dupFaceZonePoints + ( + meshRefiner_, + bufPatchIDs, // patch indices + numLayers, // num layers per patch + baffles, + pointToMaster + ); + if (mapPtr) + { + // Update numbering on any baffles + meshRefinement::mapBaffles + ( + mesh, + mapPtr().faceMap(), + internalBaffles + ); + + + //// Shrink back mesh a bit to see if there are any + //// incorrect dupFaceZonePoints ... + //if (debug & meshRefinement::MESH) + //{ + // pointField newPoints(mesh.nPoints()); + // forAll(newPoints, pointi) + // { + // const auto& pCells = mesh.pointCells()[pointi]; + // + // point avg(Zero); + // for (const label celli : pCells) + // { + // avg += mesh.cellCentres()[celli]; + // } + // avg /= pCells.size(); + // + // newPoints[pointi] = + // 0.5*mesh.points()[pointi] + // + 0.5*avg; + // } + // mesh.movePoints(newPoints); + // + // const_cast<Time&>(mesh.time())++; + // Info<< "Writing DEBUG-shrunk layer mesh to time " + // << meshRefiner_.timeName() << endl; + // meshRefiner_.write + // ( + // meshRefinement::debugType(debug), + // meshRefinement::writeType + // ( + // meshRefinement::writeLevel() + // | meshRefinement::WRITEMESH + // ), + // meshRefiner_.timeName() + // ); + //} + } + } + + //- Not needed: shrinking of mesh since now using intrusion ... + // // Move mesh back with thickness. Two purposes: + // // - avoid mapFaceZonePoints below merging points extraneously + // // (does not use addPatchCellLayer structure; uses geometric + // // tolerance) + // // - see what is happening + // { + // pointField newPoints(mesh.points()); + // const auto& mp = ppPtr().meshPoints(); + // forAll(mp, i) + // { + // newPoints[mp[i]] -= thickness[i]; + // } + // mesh.movePoints(newPoints); + // ppPtr().movePoints(mesh.points()); + // + // if (debug & meshRefinement::MESH) + // { + // const_cast<Time&>(mesh.time())++; + // Info<< "Writing shrunk buffer layer mesh to time " + // << meshRefiner_.timeName() << endl; + // meshRefiner_.write + // ( + // meshRefinement::debugType(debug), + // meshRefinement::writeType + // ( + // meshRefinement::writeLevel() + // | meshRefinement::WRITEMESH + // ), + // meshRefiner_.timeName() + // ); + // } + // } + + + { + // Layer mesh modifier + // - use intrusion, not extrusion + addPatchCellLayer addLayer(mesh, true, false); + + // Redo pp + autoPtr<indirectPrimitivePatch> bufPatchPtr + ( + meshRefinement::makePatch(mesh, bufPatchIDs) + ); + + pointField thickness + ( + wantedThickness(bufPatchPtr(), 1e-1) //cellSizeFraction + * PatchTools::pointNormals(mesh, bufPatchPtr()) + ); + + // Make sure to adhere to constraints + { + + const pointMesh& pMesh = pointMesh::New(mesh); + const labelList& mp = bufPatchPtr().meshPoints(); + + tmp<pointVectorField> tdisp + ( + meshRefinement::makeDisplacementField + ( + pMesh, + adaptPatchIDs + ) + ); + // Set internal field + UIndirectList<point>(tdisp.ref(), mp) = thickness; + // Take over onto boundary field. Needed since constraint + // patch might be before the fixedValue patches so its + // value gets overwritten + for (auto& ppf : tdisp.ref().boundaryFieldRef()) + { + ppf == ppf.patchInternalField(); + } + + // Adhere to multi-point constraints + const pointConstraints& pcs = pointConstraints::New(pMesh); + pcs.constrainDisplacement(tdisp.ref(), false); + + thickness = UIndirectList<point>(tdisp(), mp); + } + + + + // Print a bit + { + // See snappyLayerDriver::calculateLayerThickness. + const auto& pbm = mesh.boundaryMesh(); + label maxLen = 0; + for (const label patchi : bufPatchIDs) + { + maxLen = max(maxLen, label(pbm[patchi].name().size())); + } + + const int oldPrecision = Info.stream().precision(); + + Info<< nl + << setf(ios_base::left) << setw(maxLen) << "patch" + << setw(0) << " faces layers thickness[m]" << nl + << setf(ios_base::left) << setw(maxLen) << "-----" + << setw(0) << " ----- ------ ------------" << endl; + + for (const label patchi : bufPatchIDs) + { + Info<< setf(ios_base::left) << setw(maxLen) + << pbm[patchi].name() << setprecision(3) + << " " << setw(8) + << returnReduce(pbm[patchi].size(), sumOp<scalar>()) + << " " << setw(6) << 1 + << " " << setw(8) << gAverage(mag(thickness)) + << endl; + } + Info<< setprecision(oldPrecision) << endl; + } + + + // Do mesh changes : introduce point, faces, cells + autoPtr<mapPolyMesh> mapPtr = addBufferLayers + ( + bufPatchPtr(), + -thickness, //1e-3, //cellSizeFraction, + addLayer + ); + + // Update numbering on baffles, pointToMaster. Note: uses + // geometric tolerance - could be avoided since now we have + // addPatchCellLayer still intact. However would like to avoid + // use of addPatchCellLayer altogether. + if (mapPtr) + { + // Invalidate extrusion (face numbering might have changed) + ppPtr.clear(); + + snappyLayerDriver::mapFaceZonePoints + ( + meshRefiner_, + mapPtr(), + internalBaffles, + pointToMaster + ); + } + } + + + + { + // Merge duplicated points (this creates illegal cells - + // hopefully they will be smoothed out) + autoPtr<mapPolyMesh> mapPtr = + meshRefiner_.mergePoints(pointToMaster); + if (mapPtr) + { + // Invalidate extrusion (point numbering might have changed) + ppPtr.clear(); + + // Update numbering on any baffles + meshRefinement::mapBaffles + ( + mesh, + mapPtr().faceMap(), + internalBaffles + ); + // Extract baffles across internal faceZones + internalBaffles = meshRefinement::subsetBaffles + ( + mesh, + internalFaceZones, + internalBaffles + ); + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing merged points buffer layer mesh" + << " to time " << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + } + } + + + Info<< "Inflating buffer layers ..." << endl; + + const pointMesh& pMesh = pointMesh::New(mesh); + + { + autoPtr<displacementMotionSolver> motionPtr + ( + makeMotionSolver + ( + pMesh, + snapDict, + bufPatchIDs + //patchConstraints + ) + ); + + // Solve internal displacement + tmp<pointField> tnewPoints(motionPtr->newPoints()); + + // Move points + mesh.movePoints(tnewPoints); + + // Reset moving flag to avoid problems with topo changes + mesh.moving(false); + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing smoothed buffer layer mesh to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + } + + // Update mesh mover + ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs); + meshMoverPtr.reset + ( + new motionSmoother + ( + mesh, + ppPtr(), + adaptPatchIDs, + meshRefinement::makeDisplacementField + ( + pointMesh::New(mesh), + adaptPatchIDs + ), + motionDict, + dryRun_ + ) + ); + } //- Only if in feature attraction mode: @@ -2764,6 +3292,8 @@ void Foam::snappySnapDriver::doSnap DynamicList<label> splitFaces; //- Indices in face to split across DynamicList<labelPair> splits; + //- Patch for both sides of the face + DynamicList<labelPair> splitPatches; for (label iter = 0; iter < nFeatIter; iter++) @@ -2811,8 +3341,9 @@ void Foam::snappySnapDriver::doSnap meshRefiner_, globalToMasterPatch_, // for if strictRegionSnap globalToSlavePatch_, // for if strictRegionSnap - snapDist, pp, + pp.localPoints(), + snapDist, nearestPoint, nearestNormal @@ -2826,6 +3357,7 @@ void Foam::snappySnapDriver::doSnap ( Foam::cos(degToRad(planarAngle)),// planar cos for gaps pp, + pp.localPoints(), nearestPoint, // surfacepoint from nearest test nearestNormal, // surfacenormal from nearest test @@ -2838,10 +3370,12 @@ void Foam::snappySnapDriver::doSnap { splitFaces.clear(); splits.clear(); + splitPatches.clear(); disp = calcNearestSurfaceFeature ( snapParams, !doSplit, // alignMeshEdges + false, // no special handling for >=3 patch points iter, featureCos, scalar(iter+1)/nFeatIter, @@ -2849,13 +3383,15 @@ void Foam::snappySnapDriver::doSnap snapDist, disp, nearestNormal, - meshMover, + pp, + pp.localPoints(), patchAttraction, patchConstraints, splitFaces, - splits + splits, + splitPatches ); } @@ -2952,12 +3488,14 @@ void Foam::snappySnapDriver::doSnap { labelList oldSplitFaces(std::move(splitFaces)); List<labelPair> oldSplits(std::move(splits)); + List<labelPair> oldSplitPatches(std::move(splitPatches)); forAll(oldSplitFaces, i) { if (duplicateFace[oldSplitFaces[i]] == -1) { splitFaces.append(oldSplitFaces[i]); splits.append(oldSplits[i]); + splitPatches.append(oldSplitPatches[i]); } } nTotalSplit = returnReduce @@ -2968,10 +3506,15 @@ void Foam::snappySnapDriver::doSnap } // Update mesh + + // Reset moving flag to avoid meshPhi problems with topo changes + mesh.moving(false); + meshRefiner_.splitFacesUndo ( splitFaces, splits, + splitPatches, motionDict, duplicateFace, @@ -3047,6 +3590,10 @@ void Foam::snappySnapDriver::doSnap } + // Reset moving flag to avoid any meshPhi mapping problems + mesh.moving(false); + + // Merge any introduced baffles (from faceZones of faceType 'internal') { autoPtr<mapPolyMesh> mapPtr = meshRefiner_.mergeZoneBaffles diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.H b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.H index 5f6ed8fc1bec95b5632319d67d6ca99d5090d1f6..0ed56c89a308ce036378b473831dbad12779132c 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.H +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriver.H @@ -41,6 +41,7 @@ SourceFiles #include "meshRefinement.H" #include "DynamicField.H" +#include "pointConstraint.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -52,6 +53,9 @@ class motionSmoother; class refinementParameters; class snapParameters; class pointConstraint; +class layerParameters; +class displacementMotionSolver; +class addPatchCellLayer; /*---------------------------------------------------------------------------*\ Class snappySnapDriver Declaration @@ -79,6 +83,17 @@ class snappySnapDriver // Snapping + //- Top-level: snap onto surface & features and add buffer layer + void doSnapBufferLayers + ( + const dictionary& snapDict, + const dictionary& motionDict, + const meshRefinement::FaceMergeType mergeType, + const scalar featureCos, + const scalar planarAngle, + const snapParameters& snapParams + ); + //- Calculates (geometric) shared points // Requires bitSet to be sized and initialised static label getCollocatedPoints @@ -106,17 +121,60 @@ class snappySnapDriver static tmp<pointField> avg ( + const polyMesh& mesh, + const bitSet& isMasterPoint, const indirectPrimitivePatch&, const pointField& ); //- Calculate displacement per patch point. Wip. - static pointField smoothLambdaMuPatchDisplacement + static tmp<pointField> smoothLambdaMuPatchDisplacement ( - const motionSmoother& meshMover, + const polyMesh& mesh, + const indirectPrimitivePatch& pp, const List<labelPair>& baffles ); + tmp<scalarField> wantedThickness + ( + const indirectPrimitivePatch& pp, + const scalar cellSizeFraction + ) const; + + //- Create/update pointMesh + const pointMesh& makePointMesh + ( + const indirectPrimitivePatch& pp, + const pointConstraintList& pointConstraints, + const word& allEdgePatchName, + const word& allPointPatchName + ) const; + + autoPtr<displacementMotionSolver> makeMotionSolver + ( + const pointMesh& pMesh, + const dictionary& snapDict, + const labelList& adaptPatchIDs + ) const; + + void setDisplacement + ( + const indirectPrimitivePatch& pp, + const pointField& patchDisp, + const labelList& adaptPatchIDs, + const pointField& points0, + pointVectorField& fld + ); + + autoPtr<mapPolyMesh> addBufferLayers + ( + const indirectPrimitivePatch& pp, + + //const scalar cellSizeFraction, + const pointField& thickness, + // Layer mesh modifier + addPatchCellLayer& addLayer + ); //- Check that face zones are synced void checkCoupledFaceZones() const; @@ -245,6 +303,7 @@ class snappySnapDriver ( const label iter, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& faceSnapDist, vectorField& faceDisp, vectorField& faceSurfaceNormal, @@ -255,6 +314,7 @@ class snappySnapDriver ( const label iter, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const vectorField& faceDisp, const vectorField& faceSurfaceNormal, @@ -284,6 +344,7 @@ class snappySnapDriver const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& rawPatchAttraction, @@ -302,6 +363,7 @@ class snappySnapDriver const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const List<List<point>>& pointFaceCentres, @@ -376,6 +438,7 @@ class snappySnapDriver const scalar concaveCos, const scalar minAreaFraction, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const vectorField& patchAttraction, const List<pointConstraint>& patchConstraints, const vectorField& nearestAttraction, @@ -395,13 +458,16 @@ class snappySnapDriver const scalar minAreaFraction, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const vectorField& nearestAttraction, const vectorField& nearestNormal, + const List<labelList>& pointFacePatchID, vectorField& patchAttraction, List<pointConstraint>& patchConstraints, DynamicList<label>& splitFaces, - DynamicList<labelPair>& splits + DynamicList<labelPair>& splits, + DynamicList<labelPair>& splitPatches ) const; //- Avoid attraction across face diagonal since would @@ -411,6 +477,7 @@ class snappySnapDriver const label iter, const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, vectorField& patchAttraction, List<pointConstraint>& patchConstraints ) const; @@ -457,6 +524,7 @@ class snappySnapDriver const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, const label pointi, @@ -481,6 +549,7 @@ class snappySnapDriver const label iter, const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, @@ -500,8 +569,10 @@ class snappySnapDriver const label iter, const scalar featureCos, const bool multiRegionFeatureSnap, + const bool strictRegionFeatureSnap, // special feat-point const indirectPrimitivePatch&, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, @@ -528,6 +599,7 @@ class snappySnapDriver const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, // Feature-point to pp point @@ -545,6 +617,7 @@ class snappySnapDriver const label iter, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, // Feature-point to pp point @@ -570,6 +643,7 @@ class snappySnapDriver const bool isRegionEdge, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const label pointi, const point& estimatedPt, @@ -591,6 +665,7 @@ class snappySnapDriver const bool isRegionEdge, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const label pointi, const point& estimatedPt, @@ -610,6 +685,7 @@ class snappySnapDriver ( const label iter, const bool multiRegionFeatureSnap, + const bool strictRegionFeatureSnap, const bool detectBaffles, const bool baffleFeaturePoints, @@ -620,6 +696,7 @@ class snappySnapDriver const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, const vectorField& nearestNormal, @@ -638,6 +715,7 @@ class snappySnapDriver const label iter, const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestAttraction, @@ -653,18 +731,21 @@ class snappySnapDriver ( const snapParameters& snapParams, const bool alignMeshEdges, + const bool strictRegionFeatureSnap, //points on >=3 patches const label iter, const scalar featureCos, const scalar featureAttract, const scalarField& snapDist, const vectorField& nearestDisp, const vectorField& nearestNormal, - motionSmoother& meshMover, + const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, vectorField& patchAttraction, List<pointConstraint>& patchConstraints, DynamicList<label>& splitFaces, - DynamicList<labelPair>& splits + DynamicList<labelPair>& splits, + DynamicList<labelPair>& splitPatches ) const; @@ -730,7 +811,8 @@ public: void detectNearSurfaces ( const scalar planarCos, - const indirectPrimitivePatch&, + const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const pointField& nearestPoint, const vectorField& nearestNormal, vectorField& disp @@ -745,8 +827,9 @@ public: const meshRefinement& meshRefiner, const labelList& globalToMasterPatch, const labelList& globalToSlavePatch, + const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, - const indirectPrimitivePatch&, pointField& nearestPoint, vectorField& nearestNormal ); @@ -790,6 +873,7 @@ public: const labelList& preserveFaces ); + //- Snap onto surface & features void doSnap ( const dictionary& snapDict, diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriverBufferLayers.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriverBufferLayers.C new file mode 100644 index 0000000000000000000000000000000000000000..e722909b518b042df9653d224d346616b52e0f99 --- /dev/null +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriverBufferLayers.C @@ -0,0 +1,2019 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Description + All to do with snapping to the surface with buffer layer + +\*----------------------------------------------------------------------------*/ + +#include "snappySnapDriver.H" +#include "polyTopoChange.H" +#include "syncTools.H" +#include "fvMesh.H" +#include "Time.H" +#include "OBJstream.H" +#include "mapPolyMesh.H" +#include "snapParameters.H" +#include "unitConversion.H" +#include "PatchTools.H" +#include "profiling.H" +#include "addPatchCellLayer.H" +#include "snappyLayerDriver.H" +#include "weightedPosition.H" + +#include "localPointRegion.H" +#include "pointConstraints.H" +#include "displacementMotionSolver.H" +#include "meshPointPatch.H" +#include "processorPointPatch.H" +#include "dummyTransform.H" +#include "faceSet.H" +#include "motionSmoother.H" +#include "tetDecomposer.H" +#include "tetMatcher.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::tmp<Foam::pointField> Foam::snappySnapDriver::avg +( + const polyMesh& mesh, + const bitSet& isMasterPoint, + const indirectPrimitivePatch& pp, + const pointField& localPoints +) +{ + const labelListList& pointEdges = pp.pointEdges(); + const labelList& meshPoints = pp.meshPoints(); + const edgeList& edges = pp.edges(); + + Field<weightedPosition> wps + ( + pointEdges.size(), + pTraits<weightedPosition>::zero + ); + + // Calculate sum of all contributions (so not positions) + forAll(pointEdges, verti) + { + weightedPosition& wp = wps[verti]; + for (const label edgei : pointEdges[verti]) + { + const label otherVerti = edges[edgei].otherVertex(verti); + + if (isMasterPoint[meshPoints[otherVerti]]) + { + wp.first() += 1.0; + wp.second() += localPoints[otherVerti]; + } + } + } + + weightedPosition::syncPoints(mesh, meshPoints, wps); + + tmp<pointField> tavg(new pointField(wps.size())); + pointField& avg = tavg.ref(); + + forAll(wps, verti) + { + const weightedPosition& wp = wps[verti]; + + if (mag(wp.first()) < VSMALL) + { + // Set to zero? + avg[verti] = Zero; + } + else + { + avg[verti] = wp.second()/wp.first(); + } + } + + return tavg; +} + + +Foam::tmp<Foam::pointField> +Foam::snappySnapDriver::smoothLambdaMuPatchDisplacement +( + const polyMesh& mesh, + const indirectPrimitivePatch& pp, + const List<labelPair>& baffles +) +{ + const bitSet isMasterPoint(syncTools::getMasterPoints(mesh)); + + pointField newLocalPoints(pp.localPoints()); + + const label iters = 90; + const scalar lambda = 0.33; + const scalar mu = 0.34; + + for (label iter = 0; iter < iters; iter++) + { + // Lambda + newLocalPoints = + (1 - lambda)*newLocalPoints + + lambda*avg(mesh, isMasterPoint, pp, newLocalPoints); + + // Mu + newLocalPoints = + (1 + mu)*newLocalPoints + - mu*avg(mesh, isMasterPoint, pp, newLocalPoints); + } + return newLocalPoints-pp.localPoints(); +} + + +Foam::tmp<Foam::scalarField> +Foam::snappySnapDriver::wantedThickness +( + const indirectPrimitivePatch& pp, + const scalar cellSizeFraction +) const +{ + fvMesh& mesh = meshRefiner_.mesh(); + + const labelList& cellLevel = meshRefiner_.meshCutter().cellLevel(); + const labelList& owner = mesh.faceOwner(); + + // Undistorted edge length + const scalar edge0Len = + meshRefiner_.meshCutter().level0EdgeLength(); + + + tmp<scalarField> tthickness(tmp<scalarField>::New(pp.nPoints())); + scalarField& thickness = tthickness.ref(); + + labelList maxPointLevel(pp.nPoints(), labelMin); + + forAll(pp, i) + { + label ownLevel = cellLevel[owner[pp.addressing()[i]]]; + + const face& f = pp.localFaces()[i]; + + forAll(f, fp) + { + maxPointLevel[f[fp]] = max(maxPointLevel[f[fp]], ownLevel); + } + } + + syncTools::syncPointList + ( + mesh, + pp.meshPoints(), + maxPointLevel, + maxEqOp<label>(), + labelMin // null value + ); + + forAll(thickness, pointi) + { + const scalar edgeLen = edge0Len/(1<<maxPointLevel[pointi]); + thickness[pointi] = cellSizeFraction*edgeLen; + } + return tthickness; +} + + +//const Foam::pointMesh& Foam::snappySnapDriver::makePointMesh +//( +// const indirectPrimitivePatch& pp, +// const pointConstraintList& pointConstraints, +// const word& allEdgePatchName, +// const word& allPointPatchName +//) const +//{ +// fvMesh& mesh = meshRefiner_.mesh(); +// +// if (pointConstraints.size() != pp.nPoints()) +// { +// FatalErrorInFunction<< "pointConstraints:" << pointConstraints.size() +// << " pp:" << pp.nPoints() << exit(FatalError); +// } +// +// +// // Expand pointConstraints to all meshPoints +// pointConstraintList meshPointConstraints(mesh.nPoints()); +// UIndirectList<pointConstraint>(meshPointConstraints, pp.meshPoints()) = +// pointConstraints; +// +// const auto combineConstraints = [&] +// ( +// pointConstraint& x, +// const pointConstraint& y +// ) +// { +// x.combine(y); +// }; +// +// +// syncTools::syncPointList +// ( +// mesh, +// meshPointConstraints, +// combineConstraints, +// pointConstraint(), +// dummyTransform() +// ); +// +// +// // Sort point constraints: +// // - 0 : does not happen? +// // - 1 : attract to surface +// // - 2 : attract to feature edge +// // - 3 : attract to feature point +// +// DynamicList<label> featEdgeMeshPoints(pointConstraints.size()); +// DynamicList<label> featPointMeshPoints(pointConstraints.size()); +// forAll(meshPointConstraints, pointi) +// { +// if (meshPointConstraints[pointi].first() == 2) +// { +// featEdgeMeshPoints.append(pointi); +// } +// else if (meshPointConstraints[pointi].first() == 3) +// { +// featPointMeshPoints.append(pointi); +// } +// } +// +// // Lookup / construct (from polyPatches) the pointMesh +// auto& pMesh = pointMesh::New(meshRefiner_.mesh()); +// +// pointBoundaryMesh& pointBm = +// const_cast<pointBoundaryMesh&>(pMesh.boundary()); +// +// // Check if already has constraint patches +// label edgePatchi = pointBm.findPatchID(allEdgePatchName); +// if (edgePatchi != -1) +// { +// // Delete patch. TBD: clear patchGroup +// pointBm.set(edgePatchi, nullptr); +// } +// label pointPatchi = pointBm.findPatchID(allPointPatchName); +// if (pointPatchi != -1) +// { +// // Delete patch. TBD: clear patchGroup +// pointBm.set(pointPatchi, nullptr); +// } +// +// // Add additional point patches in order: +// // - polyPatch based +// // - featEdge-based constraints +// // - featPoint-based constraints (so can override edge-based constraints) +// // - processor boundaries (or should this be all constraint patches, e.g. +// // symmetry plane. Note: hopefully this is already handled in the +// // feature extraction ...) +// +// if (returnReduce(featEdgeMeshPoints.size(), sumOp<label>())) +// { +// if (edgePatchi != -1) +// { +// // Override patch +// const_cast<pointBoundaryMesh&>(pointBm).set +// ( +// edgePatchi, +// new meshPointPatch +// ( +// allEdgePatchName, +// featEdgeMeshPoints, +// List<pointConstraint> +// ( +// meshPointConstraints, +// featEdgeMeshPoints +// ), +// edgePatchi, +// pointBm, +// meshPointPatch::typeName +// ) +// ); +// } +// else +// { +// // Append +// const_cast<pointBoundaryMesh&>(pointBm).push_back +// ( +// new meshPointPatch +// ( +// allEdgePatchName, +// featEdgeMeshPoints, +// List<pointConstraint> +// ( +// meshPointConstraints, +// featEdgeMeshPoints +// ), +// pointBm.size(), +// pointBm, +// meshPointPatch::typeName +// ) +// ); +// } +// } +// if (returnReduce(featPointMeshPoints.size(), sumOp<label>())) +// { +// if (pointPatchi != -1) +// { +// // Override patch +// const_cast<pointBoundaryMesh&>(pointBm).set +// ( +// pointPatchi, +// new meshPointPatch +// ( +// allPointPatchName, +// featPointMeshPoints, +// List<pointConstraint> +// ( +// meshPointConstraints, +// featPointMeshPoints +// ), +// pointPatchi, +// pointBm, +// meshPointPatch::typeName +// ) +// ); +// } +// else +// { +// // Append +// const_cast<pointBoundaryMesh&>(pointBm).push_back +// ( +// new meshPointPatch +// ( +// allPointPatchName, +// featPointMeshPoints, +// List<pointConstraint> +// ( +// meshPointConstraints, +// featPointMeshPoints +// ), +// pointBm.size(), +// pointBm, +// meshPointPatch::typeName +// ) +// ); +// } +// } +// +// // Shuffle into order +// labelList oldToNew(pointBm.size()); +// label newPatchi = 0; +// forAll(pointBm, patchi) +// { +// if (!isA<processorPointPatch>(pointBm[patchi])) +// { +// oldToNew[patchi] = newPatchi++; +// } +// } +// forAll(pointBm, patchi) +// { +// if (isA<processorPointPatch>(pointBm[patchi])) +// { +// oldToNew[patchi] = newPatchi++; +// } +// } +// pointBm.reorder(oldToNew, true); +// +// return pMesh; +//} + + +Foam::autoPtr<Foam::displacementMotionSolver> +Foam::snappySnapDriver::makeMotionSolver +( + const pointMesh& pMesh, + const dictionary& snapDict, + const labelList& adaptPatchIDs +// const pointConstraintList& pointConstraints, +) const +{ + fvMesh& mesh = meshRefiner_.mesh(); + + tmp<pointVectorField> tallDisp + ( + meshRefinement::makeDisplacementField + ( + pMesh, + adaptPatchIDs + ) + ); + + // Make sure the pointDisplacement is not registered (since + // displacementMotionSolver itself holds it) + tallDisp.ref().checkOut(); + + autoPtr<displacementMotionSolver> motionPtr + ( + displacementMotionSolver::New + ( + snapDict.get<word>("solver"), + mesh, + IOdictionary + ( + IOobject + ( + "motionSolverDict", + pMesh.thisDb().time().constant(), + pMesh.thisDb(), + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ), + snapDict + ), + tallDisp(), + pointIOField + ( + IOobject + ( + "points0", + pMesh.thisDb().time().constant(), + polyMesh::meshSubDir, + pMesh.thisDb(), + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ), + mesh.points() + ) + ) + ); + return motionPtr; +} + + +void Foam::snappySnapDriver::setDisplacement +( + const indirectPrimitivePatch& pp, + const pointField& patchDisp, // displacement w.r.t. current mesh + const labelList& adaptPatchIDs, + const pointField& points0, + pointVectorField& fld // displacement w.r.t. points0 +) +{ + const pointMesh& pMesh = fld.mesh(); + const pointField& points = pMesh().points(); + const labelList& meshPoints = pp.meshPoints(); + + if + ( + (points0.size() != points.size()) + || (points0.size() != fld.size()) + || (points0.size() != pMesh.size()) + || (meshPoints.size() != patchDisp.size()) + ) + { + FatalErrorInFunction + << "Sizing :" + << " points0.size():" << points0.size() + << " points.size():" << points.size() + << " fld.size():" << fld.size() + << " patchDisp.size():" << patchDisp.size() + << " meshPoints.size():" << meshPoints.size() + << " mesh.nPoints():" << pMesh.size() + << exit(FatalError); + } + + + // Problem is that the patchDisp might not be consistent (parallel etc) + // across shared points so expand to mesh points + + pointField meshDisp(pMesh.size(), Zero); + + forAll(meshPoints, patchPointi) + { + const label meshPointi = meshPoints[patchPointi]; + + meshDisp[meshPointi] = + patchDisp[patchPointi]+points[meshPointi]-points0[meshPointi]; + } + + // Assign to bc + pointVectorField::Boundary& bfld = fld.boundaryFieldRef(); + for (const label patchi : adaptPatchIDs) + { + bfld[patchi] == pointField(meshDisp, bfld[patchi].patch().meshPoints()); + } + + // Apply multi-patch constraints. Problem: most patches originate from + // meshing so are type 'wall'. The pointConstraints are only on any points + // remaining from the starting mesh. + const pointConstraints& pcs = pointConstraints::New(pMesh); + pcs.constrainDisplacement(fld, true); +} + + +Foam::autoPtr<Foam::mapPolyMesh> Foam::snappySnapDriver::addBufferLayers +( + const indirectPrimitivePatch& pp, + const pointField& thickness, + // Layer mesh modifier + addPatchCellLayer& addLayer +) +{ + fvMesh& mesh = meshRefiner_.mesh(); + + // Introduce single layer of cells. Straight from snappyLayerDriver + + // Global face indices engine + const globalIndex globalFaces(mesh.nFaces()); + + // Determine extrudePatch.edgeFaces in global numbering (so across + // coupled patches). This is used only to string up edges + // between coupled + // faces (all edges between same (global)face indices get extruded). + labelListList edgeGlobalFaces + ( + addPatchCellLayer::globalEdgeFaces + ( + mesh, + globalFaces, + pp + ) + ); + + + + // Use global edge - face connectivity to + // - disable any non-manifold extrusions + // - boundary edges can be extruded - is handled by addPatchCellLayer + // - what about setting numLayers to 0 to disable layers? Should that + // affect buffer layer addition? Guess not since buffer layer is + // to aid snapping ... + labelList nFaceLayers(pp.size(), 1); + labelList nPointLayers(pp.nPoints(), 1); + forAll(edgeGlobalFaces, edgei) + { + if (edgeGlobalFaces[edgei].size() > 2) + { + const edge& e = pp.edges()[edgei]; + const edge meshE(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]); + + nPointLayers[e[0]] = 0; + nPointLayers[e[1]] = 0; + } + //else if (edgeGlobalFaces[edgei].size() == 1) + //{ + // const edge& e = pp.edges()[edgei]; + // const edge meshE(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]); + // + // nPointLayers[e[0]] = 0; + // nPointLayers[e[1]] = 0; + //} + else if (edgeGlobalFaces[edgei].size() == 0) + { + const edge& e = pp.edges()[edgei]; + const edge meshE(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]); + FatalErrorInFunction << "Edge:" << meshE + << " At:" << meshE.line(mesh.points()) + << " has no faces!" << exit(FatalError); + } + } + + syncTools::syncPointList + ( + mesh, + pp.meshPoints(), + nPointLayers, + minEqOp<label>(), + labelMax // null value + ); + + forAll(pp.localFaces(), facei) + { + const face& f = pp.localFaces()[facei]; + const UIndirectList<label> pLayers(nPointLayers, f); + if (!pLayers.found(label(1))) + { + nFaceLayers[facei] = 0; + } + } + + + + // Determine patches for extruded boundary edges. Adds any + // additional processor patches (since extruding coupled edge can cause + // additional connectivity) + + labelList edgePatchID; + labelList edgeZoneID; + boolList edgeFlip; + labelList inflateFaceID; + snappyLayerDriver::determineSidePatches + ( + meshRefiner_, + globalFaces, + edgeGlobalFaces, + pp, + + edgePatchID, + edgeZoneID, + edgeFlip, + inflateFaceID + ); + + + // Mesh topo change engine. Insert current mesh. + polyTopoChange meshMod(mesh); + + + // Add topo regardless of whether extrudeStatus is extruderemove. + // Not add layer if patchDisp is zero. + + addLayer.setRefinement + ( + globalFaces, + edgeGlobalFaces, + + scalarField(pp.nPoints(), 1), // expansion ratio + pp, + bitSet(pp.size()), // no flip + + edgePatchID, // boundary patch for extruded boundary edges + edgeZoneID, // zone for extruded edges + edgeFlip, + inflateFaceID, + + + labelList(0), // exposed patchIDs, not used for adding layers + nFaceLayers, + nPointLayers, + thickness, //patchAttraction, + + meshMod + ); + + // Apply the stored topo changes to the current mesh. + autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh, false); + mapPolyMesh& map = *mapPtr; + + // Update fields + mesh.updateMesh(map); + + // Move mesh (since morphing does not do this) + if (map.hasMotionPoints()) + { + mesh.movePoints(map.preMotionPoints()); + } + else + { + // Hack to remove meshPhi - mapped incorrectly. TBD. + mesh.clearOut(); + } + + // Reset the instance for if in overwrite mode + mesh.setInstance(meshRefiner_.timeName()); + + // Update numbering on layer + addLayer.updateMesh + ( + map, + identity(pp.size()), + identity(pp.nPoints()) + ); + + // Update intersections + const labelListList addedCells(addLayer.addedCells()); + bitSet isChangedFace(mesh.nFaces()); + for (const labelList& faceToCells : addedCells) + { + for (const label celli : faceToCells) + { + isChangedFace.set(mesh.cells()[celli]); + } + } + meshRefiner_.updateMesh(map, isChangedFace.toc()); + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing mesh-with-layer to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + return mapPtr; +} + + +void Foam::snappySnapDriver::doSnapBufferLayers +( + const dictionary& snapDict, + const dictionary& motionDict, + const meshRefinement::FaceMergeType mergeType, + const scalar featureCos, + const scalar planarAngle, + const snapParameters& snapParams +) +{ + addProfiling(snap, "snappyHexMesh::snap"); + fvMesh& mesh = meshRefiner_.mesh(); + + Info<< nl + << "Morphing phase" << nl + << "--------------" << nl + << endl; + + + // Name of pointPatch for any points attracted to feature edges + //const word allEdgePatchName("boundaryEdges"); + // Name of pointPatch for any points attracted to feature points + //const word allPointPatchName("boundaryPoints"); + + + // faceZone handling + // ~~~~~~~~~~~~~~~~~ + // + // We convert all faceZones into baffles during snapping so we can use + // a standard mesh motion (except for the mesh checking which for baffles + // created from internal faces should check across the baffles). The state + // is stored in two variables: + // baffles : pairs of boundary faces + // duplicateFace : from mesh face to its baffle colleague (or -1 for + // normal faces) + // There are three types of faceZones according to the faceType property: + // + // internal + // -------- + // - baffles: need to be checked across + // - duplicateFace: from face to duplicate face. Contains + // all faces on faceZone to prevents merging patch faces. + // + // baffle + // ------ + // - baffles: no need to be checked across + // - duplicateFace: contains all faces on faceZone to prevent + // merging patch faces. + // + // boundary + // -------- + // - baffles: no need to be checked across. Also points get duplicated + // so will no longer be baffles + // - duplicateFace: contains no faces on faceZone since both sides can + // merge faces independently. + + + + // faceZones of type internal + const labelList internalFaceZones + ( + meshRefiner_.getZones + ( + List<surfaceZonesInfo::faceZoneType> + ( + 1, + surfaceZonesInfo::INTERNAL + ) + ) + ); + + + // Create baffles (pairs of faces that share the same points) + // Baffles stored as owner and neighbour face that have been created. + { + List<labelPair> baffles; + labelList originatingFaceZone; + meshRefiner_.createZoneBaffles + ( + identity(mesh.faceZones().size()), + baffles, + originatingFaceZone + ); + } + + + // Duplicate points on faceZones of type boundary + meshRefiner_.dupNonManifoldBoundaryPoints(); + + // Extract baffles across internal faceZones (for checking mesh quality + // across) + labelPairList internalBaffles + ( + meshRefiner_.subsetBaffles + ( + mesh, + internalFaceZones, + localPointRegion::findDuplicateFacePairs(mesh) + ) + ); + + + bool doFeatures = true; //false; + label nFeatIter = 1; + if (snapParams.nFeatureSnap() > 0) + { + doFeatures = true; + + if (!dryRun_) + { + nFeatIter = snapParams.nFeatureSnap(); + } + + Info<< "Snapping to features in " << nFeatIter + << " iterations ..." << endl; + } + + // Get the labels of added patches. + const labelList adaptPatchIDs(meshRefiner_.meshedPatches()); + + autoPtr<indirectPrimitivePatch> ppPtr + ( + meshRefinement::makePatch + ( + mesh, + adaptPatchIDs + ) + ); + + + if (debug) + { + const fileName dir(mesh.time().path()); + mkDir(dir); + OBJstream str + ( + dir + / "pp_initial_" + meshRefiner_.timeName() + ".obj" + ); + str.write + ( + ppPtr().localFaces(), + ppPtr().localPoints(), + false + ); + } + + + // Maximum distance to attract to nearest feature on surface + scalarField snapDist(calcSnapDistance(mesh, snapParams, ppPtr())); + + + // Smooth patch points. Equivalent of preSmoothPatch but using mesh + // motion solver. + vectorField patchDisp + ( + smoothLambdaMuPatchDisplacement + ( + mesh, + ppPtr(), + internalBaffles + ) + ); + pointField ppLocalPoints(ppPtr().localPoints()+patchDisp); + + const bool smoothInternal = true; + if (smoothInternal) + { + // Create pointMesh with the correct patches + //const pointMesh& pMesh = makePointMesh + //( + // ppPtr(), + // patchConstraints, + // allEdgePatchName, + // allPointPatchName + //); + const pointMesh& pMesh = pointMesh::New(mesh); + + autoPtr<displacementMotionSolver> motionPtr + ( + makeMotionSolver + ( + pMesh, + snapDict, + adaptPatchIDs + //patchConstraints + ) + ); + + // Insert as bc to motionSmoother. Note that this takes displacement + // relative to points0 + setDisplacement + ( + ppPtr(), + patchDisp, + adaptPatchIDs, + motionPtr().points0(), + motionPtr().pointDisplacement() + ); + // Solve internal displacement + tmp<pointField> tnewPoints(motionPtr->newPoints()); + + // Move points + mesh.movePoints(tnewPoints); + + // Update pp for new mesh points. Ok as long as we also update geometry + // and wanted displacement (usually zero if mesh motion has succeeded) + ppLocalPoints = pointField(mesh.points(), ppPtr().meshPoints()); + patchDisp -= (ppLocalPoints-ppPtr().localPoints()); + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing smoothed mesh to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + } + + + // Construct iterative mesh mover. + Info<< "Constructing mesh displacer ..." << endl; + Info<< "Using mesh parameters " << motionDict << nl << endl; + + autoPtr<displacementMotionSolver> motionPtr + ( + makeMotionSolver + ( + pointMesh::New(mesh), + snapDict, + adaptPatchIDs + //patchConstraints + ) + ); + autoPtr<motionSmoother> meshMoverPtr + ( + new motionSmoother + ( + mesh, + ppPtr(), + adaptPatchIDs, + motionPtr().pointDisplacement(), + motionDict, + dryRun_ + ) + ); + + + // Check initial mesh + Info<< "Checking initial mesh ..." << endl; + labelHashSet wrongFaces(mesh.nFaces()/100); + motionSmoother::checkMesh(false, mesh, motionDict, wrongFaces, dryRun_); + const label nInitErrors = returnReduce + ( + wrongFaces.size(), + sumOp<label>() + ); + + Info<< "Detected " << nInitErrors << " illegal faces" + << " (concave, zero area or negative cell pyramid volume)" + << endl; + + + Info<< "Checked initial mesh in = " + << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl; + + + + //- Only if in feature attraction mode: + // Point on nearest feature + vectorField patchFeaturePoint(ppPtr().nPoints(), Zero); + // Constraints at feature + List<pointConstraint> patchConstraints(ppPtr().nPoints()); + + for (label iter = 0; iter < nFeatIter; iter++) + { + Info<< nl + << "Morph iteration " << iter << nl + << "-----------------" << endl; + + + // Calculate displacement at every patch point if we need it: + // - if automatic near-surface detection + // - if face splitting active + pointField nearestPoint(ppPtr().nPoints(), vector::max); + vectorField nearestNormal(ppPtr().nPoints(), Zero); + + + const bool strictRegionSnap + ( + iter < nFeatIter/2 + ? snapParams.strictRegionSnap() + : Switch(true) + ); + + vectorField disp = calcNearestSurface + ( + strictRegionSnap, // attract points to region only + meshRefiner_, + globalToMasterPatch_, // for if strictRegionSnap + globalToSlavePatch_, // for if strictRegionSnap + ppPtr(), + ppLocalPoints, + snapDist, // max snap distance + + nearestPoint, + nearestNormal + ); + + // Override displacement at thin gaps + if (snapParams.detectNearSurfacesSnap()) + { + detectNearSurfaces + ( + Foam::cos(degToRad(planarAngle)),// planar cos for gaps + ppPtr(), + ppLocalPoints, + nearestPoint, // surfacepoint from nearest test + nearestNormal, // surfacenormal from nearest test + + disp + ); + } + + // Override displacement with feature edge attempt + if (doFeatures) + { + //- Any faces to split + DynamicList<label> splitFaces; + //- Indices in face to split across + DynamicList<labelPair> splits; + //- Patches for split face + DynamicList<labelPair> splitPatches; + + // Offset to project to nearest feature. Use in combination with + // patchConstraints. + vectorField patchAttraction; + + disp = calcNearestSurfaceFeature + ( + snapParams, + false, // no alignMeshEdges + true, // check >=3 patch points + + iter, + featureCos, + scalar(iter+1)/nFeatIter, + + snapDist, + disp, // nearest surface + nearestNormal, + ppPtr(), + ppLocalPoints, + + patchAttraction, // offset wrt ppLocalPoints to nearest + // feature edge/point + patchConstraints, // feature type + constraint + + splitFaces, + splits, + splitPatches + ); + + + // Freeze points on exposed points/faces + freezeExposedPoints + ( + meshRefiner_, + "frozenFaces", // faceZone name + "frozenPoints", // pointZone name + ppPtr(), + disp + ); + + patchFeaturePoint = ppLocalPoints+patchAttraction; + + if (debug) + { + OBJstream str + ( + mesh.time().path() + / "calcNearestSurfaceFeature" + + meshRefiner_.timeName() + + ".obj" + ); + forAll(ppLocalPoints, pointi) + { + const point& pt = ppLocalPoints[pointi]; + str.write(linePointRef(pt, pt+disp[pointi])); + } + } + + + + // Split any faces: + // - does not move/add any points + // - tries to move new faces to correct patch + + if (returnReduce(splitFaces.size(), sumOp<label>())) + { + polyTopoChange meshMod(mesh); + + // Insert the mesh changes + meshRefiner_.doSplitFaces + ( + splitFaces, + splits, + splitPatches, + meshMod + ); + + // Save old meshPoints before changing mesh + const Map<label> oldMeshPointMap(ppPtr->meshPointMap()); + Pout<< "old pp points:" << ppPtr->nPoints() + << " oldMeshPointMap:" << oldMeshPointMap.size() + << endl; + + // Remove any unnecessary fields + meshMoverPtr.clear(); + motionPtr.clear(); + ppPtr.clear(); + mesh.clearOut(); + mesh.moving(false); + + // Change the mesh (no inflation) + autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh, false); + mapPolyMesh& map = *mapPtr; + + // Update fields + mesh.updateMesh(map); + + // Move mesh (since morphing might not do this) + if (map.hasMotionPoints()) + { + mesh.movePoints(map.preMotionPoints()); + } + else + { + mesh.clearOut(); + } + + // Reset the instance for if in overwrite mode + mesh.setInstance(meshRefiner_.timeName()); + meshRefiner_.setInstance(mesh.facesInstance()); + + // Update intersections on split faces + { + DynamicList<label> changedFaces(splitFaces.size()); + Map<label> splitFacesMap(splitFaces.size()); + forAll(splitFaces, i) + { + splitFacesMap.insert(splitFaces[i], i); + } + forAll(map.faceMap(), facei) + { + if (splitFacesMap.find(map.faceMap()[facei])) + { + changedFaces.append(facei); + } + } + // Update intersections on changed faces + meshRefiner_.updateMesh + ( + map, + meshRefiner_.growFaceCellFace(changedFaces) + ); + } + + if (debug&meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing split-faces mesh to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + mesh.time().path()/meshRefiner_.timeName() + ); + } + + + + // Update local mesh data + // ~~~~~~~~~~~~~~~~~~~~~~ + + Info<< "Updating for face-splitting" << endl; + + // baffles + forAll(internalBaffles, i) + { + labelPair& baffle = internalBaffles[i]; + baffle.first() = map.reverseFaceMap()[baffle.first()]; + baffle.second() = map.reverseFaceMap()[baffle.second()]; + } + + // re-do patch (since faces might have been split) + ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs); + motionPtr = makeMotionSolver + ( + pointMesh::New(mesh), + snapDict, + adaptPatchIDs + //patchConstraints + ); + meshMoverPtr.reset + ( + new motionSmoother + ( + mesh, + ppPtr(), + adaptPatchIDs, + motionPtr().pointDisplacement(), + motionDict, + dryRun_ + ) + ); + + const auto& mp = ppPtr->meshPoints(); + // pointMap (new-to-old) for pp points. Note: no points changed + // but local point ordering might have changed since faces + // split. + labelList ppMap(mp.size()); + forAll(mp, i) + { + ppMap[i] = oldMeshPointMap[mp[i]]; + } + // patchDisp + meshRefinement::updateList(ppMap, vector::zero, patchDisp); + // snapDist + meshRefinement::updateList(ppMap, scalar(0), snapDist); + // patchFeaturePoint + meshRefinement::updateList + ( + ppMap, + vector::zero, + patchFeaturePoint + ); + // patchConstraints + meshRefinement::updateList + ( + ppMap, + pointConstraint(), + patchConstraints + ); +// // nearestPoint +// meshRefinement::updateList(ppMap, vector::zero, nearestPoint); +// // nearestNormal +// meshRefinement::updateList(ppMap, vector::zero, nearestNormal); + // disp + meshRefinement::updateList(ppMap, vector::zero, disp); + // ppLocalPoints + meshRefinement::updateList(ppMap, vector::zero, ppLocalPoints); + + Info<< "DONE Updating for face-splitting" << endl; + } + } + + + // Attract/slide the mesh a bit + { + //// Create pointMesh with the correct patches + //// - points on single polyPatches stay as is + //// - points on two polyPatches go to allEdgePatchName + //// - points on >two polyPatches go to allPointPatchName + //const pointMesh& pMesh = makePointMesh + //( + // ppPtr(), + // patchConstraints, + // allEdgePatchName, + // allPointPatchName + //); + //const pointMesh& pMesh = pointMesh::New(mesh); + // + //autoPtr<displacementMotionSolver> motionPtr + //( + // makeMotionSolver + // ( + // pMesh, + // snapDict, + // adaptPatchIDs + // //patchConstraints + // ) + //); + + // Insert as bc to motionSmoother. Note that this takes displacement + // relative to points0 + setDisplacement + ( + ppPtr(), + disp, + adaptPatchIDs, + motionPtr().points0(), + motionPtr().pointDisplacement() + ); + + // Solve internal displacement + tmp<pointField> tnewPoints(motionPtr->newPoints()); + + // Move points + if (false) + { + // 1. Directly move points + mesh.movePoints(tnewPoints); + // Optional? Only geometry used is ppLocalPoints which we keep + // and update 'by hand'. + //ppPtr().movePoints(tnewPoints); + } + else + { + // 2. Use motionSmoother + // Set initial distribution of displacement field (on patches) + // from patchDisp and make displacement consistent with b.c. + // on displacement pointVectorField. + const vectorField newDisp(tnewPoints()-meshMoverPtr().oldPoints()); + + meshMoverPtr().displacement().vectorField::operator=(newDisp); + meshMoverPtr().setDisplacement(disp); + + // Apply internal displacement to mesh. + const bool meshOk = scaleMesh + ( + snapParams, + nInitErrors, + internalBaffles, + meshMoverPtr() + ); + + if (!meshOk) + { + WarningInFunction + << "Did not successfully snap mesh." + << " Continuing to snap to resolve easy" << nl + << " surfaces but the" + << " resulting mesh will not satisfy your quality" + << " constraints" << nl << endl; + } + + // Use current mesh as base mesh + meshMoverPtr().correct(); + } + + // Update pp for new mesh points. Ok as long as we also update + // geometry and wanted displacement (usually zero if mesh motion + // has succeeded) + ppLocalPoints = pointField(mesh.points(), ppPtr().meshPoints()); + patchDisp -= (ppLocalPoints-ppPtr().localPoints()); + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing partially moved mesh to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + } + + // Split problematic cells + { + Info<< nl << "Checking moved mesh ..." << endl; + faceSet wrongFaces(mesh, "wrongFaces", mesh.nFaces()/1000); + motionSmoother::checkMesh + ( + false, + mesh, + motionDict, + identity(mesh.nFaces()), + internalBaffles, + wrongFaces, + false // dryRun_ + ); + const label nWrong(returnReduce(wrongFaces.size(), sumOp<label>())); + Info<< "Detected " << nWrong + << " illegal faces" + << " (concave, zero area or negative cell pyramid volume)" + << endl; + + //if (nWrong) + if (false) + { + bitSet decomposeCell(mesh.nCells()); + for (const label facei : wrongFaces) + { + const label own = mesh.faceOwner()[facei]; + if (!tetMatcher::test(mesh, own)) + { + decomposeCell.set(own); + } + if (mesh.isInternalFace(facei)) + { + const label nei = mesh.faceNeighbour()[facei]; + if (!tetMatcher::test(mesh, nei)) + { + decomposeCell.set(nei); + } + } + } + Pout<< "spliyyinG :" << decomposeCell.count() << " cells" + << endl; + + tetDecomposer tetDecomp(mesh); + polyTopoChange meshMod(mesh); + tetDecomp.setRefinement + ( + tetDecomposer::FACE_CENTRE_TRIS, + decomposeCell, + meshMod + ); + + // Save old meshPoints before changing mesh + const Map<label> oldMeshPointMap(ppPtr->meshPointMap()); + + Pout<< "old pp points:" << ppPtr->nPoints() + << " oldMeshPointMap:" << oldMeshPointMap.size() + << endl; + + // Remove any unnecessary fields + meshMoverPtr.clear(); + motionPtr.clear(); + ppPtr.clear(); + mesh.clearOut(); + mesh.moving(false); + + // Change the mesh (no inflation) + autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh, false); + mapPolyMesh& map = *mapPtr; + + // Update fields + mesh.updateMesh(map); + + // Move mesh (since morphing does not do this) + if (map.hasMotionPoints()) + { + mesh.movePoints(map.preMotionPoints()); + } + else + { + mesh.clearOut(); + } + + // Reset the instance for if in overwrite mode + mesh.setInstance(meshRefiner_.timeName()); + meshRefiner_.setInstance(mesh.facesInstance()); + + //- Update numbering on tet-decomposition engine + tetDecomp.updateMesh(map); + + bitSet isChangedFace(mesh.nFaces()); + forAll(map.cellMap(), celli) + { + if (decomposeCell[map.cellMap()[celli]]) + { + isChangedFace.set(mesh.cells()[celli]); + } + } + syncTools::syncFaceList + ( + mesh, + isChangedFace, + orEqOp<unsigned int>() + ); + + Pout<< "isChangedFace :" << decomposeCell.count() << " faces" + << endl; + + + // Update intersection info + meshRefiner_.updateMesh(map, isChangedFace.toc()); + + + if (debug&meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing tet-decomp mesh to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + mesh.time().path()/meshRefiner_.timeName() + ); + } + + + // Update local mesh data + // ~~~~~~~~~~~~~~~~~~~~~~ + + Info<< "Updating for tet-decomp" << endl; + + // baffles + forAll(internalBaffles, i) + { + labelPair& baffle = internalBaffles[i]; + baffle.first() = map.reverseFaceMap()[baffle.first()]; + baffle.second() = map.reverseFaceMap()[baffle.second()]; + } + + // re-do patch (since faces might have been split) + ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs); + Pout<< "new pp points:" << ppPtr->nPoints() + << " new meshPointMap:" << ppPtr->meshPointMap().size() + << endl; + const auto& mp = ppPtr->meshPoints(); + // pointMap (new-to-old) for pp points. Might have new + // face-centre points - these get mapped from any point on + // the originating face. + labelList ppMap(mp.size(), -1); + forAll(mp, i) + { + const label oldMeshPointi = map.pointMap()[mp[i]]; + const auto mpFnd = oldMeshPointMap.find(oldMeshPointi); + if (mpFnd) + { + ppMap[i] = mpFnd(); + } + } + + // patchDisp + meshRefinement::updateList(ppMap, vector::zero, patchDisp); + // snapDist + meshRefinement::updateList(ppMap, scalar(0), snapDist); + // patchFeaturePoint + meshRefinement::updateList + ( + ppMap, + vector::zero, + patchFeaturePoint + ); + // patchConstraints + meshRefinement::updateList + ( + ppMap, + pointConstraint(), + patchConstraints + ); +// // nearestPoint +// meshRefinement::updateList(ppMap, vector::zero, nearestPoint); +// // nearestNormal +// meshRefinement::updateList(ppMap, vector::zero, nearestNormal); +// // disp +// meshRefinement::updateList(ppMap, vector::zero, disp); + + // Maximum distance to attract to nearest feature on surface + snapDist = calcSnapDistance(mesh, snapParams, ppPtr()); + ppLocalPoints = pointField(mesh.points(), ppPtr().meshPoints()); + + Info<< "DONE Updating for tet-decomp" << endl; + } + } + } + +//XXXXXX +/* + { + // Introduce single layer of cells. Straight from snappyLayerDriver + + // Global face indices engine + const globalIndex globalFaces(mesh.nFaces()); + + // Determine extrudePatch.edgeFaces in global numbering (so across + // coupled patches). This is used only to string up edges + // between coupled + // faces (all edges between same (global)face indices get extruded). + labelListList edgeGlobalFaces + ( + addPatchCellLayer::globalEdgeFaces + ( + mesh, + globalFaces, + ppPtr() + ) + ); + + // Determine patches for extruded boundary edges. Calculates if any + // additional processor patches need to be constructed. + + labelList edgePatchID; + labelList edgeZoneID; + boolList edgeFlip; + labelList inflateFaceID; + snappyLayerDriver::determineSidePatches + ( + meshRefiner_, + globalFaces, + edgeGlobalFaces, + ppPtr(), + + edgePatchID, + edgeZoneID, + edgeFlip, + inflateFaceID + ); + + + // Mesh topo change engine. Insert current mesh. + polyTopoChange meshMod(mesh); + + // Layer mesh modifier + addPatchCellLayer addLayer(mesh); + + // Extrude very thin layer of cells + pointField extrusion(PatchTools::pointNormals(mesh, ppPtr())); + const tmp<scalarField> thickness + ( + wantedThickness + ( + ppPtr(), + 1e-3 // cellSizeFraction + ) + ); + extrusion *= thickness; + + // Add topo regardless of whether extrudeStatus is extruderemove. + // Not add layer if patchDisp is zero. + + const label ppNFaces = ppPtr().size(); + const label ppNPoints = ppPtr().nPoints(); + + addLayer.setRefinement + ( + globalFaces, + edgeGlobalFaces, + + scalarField(ppNPoints, 1), // expansion ratio + ppPtr(), + bitSet(ppPtr().size()), // no flip + + edgePatchID, // boundary patch for extruded boundary edges + edgeZoneID, // zone for extruded edges + edgeFlip, + inflateFaceID, + + + labelList(0), // exposed patchIDs, not used for adding layers + labelList(ppNFaces, 1), + labelList(ppNPoints, 1), + extrusion, //patchAttraction, + + meshMod + ); + + // Save old meshPoints before changing mesh + const Map<label> oldMeshPointMap(ppPtr->meshPointMap()); + Pout<< "old pp points:" << ppPtr->nPoints() + << " oldMeshPointMap:" << oldMeshPointMap.size() + << endl; + + // Remove any unnecessary fields + meshMoverPtr.clear(); + motionPtr.clear(); + ppPtr.clear(); + mesh.clearOut(); + mesh.moving(false); + + // Apply the stored topo changes to the current mesh. + autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh, false); + mapPolyMesh& map = *mapPtr; + + // Update fields + mesh.updateMesh(map); + + // Move mesh (since morphing does not do this) + if (map.hasMotionPoints()) + { + mesh.movePoints(map.preMotionPoints()); + } + else + { + // Hack to remove meshPhi - mapped incorrectly. TBD. + mesh.clearOut(); + } + + // Reset the instance for if in overwrite mode + mesh.setInstance(meshRefiner_.timeName()); + + // Re-do the patch + ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs); + Pout<< "new pp points:" << ppPtr->nPoints() + << " new meshPointMap:" << ppPtr->meshPointMap().size() + << endl; + // Map the old-patch-point data to the new patch points + // pointMap (new-to-old) for new pp points + labelList ppMap(ppPtr->nPoints(), -1); + { + const labelListList& oldAddedPoints = addLayer.addedPoints(); + forAll(oldAddedPoints, oldPatchPointi) + { + const label oldPointi = oldAddedPoints[oldPatchPointi].last(); + const label newPointi = map.reversePointMap()[oldPointi]; + const label newPatchPointi = ppPtr().meshPointMap()[newPointi]; + + ppMap[newPatchPointi] = oldPatchPointi; + } + } + + // Update attraction + meshRefinement::updateList(ppMap, vector::zero, patchDisp); + // snapDist + meshRefinement::updateList(ppMap, scalar(0), snapDist); + // patchFeaturePoint + meshRefinement::updateList + ( + ppMap, + vector::zero, + patchFeaturePoint + ); + // patchConstraints + meshRefinement::updateList + ( + ppMap, + pointConstraint(), + patchConstraints + ); + // ppLocalPoints + //meshRefinement::updateList(ppMap, vector::zero, ppLocalPoints); + ppLocalPoints = pointField(mesh.points(), ppPtr().meshPoints()); + + + // Update numbering on layer + addLayer.updateMesh + ( + map, + identity(ppNFaces), + identity(ppNPoints) + ); + + // Update intersections + const labelListList addedCells(addLayer.addedCells()); + bitSet isChangedFace(mesh.nFaces()); + for (const labelList& faceToCells : addedCells) + { + for (const label celli : faceToCells) + { + isChangedFace.set(mesh.cells()[celli]); + } + } + meshRefiner_.updateMesh(map, isChangedFace.toc()); + + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing mesh-with-layer to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + if (debug) + { + OBJstream str + ( + mesh.time().path() + / "new_projection" + + meshRefiner_.timeName() + + ".obj" + ); + forAll(ppLocalPoints, pointi) + { + const point& pt = ppLocalPoints[pointi]; + str.write(linePointRef(pt, patchFeaturePoint[pointi])); + } + Pout<< "** writing mapped attraction to " << str.name() << endl; + } + } +*/ +//XXXX + { + // Layer mesh modifier + addPatchCellLayer addLayer(mesh); + + // Save old mesh points (to construct the new-to-old local patch points) + const Map<label> oldMeshPointMap(ppPtr->meshPointMap()); + + meshMoverPtr.clear(); + motionPtr.clear(); + + const pointField thickness + ( + wantedThickness(ppPtr(), 1e-3) //cellSizeFraction + * PatchTools::pointNormals(mesh, ppPtr()) + ); + autoPtr<mapPolyMesh> mapPtr = addBufferLayers + ( + ppPtr(), + thickness, + addLayer + ); + + // Re-do the patch + ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs); + + // Map the old-patch-point data to the new patch points + // pointMap (new-to-old) for new pp points + labelList ppMap(ppPtr->nPoints(), -1); + { + const labelListList& addedPoints = addLayer.addedPoints(); + forAll(addedPoints, oldPatchPointi) + { + const label newPointi = addedPoints[oldPatchPointi].last(); + const label newPatchPointi = ppPtr().meshPointMap()[newPointi]; + ppMap[newPatchPointi] = oldPatchPointi; + } + } + + // Update attraction + meshRefinement::updateList(ppMap, vector::zero, patchDisp); + // snapDist + meshRefinement::updateList(ppMap, scalar(0), snapDist); + // patchFeaturePoint + meshRefinement::updateList + ( + ppMap, + vector::zero, + patchFeaturePoint + ); + // patchConstraints + meshRefinement::updateList + ( + ppMap, + pointConstraint(), + patchConstraints + ); + // ppLocalPoints + ppLocalPoints = pointField(mesh.points(), ppPtr().meshPoints()); + } +//XXXXXX + const bool snapToGeometry = true; + if (snapToGeometry) + { + // Create pointMesh with the correct patches + // - points on single polyPatches stay as is + // - points on two polyPatches go to allEdgePatchName + // - points on >two polyPatches go to allPointPatchName + //const pointMesh& pMesh = makePointMesh + //( + // ppPtr(), + // patchConstraints, + // allEdgePatchName, + // allPointPatchName + //); + const pointMesh& pMesh = pointMesh::New(mesh); + + autoPtr<displacementMotionSolver> motionPtr + ( + makeMotionSolver + ( + pMesh, + snapDict, + adaptPatchIDs + //patchConstraints + ) + ); + + // Insert as bc to motionSmoother. Note that this takes displacement + // relative to points0 + setDisplacement + ( + ppPtr(), + patchFeaturePoint-ppLocalPoints, + adaptPatchIDs, + motionPtr().points0(), + motionPtr().pointDisplacement() + ); + + + if (debug) + { + OBJstream str + ( + mesh.time().path() + / "buffer_layer_new_projection" + + meshRefiner_.timeName() + + ".obj" + ); + forAll(ppLocalPoints, pointi) + { + const point& pt = ppLocalPoints[pointi]; + str.write(linePointRef(pt, patchFeaturePoint[pointi])); + } + Pout<< "** writing mapped attraction to " << str.name() << endl; + } + + + // Solve internal displacement + tmp<pointField> tnewPoints(motionPtr->newPoints()); + + // Move points + mesh.movePoints(tnewPoints); + + // Update pp for new mesh points. Ok as long as we also update geometry + // and wanted displacement (usually zero if mesh motion has succeeded) + ppLocalPoints = pointField(mesh.points(), ppPtr().meshPoints()); + patchDisp -= (ppLocalPoints-ppPtr().localPoints()); + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing smoothed LAYER mesh to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + } + + + // Merge any introduced baffles (from faceZones of faceType 'internal') + { + autoPtr<mapPolyMesh> mapPtr = meshRefiner_.mergeZoneBaffles + ( + true, // internal zones + false // baffle zones + ); + + if (mapPtr.valid()) + { + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + Info<< "Writing baffle-merged mesh to time " + << meshRefiner_.timeName() << endl; + meshRefiner_.write + ( + meshRefinement::debugType(debug), + meshRefinement::writeType + ( + meshRefinement::writeLevel() + | meshRefinement::WRITEMESH + ), + meshRefiner_.timeName() + ); + } + } + } + + // Repatch faces according to nearest. Do not repatch baffle faces. + { + labelList duplicateFace(getInternalOrBaffleDuplicateFace()); + + repatchToSurface(snapParams, adaptPatchIDs, duplicateFace); + } + + if (debug & meshRefinement::MESH) + { + const_cast<Time&>(mesh.time())++; + } +} + + +// ************************************************************************* // diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriverFeature.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriverFeature.C index e5e951c30dfcd99b6c033dfe02a69c1293197c1d..b4aaa38fa32860c24ab139052aec1c27ef7f54aa 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriverFeature.C +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappySnapDriverFeature.C @@ -68,65 +68,65 @@ namespace Foam // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -bool Foam::snappySnapDriver::isFeaturePoint -( - const scalar featureCos, - const indirectPrimitivePatch& pp, - const bitSet& isFeatureEdge, - const label pointi -) const -{ - const pointField& points = pp.localPoints(); - const edgeList& edges = pp.edges(); - const labelList& pEdges = pp.pointEdges()[pointi]; - - label nFeatEdges = 0; - - forAll(pEdges, i) - { - if (isFeatureEdge[pEdges[i]]) - { - nFeatEdges++; - - for (label j = i+1; j < pEdges.size(); j++) - { - if (isFeatureEdge[pEdges[j]]) - { - const edge& ei = edges[pEdges[i]]; - const edge& ej = edges[pEdges[j]]; - - const point& p = points[pointi]; - const point& pi = points[ei.otherVertex(pointi)]; - const point& pj = points[ej.otherVertex(pointi)]; - - vector vi = p-pi; - scalar viMag = mag(vi); - - vector vj = pj-p; - scalar vjMag = mag(vj); - - if - ( - viMag > SMALL - && vjMag > SMALL - && ((vi/viMag & vj/vjMag) < featureCos) - ) - { - return true; - } - } - } - } - } - - if (nFeatEdges == 1) - { - // End of feature-edge string - return true; - } - - return false; -} +//bool Foam::snappySnapDriver::isFeaturePoint +//( +// const scalar featureCos, +// const indirectPrimitivePatch& pp, +// const bitSet& isFeatureEdge, +// const label pointi +//) const +//{ +// const pointField& points = ppLocalPoints; +// const edgeList& edges = pp.edges(); +// const labelList& pEdges = pp.pointEdges()[pointi]; +// +// label nFeatEdges = 0; +// +// forAll(pEdges, i) +// { +// if (isFeatureEdge[pEdges[i]]) +// { +// nFeatEdges++; +// +// for (label j = i+1; j < pEdges.size(); j++) +// { +// if (isFeatureEdge[pEdges[j]]) +// { +// const edge& ei = edges[pEdges[i]]; +// const edge& ej = edges[pEdges[j]]; +// +// const point& p = points[pointi]; +// const point& pi = points[ei.otherVertex(pointi)]; +// const point& pj = points[ej.otherVertex(pointi)]; +// +// vector vi = p-pi; +// scalar viMag = mag(vi); +// +// vector vj = pj-p; +// scalar vjMag = mag(vj); +// +// if +// ( +// viMag > SMALL +// && vjMag > SMALL +// && ((vi/viMag & vj/vjMag) < featureCos) +// ) +// { +// return true; +// } +// } +// } +// } +// } +// +// if (nFeatEdges == 1) +// { +// // End of feature-edge string +// return true; +// } +// +// return false; +//} void Foam::snappySnapDriver::smoothAndConstrain @@ -224,6 +224,8 @@ void Foam::snappySnapDriver::calcNearestFace ( const label iter, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, + const scalarField& faceSnapDist, vectorField& faceDisp, vectorField& faceSurfaceNormal, @@ -234,6 +236,16 @@ void Foam::snappySnapDriver::calcNearestFace const fvMesh& mesh = meshRefiner_.mesh(); const refinementSurfaces& surfaces = meshRefiner_.surfaces(); + const pointField ppFaceCentres + ( + primitivePatch + ( + SubList<face>(pp.localFaces()), + ppLocalPoints + ).faceCentres() + ); + + // Displacement and orientation per pp face. faceDisp.setSize(pp.size()); faceDisp = Zero; @@ -268,6 +280,7 @@ void Foam::snappySnapDriver::calcNearestFace // Get indices of faces on pp that are also in zone DynamicList<label> ppFaces; DynamicList<label> meshFaces; + DynamicField<point> fc; forAll(faceZoneNames, fzi) { const word& faceZoneName = faceZoneNames[fzi]; @@ -283,6 +296,7 @@ void Foam::snappySnapDriver::calcNearestFace ppFaces.reserve(ppFaces.capacity()+fZone.size()); meshFaces.reserve(meshFaces.capacity()+fZone.size()); + fc.reserve(meshFaces.capacity()+fZone.size()); forAll(pp.addressing(), i) { @@ -291,6 +305,7 @@ void Foam::snappySnapDriver::calcNearestFace snapSurf[i] = zoneSurfi; ppFaces.append(i); meshFaces.append(pp.addressing()[i]); + fc.append(ppFaceCentres[i]); } } @@ -299,15 +314,6 @@ void Foam::snappySnapDriver::calcNearestFace // << endl; } - pointField fc - ( - indirectPrimitivePatch - ( - IndirectList<face>(mesh.faces(), meshFaces), - mesh.points() - ).faceCentres() - ); - List<pointIndexHit> hitInfo; labelList hitSurface; labelList hitRegion; @@ -364,26 +370,19 @@ void Foam::snappySnapDriver::calcNearestFace DynamicList<label> ppFaces(pp.size()); DynamicList<label> meshFaces(pp.size()); + DynamicField<point> fc(pp.size()); forAll(pp.addressing(), i) { if (snapSurf[i] == -1) { ppFaces.append(i); meshFaces.append(pp.addressing()[i]); + fc.append(ppFaceCentres[i]); } } //Pout<< "Found " << ppFaces.size() << " unzoned faces out of " // << pp.size() << endl; - pointField fc - ( - indirectPrimitivePatch - ( - IndirectList<face>(mesh.faces(), meshFaces), - mesh.points() - ).faceCentres() - ); - List<pointIndexHit> hitInfo; labelList hitSurface; labelList hitRegion; @@ -478,6 +477,7 @@ void Foam::snappySnapDriver::calcNearestFacePointProperties ( const label iter, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const vectorField& faceDisp, const vectorField& faceSurfaceNormal, @@ -541,7 +541,7 @@ void Foam::snappySnapDriver::calcNearestFacePointProperties { pNormals[nFaces] = faceSurfaceNormal[facei]; pDisp[nFaces] = faceDisp[facei]; - pFc[nFaces] = pp.faceCentres()[facei]; + pFc[nFaces] = pp.localFaces()[facei].centre(ppLocalPoints); pFid[nFaces] = globalToMasterPatch_[globalRegioni]; nFaces++; } @@ -647,7 +647,13 @@ void Foam::snappySnapDriver::calcNearestFacePointProperties List<point>& pFc = pointFaceCentres[pointi]; labelList& pFid = pointFacePatchID[pointi]; - const point& pt = mesh.points()[f[fp]]; + + // Note: these are points which are on the patch but + // the face itself is not. Could recalculate the + // facearea with the modified point but hopefully + // not necessary. + //const point& pt = mesh.points()[f[fp]]; + const point& pt = ppLocalPoints[pointi]; vector fn = mesh.faceAreas()[facei]; pNormals.append(fn/mag(fn)); @@ -682,10 +688,11 @@ void Foam::snappySnapDriver::calcNearestFacePointProperties { // Make into displacement before synchronising to avoid any problems // with parallel cyclics - pointField localPoints(pp.points(), pp.meshPoints()); + //pointField localPoints(pp.points(), pp.meshPoints()); forAll(pointFaceCentres, pointi) { - const point& pt = pp.points()[pp.meshPoints()[pointi]]; + //const point& pt = pp.points()[pp.meshPoints()[pointi]]; + const point& pt = ppLocalPoints[pointi]; List<point>& pFc = pointFaceCentres[pointi]; for (point& p : pFc) @@ -704,7 +711,8 @@ void Foam::snappySnapDriver::calcNearestFacePointProperties ); forAll(pointFaceCentres, pointi) { - const point& pt = pp.points()[pp.meshPoints()[pointi]]; + //const point& pt = pp.points()[pp.meshPoints()[pointi]]; + const point& pt = ppLocalPoints[pointi]; List<point>& pFc = pointFaceCentres[pointi]; for (point& p : pFc) @@ -975,6 +983,7 @@ void Foam::snappySnapDriver::featureAttractionUsingReconstruction const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, const label pointi, @@ -1092,7 +1101,8 @@ void Foam::snappySnapDriver::featureAttractionUsingReconstruction } - const point& pt = pp.localPoints()[pointi]; + //const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; // Check the number of directions if (surfaceNormals.size() == 1) @@ -1168,6 +1178,7 @@ void Foam::snappySnapDriver::featureAttractionUsingReconstruction const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, @@ -1212,7 +1223,7 @@ void Foam::snappySnapDriver::featureAttractionUsingReconstruction DynamicList<vector> surfaceNormals(4); labelList faceToNormalBin; - forAll(pp.localPoints(), pointi) + forAll(ppLocalPoints, pointi) { vector attraction = Zero; pointConstraint constraint; @@ -1223,6 +1234,7 @@ void Foam::snappySnapDriver::featureAttractionUsingReconstruction featureCos, pp, + ppLocalPoints, snapDist, nearestDisp, @@ -1253,7 +1265,8 @@ void Foam::snappySnapDriver::featureAttractionUsingReconstruction patchAttraction[pointi] = attraction; patchConstraints[pointi] = constraint; - const point& pt = pp.localPoints()[pointi]; + //const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; if (feStr && patchConstraints[pointi].first() == 2) { @@ -1274,6 +1287,7 @@ void Foam::snappySnapDriver::stringFeatureEdges const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& rawPatchAttraction, @@ -1314,7 +1328,8 @@ void Foam::snappySnapDriver::stringFeatureEdges { if (patchConstraints[pointi].first() == 2) { - const point& pt = pp.localPoints()[pointi]; + //const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; const labelList& pEdges = pointEdges[pointi]; const vector& featVec = patchConstraints[pointi].second(); @@ -1330,7 +1345,8 @@ void Foam::snappySnapDriver::stringFeatureEdges if (patchConstraints[nbrPointi].first() > 1) { - const point& nbrPt = pp.localPoints()[nbrPointi]; + //const point& nbrPt = pp.localPoints()[nbrPointi]; + const point& nbrPt = ppLocalPoints[nbrPointi]; const point featPt = nbrPt + patchAttraction[nbrPointi]; const scalar cosAngle = (featVec & (featPt-pt)); @@ -1349,7 +1365,7 @@ void Foam::snappySnapDriver::stringFeatureEdges if (!hasPos || !hasNeg) { //Pout<< "**Detected feature string end at " - // << pp.localPoints()[pointi] << endl; + // << ppLocalPoints[pointi] << endl; // No string. Assign best choice on either side label bestPosPointi = -1; @@ -1382,7 +1398,8 @@ void Foam::snappySnapDriver::stringFeatureEdges ); const point featPt = - pp.localPoints()[nbrPointi] + //pp.localPoints()[nbrPointi] + ppLocalPoints[nbrPointi] + rawPatchAttraction[nbrPointi]; const scalar cosAngle = (featVec & (featPt-pt)); @@ -1412,7 +1429,7 @@ void Foam::snappySnapDriver::stringFeatureEdges // Use reconstructed-feature attraction. Use only // part of it since not sure... //const point& bestPt = - // pp.localPoints()[bestPosPointi]; + // ppLocalPoints[bestPosPointi]; //Pout<< "**Overriding point " << bestPt // << " on reconstructed feature edge at " // << rawPatchAttraction[bestPosPointi]+bestPt @@ -1429,7 +1446,7 @@ void Foam::snappySnapDriver::stringFeatureEdges // Use reconstructed-feature attraction. Use only // part of it since not sure... //const point& bestPt = - // pp.localPoints()[bestNegPointi]; + // ppLocalPoints[bestNegPointi]; //Pout<< "**Overriding point " << bestPt // << " on reconstructed feature edge at " // << rawPatchAttraction[bestNegPointi]+bestPt @@ -1463,6 +1480,7 @@ void Foam::snappySnapDriver::releasePointsNextToMultiPatch const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const List<List<point>>& pointFaceCentres, @@ -1499,7 +1517,7 @@ void Foam::snappySnapDriver::releasePointsNextToMultiPatch { pointIndexHit multiPatchPt = findMultiPatchPoint ( - pp.localPoints()[pointi], + ppLocalPoints[pointi], pointFacePatchID[pointi], pointFaceCentres[pointi] ); @@ -1523,7 +1541,7 @@ void Foam::snappySnapDriver::releasePointsNextToMultiPatch //if (multiPatchStr) //{ // Pout<< "Adding constraint on multiPatchPoint:" - // << pp.localPoints()[pointi] + // << ppLocalPoints[pointi] // << " constraint:" << patchConstraints[pointi] // << " attraction:" << patchAttraction[pointi] // << endl; @@ -1568,14 +1586,14 @@ void Foam::snappySnapDriver::releasePointsNextToMultiPatch { //Pout<< "Knocking out constraint" // << " on non-multiPatchPoint:" - // << pp.localPoints()[pointi] << endl; + // << ppLocalPoints[pointi] << endl; patchAttraction[pointi] = Zero; patchConstraints[pointi] = pointConstraint(); nChanged++; if (multiPatchStr) { - multiPatchStr().write(pp.localPoints()[pointi]); + multiPatchStr().write(ppLocalPoints[pointi]); } } } @@ -1727,6 +1745,7 @@ Foam::labelPair Foam::snappySnapDriver::findDiagonalAttraction const scalar concaveCos, const scalar minAreaRatio, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const vectorField& patchAttr, const List<pointConstraint>& patchConstraints, const vectorField& nearestAttr, @@ -1743,8 +1762,6 @@ Foam::labelPair Foam::snappySnapDriver::findDiagonalAttraction if (localF.size() >= 4) { - const pointField& localPts = pp.localPoints(); - //// Estimate cell centre taking patchAttraction into account //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //// (is this necessary?) @@ -1805,8 +1822,10 @@ Foam::labelPair Foam::snappySnapDriver::findDiagonalAttraction // Check if // - sameish feature edge normal // - diagonal aligned with feature edge normal - point start = localPts[startPti]+patchAttr[startPti]; - point end = localPts[endPti]+patchAttr[endPti]; + point start = + ppLocalPoints[startPti]+patchAttr[startPti]; + point end = + ppLocalPoints[endPti]+patchAttr[endPti]; if ( @@ -1846,15 +1865,15 @@ Foam::labelPair Foam::snappySnapDriver::findDiagonalAttraction // Get compact face and points const face compact0(identity(f0.size())); points0.clear(); - points0.append(localPts[f0[0]] + patchAttr[f0[0]]); + points0.append(ppLocalPoints[f0[0]] + patchAttr[f0[0]]); for (label fp=1; fp < f0.size()-1; fp++) { label pi = f0[fp]; - points0.append(localPts[pi] + nearestAttr[pi]); + points0.append(ppLocalPoints[pi] + nearestAttr[pi]); } points0.append ( - localPts[f0.last()] + patchAttr[f0.last()] + ppLocalPoints[f0.last()] + patchAttr[f0.last()] ); @@ -1877,15 +1896,15 @@ Foam::labelPair Foam::snappySnapDriver::findDiagonalAttraction // Get compact face and points const face compact1(identity(f1.size())); points1.clear(); - points1.append(localPts[f1[0]] + patchAttr[f1[0]]); + points1.append(ppLocalPoints[f1[0]] + patchAttr[f1[0]]); for (label fp=1; fp < f1.size()-1; fp++) { label pi = f1[fp]; - points1.append(localPts[pi] + nearestAttr[pi]); + points1.append(ppLocalPoints[pi] + nearestAttr[pi]); } points1.append ( - localPts[f1.last()] + patchAttr[f1.last()] + ppLocalPoints[f1.last()] + patchAttr[f1.last()] ); @@ -1920,8 +1939,8 @@ Foam::labelPair Foam::snappySnapDriver::findDiagonalAttraction else { // Existing areas - const scalar area0 = f0.mag(localPts); - const scalar area1 = f1.mag(localPts); + const scalar area0 = f0.mag(ppLocalPoints); + const scalar area1 = f1.mag(ppLocalPoints); if ( @@ -1947,13 +1966,17 @@ void Foam::snappySnapDriver::splitDiagonals const scalar minAreaRatio, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const vectorField& nearestAttraction, const vectorField& nearestNormal, + const List<labelList>& pointFacePatchID, vectorField& patchAttraction, List<pointConstraint>& patchConstraints, + DynamicList<label>& splitFaces, - DynamicList<labelPair>& splits + DynamicList<labelPair>& splits, + DynamicList<labelPair>& splitPatches ) const { const labelList& bFaces = pp.addressing(); @@ -1962,11 +1985,13 @@ void Foam::snappySnapDriver::splitDiagonals splitFaces.setCapacity(bFaces.size()); splits.clear(); splits.setCapacity(bFaces.size()); - + splitPatches.clear(); + splitPatches.setCapacity(bFaces.size()); // Work arrays for storing points of face DynamicField<point> facePoints0; DynamicField<point> facePoints1; + face f0, f1; forAll(bFaces, facei) { @@ -1979,6 +2004,7 @@ void Foam::snappySnapDriver::splitDiagonals minAreaRatio, pp, + ppLocalPoints, patchAttraction, patchConstraints, @@ -1995,13 +2021,13 @@ void Foam::snappySnapDriver::splitDiagonals { splitFaces.append(bFaces[facei]); splits.append(split); + splitPatches.append(labelPair(-1, -1)); const face& f = pp.localFaces()[facei]; // Knock out other attractions on face forAll(f, fp) { - // Knock out any other constraints if ( fp != split[0] @@ -2020,6 +2046,105 @@ void Foam::snappySnapDriver::splitDiagonals patchAttraction[f[fp]] = nearestAttraction[f[fp]]; } } + + + // Detect any patches to give to the two faces + labelPair& twoPatches = splitPatches.last(); + + // Split into two faces: + // - face0 is from split[0] up to split[1] + // - face1 is from split[1] up to split[0] + meshRefinement::splitFace(f, split, f0, f1); + + // Bit heuristic: + // - find any inbetween vertex (i.e. not on diagonal) that + // has single patch only + // - if we find such a point on both sides we use these patches + // - if only found a point on one side check the other side + // for any other patch + + // Find single patch + for (label fp = 1; fp < f0.size()-1; fp++) + { + const auto& patches = pointFacePatchID[f0[fp]]; + if (patches.uniform()) + { + twoPatches[0] = patches[0]; + } + } + for (label fp = 1; fp < f1.size()-1; fp++) + { + const auto& patches = pointFacePatchID[f1[fp]]; + if (patches.uniform()) + { + twoPatches[1] = patches[0]; + } + } + + if (twoPatches[0] == -1) + { + // Find any patch on any point that differs from twoPatches[1] + // (can be -1 or a unform patch) + + for (label fp = 1; fp < f0.size()-1; fp++) + { + const auto& patches = pointFacePatchID[f0[fp]]; + + // Pick any patch which is not the unique patch of the + // other face. TBD: count occurences and choose most used? + for (const label patchi : patches) + { + if (patchi != twoPatches[1]) + { + twoPatches[0] = patchi; + break; + } + } + } + } + + if (twoPatches[1] == -1) + { + // Find any patch on any point that differs from twoPatches[0] + // (can be -1 or a unform patch) + + for (label fp = 1; fp < f1.size()-1; fp++) + { + const auto& patches = pointFacePatchID[f1[fp]]; + + // Pick any patch which is not the unique patch of the + // other face. TBD: count occurences and choose most used? + for (const label patchi : patches) + { + if (patchi != twoPatches[0]) + { + twoPatches[1] = patchi; + break; + } + } + } + } + + // Fall-back : choose any connected patch + if (twoPatches[0] == -1) + { + twoPatches[0] = pointFacePatchID[f0[1]][0]; + } + if (twoPatches[1] == -1) + { + twoPatches[1] = pointFacePatchID[f1[1]][0]; + } + + //if (twoPatches != labelPair(-1, -1)) + //{ + // Pout<< "Face:" << bFaces[facei] + // << " at:" << pp.faceCentres()[facei] + // << " split into f0:" << flatOutput(f0) + // << " patch:" << twoPatches[0] + // << " and f1:" << flatOutput(f1) + // << " patch:" << twoPatches[1] + // << endl; + //} } } } @@ -2031,6 +2156,7 @@ void Foam::snappySnapDriver::avoidDiagonalAttraction const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, vectorField& patchAttraction, List<pointConstraint>& patchConstraints @@ -2054,10 +2180,10 @@ void Foam::snappySnapDriver::avoidDiagonalAttraction // For now just attract my one to the average of those. const label i0 = f[diag[0]]; const point pt0 = - pp.localPoints()[i0]+patchAttraction[i0]; + ppLocalPoints[i0]+patchAttraction[i0]; const label i1 = f[diag[1]]; const point pt1 = - pp.localPoints()[i1]+patchAttraction[i1]; + ppLocalPoints[i1]+patchAttraction[i1]; const point mid = 0.5*(pt0+pt1); const scalar cosAngle = mag @@ -2084,7 +2210,7 @@ void Foam::snappySnapDriver::avoidDiagonalAttraction label pointi = f[fp]; if (patchConstraints[pointi].first() <= 1) { - scalar distSqr = mid.distSqr(pp.localPoints()[pointi]); + scalar distSqr = mid.distSqr(ppLocalPoints[pointi]); if (distSqr < minDistSqr) { minFp = fp; @@ -2095,7 +2221,7 @@ void Foam::snappySnapDriver::avoidDiagonalAttraction { label minPointi = f[minFp]; patchAttraction[minPointi] = - mid-pp.localPoints()[minPointi]; + mid-ppLocalPoints[minPointi]; patchConstraints[minPointi] = patchConstraints[f[diag[0]]]; } } @@ -2127,6 +2253,7 @@ Foam::snappySnapDriver::findNearFeatureEdge const bool isRegionEdge, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const label pointi, const point& estimatedPt, @@ -2178,7 +2305,7 @@ Foam::snappySnapDriver::findNearFeatureEdge edgeConstraints[feati][nearInfo.index()].append(c); // Store for later use - patchAttraction[pointi] = nearInfo.point()-pp.localPoints()[pointi]; + patchAttraction[pointi] = nearInfo.point()-ppLocalPoints[pointi]; patchConstraints[pointi] = c; } return Tuple2<label, pointIndexHit>(feati, nearInfo); @@ -2191,6 +2318,7 @@ Foam::snappySnapDriver::findNearFeaturePoint const bool isRegionPoint, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const label pointi, const point& estimatedPt, @@ -2224,7 +2352,7 @@ Foam::snappySnapDriver::findNearFeaturePoint if (feati != -1) { - const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; label featPointi = nearInfo[0].index(); const point& featPt = nearInfo[0].hitPoint(); @@ -2236,7 +2364,7 @@ Foam::snappySnapDriver::findNearFeaturePoint if (oldPointi != -1) { // Check distance - if (distSqr >= featPt.distSqr(pp.localPoints()[oldPointi])) + if (distSqr >= featPt.distSqr(ppLocalPoints[oldPointi])) { // oldPointi nearest. Keep. feati = -1; @@ -2262,9 +2390,10 @@ Foam::snappySnapDriver::findNearFeaturePoint isRegionPoint, // search region edges only pp, + ppLocalPoints, snapDist, oldPointi, - pp.localPoints()[oldPointi], + ppLocalPoints[oldPointi], edgeAttractors, edgeConstraints, @@ -2297,8 +2426,10 @@ void Foam::snappySnapDriver::determineFeatures const label iter, const scalar featureCos, const bool multiRegionFeatureSnap, + const bool strictRegionFeatureSnap, // special >=3 patch points handling const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, @@ -2387,9 +2518,9 @@ void Foam::snappySnapDriver::determineFeatures DynamicList<vector> surfaceNormals(4); labelList faceToNormalBin; - forAll(pp.localPoints(), pointi) + forAll(ppLocalPoints, pointi) { - const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; // Determine the geometric planes the point is (approximately) on. @@ -2409,6 +2540,7 @@ void Foam::snappySnapDriver::determineFeatures featureCos, pp, + ppLocalPoints, snapDist, nearestDisp, @@ -2417,7 +2549,7 @@ void Foam::snappySnapDriver::determineFeatures pointFaceSurfNormals, pointFaceDisp, pointFaceCentres, - pointFacePatchID, + pointFacePatchID, // currently not used surfacePoints, surfaceNormals, @@ -2427,6 +2559,43 @@ void Foam::snappySnapDriver::determineFeatures constraint ); + + if (strictRegionFeatureSnap) + { + // Bit tricky: if a point is on more than 2 points and only + // attracted-to-surface upgrade it to attract-to-edge so it follows + // more complex logic below. This is easier than complicating + // the nearestFeatureEdge/Point below. + + if (constraint.first() == 1) + { + const auto& patches = pointFacePatchID[pointi]; + label patch1 = -1; + for (label i = 1; i < patches.size(); i++) + { + if (patches[i] != patches[0]) + { + if (patch1 == -1) + { + patch1 = patches[i]; + } + else if (patches[i] != patch1) + { + // >= on 2 patches. Upgrade to edge-attract + constraint.first() = 2; + //Pout<< "** 3 patch point:" << pointi + // << " at:" << pt + // << " patches:" << flatOutput(patches) + // << " upgraded to feature-edge" + // << " attracted to " << attraction << endl; + break; + } + } + } + } + } + + // Now combine the reconstruction with the current state of the // point. The logic is quite complicated: // - the new constraint (from reconstruction) will only win if @@ -2497,6 +2666,7 @@ void Foam::snappySnapDriver::determineFeatures ( true, // isRegionEdge pp, + ppLocalPoints, snapDist, pointi, multiPatchPt.point(), // estimatedPt @@ -2567,6 +2737,7 @@ void Foam::snappySnapDriver::determineFeatures ( true, // isRegionEdge pp, + ppLocalPoints, snapDist, pointi, estimatedPt, @@ -2597,6 +2768,7 @@ void Foam::snappySnapDriver::determineFeatures ( true, // isRegionPoint pp, + ppLocalPoints, snapDist, pointi, estimatedPt, @@ -2628,6 +2800,7 @@ void Foam::snappySnapDriver::determineFeatures ( true, // isRegionEdge pp, + ppLocalPoints, snapDist, pointi, estimatedPt, @@ -2660,6 +2833,7 @@ void Foam::snappySnapDriver::determineFeatures ( false, // isRegionPoint pp, + ppLocalPoints, snapDist, pointi, estimatedPt, @@ -2728,6 +2902,7 @@ void Foam::snappySnapDriver::determineFeatures ( true, // isRegionPoint pp, + ppLocalPoints, snapDist, pointi, estimatedPt, @@ -2749,6 +2924,7 @@ void Foam::snappySnapDriver::determineFeatures ( false, // isRegionPoint pp, + ppLocalPoints, snapDist, pointi, estimatedPt, @@ -2772,6 +2948,7 @@ void Foam::snappySnapDriver::determineFeatures ( false, // isRegionPoint pp, + ppLocalPoints, snapDist, pointi, estimatedPt, @@ -2817,6 +2994,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, // Feature-point to pp point @@ -2836,6 +3014,13 @@ void Foam::snappySnapDriver::determineBaffleFeatures // Calculate edge-faces List<List<point>> edgeFaceNormals(pp.nEdges()); + vectorField ppFaceNormals(pp.size()); + forAll(ppFaceNormals, facei) + { + ppFaceNormals[facei] = pp.localFaces()[facei].unitNormal(ppLocalPoints); + } + + // Fill local data forAll(pp.edgeFaces(), edgei) { @@ -2845,7 +3030,8 @@ void Foam::snappySnapDriver::determineBaffleFeatures forAll(eFaces, i) { label facei = eFaces[i]; - eFc[i] = pp.faceNormals()[facei]; + //eFc[i] = pp.faceNormals()[facei]; + eFc[i] = ppFaceNormals[facei]; } } @@ -2913,7 +3099,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures if (baffleEdgeStr) { - baffleEdgeStr().write(e, pp.localPoints()); + baffleEdgeStr().write(e, ppLocalPoints); } } } @@ -2940,7 +3126,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures // ) // ) // { - // //Pout<< "Detected feature point:" << pp.localPoints()[pointi] + // //Pout<< "Detected feature point:" << ppLocalPoints[pointi] // // << endl; // //-TEMPORARILY DISABLED: // //pointStatus[pointi] = 1; @@ -2964,7 +3150,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures forAll(pointStatus, pointi) { - const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; if (pointStatus[pointi] == 0) // baffle edge { @@ -2974,6 +3160,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures ( false, // isRegionPoint? pp, + ppLocalPoints, snapDist, pointi, pt, @@ -3000,6 +3187,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures false, // isRegionPoint, pp, + ppLocalPoints, snapDist, pointi, pt, // estimatedPt, @@ -3053,7 +3241,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures oldPointi == -1 || ( distSqr - < featPt.distSqr(pp.localPoints()[oldPointi]) + < featPt.distSqr(ppLocalPoints[oldPointi]) ) ) { @@ -3075,9 +3263,10 @@ void Foam::snappySnapDriver::determineBaffleFeatures ( false, // isRegionPoint pp, + ppLocalPoints, snapDist, oldPointi, - pp.localPoints()[oldPointi], + ppLocalPoints[oldPointi], edgeAttractors, edgeConstraints, @@ -3106,6 +3295,7 @@ void Foam::snappySnapDriver::determineBaffleFeatures ( false, // isRegionPoint pp, + ppLocalPoints, snapDist, pointi, pt, // starting point @@ -3142,6 +3332,7 @@ void Foam::snappySnapDriver::reverseAttractMeshPoints const label iter, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, // Feature-point to pp point @@ -3167,7 +3358,7 @@ void Foam::snappySnapDriver::reverseAttractMeshPoints // nearest point on pp // Get search domain and extend it a bit - treeBoundBox bb(pp.localPoints()); + treeBoundBox bb(ppLocalPoints); { // Random number generator. Bit dodgy since not exactly random ;-) Random rndGen(65431); @@ -3263,7 +3454,7 @@ void Foam::snappySnapDriver::reverseAttractMeshPoints indexedOctree<treeDataPoint> ppTree ( - treeDataPoint(pp.localPoints(), attractPoints), + treeDataPoint(ppLocalPoints, attractPoints), bb, // overall search domain 8, // maxLevel 10, // leafsize @@ -3360,10 +3551,7 @@ void Foam::snappySnapDriver::reverseAttractMeshPoints { if (pointAttr[featPointi] != -1) { - const point& featPt = features[feati].points() - [ - featPointi - ]; + const point& featPt = features[feati].points()[featPointi]; // Find nearest pp point pointIndexHit nearInfo = ppTree.findNearest @@ -3421,6 +3609,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges ( const label iter, const bool multiRegionFeatureSnap, + const bool strictRegionFeatureSnap, // special >=3 patch points handling const bool detectBaffles, const bool baffleFeaturePoints, @@ -3432,6 +3621,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestDisp, const vectorField& nearestNormal, @@ -3496,8 +3686,10 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges iter, featureCos, multiRegionFeatureSnap, + strictRegionFeatureSnap, // extra logic for points on >=3 patches pp, + ppLocalPoints, snapDist, // per point max distance and nearest surface nearestDisp, @@ -3544,6 +3736,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges featureCos, pp, + ppLocalPoints, snapDist, // Feature-point to pp point @@ -3575,6 +3768,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges iter, pp, + ppLocalPoints, snapDist, // Feature-point to pp point @@ -3621,7 +3815,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges forAll(patchConstraints, pointi) { - const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; const vector& attr = patchAttraction[pointi]; if (patchConstraints[pointi].first() == 2) @@ -3648,6 +3842,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges featureCos, pp, + ppLocalPoints, snapDist, pointFaceCentres, @@ -3674,6 +3869,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges featureCos, pp, + ppLocalPoints, snapDist, rawPatchAttraction, @@ -3695,6 +3891,7 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges iter, featureCos, pp, + ppLocalPoints, patchAttraction, patchConstraints ); @@ -3707,8 +3904,8 @@ void Foam::snappySnapDriver::featureAttractionUsingFeatureEdges ( meshRefiner_.mesh().time().path() / "patchAttraction_" + name(iter) + ".obj", - pp.localPoints(), - pp.localPoints() + patchAttraction + ppLocalPoints, + ppLocalPoints + patchAttraction ); } } @@ -3721,6 +3918,7 @@ void Foam::snappySnapDriver::preventFaceSqueeze const scalar featureCos, const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, const scalarField& snapDist, const vectorField& nearestAttraction, @@ -3762,7 +3960,7 @@ void Foam::snappySnapDriver::preventFaceSqueeze forAll(f, fp) { label pointi = f[fp]; - const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; if (patchConstraints[pointi].first() > 1) { @@ -3786,8 +3984,8 @@ void Foam::snappySnapDriver::preventFaceSqueeze scalar maxS = -1; forAll(f, fp) { - const point& pt = pp.localPoints()[f[fp]]; - const point& nextPt = pp.localPoints()[f.nextLabel(fp)]; + const point& pt = ppLocalPoints[f[fp]]; + const point& nextPt = ppLocalPoints[f.nextLabel(fp)]; scalar s = pt.distSqr(nextPt); if (s > maxS) @@ -3802,7 +4000,7 @@ void Foam::snappySnapDriver::preventFaceSqueeze // Reset attraction on pointi to nearest - const point& pt = pp.localPoints()[pointi]; + const point& pt = ppLocalPoints[pointi]; //Pout<< "** on triangle " << pp.faceCentres()[facei] // << " knocking out attraction to " << pointi @@ -3819,7 +4017,7 @@ void Foam::snappySnapDriver::preventFaceSqueeze } else { - scalar oldArea = f.mag(pp.localPoints()); + scalar oldArea = f.mag(ppLocalPoints); scalar newArea = singleF.mag(points); if (newArea < 0.1*oldArea) { @@ -3852,19 +4050,21 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature ( const snapParameters& snapParams, const bool alignMeshEdges, + const bool strictRegionFeatureSnap, // use patches const label iter, const scalar featureCos, const scalar featureAttract, const scalarField& snapDist, const vectorField& nearestDisp, const vectorField& nearestNormal, - motionSmoother& meshMover, + const indirectPrimitivePatch& pp, + const pointField& ppLocalPoints, vectorField& patchAttraction, List<pointConstraint>& patchConstraints, DynamicList<label>& splitFaces, - DynamicList<labelPair>& splits - + DynamicList<labelPair>& splits, + DynamicList<labelPair>& splitPatches ) const { if (dryRun_) @@ -3883,8 +4083,6 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature << " multi-patch features : " << multiRegionFeatureSnap << nl << endl; - const indirectPrimitivePatch& pp = meshMover.patch(); - const pointField& localPoints = pp.localPoints(); const fvMesh& mesh = meshRefiner_.mesh(); @@ -3935,6 +4133,7 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature ( iter, pp, + ppLocalPoints, faceSnapDist, faceDisp, faceSurfaceNormal, @@ -3952,7 +4151,7 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature ( iter, pp, - + ppLocalPoints, faceDisp, faceSurfaceNormal, faceSurfaceGlobalRegion, @@ -3976,10 +4175,10 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature // here. // Nearest feature - patchAttraction.setSize(localPoints.size()); + patchAttraction.setSize(ppLocalPoints.size()); patchAttraction = Zero; // Constraints at feature - patchConstraints.setSize(localPoints.size()); + patchConstraints.setSize(ppLocalPoints.size()); patchConstraints = pointConstraint(); if (implicitFeatureAttraction) @@ -3993,6 +4192,7 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature featureCos, pp, + ppLocalPoints, snapDist, nearestDisp, @@ -4030,6 +4230,7 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature ( iter, multiRegionFeatureSnap, + strictRegionFeatureSnap, // special logic for >=3 patches points? snapParams.detectBaffles(), snapParams.baffleFeaturePoints(), // all points on baffle edges @@ -4042,6 +4243,7 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature featureCos, pp, + ppLocalPoints, snapDist, nearestDisp, nearestNormal, @@ -4064,7 +4266,7 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature ); const scalar minAreaRatio = snapParams.minAreaRatio(); - Info<< "Experimental: introducing face splits to avoid rotating" + Info<< "Introducing face splits to avoid rotating" << " mesh edges. Splitting faces when" << nl << indent << "- angle not concave by more than " << snapParams.concaveAngle() << " degrees" << nl @@ -4078,14 +4280,18 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature concaveCos, minAreaRatio, pp, + ppLocalPoints, nearestDisp, nearestNormal, - + pointFacePatchID, // per point the connected patches. Is used + // to re-patch newly split faces patchAttraction, patchConstraints, + splitFaces, - splits + splits, + splitPatches ); if (debug) @@ -4102,6 +4308,7 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature featureCos, pp, + ppLocalPoints, snapDist, nearestDisp, @@ -4227,8 +4434,8 @@ Foam::vectorField Foam::snappySnapDriver::calcNearestSurfaceFeature ( mesh.time().path() / "tangPatchDispConstrained_" + name(iter) + ".obj", - pp.localPoints(), - pp.localPoints() + tangPatchDisp + ppLocalPoints, + ppLocalPoints + tangPatchDisp ); } diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files index acbb97b1f1450d9d049b405db23fa669546b5b29..f207200fabca45b1836e841a6a99cf70c771e626 100644 --- a/src/meshTools/Make/files +++ b/src/meshTools/Make/files @@ -217,6 +217,7 @@ $(pointSources)/searchableSurfaceToPoint/searchableSurfaceToPoint.C $(pointSources)/sphereToPoint/sphereToPoint.C $(pointSources)/surfaceToPoint/surfaceToPoint.C $(pointSources)/zoneToPoint/zoneToPoint.C +$(pointSources)/patchToPoint/patchToPoint.C faceZoneSources = topoSet/faceZoneSources $(faceZoneSources)/topoSetFaceZoneSource/topoSetFaceZoneSource.C diff --git a/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.C b/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.C index 8ff95a4c48ad93a1fb538572e1ba26e28baef00e..0e35e0275d63abe759897e924a98bbe01b69c41d 100644 --- a/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.C +++ b/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2019-2023 OpenCFD Ltd. + Copyright (C) 2019-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -36,7 +36,7 @@ License // refCast<const facePointPatch>(p).patch() template<class Type> -const Foam::polyPatch& +const Foam::polyPatch* Foam::uniformFixedValuePointPatchField<Type>::getPatch(const pointPatch& p) { const polyMesh& mesh = p.boundaryMesh().mesh()(); @@ -44,11 +44,12 @@ Foam::uniformFixedValuePointPatchField<Type>::getPatch(const pointPatch& p) if (patchi == -1) { - FatalErrorInFunction - << "Cannot use uniformFixedValue on patch " << p.name() - << " since there is no underlying mesh patch" << exit(FatalError); + return nullptr; + } + else + { + return &mesh.boundaryMesh()[patchi]; } - return mesh.boundaryMesh()[patchi]; } @@ -63,7 +64,8 @@ uniformFixedValuePointPatchField ) : fixedValuePointPatchField<Type>(p, iF), - refValueFunc_(nullptr) + refValueFunc_(nullptr), + refPointValueFunc_(nullptr) {} @@ -79,13 +81,26 @@ uniformFixedValuePointPatchField fixedValuePointPatchField<Type>(p, iF, dict, IOobjectOption::NO_READ), refValueFunc_ ( - PatchFunction1<Type>::New + this->getPatch(p) + ? PatchFunction1<Type>::New ( - this->getPatch(p), + *(this->getPatch(p)), "uniformValue", dict, false // generate point values ) + : nullptr + ), + refPointValueFunc_ + ( + this->getPatch(p) + ? nullptr + : Function1<Type>::New + ( + "uniformValue", + dict, + &this->internalField().db() + ) ) { if (!this->readValueEntry(dict)) @@ -110,7 +125,8 @@ uniformFixedValuePointPatchField ) : fixedValuePointPatchField<Type>(ptf, p, iF, mapper), - refValueFunc_(ptf.refValueFunc_.clone(this->getPatch(p))) + refValueFunc_(ptf.refValueFunc_.clone(*(this->getPatch(p)))), + refPointValueFunc_(ptf.refPointValueFunc_.clone()) { if (mapper.direct() && !mapper.hasUnmapped()) { @@ -133,7 +149,8 @@ uniformFixedValuePointPatchField ) : fixedValuePointPatchField<Type>(ptf), - refValueFunc_(ptf.refValueFunc_.clone(this->getPatch(this->patch()))) + refValueFunc_(ptf.refValueFunc_.clone(*(this->getPatch(this->patch())))), + refPointValueFunc_(ptf.refPointValueFunc_.clone()) {} @@ -146,7 +163,8 @@ uniformFixedValuePointPatchField ) : fixedValuePointPatchField<Type>(ptf, iF), - refValueFunc_(ptf.refValueFunc_.clone(this->getPatch(this->patch()))) + refValueFunc_(ptf.refValueFunc_.clone(*(this->getPatch(this->patch())))), + refPointValueFunc_(ptf.refPointValueFunc_.clone()) {} @@ -170,6 +188,14 @@ void Foam::uniformFixedValuePointPatchField<Type>::autoMap this->evaluate(); } } + if (refPointValueFunc_) + { + if (refPointValueFunc_().constant()) + { + // If mapper is not dependent on time we're ok to evaluate + this->evaluate(); + } + } } @@ -201,7 +227,14 @@ void Foam::uniformFixedValuePointPatchField<Type>::updateCoeffs() } const scalar t = this->db().time().timeOutputValue(); - valuePointPatchField<Type>::operator=(refValueFunc_->value(t)); + if (refValueFunc_) + { + valuePointPatchField<Type>::operator=(refValueFunc_->value(t)); + } + else + { + valuePointPatchField<Type>::operator=(refPointValueFunc_->value(t)); + } fixedValuePointPatchField<Type>::updateCoeffs(); } @@ -216,6 +249,10 @@ write(Ostream& os) const { refValueFunc_->writeData(os); } + if (refPointValueFunc_) + { + refPointValueFunc_->writeData(os); + } } diff --git a/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.H b/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.H index 9cf2a5c27efc5136ceb572db716db072ce76cf78..3312fb063c86dfcb71fa7a5cb8da8c67ec524e42 100644 --- a/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.H +++ b/src/meshTools/fields/pointPatchFields/uniformFixedValue/uniformFixedValuePointPatchField.H @@ -86,10 +86,13 @@ class uniformFixedValuePointPatchField //- Function providing the value autoPtr<PatchFunction1<Type>> refValueFunc_; + //- Function providing the value (if not on polyPatch) + autoPtr<Function1<Type>> refPointValueFunc_; + // Private Member Functions - static const polyPatch& getPatch(const pointPatch&); + static const polyPatch* getPatch(const pointPatch&); public: diff --git a/src/meshTools/topoSet/pointSources/patchToPoint/patchToPoint.C b/src/meshTools/topoSet/pointSources/patchToPoint/patchToPoint.C new file mode 100644 index 0000000000000000000000000000000000000000..ed7198f14940c6fd4e7c7c4b6237d341bf9041fc --- /dev/null +++ b/src/meshTools/topoSet/pointSources/patchToPoint/patchToPoint.C @@ -0,0 +1,185 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "patchToPoint.H" +#include "pointMesh.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(patchToPoint, 0); + addToRunTimeSelectionTable(topoSetSource, patchToPoint, word); + addToRunTimeSelectionTable(topoSetSource, patchToPoint, istream); + addToRunTimeSelectionTable(topoSetPointSource, patchToPoint, word); + addToRunTimeSelectionTable(topoSetPointSource, patchToPoint, istream); + addNamedToRunTimeSelectionTable + ( + topoSetPointSource, + patchToPoint, + word, + patch + ); + addNamedToRunTimeSelectionTable + ( + topoSetPointSource, + patchToPoint, + istream, + patch + ); +} + + +Foam::topoSetSource::addToUsageTable Foam::patchToPoint::usage_ +( + patchToPoint::typeName, + "\n Usage: patchToPoint patch\n\n" + " Select all points in the pointPatch." + " Note:accepts wildcards for patch.\n\n" +); + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::patchToPoint::combine(topoSet& set, const bool add) const +{ + const pointMesh& pMesh = pointMesh::New(mesh_, IOobject::READ_IF_PRESENT); + const pointBoundaryMesh& pbm = pMesh.boundary(); + + labelList patchIDs + ( + pbm.indices + ( + selectedPatches_, + true // useGroups + ) + ); + + + for (const label patchi : patchIDs) + { + const pointPatch& pp = pbm[patchi]; + + if (verbose_) + { + Info<< " Found matching patch " << pp.name() << " with " + << returnReduce(pp.size(), sumOp<label>()) << " points" << endl; + } + + for (const label pointi : pp.meshPoints()) + { + addOrDelete(set, pointi, add); + } + } + + if (patchIDs.empty()) + { + WarningInFunction + << "Cannot find any patches matching " + << flatOutput(selectedPatches_) << nl + //<< "Valid names: " << flatOutput(mesh_.boundaryMesh().names()) + << endl; + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::patchToPoint::patchToPoint +( + const polyMesh& mesh, + const wordRe& patchName +) +: + topoSetPointSource(mesh), + selectedPatches_(one{}, patchName) +{} + + +Foam::patchToPoint::patchToPoint +( + const polyMesh& mesh, + const dictionary& dict +) +: + topoSetPointSource(mesh), + selectedPatches_() +{ + // Look for 'patches' and 'patch', but accept 'name' as well + if (!dict.readIfPresent("patches", selectedPatches_)) + { + selectedPatches_.resize(1); + selectedPatches_.front() = + dict.getCompat<wordRe>("patch", {{"name", 1806}}); + } +} + + +Foam::patchToPoint::patchToPoint +( + const polyMesh& mesh, + Istream& is +) +: + topoSetPointSource(mesh), + selectedPatches_(one{}, wordRe(checkIs(is))) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::patchToPoint::applyToSet +( + const topoSetSource::setAction action, + topoSet& set +) const +{ + if (action == topoSetSource::ADD || action == topoSetSource::NEW) + { + if (verbose_) + { + Info<< " Adding all points of patches: " + << flatOutput(selectedPatches_) << " ..." << endl; + } + + combine(set, true); + } + else if (action == topoSetSource::SUBTRACT) + { + if (verbose_) + { + Info<< " Removing all points of patches: " + << flatOutput(selectedPatches_) << " ..." << endl; + } + + combine(set, false); + } +} + + +// ************************************************************************* // diff --git a/src/meshTools/topoSet/pointSources/patchToPoint/patchToPoint.H b/src/meshTools/topoSet/pointSources/patchToPoint/patchToPoint.H new file mode 100644 index 0000000000000000000000000000000000000000..b1ed3913775fdc6b1e238a3b038b60d0c95e62e0 --- /dev/null +++ b/src/meshTools/topoSet/pointSources/patchToPoint/patchToPoint.H @@ -0,0 +1,174 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2024 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::patchToPoint + +Description + A \c topoSetPointSource to select points associated with given patch(es). + + Operands: + \table + Operand | Type | Location + output | pointSet | $FOAM_CASE/constant/polyMesh/sets/\<set\> + \endtable + +Usage + Minimal example by using \c system/topoSetDict.actions: + \verbatim + { + // Mandatory (inherited) entries + name <name>; + type pointSet; + action <action>; + + // Mandatory entries + source patchToPoint; + + // Conditional mandatory entries + // Select either of the below + + // Option-1 + patches + ( + <patchName1> + <patchName2> + ... + ); + + // Option-2 + patch <patchName>; + } + \endverbatim + + where the entries mean: + \table + Property | Description | Type | Req'd | Dflt + name | Name of pointSet | word | yes | - + type | Type name: pointSet | word | yes | - + action | Action applied on points - see below | word | yes | - + source | Source name: patchToPoint | word | yes | - + \endtable + + Options for the \c action entry: + \verbatim + new | Create a new pointSet from selected points + add | Add selected points into this pointSet + subtract | Remove selected points from this pointSet + \endverbatim + + Options for the conditional mandatory entries: + \verbatim + Entry | Description | Type | Req'd | Dflt + patches | Names of patches | wordList | cond'l | - + patch | Name of patch | word | cond'l | - + \endverbatim + +Note + The order of precedence among the conditional mandatory entries from the + highest to the lowest is \c patches, and \c patch. + +See also + - Foam::patchToFace + +SourceFiles + patchToPoint.C + +\*---------------------------------------------------------------------------*/ + +#ifndef patchToPoint_H +#define patchToPoint_H + +#include "topoSetPointSource.H" +#include "wordRes.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class patchToPoint Declaration +\*---------------------------------------------------------------------------*/ + +class patchToPoint +: + public topoSetPointSource +{ + // Private Data + + //- Add usage string + static addToUsageTable usage_; + + //- Matcher for patches + wordRes selectedPatches_; + + + // Private Member Functions + + void combine(topoSet& set, const bool add) const; + + +public: + + //- Runtime type information + TypeName("patchToPoint"); + + + // Constructors + + //- Construct from components + patchToPoint(const polyMesh& mesh, const wordRe& patchName); + + //- Construct from dictionary + patchToPoint(const polyMesh& mesh, const dictionary& dict); + + //- Construct from Istream + patchToPoint(const polyMesh& mesh, Istream& is); + + + //- Destructor + virtual ~patchToPoint() = default; + + + // Member Functions + + virtual void applyToSet + ( + const topoSetSource::setAction action, + topoSet& set + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/parallel/reconstruct/reconstruct/processorMeshes.C b/src/parallel/reconstruct/reconstruct/processorMeshes.C index beaa2ea85888f3cb82e634f93328bf12881275e5..22c07913b261d0ca55db20b4ef6890de7ed27eee 100644 --- a/src/parallel/reconstruct/reconstruct/processorMeshes.C +++ b/src/parallel/reconstruct/reconstruct/processorMeshes.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2023 OpenCFD Ltd. + Copyright (C) 2016-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -31,6 +31,7 @@ License #include "IndirectList.H" #include "primitiveMesh.H" #include "OSspecific.H" +#include "pointMesh.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -46,6 +47,9 @@ void Foam::processorMeshes::read() { // Make sure to clear (and hence unregister) any previously loaded meshes // and fields + pBoundaryProcAddressing_.free(); + pMeshes_.free(); + boundaryProcAddressing_.free(); cellProcAddressing_.free(); faceProcAddressing_.free(); @@ -92,6 +96,39 @@ void Foam::processorMeshes::read() // boundaryProcAddressing (polyMesh) ioAddr.rename("boundaryProcAddressing"); boundaryProcAddressing_.emplace_set(proci, ioAddr); + + + // pointMesh + // ~~~~~~~~~ + + pMeshes_.set + ( + proci, + new pointMesh + ( + meshes_[proci], + IOobject::READ_IF_PRESENT + ) + ); + + pBoundaryProcAddressing_.set + ( + proci, + autoPtr<labelIOList>::New + ( + IOobject + ( + "boundaryProcAddressing", + meshes_[proci].facesInstance(), + polyMesh::meshSubDir/pointMesh::meshSubDir, + pMeshes_[proci].thisDb(), + IOobject::READ_IF_PRESENT, + IOobject::NO_WRITE, + IOobject::NO_REGISTER + ), + boundaryProcAddressing_[proci] + ) + ); } } @@ -110,7 +147,9 @@ Foam::processorMeshes::processorMeshes pointProcAddressing_(databases.size()), faceProcAddressing_(databases.size()), cellProcAddressing_(databases.size()), - boundaryProcAddressing_(databases.size()) + boundaryProcAddressing_(databases.size()), + pMeshes_(databases.size()), + pBoundaryProcAddressing_(databases.size()) { read(); } @@ -250,6 +289,26 @@ void Foam::processorMeshes::removeFiles(const polyMesh& mesh) // boundaryProcAddressing io.rename("boundaryProcAddressing"); fileHandler().rm(fileHandler().filePath(io.objectPath())); + + + + // pointMesh + // ~~~~~~~~~ + + IOobject pointIO + ( + "boundary", + mesh.facesInstance(), + polyMesh::meshSubDir/pointMesh::meshSubDir, + mesh.thisDb() + ); + + // pointMesh/boundary + fileHandler().rm(fileHandler().filePath(pointIO.objectPath())); + + // boundaryProcAddressing + io.rename("boundaryProcAddressing"); + fileHandler().rm(fileHandler().filePath(pointIO.objectPath())); } diff --git a/src/parallel/reconstruct/reconstruct/processorMeshes.H b/src/parallel/reconstruct/reconstruct/processorMeshes.H index 9272681ba1ba625ea1110f29205f2352cc700b4c..d8da977c737976b9a105d5e5aeb33e67c66a5e1e 100644 --- a/src/parallel/reconstruct/reconstruct/processorMeshes.H +++ b/src/parallel/reconstruct/reconstruct/processorMeshes.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2014 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016,2024 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -77,6 +77,15 @@ class processorMeshes PtrList<labelIOList> boundaryProcAddressing_; + // pointMesh + + //- List of processor meshes + PtrList<pointMesh> pMeshes_; + + //- List of processor boundary addressing lists for pointMeshes + PtrList<labelIOList> pBoundaryProcAddressing_; + + // Private Member Functions //- Read all meshes @@ -140,6 +149,20 @@ public: } + // pointMesh + + const PtrList<pointMesh>& pointMeshes() const noexcept + { + return pMeshes_; + } + + const PtrList<labelIOList>& pointMeshBoundaryProcAddressing() + const noexcept + { + return pBoundaryProcAddressing_; + } + + //- Helper: remove all procAddressing files from mesh instance static void removeFiles(const polyMesh& mesh); }; diff --git a/tutorials/mesh/blockMesh/pipe/0.orig/pointDisplacement b/tutorials/mesh/blockMesh/pipe/0.orig/pointDisplacement new file mode 100644 index 0000000000000000000000000000000000000000..1fc81f71beb2ece674cebba9c302827eefed0699 --- /dev/null +++ b/tutorials/mesh/blockMesh/pipe/0.orig/pointDisplacement @@ -0,0 +1,78 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 2309 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + arch "LSB;label=32;scalar=64"; + class pointVectorField; + location "0"; + object pointDisplacement; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 0 0 0 0 0]; + +internalField uniform (0 0 0); + + +// Some macros +__surfaceSlipDisplacement +{ + type surfaceSlipDisplacement; + value uniform (0 0 0); + geometry + { + box + { + type triSurfaceMesh; + file blockMesh.obj; + } + } + projectMode nearest; +} + +__edgeSlipDisplacement +{ + type edgeSlipDisplacement; + file "blockMesh.eMesh"; + // Underrelax the displacement on edges since conflicts with + // smoothing. TBD. + velocity (1 1 1); +} + + +boundaryField +{ + // Attract to feature lines + wallsEdges + { + ${__edgeSlipDisplacement}; + } + + // Attract to feature lines + boundaryEdges + { + ${__edgeSlipDisplacement}; + } + + // Attract to feature lines + sideEdges + { + ${__edgeSlipDisplacement}; + } + + // Default is to attract to surface + ".*" + { + ${__surfaceSlipDisplacement}; + } +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/pipe/Allclean b/tutorials/mesh/blockMesh/pipe/Allclean index 64435d02b1407ff6f433978ca54fecadc70675c1..09746eab8109993bfc6e213e321387ad6ed349fc 100755 --- a/tutorials/mesh/blockMesh/pipe/Allclean +++ b/tutorials/mesh/blockMesh/pipe/Allclean @@ -6,5 +6,11 @@ cd "${0%/*}" || exit # Run from this directory cleanCase0 rm -rf constant/geometry +rm -rf constant/extendedFeatureEdgeMesh +rm -rf constant/geometry + +#- From pointMesh generation +rm -rf constant/pointMesh +rm -rf constant/triSurface #------------------------------------------------------------------------------ diff --git a/tutorials/mesh/blockMesh/pipe/Allrun b/tutorials/mesh/blockMesh/pipe/Allrun index 9c48a0769cecbc408f32f23493ffbd00aafe3373..bc3ee363bbed60a8b485136ece9ea41ea9ed15f2 100755 --- a/tutorials/mesh/blockMesh/pipe/Allrun +++ b/tutorials/mesh/blockMesh/pipe/Allrun @@ -11,8 +11,29 @@ cp -f \ runApplication blockMesh +# See if we can improve the mesh with a bit of smoothing (whilst freezing +# the features) +# - feature-edge attraction conflicts with mesh smoothing so faces with +# three vertices on feature edge get distorted. + +#- Analyse mesh and +# - generate pointMesh with additional feature patches +# (in constant/pointMesh/boundary). +# - write .obj file with outside of mesh +mkdir -p constant/triSurface +runApplication surfaceMeshExtract -featureAngle 50 \ + constant/triSurface/blockMesh.obj + +#- Extract features from surface (original of blockMesh). Writes .eMesh. +runApplication surfaceFeatureExtract + +#- Set the initial field restore0Dir -runApplication $(getApplication) +#- Run mesh smoother +runApplication moveDynamicMesh + +#- Check mesh, generate postprocessing fields +runApplication checkMesh -writeFields '(nonOrthoAngle)' #------------------------------------------------------------------------------ diff --git a/tutorials/mesh/blockMesh/pipe/README.txt b/tutorials/mesh/blockMesh/pipe/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4e7d6df7abedfc8d9c6a9cc1f31c3ae6f775b34 --- /dev/null +++ b/tutorials/mesh/blockMesh/pipe/README.txt @@ -0,0 +1,12 @@ +Demos: + +- blockMesh: + - snapping to surface + - surface defined by extrusion of line + +- surfaceMeshExtract + - generation of additional pointPatches to handle features + +- moveDynamicMesh + - point-based smoothers + - feature-attraction through boundary conditions diff --git a/tutorials/mesh/blockMesh/pipe/constant/dynamicMeshDict b/tutorials/mesh/blockMesh/pipe/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..65c6223a7f783b7f6aadf5c4299ad312454263a4 --- /dev/null +++ b/tutorials/mesh/blockMesh/pipe/constant/dynamicMeshDict @@ -0,0 +1,29 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicMotionSolverFvMesh; + +motionSolverLibs (fvMotionSolvers); + +motionSolver displacementPointSmoothing; +displacementPointSmoothingCoeffs +{ + pointSmoother geometricElementTransform; + transformationParameter 0.667; + nPointSmootherIter 1; +} + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/pipe/system/controlDict b/tutorials/mesh/blockMesh/pipe/system/controlDict index b98630e1a02dc49fa726353aea72d02fdbde16ff..a210ebbd6fb7fbcf42ac72f22d0e577b8f1234ff 100644 --- a/tutorials/mesh/blockMesh/pipe/system/controlDict +++ b/tutorials/mesh/blockMesh/pipe/system/controlDict @@ -14,17 +14,7 @@ FoamFile } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -libs (blockMesh); - -DebugSwitches -{ - //project 1; - //searchableExtrudedCircle 1; - //projectCurve 1; - solution 1; -} - -application simpleFoam; +application moveDynamicMesh; startFrom startTime; @@ -32,7 +22,7 @@ startTime 0; stopAt endTime; -endTime 100; +endTime 10; deltaT 1; diff --git a/tutorials/mesh/blockMesh/pipe/system/surfaceFeatureExtractDict b/tutorials/mesh/blockMesh/pipe/system/surfaceFeatureExtractDict new file mode 100644 index 0000000000000000000000000000000000000000..192e95601eafcd7802c3089e9dca24f19e76bf75 --- /dev/null +++ b/tutorials/mesh/blockMesh/pipe/system/surfaceFeatureExtractDict @@ -0,0 +1,33 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object surfaceFeatureExtractDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +blockMesh.obj +{ + // How to obtain raw features (extractFromFile || extractFromSurface) + extractionMethod extractFromSurface; + + // Mark edges whose adjacent surface normals are at an angle less + // than includedAngle as features + // - 0 : selects no edges + // - 180: selects all edges + includedAngle 130; + + // Write features to obj format for postprocessing + writeObj yes; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/0.orig/cellDisplacement b/tutorials/mesh/blockMesh/sphere7/0.orig/cellDisplacement new file mode 100644 index 0000000000000000000000000000000000000000..1322070750e8de199d163e12a93d04826ea4e375 --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/0.orig/cellDisplacement @@ -0,0 +1,58 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + arch "LSB;label=32;scalar=64"; + class volVectorField; + location "1"; + object cellDisplacement; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 0 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + minX + { + type cellMotion; + value uniform (0 0 0); + } + maxX + { + type cellMotion; + value uniform (0 0 0); + } + minY + { + type cellMotion; + value uniform (0 0 0); + } + maxY + { + type cellMotion; + value uniform (0 0 0); + } + minZ + { + type cellMotion; + value uniform (0 0 0); + } + maxZ + { + type cellMotion; + value uniform (0 0 0); + } +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/0.orig/pointDisplacement b/tutorials/mesh/blockMesh/sphere7/0.orig/pointDisplacement new file mode 100644 index 0000000000000000000000000000000000000000..43cfe34877938e5555012a2d5f80f1fc3d980edb --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/0.orig/pointDisplacement @@ -0,0 +1,81 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 2309 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + arch "LSB;label=32;scalar=64"; + class pointVectorField; + location "0"; + object pointDisplacement; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 0 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + minX + { + type surfaceSlipDisplacement; + value uniform (0 0 0); + velocity (0.1 0.1 0.1); + //velocity (100 100 100); + geometry + { + box + { + type triSurfaceMesh; + file box222.obj; + } + } + projectMode nearest; + } + maxX + { + $minX + } + minY + { + $minX + } + maxY + { + $minX + } + minZ + { + $minX + } + maxZ + { + $minX + } + boundaryEdges + { + type edgeSlipDisplacement; + file "box222.eMesh"; + //file "box222.extendedFeatureEdgeMesh"; + //- Underrelax motion by limiting displacement velocity + velocity (0.1 0.1 0.1); + //velocity (100 100 100); + } + boundaryPoints + { + type pointAttraction; + file "box222.eMesh"; + //- Underrelax motion by limiting displacement velocity + velocity (0.1 0.1 0.1); + //velocity (100 100 100); + } +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/Allclean b/tutorials/mesh/blockMesh/sphere7/Allclean index d4f5975bc81100693691ef5bc2e8e027d5231e53..0d325ec274bd399cd9863381be036289c564420d 100755 --- a/tutorials/mesh/blockMesh/sphere7/Allclean +++ b/tutorials/mesh/blockMesh/sphere7/Allclean @@ -5,6 +5,14 @@ cd "${0%/*}" || exit # Run from this directory cleanCase0 -rm -rf constant +rm -rf constant/extendedFeatureEdgeMesh + +#- From pointMesh generation +rm -rf constant/pointMesh +rm -f constant/triSurface/blockMesh.obj +rm -f constant/triSurface/outside.obj + +#- From surfaceFeatureExtract +rm -f constant/triSurface/box222.eMesh #------------------------------------------------------------------------------ diff --git a/tutorials/mesh/blockMesh/sphere7/Allrun b/tutorials/mesh/blockMesh/sphere7/Allrun index c0ee92beedf30f397cf3c31f146983b44bf406d5..2da43c1d7fe8478a71dd401c154c724cbf813c0e 100755 --- a/tutorials/mesh/blockMesh/sphere7/Allrun +++ b/tutorials/mesh/blockMesh/sphere7/Allrun @@ -3,6 +3,44 @@ cd "${0%/*}" || exit # Run from this directory . ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions #------------------------------------------------------------------------------ +#- Run blockMesh with projection runApplication blockMesh +# Optional + + ##- Extrude very thin cells to make it harder. Note: requires a + ##- pointSmoother first before doing the displacementLaplacian + #runApplication extrudeMesh + + #- Refine some cells + runApplication topoSet + runApplication refineHexMesh c0 -overwrite + + +#- Generate pointMesh with additional feature patches +# (in constant/pointMesh/boundary). Extracted outside of mesh is not used. +runApplication surfaceMeshExtract -featureAngle 45 \ + constant/triSurface/blockMesh.obj + +#- Set the initial field +restore0Dir + +#- TBD. move triSurfaces to resources +#mkdir -p constant/triSurface +#cp -f \ +# "$FOAM_TUTORIALS"/resources/geometry/box222.obj \ +# constant/triSurface/ + +#- Extract features from surface. Writes .eMesh +runApplication surfaceFeatureExtract + +##- Morph mesh to the surface (.obj file) and feature-edges (.eMesh file) +#runApplication moveDynamicMesh + +runApplication decomposePar + +runParallel moveDynamicMesh + +runApplication reconstructPar + #------------------------------------------------------------------------------ diff --git a/tutorials/mesh/blockMesh/sphere7/constant/dynamicMeshDict b/tutorials/mesh/blockMesh/sphere7/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..6e89b3d992a9e3df6af0ee032a12ec6855634041 --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/constant/dynamicMeshDict @@ -0,0 +1,53 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicMotionSolverFvMesh; + +motionSolverLibs (fvMotionSolvers); + +//motionSolver displacementPointSmoothing; +//displacementPointSmoothingCoeffs +//{ +// //pointSmoother geometricElementTransform; +// //transformationParameter 0.667; +// pointSmoother laplacian; +// +// nPointSmootherIter 10; +// +// //relaxationFactors (1); +// //meshQuality {} +// //moveInternalFaces true; +//} + +motionSolver multiDisplacement; +solvers +{ + displacementLaplacian + { + motionSolver displacementLaplacian; + diffusivity uniform; + } + + displacementPointSmoothing + { + motionSolver displacementPointSmoothing; + pointSmoother laplacian; + nPointSmootherIter 10; + } +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/constant/triSurface/box222.obj b/tutorials/mesh/blockMesh/sphere7/constant/triSurface/box222.obj new file mode 100644 index 0000000000000000000000000000000000000000..f1aceeca48a77cbe62aea577f651b129de3fa96d --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/constant/triSurface/box222.obj @@ -0,0 +1,79 @@ +# Generated by Visualization Toolkit +v -1 -1 -1 +v -1 -1 1 +v -1 1 -1 +v -1 1 1 +v 1 -1 -1 +v 1 -1 1 +v 1 1 -1 +v 1 1 1 +v -1 -1 -1 +v -1 -1 1 +v 1 -1 -1 +v 1 -1 1 +v -1 1 -1 +v -1 1 1 +v 1 1 -1 +v 1 1 1 +v -1 -1 -1 +v 1 -1 -1 +v -1 1 -1 +v 1 1 -1 +v -1 -1 1 +v 1 -1 1 +v -1 1 1 +v 1 1 1 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vt -0.5 -0.5 +vt 1.5 -0.5 +vt -0.5 1.5 +vt 1.5 1.5 +vt 0.5 -0.5 +vt -1.5 -0.5 +vt 0.5 1.5 +vt -1.5 1.5 +vt 0.5 0.5 +vt 0.5 -1.5 +vt -1.5 0.5 +vt -1.5 -1.5 +vt -0.5 0.5 +vt -0.5 -1.5 +vt 1.5 0.5 +vt 1.5 -1.5 +vt 0.5 -0.5 +vt -1.5 -0.5 +vt 0.5 1.5 +vt -1.5 1.5 +vt -0.5 -0.5 +vt 1.5 -0.5 +vt -0.5 1.5 +vt 1.5 1.5 +f 1/1/1 2/2/2 4/4/4 3/3/3 +f 5/5/5 7/7/7 8/8/8 6/6/6 +f 9/9/9 11/11/11 12/12/12 10/10/10 +f 13/13/13 14/14/14 16/16/16 15/15/15 +f 17/17/17 19/19/19 20/20/20 18/18/18 +f 21/21/21 22/22/22 24/24/24 23/23/23 diff --git a/tutorials/mesh/blockMesh/sphere7/constant/triSurface/box422.obj b/tutorials/mesh/blockMesh/sphere7/constant/triSurface/box422.obj new file mode 100644 index 0000000000000000000000000000000000000000..f77a6fc86c684089966ad6b8b3b4de9ad0c8448a --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/constant/triSurface/box422.obj @@ -0,0 +1,79 @@ +# Generated by Visualization Toolkit +v -2 -1 -1 +v -2 -1 1 +v -2 1 -1 +v -2 1 1 +v 2 -1 -1 +v 2 -1 1 +v 2 1 -1 +v 2 1 1 +v -2 -1 -1 +v -2 -1 1 +v 2 -1 -1 +v 2 -1 1 +v -2 1 -1 +v -2 1 1 +v 2 1 -1 +v 2 1 1 +v -2 -1 -1 +v 2 -1 -1 +v -2 1 -1 +v 2 1 -1 +v -2 -1 1 +v 2 -1 1 +v -2 1 1 +v 2 1 1 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vt -0.5 -0.5 +vt 1.5 -0.5 +vt -0.5 1.5 +vt 1.5 1.5 +vt 0.5 -0.5 +vt -1.5 -0.5 +vt 0.5 1.5 +vt -1.5 1.5 +vt 1.5 0.5 +vt 1.5 -1.5 +vt -2.5 0.5 +vt -2.5 -1.5 +vt -1.5 0.5 +vt -1.5 -1.5 +vt 2.5 0.5 +vt 2.5 -1.5 +vt 1.5 -0.5 +vt -2.5 -0.5 +vt 1.5 1.5 +vt -2.5 1.5 +vt -1.5 -0.5 +vt 2.5 -0.5 +vt -1.5 1.5 +vt 2.5 1.5 +f 1/1/1 2/2/2 4/4/4 3/3/3 +f 5/5/5 7/7/7 8/8/8 6/6/6 +f 9/9/9 11/11/11 12/12/12 10/10/10 +f 13/13/13 14/14/14 16/16/16 15/15/15 +f 17/17/17 19/19/19 20/20/20 18/18/18 +f 21/21/21 22/22/22 24/24/24 23/23/23 diff --git a/tutorials/mesh/blockMesh/sphere7/system/blockMeshDict b/tutorials/mesh/blockMesh/sphere7/system/blockMeshDict index 66b82df1e9169c31b61ce88597642932dfc87f36..a58c78cadeb0357965154cfebbc02b44ad023f55 100644 --- a/tutorials/mesh/blockMesh/sphere7/system/blockMeshDict +++ b/tutorials/mesh/blockMesh/sphere7/system/blockMeshDict @@ -127,16 +127,56 @@ faces boundary ( - walls + minX { - type wall; + type patch; faces ( (1 0) // block 1: x-min + ); + } + + maxX + { + type patch; + faces + ( (2 1) // block 2: x-max + ); + } + + minY + { + type patch; + faces + ( (3 2) // block 3: y-min + ); + } + + maxY + { + type patch; + faces + ( (4 3) // block 4: y-max + ); + } + + minZ + { + type patch; + faces + ( (5 4) // block 5: z-min + ); + } + + maxZ + { + type patch; + faces + ( (6 5) // block 6: z-max ); } diff --git a/tutorials/mesh/blockMesh/sphere7/system/controlDict b/tutorials/mesh/blockMesh/sphere7/system/controlDict index 468b34946173297764ef3b800f2a6af7bd0e757f..ab5a65c8533048f74e6aa587126223244389fd17 100644 --- a/tutorials/mesh/blockMesh/sphere7/system/controlDict +++ b/tutorials/mesh/blockMesh/sphere7/system/controlDict @@ -14,6 +14,11 @@ FoamFile } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +DebugSwitches +{ + pointBoundaryMesh 1; +} + application blockMesh; startFrom startTime; @@ -22,9 +27,9 @@ startTime 0; stopAt endTime; -endTime 0; +endTime 20; -deltaT 0; +deltaT 1; writeControl timeStep; diff --git a/tutorials/mesh/blockMesh/sphere7/system/decomposeParDict b/tutorials/mesh/blockMesh/sphere7/system/decomposeParDict new file mode 100644 index 0000000000000000000000000000000000000000..a3282112ad11ad20a8a9873519a3900c94de32d6 --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/system/decomposeParDict @@ -0,0 +1,24 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + note "mesh decomposition control dictionary"; + object decomposeParDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- The total number of domains (mandatory) +numberOfSubdomains 2; + +//- The decomposition method (mandatory) +method scotch; + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/system/extrudeMeshDict b/tutorials/mesh/blockMesh/sphere7/system/extrudeMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..78d7de718a525a5843e81c2065a10b49bc5056f5 --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/system/extrudeMeshDict @@ -0,0 +1,55 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object extrudeMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// What to extrude: +// patch : from patch of another case ('sourceCase') +// mesh : as above but with original case included +// surface : from externally read surface + +constructFrom mesh; + +// If construct from patch/mesh: +sourceCase "<case>"; + +// and one of sourcePatches or sourceFaceZones (but not both): +//sourceFaceZones (someFacesZone); +sourcePatches (".*"); + +// Flip surface normals before usage. Valid only for extrude from surface or +// patch. +flipNormals false; + +//- Linear extrusion in point-normal direction +extrudeModel linearNormal; + +nLayers 1; + +expansionRatio 1.0; + +linearNormalCoeffs +{ + thickness 1e-6; +} + +// Do front and back need to be merged? Usually only makes sense for 360 +// degree wedges. +mergeFaces false; + +// Merge small edges. Fraction of bounding box. +mergeTol 0; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/tutorials/mesh/blockMesh/sphere7/system/fvSchemes b/tutorials/mesh/blockMesh/sphere7/system/fvSchemes index a04c1fb001bdd5169eaba84849ee90a2f668ea04..5b5385b05209a42c09e8018e35a78b5ad4d8bd1b 100644 --- a/tutorials/mesh/blockMesh/sphere7/system/fvSchemes +++ b/tutorials/mesh/blockMesh/sphere7/system/fvSchemes @@ -18,19 +18,27 @@ ddtSchemes {} gradSchemes -{} +{ + default Gauss linear; +} divSchemes {} laplacianSchemes -{} +{ + default Gauss linear corrected; +} interpolationSchemes -{} +{ + default linear; +} snGradSchemes -{} +{ + default corrected; +} // ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/system/fvSolution b/tutorials/mesh/blockMesh/sphere7/system/fvSolution index 2999073b91ebce15d75792e9bd64bd252e102e77..9283a875542a0e15ffbb62133e774f9c624654d5 100644 --- a/tutorials/mesh/blockMesh/sphere7/system/fvSolution +++ b/tutorials/mesh/blockMesh/sphere7/system/fvSolution @@ -14,5 +14,20 @@ FoamFile } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +solvers +{ + "cellDisplacement.*" + { + solver GAMG; + tolerance 1e-08; + relTol 0; + smoother GaussSeidel; + } +} + + +PIMPLE +{} + // ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/system/surfaceFeatureExtractDict b/tutorials/mesh/blockMesh/sphere7/system/surfaceFeatureExtractDict new file mode 100644 index 0000000000000000000000000000000000000000..9039408675c88bdcb9ca01631b684db47c22448a --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/system/surfaceFeatureExtractDict @@ -0,0 +1,33 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object surfaceFeatureExtractDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +box222.obj +{ + // How to obtain raw features (extractFromFile || extractFromSurface) + extractionMethod extractFromSurface; + + // Mark edges whose adjacent surface normals are at an angle less + // than includedAngle as features + // - 0 : selects no edges + // - 180: selects all edges + includedAngle 135; + + // Write features to obj format for postprocessing + writeObj yes; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/blockMesh/sphere7/system/topoSetDict b/tutorials/mesh/blockMesh/sphere7/system/topoSetDict new file mode 100644 index 0000000000000000000000000000000000000000..fa7fef4902005a115811ac8a6f23affe917adfae --- /dev/null +++ b/tutorials/mesh/blockMesh/sphere7/system/topoSetDict @@ -0,0 +1,47 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object topoSetDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +actions +( + { + name c0; + type cellSet; + action new; + source boundaryToCell; + } + { + name c0; + type cellSet; + action subset; + source boxToCell; + sourceInfo + { + box (-100 -100 -100) (0 100 100); + } + } + { + name c0; + type cellSet; + action add; + source boxToCell; + sourceInfo + { + box (-0.3 -0.3 -0.3) (0 0 0); + } + } +); + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/badMove/0/pointDisplacement b/tutorials/mesh/moveDynamicMesh/badMove/0/pointDisplacement new file mode 100644 index 0000000000000000000000000000000000000000..2dd44c19be6e956ffe12f69e2da0a1edafc392e1 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/0/pointDisplacement @@ -0,0 +1,62 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 2309 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + arch "LSB;label=32;scalar=64"; + class pointVectorField; + location "0"; + object pointDisplacement; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 0 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + minX + { + type slip; + } + maxX + { + $minX + } + minY + { + $minX + } + maxY + { + $minX + } + minZ + { + $minX + } + maxZ + { + $minX + } + boundaryEdges + { + type uniformFixedValue; + uniformValue table + ( + ( 0.0 (0 0 0)) + ( 1.0 (1.0 -1.0 0)) + //(10.0 (0 0 0)) + ); + } +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/badMove/Allclean b/tutorials/mesh/moveDynamicMesh/badMove/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..5ef46f9d35db1f707b94b73f1b5c3903b6e47332 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/Allclean @@ -0,0 +1,17 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +cleanCase + +rm -rf constant/extendedFeatureEdgeMesh + +#- From pointMesh generation +rm -rf constant/pointMesh +rm -f constant/triSurface/blockMesh.obj + +#- From surfaceFeatureExtract +rm -f constant/triSurface/box222.eMesh + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/moveDynamicMesh/badMove/Allrun b/tutorials/mesh/moveDynamicMesh/badMove/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..e48b35c7fa6a6a3744905afc6286da061dd9b5cd --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/Allrun @@ -0,0 +1,23 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + +#- Generate mesh +runApplication blockMesh + +runApplication surfaceMeshExtract \ + -featureAngle 45 \ + -patches '(minX maxY)' \ + constant/triSurface/blockMesh.obj + +#- For postprocessing: extract new pointPatches as vtk files +setSet <<EOF +pointSet p0 new patchToPoint boundaryEdges +EOF + +#- Morph mesh to the surface (.obj file) and feature-edges (.eMesh file) +#- Note: needs point-based motion solver +runApplication moveDynamicMesh + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/moveDynamicMesh/badMove/README.txt b/tutorials/mesh/moveDynamicMesh/badMove/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..c357006107b3d8eeae1b2feadc5df8e9bee5e0f5 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/README.txt @@ -0,0 +1 @@ +Testing relaxation of mesh motion diff --git a/tutorials/mesh/moveDynamicMesh/badMove/constant/dynamicMeshDict b/tutorials/mesh/moveDynamicMesh/badMove/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..d4d20613a9d7d57840c106ed64272b335bd162a3 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/constant/dynamicMeshDict @@ -0,0 +1,39 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicMotionSolverFvMesh; + +// For point-bcs +motionSolverLibs (fvMotionSolvers); + +motionSolver displacementPointSmoothing; +displacementPointSmoothingCoeffs +{ + // Use geometricElementTransform to maintain relative sizes + //pointSmoother geometricElementTransform; + //transformationParameter 0.667; + //nPointSmootherIter 10; + + pointSmoother laplacian; + nPointSmootherIter 10; + relaxationFactors (1.0 0.8 0.6 0.4 0.2 0.0); + meshQuality + { + #includeEtc "caseDicts/meshQualityDict" + } +} + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/badMove/system/blockMeshDict b/tutorials/mesh/moveDynamicMesh/badMove/system/blockMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..239ef4d94e125c4c392cf17bd155511ce1df11c6 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/system/blockMeshDict @@ -0,0 +1,95 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +vertices +( + // Inner block + (-2 -2 -2) + ( 2 -2 -2) + ( 2 2 -2) + (-2 2 -2) + (-2 -2 2) + ( 2 -2 2) + ( 2 2 2) + (-2 2 2) +); + +blocks +( + hex (0 1 2 3 4 5 6 7) (5 5 4) grading (1 1 1) // Inner block +); + +boundary +( + minX + { + type patch; + faces + ( + (0 0) // block 0: x-min + ); + } + + maxX + { + type patch; + faces + ( + (0 1) // block 0: x-max + ); + } + + minY + { + type patch; + faces + ( + (0 2) // block 0: y-min + ); + } + + maxY + { + type patch; + faces + ( + (0 3) // block 0: y-max + ); + } + + minZ + { + type patch; + faces + ( + (0 4) // block 0: z-min + ); + } + + maxZ + { + type patch; + faces + ( + (0 5) // block 0: z-max + ); + } +); + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/badMove/system/controlDict b/tutorials/mesh/moveDynamicMesh/badMove/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..f7bf44fca761a8dfcc42bf1e0743c56cd3362daa --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/system/controlDict @@ -0,0 +1,53 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +DebugSwitches +{ + pointBoundaryMesh 1; +} + +application moveDynamicMesh; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 10; + +deltaT 1; + +writeControl timeStep; + +writeInterval 1; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 6; + +writeCompression off; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable true; + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/badMove/system/fvSchemes b/tutorials/mesh/moveDynamicMesh/badMove/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..dce45d04ae700d8dc803ec1a4749fef42b01ad9a --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/system/fvSchemes @@ -0,0 +1,44 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +ddtSchemes +{} + +gradSchemes +{ + default Gauss linear; +} + +divSchemes +{} + +laplacianSchemes +{ + default Gauss linear corrected; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default corrected; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/badMove/system/fvSolution b/tutorials/mesh/moveDynamicMesh/badMove/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..eaff818230d35f16dff830ce18b781ad43ace4d3 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/badMove/system/fvSolution @@ -0,0 +1,33 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ + "cellDisplacement.*" + { + solver GAMG; + tolerance 1e-08; + relTol 0; + smoother GaussSeidel; + } +} + + +PIMPLE +{} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/0/pointDisplacement b/tutorials/mesh/moveDynamicMesh/bendJunction/0/pointDisplacement new file mode 100644 index 0000000000000000000000000000000000000000..70f2c0752818ff34d38ffd94d13f013b8c5f4185 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/0/pointDisplacement @@ -0,0 +1,130 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class pointVectorField; + location "0"; + object pointDisplacement; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 0 0 0 0 0]; + +internalField uniform (0 0 0); + +_surfaceDisplacement +{ + type surfaceSlipDisplacement; + value $internalField; + projectMode nearest; +// // if fixedNormal : normal +// projectDirection (0 0 1); +// //- -1 or component to knock out before doing projection +// wedgePlane -1; +// relax 0.5; + //- Underrelax motion by limiting displacement velocity + velocity (100 100 100); +} + + +boundaryField +{ + //#includeEtc "caseDicts/setConstraintTypes" + + InletSmall + { + ${^_surfaceDisplacement} + geometry + { + InletSmall + { + type triSurfaceMesh; + file "InletSmall.obj"; + } + } + } + Outlet + { + ${^_surfaceDisplacement} + geometry + { + Outlet + { + type triSurfaceMesh; + file "Outlet.obj"; + } + } + } + SmallPipe + { + ${^_surfaceDisplacement} + geometry + { + SmallPipe + { + type triSurfaceMesh; + file "SmallPipe.obj"; + } + } + } + Inlet + { + ${^_surfaceDisplacement} + geometry + { + Inlet + { + type triSurfaceMesh; + file "Inlet.obj"; + } + } + } + BigPipe + { + ${^_surfaceDisplacement} + geometry + { + BigPipe + { + type triSurfaceMesh; + file "BigPipe.obj"; + } + } + } + + // Per-patch feature-edges + SmallPipeEdges + { + type edgeSlipDisplacement; + file "SmallPipe.eMesh"; + //file "box222.extendedFeatureEdgeMesh"; + //- Underrelax motion by limiting displacement velocity + velocity (100 100 100); + } + BigPipeEdges + { + type edgeSlipDisplacement; + file "BigPipe.eMesh"; + //file "box222.extendedFeatureEdgeMesh"; + //- Underrelax motion by limiting displacement velocity + velocity (100 100 100); + } + // Inter-patch feature-edges + boundaryEdges + { + type edgeSlipDisplacement; + file "geometry.eMesh"; + //file "box222.extendedFeatureEdgeMesh"; + //- Underrelax motion by limiting displacement velocity + velocity (100 100 100); + } +} + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/Allclean b/tutorials/mesh/moveDynamicMesh/bendJunction/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..c0ceba7bef8401e0d57357211a744b094d989d20 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/Allclean @@ -0,0 +1,16 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +#cleanCase0 +cleanCase + +rm -f constant/triSurface/boundary.obj +rm -f constant/triSurface/geometry.eMesh +rm -f constant/triSurface/geometry.obj +rm -f constant/triSurface/blockMesh.obj +rm -f constant/triSurface/outside*.obj +rm -rf constant/extendedFeatureEdgeMesh + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/Allrun b/tutorials/mesh/moveDynamicMesh/bendJunction/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..c3efbea1188bc802f55bed4f11194707fff708a6 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/Allrun @@ -0,0 +1,54 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + + +# Add bit of preprocessing of the surface +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Add all surfaces +runApplication -s BigPipeInlet surfaceAdd \ + constant/triSurface/BigPipe.obj constant/triSurface/Inlet.obj \ + constant/triSurface/geometry.obj +runApplication -s InletSmall surfaceAdd \ + constant/triSurface/geometry.obj constant/triSurface/InletSmall.obj \ + constant/triSurface/geometry.obj +runApplication -s Outlet surfaceAdd \ + constant/triSurface/geometry.obj constant/triSurface/Outlet.obj \ + constant/triSurface/geometry.obj +runApplication -s SmallPipe surfaceAdd \ + constant/triSurface/geometry.obj constant/triSurface/SmallPipe.obj \ + constant/triSurface/geometry.obj + +# Extract features from surface +runApplication surfaceFeatureExtract + + + +# Generate mesh and features +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +runApplication blockMesh +runApplication -s presmooth checkMesh + +# Detect feature edges on mesh and generate new point patches from these. +# Note we only are interested in inter-patch features for this particular +# geometry. +runApplication surfaceMeshExtract \ + -featureAngle 180 constant/triSurface/blockMesh.obj + +# Generate some VTK files for the added point patches +setSet <<POINTPATCH +#pointSet SmallPipeEdges new patchToPoint SmallPipeEdges +#pointSet BigPipeEdges new patchToPoint BigPipeEdges +pointSet boundaryEdges new patchToPoint boundaryEdges +POINTPATCH + +# Do mesh motion to conform to surface +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +runApplication moveDynamicMesh +runApplication -s postsmooth checkMesh + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/README.txt b/tutorials/mesh/moveDynamicMesh/bendJunction/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f60bea01e52021c5721bb7240630653eb1c1ebc --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/README.txt @@ -0,0 +1,4 @@ +Copy of extBlockMesh/tutorial/bendJunction from +https://github.com/Etudes-NG/extBlockMesh + +Adapted to use simple OpenFOAM mesh motion solver diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/constant/dynamicMeshDict b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..7469174a2819a769e0485134b4b08e465c5e81f4 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/dynamicMeshDict @@ -0,0 +1,38 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2406 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicMotionSolverFvMesh; + +motionSolverLibs (fvMotionSolvers); + +//motionSolver displacementSBRStress; +//diffusivity uniform; + +motionSolver displacementPointSmoothing; +displacementPointSmoothingCoeffs +{ + // Use geometricElementTransform to maintain relative sizes + //pointSmoother geometricElementTransform; + //transformationParameter 0.667; + //nPointSmootherIter 10; + + pointSmoother laplacian; + nPointSmootherIter 10; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/BigPipe.obj b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/BigPipe.obj new file mode 100644 index 0000000000000000000000000000000000000000..907ec0eae5fedee38d3bf9090c565278d6fd945a --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/BigPipe.obj @@ -0,0 +1,23708 @@ +# Wavefront OBJ file +# Regions: +# 0 CATIASTL +# +# points : 8010 +# triangles : 15690 +# +v 69.8947 -9.79717e-15 3.8378 +v 69.0543 -9.79717e-15 11.4672 +v 21.2989 -9.79717e-15 66.681 +v 55.375 -9.79717e-15 42.8207 +v -23.9414 -9.79717e-15 65.7785 +v 64.9029 -9.79717e-15 26.2225 +v 68.3218 -9.79717e-15 15.236 +v 67.3837 -9.79717e-15 18.9588 +v 47.6121 -9.79717e-15 51.3136 +v 35.3019 -9.79717e-15 60.4465 +v 59.7304 -9.79717e-15 36.5005 +v 44.7272 -9.79717e-15 53.8468 +v 41.7077 -9.79717e-15 56.218 +v 69.5792 -9.79717e-15 7.66405 +v 24.9227 -9.79717e-15 65.413 +v 6.27475 -9.79717e-15 69.7182 +v 70 -9.79717e-15 0 +v -1.39617 -9.79717e-15 69.9861 +v 28.4716 -9.79717e-15 63.9482 +v -5.23111 -9.79717e-15 69.8043 +v 57.6394 -9.79717e-15 39.7203 +v 2.44297 -9.79717e-15 69.9574 +v -12.8423 -9.79717e-15 68.8119 +v -16.5956 -9.79717e-15 68.0043 +v 61.6417 -9.79717e-15 33.1708 +v 52.944 -9.79717e-15 45.7923 +v -20.299 -9.79717e-15 66.9922 +v 38.5628 -9.79717e-15 58.4201 +v 66.2429 -9.79717e-15 22.6247 +v 63.3676 -9.79717e-15 29.7414 +v -9.05031 -9.79717e-15 69.4125 +v 31.9347 -9.79717e-15 62.291 +v 50.3538 -9.79717e-15 48.6261 +v 10.0877 -9.79717e-15 69.2693 +v 17.6111 -9.79717e-15 67.7484 +v 13.8702 -9.79717e-15 68.6121 +v -19.9205 4.1183 67.2163 +v -19.9205 -4.1183 67.2163 +v 70.0735 4.1183 2.13608 +v 70.0735 -4.1183 2.13608 +v -13.7008 4.1183 68.7543 +v -13.7008 -4.1183 68.7543 +v 42.7933 4.1183 55.5301 +v 26.1541 4.1183 65.0448 +v 66.204 4.1183 23.0629 +v 59.8209 4.1183 36.5558 +v 41.0815 4.1183 56.8082 +v 66.204 -4.1183 23.0629 +v 59.8209 -4.1183 36.5558 +v 42.7933 -4.1183 55.5301 +v 41.0815 -4.1183 56.8082 +v 26.1541 -4.1183 65.0448 +v 61.9364 4.1183 32.8442 +v 24.1601 4.1183 65.8115 +v 61.9364 -4.1183 32.8442 +v 24.1601 -4.1183 65.8115 +v 18.051 4.1183 67.7423 +v 18.051 -4.1183 67.7423 +v 69.2938 4.1183 10.6408 +v 69.2938 -4.1183 10.6408 +v 69.8133 4.1183 6.40031 +v 69.8133 -4.1183 6.40031 +v 65.4705 4.1183 25.0694 +v 28.1238 4.1183 64.2177 +v 65.4705 -4.1183 25.0694 +v 28.1238 -4.1183 64.2177 +v -11.5996 4.1183 69.1398 +v -11.5996 -4.1183 69.1398 +v 49.228 4.1183 49.9146 +v 64.6763 4.1183 27.0526 +v 64.6763 -4.1183 27.0526 +v 49.228 -4.1183 49.9146 +v 15.9785 4.1183 68.2609 +v -23.9777 4.1183 65.8782 +v 15.9785 -4.1183 68.2609 +v -23.9777 -4.1183 65.8782 +v 63.822 4.1183 29.0106 +v 53.5793 4.1183 45.2119 +v 50.726 4.1183 48.3915 +v 46.0962 4.1183 52.8204 +v 70.1061 4.1183 0 +v 37.545 4.1183 59.205 +v 20.1066 4.1183 67.1609 +v 63.822 -4.1183 29.0106 +v 53.5793 -4.1183 45.2119 +v 50.726 -4.1183 48.3915 +v 46.0962 -4.1183 52.8204 +v 20.1066 -4.1183 67.1609 +v 70.1061 -4.1183 0 +v 37.545 -4.1183 59.205 +v 13.8912 4.1183 68.716 +v 13.8912 -4.1183 68.716 +v 68.517 4.1183 14.8417 +v 68.517 -4.1183 14.8417 +v 58.6793 4.1183 38.3615 +v 58.6793 -4.1183 38.3615 +v 69.5859 4.1183 8.5245 +v 69.5859 -4.1183 8.5245 +v -5.23903 4.1183 69.91 +v -5.23903 -4.1183 69.91 +v 60.9069 4.1183 34.7161 +v 39.3315 4.1183 58.0335 +v 35.7237 4.1183 60.3215 +v -17.8632 4.1183 67.7921 +v 60.9069 -4.1183 34.7161 +v 39.3315 -4.1183 58.0335 +v 35.7237 -4.1183 60.3215 +v -17.8632 -4.1183 67.7921 +v -9.48755 4.1183 69.4611 +v -9.48755 -4.1183 69.4611 +v -7.36671 4.1183 69.718 +v -7.36671 -4.1183 69.718 +v 56.2337 4.1183 41.8644 +v 22.1437 4.1183 66.5171 +v 54.932 4.1183 43.5584 +v 56.2337 -4.1183 41.8644 +v 54.932 -4.1183 43.5584 +v 22.1437 -4.1183 66.5171 +v -3.10649 4.1183 70.0372 +v -3.10649 -4.1183 70.0372 +v 1.16526 4.1183 70.0964 +v 1.16526 -4.1183 70.0964 +v 68.033 4.1183 16.9225 +v 68.033 -4.1183 16.9225 +v 5.43269 4.1183 69.8953 +v 5.43269 -4.1183 69.8953 +v 33.8691 4.1183 61.382 +v 30.0674 4.1183 63.331 +v 52.1769 4.1183 46.8235 +v 47.6842 4.1183 51.3914 +v 52.1769 -4.1183 46.8235 +v 47.6842 -4.1183 51.3914 +v 33.8691 -4.1183 61.382 +v 30.0674 -4.1183 63.331 +v 11.7911 4.1183 69.1074 +v 11.7911 -4.1183 69.1074 +v 69.9759 4.1183 4.27018 +v 69.9759 -4.1183 4.27018 +v 7.55982 4.1183 69.6973 +v 7.55982 -4.1183 69.6973 +v 67.4858 4.1183 18.9876 +v 67.4858 -4.1183 18.9876 +v -0.971066 4.1183 70.0993 +v -0.971066 -4.1183 70.0993 +v 9.67994 4.1183 69.4346 +v 9.67994 -4.1183 69.4346 +v 66.8759 4.1183 21.035 +v 68.9374 4.1183 12.7472 +v 68.9374 -4.1183 12.7472 +v 66.8759 -4.1183 21.035 +v 44.4654 4.1183 54.2004 +v 44.4654 -4.1183 54.2004 +v 3.30051 4.1183 70.0283 +v 3.30051 -4.1183 70.0283 +v 31.9831 4.1183 62.3854 +v 31.9831 -4.1183 62.3854 +v 57.4832 4.1183 40.1316 +v 57.4832 -4.1183 40.1316 +v 62.9084 4.1183 30.9418 +v 62.9084 -4.1183 30.9418 +v -15.7894 4.1183 68.3049 +v -15.7894 -4.1183 68.3049 +v -21.9593 4.1183 66.5782 +v -21.9593 -4.1183 66.5782 +v -15.861 8.22568 68.6146 +v -15.861 -8.22568 68.6146 +v 3.31548 8.22568 70.3459 +v 3.31548 -8.22568 70.3459 +v 58.9454 8.22568 38.5355 +v 58.9454 -8.22568 38.5355 +v -11.6522 8.22568 69.4533 +v -11.6522 -8.22568 69.4533 +v 61.1831 8.22568 34.8735 +v 41.2678 8.22568 57.0658 +v 61.1831 -8.22568 34.8735 +v 41.2678 -8.22568 57.0658 +v 64.9696 8.22568 27.1752 +v 52.4135 8.22568 47.0358 +v 64.9696 -8.22568 27.1752 +v 52.4135 -8.22568 47.0358 +v -7.40012 8.22568 70.0341 +v -7.40012 -8.22568 70.0341 +v -20.0109 8.22568 67.5212 +v -20.0109 -8.22568 67.5212 +v 68.8278 8.22568 14.909 +v 20.1978 8.22568 67.4655 +v 68.8278 -8.22568 14.909 +v 20.1978 -8.22568 67.4655 +v 69.2501 8.22568 12.805 +v 69.2501 -8.22568 12.805 +v 56.4887 8.22568 42.0543 +v 56.4887 -8.22568 42.0543 +v 24.2697 8.22568 66.1099 +v 24.2697 -8.22568 66.1099 +v 70.3913 8.22568 2.14577 +v 70.3913 -8.22568 2.14577 +v 35.8857 8.22568 60.595 +v 28.2514 8.22568 64.5089 +v 35.8857 -8.22568 60.595 +v 28.2514 -8.22568 64.5089 +v -0.97547 8.22568 70.4173 +v -0.97547 -8.22568 70.4173 +v 16.051 8.22568 68.5704 +v 16.051 -8.22568 68.5704 +v 70.1299 8.22568 6.42934 +v 70.1299 -8.22568 6.42934 +v 49.4512 8.22568 50.141 +v 47.9005 8.22568 51.6245 +v 49.4512 -8.22568 50.141 +v 47.9005 -8.22568 51.6245 +v 7.59411 8.22568 70.0134 +v 7.59411 -8.22568 70.0134 +v 63.1937 8.22568 31.0821 +v 44.6671 8.22568 54.4462 +v 37.7153 8.22568 59.4735 +v 63.1937 -8.22568 31.0821 +v 44.6671 -8.22568 54.4462 +v 37.7153 -8.22568 59.4735 +v -13.763 8.22568 69.0661 +v -13.763 -8.22568 69.0661 +v 18.1328 8.22568 68.0496 +v 18.1328 -8.22568 68.0496 +v 5.45733 8.22568 70.2122 +v 5.45733 -8.22568 70.2122 +v 67.1792 8.22568 21.1304 +v -5.26279 8.22568 70.2271 +v 67.1792 -8.22568 21.1304 +v -5.26279 -8.22568 70.2271 +v 66.5042 8.22568 23.1675 +v 62.2173 8.22568 32.9931 +v 50.956 8.22568 48.611 +v 46.3053 8.22568 53.06 +v 66.5042 -8.22568 23.1675 +v 62.2173 -8.22568 32.9931 +v 50.956 -8.22568 48.611 +v 46.3053 -8.22568 53.06 +v -9.53057 8.22568 69.7761 +v -9.53057 -8.22568 69.7761 +v 70.2933 8.22568 4.28955 +v 70.2933 -8.22568 4.28955 +v 34.0227 8.22568 61.6603 +v 32.1282 8.22568 62.6683 +v 64.1114 8.22568 29.1422 +v 32.1282 -8.22568 62.6683 +v 34.0227 -8.22568 61.6603 +v 64.1114 -8.22568 29.1422 +v 13.9543 8.22568 69.0277 +v 13.9543 -8.22568 69.0277 +v -22.0589 8.22568 66.8801 +v -22.0589 -8.22568 66.8801 +v 70.424 8.22568 0 +v 55.1811 8.22568 43.756 +v 26.2727 8.22568 65.3398 +v 70.424 -8.22568 0 +v 55.1811 -8.22568 43.756 +v 26.2727 -8.22568 65.3398 +v 1.17055 8.22568 70.4143 +v 1.17055 -8.22568 70.4143 +v 69.9015 8.22568 8.56316 +v 57.7439 8.22568 40.3136 +v 69.9015 -8.22568 8.56316 +v 57.7439 -8.22568 40.3136 +v 11.8445 8.22568 69.4208 +v 11.8445 -8.22568 69.4208 +v 67.7919 8.22568 19.0737 +v 67.7919 -8.22568 19.0737 +v -3.12058 8.22568 70.3548 +v -3.12058 -8.22568 70.3548 +v 53.8223 8.22568 45.417 +v 42.9874 8.22568 55.7819 +v 53.8223 -8.22568 45.417 +v 42.9874 -8.22568 55.7819 +v 39.5099 8.22568 58.2967 +v 30.2038 8.22568 63.6182 +v 39.5099 -8.22568 58.2967 +v 30.2038 -8.22568 63.6182 +v 69.6081 8.22568 10.689 +v 69.6081 -8.22568 10.689 +v 65.7674 8.22568 25.1831 +v 65.7674 -8.22568 25.1831 +v 60.0922 8.22568 36.7216 +v 60.0922 -8.22568 36.7216 +v -17.9442 8.22568 68.0995 +v -17.9442 -8.22568 68.0995 +v 22.2441 8.22568 66.8187 +v 22.2441 -8.22568 66.8187 +v 9.72384 8.22568 69.7495 +v 9.72384 -8.22568 69.7495 +v 68.3416 8.22568 16.9993 +v 68.3416 -8.22568 16.9993 +v -24.0864 8.22568 66.1769 +v -24.0864 -8.22568 66.1769 +v 70.953 12.3112 0 +v 70.953 -12.3112 0 +v 61.6427 12.3112 35.1355 +v 61.6427 -12.3112 35.1355 +v 70.1309 12.3112 10.7693 +v 70.1309 -12.3112 10.7693 +v -15.9801 12.3112 69.13 +v -15.9801 -12.3112 69.13 +v 3.34038 12.3112 70.8743 +v 3.34038 -12.3112 70.8743 +v 69.7702 12.3112 12.9012 +v 69.7702 -12.3112 12.9012 +v 28.4636 12.3112 64.9934 +v 28.4636 -12.3112 64.9934 +v -0.982796 12.3112 70.9462 +v -0.982796 -12.3112 70.9462 +v -7.4557 12.3112 70.5602 +v -7.4557 -12.3112 70.5602 +v 56.913 12.3112 42.3702 +v 56.913 -12.3112 42.3702 +v 68.8549 12.3112 17.1269 +v 68.8549 -12.3112 17.1269 +v 67.6838 12.3112 21.2891 +v 67.6838 -12.3112 21.2891 +v 70.6567 12.3112 6.47763 +v 70.6567 -12.3112 6.47763 +v 52.8072 12.3112 47.3891 +v 49.8226 12.3112 50.5176 +v 48.2603 12.3112 52.0122 +v 52.8072 -12.3112 47.3891 +v 49.8226 -12.3112 50.5176 +v 48.2603 -12.3112 52.0122 +v 22.4112 12.3112 67.3206 +v 20.3495 12.3112 67.9722 +v 22.4112 -12.3112 67.3206 +v 20.3495 -12.3112 67.9722 +v -22.2246 12.3112 67.3824 +v -22.2246 -12.3112 67.3824 +v -5.30232 12.3112 70.7546 +v -5.30232 -12.3112 70.7546 +v 68.301 12.3112 19.2169 +v -18.079 12.3112 68.611 +v 68.301 -12.3112 19.2169 +v -18.079 -12.3112 68.611 +v -24.2673 12.3112 66.674 +v -24.2673 -12.3112 66.674 +v 66.2614 12.3112 25.3722 +v 65.4576 12.3112 27.3794 +v 45.0026 12.3112 54.8552 +v 16.1716 12.3112 69.0855 +v 66.2614 -12.3112 25.3722 +v 65.4576 -12.3112 27.3794 +v 45.0026 -12.3112 54.8552 +v 16.1716 -12.3112 69.0855 +v 5.49832 12.3112 70.7396 +v 5.49832 -12.3112 70.7396 +v -3.14402 12.3112 70.8833 +v -3.14402 -12.3112 70.8833 +v 55.5956 12.3112 44.0846 +v 18.269 12.3112 68.5607 +v 55.5956 -12.3112 44.0846 +v 18.269 -12.3112 68.5607 +v 63.6684 12.3112 31.3156 +v -20.1612 12.3112 68.0283 +v 63.6684 -12.3112 31.3156 +v -20.1612 -12.3112 68.0283 +v -13.8663 12.3112 69.5848 +v -13.8663 -12.3112 69.5848 +v 1.17934 12.3112 70.9432 +v 1.17934 -12.3112 70.9432 +v 32.3695 12.3112 63.139 +v 58.1776 12.3112 40.6164 +v 54.2266 12.3112 45.7581 +v 30.4307 12.3112 64.096 +v -11.7397 12.3112 69.975 +v 32.3695 -12.3112 63.139 +v 58.1776 -12.3112 40.6164 +v 54.2266 -12.3112 45.7581 +v 30.4307 -12.3112 64.096 +v -11.7397 -12.3112 69.975 +v -9.60216 12.3112 70.3002 +v -9.60216 -12.3112 70.3002 +v 9.79688 12.3112 70.2734 +v 9.79688 -12.3112 70.2734 +v 70.4265 12.3112 8.62748 +v 70.4265 -12.3112 8.62748 +v 34.2783 12.3112 62.1235 +v 60.5435 12.3112 36.9974 +v 37.9986 12.3112 59.9202 +v 24.452 12.3112 66.6065 +v 34.2783 -12.3112 62.1235 +v 60.5435 -12.3112 36.9974 +v 37.9986 -12.3112 59.9202 +v 24.452 -12.3112 66.6065 +v 70.8212 12.3112 4.32176 +v 70.8212 -12.3112 4.32176 +v 70.92 12.3112 2.16189 +v 70.92 -12.3112 2.16189 +v 67.0037 12.3112 23.3415 +v 64.593 12.3112 29.3611 +v 14.0591 12.3112 69.5462 +v 67.0037 -12.3112 23.3415 +v 64.593 -12.3112 29.3611 +v 14.0591 -12.3112 69.5462 +v 11.9335 12.3112 69.9422 +v 11.9335 -12.3112 69.9422 +v 36.1552 12.3112 61.0502 +v 46.6531 12.3112 53.4585 +v 43.3103 12.3112 56.2009 +v 39.8067 12.3112 58.7346 +v 46.6531 -12.3112 53.4585 +v 43.3103 -12.3112 56.2009 +v 39.8067 -12.3112 58.7346 +v 36.1552 -12.3112 61.0502 +v 7.65115 12.3112 70.5392 +v 7.65115 -12.3112 70.5392 +v 41.5778 12.3112 57.4944 +v 41.5778 -12.3112 57.4944 +v 69.3447 12.3112 15.021 +v 69.3447 -12.3112 15.021 +v 62.6846 12.3112 33.241 +v 59.3881 12.3112 38.8249 +v 51.3387 12.3112 48.9761 +v 62.6846 -12.3112 33.241 +v 59.3881 -12.3112 38.8249 +v 51.3387 -12.3112 48.9761 +v 26.4701 12.3112 65.8305 +v 26.4701 -12.3112 65.8305 +v -3.17675 16.3642 71.6211 +v -3.17675 -16.3642 71.6211 +v -11.8619 16.3642 70.7034 +v -11.8619 -16.3642 70.7034 +v 70.0666 16.3642 15.1774 +v 70.0666 -16.3642 15.1774 +v 71.1596 16.3642 8.71729 +v 71.1596 -16.3642 8.71729 +v -16.1464 16.3642 69.8496 +v -16.1464 -16.3642 69.8496 +v 69.012 16.3642 19.417 +v 69.012 -16.3642 19.417 +v 53.3569 16.3642 47.8824 +v 48.7626 16.3642 52.5536 +v 53.3569 -16.3642 47.8824 +v 48.7626 -16.3642 52.5536 +v -22.4559 16.3642 68.0838 +v -22.4559 -16.3642 68.0838 +v 71.6915 16.3642 0 +v 32.7065 16.3642 63.7963 +v 47.1387 16.3642 54.015 +v 43.7611 16.3642 56.7859 +v 24.7065 16.3642 67.2998 +v 71.6915 -16.3642 0 +v 32.7065 -16.3642 63.7963 +v 47.1387 -16.3642 54.015 +v 43.7611 -16.3642 56.7859 +v 24.7065 -16.3642 67.2998 +v 9.89886 16.3642 71.0049 +v 9.89886 -16.3642 71.0049 +v 71.6583 16.3642 2.18439 +v 71.6583 -16.3642 2.18439 +v 34.6351 16.3642 62.7701 +v 57.5055 16.3642 42.8112 +v 22.6444 16.3642 68.0214 +v 34.6351 -16.3642 62.7701 +v 57.5055 -16.3642 42.8112 +v 22.6444 -16.3642 68.0214 +v 12.0577 16.3642 70.6703 +v 12.0577 -16.3642 70.6703 +v 67.7012 16.3642 23.5845 +v 30.7474 16.3642 64.7632 +v 67.7012 -16.3642 23.5845 +v 30.7474 -16.3642 64.7632 +v 36.5316 16.3642 61.6857 +v 56.1743 16.3642 44.5435 +v 56.1743 -16.3642 44.5435 +v 36.5316 -16.3642 61.6857 +v -7.53331 16.3642 71.2946 +v -7.53331 -16.3642 71.2946 +v -5.35752 16.3642 71.4911 +v -5.35752 -16.3642 71.4911 +v 66.1389 16.3642 27.6644 +v 26.7456 16.3642 66.5158 +v 20.5614 16.3642 68.6797 +v 14.2054 16.3642 70.2701 +v 66.1389 -16.3642 27.6644 +v 26.7456 -16.3642 66.5158 +v 20.5614 -16.3642 68.6797 +v 14.2054 -16.3642 70.2701 +v 60.0063 16.3642 39.2291 +v 54.791 16.3642 46.2344 +v 60.0063 -16.3642 39.2291 +v 54.791 -16.3642 46.2344 +v 1.19161 16.3642 71.6816 +v 1.19161 -16.3642 71.6816 +v 70.8609 16.3642 10.8814 +v 70.8609 -16.3642 10.8814 +v 3.37515 16.3642 71.6121 +v 3.37515 -16.3642 71.6121 +v 64.3311 16.3642 31.6415 +v 64.3311 -16.3642 31.6415 +v -9.70211 16.3642 71.032 +v -9.70211 -16.3642 71.032 +v 61.1737 16.3642 37.3825 +v 40.221 16.3642 59.346 +v 61.1737 -16.3642 37.3825 +v 40.221 -16.3642 59.346 +v 71.5584 16.3642 4.36675 +v 71.5584 -16.3642 4.36675 +v 65.2653 16.3642 29.6667 +v 65.2653 -16.3642 29.6667 +v 62.2844 16.3642 35.5012 +v 45.471 16.3642 55.4262 +v 28.7599 16.3642 65.67 +v 62.2844 -16.3642 35.5012 +v 45.471 -16.3642 55.4262 +v 28.7599 -16.3642 65.67 +v -0.993027 16.3642 71.6847 +v -0.993027 -16.3642 71.6847 +v 68.3884 16.3642 21.5107 +v 68.3884 -16.3642 21.5107 +v 16.3399 16.3642 69.8046 +v 16.3399 -16.3642 69.8046 +v 58.7832 16.3642 41.0392 +v 38.3941 16.3642 60.5439 +v 18.4592 16.3642 69.2744 +v 58.7832 -16.3642 41.0392 +v 38.3941 -16.3642 60.5439 +v 18.4592 -16.3642 69.2744 +v 5.55555 16.3642 71.476 +v 5.55555 -16.3642 71.476 +v 71.3922 16.3642 6.54506 +v -20.371 16.3642 68.7365 +v 71.3922 -16.3642 6.54506 +v -20.371 -16.3642 68.7365 +v -24.52 16.3642 67.368 +v -24.52 -16.3642 67.368 +v 51.8731 16.3642 49.4859 +v 50.3413 16.3642 51.0435 +v 42.0106 16.3642 58.0929 +v 51.8731 -16.3642 49.4859 +v 50.3413 -16.3642 51.0435 +v 42.0106 -16.3642 58.0929 +v 69.5716 16.3642 17.3052 +v 69.5716 -16.3642 17.3052 +v 70.4965 16.3642 13.0354 +v 70.4965 -16.3642 13.0354 +v 66.9512 16.3642 25.6363 +v 66.9512 -16.3642 25.6363 +v 63.3371 16.3642 33.587 +v 63.3371 -16.3642 33.587 +v 7.73079 16.3642 71.2735 +v 7.73079 -16.3642 71.2735 +v -18.2672 16.3642 69.3252 +v -18.2672 -16.3642 69.3252 +v -14.0107 16.3642 70.3092 +v -14.0107 -16.3642 70.3092 +v 67.0119 20.3737 28.0295 +v 67.0119 -20.3737 28.0295 +v 27.0986 20.3737 67.3937 +v 27.0986 -20.3737 67.3937 +v 56.9157 20.3737 45.1314 +v 56.9157 -20.3737 45.1314 +v 72.5029 20.3737 4.42439 +v 72.5029 -20.3737 4.42439 +v -22.7523 20.3737 68.9825 +v 31.1533 20.3737 65.618 +v -22.7523 -20.3737 68.9825 +v 31.1533 -20.3737 65.618 +v -20.6399 20.3737 69.6437 +v -20.6399 -20.3737 69.6437 +v 47.7609 20.3737 54.7279 +v 38.9009 20.3737 61.343 +v 10.0295 20.3737 71.942 +v 47.7609 -20.3737 54.7279 +v 38.9009 -20.3737 61.343 +v 10.0295 -20.3737 71.942 +v -5.42823 20.3737 72.4347 +v -5.42823 -20.3737 72.4347 +v -24.8436 20.3737 68.2572 +v 37.0137 20.3737 62.4998 +v 33.1381 20.3737 64.6383 +v 58.2645 20.3737 43.3763 +v 33.1381 -20.3737 64.6383 +v -24.8436 -20.3737 68.2572 +v 58.2645 -20.3737 43.3763 +v 37.0137 -20.3737 62.4998 +v -14.1956 20.3737 71.2372 +v -14.1956 -20.3737 71.2372 +v 72.6378 20.3737 0 +v 64.1731 20.3737 34.0303 +v 49.4062 20.3737 53.2473 +v 72.6378 -20.3737 0 +v 64.1731 -20.3737 34.0303 +v 49.4062 -20.3737 53.2473 +v 72.0988 20.3737 8.83235 +v 68.5948 20.3737 23.8957 +v 72.0988 -20.3737 8.83235 +v 68.5948 -20.3737 23.8957 +v 71.4269 20.3737 13.2075 +v 71.4269 -20.3737 13.2075 +v -1.00613 20.3737 72.6308 +v -1.00613 -20.3737 72.6308 +v 70.4899 20.3737 17.5336 +v 69.291 20.3737 21.7946 +v 59.559 20.3737 41.5809 +v 42.5651 20.3737 58.8597 +v 70.4899 -20.3737 17.5336 +v 69.291 -20.3737 21.7946 +v 59.559 -20.3737 41.5809 +v 42.5651 -20.3737 58.8597 +v 69.9229 20.3737 19.6733 +v 69.9229 -20.3737 19.6733 +v 1.20734 20.3737 72.6277 +v 1.20734 -20.3737 72.6277 +v 29.1395 20.3737 66.5368 +v 29.1395 -20.3737 66.5368 +v 71.7962 20.3737 11.025 +v 71.7962 -20.3737 11.025 +v 60.7983 20.3737 39.7468 +v 60.7983 -20.3737 39.7468 +v -18.5083 20.3737 70.2402 +v -18.5083 -20.3737 70.2402 +v -9.83017 20.3737 71.9695 +v -9.83017 -20.3737 71.9695 +v 66.1267 20.3737 30.0583 +v 22.9433 20.3737 68.9192 +v 18.7028 20.3737 70.1887 +v 66.1267 -20.3737 30.0583 +v 22.9433 -20.3737 68.9192 +v 18.7028 -20.3737 70.1887 +v 72.6041 20.3737 2.21322 +v 72.6041 -20.3737 2.21322 +v -7.63274 20.3737 72.2356 +v -7.63274 -20.3737 72.2356 +v 67.8348 20.3737 25.9747 +v 67.8348 -20.3737 25.9747 +v 72.3344 20.3737 6.63144 +v 72.3344 -20.3737 6.63144 +v 63.1064 20.3737 35.9698 +v 55.5142 20.3737 46.8446 +v 46.0712 20.3737 56.1577 +v 40.7519 20.3737 60.1293 +v 63.1064 -20.3737 35.9698 +v 55.5142 -20.3737 46.8446 +v 46.0712 -20.3737 56.1577 +v 40.7519 -20.3737 60.1293 +v -3.21867 20.3737 72.5664 +v -3.21867 -20.3737 72.5664 +v 70.9914 20.3737 15.3777 +v 70.9914 -20.3737 15.3777 +v -12.0185 20.3737 71.6366 +v -12.0185 -20.3737 71.6366 +v -16.3596 20.3737 70.7716 +v -16.3596 -20.3737 70.7716 +v 5.62888 20.3737 72.4194 +v 5.62888 -20.3737 72.4194 +v 12.2169 20.3737 71.603 +v 12.2169 -20.3737 71.603 +v 54.0611 20.3737 48.5144 +v 52.5578 20.3737 50.139 +v 25.0326 20.3737 68.1881 +v 54.0611 -20.3737 48.5144 +v 52.5578 -20.3737 50.139 +v 25.0326 -20.3737 68.1881 +v 16.5555 20.3737 70.726 +v 16.5555 -20.3737 70.726 +v 35.0922 20.3737 63.5986 +v 65.1802 20.3737 32.0592 +v 61.9812 20.3737 37.8759 +v 44.3387 20.3737 57.5354 +v 35.0922 -20.3737 63.5986 +v 65.1802 -20.3737 32.0592 +v 61.9812 -20.3737 37.8759 +v 44.3387 -20.3737 57.5354 +v 3.4197 20.3737 72.5572 +v 3.4197 -20.3737 72.5572 +v 51.0057 20.3737 51.7172 +v 51.0057 -20.3737 51.7172 +v 14.3929 20.3737 71.1976 +v 14.3929 -20.3737 71.1976 +v 20.8328 20.3737 69.5862 +v 20.8328 -20.3737 69.5862 +v 7.83283 20.3737 72.2142 +v 7.83283 -20.3737 72.2142 +v 7.95699 24.3292 73.3589 +v 7.95699 -24.3292 73.3589 +v 54.918 24.3292 49.2834 +v 54.918 -24.3292 49.2834 +v 31.6471 24.3292 66.6581 +v 31.6471 -24.3292 66.6581 +v -18.8017 24.3292 71.3536 +v -18.8017 -24.3292 71.3536 +v -9.98598 24.3292 73.1103 +v -9.98598 -24.3292 73.1103 +v 10.1885 24.3292 73.0824 +v 10.1885 -24.3292 73.0824 +v 21.163 24.3292 70.6892 +v 21.163 -24.3292 70.6892 +v 57.8179 24.3292 45.8468 +v 18.9993 24.3292 71.3012 +v 57.8179 -24.3292 45.8468 +v 18.9993 -24.3292 71.3012 +v 66.2134 24.3292 32.5673 +v 59.188 24.3292 44.0638 +v 43.2398 24.3292 59.7927 +v 66.2134 -24.3292 32.5673 +v 59.188 -24.3292 44.0638 +v 43.2398 -24.3292 59.7927 +v 73.481 24.3292 6.73656 +v 73.481 -24.3292 6.73656 +v 72.5591 24.3292 13.4169 +v -14.4206 24.3292 72.3663 +v 72.5591 -24.3292 13.4169 +v -14.4206 -24.3292 72.3663 +v 72.1167 24.3292 15.6215 +v 14.621 24.3292 72.3261 +v 72.1167 -24.3292 15.6215 +v 14.621 -24.3292 72.3261 +v 72.9343 24.3292 11.1998 +v 72.9343 -24.3292 11.1998 +v -3.2697 24.3292 73.7167 +v -3.2697 -24.3292 73.7167 +v 73.7892 24.3292 0 +v 71.6072 24.3292 17.8115 +v 53.3909 24.3292 50.9338 +v 41.3979 24.3292 61.0824 +v 73.7892 -24.3292 0 +v 71.6072 -24.3292 17.8115 +v 53.3909 -24.3292 50.9338 +v 41.3979 -24.3292 61.0824 +v 73.6522 24.3292 4.49452 +v 73.6522 -24.3292 4.49452 +v 71.0312 24.3292 19.9851 +v 71.0312 -24.3292 19.9851 +v 35.6485 24.3292 64.6067 +v 35.6485 -24.3292 64.6067 +v -7.75373 24.3292 73.3807 +v -7.75373 -24.3292 73.3807 +v 16.818 24.3292 71.847 +v 16.818 -24.3292 71.847 +v -1.02208 24.3292 73.7821 +v -1.02208 -24.3292 73.7821 +v 51.8142 24.3292 52.5369 +v 50.1894 24.3292 54.0913 +v 46.8015 24.3292 57.0479 +v 29.6014 24.3292 67.5914 +v 51.8142 -24.3292 52.5369 +v 50.1894 -24.3292 54.0913 +v 46.8015 -24.3292 57.0479 +v 29.6014 -24.3292 67.5914 +v -16.6189 24.3292 71.8934 +v -16.6189 -24.3292 71.8934 +v 1.22648 24.3292 73.779 +v 1.22648 -24.3292 73.779 +v 67.1749 24.3292 30.5347 +v 61.7621 24.3292 40.3769 +v 67.1749 -24.3292 30.5347 +v 61.7621 -24.3292 40.3769 +v 5.7181 24.3292 73.5673 +v 5.7181 -24.3292 73.5673 +v -23.1129 24.3292 70.0759 +v 69.6821 24.3292 24.2745 +v 68.9101 24.3292 26.3864 +v -23.1129 -24.3292 70.0759 +v 69.6821 -24.3292 24.2745 +v 68.9101 -24.3292 26.3864 +v -5.51427 24.3292 73.5828 +v -5.51427 -24.3292 73.5828 +v -25.2374 24.3292 69.3391 +v 37.6004 24.3292 63.4905 +v 68.0741 24.3292 28.4738 +v -25.2374 -24.3292 69.3391 +v 68.0741 -24.3292 28.4738 +v 37.6004 -24.3292 63.4905 +v 25.4294 24.3292 69.269 +v 25.4294 -24.3292 69.269 +v 33.6634 24.3292 65.6629 +v 62.9636 24.3292 38.4763 +v 60.5031 24.3292 42.24 +v 39.5175 24.3292 62.3154 +v 33.6634 -24.3292 65.6629 +v 62.9636 -24.3292 38.4763 +v 60.5031 -24.3292 42.24 +v 39.5175 -24.3292 62.3154 +v 3.4739 24.3292 73.7074 +v 3.4739 -24.3292 73.7074 +v 73.7549 24.3292 2.2483 +v 73.7549 -24.3292 2.2483 +v 56.3942 24.3292 47.5872 +v 48.518 24.3292 55.5954 +v 27.5282 24.3292 68.462 +v 56.3942 -24.3292 47.5872 +v 48.518 -24.3292 55.5954 +v 27.5282 -24.3292 68.462 +v 12.4105 24.3292 72.738 +v 12.4105 -24.3292 72.738 +v -12.209 24.3292 72.7721 +v -12.209 -24.3292 72.7721 +v 45.0415 24.3292 58.4474 +v 23.307 24.3292 70.0116 +v 45.0415 -24.3292 58.4474 +v 23.307 -24.3292 70.0116 +v -20.9671 24.3292 70.7476 +v -20.9671 -24.3292 70.7476 +v 65.1903 24.3292 34.5697 +v 64.1067 24.3292 36.54 +v 65.1903 -24.3292 34.5697 +v 64.1067 -24.3292 36.54 +v 73.2417 24.3292 8.97235 +v 73.2417 -24.3292 8.97235 +v 70.3893 24.3292 22.1401 +v 70.3893 -24.3292 22.1401 +v 5.82299 28.2202 74.9167 +v 5.82299 -28.2202 74.9167 +v 72.9206 28.2202 18.1383 +v 72.9206 -28.2202 18.1383 +v -1.04083 28.2202 75.1354 +v -1.04083 -28.2202 75.1354 +v 70.1741 28.2202 26.8704 +v 70.1741 -28.2202 26.8704 +v 75.1426 28.2202 0 +v 75.1426 -28.2202 0 +v -7.89595 28.2202 74.7266 +v -7.89595 -28.2202 74.7266 +v 38.2901 28.2202 64.6551 +v 38.2901 -28.2202 64.6551 +v 1.24898 28.2202 75.1323 +v 1.24898 -28.2202 75.1323 +v 74.2721 28.2202 11.4052 +v 74.2721 -28.2202 11.4052 +v 74.5851 28.2202 9.13692 +v 74.5851 -28.2202 9.13692 +v 72.3341 28.2202 20.3517 +v 55.9254 28.2202 50.1874 +v 52.7646 28.2202 53.5006 +v 42.1572 28.2202 62.2028 +v -10.1692 28.2202 74.4514 +v 72.3341 -28.2202 20.3517 +v 55.9254 -28.2202 50.1874 +v 52.7646 -28.2202 53.5006 +v 42.1572 -28.2202 62.2028 +v -10.1692 -28.2202 74.4514 +v -12.4329 28.2202 74.107 +v -12.4329 -28.2202 74.107 +v 67.4279 28.2202 33.1647 +v 67.4279 -28.2202 33.1647 +v 12.6382 28.2202 74.0722 +v 12.6382 -28.2202 74.0722 +v 69.3228 28.2202 28.9961 +v 62.8949 28.2202 41.1175 +v 61.6129 28.2202 43.0148 +v 58.8785 28.2202 46.6877 +v 57.4286 28.2202 48.46 +v 49.4079 28.2202 56.6152 +v 32.2276 28.2202 67.8808 +v 69.3228 -28.2202 28.9961 +v 62.8949 -28.2202 41.1175 +v 61.6129 -28.2202 43.0148 +v 58.8785 -28.2202 46.6877 +v 57.4286 -28.2202 48.46 +v 49.4079 -28.2202 56.6152 +v 32.2276 -28.2202 67.8808 +v -23.5369 28.2202 71.3613 +v 74.8288 28.2202 6.86013 +v 30.1443 28.2202 68.8312 +v -23.5369 -28.2202 71.3613 +v 74.8288 -28.2202 6.86013 +v 30.1443 -28.2202 68.8312 +v 10.3754 28.2202 74.4229 +v 10.3754 -28.2202 74.4229 +v 8.10294 28.2202 74.7045 +v 8.10294 -28.2202 74.7045 +v -19.1466 28.2202 72.6624 +v -19.1466 -28.2202 72.6624 +v 36.3024 28.2202 65.7918 +v 54.3702 28.2202 51.8681 +v 40.2424 28.2202 63.4584 +v -16.9237 28.2202 73.2121 +v 36.3024 -28.2202 65.7918 +v 54.3702 -28.2202 51.8681 +v 40.2424 -28.2202 63.4584 +v -16.9237 -28.2202 73.2121 +v -25.7003 28.2202 70.611 +v 19.3478 28.2202 72.6091 +v -25.7003 -28.2202 70.611 +v 19.3478 -28.2202 72.6091 +v 71.6805 28.2202 22.5462 +v 44.0329 28.2202 60.8894 +v 71.6805 -28.2202 22.5462 +v 44.0329 -28.2202 60.8894 +v 3.53762 28.2202 75.0593 +v 3.53762 -28.2202 75.0593 +v 17.1265 28.2202 73.1649 +v 17.1265 -28.2202 73.1649 +v -5.61542 28.2202 74.9325 +v -5.61542 -28.2202 74.9325 +v 73.4395 28.2202 15.908 +v 14.8892 28.2202 73.6528 +v 73.4395 -28.2202 15.908 +v 14.8892 -28.2202 73.6528 +v 73.8901 28.2202 13.663 +v 73.8901 -28.2202 13.663 +v 51.11 28.2202 55.0835 +v 47.6599 28.2202 58.0943 +v 25.8958 28.2202 70.5395 +v 51.11 -28.2202 55.0835 +v 47.6599 -28.2202 58.0943 +v 25.8958 -28.2202 70.5395 +v -3.32967 28.2202 75.0688 +v -3.32967 -28.2202 75.0688 +v 68.4071 28.2202 31.0948 +v 66.3861 28.2202 35.2038 +v 68.4071 -28.2202 31.0948 +v 66.3861 -28.2202 35.2038 +v -21.3517 28.2202 72.0453 +v -21.3517 -28.2202 72.0453 +v 34.2809 28.2202 66.8673 +v 60.2737 28.2202 44.8721 +v 45.8677 28.2202 59.5195 +v 34.2809 -28.2202 66.8673 +v 60.2737 -28.2202 44.8721 +v 45.8677 -28.2202 59.5195 +v 70.9602 28.2202 24.7198 +v 65.2826 28.2202 37.2102 +v 70.9602 -28.2202 24.7198 +v 65.2826 -28.2202 37.2102 +v 28.0331 28.2202 69.7178 +v 28.0331 -28.2202 69.7178 +v -14.6851 28.2202 73.6937 +v -14.6851 -28.2202 73.6937 +v 23.7345 28.2202 71.2958 +v 23.7345 -28.2202 71.2958 +v 21.5512 28.2202 71.9859 +v 21.5512 -28.2202 71.9859 +v 75.1078 28.2202 2.28954 +v 75.1078 -28.2202 2.28954 +v 75.0031 28.2202 4.57696 +v 75.0031 -28.2202 4.57696 +v 64.1186 28.2202 39.182 +v 64.1186 -28.2202 39.182 +v 26.4307 32.0363 71.9964 +v 26.4307 -32.0363 71.9964 +v 3.61069 32.0363 76.6096 +v 3.61069 -32.0363 76.6096 +v -24.023 32.0363 72.8352 +v -24.023 -32.0363 72.8352 +v 55.4932 32.0363 52.9393 +v 55.4932 -32.0363 52.9393 +v -5.7314 32.0363 76.4802 +v -5.7314 -32.0363 76.4802 +v 19.7474 32.0363 74.1088 +v 19.7474 -32.0363 74.1088 +v 76.1256 32.0363 9.32564 +v 76.1256 -32.0363 9.32564 +v 10.5897 32.0363 75.96 +v 10.5897 -32.0363 75.96 +v 37.0522 32.0363 67.1506 +v 70.7545 32.0363 29.595 +v 67.7572 32.0363 35.9309 +v 37.0522 -32.0363 67.1506 +v 70.7545 -32.0363 29.595 +v 67.7572 -32.0363 35.9309 +v 5.94325 32.0363 76.464 +v 5.94325 -32.0363 76.464 +v -1.06233 32.0363 76.6873 +v -1.06233 -32.0363 76.6873 +v 64.1939 32.0363 41.9667 +v 24.2247 32.0363 72.7683 +v 64.1939 -32.0363 41.9667 +v 24.2247 -32.0363 72.7683 +v -12.6897 32.0363 75.6376 +v -12.6897 -32.0363 75.6376 +v 12.8992 32.0363 75.6021 +v 12.8992 -32.0363 75.6021 +v 61.5186 32.0363 45.7989 +v 52.1656 32.0363 56.2211 +v 48.6443 32.0363 59.2942 +v 61.5186 -32.0363 45.7989 +v 52.1656 -32.0363 56.2211 +v 48.6443 -32.0363 59.2942 +v -8.05903 32.0363 76.2701 +v -8.05903 -32.0363 76.2701 +v 15.1967 32.0363 75.174 +v 15.1967 -32.0363 75.174 +v 62.8854 32.0363 43.9032 +v 41.0735 32.0363 64.7691 +v 30.7669 32.0363 70.2529 +v 62.8854 -32.0363 43.9032 +v 41.0735 -32.0363 64.7691 +v 30.7669 -32.0363 70.2529 +v 69.82 32.0363 31.7371 +v 69.82 -32.0363 31.7371 +v 53.8544 32.0363 54.6056 +v 46.8151 32.0363 60.7488 +v 53.8544 -32.0363 54.6056 +v 46.8151 -32.0363 60.7488 +v 1.27477 32.0363 76.6841 +v 1.27477 -32.0363 76.6841 +v 39.081 32.0363 65.9905 +v 65.4428 32.0363 39.9913 +v 65.4428 -32.0363 39.9913 +v 39.081 -32.0363 65.9905 +v 74.4268 32.0363 18.5129 +v 74.4268 -32.0363 18.5129 +v -14.9884 32.0363 75.2158 +v -14.9884 -32.0363 75.2158 +v 58.6147 32.0363 49.4609 +v 50.4284 32.0363 57.7845 +v 44.9424 32.0363 62.147 +v 28.6121 32.0363 71.1577 +v 58.6147 -32.0363 49.4609 +v 50.4284 -32.0363 57.7845 +v 44.9424 -32.0363 62.147 +v 28.6121 -32.0363 71.1577 +v -26.2311 32.0363 72.0694 +v 73.1609 32.0363 23.0119 +v -26.2311 -32.0363 72.0694 +v 73.1609 -32.0363 23.0119 +v 32.8932 32.0363 69.2828 +v 32.8932 -32.0363 69.2828 +v 8.2703 32.0363 76.2474 +v 8.2703 -32.0363 76.2474 +v 21.9963 32.0363 73.4727 +v 17.4802 32.0363 74.676 +v 21.9963 -32.0363 73.4727 +v 17.4802 -32.0363 74.676 +v 75.4162 32.0363 13.9452 +v 75.4162 -32.0363 13.9452 +v 76.6946 32.0363 0 +v 68.8205 32.0363 33.8497 +v 76.6946 -32.0363 0 +v 68.8205 -32.0363 33.8497 +v -17.2732 32.0363 74.7242 +v -17.2732 -32.0363 74.7242 +v 76.3744 32.0363 7.00182 +v 76.3744 -32.0363 7.00182 +v -10.3792 32.0363 75.9891 +v -10.3792 -32.0363 75.9891 +v 66.631 32.0363 37.9787 +v 66.631 -32.0363 37.9787 +v 72.4258 32.0363 25.2303 +v 71.6234 32.0363 27.4254 +v 72.4258 -32.0363 25.2303 +v 71.6234 -32.0363 27.4254 +v 34.9889 32.0363 68.2484 +v 34.9889 -32.0363 68.2484 +v 76.659 32.0363 2.33683 +v 76.659 -32.0363 2.33683 +v 73.8281 32.0363 20.772 +v 73.8281 -32.0363 20.772 +v -19.542 32.0363 74.1632 +v -19.542 -32.0363 74.1632 +v 60.0945 32.0363 47.652 +v 43.0279 32.0363 63.4875 +v 60.0945 -32.0363 47.652 +v 43.0279 -32.0363 63.4875 +v 74.9563 32.0363 16.2365 +v 74.9563 -32.0363 16.2365 +v 57.0805 32.0363 51.2239 +v -21.7926 32.0363 73.5333 +v 57.0805 -32.0363 51.2239 +v -21.7926 -32.0363 73.5333 +v -3.39844 32.0363 76.6193 +v -3.39844 -32.0363 76.6193 +v 76.5523 32.0363 4.67149 +v 76.5523 -32.0363 4.67149 +v 75.8061 32.0363 11.6408 +v 75.8061 -32.0363 11.6408 +v 6.07859 35.7675 78.2051 +v 6.07859 -35.7675 78.2051 +v -5.86191 35.7675 78.2217 +v -5.86191 -35.7675 78.2217 +v -15.3297 35.7675 76.9285 +v -15.3297 -35.7675 76.9285 +v 17.8782 35.7675 76.3765 +v 17.8782 -35.7675 76.3765 +v 8.45862 35.7675 77.9836 +v 8.45862 -35.7675 77.9836 +v 74.8269 35.7675 23.5359 +v 72.3657 35.7675 30.2689 +v 74.8269 -35.7675 23.5359 +v 72.3657 -35.7675 30.2689 +v -17.6666 35.7675 76.4257 +v -17.6666 -35.7675 76.4257 +v -26.8284 35.7675 73.7105 +v -26.8284 -35.7675 73.7105 +v 77.1335 35.7675 14.2627 +v 77.1335 -35.7675 14.2627 +v -8.24254 35.7675 78.0068 +v -8.24254 -35.7675 78.0068 +v 10.8308 35.7675 77.6897 +v 10.8308 -35.7675 77.6897 +v 74.075 35.7675 25.8048 +v 74.075 -35.7675 25.8048 +v -19.987 35.7675 75.8519 +v -19.987 -35.7675 75.8519 +v 68.1482 35.7675 38.8435 +v 64.3174 35.7675 44.9029 +v 61.4629 35.7675 48.7371 +v 68.1482 -35.7675 38.8435 +v 64.3174 -35.7675 44.9029 +v 61.4629 -35.7675 48.7371 +v 73.2543 35.7675 28.0499 +v -3.47583 35.7675 78.364 +v 73.2543 -35.7675 28.0499 +v -3.47583 -35.7675 78.364 +v 78.1135 35.7675 7.16125 +v 78.1135 -35.7675 7.16125 +v 78.2954 35.7675 4.77786 +v 78.2954 -35.7675 4.77786 +v 75.5092 35.7675 21.245 +v 69.3001 35.7675 36.7491 +v 29.2636 35.7675 72.778 +v 24.7763 35.7675 74.4253 +v 75.5092 -35.7675 21.245 +v 69.3001 -35.7675 36.7491 +v 29.2636 -35.7675 72.778 +v 24.7763 -35.7675 74.4253 +v 78.441 35.7675 0 +v 70.3876 35.7675 34.6205 +v 62.9194 35.7675 46.8417 +v 59.9494 35.7675 50.5872 +v 55.0807 35.7675 55.849 +v 47.8811 35.7675 62.1321 +v 45.9657 35.7675 63.5622 +v 44.0077 35.7675 64.9332 +v 31.4675 35.7675 71.8526 +v 78.441 -35.7675 0 +v 70.3876 -35.7675 34.6205 +v 62.9194 -35.7675 46.8417 +v 59.9494 -35.7675 50.5872 +v 55.0807 -35.7675 55.849 +v 47.8811 -35.7675 62.1321 +v 45.9657 -35.7675 63.5622 +v 44.0077 -35.7675 64.9332 +v 31.4675 -35.7675 71.8526 +v 76.6631 35.7675 16.6063 +v 76.6631 -35.7675 16.6063 +v 1.3038 35.7675 78.4302 +v 1.3038 -35.7675 78.4302 +v 15.5428 35.7675 76.8857 +v 15.5428 -35.7675 76.8857 +v 77.5322 35.7675 11.9059 +v 58.3802 35.7675 52.3903 +v 56.7568 35.7675 54.1448 +v 51.5767 35.7675 59.1003 +v 49.752 35.7675 60.6444 +v 77.5322 -35.7675 11.9059 +v 58.3802 -35.7675 52.3903 +v 56.7568 -35.7675 54.1448 +v 51.5767 -35.7675 59.1003 +v 49.752 -35.7675 60.6444 +v -24.57 35.7675 74.4937 +v 27.0325 35.7675 73.6359 +v 20.1971 35.7675 75.7963 +v -24.57 -35.7675 74.4937 +v 27.0325 -35.7675 73.6359 +v 20.1971 -35.7675 75.7963 +v -1.08652 35.7675 78.4335 +v -1.08652 -35.7675 78.4335 +v 3.69291 35.7675 78.3541 +v 3.69291 -35.7675 78.3541 +v 71.4098 35.7675 32.4597 +v 71.4098 -35.7675 32.4597 +v 13.1929 35.7675 77.3236 +v 13.1929 -35.7675 77.3236 +v 53.3535 35.7675 57.5014 +v 33.6422 35.7675 70.8604 +v 53.3535 -35.7675 57.5014 +v 33.6422 -35.7675 70.8604 +v -12.9787 35.7675 77.3599 +v -12.9787 -35.7675 77.3599 +v 77.859 35.7675 9.53799 +v 77.859 -35.7675 9.53799 +v 65.6557 35.7675 42.9223 +v 42.0088 35.7675 66.2439 +v 65.6557 -35.7675 42.9223 +v 42.0088 -35.7675 66.2439 +v 39.9709 35.7675 67.4931 +v 35.7856 35.7675 69.8025 +v 66.933 35.7675 40.9019 +v 22.4971 35.7675 75.1457 +v 35.7856 -35.7675 69.8025 +v 66.933 -35.7675 40.9019 +v 39.9709 -35.7675 67.4931 +v 22.4971 -35.7675 75.1457 +v 78.4046 35.7675 2.39004 +v 78.4046 -35.7675 2.39004 +v -10.6155 35.7675 77.7194 +v -10.6155 -35.7675 77.7194 +v 37.8959 35.7675 68.6797 +v 37.8959 -35.7675 68.6797 +v -22.2889 35.7675 75.2077 +v -22.2889 -35.7675 75.2077 +v 76.1215 35.7675 18.9344 +v 76.1215 -35.7675 18.9344 +v 77.373 39.4039 21.7694 +v 77.373 -39.4039 21.7694 +v -22.839 39.4039 77.0641 +v -22.839 -39.4039 77.0641 +v 69.8303 39.4039 39.8023 +v 61.4291 39.4039 51.8358 +v 69.8303 -39.4039 39.8023 +v 61.4291 -39.4039 51.8358 +v -20.4803 39.4039 77.7242 +v -20.4803 -39.4039 77.7242 +v -15.7081 39.4039 78.8273 +v -15.7081 -39.4039 78.8273 +v -13.299 39.4039 79.2693 +v -13.299 -39.4039 79.2693 +v 34.4726 39.4039 72.6095 +v 34.4726 -39.4039 72.6095 +v 1.33598 39.4039 80.3661 +v 1.33598 -39.4039 80.3661 +v 64.4724 39.4039 47.9979 +v 52.8497 39.4039 60.5591 +v 64.4724 -39.4039 47.9979 +v 52.8497 -39.4039 60.5591 +v 27.6998 39.4039 75.4534 +v 27.6998 -39.4039 75.4534 +v 76.6738 39.4039 24.1168 +v 76.6738 -39.4039 24.1168 +v 58.1577 39.4039 55.4813 +v 54.6704 39.4039 58.9206 +v 58.1577 -39.4039 55.4813 +v 54.6704 -39.4039 58.9206 +v 11.0981 39.4039 79.6073 +v 11.0981 -39.4039 79.6073 +v 79.7808 39.4039 9.77341 +v 25.3879 39.4039 76.2624 +v 79.7808 -39.4039 9.77341 +v 25.3879 -39.4039 76.2624 +v -6.00659 39.4039 80.1524 +v -6.00659 -39.4039 80.1524 +v 38.8312 39.4039 70.3749 +v 38.8312 -39.4039 70.3749 +v -18.1026 39.4039 78.3121 +v -18.1026 -39.4039 78.3121 +v 79.4459 39.4039 12.1997 +v 79.4459 -39.4039 12.1997 +v 80.3399 39.4039 2.44903 +v 80.3399 -39.4039 2.44903 +v 72.125 39.4039 35.475 +v 62.98 39.4039 49.9401 +v 56.4403 39.4039 57.2275 +v 47.1003 39.4039 65.1311 +v 72.125 -39.4039 35.475 +v 62.98 -39.4039 49.9401 +v 56.4403 -39.4039 57.2275 +v 47.1003 -39.4039 65.1311 +v -1.11334 39.4039 80.3695 +v -1.11334 -39.4039 80.3695 +v 15.9264 39.4039 78.7835 +v 15.9264 -39.4039 78.7835 +v -10.8776 39.4039 79.6377 +v -10.8776 -39.4039 79.6377 +v 8.6674 39.4039 79.9085 +v -8.44599 39.4039 79.9322 +v 8.6674 -39.4039 79.9085 +v -8.44599 -39.4039 79.9322 +v 78.0004 39.4039 19.4018 +v 78.0004 -39.4039 19.4018 +v 68.5851 39.4039 41.9115 +v 20.6956 39.4039 77.6671 +v 68.5851 -39.4039 41.9115 +v 20.6956 -39.4039 77.6671 +v 29.9859 39.4039 74.5744 +v 29.9859 -39.4039 74.5744 +v 80.3772 39.4039 0 +v 79.0373 39.4039 14.6147 +v 67.2763 39.4039 43.9818 +v 59.8212 39.4039 53.6835 +v 50.98 39.4039 62.1412 +v 43.0457 39.4039 67.879 +v 80.3772 -39.4039 0 +v 79.0373 -39.4039 14.6147 +v 67.2763 -39.4039 43.9818 +v 59.8212 -39.4039 53.6835 +v 50.98 -39.4039 62.1412 +v 43.0457 -39.4039 67.879 +v 75.0625 39.4039 28.7422 +v 75.0625 -39.4039 28.7422 +v -3.56162 39.4039 80.2982 +v -3.56162 -39.4039 80.2982 +v 32.2442 39.4039 73.6261 +v 32.2442 -39.4039 73.6261 +v -25.1765 39.4039 76.3324 +v -25.1765 -39.4039 76.3324 +v 80.0415 39.4039 7.33801 +v 80.0415 -39.4039 7.33801 +v -27.4906 39.4039 75.5298 +v 75.9034 39.4039 26.4418 +v 65.9049 39.4039 46.0112 +v 49.0629 39.4039 63.6657 +v -27.4906 -39.4039 75.5298 +v 75.9034 -39.4039 26.4418 +v 65.9049 -39.4039 46.0112 +v 49.0629 -39.4039 63.6657 +v 6.22862 39.4039 80.1355 +v 6.22862 -39.4039 80.1355 +v 78.5553 39.4039 17.0162 +v 74.1519 39.4039 31.016 +v 45.0939 39.4039 66.5359 +v 78.5553 -39.4039 17.0162 +v 74.1519 -39.4039 31.016 +v 45.0939 -39.4039 66.5359 +v 18.3195 39.4039 78.2617 +v 18.3195 -39.4039 78.2617 +v 13.5186 39.4039 79.2322 +v 13.5186 -39.4039 79.2322 +v 80.2279 39.4039 4.8958 +v 80.2279 -39.4039 4.8958 +v 36.6689 39.4039 71.5254 +v 73.1724 39.4039 33.2609 +v 36.6689 -39.4039 71.5254 +v 73.1724 -39.4039 33.2609 +v 40.9575 39.4039 69.1591 +v 40.9575 -39.4039 69.1591 +v 3.78406 39.4039 80.2881 +v 3.78406 -39.4039 80.2881 +v 23.0524 39.4039 77.0005 +v 23.0524 -39.4039 77.0005 +v 71.0106 39.4039 37.6561 +v 71.0106 -39.4039 37.6561 +v 82.1534 42.9357 7.53163 +v 82.1534 -42.9357 7.53163 +v 81.5421 42.9357 12.5216 +v 81.5421 -42.9357 12.5216 +v 80.628 42.9357 17.4651 +v 80.628 -42.9357 17.4651 +v 13.8752 42.9357 81.3227 +v 13.8752 -42.9357 81.3227 +v 61.3996 42.9357 55.0999 +v 61.3996 -42.9357 55.0999 +v -25.8408 42.9357 78.3464 +v -25.8408 -42.9357 78.3464 +v 69.0514 42.9357 45.1422 +v 69.0514 -42.9357 45.1422 +v -8.66884 42.9357 82.0412 +v -8.66884 -42.9357 82.0412 +v 18.8029 42.9357 80.3266 +v 18.8029 -42.9357 80.3266 +v -13.6499 42.9357 81.3609 +v -13.6499 -42.9357 81.3609 +v 66.1735 42.9357 49.2644 +v 66.1735 -42.9357 49.2644 +v 82.4596 42.9357 2.51365 +v 82.4596 -42.9357 2.51365 +v 80.0585 42.9357 19.9137 +v 80.0585 -42.9357 19.9137 +v 78.6969 42.9357 24.7531 +v 23.6607 42.9357 79.0322 +v 78.6969 -42.9357 24.7531 +v 23.6607 -42.9357 79.0322 +v 3.8839 42.9357 82.4065 +v 3.8839 -42.9357 82.4065 +v -28.216 42.9357 77.5227 +v 81.1228 42.9357 15.0003 +v 64.6417 42.9357 51.2578 +v 33.095 42.9357 75.5687 +v -23.4416 42.9357 79.0974 +v -28.216 -42.9357 77.5227 +v 81.1228 -42.9357 15.0003 +v 64.6417 -42.9357 51.2578 +v 33.095 -42.9357 75.5687 +v -23.4416 -42.9357 79.0974 +v 8.89609 42.9357 82.0169 +v 8.89609 -42.9357 82.0169 +v 75.1031 42.9357 34.1385 +v 74.028 42.9357 36.411 +v 28.4306 42.9357 77.4443 +v 75.1031 -42.9357 34.1385 +v 74.028 -42.9357 36.411 +v 28.4306 -42.9357 77.4443 +v 6.39297 42.9357 82.2499 +v 6.39297 -42.9357 82.2499 +v 1.37123 42.9357 82.4866 +v 1.37123 -42.9357 82.4866 +v -6.16508 42.9357 82.2673 +v -6.16508 -42.9357 82.2673 +v 77.9061 42.9357 27.1395 +v 72.8842 42.9357 38.6497 +v 77.9061 -42.9357 27.1395 +v 72.8842 -42.9357 38.6497 +v 11.391 42.9357 81.7078 +v 11.391 -42.9357 81.7078 +v -3.65559 42.9357 82.4169 +v -3.65559 -42.9357 82.4169 +v 42.0382 42.9357 70.9838 +v 42.0382 -42.9357 70.9838 +v 63.0499 42.9357 53.2035 +v 59.6922 42.9357 56.9451 +v 57.9295 42.9357 58.7375 +v 56.1129 42.9357 60.4753 +v 30.7771 42.9357 76.542 +v 21.2416 42.9357 79.7164 +v -16.1226 42.9357 80.9072 +v 63.0499 -42.9357 53.2035 +v 59.6922 -42.9357 56.9451 +v 57.9295 -42.9357 58.7375 +v 56.1129 -42.9357 60.4753 +v 30.7771 -42.9357 76.542 +v 21.2416 -42.9357 79.7164 +v -16.1226 -42.9357 80.9072 +v 77.043 42.9357 29.5006 +v 77.043 -42.9357 29.5006 +v 81.8858 42.9357 10.0313 +v 81.8858 -42.9357 10.0313 +v 82.3448 42.9357 5.02497 +v 82.3448 -42.9357 5.02497 +v 70.3948 42.9357 43.0173 +v 54.2442 42.9357 62.1569 +v 52.3251 42.9357 63.7808 +v 46.2837 42.9357 68.2915 +v 44.1815 42.9357 69.67 +v 26.0578 42.9357 78.2746 +v 70.3948 -42.9357 43.0173 +v 54.2442 -42.9357 62.1569 +v 52.3251 -42.9357 63.7808 +v 46.2837 -42.9357 68.2915 +v 44.1815 -42.9357 69.67 +v 26.0578 -42.9357 78.2746 +v -21.0207 42.9357 79.7749 +v -21.0207 -42.9357 79.7749 +v 16.3466 42.9357 80.8622 +v 16.3466 -42.9357 80.8622 +v 76.1084 42.9357 31.8344 +v -1.14271 42.9357 82.49 +v 76.1084 -42.9357 31.8344 +v -1.14271 -42.9357 82.49 +v 67.6439 42.9357 47.2252 +v 67.6439 -42.9357 47.2252 +v -11.1646 42.9357 81.739 +v -11.1646 -42.9357 81.739 +v 71.6728 42.9357 40.8525 +v 71.6728 -42.9357 40.8525 +v 50.3575 42.9357 65.3455 +v 48.343 42.9357 66.8496 +v 50.3575 -42.9357 65.3455 +v 48.343 -42.9357 66.8496 +v 35.3821 42.9357 74.5253 +v 35.3821 -42.9357 74.5253 +v 79.4145 42.9357 22.3438 +v -18.5803 42.9357 80.3784 +v 79.4145 -42.9357 22.3438 +v -18.5803 -42.9357 80.3784 +v 82.498 42.9357 0 +v 39.8558 42.9357 72.2318 +v 37.6365 42.9357 73.4126 +v 82.498 -42.9357 0 +v 37.6365 -42.9357 73.4126 +v 39.8558 -42.9357 72.2318 +v 3.99217 46.3537 84.7037 +v 3.99217 -46.3537 84.7037 +v 34.0176 46.3537 77.6753 +v 34.0176 -46.3537 77.6753 +v 82.8757 46.3537 17.952 +v 82.8757 -46.3537 17.952 +v 49.6907 46.3537 68.7131 +v 26.7841 46.3537 80.4566 +v 49.6907 -46.3537 68.7131 +v 26.7841 -46.3537 80.4566 +v -26.5612 46.3537 80.5305 +v -26.5612 -46.3537 80.5305 +v 73.6708 46.3537 41.9913 +v 73.6708 -46.3537 41.9913 +v 79.1907 46.3537 30.323 +v 47.574 46.3537 70.1952 +v 79.1907 -46.3537 30.323 +v 47.574 -46.3537 70.1952 +v 38.6856 46.3537 75.4591 +v 24.3203 46.3537 81.2353 +v 38.6856 -46.3537 75.4591 +v 24.3203 -46.3537 81.2353 +v 84.7977 46.3537 0 +v 80.0779 46.3537 27.896 +v 84.7977 -46.3537 0 +v 80.0779 -46.3537 27.896 +v 21.8338 46.3537 81.9386 +v 14.262 46.3537 83.5898 +v 21.8338 -46.3537 81.9386 +v 14.262 -46.3537 83.5898 +v 84.6403 46.3537 5.16505 +v 84.6403 -46.3537 5.16505 +v -3.7575 46.3537 84.7144 +v -3.7575 -46.3537 84.7144 +v 78.23 46.3537 32.7218 +v 16.8023 46.3537 83.1164 +v 78.23 -46.3537 32.7218 +v 16.8023 -46.3537 83.1164 +v 19.327 46.3537 82.5659 +v 19.327 -46.3537 82.5659 +v 83.8153 46.3537 12.8707 +v 72.3571 46.3537 44.2165 +v 36.3685 46.3537 76.6028 +v 83.8153 -46.3537 12.8707 +v 72.3571 -46.3537 44.2165 +v 36.3685 -46.3537 76.6028 +v 83.3842 46.3537 15.4185 +v 70.9763 46.3537 46.4007 +v 57.6771 46.3537 62.1611 +v 51.7613 46.3537 67.1672 +v 45.4131 46.3537 71.6122 +v 83.3842 -46.3537 15.4185 +v 70.9763 -46.3537 46.4007 +v 57.6771 -46.3537 62.1611 +v 51.7613 -46.3537 67.1672 +v 45.4131 -46.3537 71.6122 +v 9.14409 46.3537 84.3033 +v -8.9105 46.3537 84.3283 +v 9.14409 -46.3537 84.3033 +v -8.9105 -46.3537 84.3283 +v 11.7085 46.3537 83.9855 +v 11.7085 -46.3537 83.9855 +v 40.9669 46.3537 74.2454 +v 76.0917 46.3537 37.426 +v 31.6351 46.3537 78.6758 +v 40.9669 -46.3537 74.2454 +v 76.0917 -46.3537 37.426 +v 31.6351 -46.3537 78.6758 +v -14.0304 46.3537 83.629 +v -14.0304 -46.3537 83.629 +v -1.17456 46.3537 84.7896 +v -1.17456 -46.3537 84.7896 +v 43.21 46.3537 72.9626 +v 82.2902 46.3537 20.4688 +v 74.916 46.3537 39.7271 +v 68.0182 46.3537 50.6377 +v 64.8076 46.3537 54.6867 +v 63.1112 46.3537 56.6359 +v 82.2902 -46.3537 20.4688 +v 74.916 -46.3537 39.7271 +v 68.0182 -46.3537 50.6377 +v 64.8076 -46.3537 54.6867 +v 63.1112 -46.3537 56.6359 +v 43.21 -46.3537 72.9626 +v 1.40946 46.3537 84.786 +v 1.40946 -46.3537 84.786 +v 6.57118 46.3537 84.5427 +v 6.57118 -46.3537 84.5427 +v 84.7584 46.3537 2.58373 +v 84.7584 -46.3537 2.58373 +v 80.8907 46.3537 25.4431 +v 80.8907 -46.3537 25.4431 +v 84.4436 46.3537 7.74158 +v 84.4436 -46.3537 7.74158 +v 69.5295 46.3537 48.5417 +v 61.3563 46.3537 58.5326 +v 69.5295 -46.3537 48.5417 +v 61.3563 -46.3537 58.5326 +v -24.0951 46.3537 81.3024 +v -24.0951 -46.3537 81.3024 +v -6.33694 46.3537 84.5606 +v -6.33694 -46.3537 84.5606 +v 77.1967 46.3537 35.0902 +v 77.1967 -46.3537 35.0902 +v -29.0025 46.3537 79.6838 +v 81.6284 46.3537 22.9667 +v 29.2232 46.3537 79.6031 +v -29.0025 -46.3537 79.6838 +v 81.6284 -46.3537 22.9667 +v 29.2232 -46.3537 79.6031 +v -19.0982 46.3537 82.6191 +v -19.0982 -46.3537 82.6191 +v 59.5443 46.3537 60.3749 +v 55.7563 46.3537 63.8897 +v 59.5443 -46.3537 60.3749 +v 55.7563 -46.3537 63.8897 +v -21.6067 46.3537 81.9988 +v -21.6067 -46.3537 81.9988 +v -11.4758 46.3537 84.0176 +v -11.4758 -46.3537 84.0176 +v 53.7838 46.3537 65.5589 +v 53.7838 -46.3537 65.5589 +v 66.4438 46.3537 52.6866 +v 66.4438 -46.3537 52.6866 +v 84.1685 46.3537 10.3109 +v 84.1685 -46.3537 10.3109 +v -16.572 46.3537 83.1626 +v -16.572 -46.3537 83.1626 +v 79.4477 49.6488 36.1134 +v 79.4477 -49.6488 36.1134 +v 64.9515 49.6488 58.2874 +v 64.9515 -49.6488 58.2874 +v -22.2367 49.6488 84.3899 +v -22.2367 -49.6488 84.3899 +v 39.8137 49.6488 77.6595 +v 39.8137 -49.6488 77.6595 +v -3.86707 49.6488 87.1847 +v -3.86707 -49.6488 87.1847 +v 19.8906 49.6488 84.9735 +v -24.7977 49.6488 83.6732 +v 19.8906 -49.6488 84.9735 +v -24.7977 -49.6488 83.6732 +v -11.8104 49.6488 86.4676 +v -11.8104 -49.6488 86.4676 +v 73.0459 49.6488 47.7537 +v 66.6973 49.6488 56.2813 +v 61.2806 49.6488 62.1354 +v 73.0459 -49.6488 47.7537 +v 66.6973 -49.6488 56.2813 +v 61.2806 -49.6488 62.1354 +v -14.4395 49.6488 86.0676 +v -14.4395 -49.6488 86.0676 +v 12.0499 49.6488 86.4345 +v 12.0499 -49.6488 86.4345 +v -29.8482 49.6488 82.0074 +v -19.6551 49.6488 85.0282 +v -29.8482 -49.6488 82.0074 +v -19.6551 -49.6488 85.0282 +v 71.557 49.6488 49.9572 +v 57.3822 49.6488 65.7527 +v 37.429 49.6488 78.8365 +v 32.5575 49.6488 80.9699 +v 71.557 -49.6488 49.9572 +v 57.3822 -49.6488 65.7527 +v 37.429 -49.6488 78.8365 +v 32.5575 -49.6488 80.9699 +v 83.2494 49.6488 26.1851 +v 25.0294 49.6488 83.6041 +v 83.2494 -49.6488 26.1851 +v 25.0294 -49.6488 83.6041 +v -9.17033 49.6488 86.7873 +v -9.17033 -49.6488 86.7873 +v 27.5652 49.6488 82.8027 +v 27.5652 -49.6488 82.8027 +v 87.2299 49.6488 2.65907 +v 87.2299 -49.6488 2.65907 +v 14.6779 49.6488 86.0272 +v 14.6779 -49.6488 86.0272 +v 87.2704 49.6488 0 +v 75.819 49.6488 43.2158 +v 74.467 49.6488 45.5059 +v 59.359 49.6488 63.9737 +v 87.2704 -49.6488 0 +v 75.819 -49.6488 43.2158 +v 74.467 -49.6488 45.5059 +v 59.359 -49.6488 63.9737 +v 85.8157 49.6488 15.8681 +v 85.8157 -49.6488 15.8681 +v 6.7628 49.6488 87.008 +v 6.7628 -49.6488 87.008 +v 84.6898 49.6488 21.0657 +v 84.6898 -49.6488 21.0657 +v 1.45056 49.6488 87.2584 +v 1.45056 -49.6488 87.2584 +v 78.3105 49.6488 38.5174 +v 78.3105 -49.6488 38.5174 +v 17.2923 49.6488 85.5401 +v 17.2923 -49.6488 85.5401 +v -6.52173 49.6488 87.0264 +v -6.52173 -49.6488 87.0264 +v -17.0553 49.6488 85.5876 +v -17.0553 -49.6488 85.5876 +v 42.1614 49.6488 76.4103 +v 68.3812 49.6488 54.223 +v 63.1454 49.6488 60.2394 +v 55.3521 49.6488 67.4705 +v 51.1397 49.6488 70.7168 +v 35.0095 49.6488 79.9404 +v 42.1614 -49.6488 76.4103 +v 68.3812 -49.6488 54.223 +v 63.1454 -49.6488 60.2394 +v 55.3521 -49.6488 67.4705 +v 51.1397 -49.6488 70.7168 +v 35.0095 -49.6488 79.9404 +v 86.906 49.6488 7.96733 +v 86.906 -49.6488 7.96733 +v 84.0086 49.6488 23.6364 +v 84.0086 -49.6488 23.6364 +v 30.0753 49.6488 81.9244 +v 30.0753 -49.6488 81.9244 +v 48.9612 49.6488 72.2421 +v 48.9612 -49.6488 72.2421 +v 4.10858 49.6488 87.1737 +v 4.10858 -49.6488 87.1737 +v 82.4129 49.6488 28.7095 +v 82.4129 -49.6488 28.7095 +v 22.4705 49.6488 84.328 +v 22.4705 -49.6488 84.328 +v 53.2706 49.6488 69.1257 +v 46.7373 49.6488 73.7004 +v 53.2706 -49.6488 69.1257 +v 46.7373 -49.6488 73.7004 +v -1.20881 49.6488 87.262 +v -1.20881 -49.6488 87.262 +v 86.6229 49.6488 10.6116 +v 86.6229 -49.6488 10.6116 +v 77.1006 49.6488 40.8856 +v 77.1006 -49.6488 40.8856 +v 44.47 49.6488 75.0902 +v 80.5112 49.6488 33.6759 +v 70.0016 49.6488 52.1143 +v 80.5112 -49.6488 33.6759 +v 70.0016 -49.6488 52.1143 +v 44.47 -49.6488 75.0902 +v 87.1084 49.6488 5.31566 +v 87.1084 -49.6488 5.31566 +v 85.2923 49.6488 18.4755 +v 85.2923 -49.6488 18.4755 +v -27.3357 49.6488 82.8788 +v 81.4999 49.6488 31.2072 +v -27.3357 -49.6488 82.8788 +v 81.4999 -49.6488 31.2072 +v 9.41073 49.6488 86.7615 +v 9.41073 -49.6488 86.7615 +v 86.2593 49.6488 13.246 +v 86.2593 -49.6488 13.246 +v 87.8715 52.8122 19.0342 +v 87.8715 -52.8122 19.0342 +v -20.2495 52.8122 87.5995 +v -20.2495 -52.8122 87.5995 +v -25.5476 52.8122 86.2034 +v -25.5476 -52.8122 86.2034 +v 43.4364 52.8122 78.7209 +v 59.1174 52.8122 67.741 +v 43.4364 -52.8122 78.7209 +v 59.1174 -52.8122 67.741 +v 6.9673 52.8122 89.6391 +v 6.9673 -52.8122 89.6391 +v 68.7143 52.8122 57.9833 +v 36.0682 52.8122 82.3577 +v 68.7143 -52.8122 57.9833 +v 36.0682 -52.8122 82.3577 +v 66.9156 52.8122 60.05 +v 54.8815 52.8122 71.2161 +v 66.9156 -52.8122 60.05 +v 54.8815 -52.8122 71.2161 +v 15.1218 52.8122 88.6287 +v 15.1218 -52.8122 88.6287 +v 89.8677 52.8122 2.73948 +v 89.8677 -52.8122 2.73948 +v 17.8152 52.8122 88.1268 +v -22.9092 52.8122 86.9418 +v 17.8152 -52.8122 88.1268 +v -22.9092 -52.8122 86.9418 +v 89.534 52.8122 8.20826 +v 89.534 -52.8122 8.20826 +v 73.7209 52.8122 51.4679 +v 72.1184 52.8122 53.6902 +v 61.1539 52.8122 65.9083 +v 50.4418 52.8122 74.4267 +v 73.7209 -52.8122 51.4679 +v 72.1184 -52.8122 53.6902 +v 61.1539 -52.8122 65.9083 +v 50.4418 -52.8122 74.4267 +v -9.44764 52.8122 89.4117 +v -9.44764 -52.8122 89.4117 +v 83.9644 52.8122 32.1509 +v 79.4321 52.8122 42.1219 +v 78.1117 52.8122 44.5226 +v 83.9644 -52.8122 32.1509 +v 79.4321 -52.8122 42.1219 +v 78.1117 -52.8122 44.5226 +v -1.24537 52.8122 89.9008 +v -1.24537 -52.8122 89.9008 +v -12.1676 52.8122 89.0823 +v -12.1676 -52.8122 89.0823 +v 82.9458 52.8122 34.6943 +v 76.7189 52.8122 46.882 +v 75.2548 52.8122 49.1978 +v 57.0259 52.8122 69.5108 +v 82.9458 -52.8122 34.6943 +v 76.7189 -52.8122 46.882 +v 75.2548 -52.8122 49.1978 +v 57.0259 -52.8122 69.5108 +v -17.571 52.8122 88.1758 +v -17.571 -52.8122 88.1758 +v 12.4143 52.8122 89.0483 +v 12.4143 -52.8122 89.0483 +v -30.7508 52.8122 84.4872 +v 80.6786 52.8122 39.6821 +v 20.4921 52.8122 87.543 +v -30.7508 -52.8122 84.4872 +v 80.6786 -52.8122 39.6821 +v 20.4921 -52.8122 87.543 +v -28.1623 52.8122 85.385 +v -28.1623 -52.8122 85.385 +v 89.9094 52.8122 0 +v 86.549 52.8122 24.3511 +v 81.8502 52.8122 37.2055 +v 38.5608 52.8122 81.2205 +v 89.9094 -52.8122 0 +v 86.549 -52.8122 24.3511 +v 81.8502 -52.8122 37.2055 +v 38.5608 -52.8122 81.2205 +v 88.8678 52.8122 13.6466 +v 88.8678 -52.8122 13.6466 +v -6.71894 52.8122 89.658 +v -6.71894 -52.8122 89.658 +v 85.7669 52.8122 26.9769 +v 25.7863 52.8122 86.1323 +v 85.7669 -52.8122 26.9769 +v 25.7863 -52.8122 86.1323 +v -3.984 52.8122 89.8211 +v -3.984 -52.8122 89.8211 +v 45.8148 52.8122 77.3609 +v 48.1507 52.8122 75.9291 +v 48.1507 -52.8122 75.9291 +v 45.8148 -52.8122 77.3609 +v -14.8762 52.8122 88.6702 +v -14.8762 -52.8122 88.6702 +v 4.23283 52.8122 89.8098 +v 4.23283 -52.8122 89.8098 +v 89.7425 52.8122 5.47641 +v 89.7425 -52.8122 5.47641 +v 41.0177 52.8122 80.0079 +v 41.0177 -52.8122 80.0079 +v 9.6953 52.8122 89.3852 +v 9.6953 -52.8122 89.3852 +v 65.0549 52.8122 62.061 +v 63.1337 52.8122 64.0144 +v 33.5421 52.8122 83.4185 +v 65.0549 -52.8122 62.061 +v 63.1337 -52.8122 64.0144 +v 33.5421 -52.8122 83.4185 +v 89.2423 52.8122 10.9325 +v 89.2423 -52.8122 10.9325 +v 84.9051 52.8122 29.5776 +v 84.9051 -52.8122 29.5776 +v 52.6861 52.8122 72.8552 +v 52.6861 -52.8122 72.8552 +v 87.2508 52.8122 21.7027 +v 87.2508 -52.8122 21.7027 +v 30.9848 52.8122 84.4017 +v 30.9848 -52.8122 84.4017 +v 70.4491 52.8122 55.8627 +v 23.15 52.8122 86.878 +v 70.4491 -52.8122 55.8627 +v 23.15 -52.8122 86.878 +v 1.49442 52.8122 89.897 +v 1.49442 -52.8122 89.897 +v 88.4107 52.8122 16.348 +v 88.4107 -52.8122 16.348 +v 28.3987 52.8122 85.3066 +v 28.3987 -52.8122 85.3066 +v 1.54094 55.8355 92.695 +v 1.54094 -55.8355 92.695 +v 92.7078 55.8355 0 +v 92.7078 -55.8355 0 +v 83.1897 55.8355 40.9172 +v 83.1897 -55.8355 40.9172 +v 91.6337 55.8355 14.0713 +v 91.6337 -55.8355 14.0713 +v -26.3428 55.8355 88.8864 +v -26.3428 -55.8355 88.8864 +v 81.9043 55.8355 43.4329 +v 81.9043 -55.8355 43.4329 +v 4.36457 55.8355 92.605 +v 4.36457 -55.8355 92.605 +v -29.0388 55.8355 88.0425 +v 77.5971 55.8355 50.729 +v 72.6417 55.8355 57.6014 +v 60.9574 55.8355 69.8494 +v -29.0388 -55.8355 88.0425 +v 77.5971 -55.8355 50.729 +v 72.6417 -55.8355 57.6014 +v 60.9574 -55.8355 69.8494 +v 15.5924 55.8355 91.3872 +v 15.5924 -55.8355 91.3872 +v 31.9492 55.8355 87.0287 +v 31.9492 -55.8355 87.0287 +v 89.2428 55.8355 25.109 +v 85.5275 55.8355 35.7741 +v 80.5429 55.8355 45.9084 +v 49.6493 55.8355 78.2923 +v 89.2428 -55.8355 25.109 +v 85.5275 -55.8355 35.7741 +v 80.5429 -55.8355 45.9084 +v 49.6493 -55.8355 78.2923 +v -6.92806 55.8355 92.4486 +v -6.92806 -55.8355 92.4486 +v 21.1299 55.8355 90.2678 +v 21.1299 -55.8355 90.2678 +v -15.3392 55.8355 91.43 +v -15.3392 -55.8355 91.43 +v -18.1179 55.8355 90.9202 +v -18.1179 -55.8355 90.9202 +v 12.8007 55.8355 91.8198 +v 12.8007 -55.8355 91.8198 +v 42.2943 55.8355 82.4981 +v 87.5477 55.8355 30.4982 +v 39.761 55.8355 83.7485 +v 42.2943 -55.8355 82.4981 +v 87.5477 -55.8355 30.4982 +v 39.761 -55.8355 83.7485 +v 92.5357 55.8355 5.64686 +v 92.5357 -55.8355 5.64686 +v -31.7079 55.8355 87.1169 +v 44.7883 55.8355 81.1711 +v 44.7883 -55.8355 81.1711 +v -31.7079 -55.8355 87.1169 +v 23.8705 55.8355 89.582 +v -23.6222 55.8355 89.6478 +v 23.8705 -55.8355 89.582 +v -23.6222 -55.8355 89.6478 +v 76.0154 55.8355 53.0698 +v 70.853 55.8355 59.788 +v 67.0797 55.8355 63.9926 +v 63.0573 55.8355 67.9596 +v 52.0118 55.8355 76.7432 +v 76.0154 -55.8355 53.0698 +v 70.853 -55.8355 59.788 +v 67.0797 -55.8355 63.9926 +v 63.0573 -55.8355 67.9596 +v 52.0118 -55.8355 76.7432 +v 18.3697 55.8355 90.8697 +v 18.3697 -55.8355 90.8697 +v -1.28413 55.8355 92.6989 +v -1.28413 -55.8355 92.6989 +v 91.1624 55.8355 16.8568 +v 88.4363 55.8355 27.8165 +v 91.1624 -55.8355 16.8568 +v 88.4363 -55.8355 27.8165 +v 92.6648 55.8355 2.82474 +v 92.6648 -55.8355 2.82474 +v 92.0199 55.8355 11.2727 +v 92.0199 -55.8355 11.2727 +v -12.5463 55.8355 91.8549 +v -12.5463 -55.8355 91.8549 +v -4.10801 55.8355 92.6168 +v -4.10801 -55.8355 92.6168 +v 79.1067 55.8355 48.3411 +v 74.3631 55.8355 55.3613 +v 68.9984 55.8355 61.919 +v 58.8008 55.8355 71.6743 +v 56.5896 55.8355 73.4326 +v 79.1067 -55.8355 48.3411 +v 74.3631 -55.8355 55.3613 +v 68.9984 -55.8355 61.919 +v 58.8008 -55.8355 71.6743 +v 56.5896 -55.8355 73.4326 +v 7.18415 55.8355 92.429 +v 7.18415 -55.8355 92.429 +v 29.2826 55.8355 87.9617 +v 29.2826 -55.8355 87.9617 +v 9.99707 55.8355 92.1672 +v 9.99707 -55.8355 92.1672 +v 65.0987 55.8355 66.0068 +v 37.1908 55.8355 84.9211 +v 65.0987 -55.8355 66.0068 +v 37.1908 -55.8355 84.9211 +v 92.3207 55.8355 8.46373 +v 92.3207 -55.8355 8.46373 +v -20.8797 55.8355 90.326 +v -20.8797 -55.8355 90.326 +v 89.9664 55.8355 22.3782 +v 89.9664 -55.8355 22.3782 +v -9.74169 55.8355 92.1946 +v -9.74169 -55.8355 92.1946 +v 86.5778 55.8355 33.1516 +v 86.5778 -55.8355 33.1516 +v 34.586 55.8355 86.0148 +v 34.586 -55.8355 86.0148 +v 84.3978 55.8355 38.3635 +v 84.3978 -55.8355 38.3635 +v 90.6065 55.8355 19.6266 +v 90.6065 -55.8355 19.6266 +v 26.5889 55.8355 88.8131 +v 26.5889 -55.8355 88.8131 +v 54.3259 55.8355 75.1228 +v 54.3259 -55.8355 75.1228 +v 47.2407 55.8355 79.7688 +v 47.2407 -55.8355 79.7688 +v 43.6403 58.7108 85.1235 +v 43.6403 -58.7108 85.1235 +v -21.5442 58.7108 93.2004 +v -21.5442 -58.7108 93.2004 +v -12.9455 58.7108 94.7781 +v -12.9455 -58.7108 94.7781 +v 46.2136 58.7108 83.7543 +v 46.2136 -58.7108 83.7543 +v 4.50347 58.7108 95.5521 +v 4.50347 -58.7108 95.5521 +v -32.717 58.7108 89.8892 +v 95.6581 58.7108 0 +v 95.6581 -58.7108 0 +v -32.717 -58.7108 89.8892 +v -15.8273 58.7108 94.3397 +v -15.8273 -58.7108 94.3397 +v 92.8295 58.7108 23.0904 +v 92.8295 -58.7108 23.0904 +v 81.6242 58.7108 49.8795 +v 81.6242 -58.7108 49.8795 +v -18.6945 58.7108 93.8136 +v -18.6945 -58.7108 93.8136 +v 87.0836 58.7108 39.5844 +v 78.4345 58.7108 54.7587 +v 18.9543 58.7108 93.7615 +v 87.0836 -58.7108 39.5844 +v 78.4345 -58.7108 54.7587 +v 18.9543 -58.7108 93.7615 +v -27.1811 58.7108 91.7151 +v -27.1811 -58.7108 91.7151 +v 94.5499 58.7108 14.5191 +v 94.5499 -58.7108 14.5191 +v -29.963 58.7108 90.8444 +v -29.963 -58.7108 90.8444 +v 92.0828 58.7108 25.9081 +v 92.0828 -58.7108 25.9081 +v 13.2081 58.7108 94.7419 +v 13.2081 -58.7108 94.7419 +v 93.4899 58.7108 20.2512 +v 88.2493 58.7108 36.9126 +v 58.3905 58.7108 75.7695 +v 93.4899 -58.7108 20.2512 +v 88.2493 -58.7108 36.9126 +v 58.3905 -58.7108 75.7695 +v -1.325 58.7108 95.649 +v -1.325 -58.7108 95.649 +v 21.8023 58.7108 93.1404 +v 21.8023 -58.7108 93.1404 +v 24.6301 58.7108 92.4329 +v 24.6301 -58.7108 92.4329 +v 90.3338 58.7108 31.4688 +v 27.4351 58.7108 91.6395 +v 90.3338 -58.7108 31.4688 +v 27.4351 -58.7108 91.6395 +v 91.2507 58.7108 28.7018 +v 89.333 58.7108 34.2066 +v 80.0665 58.7108 52.3434 +v 74.9535 58.7108 59.4344 +v 51.2293 58.7108 80.7839 +v 41.0263 58.7108 86.4136 +v 91.2507 -58.7108 28.7018 +v 89.333 -58.7108 34.2066 +v 80.0665 -58.7108 52.3434 +v 74.9535 -58.7108 59.4344 +v 51.2293 -58.7108 80.7839 +v 41.0263 -58.7108 86.4136 +v 7.41278 58.7108 95.3705 +v 7.41278 -58.7108 95.3705 +v -4.23874 58.7108 95.5642 +v -4.23874 -58.7108 95.5642 +v 95.2587 58.7108 8.73308 +v 95.2587 -58.7108 8.73308 +v 85.8371 58.7108 42.2194 +v 53.667 58.7108 79.1854 +v 10.3152 58.7108 95.1003 +v 85.8371 -58.7108 42.2194 +v 53.667 -58.7108 79.1854 +v 10.3152 -58.7108 95.1003 +v 84.5108 58.7108 44.8152 +v 35.6867 58.7108 88.7521 +v 84.5108 -58.7108 44.8152 +v 35.6867 -58.7108 88.7521 +v 48.7441 58.7108 82.3073 +v 83.1061 58.7108 47.3693 +v 76.7296 58.7108 57.1231 +v 69.2144 58.7108 66.0291 +v 83.1061 -58.7108 47.3693 +v 76.7296 -58.7108 57.1231 +v 69.2144 -58.7108 66.0291 +v 48.7441 -58.7108 82.3073 +v 94.9483 58.7108 11.6315 +v 94.9483 -58.7108 11.6315 +v -24.374 58.7108 92.5007 +v -24.374 -58.7108 92.5007 +v 16.0886 58.7108 94.2955 +v 16.0886 -58.7108 94.2955 +v 95.4805 58.7108 5.82656 +v 95.4805 -58.7108 5.82656 +v 30.2145 58.7108 90.761 +v 30.2145 -58.7108 90.761 +v 1.58997 58.7108 95.6449 +v 1.58997 -58.7108 95.6449 +v 94.0636 58.7108 17.3932 +v 94.0636 -58.7108 17.3932 +v 73.1078 58.7108 61.6906 +v 62.8973 58.7108 72.0723 +v 73.1078 -58.7108 61.6906 +v 62.8973 -58.7108 72.0723 +v 32.9659 58.7108 89.7983 +v 32.9659 -58.7108 89.7983 +v 95.6137 58.7108 2.91463 +v 95.6137 -58.7108 2.91463 +v 71.1942 58.7108 63.8895 +v 60.6721 58.7108 73.9553 +v 56.0548 58.7108 77.5135 +v 71.1942 -58.7108 63.8895 +v 60.6721 -58.7108 73.9553 +v 56.0548 -58.7108 77.5135 +v 67.1704 58.7108 68.1074 +v 65.0641 58.7108 70.1224 +v 67.1704 -58.7108 68.1074 +v 65.0641 -58.7108 70.1224 +v -10.0517 58.7108 95.1286 +v -10.0517 -58.7108 95.1286 +v -7.14854 58.7108 95.3907 +v -7.14854 -58.7108 95.3907 +v 38.3743 58.7108 87.6236 +v 38.3743 -58.7108 87.6236 +v 71.4534 61.4304 68.165 +v 71.4534 -61.4304 68.165 +v 87.2446 61.4304 46.2649 +v 87.2446 -61.4304 46.2649 +v 92.2228 61.4304 35.3131 +v 92.2228 -61.4304 35.3131 +v 75.4727 61.4304 63.6862 +v 75.4727 -61.4304 63.6862 +v 93.256 61.4304 32.4868 +v 93.256 -61.4304 32.4868 +v 16.6091 61.4304 97.3458 +v 16.6091 -61.4304 97.3458 +v 31.1919 61.4304 93.697 +v 31.1919 -61.4304 93.697 +v 55.403 61.4304 81.747 +v 55.403 -61.4304 81.747 +v 28.3225 61.4304 94.6039 +v 28.3225 -61.4304 94.6039 +v 34.0323 61.4304 92.7031 +v 34.0323 -61.4304 92.7031 +v 98.5692 61.4304 6.01505 +v 98.5692 -61.4304 6.01505 +v 97.1064 61.4304 17.9559 +v 97.1064 -61.4304 17.9559 +v 50.3209 61.4304 84.9698 +v 95.0616 61.4304 26.7462 +v 82.6566 61.4304 54.0366 +v 77.3781 61.4304 61.3571 +v 95.0616 -61.4304 26.7462 +v 82.6566 -61.4304 54.0366 +v 77.3781 -61.4304 61.3571 +v 50.3209 -61.4304 84.9698 +v -7.37979 61.4304 98.4764 +v -7.37979 -61.4304 98.4764 +v 4.64915 61.4304 98.643 +v 4.64915 -61.4304 98.643 +v 25.4269 61.4304 95.4229 +v 7.65257 61.4304 98.4556 +v 25.4269 -61.4304 95.4229 +v 7.65257 -61.4304 98.4556 +v -25.1624 61.4304 95.493 +v -25.1624 -61.4304 95.493 +v 84.2646 61.4304 51.493 +v 79.2117 61.4304 58.9709 +v 69.3433 61.4304 70.3105 +v 64.9319 61.4304 74.4037 +v 84.2646 -61.4304 51.493 +v 79.2117 -61.4304 58.9709 +v 69.3433 -61.4304 70.3105 +v 64.9319 -61.4304 74.4037 +v 98.0198 61.4304 12.0077 +v 98.0198 -61.4304 12.0077 +v 88.6138 61.4304 43.5851 +v 42.3535 61.4304 89.209 +v 88.6138 -61.4304 43.5851 +v 42.3535 -61.4304 89.209 +v -4.37585 61.4304 98.6555 +v -4.37585 -61.4304 98.6555 +v -10.3769 61.4304 98.2058 +v -10.3769 -61.4304 98.2058 +v 89.9007 61.4304 40.8649 +v 52.8865 61.4304 83.3971 +v 22.5076 61.4304 96.1534 +v 89.9007 -61.4304 40.8649 +v 52.8865 -61.4304 83.3971 +v 22.5076 -61.4304 96.1534 +v 36.8411 61.4304 91.6231 +v 36.8411 -61.4304 91.6231 +v -1.36786 61.4304 98.7431 +v -1.36786 -61.4304 98.7431 +v 98.7525 61.4304 0 +v 91.104 61.4304 38.1067 +v 85.7945 61.4304 48.9017 +v 67.1688 61.4304 72.3907 +v 60.2794 61.4304 78.2206 +v 98.7525 -61.4304 0 +v 91.104 -61.4304 38.1067 +v 85.7945 -61.4304 48.9017 +v 67.1688 -61.4304 72.3907 +v 60.2794 -61.4304 78.2206 +v 13.6353 61.4304 97.8067 +v 13.6353 -61.4304 97.8067 +v 97.6084 61.4304 14.9888 +v 97.6084 -61.4304 14.9888 +v 80.9717 61.4304 56.53 +v 57.8681 61.4304 80.0209 +v 80.9717 -61.4304 56.53 +v 57.8681 -61.4304 80.0209 +v -13.3643 61.4304 97.8441 +v -13.3643 -61.4304 97.8441 +v 94.2025 61.4304 29.6302 +v 94.2025 -61.4304 29.6302 +v 39.6157 61.4304 90.4581 +v 39.6157 -61.4304 90.4581 +v -16.3393 61.4304 97.3914 +v -16.3393 -61.4304 97.3914 +v 10.6489 61.4304 98.1767 +v 10.6489 -61.4304 98.1767 +v -28.0604 61.4304 94.682 +v -28.0604 -61.4304 94.682 +v -33.7754 61.4304 92.797 +v 47.7086 61.4304 86.4636 +v 47.7086 -61.4304 86.4636 +v -33.7754 -61.4304 92.797 +v 98.3401 61.4304 9.01558 +v 98.3401 -61.4304 9.01558 +v 95.8324 61.4304 23.8373 +v 95.8324 -61.4304 23.8373 +v -22.2411 61.4304 96.2154 +v -22.2411 -61.4304 96.2154 +v 45.052 61.4304 87.8771 +v 45.052 -61.4304 87.8771 +v 1.64141 61.4304 98.7389 +v 1.64141 -61.4304 98.7389 +v 19.5674 61.4304 96.7945 +v 19.5674 -61.4304 96.7945 +v 73.4972 61.4304 65.9563 +v 73.4972 -61.4304 65.9563 +v 96.5142 61.4304 20.9063 +v 96.5142 -61.4304 20.9063 +v -30.9322 61.4304 93.7831 +v -30.9322 -61.4304 93.7831 +v -19.2992 61.4304 96.8484 +v -19.2992 -61.4304 96.8484 +v 62.6347 61.4304 76.3476 +v 62.6347 -61.4304 76.3476 +v 98.7067 61.4304 3.00892 +v 98.7067 -61.4304 3.00892 +v 14.0814 63.9871 101.006 +v 14.0814 -63.9871 101.006 +v 101.226 63.9871 12.4005 +v 101.226 -63.9871 12.4005 +v -16.8738 63.9871 100.577 +v -16.8738 -63.9871 100.577 +v -31.944 63.9871 96.8508 +v -31.944 -63.9871 96.8508 +v 83.6204 63.9871 58.3792 +v 83.6204 -63.9871 58.3792 +v 101.936 63.9871 3.10735 +v 101.936 -63.9871 3.10735 +v 32.2122 63.9871 96.7619 +v 32.2122 -63.9871 96.7619 +v 57.2153 63.9871 84.421 +v 57.2153 -63.9871 84.421 +v 23.2439 63.9871 99.2987 +v 23.2439 -63.9871 99.2987 +v 87.021 63.9871 53.1774 +v -25.9855 63.9871 98.6167 +v 87.021 -63.9871 53.1774 +v -25.9855 -63.9871 98.6167 +v 96.3065 63.9871 33.5494 +v 96.3065 -63.9871 33.5494 +v 49.2692 63.9871 89.2919 +v 73.7907 63.9871 70.3948 +v 49.2692 -63.9871 89.2919 +v 73.7907 -63.9871 70.3948 +v 26.2586 63.9871 98.5443 +v 26.2586 -63.9871 98.5443 +v 38.0462 63.9871 94.6202 +v 38.0462 -63.9871 94.6202 +v 98.1712 63.9871 27.6211 +v 85.3604 63.9871 55.8042 +v 62.2512 63.9871 80.7793 +v 43.7389 63.9871 92.1271 +v 98.1712 -63.9871 27.6211 +v 85.3604 -63.9871 55.8042 +v 62.2512 -63.9871 80.7793 +v 43.7389 -63.9871 92.1271 +v 97.284 63.9871 30.5995 +v 97.284 -63.9871 30.5995 +v 94.0842 63.9871 39.3532 +v 90.0985 63.9871 47.7782 +v 77.9415 63.9871 65.7695 +v 75.9014 63.9871 68.1138 +v 69.366 63.9871 74.7587 +v 67.0559 63.9871 76.8375 +v 54.6165 63.9871 86.1251 +v 94.0842 -63.9871 39.3532 +v 90.0985 -63.9871 47.7782 +v 77.9415 -63.9871 65.7695 +v 75.9014 -63.9871 68.1138 +v 69.366 -63.9871 74.7587 +v 67.0559 -63.9871 76.8375 +v 54.6165 -63.9871 86.1251 +v 101.794 63.9871 6.2118 +v 101.794 -63.9871 6.2118 +v 95.2395 63.9871 36.4683 +v 95.2395 -63.9871 36.4683 +v 99.6713 63.9871 21.5902 +v 29.249 63.9871 97.6985 +v 99.6713 -63.9871 21.5902 +v 29.249 -63.9871 97.6985 +v 20.2075 63.9871 99.9608 +v 20.2075 -63.9871 99.9608 +v 88.6009 63.9871 50.5013 +v 35.1455 63.9871 95.7355 +v 88.6009 -63.9871 50.5013 +v 35.1455 -63.9871 95.7355 +v -34.8802 63.9871 95.8325 +v 40.9116 63.9871 93.4171 +v -34.8802 -63.9871 95.8325 +v 40.9116 -63.9871 93.4171 +v 81.8028 63.9871 60.8999 +v 71.6116 63.9871 72.6105 +v 64.6836 63.9871 78.845 +v 81.8028 -63.9871 60.8999 +v 71.6116 -63.9871 72.6105 +v 64.6836 -63.9871 78.845 +v 100.801 63.9871 15.4791 +v 100.801 -63.9871 15.4791 +v -28.9782 63.9871 97.7792 +v -28.9782 -63.9871 97.7792 +v 91.5125 63.9871 45.0108 +v 91.5125 -63.9871 45.0108 +v 46.5257 63.9871 90.7517 +v 46.5257 -63.9871 90.7517 +v 79.9093 63.9871 63.3641 +v 79.9093 -63.9871 63.3641 +v -7.62119 63.9871 101.698 +v -7.62119 -63.9871 101.698 +v 51.967 63.9871 87.7493 +v 59.761 63.9871 82.6385 +v 59.761 -63.9871 82.6385 +v 51.967 -63.9871 87.7493 +v 92.8414 63.9871 42.2016 +v 17.1524 63.9871 100.53 +v 92.8414 -63.9871 42.2016 +v 17.1524 -63.9871 100.53 +v -4.51899 63.9871 101.883 +v -4.51899 -63.9871 101.883 +v 10.9972 63.9871 101.388 +v 10.9972 -63.9871 101.388 +v 98.9672 63.9871 24.6171 +v 98.9672 -63.9871 24.6171 +v -22.9687 63.9871 99.3627 +v -22.9687 -63.9871 99.3627 +v 7.9029 63.9871 101.676 +v 7.9029 -63.9871 101.676 +v -19.9305 63.9871 100.016 +v -19.9305 -63.9871 100.016 +v 4.80123 63.9871 101.87 +v 4.80123 -63.9871 101.87 +v -1.4126 63.9871 101.973 +v -1.4126 -63.9871 101.973 +v 101.557 63.9871 9.3105 +v 101.557 -63.9871 9.3105 +v 1.6951 63.9871 101.969 +v 1.6951 -63.9871 101.969 +v -10.7163 63.9871 101.418 +v -10.7163 -63.9871 101.418 +v 100.283 63.9871 18.5432 +v 100.283 -63.9871 18.5432 +v -13.8015 63.9871 101.045 +v -13.8015 -63.9871 101.045 +v 101.983 63.9871 0 +v 101.983 -63.9871 0 +v 70 9.79717e-15 -100 +v -117.911 9.79717e-15 31.5765 +v 70.1061 -4.1183 -100 +v 70.1061 4.1183 -100 +v -117.947 -4.1183 31.6761 +v -117.947 4.1183 31.6761 +v 70.424 -8.22568 -100 +v 70.424 8.22568 -100 +v -118.056 -8.22568 31.9749 +v -118.056 8.22568 31.9749 +v 70.953 -12.3112 -100 +v 70.953 12.3112 -100 +v -118.237 -12.3112 32.472 +v -118.237 12.3112 32.472 +v -118.489 -16.3642 33.166 +v -118.489 16.3642 33.166 +v 71.6915 -16.3642 -100 +v 71.6915 16.3642 -100 +v 11.3593 66.3742 104.726 +v 11.3593 -66.3742 104.726 +v 102.953 66.3742 22.301 +v 102.953 -66.3742 22.301 +v 8.16309 66.3742 105.024 +v 8.16309 -66.3742 105.024 +v 104.12 66.3742 15.9887 +v 104.12 -66.3742 15.9887 +v 24.0091 66.3742 102.568 +v 24.0091 -66.3742 102.568 +v 102.226 66.3742 25.4275 +v 102.226 -66.3742 25.4275 +v 100.487 66.3742 31.6069 +v 100.487 -66.3742 31.6069 +v -4.66778 66.3742 105.237 +v -4.66778 -66.3742 105.237 +v 103.585 66.3742 19.1537 +v 103.585 -66.3742 19.1537 +v -26.8411 66.3742 101.864 +v -26.8411 -66.3742 101.864 +v 101.403 66.3742 28.5305 +v 101.403 -66.3742 28.5305 +v 14.545 66.3742 104.331 +v 14.545 -66.3742 104.331 +v -11.0691 66.3742 104.757 +v -11.0691 -66.3742 104.757 +v 105.145 66.3742 6.41632 +v 105.145 -66.3742 6.41632 +v -14.2559 66.3742 104.371 +v -14.2559 -66.3742 104.371 +v 71.6497 66.3742 77.22 +v 71.6497 -66.3742 77.22 +v -29.9323 66.3742 100.998 +v -29.9323 -66.3742 100.998 +v 17.7171 66.3742 103.84 +v 17.7171 -66.3742 103.84 +v 50.8913 66.3742 92.2317 +v 50.8913 -66.3742 92.2317 +v 53.6779 66.3742 90.6383 +v 93.0649 66.3742 49.3513 +v 45.179 66.3742 95.1603 +v 93.0649 -66.3742 49.3513 +v 53.6779 -66.3742 90.6383 +v 45.179 -66.3742 95.1603 +v 33.2728 66.3742 99.9477 +v 33.2728 -66.3742 99.9477 +v 105.34 66.3742 0 +v 48.0575 66.3742 93.7395 +v 80.5076 66.3742 67.9349 +v 78.4003 66.3742 70.3563 +v 73.9693 66.3742 75.0011 +v 36.3027 66.3742 98.8875 +v 105.34 -66.3742 0 +v 48.0575 -66.3742 93.7395 +v 80.5076 -66.3742 67.9349 +v 78.4003 -66.3742 70.3563 +v 73.9693 -66.3742 75.0011 +v 36.3027 -66.3742 98.8875 +v -36.0286 66.3742 98.9877 +v 95.8981 66.3742 43.591 +v 42.2585 66.3742 96.4927 +v -36.0286 -66.3742 98.9877 +v 95.8981 -66.3742 43.591 +v 42.2585 -66.3742 96.4927 +v 99.4772 66.3742 34.654 +v 88.1707 66.3742 57.6415 +v 99.4772 -66.3742 34.654 +v 88.1707 -66.3742 57.6415 +v 39.2988 66.3742 97.7355 +v 39.2988 -66.3742 97.7355 +v 91.518 66.3742 52.164 +v 86.3735 66.3742 60.3013 +v 66.8132 66.3742 81.4409 +v 91.518 -66.3742 52.164 +v 86.3735 -66.3742 60.3013 +v 66.8132 -66.3742 81.4409 +v -32.9958 66.3742 100.039 +v -32.9958 -66.3742 100.039 +v 56.4147 66.3742 88.9607 +v 56.4147 -66.3742 88.9607 +v 4.9593 66.3742 105.224 +v 4.9593 -66.3742 105.224 +v 104.901 66.3742 9.61703 +v 104.901 -66.3742 9.61703 +v 69.2636 66.3742 79.3673 +v 64.3007 66.3742 83.4388 +v 59.0991 66.3742 87.2005 +v 69.2636 -66.3742 79.3673 +v 64.3007 -66.3742 83.4388 +v 59.0991 -66.3742 87.2005 +v -1.45911 66.3742 105.33 +v -1.45911 -66.3742 105.33 +v 89.8861 66.3742 54.9282 +v 84.4961 66.3742 62.905 +v 89.8861 -66.3742 54.9282 +v 84.4961 -66.3742 62.905 +v 30.212 66.3742 100.915 +v 30.212 -66.3742 100.915 +v 82.5402 66.3742 65.4503 +v 76.2202 66.3742 72.7125 +v 82.5402 -66.3742 65.4503 +v 76.2202 -66.3742 72.7125 +v 94.5254 66.3742 46.4927 +v 94.5254 -66.3742 46.4927 +v 105.292 66.3742 3.20965 +v 105.292 -66.3742 3.20965 +v 61.7286 66.3742 85.3593 +v 61.7286 -66.3742 85.3593 +v 98.3752 66.3742 37.6689 +v 98.3752 -66.3742 37.6689 +v 97.1818 66.3742 40.6488 +v 97.1818 -66.3742 40.6488 +v -20.5867 66.3742 103.309 +v -20.5867 -66.3742 103.309 +v -17.4294 66.3742 103.889 +v -17.4294 -66.3742 103.889 +v 27.1232 66.3742 101.789 +v 27.1232 -66.3742 101.789 +v 104.559 66.3742 12.8088 +v 104.559 -66.3742 12.8088 +v -23.7249 66.3742 102.634 +v -23.7249 -66.3742 102.634 +v 20.8728 66.3742 103.252 +v 20.8728 -66.3742 103.252 +v 1.75091 66.3742 105.326 +v 1.75091 -66.3742 105.326 +v -7.87211 66.3742 105.046 +v -7.87211 -66.3742 105.046 +v -118.813 -20.3737 34.0552 +v -118.813 20.3737 34.0552 +v 72.6378 -20.3737 -100 +v 72.6378 20.3737 -100 +v -119.207 -24.3292 35.1371 +v -119.207 24.3292 35.1371 +v 73.7892 -24.3292 -100 +v 73.7892 24.3292 -100 +v 75.1426 -28.2202 -100 +v 75.1426 28.2202 -100 +v -119.67 -28.2202 36.409 +v -119.67 28.2202 36.409 +v 103.803 68.5852 32.6499 +v 103.803 -68.5852 32.6499 +v 1.80869 68.5852 108.801 +v 1.80869 -68.5852 108.801 +v -11.4344 68.5852 108.214 +v -11.4344 -68.5852 108.214 +v -34.0846 68.5852 103.341 +v -34.0846 -68.5852 103.341 +v -18.0045 68.5852 107.317 +v -18.0045 -68.5852 107.317 +v 108.009 68.5852 13.2315 +v 108.009 -68.5852 13.2315 +v 107.556 68.5852 16.5163 +v 107.556 -68.5852 16.5163 +v 37.5006 68.5852 102.151 +v 37.5006 -68.5852 102.151 +v -1.50726 68.5852 108.806 +v -1.50726 -68.5852 108.806 +v -21.266 68.5852 106.718 +v -21.266 -68.5852 106.718 +v 31.209 68.5852 104.245 +v 31.209 -68.5852 104.245 +v -37.2175 68.5852 102.254 +v -37.2175 -68.5852 102.254 +v 102.76 68.5852 35.7975 +v 102.76 -68.5852 35.7975 +v -24.5078 68.5852 106.021 +v -24.5078 -68.5852 106.021 +v 24.8014 68.5852 105.952 +v 24.8014 -68.5852 105.952 +v 105.599 68.5852 26.2666 +v 105.599 -68.5852 26.2666 +v 108.615 68.5852 6.62805 +v 108.615 -68.5852 6.62805 +v 34.3707 68.5852 103.246 +v 34.3707 -68.5852 103.246 +v 106.35 68.5852 23.0369 +v 106.35 -68.5852 23.0369 +v 21.5616 68.5852 106.659 +v 21.5616 -68.5852 106.659 +v 5.12295 68.5852 108.696 +v 5.12295 -68.5852 108.696 +v 63.7655 68.5852 88.176 +v 63.7655 -68.5852 88.176 +v -14.7263 68.5852 107.815 +v -14.7263 -68.5852 107.815 +v 99.0626 68.5852 45.0295 +v 89.2237 68.5852 62.2911 +v 71.5492 68.5852 81.9863 +v 99.0626 -68.5852 45.0295 +v 89.2237 -68.5852 62.2911 +v 71.5492 -68.5852 81.9863 +v -8.13187 68.5852 108.512 +v -8.13187 -68.5852 108.512 +v 85.2638 68.5852 67.6101 +v 78.7353 68.5852 75.1119 +v 66.4226 68.5852 86.1922 +v 85.2638 -68.5852 67.6101 +v 78.7353 -68.5852 75.1119 +v 66.4226 -68.5852 86.1922 +v 55.4492 68.5852 93.6292 +v 55.4492 -68.5852 93.6292 +v 97.6446 68.5852 48.0269 +v 69.0179 68.5852 84.1283 +v 61.0492 68.5852 90.0779 +v 97.6446 -68.5852 48.0269 +v 69.0179 -68.5852 84.1283 +v 61.0492 -68.5852 90.0779 +v 49.6433 68.5852 96.8328 +v 49.6433 -68.5852 96.8328 +v -30.92 68.5852 104.331 +v -30.92 -68.5852 104.331 +v 96.1359 68.5852 50.9798 +v 87.2843 68.5852 64.9808 +v 83.1642 68.5852 70.1766 +v 96.1359 -68.5852 50.9798 +v 87.2843 -68.5852 64.9808 +v 83.1642 -68.5852 70.1766 +v 101.621 68.5852 38.9119 +v 101.621 -68.5852 38.9119 +v 94.5379 68.5852 53.8853 +v 91.0802 68.5852 59.5436 +v 94.5379 -68.5852 53.8853 +v 91.0802 -68.5852 59.5436 +v 46.6698 68.5852 98.3004 +v 46.6698 -68.5852 98.3004 +v 100.389 68.5852 41.9902 +v 100.389 -68.5852 41.9902 +v 15.0249 68.5852 107.774 +v 15.0249 -68.5852 107.774 +v 43.653 68.5852 99.6768 +v 43.653 -68.5852 99.6768 +v 52.5707 68.5852 95.2753 +v 52.5707 -68.5852 95.2753 +v -4.82181 68.5852 108.71 +v -4.82181 -68.5852 108.71 +v 74.0141 68.5852 79.7682 +v 58.2763 68.5852 91.8963 +v 74.0141 -68.5852 79.7682 +v 58.2763 -68.5852 91.8963 +v 80.9874 68.5852 72.678 +v 76.4102 68.5852 77.476 +v 80.9874 -68.5852 72.678 +v 76.4102 -68.5852 77.476 +v 92.8522 68.5852 56.7408 +v 92.8522 -68.5852 56.7408 +v 40.5956 68.5852 100.961 +v 40.5956 -68.5852 100.961 +v 104.749 68.5852 29.4719 +v 104.749 -68.5852 29.4719 +v 108.817 68.5852 0 +v 108.817 -68.5852 0 +v -27.7268 68.5852 105.225 +v -27.7268 -68.5852 105.225 +v 107.003 68.5852 19.7858 +v 107.003 -68.5852 19.7858 +v 11.7341 68.5852 108.182 +v 11.7341 -68.5852 108.182 +v 28.0182 68.5852 105.148 +v 28.0182 -68.5852 105.148 +v 8.43246 68.5852 108.489 +v 8.43246 -68.5852 108.489 +v 18.3018 68.5852 107.267 +v 18.3018 -68.5852 107.267 +v 108.766 68.5852 3.31556 +v 108.766 -68.5852 3.31556 +v 108.362 68.5852 9.93438 +v 108.362 -68.5852 9.93438 +v 76.6946 -32.0363 -100 +v 76.6946 32.0363 -100 +v -120.2 -32.0363 37.8674 +v -120.2 32.0363 37.8674 +v 78.441 -35.7675 -100 +v 78.441 35.7675 -100 +v -120.798 -35.7675 39.5084 +v -120.798 35.7675 39.5084 +v 25.6185 70.6143 109.443 +v 25.6185 -70.6143 109.443 +v 107.223 70.6143 33.7256 +v 107.223 -70.6143 33.7256 +v 109.854 70.6143 23.7959 +v 109.854 -70.6143 23.7959 +v 51.2789 70.6143 100.023 +v 51.2789 -70.6143 100.023 +v 45.0913 70.6143 102.961 +v 45.0913 -70.6143 102.961 +v 15.52 70.6143 111.325 +v 15.52 -70.6143 111.325 +v 48.2075 70.6143 101.539 +v 48.2075 -70.6143 101.539 +v 12.1208 70.6143 111.746 +v 12.1208 -70.6143 111.746 +v 1.86828 70.6143 112.386 +v 1.86828 -70.6143 112.386 +v 5.29174 70.6143 112.277 +v 5.29174 -70.6143 112.277 +v 41.9332 70.6143 104.287 +v 41.9332 -70.6143 104.287 +v 111.568 70.6143 13.6674 +v 111.568 -70.6143 13.6674 +v 104.97 70.6143 40.194 +v 104.97 -70.6143 40.194 +v -18.5977 70.6143 110.853 +v -18.5977 -70.6143 110.853 +v -15.2115 70.6143 111.368 +v -15.2115 -70.6143 111.368 +v -35.2076 70.6143 106.745 +v -35.2076 -70.6143 106.745 +v -28.6403 70.6143 108.692 +v -28.6403 -70.6143 108.692 +v 85.9043 70.6143 72.4888 +v 85.9043 -70.6143 72.4888 +v 22.272 70.6143 110.173 +v 22.272 -70.6143 110.173 +v 90.1601 70.6143 67.1217 +v 88.0731 70.6143 69.8377 +v 73.9066 70.6143 84.6876 +v 65.8665 70.6143 91.0812 +v 90.1601 -70.6143 67.1217 +v 88.0731 -70.6143 69.8377 +v 73.9066 -70.6143 84.6876 +v 65.8665 -70.6143 91.0812 +v 103.696 70.6143 43.3737 +v 103.696 -70.6143 43.3737 +v 57.2762 70.6143 96.7141 +v 81.3295 70.6143 77.5866 +v 78.9277 70.6143 80.0287 +v 81.3295 -70.6143 77.5866 +v 78.9277 -70.6143 80.0287 +v 57.2762 -70.6143 96.7141 +v 32.2372 70.6143 107.68 +v 32.2372 -70.6143 107.68 +v 97.6528 70.6143 55.6607 +v 76.4527 70.6143 82.3964 +v 63.0607 70.6143 93.0458 +v 97.6528 -70.6143 55.6607 +v 76.4527 -70.6143 82.3964 +v 63.0607 -70.6143 93.0458 +v -31.9388 70.6143 107.769 +v -31.9388 -70.6143 107.769 +v 94.0811 70.6143 61.5054 +v 94.0811 -70.6143 61.5054 +v -38.4437 70.6143 105.623 +v 92.1634 70.6143 64.3435 +v 83.6558 70.6143 75.0726 +v 71.2919 70.6143 86.9002 +v 68.6111 70.6143 89.032 +v -38.4437 -70.6143 105.623 +v 92.1634 -70.6143 64.3435 +v 83.6558 -70.6143 75.0726 +v 71.2919 -70.6143 86.9002 +v 68.6111 -70.6143 89.032 +v -25.3153 70.6143 109.514 +v -25.3153 -70.6143 109.514 +v 99.3034 70.6143 52.6595 +v 95.9115 70.6143 58.6103 +v 99.3034 -70.6143 52.6595 +v 95.9115 -70.6143 58.6103 +v 54.3027 70.6143 98.4144 +v 54.3027 -70.6143 98.4144 +v 60.1964 70.6143 94.924 +v 38.7362 70.6143 105.516 +v 60.1964 -70.6143 94.924 +v 38.7362 -70.6143 105.516 +v 109.078 70.6143 27.132 +v 109.078 -70.6143 27.132 +v -21.9667 70.6143 110.234 +v -21.9667 -70.6143 110.234 +v 111.1 70.6143 17.0605 +v 111.1 -70.6143 17.0605 +v 110.528 70.6143 20.4377 +v 110.528 -70.6143 20.4377 +v 102.326 70.6143 46.5131 +v 102.326 -70.6143 46.5131 +v -11.8111 70.6143 111.78 +v -11.8111 -70.6143 111.78 +v -1.55692 70.6143 112.391 +v -1.55692 -70.6143 112.391 +v 112.35 70.6143 3.4248 +v 112.35 -70.6143 3.4248 +v 18.9048 70.6143 110.801 +v 18.9048 -70.6143 110.801 +v 35.5032 70.6143 106.648 +v 35.5032 -70.6143 106.648 +v 100.862 70.6143 49.6093 +v 100.862 -70.6143 49.6093 +v 106.146 70.6143 36.977 +v 106.146 -70.6143 36.977 +v -8.3998 70.6143 112.088 +v -8.3998 -70.6143 112.088 +v -4.98067 70.6143 112.291 +v -4.98067 -70.6143 112.291 +v 111.933 70.6143 10.2617 +v 111.933 -70.6143 10.2617 +v 112.193 70.6143 6.84643 +v 112.193 -70.6143 6.84643 +v 112.402 70.6143 0 +v 108.201 70.6143 30.443 +v 112.402 -70.6143 0 +v 108.201 -70.6143 30.443 +v 8.71029 70.6143 112.064 +v 8.71029 -70.6143 112.064 +v 28.9413 70.6143 108.612 +v 28.9413 -70.6143 108.612 +v 80.3772 -39.4039 -100 +v 80.3772 39.4039 -100 +v -121.46 -39.4039 41.3278 +v -121.46 39.4039 41.3278 +v -122.185 -42.9357 43.3207 +v -122.185 42.9357 43.3207 +v 82.498 -42.9357 -100 +v 82.498 42.9357 -100 +v -8.67518 72.4562 115.762 +v -8.67518 -72.4562 115.762 +v 116.087 72.4562 0 +v 109.625 72.4562 38.1892 +v 116.087 -72.4562 0 +v 109.625 -72.4562 38.1892 +v 108.411 72.4562 41.5117 +v 108.411 -72.4562 41.5117 +v 110.738 72.4562 34.8313 +v 26.4584 72.4562 113.031 +v 110.738 -72.4562 34.8313 +v 26.4584 -72.4562 113.031 +v 114.152 72.4562 21.1077 +v 114.152 -72.4562 21.1077 +v 12.5181 72.4562 115.41 +v 12.5181 -72.4562 115.41 +v 40.0061 72.4562 108.976 +v 40.0061 -72.4562 108.976 +v 16.0288 72.4562 114.975 +v 16.0288 -72.4562 114.975 +v 23.0022 72.4562 113.785 +v 23.0022 -72.4562 113.785 +v 102.559 72.4562 54.3859 +v 102.559 -72.4562 54.3859 +v 5.46523 72.4562 115.958 +v 5.46523 -72.4562 115.958 +v -22.6868 72.4562 113.848 +v -22.6868 -72.4562 113.848 +v -5.14396 72.4562 115.973 +v -5.14396 -72.4562 115.973 +v -19.2074 72.4562 114.487 +v -19.2074 -72.4562 114.487 +v -1.60796 72.4562 116.076 +v -1.60796 -72.4562 116.076 +v 112.654 72.4562 28.0215 +v 112.654 -72.4562 28.0215 +v 100.854 72.4562 57.4855 +v 100.854 -72.4562 57.4855 +v 46.5695 72.4562 106.336 +v 46.5695 -72.4562 106.336 +v 1.92953 72.4562 116.071 +v 1.92953 -72.4562 116.071 +v 52.9601 72.4562 103.302 +v 52.9601 -72.4562 103.302 +v 111.748 72.4562 31.441 +v 111.748 -72.4562 31.441 +v -26.1452 72.4562 113.104 +v -26.1452 -72.4562 113.104 +v 113.456 72.4562 24.576 +v 113.456 -72.4562 24.576 +v 104.168 72.4562 51.2357 +v 104.168 -72.4562 51.2357 +v 88.7206 72.4562 74.8653 +v 88.7206 -72.4562 74.8653 +v 99.0558 72.4562 60.5318 +v 99.0558 -72.4562 60.5318 +v 115.871 72.4562 7.07088 +v 115.871 -72.4562 7.07088 +v 36.6671 72.4562 110.144 +v 36.6671 -72.4562 110.144 +v 93.116 72.4562 69.3223 +v 90.9605 72.4562 72.1273 +v 78.9591 72.4562 85.0977 +v 76.3296 72.4562 87.464 +v 93.116 -72.4562 69.3223 +v 90.9605 -72.4562 72.1273 +v 78.9591 -72.4562 85.0977 +v 76.3296 -72.4562 87.464 +v 81.5153 72.4562 82.6523 +v 65.1281 72.4562 96.0963 +v 81.5153 -72.4562 82.6523 +v 65.1281 -72.4562 96.0963 +v -15.7102 72.4562 115.019 +v -15.7102 -72.4562 115.019 +v 49.7879 72.4562 104.868 +v 49.7879 -72.4562 104.868 +v 86.3983 72.4562 77.5338 +v 83.9958 72.4562 80.1303 +v 70.8604 72.4562 91.9509 +v 86.3983 -72.4562 77.5338 +v 83.9958 -72.4562 80.1303 +v 70.8604 -72.4562 91.9509 +v 29.8901 72.4562 112.173 +v 29.8901 -72.4562 112.173 +v 97.1655 72.4562 63.5218 +v 62.1699 72.4562 98.036 +v 97.1655 -72.4562 63.5218 +v 62.1699 -72.4562 98.036 +v 95.1849 72.4562 66.4529 +v 73.6292 72.4562 89.7491 +v 95.1849 -72.4562 66.4529 +v 73.6292 -72.4562 89.7491 +v 56.083 72.4562 101.641 +v 59.1539 72.4562 99.8848 +v 56.083 -72.4562 101.641 +v 59.1539 -72.4562 99.8848 +v 68.0258 72.4562 94.0672 +v 68.0258 -72.4562 94.0672 +v -32.9859 72.4562 111.302 +v -32.9859 -72.4562 111.302 +v 43.3079 72.4562 107.706 +v 33.2941 72.4562 111.21 +v 43.3079 -72.4562 107.706 +v 33.2941 -72.4562 111.21 +v 114.742 72.4562 17.6198 +v 114.742 -72.4562 17.6198 +v 107.096 72.4562 44.7957 +v 107.096 -72.4562 44.7957 +v -12.1983 72.4562 115.444 +v -12.1983 -72.4562 115.444 +v 105.681 72.4562 48.038 +v -29.5793 72.4562 112.255 +v 105.681 -72.4562 48.038 +v -29.5793 -72.4562 112.255 +v 8.99585 72.4562 115.738 +v 8.99585 -72.4562 115.738 +v 115.226 72.4562 14.1155 +v 115.226 -72.4562 14.1155 +v 19.5245 72.4562 114.433 +v 19.5245 -72.4562 114.433 +v 115.602 72.4562 10.5981 +v 115.602 -72.4562 10.5981 +v -39.704 72.4562 109.086 +v -36.3618 72.4562 110.245 +v -36.3618 -72.4562 110.245 +v -39.704 -72.4562 109.086 +v 116.033 72.4562 3.53708 +v 116.033 -72.4562 3.53708 +v 84.7977 -46.3537 -100 +v 84.7977 46.3537 -100 +v -122.972 -46.3537 45.4818 +v -122.972 46.3537 45.4818 +v 115.382 74.1059 32.4634 +v 115.382 -74.1059 32.4634 +v 9.28838 74.1059 119.501 +v 9.28838 -74.1059 119.501 +v -26.9954 74.1059 116.782 +v -26.9954 -74.1059 116.782 +v 12.9252 74.1059 119.163 +v 12.9252 -74.1059 119.163 +v 30.8621 74.1059 115.82 +v 30.8621 -74.1059 115.82 +v 117.864 74.1059 21.7941 +v 117.864 -74.1059 21.7941 +v -5.31123 74.1059 119.744 +v -5.31123 -74.1059 119.744 +v 114.339 74.1059 35.964 +v 114.339 -74.1059 35.964 +v 100.325 74.1059 65.5874 +v 100.325 -74.1059 65.5874 +v 110.578 74.1059 46.2523 +v 110.578 -74.1059 46.2523 +v 119.806 74.1059 3.6521 +v 119.806 -74.1059 3.6521 +v 34.3767 74.1059 114.826 +v 34.3767 -74.1059 114.826 +v 119.361 74.1059 10.9427 +v 119.361 -74.1059 10.9427 +v -34.0585 74.1059 114.921 +v -34.0585 -74.1059 114.921 +v -40.9951 74.1059 112.633 +v -40.9951 -74.1059 112.633 +v 119.639 74.1059 7.30081 +v 119.639 -74.1059 7.30081 +v 20.1594 74.1059 118.154 +v 20.1594 -74.1059 118.154 +v -37.5443 74.1059 113.83 +v 51.4069 74.1059 108.278 +v -37.5443 -74.1059 113.83 +v 51.4069 -74.1059 108.278 +v 116.317 74.1059 28.9327 +v 116.317 -74.1059 28.9327 +v 109.118 74.1059 49.6001 +v 109.118 -74.1059 49.6001 +v 41.307 74.1059 112.519 +v 41.307 -74.1059 112.519 +v 1.99227 74.1059 119.845 +v 1.99227 -74.1059 119.845 +v 54.6822 74.1059 106.662 +v 54.6822 -74.1059 106.662 +v 70.2379 74.1059 97.1261 +v 27.3188 74.1059 116.707 +v 70.2379 -74.1059 97.1261 +v 27.3188 -74.1059 116.707 +v 23.7502 74.1059 117.485 +v 23.7502 -74.1059 117.485 +v -19.832 74.1059 118.21 +v -19.832 -74.1059 118.21 +v -8.95728 74.1059 119.527 +v -8.95728 -74.1059 119.527 +v 104.134 74.1059 59.3548 +v 84.166 74.1059 85.34 +v 104.134 -74.1059 59.3548 +v 84.166 -74.1059 85.34 +v 76.0235 74.1059 92.6676 +v 76.0235 -74.1059 92.6676 +v 93.9184 74.1059 74.4727 +v 91.6056 74.1059 77.2997 +v 73.1646 74.1059 94.9409 +v 93.9184 -74.1059 74.4727 +v 91.6056 -74.1059 77.2997 +v 73.1646 -74.1059 94.9409 +v 81.5267 74.1059 87.8649 +v 81.5267 -74.1059 87.8649 +v 96.1439 74.1059 71.5765 +v 89.2078 74.1059 80.055 +v -12.595 74.1059 119.198 +v 96.1439 -74.1059 71.5765 +v 89.2078 -74.1059 80.055 +v -12.595 -74.1059 119.198 +v 16.55 74.1059 118.714 +v 16.55 -74.1059 118.714 +v 86.7272 74.1059 82.7359 +v 78.8117 74.1059 90.3082 +v 67.2459 74.1059 99.2211 +v 86.7272 -74.1059 82.7359 +v 78.8117 -74.1059 90.3082 +v 67.2459 -74.1059 99.2211 +v 98.2802 74.1059 68.6138 +v 98.2802 -74.1059 68.6138 +v -30.5411 74.1059 115.906 +v -30.5411 -74.1059 115.906 +v 64.1915 74.1059 101.224 +v 64.1915 -74.1059 101.224 +v -16.2211 74.1059 118.759 +v -16.2211 -74.1059 118.759 +v 44.7162 74.1059 111.208 +v 44.7162 -74.1059 111.208 +v 118.972 74.1059 14.5745 +v 118.972 -74.1059 14.5745 +v 48.0839 74.1059 109.794 +v 48.0839 -74.1059 109.794 +v 107.556 74.1059 52.9018 +v 107.556 -74.1059 52.9018 +v 117.145 74.1059 25.3752 +v 117.145 -74.1059 25.3752 +v 118.473 74.1059 18.1928 +v 118.473 -74.1059 18.1928 +v 37.8595 74.1059 113.726 +v 37.8595 -74.1059 113.726 +v 119.862 74.1059 0 +v 119.862 -74.1059 0 +v 5.64295 74.1059 119.729 +v 5.64295 -74.1059 119.729 +v 61.0775 74.1059 103.133 +v 61.0775 -74.1059 103.133 +v 111.936 74.1059 42.8616 +v 111.936 -74.1059 42.8616 +v -1.66025 74.1059 119.85 +v -1.66025 -74.1059 119.85 +v 57.9067 74.1059 104.946 +v 102.277 74.1059 62.5001 +v 57.9067 -74.1059 104.946 +v 102.277 -74.1059 62.5001 +v 105.894 74.1059 56.1544 +v 105.894 -74.1059 56.1544 +v 113.19 74.1059 39.4311 +v 113.19 -74.1059 39.4311 +v -23.4246 74.1059 117.551 +v -23.4246 -74.1059 117.551 +v -123.817 -49.6488 47.8054 +v -123.817 49.6488 47.8054 +v 87.2704 -49.6488 -100 +v 87.2704 49.6488 -100 +v -124.72 -52.8122 50.2852 +v -124.72 52.8122 50.2852 +v 89.9094 -52.8122 -100 +v 89.9094 52.8122 -100 +v -1.71364 75.5591 123.705 +v -1.71364 -75.5591 123.705 +v 122.283 75.5591 18.7778 +v 122.283 -75.5591 18.7778 +v -27.8636 75.5591 120.538 +v -27.8636 -75.5591 120.538 +v 111.015 75.5591 54.6031 +v 111.015 -75.5591 54.6031 +v 20.8078 75.5591 121.954 +v 20.8078 -75.5591 121.954 +v 116.83 75.5591 40.6992 +v 69.4086 75.5591 102.412 +v 116.83 -75.5591 40.6992 +v 69.4086 -75.5591 102.412 +v 49.6303 75.5591 113.325 +v 49.6303 -75.5591 113.325 +v 5.82443 75.5591 123.579 +v 5.82443 -75.5591 123.579 +v 120.912 75.5591 26.1913 +v 120.912 -75.5591 26.1913 +v 121.654 75.5591 22.495 +v 121.654 -75.5591 22.495 +v 46.1543 75.5591 114.785 +v 46.1543 -75.5591 114.785 +v 56.4408 75.5591 110.092 +v 107.483 75.5591 61.2637 +v 56.4408 -75.5591 110.092 +v 107.483 -75.5591 61.2637 +v 2.05634 75.5591 123.7 +v 2.05634 -75.5591 123.7 +v 122.799 75.5591 15.0432 +v 122.799 -75.5591 15.0432 +v 53.0602 75.5591 111.76 +v 53.0602 -75.5591 111.76 +v 112.627 75.5591 51.1953 +v 66.2559 75.5591 104.479 +v 112.627 -75.5591 51.1953 +v 66.2559 -75.5591 104.479 +v -20.4698 75.5591 122.011 +v -20.4698 -75.5591 122.011 +v 42.6355 75.5591 116.138 +v 42.6355 -75.5591 116.138 +v 24.514 75.5591 121.264 +v 24.514 -75.5591 121.264 +v 17.0823 75.5591 122.532 +v 17.0823 -75.5591 122.532 +v 35.4823 75.5591 118.519 +v 35.4823 -75.5591 118.519 +v 123.717 75.5591 0 +v 123.717 -75.5591 0 +v 115.536 75.5591 44.2401 +v 115.536 -75.5591 44.2401 +v 119.093 75.5591 33.5075 +v 114.135 75.5591 47.7398 +v 119.093 -75.5591 33.5075 +v 114.135 -75.5591 47.7398 +v 31.8547 75.5591 119.545 +v 31.8547 -75.5591 119.545 +v 13.3409 75.5591 122.995 +v 13.3409 -75.5591 122.995 +v 101.441 75.5591 70.8205 +v 101.441 -75.5591 70.8205 +v 84.1487 75.5591 90.6907 +v 81.3463 75.5591 93.2125 +v 84.1487 -75.5591 90.6907 +v 81.3463 -75.5591 93.2125 +v 59.7691 75.5591 108.321 +v 99.236 75.5591 73.8784 +v 94.5518 75.5591 79.7858 +v 89.5164 75.5591 85.3968 +v 86.8729 75.5591 88.0846 +v 59.7691 -75.5591 108.321 +v 99.236 -75.5591 73.8784 +v 94.5518 -75.5591 79.7858 +v 89.5164 -75.5591 85.3968 +v 86.8729 -75.5591 88.0846 +v 123.487 75.5591 7.53561 +v 123.487 -75.5591 7.53561 +v 78.4684 75.5591 95.6478 +v 75.5177 75.5591 97.9943 +v 78.4684 -75.5591 95.6478 +v 75.5177 -75.5591 97.9943 +v -31.5233 75.5591 119.633 +v -31.5233 -75.5591 119.633 +v -13.0001 75.5591 123.032 +v -13.0001 -75.5591 123.032 +v 96.9389 75.5591 76.8678 +v 92.0768 75.5591 82.6296 +v 96.9389 -75.5591 76.8678 +v 92.0768 -75.5591 82.6296 +v -5.48205 75.5591 123.595 +v -5.48205 -75.5591 123.595 +v 9.5871 75.5591 123.345 +v 9.5871 -75.5591 123.345 +v -42.3136 75.5591 116.256 +v -42.3136 -75.5591 116.256 +v 28.1974 75.5591 120.46 +v 28.1974 -75.5591 120.46 +v 63.0418 75.5591 106.45 +v 63.0418 -75.5591 106.45 +v 109.3 75.5591 57.9604 +v 109.3 -75.5591 57.9604 +v -38.7517 75.5591 117.491 +v -9.24535 75.5591 123.371 +v -38.7517 -75.5591 117.491 +v -9.24535 -75.5591 123.371 +v 103.552 75.5591 67.6968 +v 103.552 -75.5591 67.6968 +v 120.058 75.5591 29.8632 +v 120.058 -75.5591 29.8632 +v -16.7427 75.5591 122.578 +v -16.7427 -75.5591 122.578 +v 118.016 75.5591 37.1206 +v 118.016 -75.5591 37.1206 +v 105.566 75.5591 64.5102 +v 105.566 -75.5591 64.5102 +v 123.659 75.5591 3.76956 +v 123.659 -75.5591 3.76956 +v -24.1779 75.5591 121.331 +v -24.1779 -75.5591 121.331 +v 39.077 75.5591 117.383 +v 39.077 -75.5591 117.383 +v 123.2 75.5591 11.2947 +v 123.2 -75.5591 11.2947 +v 72.4968 75.5591 100.25 +v 72.4968 -75.5591 100.25 +v -35.1539 75.5591 118.617 +v -35.1539 -75.5591 118.617 +v -125.677 -55.8355 52.9148 +v -125.677 55.8355 52.9148 +v 92.7078 -55.8355 -100 +v 92.7078 55.8355 -100 +v 51.2047 76.812 116.92 +v 51.2047 -76.812 116.92 +v 25.2916 76.812 125.11 +v 25.2916 -76.812 125.11 +v -43.6558 76.812 119.943 +v 43.988 76.812 119.822 +v -43.6558 -76.812 119.943 +v 43.988 -76.812 119.822 +v 125.513 76.812 23.2086 +v 125.513 -76.812 23.2086 +v 29.0919 76.812 124.282 +v 29.0919 -76.812 124.282 +v 120.537 76.812 41.9903 +v 120.537 -76.812 41.9903 +v -9.53864 76.812 127.284 +v -9.53864 -76.812 127.284 +v 126.694 76.812 15.5204 +v 126.694 -76.812 15.5204 +v -24.9449 76.812 125.18 +v -36.269 76.812 122.38 +v -24.9449 -76.812 125.18 +v -36.269 -76.812 122.38 +v 47.6184 76.812 118.426 +v 47.6184 -76.812 118.426 +v 108.915 76.812 66.5566 +v 108.915 -76.812 66.5566 +v 9.89122 76.812 127.257 +v 9.89122 -76.812 127.257 +v 104.659 76.812 73.067 +v 104.659 -76.812 73.067 +v 106.837 76.812 69.8443 +v 32.8652 76.812 123.338 +v 106.837 -76.812 69.8443 +v 32.8652 -76.812 123.338 +v 2.12158 76.812 127.623 +v 2.12158 -76.812 127.623 +v 102.384 76.812 76.222 +v 102.384 -76.812 76.222 +v 6.00919 76.812 127.5 +v 6.00919 -76.812 127.5 +v 124.748 76.812 27.0221 +v 124.748 -76.812 27.0221 +v -39.981 76.812 121.218 +v -39.981 -76.812 121.218 +v 126.162 76.812 19.3735 +v 126.162 -76.812 19.3735 +v 68.3577 76.812 107.794 +v 68.3577 -76.812 107.794 +v 127.108 76.812 11.653 +v 127.108 -76.812 11.653 +v 89.6286 76.812 90.8789 +v 89.6286 -76.812 90.8789 +v -1.76801 76.812 127.629 +v -1.76801 -76.812 127.629 +v -13.4125 76.812 126.935 +v -13.4125 -76.812 126.935 +v 97.5511 76.812 82.3167 +v 97.5511 -76.812 82.3167 +v 86.818 76.812 93.5676 +v -32.5233 76.812 123.428 +v 86.818 -76.812 93.5676 +v -32.5233 -76.812 123.428 +v -17.2738 76.812 126.467 +v -17.2738 -76.812 126.467 +v 94.9977 76.812 85.2508 +v 92.3561 76.812 88.1057 +v 80.9576 76.812 98.682 +v 94.9977 -76.812 85.2508 +v 92.3561 -76.812 88.1057 +v 80.9576 -76.812 98.682 +v 83.9268 76.812 96.1694 +v 83.9268 -76.812 96.1694 +v 40.3167 76.812 121.107 +v 40.3167 -76.812 121.107 +v 110.892 76.812 63.2071 +v 110.892 -76.812 63.2071 +v 54.7434 76.812 115.306 +v 54.7434 -76.812 115.306 +v 74.7965 76.812 103.43 +v 74.7965 -76.812 103.43 +v 127.582 76.812 3.88913 +v 127.582 -76.812 3.88913 +v 117.755 76.812 49.2542 +v 117.755 -76.812 49.2542 +v 65.0416 76.812 109.826 +v 36.6079 76.812 122.279 +v 65.0416 -76.812 109.826 +v 36.6079 -76.812 122.279 +v 121.76 76.812 38.2981 +v 121.76 -76.812 38.2981 +v 112.767 76.812 59.799 +v 112.767 -76.812 59.799 +v -5.65595 76.812 127.516 +v -5.65595 -76.812 127.516 +v 116.2 76.812 52.8193 +v 71.6104 76.812 105.661 +v 116.2 -76.812 52.8193 +v 71.6104 -76.812 105.661 +v 100.014 76.812 79.3062 +v 21.4678 76.812 125.823 +v 100.014 -76.812 79.3062 +v 21.4678 -76.812 125.823 +v 122.87 76.812 34.5704 +v 77.9133 76.812 101.103 +v 122.87 -76.812 34.5704 +v 77.9133 -76.812 101.103 +v 58.2313 76.812 113.584 +v 58.2313 -76.812 113.584 +v -21.1192 76.812 125.882 +v -21.1192 -76.812 125.882 +v 13.7641 76.812 126.897 +v 13.7641 -76.812 126.897 +v 61.6651 76.812 111.757 +v 61.6651 -76.812 111.757 +v 114.536 76.812 56.3353 +v 114.536 -76.812 56.3353 +v 17.6241 76.812 126.419 +v 17.6241 -76.812 126.419 +v 119.201 76.812 45.6434 +v 119.201 -76.812 45.6434 +v 123.867 76.812 30.8106 +v 123.867 -76.812 30.8106 +v 127.404 76.812 7.77466 +v 127.404 -76.812 7.77466 +v -28.7475 76.812 124.362 +v -28.7475 -76.812 124.362 +v 127.641 76.812 0 +v 127.641 -76.812 0 +v 95.6581 -58.7108 -100 +v 95.6581 58.7108 -100 +v -126.686 -58.7108 55.6872 +v -126.686 58.7108 55.6872 +v -37.401 77.8612 126.199 +v -37.401 -77.8612 126.199 +v 49.1047 77.8612 122.122 +v 49.1047 -77.8612 122.122 +v -25.7235 77.8612 129.087 +v -25.7235 -77.8612 129.087 +v 107.925 77.8612 75.3476 +v 107.925 -77.8612 75.3476 +v -29.6447 77.8612 128.243 +v -29.6447 -77.8612 128.243 +v 33.8909 77.8612 127.187 +v 18.1742 77.8612 130.364 +v 33.8909 -77.8612 127.187 +v 18.1742 -77.8612 130.364 +v 83.4844 77.8612 101.762 +v -33.5384 77.8612 127.28 +v 83.4844 -77.8612 101.762 +v -33.5384 -77.8612 127.28 +v -9.83635 77.8612 131.257 +v -9.83635 -77.8612 131.257 +v 45.3609 77.8612 123.562 +v 45.3609 -77.8612 123.562 +v 6.19674 77.8612 131.479 +v 6.19674 -77.8612 131.479 +v -45.0184 77.8612 123.687 +v -45.0184 -77.8612 123.687 +v 63.5897 77.8612 115.245 +v 63.5897 -77.8612 115.245 +v 124.299 77.8612 43.3008 +v 124.299 -77.8612 43.3008 +v 110.171 77.8612 72.0242 +v 110.171 -77.8612 72.0242 +v 29.9999 77.8612 128.161 +v 29.9999 -77.8612 128.161 +v 56.452 77.8612 118.905 +v 56.452 -77.8612 118.905 +v 103.135 77.8612 81.7814 +v 86.5462 77.8612 99.171 +v 103.135 -77.8612 81.7814 +v 86.5462 -77.8612 99.171 +v 92.4261 77.8612 93.7153 +v 80.345 77.8612 104.258 +v 92.4261 -77.8612 93.7153 +v 80.345 -77.8612 104.258 +v 130.648 77.8612 16.0049 +v 130.648 -77.8612 16.0049 +v 119.826 77.8612 54.4678 +v 97.9627 77.8612 87.9116 +v 119.826 -77.8612 54.4678 +v 97.9627 -77.8612 87.9116 +v 131.075 77.8612 12.0167 +v 131.075 -77.8612 12.0167 +v 100.596 77.8612 84.8859 +v 100.596 -77.8612 84.8859 +v 126.705 77.8612 35.6494 +v 126.705 -77.8612 35.6494 +v 2.18779 77.8612 131.607 +v 2.18779 -77.8612 131.607 +v 67.0716 77.8612 113.254 +v 95.2386 77.8612 90.8556 +v 89.5277 77.8612 96.4879 +v 95.2386 -77.8612 90.8556 +v 89.5277 -77.8612 96.4879 +v 67.0716 -77.8612 113.254 +v -5.83248 77.8612 131.496 +v -5.83248 -77.8612 131.496 +v 112.314 77.8612 68.6339 +v 70.4912 77.8612 111.158 +v 112.314 -77.8612 68.6339 +v 70.4912 -77.8612 111.158 +v -17.813 77.8612 130.414 +v -17.813 -77.8612 130.414 +v 131.381 77.8612 8.01731 +v 131.381 -77.8612 8.01731 +v 26.081 77.8612 129.015 +v 26.081 -77.8612 129.015 +v 130.1 77.8612 19.9782 +v 130.1 -77.8612 19.9782 +v 131.625 77.8612 0 +v 131.625 -77.8612 0 +v -13.8311 77.8612 130.896 +v -13.8311 -77.8612 130.896 +v 114.354 77.8612 65.1799 +v 114.354 -77.8612 65.1799 +v 41.575 77.8612 124.887 +v 41.575 -77.8612 124.887 +v 118.111 77.8612 58.0936 +v -21.7783 77.8612 129.811 +v 118.111 -77.8612 58.0936 +v -21.7783 -77.8612 129.811 +v -41.2288 77.8612 125.001 +v -41.2288 -77.8612 125.001 +v 127.733 77.8612 31.7722 +v 127.733 -77.8612 31.7722 +v 129.431 77.8612 23.933 +v 129.431 -77.8612 23.933 +v 10.1999 77.8612 131.229 +v 10.1999 -77.8612 131.229 +v 121.43 77.8612 50.7915 +v 116.286 77.8612 61.6654 +v 121.43 -77.8612 50.7915 +v 116.286 -77.8612 61.6654 +v 122.922 77.8612 47.068 +v 122.922 -77.8612 47.068 +v 77.131 77.8612 106.658 +v 77.131 -77.8612 106.658 +v 131.564 77.8612 4.01052 +v 131.564 -77.8612 4.01052 +v 73.8454 77.8612 108.959 +v 52.8028 77.8612 120.57 +v 73.8454 -77.8612 108.959 +v 52.8028 -77.8612 120.57 +v 14.1937 77.8612 130.857 +v 14.1937 -77.8612 130.857 +v 60.0487 77.8612 117.129 +v 125.56 77.8612 39.4934 +v 60.0487 -77.8612 117.129 +v 125.56 -77.8612 39.4934 +v 105.579 77.8612 78.601 +v 105.579 -77.8612 78.601 +v -1.82319 77.8612 131.612 +v -1.82319 -77.8612 131.612 +v 37.7505 77.8612 126.095 +v 37.7505 -77.8612 126.095 +v 22.1379 77.8612 129.75 +v 22.1379 -77.8612 129.75 +v 128.642 77.8612 27.8655 +v 128.642 -77.8612 27.8655 +v -127.745 -61.4304 58.595 +v -127.745 61.4304 58.595 +v 98.7525 -61.4304 -100 +v 98.7525 61.4304 -100 +v 101.983 -63.9871 -100 +v 101.983 63.9871 -100 +v -128.85 -63.9871 61.6305 +v -128.85 63.9871 61.6305 +v 134.651 78.7038 16.4952 +v 134.651 -78.7038 16.4952 +v -26.5116 78.7038 133.042 +v -26.5116 -78.7038 133.042 +v -18.3587 78.7038 134.41 +v -18.3587 -78.7038 134.41 +v 135.658 78.7038 0 +v 135.658 -78.7038 0 +v 106.295 78.7038 84.2869 +v 106.295 -78.7038 84.2869 +v 115.755 78.7038 70.7366 +v 100.964 78.7038 90.6049 +v 115.755 -78.7038 70.7366 +v 100.964 -78.7038 90.6049 +v 130.587 78.7038 36.7416 +v 130.587 -78.7038 36.7416 +v 30.919 78.7038 132.087 +v 30.919 -78.7038 132.087 +v 69.1265 78.7038 116.724 +v 82.8065 78.7038 107.452 +v 82.8065 -78.7038 107.452 +v 69.1265 -78.7038 116.724 +v 34.9292 78.7038 131.084 +v 34.9292 -78.7038 131.084 +v 128.107 78.7038 44.6274 +v 128.107 -78.7038 44.6274 +v 134.086 78.7038 20.5903 +v 134.086 -78.7038 20.5903 +v -1.87904 78.7038 135.645 +v -1.87904 -78.7038 135.645 +v 103.678 78.7038 87.4865 +v 103.678 -78.7038 87.4865 +v -14.2548 78.7038 134.906 +v -14.2548 -78.7038 134.906 +v 111.232 78.7038 77.656 +v 111.232 -78.7038 77.656 +v 6.38659 78.7038 135.507 +v 6.38659 -78.7038 135.507 +v 61.8884 78.7038 120.718 +v 121.73 78.7038 59.8734 +v 61.8884 -78.7038 120.718 +v 121.73 -78.7038 59.8734 +v 54.4206 78.7038 124.263 +v 54.4206 -78.7038 124.263 +v 135.091 78.7038 12.3848 +v 135.091 -78.7038 12.3848 +v -10.1377 78.7038 135.278 +v -10.1377 -78.7038 135.278 +v 98.1564 78.7038 93.6391 +v 98.1564 -78.7038 93.6391 +v 129.407 78.7038 40.7034 +v 129.407 -78.7038 40.7034 +v 133.396 78.7038 24.6662 +v 133.396 -78.7038 24.6662 +v 14.6285 78.7038 134.867 +v 14.6285 -78.7038 134.867 +v 10.5124 78.7038 135.25 +v 10.5124 -78.7038 135.25 +v -42.492 78.7038 128.831 +v 72.6509 78.7038 114.564 +v -42.492 -78.7038 128.831 +v 72.6509 -78.7038 114.564 +v 79.4941 78.7038 109.926 +v 79.4941 -78.7038 109.926 +v 2.25482 78.7038 135.639 +v 2.25482 -78.7038 135.639 +v 119.849 78.7038 63.5546 +v 119.849 -78.7038 63.5546 +v 38.907 78.7038 129.958 +v 38.907 -78.7038 129.958 +v 123.498 78.7038 56.1365 +v 123.498 -78.7038 56.1365 +v 132.583 78.7038 28.7192 +v 132.583 -78.7038 28.7192 +v 113.546 78.7038 74.2308 +v 113.546 -78.7038 74.2308 +v 76.1078 78.7038 112.297 +v 76.1078 -78.7038 112.297 +v 125.151 78.7038 52.3476 +v -34.5659 78.7038 131.18 +v 125.151 -78.7038 52.3476 +v -34.5659 -78.7038 131.18 +v 92.2706 78.7038 99.444 +v 92.2706 -78.7038 99.444 +v -30.5529 78.7038 132.172 +v -30.5529 -78.7038 132.172 +v -38.5468 78.7038 130.066 +v -38.5468 -78.7038 130.066 +v 117.857 78.7038 67.1768 +v 86.0421 78.7038 104.88 +v 117.857 -78.7038 67.1768 +v 86.0421 -78.7038 104.88 +v 131.646 78.7038 32.7456 +v 131.646 -78.7038 32.7456 +v -46.3976 78.7038 127.476 +v 95.2577 78.7038 96.5864 +v -46.3976 -78.7038 127.476 +v 95.2577 -78.7038 96.5864 +v -6.01116 78.7038 135.524 +v -6.01116 -78.7038 135.524 +v 126.688 78.7038 48.51 +v 42.8487 78.7038 128.713 +v 126.688 -78.7038 48.51 +v 42.8487 -78.7038 128.713 +v 65.5379 78.7038 118.776 +v 65.5379 -78.7038 118.776 +v 26.88 78.7038 132.968 +v 26.88 -78.7038 132.968 +v 50.6091 78.7038 125.864 +v 50.6091 -78.7038 125.864 +v 18.731 78.7038 134.358 +v 18.731 -78.7038 134.358 +v 89.1977 78.7038 102.209 +v 89.1977 -78.7038 102.209 +v 58.1815 78.7038 122.548 +v 58.1815 -78.7038 122.548 +v -22.4456 78.7038 133.788 +v -22.4456 -78.7038 133.788 +v 22.8161 78.7038 133.725 +v 22.8161 -78.7038 133.725 +v 108.814 78.7038 81.0091 +v 46.7506 78.7038 127.347 +v 108.814 -78.7038 81.0091 +v 46.7506 -78.7038 127.347 +v 135.406 78.7038 8.26294 +v 135.406 -78.7038 8.26294 +v 135.595 78.7038 4.13339 +v 135.595 -78.7038 4.13339 +v -129.998 -66.3742 64.7857 +v -129.998 66.3742 64.7857 +v 105.34 -66.3742 -100 +v 105.34 66.3742 -100 +v -27.3071 79.3378 137.034 +v -27.3071 -79.3378 137.034 +v 74.8308 79.3378 118.001 +v 74.8308 -79.3378 118.001 +v -23.1191 79.3378 137.802 +v -23.1191 -79.3378 137.802 +v 121.393 79.3378 69.1925 +v 121.393 -79.3378 69.1925 +v 137.399 79.3378 25.4063 +v 137.399 -79.3378 25.4063 +v 119.229 79.3378 72.8592 +v 119.229 -79.3378 72.8592 +v 88.6239 79.3378 108.027 +v 88.6239 -79.3378 108.027 +v 123.445 79.3378 65.4616 +v 123.445 -79.3378 65.4616 +v 138.691 79.3378 16.9902 +v 138.691 -79.3378 16.9902 +v 2.32248 79.3378 139.709 +v 2.32248 -79.3378 139.709 +v 136.561 79.3378 29.581 +v 136.561 -79.3378 29.581 +v 139.728 79.3378 0 +v 139.728 -79.3378 0 +v 106.789 79.3378 90.1117 +v 106.789 -79.3378 90.1117 +v -35.6031 79.3378 135.116 +v -35.6031 -79.3378 135.116 +v 63.7455 79.3378 124.34 +v 63.7455 -79.3378 124.34 +v 135.596 79.3378 33.7282 +v 135.596 -79.3378 33.7282 +v 130.489 79.3378 49.9656 +v 130.489 -79.3378 49.9656 +v -1.93543 79.3378 139.715 +v -1.93543 -79.3378 139.715 +v -10.4419 79.3378 139.337 +v -10.4419 -79.3378 139.337 +v 101.102 79.3378 96.4489 +v 101.102 -79.3378 96.4489 +v 67.5044 79.3378 122.34 +v 116.953 79.3378 76.4582 +v 67.5044 -79.3378 122.34 +v 116.953 -79.3378 76.4582 +v 56.0535 79.3378 127.992 +v 56.0535 -79.3378 127.992 +v 128.906 79.3378 53.9184 +v 127.203 79.3378 57.821 +v 128.906 -79.3378 53.9184 +v 127.203 -79.3378 57.821 +v 78.3915 79.3378 115.666 +v 78.3915 -79.3378 115.666 +v 98.116 79.3378 99.4846 +v 48.1534 79.3378 131.169 +v 98.116 -79.3378 99.4846 +v 48.1534 -79.3378 131.169 +v 139.145 79.3378 12.7564 +v 139.145 -79.3378 12.7564 +v 85.2912 79.3378 110.677 +v 85.2912 -79.3378 110.677 +v 103.993 79.3378 93.3236 +v 103.993 -79.3378 93.3236 +v 71.2007 79.3378 120.227 +v 71.2007 -79.3378 120.227 +v 6.57823 79.3378 139.573 +v 6.57823 -79.3378 139.573 +v -31.4697 79.3378 136.138 +v -31.4697 -79.3378 136.138 +v 40.0745 79.3378 133.858 +v 40.0745 -79.3378 133.858 +v 91.8742 79.3378 105.276 +v 91.8742 -79.3378 105.276 +v -47.7898 79.3378 131.301 +v 52.1277 79.3378 129.641 +v -47.7898 -79.3378 131.301 +v 52.1277 -79.3378 129.641 +v 114.57 79.3378 79.9861 +v -39.7035 79.3378 133.969 +v 114.57 -79.3378 79.9861 +v -39.7035 -79.3378 133.969 +v 44.1344 79.3378 132.575 +v 44.1344 -79.3378 132.575 +v 125.382 79.3378 61.6699 +v 125.382 -79.3378 61.6699 +v -6.19154 79.3378 139.591 +v -6.19154 -79.3378 139.591 +v 139.469 79.3378 8.51088 +v 139.469 -79.3378 8.51088 +v 81.8794 79.3378 113.224 +v 81.8794 -79.3378 113.224 +v 31.8467 79.3378 136.051 +v 31.8467 -79.3378 136.051 +v -18.9096 79.3378 138.443 +v -18.9096 -79.3378 138.443 +v 134.506 79.3378 37.844 +v 134.506 -79.3378 37.844 +v 109.485 79.3378 86.8161 +v 109.485 -79.3378 86.8161 +v 35.9773 79.3378 135.017 +v 35.9773 -79.3378 135.017 +v 112.079 79.3378 83.4399 +v 112.079 -79.3378 83.4399 +v 59.9273 79.3378 126.225 +v 59.9273 -79.3378 126.225 +v 95.0393 79.3378 102.428 +v 95.0393 -79.3378 102.428 +v 19.2931 79.3378 138.39 +v 19.2931 -79.3378 138.39 +v 23.5007 79.3378 137.738 +v 23.5007 -79.3378 137.738 +v 27.6866 79.3378 136.958 +v 27.6866 -79.3378 136.958 +v -14.6826 79.3378 138.955 +v -14.6826 -79.3378 138.955 +v 138.109 79.3378 21.2081 +v 138.109 -79.3378 21.2081 +v 10.8279 79.3378 139.308 +v 10.8279 -79.3378 139.308 +v 15.0675 79.3378 138.913 +v 15.0675 -79.3378 138.913 +v -43.767 79.3378 132.697 +v -43.767 -79.3378 132.697 +v 131.951 79.3378 45.9665 +v 131.951 -79.3378 45.9665 +v 139.663 79.3378 4.25742 +v 139.663 -79.3378 4.25742 +v 133.29 79.3378 41.9248 +v 133.29 -79.3378 41.9248 +v -131.187 -68.5852 68.0521 +v -131.187 68.5852 68.0521 +v 108.817 -68.5852 -100 +v 108.817 68.5852 -100 +v 19.8589 79.7614 142.448 +v 19.8589 -79.7614 142.448 +v 37.0324 79.7614 138.977 +v 37.0324 -79.7614 138.977 +v 107.043 79.7614 96.0605 +v 100.993 79.7614 102.402 +v 107.043 -79.7614 96.0605 +v 100.993 -79.7614 102.402 +v 115.366 79.7614 85.8869 +v 87.7926 79.7614 113.923 +v 115.366 -79.7614 85.8869 +v 87.7926 -79.7614 113.923 +v -32.3926 79.7614 140.131 +v -32.3926 -79.7614 140.131 +v 94.5686 79.7614 108.364 +v 94.5686 -79.7614 108.364 +v 143.225 79.7614 13.1306 +v 143.225 -79.7614 13.1306 +v 127.065 79.7614 67.3814 +v 45.4288 79.7614 136.463 +v 127.065 -79.7614 67.3814 +v 45.4288 -79.7614 136.463 +v 104.067 79.7614 99.2775 +v 104.067 -79.7614 99.2775 +v 120.383 79.7614 78.7004 +v 120.383 -79.7614 78.7004 +v 24.1899 79.7614 141.777 +v 24.1899 -79.7614 141.777 +v 109.921 79.7614 92.7544 +v 109.921 -79.7614 92.7544 +v -15.1132 79.7614 143.03 +v -15.1132 -79.7614 143.03 +v 84.2807 79.7614 116.545 +v 84.2807 -79.7614 116.545 +v 130.934 79.7614 59.5167 +v 130.934 -79.7614 59.5167 +v 143.559 79.7614 8.76048 +v 143.559 -79.7614 8.76048 +v -19.4642 79.7614 142.503 +v -19.4642 -79.7614 142.503 +v 142.16 79.7614 21.8301 +v 142.16 -79.7614 21.8301 +v 49.5656 79.7614 135.015 +v 49.5656 -79.7614 135.015 +v -40.8679 79.7614 137.898 +v -40.8679 -79.7614 137.898 +v -23.7971 79.7614 141.844 +v -23.7971 -79.7614 141.844 +v 69.4841 79.7614 125.928 +v 69.4841 -79.7614 125.928 +v -10.7481 79.7614 143.424 +v -10.7481 -79.7614 143.424 +v 73.2888 79.7614 123.752 +v 129.06 79.7614 63.4785 +v 129.06 -79.7614 63.4785 +v 73.2888 -79.7614 123.752 +v -6.37312 79.7614 143.685 +v -6.37312 -79.7614 143.685 +v 135.821 79.7614 47.3146 +v 135.821 -79.7614 47.3146 +v 15.5093 79.7614 142.987 +v 15.5093 -79.7614 142.987 +v -36.6473 79.7614 139.079 +v -36.6473 -79.7614 139.079 +v 134.316 79.7614 51.431 +v 134.316 -79.7614 51.431 +v 117.929 79.7614 82.3319 +v 77.0254 79.7614 121.462 +v 117.929 -79.7614 82.3319 +v 77.0254 -79.7614 121.462 +v 97.8265 79.7614 105.432 +v 97.8265 -79.7614 105.432 +v 2.39059 79.7614 143.806 +v 2.39059 -79.7614 143.806 +v 61.6848 79.7614 129.926 +v 61.6848 -79.7614 129.926 +v 140.566 79.7614 30.4485 +v 140.566 -79.7614 30.4485 +v 80.6905 79.7614 119.059 +v 80.6905 -79.7614 119.059 +v -49.1914 79.7614 135.152 +v -49.1914 -79.7614 135.152 +v 143.759 79.7614 4.38228 +v 143.759 -79.7614 4.38228 +v 122.725 79.7614 74.9959 +v 122.725 -79.7614 74.9959 +v 6.77115 79.7614 143.667 +v 6.77115 -79.7614 143.667 +v 139.573 79.7614 34.7173 +v 139.573 -79.7614 34.7173 +v 11.1454 79.7614 143.393 +v 11.1454 -79.7614 143.393 +v 137.199 79.7614 43.1543 +v 53.6564 79.7614 133.443 +v 137.199 -79.7614 43.1543 +v 53.6564 -79.7614 133.443 +v 132.686 79.7614 55.4996 +v 132.686 -79.7614 55.4996 +v 124.953 79.7614 71.2217 +v 124.953 -79.7614 71.2217 +v 32.7807 79.7614 140.04 +v 32.7807 -79.7614 140.04 +v 65.6149 79.7614 127.987 +v 65.6149 -79.7614 127.987 +v 91.223 79.7614 111.195 +v 91.223 -79.7614 111.195 +v -1.99219 79.7614 143.812 +v -1.99219 -79.7614 143.812 +v -45.0505 79.7614 136.588 +v -45.0505 -79.7614 136.588 +v 41.2497 79.7614 137.784 +v 41.2497 -79.7614 137.784 +v 141.428 79.7614 26.1514 +v 141.428 -79.7614 26.1514 +v 112.696 79.7614 89.3622 +v 112.696 -79.7614 89.3622 +v 138.45 79.7614 38.9539 +v 138.45 -79.7614 38.9539 +v 57.6974 79.7614 131.746 +v 57.6974 -79.7614 131.746 +v -28.1079 79.7614 141.053 +v -28.1079 -79.7614 141.053 +v 143.826 79.7614 0 +v 143.826 -79.7614 0 +v 142.759 79.7614 17.4884 +v 142.759 -79.7614 17.4884 +v 28.4986 79.7614 140.974 +v 28.4986 -79.7614 140.974 +v -132.413 -70.6143 71.4212 +v -132.413 70.6143 71.4212 +v 112.402 -70.6143 -100 +v 112.402 70.6143 -100 +v -15.5455 79.9735 147.121 +v -15.5455 -79.9735 147.121 +v 20.4269 79.9735 146.523 +v 20.4269 -79.9735 146.523 +v 134.679 79.9735 61.2192 +v 134.679 -79.9735 61.2192 +v -28.9119 79.9735 145.087 +v -28.9119 -79.9735 145.087 +v 90.3039 79.9735 117.181 +v 90.3039 -79.9735 117.181 +v 6.96484 79.9735 147.776 +v 6.96484 -79.9735 147.776 +v 144.587 79.9735 31.3195 +v 144.587 -79.9735 31.3195 +v 2.45898 79.9735 147.92 +v 2.45898 -79.9735 147.92 +v 93.8324 79.9735 114.376 +v 86.6916 79.9735 119.879 +v 93.8324 -79.9735 114.376 +v 86.6916 -79.9735 119.879 +v 118.666 79.9735 88.3437 +v 118.666 -79.9735 88.3437 +v -46.3392 79.9735 140.495 +v 38.0918 79.9735 142.952 +v -46.3392 -79.9735 140.495 +v 38.0918 -79.9735 142.952 +v 136.482 79.9735 57.0872 +v 136.482 -79.9735 57.0872 +v 71.4718 79.9735 129.53 +v 42.4297 79.9735 141.725 +v -42.0369 79.9735 141.842 +v 71.4718 -79.9735 129.53 +v 42.4297 -79.9735 141.725 +v -42.0369 -79.9735 141.842 +v 46.7283 79.9735 140.367 +v 46.7283 -79.9735 140.367 +v 141.124 79.9735 44.3887 +v 141.124 -79.9735 44.3887 +v 97.2738 79.9735 111.463 +v 97.2738 -79.9735 111.463 +v 146.842 79.9735 17.9887 +v 146.842 -79.9735 17.9887 +v 24.8819 79.9735 145.833 +v 24.8819 -79.9735 145.833 +v 128.528 79.9735 73.2591 +v 128.528 -79.9735 73.2591 +v 15.953 79.9735 147.077 +v 15.953 -79.9735 147.077 +v 143.566 79.9735 35.7104 +v 143.566 -79.9735 35.7104 +v 139.706 79.9735 48.6681 +v 139.706 -79.9735 48.6681 +v -37.6956 79.9735 143.057 +v -37.6956 -79.9735 143.057 +v 121.303 79.9735 84.687 +v 82.9987 79.9735 122.464 +v 121.303 -79.9735 84.687 +v 82.9987 -79.9735 122.464 +v -24.4778 79.9735 145.901 +v -24.4778 -79.9735 145.901 +v 11.4642 79.9735 147.495 +v 11.4642 -79.9735 147.495 +v 132.751 79.9735 65.2944 +v 132.751 -79.9735 65.2944 +v 130.7 79.9735 69.3089 +v 130.7 -79.9735 69.3089 +v 59.3479 79.9735 135.514 +v 59.3479 -79.9735 135.514 +v 75.3853 79.9735 127.292 +v 75.3853 -79.9735 127.292 +v 126.236 79.9735 77.1412 +v 63.4493 79.9735 133.643 +v 126.236 -79.9735 77.1412 +v 63.4493 -79.9735 133.643 +v 142.411 79.9735 40.0682 +v 142.411 -79.9735 40.0682 +v -50.5985 79.9735 139.018 +v 100.625 79.9735 108.448 +v -50.5985 -79.9735 139.018 +v 100.625 -79.9735 108.448 +v -11.0556 79.9735 147.527 +v -11.0556 -79.9735 147.527 +v 67.4919 79.9735 131.648 +v 107.044 79.9735 102.117 +v 67.4919 -79.9735 131.648 +v 107.044 -79.9735 102.117 +v 33.7184 79.9735 144.046 +v 33.7184 -79.9735 144.046 +v -20.0209 79.9735 146.579 +v -20.0209 -79.9735 146.579 +v 29.3138 79.9735 145.007 +v 29.3138 -79.9735 145.007 +v 145.474 79.9735 26.8995 +v 145.474 -79.9735 26.8995 +v 50.9835 79.9735 138.878 +v 50.9835 -79.9735 138.878 +v -2.04918 79.9735 147.926 +v -2.04918 -79.9735 147.926 +v 103.882 79.9735 105.331 +v 103.882 -79.9735 105.331 +v 147.665 79.9735 9.01108 +v 147.665 -79.9735 9.01108 +v 115.919 79.9735 91.9184 +v 113.065 79.9735 95.4077 +v 110.105 79.9735 98.8084 +v 115.919 -79.9735 91.9184 +v 113.065 -79.9735 95.4077 +v 110.105 -79.9735 98.8084 +v 147.872 79.9735 4.50763 +v 147.872 -79.9735 4.50763 +v 147.94 79.9735 0 +v 147.94 -79.9735 0 +v 138.158 79.9735 52.9022 +v 55.1913 79.9735 137.26 +v 138.158 -79.9735 52.9022 +v 55.1913 -79.9735 137.26 +v 79.2288 79.9735 124.936 +v 79.2288 -79.9735 124.936 +v 146.226 79.9735 22.4545 +v 146.226 -79.9735 22.4545 +v 123.827 79.9735 80.9517 +v 123.827 -79.9735 80.9517 +v 147.322 79.9735 13.5062 +v 147.322 -79.9735 13.5062 +v -6.55542 79.9735 147.795 +v -6.55542 -79.9735 147.795 +v -33.3192 79.9735 144.139 +v -33.3192 -79.9735 144.139 +v 116.087 -72.4562 -100 +v 116.087 72.4562 -100 +v -133.673 -72.4562 74.8839 +v -133.673 72.4562 74.8839 +v -2.10624 79.9735 152.045 +v -2.10624 -79.9735 152.045 +v -11.3635 79.9735 151.635 +v -11.3635 -79.9735 151.635 +v 85.31 79.9735 125.874 +v 85.31 -79.9735 125.874 +v -20.5784 79.9735 150.661 +v -20.5784 -79.9735 150.661 +v 113.171 79.9735 101.56 +v 110.024 79.9735 104.961 +v 113.171 -79.9735 101.56 +v 110.024 -79.9735 104.961 +v 61.0005 79.9735 139.288 +v 61.0005 -79.9735 139.288 +v 152.06 79.9735 0 +v 152.06 -79.9735 0 +v 138.43 79.9735 62.924 +v 81.435 79.9735 128.415 +v 65.2162 79.9735 137.365 +v 138.43 -79.9735 62.924 +v 81.435 -79.9735 128.415 +v 65.2162 -79.9735 137.365 +v 151.989 79.9735 4.63315 +v 151.989 -79.9735 4.63315 +v 127.275 79.9735 83.206 +v 96.4454 79.9735 117.561 +v 127.275 -79.9735 83.206 +v 96.4454 -79.9735 117.561 +v 73.462 79.9735 133.137 +v 73.462 -79.9735 133.137 +v 150.932 79.9735 18.4896 +v 150.932 -79.9735 18.4896 +v 99.9826 79.9735 114.567 +v 99.9826 -79.9735 114.567 +v 142.005 79.9735 54.3754 +v 142.005 -79.9735 54.3754 +v 2.52745 79.9735 152.039 +v 2.52745 -79.9735 152.039 +v 7.15879 79.9735 151.891 +v 7.15879 -79.9735 151.891 +v 34.6574 79.9735 148.058 +v 34.6574 -79.9735 148.058 +v 140.283 79.9735 58.6769 +v 140.283 -79.9735 58.6769 +v 148.613 79.9735 32.1917 +v 148.613 -79.9735 32.1917 +v 43.6113 79.9735 145.672 +v 43.6113 -79.9735 145.672 +v 151.425 79.9735 13.8823 +v 151.425 -79.9735 13.8823 +v 56.7282 79.9735 141.082 +v 56.7282 -79.9735 141.082 +v 121.971 79.9735 90.8038 +v 121.971 -79.9735 90.8038 +v 124.681 79.9735 87.0453 +v 106.775 79.9735 108.265 +v 124.681 -79.9735 87.0453 +v 106.775 -79.9735 108.265 +v 132.107 79.9735 75.2991 +v 132.107 -79.9735 75.2991 +v -52.0075 79.9735 142.889 +v 136.448 79.9735 67.1126 +v -52.0075 -79.9735 142.889 +v 136.448 -79.9735 67.1126 +v 103.427 79.9735 111.468 +v 103.427 -79.9735 111.468 +v 25.5748 79.9735 149.894 +v 25.5748 -79.9735 149.894 +v 151.777 79.9735 9.26201 +v 151.777 -79.9735 9.26201 +v -15.9784 79.9735 151.218 +v -15.9784 -79.9735 151.218 +v -38.7453 79.9735 147.041 +v -38.7453 -79.9735 147.041 +v 150.298 79.9735 23.0798 +v 150.298 -79.9735 23.0798 +v 77.4845 79.9735 130.837 +v 77.4845 -79.9735 130.837 +v 48.0295 79.9735 144.275 +v 48.0295 -79.9735 144.275 +v 146.376 79.9735 41.184 +v 39.1525 79.9735 146.933 +v 146.376 -79.9735 41.184 +v 39.1525 -79.9735 146.933 +v 89.1057 79.9735 123.217 +v 89.1057 -79.9735 123.217 +v -47.6296 79.9735 144.408 +v -47.6296 -79.9735 144.408 +v 11.7835 79.9735 151.603 +v 11.7835 -79.9735 151.603 +v 92.8186 79.9735 120.445 +v 92.8186 -79.9735 120.445 +v -43.2075 79.9735 145.792 +v -43.2075 -79.9735 145.792 +v 145.054 79.9735 45.6248 +v 145.054 -79.9735 45.6248 +v 149.525 79.9735 27.6486 +v 134.34 79.9735 71.239 +v 149.525 -79.9735 27.6486 +v 134.34 -79.9735 71.239 +v 129.751 79.9735 79.2894 +v 129.751 -79.9735 79.2894 +v -25.1594 79.9735 149.964 +v -25.1594 -79.9735 149.964 +v 119.147 79.9735 94.478 +v 119.147 -79.9735 94.478 +v 52.4032 79.9735 142.745 +v 52.4032 -79.9735 142.745 +v 116.213 79.9735 98.0645 +v 116.213 -79.9735 98.0645 +v -6.73797 79.9735 151.911 +v -6.73797 -79.9735 151.911 +v 147.563 79.9735 36.7048 +v 147.563 -79.9735 36.7048 +v 143.596 79.9735 50.0233 +v 143.596 -79.9735 50.0233 +v 69.3713 79.9735 135.314 +v 69.3713 -79.9735 135.314 +v 20.9958 79.9735 150.603 +v 20.9958 -79.9735 150.603 +v -34.2471 79.9735 148.153 +v -34.2471 -79.9735 148.153 +v 30.1301 79.9735 149.045 +v 30.1301 -79.9735 149.045 +v -29.7171 79.9735 149.128 +v -29.7171 -79.9735 149.128 +v 16.3972 79.9735 151.173 +v 16.3972 -79.9735 151.173 +v -134.964 -74.1059 78.4312 +v -134.964 74.1059 78.4312 +v 119.862 -74.1059 -100 +v 119.862 74.1059 -100 +v 21.5638 79.7614 154.678 +v 21.5638 -79.7614 154.678 +v 142.175 79.7614 64.6265 +v 142.175 -79.7614 64.6265 +v 156.174 79.7614 0 +v 156.174 -79.7614 0 +v -11.6709 79.7614 155.737 +v -11.6709 -79.7614 155.737 +v -30.5211 79.7614 153.163 +v -30.5211 -79.7614 153.163 +v 155.522 79.7614 14.2579 +v 155.522 -79.7614 14.2579 +v -6.92028 79.7614 156.021 +v -6.92028 -79.7614 156.021 +v 128.054 79.7614 89.4005 +v 128.054 -79.7614 89.4005 +v 154.365 79.7614 23.7043 +v 154.365 -79.7614 23.7043 +v 109.664 79.7614 111.194 +v 35.5951 79.7614 152.064 +v 109.664 -79.7614 111.194 +v 35.5951 -79.7614 152.064 +v -16.4107 79.7614 155.309 +v -16.4107 -79.7614 155.309 +v 140.14 79.7614 68.9285 +v 140.14 -79.7614 68.9285 +v 66.9807 79.7614 141.081 +v 66.9807 -79.7614 141.081 +v 156.102 79.7614 4.75851 +v 156.102 -79.7614 4.75851 +v 83.6384 79.7614 131.89 +v 83.6384 -79.7614 131.89 +v 151.556 79.7614 37.6979 +v 151.556 -79.7614 37.6979 +v 150.337 79.7614 42.2982 +v 150.337 -79.7614 42.2982 +v 148.978 79.7614 46.8593 +v 125.271 79.7614 93.2607 +v 148.978 -79.7614 46.8593 +v 125.271 -79.7614 93.2607 +v 155.015 79.7614 18.9899 +v 155.015 -79.7614 18.9899 +v -39.7936 79.7614 151.019 +v -39.7936 -79.7614 151.019 +v 26.2668 79.7614 153.949 +v 26.2668 -79.7614 153.949 +v 12.1023 79.7614 155.704 +v 12.1023 -79.7614 155.704 +v 113.001 79.7614 107.801 +v 99.0549 79.7614 120.741 +v 113.001 -79.7614 107.801 +v 99.0549 -79.7614 120.741 +v 153.571 79.7614 28.3966 +v 153.571 -79.7614 28.3966 +v -44.3766 79.7614 149.737 +v -44.3766 -79.7614 149.737 +v 102.688 79.7614 117.667 +v 102.688 -79.7614 117.667 +v -21.1352 79.7614 154.737 +v -21.1352 -79.7614 154.737 +v 58.2631 79.7614 144.899 +v 30.9453 79.7614 153.077 +v 58.2631 -79.7614 144.899 +v 30.9453 -79.7614 153.077 +v 91.5165 79.7614 126.551 +v 91.5165 -79.7614 126.551 +v 95.33 79.7614 123.703 +v 95.33 -79.7614 123.703 +v 145.848 79.7614 55.8466 +v 62.651 79.7614 143.057 +v 145.848 -79.7614 55.8466 +v 62.651 -79.7614 143.057 +v 44.7912 79.7614 149.613 +v 44.7912 -79.7614 149.613 +v -53.4147 79.7614 146.756 +v 119.358 79.7614 100.718 +v 106.225 79.7614 114.484 +v -53.4147 -79.7614 146.756 +v 119.358 -79.7614 100.718 +v 106.225 -79.7614 114.484 +v 133.262 79.7614 81.4346 +v 133.262 -79.7614 81.4346 +v 40.2118 79.7614 150.908 +v 40.2118 -79.7614 150.908 +v 147.481 79.7614 51.3768 +v 147.481 -79.7614 51.3768 +v 87.6181 79.7614 129.28 +v 87.6181 -79.7614 129.28 +v -25.8402 79.7614 154.021 +v -25.8402 -79.7614 154.021 +v 49.329 79.7614 148.179 +v 49.329 -79.7614 148.179 +v 79.581 79.7614 134.377 +v 71.2483 79.7614 138.975 +v 122.371 79.7614 97.0343 +v 71.2483 -79.7614 138.975 +v 122.371 -79.7614 97.0343 +v 79.581 -79.7614 134.377 +v 152.634 79.7614 33.0626 +v 152.634 -79.7614 33.0626 +v 16.8409 79.7614 155.263 +v 16.8409 -79.7614 155.263 +v 144.078 79.7614 60.2645 +v 144.078 -79.7614 60.2645 +v 135.681 79.7614 77.3364 +v 135.681 -79.7614 77.3364 +v 2.59583 79.7614 156.152 +v 2.59583 -79.7614 156.152 +v 7.35248 79.7614 156.001 +v 7.35248 -79.7614 156.001 +v 155.884 79.7614 9.5126 +v 155.884 -79.7614 9.5126 +v 130.719 79.7614 85.4572 +v 130.719 -79.7614 85.4572 +v -35.1737 79.7614 152.162 +v -35.1737 -79.7614 152.162 +v 75.4497 79.7614 136.74 +v 75.4497 -79.7614 136.74 +v 137.975 79.7614 73.1664 +v 116.233 79.7614 104.308 +v 137.975 -79.7614 73.1664 +v 116.233 -79.7614 104.308 +v -48.9183 79.7614 148.315 +v -48.9183 -79.7614 148.315 +v -2.16322 79.7614 156.159 +v -2.16322 -79.7614 156.159 +v 53.821 79.7614 146.607 +v 53.821 -79.7614 146.607 +v -136.283 -75.5591 82.0536 +v -136.283 75.5591 82.0536 +v 123.717 -75.5591 -100 +v 123.717 75.5591 -100 +v 160.197 79.3378 4.88337 +v 160.197 -79.3378 4.88337 +v 41.2669 79.3378 154.868 +v 41.2669 -79.3378 154.868 +v -7.10186 79.3378 160.114 +v -7.10186 -79.3378 160.114 +v 101.654 79.3378 123.909 +v 101.654 -79.3378 123.909 +v 77.4294 79.3378 140.327 +v 77.4294 -79.3378 140.327 +v 152.887 79.3378 48.0888 +v 152.887 -79.3378 48.0888 +v -21.6898 79.3378 158.797 +v -21.6898 -79.3378 158.797 +v 22.1296 79.3378 158.737 +v 22.1296 -79.3378 158.737 +v 89.9172 79.3378 132.672 +v 89.9172 -79.3378 132.672 +v 159.083 79.3378 19.4882 +v 159.083 -79.3378 19.4882 +v 131.414 79.3378 91.7462 +v 131.414 -79.3378 91.7462 +v 2.66395 79.3378 160.25 +v 2.66395 -79.3378 160.25 +v 125.582 79.3378 99.5804 +v 125.582 -79.3378 99.5804 +v 143.817 79.3378 70.7371 +v 143.817 -79.3378 70.7371 +v -45.541 79.3378 153.665 +v -45.541 -79.3378 153.665 +v 93.9178 79.3378 129.871 +v 93.9178 -79.3378 129.871 +v 64.2949 79.3378 146.81 +v 64.2949 -79.3378 146.81 +v -26.5182 79.3378 158.063 +v -26.5182 -79.3378 158.063 +v 156.639 79.3378 33.9302 +v 156.639 -79.3378 33.9302 +v 50.6234 79.3378 152.067 +v 50.6234 -79.3378 152.067 +v 36.529 79.3378 156.053 +v 36.529 -79.3378 156.053 +v -36.0966 79.3378 156.154 +v -36.0966 -79.3378 156.154 +v 157.6 79.3378 29.1417 +v 157.6 -79.3378 29.1417 +v 12.4199 79.3378 159.79 +v 12.4199 -79.3378 159.79 +v 97.8313 79.3378 126.949 +v 97.8313 -79.3378 126.949 +v 151.351 79.3378 52.7248 +v 147.859 79.3378 61.8458 +v 151.351 -79.3378 52.7248 +v 147.859 -79.3378 61.8458 +v 136.758 79.3378 83.5714 +v 136.758 -79.3378 83.5714 +v -11.9771 79.3378 159.824 +v -11.9771 -79.3378 159.824 +v 73.1177 79.3378 142.621 +v 73.1177 -79.3378 142.621 +v 17.2828 79.3378 159.337 +v 17.2828 -79.3378 159.337 +v 115.966 79.3378 110.63 +v 115.966 -79.3378 110.63 +v 122.49 79.3378 103.36 +v 112.542 79.3378 114.112 +v 122.49 -79.3378 103.36 +v 112.542 -79.3378 114.112 +v 139.241 79.3378 79.3656 +v 139.241 -79.3378 79.3656 +v -54.8162 79.3378 150.606 +v -54.8162 -79.3378 150.606 +v 119.283 79.3378 107.045 +v 119.283 -79.3378 107.045 +v -2.21999 79.3378 160.257 +v -2.21999 -79.3378 160.257 +v 59.7918 79.3378 148.701 +v 59.7918 -79.3378 148.701 +v 158.415 79.3378 24.3262 +v 158.415 -79.3378 24.3262 +v 154.282 79.3378 43.4081 +v 154.282 -79.3378 43.4081 +v 81.6691 79.3378 137.903 +v 128.558 79.3378 95.7077 +v 128.558 -79.3378 95.7077 +v 81.6691 -79.3378 137.903 +v -40.8377 79.3378 154.982 +v -40.8377 -79.3378 154.982 +v 159.974 79.3378 9.7622 +v 159.974 -79.3378 9.7622 +v 145.906 79.3378 66.3222 +v 134.149 79.3378 87.6995 +v 145.906 -79.3378 66.3222 +v 134.149 -79.3378 87.6995 +v -16.8413 79.3378 159.385 +v -16.8413 -79.3378 159.385 +v 155.533 79.3378 38.6871 +v 155.533 -79.3378 38.6871 +v -50.2019 79.3378 152.207 +v -50.2019 -79.3378 152.207 +v 31.7572 79.3378 157.094 +v 31.7572 -79.3378 157.094 +v 160.272 79.3378 0 +v 149.674 79.3378 57.3119 +v 160.272 -79.3378 0 +v 149.674 -79.3378 57.3119 +v 105.382 79.3378 120.755 +v 105.382 -79.3378 120.755 +v 45.9665 79.3378 153.539 +v 45.9665 -79.3378 153.539 +v 7.5454 79.3378 160.094 +v 7.5454 -79.3378 160.094 +v 85.833 79.3378 135.351 +v 85.833 -79.3378 135.351 +v 26.956 79.3378 157.989 +v 26.956 -79.3378 157.989 +v 159.603 79.3378 14.632 +v 159.603 -79.3378 14.632 +v 141.595 79.3378 75.0862 +v 109.013 79.3378 117.488 +v 141.595 -79.3378 75.0862 +v 109.013 -79.3378 117.488 +v 68.7382 79.3378 144.783 +v 68.7382 -79.3378 144.783 +v 55.2332 79.3378 150.454 +v 55.2332 -79.3378 150.454 +v -31.3219 79.3378 157.182 +v -31.3219 -79.3378 157.182 +v -137.625 -76.812 85.7414 +v -137.625 76.812 85.7414 +v 127.641 -76.812 -100 +v 127.641 76.812 -100 +v 160.617 78.7038 34.7919 +v 160.617 -78.7038 34.7919 +v 115.4 78.7038 117.01 +v 115.4 -78.7038 117.01 +v 155.195 78.7038 54.0639 +v 155.195 -78.7038 54.0639 +v 22.6917 78.7038 162.768 +v 22.6917 -78.7038 162.768 +v 158.2 78.7038 44.5106 +v 158.2 -78.7038 44.5106 +v 142.778 78.7038 81.3814 +v 142.778 -78.7038 81.3814 +v -7.28223 78.7038 164.181 +v -7.28223 -78.7038 164.181 +v -17.269 78.7038 163.433 +v -17.269 -78.7038 163.433 +v 7.73704 78.7038 164.16 +v 7.73704 -78.7038 164.16 +v 164.037 78.7038 10.0101 +v 164.037 -78.7038 10.0101 +v -51.4769 78.7038 156.072 +v -51.4769 -78.7038 156.072 +v 74.9748 78.7038 146.244 +v 151.614 78.7038 63.4165 +v 74.9748 -78.7038 146.244 +v 151.614 -78.7038 63.4165 +v -46.6976 78.7038 157.568 +v -46.6976 -78.7038 157.568 +v -12.2813 78.7038 163.883 +v -12.2813 -78.7038 163.883 +v -37.0134 78.7038 160.12 +v -37.0134 -78.7038 160.12 +v 51.9091 78.7038 155.929 +v 51.9091 -78.7038 155.929 +v 65.9278 78.7038 150.539 +v 65.9278 -78.7038 150.539 +v -27.1917 78.7038 162.077 +v -27.1917 -78.7038 162.077 +v 163.123 78.7038 19.9831 +v 163.123 -78.7038 19.9831 +v 100.316 78.7038 130.173 +v 100.316 -78.7038 130.173 +v 140.232 78.7038 85.6939 +v 140.232 -78.7038 85.6939 +v -41.8749 78.7038 158.918 +v -41.8749 -78.7038 158.918 +v 147.47 78.7038 72.5337 +v 111.781 78.7038 120.471 +v 147.47 -78.7038 72.5337 +v 111.781 -78.7038 120.471 +v 162.438 78.7038 24.9441 +v 162.438 -78.7038 24.9441 +v 96.3032 78.7038 133.17 +v 61.3104 78.7038 152.478 +v 96.3032 -78.7038 133.17 +v 61.3104 -78.7038 152.478 +v 88.013 78.7038 138.788 +v 88.013 -78.7038 138.788 +v 153.476 78.7038 58.7675 +v 153.476 -78.7038 58.7675 +v -56.2084 78.7038 154.431 +v 118.912 78.7038 113.439 +v -56.2084 -78.7038 154.431 +v 118.912 -78.7038 113.439 +v 145.191 78.7038 76.9933 +v 145.191 -78.7038 76.9933 +v 134.752 78.7038 94.0764 +v 134.752 -78.7038 94.0764 +v 131.823 78.7038 98.1385 +v 131.823 -78.7038 98.1385 +v 79.3959 78.7038 143.891 +v 159.483 78.7038 39.6697 +v 122.313 78.7038 109.763 +v 108.059 78.7038 123.822 +v 79.3959 -78.7038 143.891 +v 159.483 -78.7038 39.6697 +v 122.313 -78.7038 109.763 +v 108.059 -78.7038 123.822 +v -2.27637 78.7038 164.327 +v -2.27637 -78.7038 164.327 +v 42.315 78.7038 158.801 +v 42.315 -78.7038 158.801 +v 56.6361 78.7038 154.275 +v 56.6361 -78.7038 154.275 +v 128.771 78.7038 102.109 +v 128.771 -78.7038 102.109 +v 149.611 78.7038 68.0067 +v 149.611 -78.7038 68.0067 +v -22.2407 78.7038 162.831 +v -22.2407 -78.7038 162.831 +v 137.556 78.7038 89.9269 +v 137.556 -78.7038 89.9269 +v 12.7353 78.7038 163.848 +v 12.7353 -78.7038 163.848 +v 156.77 78.7038 49.3102 +v 156.77 -78.7038 49.3102 +v 37.4568 78.7038 160.017 +v 37.4568 -78.7038 160.017 +v 92.2009 78.7038 136.042 +v 92.2009 -78.7038 136.042 +v 125.601 78.7038 105.986 +v 125.601 -78.7038 105.986 +v 2.73161 78.7038 164.32 +v 2.73161 -78.7038 164.32 +v 17.7217 78.7038 163.384 +v 17.7217 -78.7038 163.384 +v 161.603 78.7038 29.8819 +v 161.603 -78.7038 29.8819 +v 164.342 78.7038 0 +v 32.5638 78.7038 161.084 +v 164.342 -78.7038 0 +v 32.5638 -78.7038 161.084 +v 27.6406 78.7038 162.001 +v 27.6406 -78.7038 162.001 +v 70.484 78.7038 148.46 +v 70.484 -78.7038 148.46 +v 104.236 78.7038 127.057 +v 104.236 -78.7038 127.057 +v 83.7433 78.7038 141.406 +v 83.7433 -78.7038 141.406 +v 47.1339 78.7038 157.438 +v 47.1339 -78.7038 157.438 +v -32.1174 78.7038 161.174 +v -32.1174 -78.7038 161.174 +v 164.266 78.7038 5.0074 +v 164.266 -78.7038 5.0074 +v 163.656 78.7038 15.0036 +v 163.656 -78.7038 15.0036 +v 131.625 -77.8612 -100 +v 131.625 77.8612 -100 +v -138.988 -77.8612 89.485 +v -138.988 77.8612 89.485 +v 106.793 77.8612 130.174 +v 106.793 -77.8612 130.174 +v 102.777 77.8612 133.368 +v 102.777 -77.8612 133.368 +v -7.46092 77.8612 168.21 +v -7.46092 -77.8612 168.21 +v 168.297 77.8612 5.13027 +v 168.297 -77.8612 5.13027 +v 160.617 77.8612 50.5201 +v 160.617 -77.8612 50.5201 +v 125.314 77.8612 112.457 +v 125.314 -77.8612 112.457 +v 62.8148 77.8612 156.219 +v 62.8148 -77.8612 156.219 +v -22.7864 77.8612 166.826 +v -22.7864 -77.8612 166.826 +v 53.1828 77.8612 159.755 +v 53.1828 -77.8612 159.755 +v 7.92689 77.8612 168.188 +v 7.92689 -77.8612 168.188 +v 81.3441 77.8612 147.422 +v 81.3441 -77.8612 147.422 +v 58.0258 77.8612 158.061 +v 58.0258 -77.8612 158.061 +v 131.931 77.8612 104.615 +v 131.931 -77.8612 104.615 +v 168.375 77.8612 0 +v 90.1726 77.8612 142.194 +v 168.375 -77.8612 0 +v 90.1726 -77.8612 142.194 +v 157.242 77.8612 60.2095 +v 157.242 -77.8612 60.2095 +v 148.754 77.8612 78.8825 +v 148.754 -77.8612 78.8825 +v 114.524 77.8612 123.428 +v 114.524 -77.8612 123.428 +v 164.559 77.8612 35.6456 +v 164.559 -77.8612 35.6456 +v 13.0478 77.8612 167.869 +v 13.0478 -77.8612 167.869 +v 18.1566 77.8612 167.393 +v 18.1566 -77.8612 167.393 +v 128.682 77.8612 108.586 +v 128.682 -77.8612 108.586 +v -12.5827 77.8612 167.904 +v -12.5827 -77.8612 167.904 +v 48.2905 77.8612 161.301 +v 48.2905 -77.8612 161.301 +v 165.568 77.8612 30.6151 +v 165.568 -77.8612 30.6151 +v 135.057 77.8612 100.547 +v 135.057 -77.8612 100.547 +v 163.396 77.8612 40.6431 +v 163.396 -77.8612 40.6431 +v 72.2135 77.8612 152.103 +v 72.2135 -77.8612 152.103 +v 85.7982 77.8612 144.875 +v 94.4633 77.8612 139.38 +v 94.4633 -77.8612 139.38 +v 85.7982 -77.8612 144.875 +v 168.062 77.8612 10.2558 +v 168.062 -77.8612 10.2558 +v 38.3759 77.8612 163.943 +v 38.3759 -77.8612 163.943 +v 43.3533 77.8612 162.698 +v 43.3533 -77.8612 162.698 +v 138.058 77.8612 96.3848 +v 138.058 -77.8612 96.3848 +v -27.8589 77.8612 166.054 +v -27.8589 -77.8612 166.054 +v 76.8145 77.8612 149.832 +v 153.282 77.8612 69.6754 +v 76.8145 -77.8612 149.832 +v 153.282 -77.8612 69.6754 +v 162.082 77.8612 45.6028 +v 162.082 -77.8612 45.6028 +v -37.9216 77.8612 164.049 +v -37.9216 -77.8612 164.049 +v 28.3188 77.8612 165.977 +v 28.3188 -77.8612 165.977 +v 155.334 77.8612 64.9726 +v 146.281 77.8612 83.3783 +v -47.8434 77.8612 161.435 +v 155.334 -77.8612 64.9726 +v 146.281 -77.8612 83.3783 +v -47.8434 -77.8612 161.435 +v 143.673 77.8612 87.7967 +v 143.673 -77.8612 87.7967 +v 23.2485 77.8612 166.762 +v 23.2485 -77.8612 166.762 +v 67.5455 77.8612 154.233 +v 67.5455 -77.8612 154.233 +v 110.71 77.8612 126.86 +v 98.6662 77.8612 136.437 +v 110.71 -77.8612 126.86 +v 98.6662 -77.8612 136.437 +v -57.5877 77.8612 158.221 +v -57.5877 -77.8612 158.221 +v 167.672 77.8612 15.3717 +v 167.672 -77.8612 15.3717 +v -52.74 77.8612 159.902 +v -52.74 -77.8612 159.902 +v -42.9024 77.8612 162.818 +v -42.9024 -77.8612 162.818 +v -17.6928 77.8612 167.443 +v -17.6928 -77.8612 167.443 +v 140.931 77.8612 92.1335 +v 140.931 -77.8612 92.1335 +v -2.33223 77.8612 168.359 +v -2.33223 -77.8612 168.359 +v 159.003 77.8612 55.3905 +v 159.003 -77.8612 55.3905 +v -32.9055 77.8612 165.128 +v -32.9055 -77.8612 165.128 +v 167.126 77.8612 20.4734 +v 167.126 -77.8612 20.4734 +v 2.79863 77.8612 168.352 +v 2.79863 -77.8612 168.352 +v 33.3629 77.8612 165.037 +v 33.3629 -77.8612 165.037 +v 118.232 77.8612 119.881 +v 118.232 -77.8612 119.881 +v 151.088 77.8612 74.3135 +v 151.088 -77.8612 74.3135 +v 166.424 77.8612 25.5562 +v 166.424 -77.8612 25.5562 +v 121.829 77.8612 116.223 +v 121.829 -77.8612 116.223 +v 135.658 -78.7038 -100 +v 135.658 78.7038 -100 +v -140.367 -78.7038 93.2744 +v -140.367 78.7038 93.2744 +v 113.33 76.812 129.861 +v 113.33 -76.812 129.861 +v 149.742 76.812 85.3511 +v 149.742 -76.812 85.3511 +v 159.009 76.812 66.5099 +v 159.009 -76.812 66.5099 +v 144.266 76.812 94.3134 +v 144.266 -76.812 94.3134 +v 23.7986 76.812 170.708 +v 23.7986 -76.812 170.708 +v 8.11444 76.812 172.168 +v 8.11444 -76.812 172.168 +v -18.1114 76.812 171.405 +v -18.1114 -76.812 171.405 +v -58.9502 76.812 161.964 +v -58.9502 -76.812 161.964 +v 167.262 76.812 41.6047 +v 167.262 -76.812 41.6047 +v 168.452 76.812 36.489 +v 168.452 -76.812 36.489 +v 109.32 76.812 133.254 +v 109.32 -76.812 133.254 +v 171.08 76.812 20.9579 +v 171.08 -76.812 20.9579 +v 172.279 76.812 5.25165 +v 172.279 -76.812 5.25165 +v 170.362 76.812 26.1608 +v 170.362 -76.812 26.1608 +v 124.712 76.812 118.973 +v 124.712 -76.812 118.973 +v 160.962 76.812 61.6341 +v 160.962 -76.812 61.6341 +v 2.86485 76.812 172.335 +v 2.86485 -76.812 172.335 +v 147.072 76.812 89.874 +v 147.072 -76.812 89.874 +v 73.9221 76.812 155.702 +v 73.9221 -76.812 155.702 +v 54.4412 76.812 163.535 +v 54.4412 -76.812 163.535 +v -23.3256 76.812 170.773 +v -23.3256 -76.812 170.773 +v 128.279 76.812 115.118 +v 128.279 -76.812 115.118 +v 172.039 76.812 10.4984 +v 172.039 -76.812 10.4984 +v 169.486 76.812 31.3395 +v 169.486 -76.812 31.3395 +v 101.001 76.812 139.665 +v 101.001 -76.812 139.665 +v -28.518 76.812 169.983 +v -28.518 -76.812 169.983 +v 165.917 76.812 46.6818 +v 164.417 76.812 51.7154 +v 165.917 -76.812 46.6818 +v 164.417 -76.812 51.7154 +v 87.8282 76.812 148.303 +v 87.8282 -76.812 148.303 +v -2.38741 76.812 172.342 +v -2.38741 -76.812 172.342 +v 135.053 76.812 107.09 +v 135.053 -76.812 107.09 +v 83.2687 76.812 150.91 +v 83.2687 -76.812 150.91 +v 156.909 76.812 71.3239 +v 156.909 -76.812 71.3239 +v -53.9879 76.812 163.685 +v 59.3987 76.812 161.8 +v -53.9879 -76.812 163.685 +v 59.3987 -76.812 161.8 +v 96.6983 76.812 142.678 +v 96.6983 -76.812 142.678 +v -43.9175 76.812 166.67 +v -43.9175 -76.812 166.67 +v 141.325 76.812 98.6653 +v 141.325 -76.812 98.6653 +v 18.5862 76.812 171.354 +v 18.5862 -76.812 171.354 +v 138.253 76.812 102.926 +v 131.727 76.812 111.156 +v 138.253 -76.812 102.926 +v 131.727 -76.812 111.156 +v 34.1522 76.812 168.941 +v 34.1522 -76.812 168.941 +v 44.3791 76.812 166.548 +v 44.3791 -76.812 166.548 +v 152.273 76.812 80.7489 +v 152.273 -76.812 80.7489 +v -12.8804 76.812 171.877 +v -12.8804 -76.812 171.877 +v 69.1437 76.812 157.882 +v 69.1437 -76.812 157.882 +v 105.209 76.812 136.523 +v 105.209 -76.812 136.523 +v -48.9754 76.812 165.254 +v -48.9754 -76.812 165.254 +v 121.029 76.812 122.717 +v 92.3061 76.812 145.558 +v 121.029 -76.812 122.717 +v 92.3061 -76.812 145.558 +v 78.6319 76.812 153.377 +v 78.6319 -76.812 153.377 +v 49.4331 76.812 165.118 +v 49.4331 -76.812 165.118 +v 117.234 76.812 126.348 +v 117.234 -76.812 126.348 +v -33.6841 76.812 169.035 +v -33.6841 -76.812 169.035 +v 154.663 76.812 76.0717 +v 154.663 -76.812 76.0717 +v 39.2839 76.812 167.822 +v 39.2839 -76.812 167.822 +v 171.639 76.812 15.7354 +v 171.639 -76.812 15.7354 +v 28.9889 76.812 169.904 +v 28.9889 -76.812 169.904 +v -38.8188 76.812 167.931 +v -38.8188 -76.812 167.931 +v 13.3565 76.812 171.841 +v 13.3565 -76.812 171.841 +v 64.301 76.812 159.915 +v 64.301 -76.812 159.915 +v 162.765 76.812 56.7011 +v 162.765 -76.812 56.7011 +v -7.63745 76.812 172.19 +v -7.63745 -76.812 172.19 +v 172.359 76.812 0 +v 172.359 -76.812 0 +v 139.728 -79.3378 -100 +v 139.728 79.3378 -100 +v -141.759 -79.3378 97.0995 +v -141.759 79.3378 97.0995 +v -18.5238 75.5591 175.307 +v -18.5238 -75.5591 175.307 +v 174.975 75.5591 21.4351 +v 174.975 -75.5591 21.4351 +v 55.6808 75.5591 167.259 +v 55.6808 -75.5591 167.259 +v 173.345 75.5591 32.0531 +v 173.345 -75.5591 32.0531 +v 50.5587 75.5591 168.878 +v 50.5587 -75.5591 168.878 +v -7.81135 75.5591 176.11 +v -7.81135 -75.5591 176.11 +v 176.202 75.5591 5.37123 +v 176.202 -75.5591 5.37123 +v 166.471 75.5591 57.9922 +v 166.471 -75.5591 57.9922 +v 2.93008 75.5591 176.259 +v 2.93008 -75.5591 176.259 +v -34.451 75.5591 172.884 +v -34.451 -75.5591 172.884 +v 60.7512 75.5591 165.484 +v 60.7512 -75.5591 165.484 +v 168.161 75.5591 52.893 +v 168.161 -75.5591 52.893 +v 34.9299 75.5591 172.788 +v 34.9299 -75.5591 172.788 +v 141.401 75.5591 105.269 +v 107.605 75.5591 139.632 +v 141.401 -75.5591 105.269 +v 107.605 -75.5591 139.632 +v 171.071 75.5591 42.552 +v 171.071 -75.5591 42.552 +v 162.63 75.5591 68.0243 +v 153.152 75.5591 87.2945 +v 162.63 -75.5591 68.0243 +v 153.152 -75.5591 87.2945 +v 172.288 75.5591 37.3199 +v 172.288 -75.5591 37.3199 +v 80.4224 75.5591 156.87 +v 80.4224 -75.5591 156.87 +v 175.547 75.5591 16.0937 +v 175.547 -75.5591 16.0937 +v 98.9001 75.5591 145.927 +v 98.9001 -75.5591 145.927 +v 8.29921 75.5591 176.088 +v 8.29921 -75.5591 176.088 +v 147.55 75.5591 96.4609 +v 115.91 75.5591 132.818 +v 147.55 -75.5591 96.4609 +v 115.91 -75.5591 132.818 +v 40.1784 75.5591 171.644 +v 40.1784 -75.5591 171.644 +v 150.421 75.5591 91.9204 +v 150.421 -75.5591 91.9204 +v 45.3896 75.5591 170.34 +v 45.3896 -75.5591 170.34 +v -44.9175 75.5591 170.465 +v -44.9175 -75.5591 170.465 +v 89.828 75.5591 151.68 +v 89.828 -75.5591 151.68 +v 155.741 75.5591 82.5875 +v 155.741 -75.5591 82.5875 +v 144.543 75.5591 100.912 +v 75.6053 75.5591 159.247 +v 144.543 -75.5591 100.912 +v 75.6053 -75.5591 159.247 +v 70.7181 75.5591 161.477 +v 70.7181 -75.5591 161.477 +v 13.6606 75.5591 175.753 +v 13.6606 -75.5591 175.753 +v 24.3404 75.5591 174.595 +v 24.3404 -75.5591 174.595 +v 174.241 75.5591 26.7565 +v 174.241 -75.5591 26.7565 +v -60.2925 75.5591 165.652 +v -60.2925 -75.5591 165.652 +v 29.6489 75.5591 173.772 +v 29.6489 -75.5591 173.772 +v 123.785 75.5591 125.511 +v 123.785 -75.5591 125.511 +v 176.283 75.5591 0 +v 158.185 75.5591 77.8039 +v 103.3 75.5591 142.846 +v 176.283 -75.5591 0 +v 158.185 -75.5591 77.8039 +v 103.3 -75.5591 142.846 +v -2.44177 75.5591 176.266 +v -2.44177 -75.5591 176.266 +v 131.2 75.5591 117.739 +v 131.2 -75.5591 117.739 +v 175.956 75.5591 10.7375 +v 175.956 -75.5591 10.7375 +v 164.627 75.5591 63.0375 +v 164.627 -75.5591 63.0375 +v 111.809 75.5591 136.288 +v 94.4079 75.5591 148.872 +v 111.809 -75.5591 136.288 +v 94.4079 -75.5591 148.872 +v 85.1647 75.5591 154.346 +v 85.1647 -75.5591 154.346 +v 19.0094 75.5591 175.255 +v 19.0094 -75.5591 175.255 +v -13.1737 75.5591 175.79 +v -13.1737 -75.5591 175.79 +v 169.695 75.5591 47.7447 +v 169.695 -75.5591 47.7447 +v 160.482 75.5591 72.948 +v 160.482 -75.5591 72.948 +v -29.1674 75.5591 173.854 +v -29.1674 -75.5591 173.854 +v -39.7027 75.5591 171.754 +v -39.7027 -75.5591 171.754 +v 127.552 75.5591 121.682 +v 127.552 -75.5591 121.682 +v -55.2172 75.5591 167.412 +v 65.7651 75.5591 163.557 +v -55.2172 -75.5591 167.412 +v 65.7651 -75.5591 163.557 +v -23.8567 75.5591 174.662 +v -23.8567 -75.5591 174.662 +v -50.0906 75.5591 169.017 +v -50.0906 -75.5591 169.017 +v 134.727 75.5591 113.687 +v 134.727 -75.5591 113.687 +v 119.903 75.5591 129.225 +v 119.903 -75.5591 129.225 +v 138.128 75.5591 109.529 +v 138.128 -75.5591 109.529 +v -143.161 -79.7614 100.95 +v -143.161 79.7614 100.95 +v 143.826 -79.7614 -100 +v 143.826 79.7614 -100 +v 141.148 74.1059 111.924 +v 141.148 -74.1059 111.924 +v 2.99415 74.1059 180.113 +v 2.99415 -74.1059 180.113 +v 150.777 74.1059 98.5702 +v 150.777 -74.1059 98.5702 +v 13.9593 74.1059 179.596 +v 13.9593 -74.1059 179.596 +v -35.2044 74.1059 176.665 +v -35.2044 -74.1059 176.665 +v 56.8983 74.1059 170.916 +v 56.8983 -74.1059 170.916 +v 35.6937 74.1059 176.566 +v 35.6937 -74.1059 176.566 +v 51.6642 74.1059 172.57 +v 51.6642 -74.1059 172.57 +v 82.181 74.1059 160.3 +v 159.146 74.1059 84.3935 +v 82.181 -74.1059 160.3 +v 159.146 -74.1059 84.3935 +v 62.0796 74.1059 169.103 +v 62.0796 -74.1059 169.103 +v 118.445 74.1059 135.723 +v 118.445 -74.1059 135.723 +v 173.405 74.1059 48.7887 +v 173.405 -74.1059 48.7887 +v 156.501 74.1059 89.2034 +v 156.501 -74.1059 89.2034 +v 180.138 74.1059 0 +v 91.7923 74.1059 154.997 +v 180.138 -74.1059 0 +v 91.7923 -74.1059 154.997 +v 19.4251 74.1059 179.088 +v 19.4251 -74.1059 179.088 +v -24.3783 74.1059 178.481 +v -24.3783 -74.1059 178.481 +v 105.559 74.1059 145.969 +v 105.559 -74.1059 145.969 +v 170.112 74.1059 59.2603 +v 170.112 -74.1059 59.2603 +v 168.227 74.1059 64.416 +v 168.227 -74.1059 64.416 +v 30.2973 74.1059 177.572 +v 30.2973 -74.1059 177.572 +v -13.4618 74.1059 179.635 +v -13.4618 -74.1059 179.635 +v 24.8727 74.1059 178.413 +v 24.8727 -74.1059 178.413 +v 177.135 74.1059 32.754 +v 177.135 -74.1059 32.754 +v 87.027 74.1059 157.721 +v 87.027 -74.1059 157.721 +v -56.4246 74.1059 171.073 +v -56.4246 -74.1059 171.073 +v 153.71 74.1059 93.9304 +v 96.4723 74.1059 152.128 +v 153.71 -74.1059 93.9304 +v 96.4723 -74.1059 152.128 +v -45.8997 74.1059 174.192 +v -45.8997 -74.1059 174.192 +v 147.704 74.1059 103.118 +v 147.704 -74.1059 103.118 +v 126.492 74.1059 128.256 +v 109.958 74.1059 142.685 +v 101.063 74.1059 149.118 +v 126.492 -74.1059 128.256 +v 109.958 -74.1059 142.685 +v 101.063 -74.1059 149.118 +v 166.186 74.1059 69.5118 +v 166.186 -74.1059 69.5118 +v 67.2032 74.1059 167.133 +v 67.2032 -74.1059 167.133 +v -51.186 74.1059 172.713 +v -51.186 -74.1059 172.713 +v 114.254 74.1059 139.268 +v 114.254 -74.1059 139.268 +v 130.341 74.1059 124.342 +v 130.341 -74.1059 124.342 +v 77.2586 74.1059 162.73 +v 77.2586 -74.1059 162.73 +v 180.055 74.1059 5.48868 +v 180.055 -74.1059 5.48868 +v 41.057 74.1059 175.397 +v 41.057 -74.1059 175.397 +v -7.98216 74.1059 179.961 +v -7.98216 -74.1059 179.961 +v 134.069 74.1059 120.313 +v 134.069 -74.1059 120.313 +v 176.055 74.1059 38.136 +v 176.055 -74.1059 38.136 +v 178.051 74.1059 27.3416 +v 178.051 -74.1059 27.3416 +v 174.811 74.1059 43.4825 +v 174.811 -74.1059 43.4825 +v 122.525 74.1059 132.051 +v 122.525 -74.1059 132.051 +v 8.48069 74.1059 179.939 +v 8.48069 -74.1059 179.939 +v 46.3821 74.1059 174.065 +v 46.3821 -74.1059 174.065 +v 163.991 74.1059 74.5431 +v 163.991 -74.1059 74.5431 +v -29.8052 74.1059 177.655 +v -29.8052 -74.1059 177.655 +v 178.802 74.1059 21.9038 +v 178.802 -74.1059 21.9038 +v -61.6109 74.1059 169.275 +v -61.6109 -74.1059 169.275 +v -40.5709 74.1059 175.51 +v -40.5709 -74.1059 175.51 +v 171.838 74.1059 54.0496 +v 72.2645 74.1059 165.008 +v 171.838 -74.1059 54.0496 +v 72.2645 -74.1059 165.008 +v 137.673 74.1059 116.173 +v 137.673 -74.1059 116.173 +v 161.644 74.1059 79.5052 +v 161.644 -74.1059 79.5052 +v 144.493 74.1059 107.571 +v 144.493 -74.1059 107.571 +v 179.386 74.1059 16.4457 +v 179.386 -74.1059 16.4457 +v 179.804 74.1059 10.9723 +v 179.804 -74.1059 10.9723 +v -18.9288 74.1059 179.141 +v -18.9288 -74.1059 179.141 +v -2.49516 74.1059 180.121 +v -2.49516 -74.1059 180.121 +v 147.94 -79.9735 -100 +v 147.94 79.9735 -100 +v -144.568 -79.9735 104.816 +v -144.568 79.9735 104.816 +v 183.913 72.4562 0 +v 183.913 -72.4562 0 +v 3.0569 72.4562 183.888 +v 3.0569 -72.4562 183.888 +v 175.439 72.4562 55.1823 +v 162.481 72.4562 86.162 +v 175.439 -72.4562 55.1823 +v 162.481 -72.4562 86.162 +v 133.072 72.4562 126.948 +v 133.072 -72.4562 126.948 +v 171.752 72.4562 65.7658 +v 171.752 -72.4562 65.7658 +v -62.902 72.4562 172.822 +v -62.902 -72.4562 172.822 +v -46.8616 72.4562 177.843 +v -46.8616 -72.4562 177.843 +v 19.8321 72.4562 182.841 +v 19.8321 -72.4562 182.841 +v 173.676 72.4562 60.5022 +v 173.676 -72.4562 60.5022 +v 140.558 72.4562 118.607 +v 129.142 72.4562 130.944 +v 140.558 -72.4562 118.607 +v 129.142 -72.4562 130.944 +v 8.65841 72.4562 183.709 +v 8.65841 -72.4562 183.709 +v 47.3541 72.4562 177.712 +v 47.3541 -72.4562 177.712 +v 180.847 72.4562 33.4404 +v 180.847 -72.4562 33.4404 +v 83.9031 72.4562 163.659 +v 83.9031 -72.4562 163.659 +v 183.145 72.4562 16.7903 +v -24.8892 72.4562 182.221 +v 183.145 -72.4562 16.7903 +v -24.8892 -72.4562 182.221 +v 156.931 72.4562 95.8988 +v 147.521 72.4562 109.825 +v 156.931 -72.4562 95.8988 +v 147.521 -72.4562 109.825 +v -2.54745 72.4562 183.895 +v -2.54745 -72.4562 183.895 +v 159.781 72.4562 91.0727 +v -52.2586 72.4562 176.332 +v 159.781 -72.4562 91.0727 +v -52.2586 -72.4562 176.332 +v 167.428 72.4562 76.1052 +v 167.428 -72.4562 76.1052 +v 73.7788 72.4562 168.466 +v 73.7788 -72.4562 168.466 +v 58.0907 72.4562 174.498 +v 58.0907 -72.4562 174.498 +v 36.4417 72.4562 180.267 +v 36.4417 -72.4562 180.267 +v 165.031 72.4562 81.1713 +v 63.3805 72.4562 172.647 +v 165.031 -72.4562 81.1713 +v 63.3805 -72.4562 172.647 +v 78.8776 72.4562 166.14 +v 78.8776 -72.4562 166.14 +v 14.2519 72.4562 183.36 +v 14.2519 -72.4562 183.36 +v 103.181 72.4562 152.243 +v 103.181 -72.4562 152.243 +v -8.14943 72.4562 183.732 +v -8.14943 -72.4562 183.732 +v -41.4211 72.4562 179.188 +v -41.4211 -72.4562 179.188 +v 182.548 72.4562 22.3628 +v 182.548 -72.4562 22.3628 +v 144.106 72.4562 114.269 +v 144.106 -72.4562 114.269 +v -13.7438 72.4562 183.399 +v -13.7438 -72.4562 183.399 +v 125.093 72.4562 134.818 +v 125.093 -72.4562 134.818 +v 150.799 72.4562 105.28 +v 150.799 -72.4562 105.28 +v 93.7159 72.4562 158.245 +v 120.927 72.4562 138.567 +v 107.771 72.4562 149.028 +v 120.927 -72.4562 138.567 +v 107.771 -72.4562 149.028 +v 93.7159 -72.4562 158.245 +v 68.6115 72.4562 170.636 +v 68.6115 -72.4562 170.636 +v -35.9421 72.4562 180.367 +v -35.9421 -72.4562 180.367 +v 25.3939 72.4562 182.152 +v 25.3939 -72.4562 182.152 +v 178.475 72.4562 44.3937 +v 178.475 -72.4562 44.3937 +v -19.3255 72.4562 182.895 +v -19.3255 -72.4562 182.895 +v 88.8508 72.4562 161.027 +v 88.8508 -72.4562 161.027 +v 98.494 72.4562 155.316 +v 98.494 -72.4562 155.316 +v -30.4298 72.4562 181.378 +v -30.4298 -72.4562 181.378 +v -57.607 72.4562 174.658 +v -57.607 -72.4562 174.658 +v 183.572 72.4562 11.2022 +v 183.572 -72.4562 11.2022 +v 52.7469 72.4562 176.187 +v 52.7469 -72.4562 176.187 +v 30.9322 72.4562 181.293 +v 30.9322 -72.4562 181.293 +v 41.9174 72.4562 179.073 +v 41.9174 -72.4562 179.073 +v 181.782 72.4562 27.9145 +v 181.782 -72.4562 27.9145 +v 153.937 72.4562 100.636 +v 116.649 72.4562 142.187 +v 153.937 -72.4562 100.636 +v 116.649 -72.4562 142.187 +v 183.828 72.4562 5.6037 +v 183.828 -72.4562 5.6037 +v 136.878 72.4562 122.835 +v 136.878 -72.4562 122.835 +v 169.669 72.4562 70.9685 +v 169.669 -72.4562 70.9685 +v 177.039 72.4562 49.8111 +v 177.039 -72.4562 49.8111 +v 112.262 72.4562 145.675 +v 112.262 -72.4562 145.675 +v 179.745 72.4562 38.9351 +v 179.745 -72.4562 38.9351 +v 152.06 -79.9735 -100 +v 152.06 79.9735 -100 +v -145.977 -79.9735 108.688 +v -145.977 79.9735 108.688 +v 139.621 70.6143 125.296 +v 100.467 70.6143 158.428 +v 139.621 -70.6143 125.296 +v 100.467 -70.6143 158.428 +v -2.59849 70.6143 187.58 +v -2.59849 -70.6143 187.58 +v 59.2546 70.6143 177.994 +v 59.2546 -70.6143 177.994 +v 187.598 70.6143 0 +v 187.598 -70.6143 0 +v 37.1718 70.6143 183.878 +v 37.1718 -70.6143 183.878 +v 186.206 70.6143 22.8109 +v 186.206 -70.6143 22.8109 +v 187.511 70.6143 5.71598 +v 187.511 -70.6143 5.71598 +v 20.2295 70.6143 186.504 +v 20.2295 -70.6143 186.504 +v 150.477 70.6143 112.026 +v 150.477 -70.6143 112.026 +v 69.9863 70.6143 174.055 +v 69.9863 -70.6143 174.055 +v 14.5374 70.6143 187.034 +v 14.5374 -70.6143 187.034 +v 146.994 70.6143 116.559 +v 146.994 -70.6143 116.559 +v 173.068 70.6143 72.3905 +v 173.068 -70.6143 72.3905 +v 8.83189 70.6143 187.39 +v 8.83189 -70.6143 187.39 +v 183.346 70.6143 39.7152 +v 183.346 -70.6143 39.7152 +v 3.11815 70.6143 187.572 +v 3.11815 -70.6143 187.572 +v 186.815 70.6143 17.1267 +v 186.815 -70.6143 17.1267 +v 165.737 70.6143 87.8884 +v 165.737 -70.6143 87.8884 +v -58.7613 70.6143 178.158 +v -58.7613 -70.6143 178.158 +v -53.3057 70.6143 179.865 +v -53.3057 -70.6143 179.865 +v 180.587 70.6143 50.8092 +v 180.587 -70.6143 50.8092 +v 187.25 70.6143 11.4267 +v 187.25 -70.6143 11.4267 +v -25.3879 70.6143 185.872 +v -25.3879 -70.6143 185.872 +v 105.248 70.6143 155.293 +v 105.248 -70.6143 155.293 +v 177.156 70.6143 61.7144 +v 177.156 -70.6143 61.7144 +v 143.374 70.6143 120.983 +v 118.986 70.6143 145.036 +v 114.511 70.6143 148.594 +v 143.374 -70.6143 120.983 +v 118.986 -70.6143 145.036 +v 114.511 -70.6143 148.594 +v 153.82 70.6143 107.389 +v 127.599 70.6143 137.519 +v 153.82 -70.6143 107.389 +v 127.599 -70.6143 137.519 +v -42.251 70.6143 182.778 +v -42.251 -70.6143 182.778 +v 85.5843 70.6143 166.938 +v 75.2571 70.6143 171.841 +v 85.5843 -70.6143 166.938 +v 75.2571 -70.6143 171.841 +v -36.6623 70.6143 183.981 +v -36.6623 -70.6143 183.981 +v 170.782 70.6143 77.6301 +v 170.782 -70.6143 77.6301 +v 182.051 70.6143 45.2832 +v 182.051 -70.6143 45.2832 +v 90.631 70.6143 164.253 +v -47.8005 70.6143 181.406 +v 90.631 -70.6143 164.253 +v -47.8005 -70.6143 181.406 +v 184.471 70.6143 34.1104 +v 184.471 -70.6143 34.1104 +v -14.0192 70.6143 187.074 +v -14.0192 -70.6143 187.074 +v 160.076 70.6143 97.8203 +v 135.739 70.6143 129.492 +v 109.931 70.6143 152.014 +v 160.076 -70.6143 97.8203 +v 135.739 -70.6143 129.492 +v 109.931 -70.6143 152.014 +v -64.1624 70.6143 176.285 +v 162.982 70.6143 92.8975 +v -64.1624 -70.6143 176.285 +v 162.982 -70.6143 92.8975 +v -8.31272 70.6143 187.414 +v -8.31272 -70.6143 187.414 +v 131.73 70.6143 133.568 +v 131.73 -70.6143 133.568 +v 48.3029 70.6143 181.273 +v 48.3029 -70.6143 181.273 +v 80.4581 70.6143 169.469 +v 80.4581 -70.6143 169.469 +v 123.35 70.6143 141.343 +v 123.35 -70.6143 141.343 +v 95.5936 70.6143 161.415 +v 168.338 70.6143 82.7977 +v 168.338 -70.6143 82.7977 +v 95.5936 -70.6143 161.415 +v 175.194 70.6143 67.0836 +v 175.194 -70.6143 67.0836 +v 31.5519 70.6143 184.926 +v -19.7127 70.6143 186.56 +v 31.5519 -70.6143 184.926 +v -19.7127 -70.6143 186.56 +v 42.7572 70.6143 182.661 +v 42.7572 -70.6143 182.661 +v -31.0395 70.6143 185.012 +v -31.0395 -70.6143 185.012 +v 25.9027 70.6143 185.801 +v 25.9027 -70.6143 185.801 +v 64.6505 70.6143 176.106 +v 64.6505 -70.6143 176.106 +v 53.8037 70.6143 179.717 +v 53.8037 -70.6143 179.717 +v 178.955 70.6143 56.2879 +v 178.955 -70.6143 56.2879 +v 185.425 70.6143 28.4739 +v 185.425 -70.6143 28.4739 +v 157.021 70.6143 102.652 +v 157.021 -70.6143 102.652 +v 156.174 -79.7614 -100 +v 156.174 79.7614 -100 +v -147.384 -79.7614 112.554 +v -147.384 79.7614 112.554 +v 190.828 68.5852 11.645 +v 190.828 -68.5852 11.645 +v 87.2199 68.5852 170.129 +v 87.2199 -68.5852 170.129 +v 142.289 68.5852 127.69 +v 76.6954 68.5852 175.125 +v 142.289 -68.5852 127.69 +v 76.6954 -68.5852 175.125 +v 182.375 68.5852 57.3637 +v 182.375 -68.5852 57.3637 +v 180.542 68.5852 62.8939 +v 180.542 -68.5852 62.8939 +v -14.2872 68.5852 190.649 +v -14.2872 -68.5852 190.649 +v -8.47159 68.5852 190.996 +v -8.47159 -68.5852 190.996 +v 190.385 68.5852 17.454 +v 190.385 -68.5852 17.454 +v 37.8823 68.5852 187.393 +v 37.8823 -68.5852 187.393 +v -48.7141 68.5852 184.873 +v -48.7141 -68.5852 184.873 +v 191.183 68.5852 0 +v 112.032 68.5852 154.919 +v 191.183 -68.5852 0 +v 112.032 -68.5852 154.919 +v -31.6327 68.5852 188.548 +v -31.6327 -68.5852 188.548 +v 9.00068 68.5852 190.971 +v 9.00068 -68.5852 190.971 +v 125.707 68.5852 144.044 +v 107.259 68.5852 158.261 +v 125.707 -68.5852 144.044 +v 107.259 -68.5852 158.261 +v 176.376 68.5852 73.7739 +v 176.376 -68.5852 73.7739 +v 186.85 68.5852 40.4743 +v 186.85 -68.5852 40.4743 +v 156.76 68.5852 109.441 +v 156.76 -68.5852 109.441 +v 14.8153 68.5852 190.609 +v 14.8153 -68.5852 190.609 +v 3.17774 68.5852 191.157 +v 3.17774 -68.5852 191.157 +v 92.3631 68.5852 167.392 +v 92.3631 -68.5852 167.392 +v 189.765 68.5852 23.2468 +v 189.765 -68.5852 23.2468 +v 138.333 68.5852 131.967 +v 138.333 -68.5852 131.967 +v -54.3244 68.5852 183.303 +v -54.3244 -68.5852 183.303 +v -25.8731 68.5852 189.425 +v -25.8731 -68.5852 189.425 +v 65.886 68.5852 179.472 +v 54.832 68.5852 183.152 +v 65.886 -68.5852 179.472 +v 54.832 -68.5852 183.152 +v 20.6161 68.5852 190.069 +v 20.6161 -68.5852 190.069 +v 174.046 68.5852 79.1137 +v 174.046 -68.5852 79.1137 +v 168.904 68.5852 89.5681 +v 168.904 -68.5852 89.5681 +v 184.038 68.5852 51.7802 +v 184.038 -68.5852 51.7802 +v 166.097 68.5852 94.6729 +v 26.3978 68.5852 189.352 +v 166.097 -68.5852 94.6729 +v 26.3978 -68.5852 189.352 +v 188.968 68.5852 29.018 +v 188.968 -68.5852 29.018 +v 134.248 68.5852 136.12 +v 134.248 -68.5852 136.12 +v -20.0895 68.5852 190.125 +v -20.0895 -68.5852 190.125 +v 187.997 68.5852 34.7623 +v 187.997 -68.5852 34.7623 +v 71.3238 68.5852 177.381 +v 71.3238 -68.5852 177.381 +v 60.3871 68.5852 181.396 +v 60.3871 -68.5852 181.396 +v 146.114 68.5852 123.296 +v 146.114 -68.5852 123.296 +v -2.64815 68.5852 191.165 +v -2.64815 -68.5852 191.165 +v -43.0585 68.5852 186.271 +v -43.0585 -68.5852 186.271 +v 102.387 68.5852 161.456 +v 102.387 -68.5852 161.456 +v -59.8843 68.5852 181.563 +v 178.542 68.5852 68.3656 +v -59.8843 -68.5852 181.563 +v 178.542 -68.5852 68.3656 +v 121.26 68.5852 147.808 +v 43.5744 68.5852 186.152 +v 121.26 -68.5852 147.808 +v 43.5744 -68.5852 186.152 +v 49.2261 68.5852 184.737 +v 49.2261 -68.5852 184.737 +v 163.135 68.5852 99.6898 +v 153.353 68.5852 114.167 +v 163.135 -68.5852 99.6898 +v 153.353 -68.5852 114.167 +v 81.9957 68.5852 172.707 +v 81.9957 -68.5852 172.707 +v -37.363 68.5852 187.497 +v -37.363 -68.5852 187.497 +v 171.555 68.5852 84.3801 +v 171.555 -68.5852 84.3801 +v 97.4206 68.5852 164.5 +v 97.4206 -68.5852 164.5 +v 116.7 68.5852 151.434 +v 116.7 -68.5852 151.434 +v 32.1549 68.5852 188.46 +v 32.1549 -68.5852 188.46 +v 191.095 68.5852 5.82522 +v 191.095 -68.5852 5.82522 +v 160.022 68.5852 104.614 +v 160.022 -68.5852 104.614 +v 149.803 68.5852 118.786 +v 149.803 -68.5852 118.786 +v -65.3886 68.5852 179.654 +v -65.3886 -68.5852 179.654 +v 130.038 68.5852 140.147 +v 130.038 -68.5852 140.147 +v 185.53 68.5852 46.1487 +v 185.53 -68.5852 46.1487 +v 160.272 -79.3378 -100 +v 160.272 79.3378 -100 +v -148.786 -79.3378 116.404 +v -148.786 79.3378 116.404 +v 15.0846 66.3742 194.074 +v 15.0846 -66.3742 194.074 +v 9.16433 66.3742 194.444 +v 9.16433 -66.3742 194.444 +v -43.8414 66.3742 189.658 +v -43.8414 -66.3742 189.658 +v 188.903 66.3742 46.9877 +v 148.771 66.3742 125.537 +v 188.903 -66.3742 46.9877 +v 148.771 -66.3742 125.537 +v 159.61 66.3742 111.431 +v 159.61 -66.3742 111.431 +v -60.9731 66.3742 184.864 +v -60.9731 -66.3742 184.864 +v 191.415 66.3742 35.3943 +v 191.415 -66.3742 35.3943 +v 174.674 66.3742 85.9143 +v 50.1211 66.3742 188.096 +v 174.674 -66.3742 85.9143 +v 50.1211 -66.3742 188.096 +v 104.249 66.3742 164.391 +v 104.249 -66.3742 164.391 +v 183.825 66.3742 64.0374 +v 183.825 -66.3742 64.0374 +v -2.6963 66.3742 194.641 +v -2.6963 -66.3742 194.641 +v -20.4547 66.3742 193.582 +v -20.4547 -66.3742 193.582 +v 32.7396 66.3742 191.887 +v 32.7396 -66.3742 191.887 +v 123.465 66.3742 150.495 +v 123.465 -66.3742 150.495 +v 20.9909 66.3742 193.524 +v 20.9909 -66.3742 193.524 +v 94.0425 66.3742 170.436 +v 118.822 66.3742 154.187 +v 114.069 66.3742 157.736 +v 94.0425 -66.3742 170.436 +v 118.822 -66.3742 154.187 +v 114.069 -66.3742 157.736 +v 83.4866 66.3742 175.847 +v 83.4866 -66.3742 175.847 +v 181.788 66.3742 69.6087 +v 181.788 -66.3742 69.6087 +v 190.247 66.3742 41.2102 +v 190.247 -66.3742 41.2102 +v 194.569 66.3742 5.93114 +v 194.569 -66.3742 5.93114 +v -55.3121 66.3742 186.636 +v -55.3121 -66.3742 186.636 +v 3.23552 66.3742 194.633 +v 3.23552 -66.3742 194.633 +v 72.6206 66.3742 180.606 +v 72.6206 -66.3742 180.606 +v -26.3435 66.3742 192.869 +v -26.3435 -66.3742 192.869 +v -38.0423 66.3742 190.906 +v -38.0423 -66.3742 190.906 +v 171.975 66.3742 91.1966 +v 144.876 66.3742 130.012 +v 136.688 66.3742 138.595 +v 171.975 -66.3742 91.1966 +v 144.876 -66.3742 130.012 +v 136.688 -66.3742 138.595 +v 193.215 66.3742 23.6695 +v 193.215 -66.3742 23.6695 +v 194.66 66.3742 0 +v 132.402 66.3742 142.695 +v 194.66 -66.3742 0 +v 132.402 -66.3742 142.695 +v 88.8057 66.3742 173.222 +v 88.8057 -66.3742 173.222 +v 109.21 66.3742 161.138 +v 109.21 -66.3742 161.138 +v 61.485 66.3742 184.694 +v 61.485 -66.3742 184.694 +v 156.141 66.3742 116.243 +v 152.527 66.3742 120.946 +v 156.141 -66.3742 116.243 +v 152.527 -66.3742 120.946 +v -32.2079 66.3742 191.977 +v -32.2079 -66.3742 191.977 +v 26.8777 66.3742 192.795 +v 26.8777 -66.3742 192.795 +v -8.62562 66.3742 194.468 +v -8.62562 -66.3742 194.468 +v 99.1918 66.3742 167.491 +v 166.101 66.3742 101.502 +v 166.101 -66.3742 101.502 +v 99.1918 -66.3742 167.491 +v 177.211 66.3742 80.5522 +v 177.211 -66.3742 80.5522 +v 192.404 66.3742 29.5456 +v 192.404 -66.3742 29.5456 +v -14.5469 66.3742 194.115 +v -14.5469 -66.3742 194.115 +v -66.5775 66.3742 182.92 +v -66.5775 -66.3742 182.92 +v 193.847 66.3742 17.7714 +v 193.847 -66.3742 17.7714 +v 38.571 66.3742 190.8 +v 38.571 -66.3742 190.8 +v 179.583 66.3742 75.1153 +v 179.583 -66.3742 75.1153 +v 140.848 66.3742 134.366 +v 140.848 -66.3742 134.366 +v -49.5998 66.3742 188.234 +v -49.5998 -66.3742 188.234 +v 194.298 66.3742 11.8568 +v 194.298 -66.3742 11.8568 +v 185.691 66.3742 58.4067 +v 185.691 -66.3742 58.4067 +v 44.3667 66.3742 189.536 +v 44.3667 -66.3742 189.536 +v 55.829 66.3742 186.482 +v 55.829 -66.3742 186.482 +v 169.117 66.3742 96.3942 +v 169.117 -66.3742 96.3942 +v 127.993 66.3742 146.663 +v 127.993 -66.3742 146.663 +v 78.0898 66.3742 178.31 +v 78.0898 -66.3742 178.31 +v 187.384 66.3742 52.7217 +v 187.384 -66.3742 52.7217 +v 162.931 66.3742 106.516 +v 67.084 66.3742 182.735 +v 162.931 -66.3742 106.516 +v 67.084 -66.3742 182.735 +v -150.178 -78.7038 120.229 +v -150.178 78.7038 120.229 +v 164.342 -78.7038 -100 +v 164.342 78.7038 -100 +v 111.093 63.9871 163.918 +v 111.093 -63.9871 163.918 +v -67.7259 63.9871 186.075 +v 158.834 63.9871 118.248 +v -67.7259 -63.9871 186.075 +v 158.834 -63.9871 118.248 +v -56.2662 63.9871 189.855 +v -56.2662 -63.9871 189.855 +v -14.7978 63.9871 197.463 +v -14.7978 -63.9871 197.463 +v -2.74281 63.9871 197.998 +v -2.74281 -63.9871 197.998 +v 165.742 63.9871 108.353 +v 165.742 -63.9871 108.353 +v -8.7744 63.9871 197.823 +v -8.7744 -63.9871 197.823 +v 195.723 63.9871 30.0553 +v 195.723 -63.9871 30.0553 +v 56.792 63.9871 189.698 +v 56.792 -63.9871 189.698 +v 73.8733 63.9871 183.721 +v 73.8733 -63.9871 183.721 +v 198.017 63.9871 0 +v 198.017 -63.9871 0 +v 33.3043 63.9871 195.196 +v 33.3043 -63.9871 195.196 +v 45.1319 63.9871 192.805 +v 45.1319 -63.9871 192.805 +v 184.924 63.9871 70.8093 +v 184.924 -63.9871 70.8093 +v -44.5976 63.9871 192.93 +v -44.5976 -63.9871 192.93 +v 95.6646 63.9871 173.376 +v 95.6646 -63.9871 173.376 +v 151.337 63.9871 127.703 +v 151.337 -63.9871 127.703 +v 196.548 63.9871 24.0778 +v 196.548 -63.9871 24.0778 +v 168.966 63.9871 103.253 +v 168.966 -63.9871 103.253 +v 172.034 63.9871 98.0569 +v 172.034 -63.9871 98.0569 +v 194.716 63.9871 36.0048 +v 194.716 -63.9871 36.0048 +v -62.0248 63.9871 188.052 +v -62.0248 -63.9871 188.052 +v 130.201 63.9871 149.193 +v -38.6985 63.9871 194.199 +v 130.201 -63.9871 149.193 +v -38.6985 -63.9871 194.199 +v 188.893 63.9871 59.4141 +v 188.893 -63.9871 59.4141 +v 116.036 63.9871 160.457 +v 116.036 -63.9871 160.457 +v 125.594 63.9871 153.091 +v 125.594 -63.9871 153.091 +v 192.162 63.9871 47.7982 +v 134.686 63.9871 145.157 +v 192.162 -63.9871 47.7982 +v 134.686 -63.9871 145.157 +v 68.2411 63.9871 185.887 +v 68.2411 -63.9871 185.887 +v 197.19 63.9871 18.0779 +v 197.19 -63.9871 18.0779 +v 162.363 63.9871 113.353 +v 162.363 -63.9871 113.353 +v 100.903 63.9871 170.38 +v 143.277 63.9871 136.684 +v 143.277 -63.9871 136.684 +v 100.903 -63.9871 170.38 +v 197.925 63.9871 6.03344 +v 197.925 -63.9871 6.03344 +v 190.616 63.9871 53.6311 +v 190.616 -63.9871 53.6311 +v 186.995 63.9871 65.142 +v 186.995 -63.9871 65.142 +v -50.4553 63.9871 191.481 +v -50.4553 -63.9871 191.481 +v 147.376 63.9871 132.255 +v 147.376 -63.9871 132.255 +v -20.8075 63.9871 196.921 +v -20.8075 -63.9871 196.921 +v 50.9856 63.9871 191.341 +v 50.9856 -63.9871 191.341 +v 21.353 63.9871 196.863 +v 21.353 -63.9871 196.863 +v 15.3448 63.9871 197.422 +v 15.3448 -63.9871 197.422 +v 84.9266 63.9871 178.881 +v 84.9266 -63.9871 178.881 +v 155.158 63.9871 123.032 +v 155.158 -63.9871 123.032 +v 182.68 63.9871 76.4109 +v 79.4368 63.9871 181.385 +v 182.68 -63.9871 76.4109 +v 79.4368 -63.9871 181.385 +v 3.29133 63.9871 197.99 +v 3.29133 -63.9871 197.99 +v 90.3375 63.9871 176.21 +v 90.3375 -63.9871 176.21 +v 27.3414 63.9871 196.12 +v 27.3414 -63.9871 196.12 +v 106.047 63.9871 167.227 +v 106.047 -63.9871 167.227 +v 177.687 63.9871 87.3962 +v 177.687 -63.9871 87.3962 +v -26.7979 63.9871 196.195 +v -26.7979 -63.9871 196.195 +v 174.942 63.9871 92.7696 +v 174.942 -63.9871 92.7696 +v 9.3224 63.9871 197.798 +v 9.3224 -63.9871 197.798 +v 180.268 63.9871 81.9416 +v 180.268 -63.9871 81.9416 +v 62.5456 63.9871 187.88 +v 62.5456 -63.9871 187.88 +v 197.65 63.9871 12.0613 +v 197.65 -63.9871 12.0613 +v 193.529 63.9871 41.921 +v 193.529 -63.9871 41.921 +v -32.7634 63.9871 195.288 +v -32.7634 -63.9871 195.288 +v 39.2363 63.9871 194.091 +v 39.2363 -63.9871 194.091 +v 120.871 63.9871 156.847 +v 120.871 -63.9871 156.847 +v 139.046 63.9871 140.986 +v 139.046 -63.9871 140.986 +v 161.425 61.4304 120.177 +v 161.425 -61.4304 120.177 +v 149.78 61.4304 134.412 +v 149.78 -61.4304 134.412 +v 27.7874 61.4304 199.32 +v 27.7874 -61.4304 199.32 +v 196.686 61.4304 42.6049 +v 196.686 -61.4304 42.6049 +v -33.2979 61.4304 198.474 +v -33.2979 -61.4304 198.474 +v 168.445 61.4304 110.121 +v 136.883 61.4304 147.525 +v 168.445 -61.4304 110.121 +v 136.883 -61.4304 147.525 +v -2.78755 61.4304 201.228 +v -2.78755 -61.4304 201.228 +v 69.3543 61.4304 188.919 +v 69.3543 -61.4304 188.919 +v -68.8307 61.4304 189.111 +v 75.0784 61.4304 186.718 +v -68.8307 -61.4304 189.111 +v 75.0784 -61.4304 186.718 +v 177.796 61.4304 94.283 +v 177.796 -61.4304 94.283 +v -39.3298 61.4304 197.367 +v -39.3298 -61.4304 197.367 +v 91.8112 61.4304 179.084 +v 91.8112 -61.4304 179.084 +v 33.8476 61.4304 198.381 +v 33.8476 -61.4304 198.381 +v 180.586 61.4304 88.8219 +v 180.586 -61.4304 88.8219 +v 200.407 61.4304 18.3728 +v 200.407 -61.4304 18.3728 +v -15.0392 61.4304 200.685 +v -15.0392 -61.4304 200.685 +v 165.012 61.4304 115.202 +v 165.012 -61.4304 115.202 +v 198.916 61.4304 30.5456 +v 198.916 -61.4304 30.5456 +v 171.723 61.4304 104.938 +v 171.723 -61.4304 104.938 +v 45.8682 61.4304 195.951 +v 39.8764 61.4304 197.257 +v 45.8682 -61.4304 195.951 +v 39.8764 -61.4304 197.257 +v 183.208 61.4304 83.2784 +v 183.208 -61.4304 83.2784 +v 122.843 61.4304 159.405 +v 122.843 -61.4304 159.405 +v 201.154 61.4304 6.13187 +v 201.154 -61.4304 6.13187 +v -21.147 61.4304 200.133 +v -21.147 -61.4304 200.133 +v 153.805 61.4304 129.786 +v 153.805 -61.4304 129.786 +v 86.312 61.4304 181.799 +v -57.1841 61.4304 192.952 +v 86.312 -61.4304 181.799 +v -57.1841 -61.4304 192.952 +v 63.5659 61.4304 190.945 +v 63.5659 -61.4304 190.945 +v 102.549 61.4304 173.16 +v 195.296 61.4304 48.578 +v 195.296 -61.4304 48.578 +v 102.549 -61.4304 173.16 +v 112.906 61.4304 166.592 +v 112.906 -61.4304 166.592 +v 190.046 61.4304 66.2046 +v 190.046 -61.4304 66.2046 +v 9.47448 61.4304 201.024 +v 9.47448 -61.4304 201.024 +v 15.5951 61.4304 200.642 +v 15.5951 -61.4304 200.642 +v 200.874 61.4304 12.258 +v 200.874 -61.4304 12.258 +v 185.661 61.4304 77.6575 +v 127.643 61.4304 155.589 +v 185.661 -61.4304 77.6575 +v 127.643 -61.4304 155.589 +v 193.726 61.4304 54.506 +v 193.726 -61.4304 54.506 +v 157.689 61.4304 125.039 +v 145.615 61.4304 138.913 +v 157.689 -61.4304 125.039 +v 145.615 -61.4304 138.913 +v 107.777 61.4304 169.955 +v 107.777 -61.4304 169.955 +v -8.91754 61.4304 201.05 +v -8.91754 -61.4304 201.05 +v 199.754 61.4304 24.4706 +v 199.754 -61.4304 24.4706 +v 51.8174 61.4304 194.462 +v 51.8174 -61.4304 194.462 +v 80.7327 61.4304 184.344 +v 80.7327 -61.4304 184.344 +v -51.2784 61.4304 194.605 +v -51.2784 -61.4304 194.605 +v 191.975 61.4304 60.3833 +v 191.975 -61.4304 60.3833 +v -63.0367 61.4304 191.12 +v -63.0367 -61.4304 191.12 +v 141.314 61.4304 143.286 +v 132.324 61.4304 151.627 +v 141.314 -61.4304 143.286 +v 132.324 -61.4304 151.627 +v 187.941 61.4304 71.9645 +v 174.84 61.4304 99.6565 +v 187.941 -61.4304 71.9645 +v 174.84 -61.4304 99.6565 +v 197.893 61.4304 36.5922 +v 197.893 -61.4304 36.5922 +v 97.2252 61.4304 176.204 +v 97.2252 -61.4304 176.204 +v -27.2351 61.4304 199.396 +v -27.2351 -61.4304 199.396 +v 201.247 61.4304 0 +v 201.247 -61.4304 0 +v 117.929 61.4304 163.074 +v 117.929 -61.4304 163.074 +v 3.34502 61.4304 201.22 +v 3.34502 -61.4304 201.22 +v 57.7184 61.4304 192.793 +v 57.7184 -61.4304 192.793 +v -45.3251 61.4304 196.077 +v -45.3251 -61.4304 196.077 +v 21.7013 61.4304 200.074 +v 21.7013 -61.4304 200.074 +v -151.557 -77.8612 124.019 +v -151.557 77.8612 124.019 +v 168.375 -77.8612 -100 +v 168.375 77.8612 -100 +v 203.962 58.7108 12.4465 +v 203.962 -58.7108 12.4465 +v -69.889 58.7108 192.018 +v -69.889 -58.7108 192.018 +v 183.362 58.7108 90.1877 +v 163.907 58.7108 122.024 +v 183.362 -58.7108 90.1877 +v 163.907 -58.7108 122.024 +v 3.39645 58.7108 204.314 +v 3.39645 -58.7108 204.314 +v 188.515 58.7108 78.8515 +v 188.515 -58.7108 78.8515 +v 22.035 58.7108 203.15 +v 22.035 -58.7108 203.15 +v 134.359 58.7108 153.958 +v 134.359 -58.7108 153.958 +v 203.488 58.7108 18.6553 +v 203.488 -58.7108 18.6553 +v 199.71 58.7108 43.26 +v 199.71 -58.7108 43.26 +v 196.704 58.7108 55.3441 +v 196.704 -58.7108 55.3441 +v 114.642 58.7108 169.153 +v 114.642 -58.7108 169.153 +v 202.826 58.7108 24.8468 +v 202.826 -58.7108 24.8468 +v 109.435 58.7108 172.568 +v 109.435 -58.7108 172.568 +v 194.927 58.7108 61.3118 +v 194.927 -58.7108 61.3118 +v 28.2146 58.7108 202.385 +v 28.2146 -58.7108 202.385 +v 98.7201 58.7108 178.913 +v 98.7201 -58.7108 178.913 +v 198.299 58.7108 49.3249 +v 198.299 -58.7108 49.3249 +v 200.936 58.7108 37.1549 +v -33.8099 58.7108 201.525 +v 200.936 -58.7108 37.1549 +v -33.8099 -58.7108 201.525 +v 177.529 58.7108 101.189 +v 177.529 -58.7108 101.189 +v 143.487 58.7108 145.489 +v 143.487 -58.7108 145.489 +v -27.6539 58.7108 202.462 +v -27.6539 -58.7108 202.462 +v 46.5735 58.7108 198.964 +v 46.5735 -58.7108 198.964 +v -21.4721 58.7108 203.211 +v -21.4721 -58.7108 203.211 +v 119.743 58.7108 165.582 +v 64.5433 58.7108 193.881 +v 119.743 -58.7108 165.582 +v 64.5433 -58.7108 193.881 +v 204.247 58.7108 6.22615 +v 204.247 -58.7108 6.22615 +v 15.835 58.7108 203.727 +v 15.835 -58.7108 203.727 +v 201.974 58.7108 31.0152 +v 201.974 -58.7108 31.0152 +v 124.732 58.7108 161.857 +v 124.732 -58.7108 161.857 +v -15.2705 58.7108 203.77 +v -15.2705 -58.7108 203.77 +v 9.62017 58.7108 204.115 +v 9.62017 -58.7108 204.115 +v 70.4207 58.7108 191.824 +v 70.4207 -58.7108 191.824 +v 192.968 58.7108 67.2226 +v 81.974 58.7108 187.179 +v 192.968 -58.7108 67.2226 +v 81.974 -58.7108 187.179 +v 174.363 58.7108 106.551 +v 174.363 -58.7108 106.551 +v 87.6392 58.7108 184.594 +v 40.4896 58.7108 200.29 +v 87.6392 -58.7108 184.594 +v 40.4896 -58.7108 200.29 +v 104.126 58.7108 175.822 +v 138.988 58.7108 149.793 +v 138.988 -58.7108 149.793 +v 104.126 -58.7108 175.822 +v -39.9345 58.7108 200.402 +v -39.9345 -58.7108 200.402 +v 186.025 58.7108 84.5589 +v 186.025 -58.7108 84.5589 +v 52.6141 58.7108 197.452 +v 52.6141 -58.7108 197.452 +v 34.368 58.7108 201.431 +v 34.368 -58.7108 201.431 +v 76.2328 58.7108 189.589 +v -58.0634 58.7108 195.919 +v 76.2328 -58.7108 189.589 +v -58.0634 -58.7108 195.919 +v -2.83042 58.7108 204.322 +v -2.83042 -58.7108 204.322 +v -64.0059 58.7108 194.059 +v 204.342 58.7108 0 +v 190.83 58.7108 73.071 +v 171.036 58.7108 111.814 +v 152.083 58.7108 136.479 +v 204.342 -58.7108 0 +v -64.0059 -58.7108 194.059 +v 190.83 -58.7108 73.071 +v 171.036 -58.7108 111.814 +v 152.083 -58.7108 136.479 +v -52.0669 58.7108 197.597 +v -52.0669 -58.7108 197.597 +v 58.6059 58.7108 195.757 +v 58.6059 -58.7108 195.757 +v 93.2229 58.7108 181.838 +v 180.529 58.7108 95.7327 +v 167.549 58.7108 116.974 +v 93.2229 -58.7108 181.838 +v 180.529 -58.7108 95.7327 +v 167.549 -58.7108 116.974 +v 160.113 58.7108 126.962 +v 160.113 -58.7108 126.962 +v 156.171 58.7108 131.782 +v 156.171 -58.7108 131.782 +v -46.0221 58.7108 199.092 +v -46.0221 -58.7108 199.092 +v -9.05466 58.7108 204.141 +v -9.05466 -58.7108 204.141 +v 147.854 58.7108 141.049 +v 147.854 -58.7108 141.049 +v 129.606 58.7108 157.981 +v 129.606 -58.7108 157.981 +v -152.919 -76.812 127.762 +v -152.919 76.812 127.762 +v 172.359 -76.812 -100 +v 172.359 76.812 -100 +v -15.491 55.8355 206.712 +v -15.491 -55.8355 206.712 +v 105.629 55.8355 178.361 +v 186.01 55.8355 91.4898 +v 186.01 -55.8355 91.4898 +v 105.629 -55.8355 178.361 +v 16.0636 55.8355 206.669 +v 16.0636 -55.8355 206.669 +v 205.754 55.8355 25.2056 +v 176.88 55.8355 108.089 +v 205.754 -55.8355 25.2056 +v 176.88 -55.8355 108.089 +v 34.8643 55.8355 204.339 +v 34.8643 -55.8355 204.339 +v 191.237 55.8355 79.99 +v 191.237 -55.8355 79.99 +v 3.44549 55.8355 207.264 +v 3.44549 -55.8355 207.264 +v 59.4521 55.8355 198.584 +v 59.4521 -55.8355 198.584 +v -70.8981 55.8355 194.791 +v -70.8981 -55.8355 194.791 +v 22.3532 55.8355 206.083 +v 22.3532 -55.8355 206.083 +v 9.75906 55.8355 207.062 +v 9.75906 -55.8355 207.062 +v 203.837 55.8355 37.6913 +v 203.837 -55.8355 37.6913 +v 207.196 55.8355 6.31604 +v 207.196 -55.8355 6.31604 +v 180.092 55.8355 102.65 +v 169.968 55.8355 118.663 +v 180.092 -55.8355 102.65 +v 169.968 -55.8355 118.663 +v 121.471 55.8355 167.973 +v 121.471 -55.8355 167.973 +v 204.891 55.8355 31.463 +v 204.891 -55.8355 31.463 +v 158.425 55.8355 133.684 +v 158.425 -55.8355 133.684 +v 206.426 55.8355 18.9247 +v 206.426 -55.8355 18.9247 +v 188.711 55.8355 85.7797 +v 188.711 -55.8355 85.7797 +v 136.299 55.8355 156.181 +v 136.299 -55.8355 156.181 +v 111.015 55.8355 175.059 +v 111.015 -55.8355 175.059 +v -64.93 55.8355 196.861 +v -64.93 -55.8355 196.861 +v 140.995 55.8355 151.956 +v 131.477 55.8355 160.262 +v 140.995 -55.8355 151.956 +v 131.477 -55.8355 160.262 +v 53.3738 55.8355 200.303 +v 53.3738 -55.8355 200.303 +v -40.5111 55.8355 203.295 +v -40.5111 -55.8355 203.295 +v 126.533 55.8355 164.193 +v 126.533 -55.8355 164.193 +v -2.87128 55.8355 207.272 +v -2.87128 -55.8355 207.272 +v 41.0742 55.8355 203.182 +v 41.0742 -55.8355 203.182 +v -52.8186 55.8355 200.45 +v -52.8186 -55.8355 200.45 +v 197.741 55.8355 62.197 +v 197.741 -55.8355 62.197 +v 193.586 55.8355 74.126 +v 193.586 -55.8355 74.126 +v 83.1576 55.8355 189.881 +v 83.1576 -55.8355 189.881 +v 199.544 55.8355 56.1431 +v 199.544 -55.8355 56.1431 +v 206.907 55.8355 12.6262 +v 206.907 -55.8355 12.6262 +v 145.559 55.8355 147.589 +v 116.297 55.8355 171.596 +v 145.559 -55.8355 147.589 +v 116.297 -55.8355 171.596 +v -9.18539 55.8355 207.089 +v -9.18539 -55.8355 207.089 +v 195.754 55.8355 68.1932 +v 195.754 -55.8355 68.1932 +v 166.274 55.8355 123.786 +v -28.0531 55.8355 205.385 +v 166.274 -55.8355 123.786 +v -28.0531 -55.8355 205.385 +v 88.9045 55.8355 187.259 +v 88.9045 -55.8355 187.259 +v 173.505 55.8355 113.429 +v 173.505 -55.8355 113.429 +v -58.9017 55.8355 198.748 +v -58.9017 -55.8355 198.748 +v 71.4375 55.8355 194.594 +v 71.4375 -55.8355 194.594 +v 207.292 55.8355 0 +v 94.5689 55.8355 184.464 +v 207.292 -55.8355 0 +v 94.5689 -55.8355 184.464 +v 28.622 55.8355 205.307 +v 28.622 -55.8355 205.307 +v 77.3334 55.8355 192.327 +v 77.3334 -55.8355 192.327 +v -21.7822 55.8355 206.145 +v -21.7822 -55.8355 206.145 +v -46.6866 55.8355 201.966 +v -46.6866 -55.8355 201.966 +v 65.4752 55.8355 196.68 +v 65.4752 -55.8355 196.68 +v 162.425 55.8355 128.795 +v 162.425 -55.8355 128.795 +v 183.136 55.8355 97.1149 +v 183.136 -55.8355 97.1149 +v 100.146 55.8355 181.496 +v 100.146 -55.8355 181.496 +v 201.163 55.8355 50.0371 +v 201.163 -55.8355 50.0371 +v 154.279 55.8355 138.449 +v 154.279 -55.8355 138.449 +v 202.594 55.8355 43.8846 +v 202.594 -55.8355 43.8846 +v -34.298 55.8355 204.435 +v -34.298 -55.8355 204.435 +v 149.988 55.8355 143.086 +v 149.988 -55.8355 143.086 +v 47.2459 55.8355 201.836 +v 47.2459 -55.8355 201.836 +v -154.262 -75.5591 131.45 +v -154.262 75.5591 131.45 +v 176.283 -75.5591 -100 +v 176.283 75.5591 -100 +v -47.3168 52.8122 204.693 +v -47.3168 -52.8122 204.693 +v 60.2547 52.8122 201.264 +v 60.2547 -52.8122 201.264 +v 185.608 52.8122 98.4259 +v 185.608 -52.8122 98.4259 +v -71.8552 52.8122 197.421 +v -71.8552 -52.8122 197.421 +v 29.0084 52.8122 208.078 +v 29.0084 -52.8122 208.078 +v 3.492 52.8122 210.061 +v 3.492 -52.8122 210.061 +v 200.411 52.8122 63.0367 +v 200.411 -52.8122 63.0367 +v 196.199 52.8122 75.1267 +v 196.199 -52.8122 75.1267 +v 78.3774 52.8122 194.923 +v 78.3774 -52.8122 194.923 +v 205.329 52.8122 44.477 +v 205.329 -52.8122 44.477 +v 72.4019 52.8122 197.221 +v 72.4019 -52.8122 197.221 +v 123.111 52.8122 170.24 +v 112.513 52.8122 177.423 +v 123.111 -52.8122 170.24 +v 112.513 -52.8122 177.423 +v 188.521 52.8122 92.7249 +v 128.241 52.8122 166.41 +v 188.521 -52.8122 92.7249 +v 128.241 -52.8122 166.41 +v 209.993 52.8122 6.40131 +v 209.993 -52.8122 6.40131 +v -41.058 52.8122 206.04 +v -41.058 -52.8122 206.04 +v 54.0943 52.8122 203.007 +v 54.0943 -52.8122 203.007 +v -59.6968 52.8122 201.431 +v -59.6968 -52.8122 201.431 +v 84.2802 52.8122 192.445 +v 84.2802 -52.8122 192.445 +v 101.497 52.8122 183.947 +v 101.497 -52.8122 183.947 +v 209.213 52.8122 19.1802 +v 209.213 -52.8122 19.1802 +v 22.6549 52.8122 208.865 +v 22.6549 -52.8122 208.865 +v 90.1047 52.8122 189.787 +v 90.1047 -52.8122 189.787 +v -53.5317 52.8122 203.156 +v -53.5317 -52.8122 203.156 +v -15.7001 52.8122 209.503 +v -15.7001 -52.8122 209.503 +v 198.397 52.8122 69.1138 +v 198.397 -52.8122 69.1138 +v 203.878 52.8122 50.7126 +v 203.878 -52.8122 50.7126 +v 16.2804 52.8122 209.459 +v 16.2804 -52.8122 209.459 +v -28.4318 52.8122 208.158 +v -28.4318 -52.8122 208.158 +v 168.518 52.8122 125.457 +v 168.518 -52.8122 125.457 +v -2.91004 52.8122 210.07 +v -2.91004 -52.8122 210.07 +v 9.89081 52.8122 209.858 +v 9.89081 -52.8122 209.858 +v 138.139 52.8122 158.29 +v 138.139 -52.8122 158.29 +v -9.30939 52.8122 209.884 +v -9.30939 -52.8122 209.884 +v 193.819 52.8122 81.0698 +v 147.524 52.8122 149.582 +v 133.252 52.8122 162.425 +v 193.819 -52.8122 81.0698 +v 147.524 -52.8122 149.582 +v 133.252 -52.8122 162.425 +v 66.3591 52.8122 199.335 +v 66.3591 -52.8122 199.335 +v 41.6286 52.8122 205.925 +v 41.6286 -52.8122 205.925 +v 207.656 52.8122 31.8878 +v 207.656 -52.8122 31.8878 +v 182.523 52.8122 104.036 +v 156.361 52.8122 140.318 +v 47.8837 52.8122 204.561 +v 182.523 -52.8122 104.036 +v 156.361 -52.8122 140.318 +v 47.8837 -52.8122 204.561 +v 35.3349 52.8122 207.098 +v 35.3349 -52.8122 207.098 +v 175.847 52.8122 114.96 +v 175.847 -52.8122 114.96 +v 202.238 52.8122 56.901 +v 202.238 -52.8122 56.901 +v 208.532 52.8122 25.5458 +v 208.532 -52.8122 25.5458 +v 172.263 52.8122 120.265 +v 172.263 -52.8122 120.265 +v 209.701 52.8122 12.7967 +v 209.701 -52.8122 12.7967 +v 179.268 52.8122 109.549 +v 179.268 -52.8122 109.549 +v -65.8066 52.8122 199.518 +v 95.8456 52.8122 186.954 +v 152.013 52.8122 145.017 +v 142.898 52.8122 154.007 +v 95.8456 -52.8122 186.954 +v -65.8066 -52.8122 199.518 +v 152.013 -52.8122 145.017 +v 142.898 -52.8122 154.007 +v -34.7611 52.8122 207.195 +v -34.7611 -52.8122 207.195 +v 206.589 52.8122 38.2001 +v 206.589 -52.8122 38.2001 +v 191.259 52.8122 86.9377 +v 191.259 -52.8122 86.9377 +v 117.867 52.8122 173.912 +v 117.867 -52.8122 173.912 +v 107.055 52.8122 180.769 +v 164.618 52.8122 130.534 +v 164.618 -52.8122 130.534 +v 107.055 -52.8122 180.769 +v -22.0762 52.8122 208.928 +v -22.0762 -52.8122 208.928 +v 210.091 52.8122 0 +v 210.091 -52.8122 0 +v 160.564 52.8122 135.489 +v 160.564 -52.8122 135.489 +v 102.772 49.6488 186.257 +v 102.772 -49.6488 186.257 +v -9.42633 49.6488 212.521 +v -9.42633 -49.6488 212.521 +v 210.265 49.6488 32.2883 +v 210.265 -49.6488 32.2883 +v 149.377 49.6488 151.461 +v 22.9395 49.6488 211.489 +v 149.377 -49.6488 151.461 +v 22.9395 -49.6488 211.489 +v -54.2041 49.6488 205.708 +v -54.2041 -49.6488 205.708 +v 79.3619 49.6488 197.372 +v 79.3619 -49.6488 197.372 +v 184.816 49.6488 105.342 +v 184.816 -49.6488 105.342 +v 200.889 49.6488 69.9819 +v 193.661 49.6488 88.0298 +v 200.889 -49.6488 69.9819 +v 193.661 -49.6488 88.0298 +v 187.94 49.6488 99.6623 +v 170.635 49.6488 127.033 +v 187.94 -49.6488 99.6623 +v 170.635 -49.6488 127.033 +v 178.056 49.6488 116.404 +v 178.056 -49.6488 116.404 +v 61.0115 49.6488 203.793 +v 61.0115 -49.6488 203.793 +v 212.631 49.6488 6.48172 +v 212.631 -49.6488 6.48172 +v 207.908 49.6488 45.0357 +v 67.1926 49.6488 201.839 +v 207.908 -49.6488 45.0357 +v 67.1926 -49.6488 201.839 +v -72.7578 49.6488 199.9 +v 129.852 49.6488 168.5 +v -72.7578 -49.6488 199.9 +v 129.852 -49.6488 168.5 +v -35.1977 49.6488 209.798 +v -35.1977 -49.6488 209.798 +v 181.52 49.6488 110.925 +v 174.427 49.6488 121.775 +v 181.52 -49.6488 110.925 +v 174.427 -49.6488 121.775 +v 10.015 49.6488 212.494 +v 10.015 -49.6488 212.494 +v 196.253 49.6488 82.0882 +v 196.253 -49.6488 82.0882 +v 113.926 49.6488 179.651 +v 113.926 -49.6488 179.651 +v 211.151 49.6488 25.8667 +v 211.151 -49.6488 25.8667 +v 119.348 49.6488 176.097 +v 119.348 -49.6488 176.097 +v 211.841 49.6488 19.4211 +v 211.841 -49.6488 19.4211 +v 212.335 49.6488 12.9574 +v 212.335 -49.6488 12.9574 +v 190.889 49.6488 93.8896 +v 190.889 -49.6488 93.8896 +v 3.53587 49.6488 212.7 +v 3.53587 -49.6488 212.7 +v 209.184 49.6488 38.68 +v 209.184 -49.6488 38.68 +v 35.7788 49.6488 209.699 +v 35.7788 -49.6488 209.699 +v 85.3389 49.6488 194.862 +v 85.3389 -49.6488 194.862 +v 91.2365 49.6488 192.171 +v 91.2365 -49.6488 192.171 +v 206.439 49.6488 51.3496 +v 206.439 -49.6488 51.3496 +v 108.4 49.6488 183.039 +v 144.693 49.6488 155.942 +v 144.693 -49.6488 155.942 +v 108.4 -49.6488 183.039 +v 29.3728 49.6488 210.692 +v 29.3728 -49.6488 210.692 +v 73.3113 49.6488 199.698 +v 73.3113 -49.6488 199.698 +v 16.4849 49.6488 212.09 +v 16.4849 -49.6488 212.09 +v 42.1516 49.6488 208.512 +v 42.1516 -49.6488 208.512 +v 212.73 49.6488 0 +v 158.325 49.6488 142.081 +v 212.73 -49.6488 0 +v 158.325 -49.6488 142.081 +v -22.3535 49.6488 211.552 +v -22.3535 -49.6488 211.552 +v -2.9466 49.6488 212.709 +v -2.9466 -49.6488 212.709 +v -66.6332 49.6488 202.025 +v -66.6332 -49.6488 202.025 +v -47.9112 49.6488 207.264 +v -47.9112 -49.6488 207.264 +v 198.663 49.6488 76.0704 +v 54.7738 49.6488 205.557 +v 198.663 -49.6488 76.0704 +v 54.7738 -49.6488 205.557 +v 97.0495 49.6488 189.302 +v 97.0495 -49.6488 189.302 +v 202.928 49.6488 63.8285 +v 166.686 49.6488 132.173 +v 202.928 -49.6488 63.8285 +v 166.686 -49.6488 132.173 +v 153.923 49.6488 146.839 +v 139.874 49.6488 160.278 +v 153.923 -49.6488 146.839 +v 139.874 -49.6488 160.278 +v -41.5737 49.6488 208.628 +v -41.5737 -49.6488 208.628 +v 162.581 49.6488 137.191 +v 162.581 -49.6488 137.191 +v 204.779 49.6488 57.6158 +v 204.779 -49.6488 57.6158 +v -28.789 49.6488 210.773 +v -28.789 -49.6488 210.773 +v -60.4467 49.6488 203.961 +v -60.4467 -49.6488 203.961 +v -15.8973 49.6488 212.135 +v -15.8973 -49.6488 212.135 +v 48.4852 49.6488 207.131 +v 48.4852 -49.6488 207.131 +v 124.658 49.6488 172.379 +v 124.658 -49.6488 172.379 +v 134.926 49.6488 164.466 +v 134.926 -49.6488 164.466 +v 180.138 -74.1059 -100 +v 180.138 74.1059 -100 +v -155.58 -74.1059 135.073 +v -155.58 74.1059 135.073 +v 109.66 46.3537 185.167 +v 109.66 -46.3537 185.167 +v 183.63 46.3537 112.214 +v 183.63 -46.3537 112.214 +v 164.471 46.3537 138.786 +v 164.471 -46.3537 138.786 +v 49.0488 46.3537 209.538 +v 49.0488 -46.3537 209.538 +v 213.605 46.3537 26.1674 +v 213.605 -46.3537 26.1674 +v 16.6765 46.3537 214.555 +v 16.6765 -46.3537 214.555 +v 3.57697 46.3537 215.173 +v 3.57697 -46.3537 215.173 +v -67.4077 46.3537 204.373 +v -67.4077 -46.3537 204.373 +v 146.375 46.3537 157.754 +v 146.375 -46.3537 157.754 +v 42.6415 46.3537 210.935 +v 42.6415 -46.3537 210.935 +v 126.106 46.3537 174.382 +v 126.106 -46.3537 174.382 +v -2.98085 46.3537 215.182 +v -2.98085 -46.3537 215.182 +v 98.1776 46.3537 191.502 +v 98.1776 -46.3537 191.502 +v -16.0821 46.3537 214.6 +v -16.0821 -46.3537 214.6 +v 176.454 46.3537 123.191 +v 176.454 -46.3537 123.191 +v -48.4681 46.3537 209.673 +v -48.4681 -46.3537 209.673 +v -35.6068 46.3537 212.236 +v -35.6068 -46.3537 212.236 +v 115.251 46.3537 181.74 +v 115.251 -46.3537 181.74 +v 193.108 46.3537 94.981 +v 193.108 -46.3537 94.981 +v 103.967 46.3537 188.422 +v 205.287 46.3537 64.5704 +v 103.967 -46.3537 188.422 +v 205.287 -46.3537 64.5704 +v 61.7207 46.3537 206.161 +v 61.7207 -46.3537 206.161 +v 207.159 46.3537 58.2855 +v 172.619 46.3537 128.51 +v 136.494 46.3537 166.377 +v 67.9736 46.3537 204.185 +v 207.159 -46.3537 58.2855 +v 172.619 -46.3537 128.51 +v 136.494 -46.3537 166.377 +v 67.9736 -46.3537 204.185 +v -61.1493 46.3537 206.332 +v -61.1493 -46.3537 206.332 +v 120.735 46.3537 178.144 +v 120.735 -46.3537 178.144 +v 180.126 46.3537 117.757 +v 180.126 -46.3537 117.757 +v 92.297 46.3537 194.405 +v 92.297 -46.3537 194.405 +v 141.5 46.3537 162.141 +v 74.1635 46.3537 202.019 +v 141.5 -46.3537 162.141 +v 74.1635 -46.3537 202.019 +v 23.2061 46.3537 213.947 +v 23.2061 -46.3537 213.947 +v 80.2844 46.3537 199.666 +v -29.1236 46.3537 213.223 +v 80.2844 -46.3537 199.666 +v -29.1236 -46.3537 213.223 +v 55.4104 46.3537 207.946 +v 55.4104 -46.3537 207.946 +v 198.535 46.3537 83.0424 +v 198.535 -46.3537 83.0424 +v 29.7142 46.3537 213.141 +v 29.7142 -46.3537 213.141 +v -9.53589 46.3537 214.991 +v -9.53589 -46.3537 214.991 +v -73.6035 46.3537 202.224 +v 155.712 46.3537 148.546 +v -54.8342 46.3537 208.099 +v -73.6035 -46.3537 202.224 +v 155.712 -46.3537 148.546 +v -54.8342 -46.3537 208.099 +v 214.803 46.3537 13.108 +v 214.803 -46.3537 13.108 +v 203.224 46.3537 70.7954 +v 203.224 -46.3537 70.7954 +v 168.623 46.3537 133.71 +v 160.166 46.3537 143.732 +v 151.113 46.3537 153.221 +v 131.361 46.3537 170.459 +v 168.623 -46.3537 133.71 +v 160.166 -46.3537 143.732 +v 151.113 -46.3537 153.221 +v 131.361 -46.3537 170.459 +v 210.324 46.3537 45.5592 +v 210.324 -46.3537 45.5592 +v -22.6133 46.3537 214.011 +v -22.6133 -46.3537 214.011 +v 195.912 46.3537 89.053 +v 190.124 46.3537 100.821 +v 86.3308 46.3537 197.127 +v 195.912 -46.3537 89.053 +v 190.124 -46.3537 100.821 +v 86.3308 -46.3537 197.127 +v 212.709 46.3537 32.6636 +v 212.709 -46.3537 32.6636 +v -42.057 46.3537 211.053 +v -42.057 -46.3537 211.053 +v 215.202 46.3537 0 +v 215.202 -46.3537 0 +v 211.615 46.3537 39.1296 +v 211.615 -46.3537 39.1296 +v 214.304 46.3537 19.6468 +v 36.1946 46.3537 212.137 +v 214.304 -46.3537 19.6468 +v 36.1946 -46.3537 212.137 +v 208.839 46.3537 51.9464 +v 208.839 -46.3537 51.9464 +v 200.973 46.3537 76.9546 +v 200.973 -46.3537 76.9546 +v 10.1315 46.3537 214.964 +v 10.1315 -46.3537 214.964 +v 215.102 46.3537 6.55706 +v 215.102 -46.3537 6.55706 +v 186.964 46.3537 106.567 +v 186.964 -46.3537 106.567 +v 183.913 -72.4562 -100 +v 183.913 72.4562 -100 +v -156.871 -72.4562 138.62 +v -156.871 72.4562 138.62 +v 192.156 42.9357 101.898 +v 192.156 -42.9357 101.898 +v 157.376 42.9357 150.133 +v 137.953 42.9357 168.155 +v 157.376 -42.9357 150.133 +v 137.953 -42.9357 168.155 +v 68.7001 42.9357 206.367 +v 68.7001 -42.9357 206.367 +v 110.832 42.9357 187.146 +v 110.832 -42.9357 187.146 +v 209.373 42.9357 58.9084 +v 209.373 -42.9357 58.9084 +v 217.502 42.9357 0 +v 174.463 42.9357 129.883 +v 217.502 -42.9357 0 +v 174.463 -42.9357 129.883 +v 30.0317 42.9357 215.419 +v 30.0317 -42.9357 215.419 +v 216.594 42.9357 19.8568 +v 216.594 -42.9357 19.8568 +v 93.2834 42.9357 196.482 +v 81.1424 42.9357 201.799 +v 93.2834 -42.9357 196.482 +v 81.1424 -42.9357 201.799 +v 182.051 42.9357 119.015 +v 182.051 -42.9357 119.015 +v 99.2268 42.9357 193.549 +v 207.481 42.9357 65.2604 +v 185.592 42.9357 113.413 +v 99.2268 -42.9357 193.549 +v 207.481 -42.9357 65.2604 +v 185.592 -42.9357 113.413 +v 43.0972 42.9357 213.189 +v 43.0972 -42.9357 213.189 +v 211.07 42.9357 52.5016 +v 211.07 -42.9357 52.5016 +v -48.986 42.9357 211.914 +v -48.986 -42.9357 211.914 +v -29.4348 42.9357 215.501 +v -29.4348 -42.9357 215.501 +v 56.0026 42.9357 210.169 +v 56.0026 -42.9357 210.169 +v -22.855 42.9357 216.298 +v -22.855 -42.9357 216.298 +v 212.572 42.9357 46.046 +v 212.572 -42.9357 46.046 +v 161.877 42.9357 145.268 +v 161.877 -42.9357 145.268 +v -9.6378 42.9357 217.288 +v -9.6378 -42.9357 217.288 +v 198.006 42.9357 90.0047 +v 198.006 -42.9357 90.0047 +v -35.9873 42.9357 214.504 +v -35.9873 -42.9357 214.504 +v 195.171 42.9357 95.996 +v 178.34 42.9357 124.507 +v 195.171 -42.9357 95.996 +v 178.34 -42.9357 124.507 +v 3.61519 42.9357 217.472 +v 3.61519 -42.9357 217.472 +v 213.876 42.9357 39.5477 +v 213.876 -42.9357 39.5477 +v -68.1281 42.9357 206.557 +v 105.078 42.9357 190.436 +v -61.8028 42.9357 208.537 +v 105.078 -42.9357 190.436 +v -68.1281 -42.9357 206.557 +v -61.8028 -42.9357 208.537 +v 49.5729 42.9357 211.777 +v 49.5729 -42.9357 211.777 +v 16.8548 42.9357 216.848 +v 16.8548 -42.9357 216.848 +v 122.025 42.9357 180.047 +v 122.025 -42.9357 180.047 +v 87.2534 42.9357 199.234 +v 87.2534 -42.9357 199.234 +v -42.5064 42.9357 213.308 +v -42.5064 -42.9357 213.308 +v 214.982 42.9357 33.0127 +v 214.982 -42.9357 33.0127 +v 217.098 42.9357 13.2481 +v 217.098 -42.9357 13.2481 +v 132.765 42.9357 172.281 +v 74.956 42.9357 204.178 +v 132.765 -42.9357 172.281 +v 74.956 -42.9357 204.178 +v 143.012 42.9357 163.874 +v 62.3803 42.9357 208.365 +v 143.012 -42.9357 163.874 +v 62.3803 -42.9357 208.365 +v 10.2397 42.9357 217.261 +v 10.2397 -42.9357 217.261 +v 116.482 42.9357 183.682 +v 116.482 -42.9357 183.682 +v 170.425 42.9357 135.139 +v 170.425 -42.9357 135.139 +v -3.0127 42.9357 217.481 +v -3.0127 -42.9357 217.481 +v 23.4541 42.9357 216.234 +v 23.4541 -42.9357 216.234 +v 36.5815 42.9357 214.404 +v 36.5815 -42.9357 214.404 +v 152.728 42.9357 154.859 +v 152.728 -42.9357 154.859 +v 217.401 42.9357 6.62713 +v 217.401 -42.9357 6.62713 +v -74.3901 42.9357 204.385 +v -74.3901 -42.9357 204.385 +v -55.4202 42.9357 210.323 +v -55.4202 -42.9357 210.323 +v 203.12 42.9357 77.777 +v 203.12 -42.9357 77.777 +v -16.254 42.9357 216.894 +v -16.254 -42.9357 216.894 +v 205.396 42.9357 71.5519 +v 205.396 -42.9357 71.5519 +v 127.454 42.9357 176.246 +v 127.454 -42.9357 176.246 +v 200.656 42.9357 83.9298 +v 166.228 42.9357 140.269 +v 147.939 42.9357 159.44 +v 200.656 -42.9357 83.9298 +v 166.228 -42.9357 140.269 +v 147.939 -42.9357 159.44 +v 188.962 42.9357 107.706 +v 188.962 -42.9357 107.706 +v 215.888 42.9357 26.447 +v 215.888 -42.9357 26.447 +v 219.521 39.4039 6.69175 +v 219.521 -39.4039 6.69175 +v -3.04208 39.4039 219.602 +v -3.04208 -39.4039 219.602 +v 134.06 39.4039 173.96 +v 134.06 -39.4039 173.96 +v 211.414 39.4039 59.4827 +v 50.0563 39.4039 213.842 +v 211.414 -39.4039 59.4827 +v 50.0563 -39.4039 213.842 +v 43.5174 39.4039 215.268 +v 43.5174 -39.4039 215.268 +v -75.1154 39.4039 206.378 +v 158.91 39.4039 151.597 +v -75.1154 -39.4039 206.378 +v 158.91 -39.4039 151.597 +v 36.9381 39.4039 216.494 +v 36.9381 -39.4039 216.494 +v -36.3382 39.4039 216.596 +v -36.3382 -39.4039 216.596 +v 88.1042 39.4039 201.176 +v 88.1042 -39.4039 201.176 +v 219.215 39.4039 13.3773 +v 219.215 -39.4039 13.3773 +v -68.7924 39.4039 208.571 +v -68.7924 -39.4039 208.571 +v 197.074 39.4039 96.932 +v 197.074 -39.4039 96.932 +v 187.402 39.4039 114.519 +v 187.402 -39.4039 114.519 +v -55.9605 39.4039 212.374 +v -55.9605 -39.4039 212.374 +v 183.826 39.4039 120.176 +v 144.407 39.4039 165.472 +v 183.826 -39.4039 120.176 +v 144.407 -39.4039 165.472 +v 117.618 39.4039 185.473 +v 117.618 -39.4039 185.473 +v 215.962 39.4039 39.9333 +v 215.962 -39.4039 39.9333 +v 219.623 39.4039 0 +v 111.912 39.4039 188.97 +v 219.623 -39.4039 0 +v 111.912 -39.4039 188.97 +v -16.4124 39.4039 219.009 +v -16.4124 -39.4039 219.009 +v 154.217 39.4039 156.369 +v 154.217 -39.4039 156.369 +v -49.4637 39.4039 213.98 +v -49.4637 -39.4039 213.98 +v 81.9336 39.4039 203.767 +v 81.9336 -39.4039 203.767 +v 217.078 39.4039 33.3346 +v 217.078 -39.4039 33.3346 +v 214.645 39.4039 46.495 +v 214.645 -39.4039 46.495 +v 30.3246 39.4039 217.519 +v 30.3246 -39.4039 217.519 +v 209.504 39.4039 65.8968 +v 209.504 -39.4039 65.8968 +v 217.993 39.4039 26.7049 +v 217.993 -39.4039 26.7049 +v 205.101 39.4039 78.5353 +v 172.087 39.4039 136.456 +v 128.697 39.4039 177.964 +v 123.215 39.4039 181.803 +v 205.101 -39.4039 78.5353 +v 172.087 -39.4039 136.456 +v 128.697 -39.4039 177.964 +v 123.215 -39.4039 181.803 +v 213.128 39.4039 53.0135 +v 213.128 -39.4039 53.0135 +v -9.73177 39.4039 219.407 +v -9.73177 -39.4039 219.407 +v 10.3396 39.4039 219.379 +v 10.3396 -39.4039 219.379 +v 56.5487 39.4039 212.218 +v 56.5487 -39.4039 212.218 +v 17.0191 39.4039 218.962 +v 17.0191 -39.4039 218.962 +v 207.399 39.4039 72.2496 +v 207.399 -39.4039 72.2496 +v 23.6828 39.4039 218.342 +v 23.6828 -39.4039 218.342 +v 199.936 39.4039 90.8823 +v 194.03 39.4039 102.892 +v 199.936 -39.4039 90.8823 +v 194.03 -39.4039 102.892 +v 167.849 39.4039 141.636 +v 149.382 39.4039 160.995 +v 167.849 -39.4039 141.636 +v 149.382 -39.4039 160.995 +v -29.7218 39.4039 217.602 +v -29.7218 -39.4039 217.602 +v 3.65044 39.4039 219.592 +v 3.65044 -39.4039 219.592 +v 180.079 39.4039 125.721 +v 163.456 39.4039 146.685 +v 180.079 -39.4039 125.721 +v 163.456 -39.4039 146.685 +v -42.9209 39.4039 215.388 +v -42.9209 -39.4039 215.388 +v 62.9885 39.4039 210.396 +v 62.9885 -39.4039 210.396 +v 202.613 39.4039 84.7482 +v 202.613 -39.4039 84.7482 +v 94.1929 39.4039 198.398 +v 94.1929 -39.4039 198.398 +v 75.6869 39.4039 206.169 +v 75.6869 -39.4039 206.169 +v 69.3699 39.4039 208.38 +v 69.3699 -39.4039 208.38 +v -62.4054 39.4039 210.57 +v -62.4054 -39.4039 210.57 +v 218.706 39.4039 20.0504 +v 218.706 -39.4039 20.0504 +v -23.0779 39.4039 218.407 +v -23.0779 -39.4039 218.407 +v 190.805 39.4039 108.756 +v 190.805 -39.4039 108.756 +v 100.194 39.4039 195.436 +v 100.194 -39.4039 195.436 +v 106.103 39.4039 192.293 +v 106.103 -39.4039 192.293 +v 176.165 39.4039 131.15 +v 176.165 -39.4039 131.15 +v 139.298 39.4039 169.795 +v 139.298 -39.4039 169.795 +v 187.598 -70.6143 -100 +v 187.598 70.6143 -100 +v -158.132 -70.6143 142.083 +v -158.132 70.6143 142.083 +v 155.577 35.7675 157.747 +v 155.577 -35.7675 157.747 +v 189.054 35.7675 115.529 +v 189.054 -35.7675 115.529 +v -69.3988 35.7675 210.41 +v -69.3988 -35.7675 210.41 +v -9.81757 35.7675 221.341 +v -9.81757 -35.7675 221.341 +v 50.4976 35.7675 215.727 +v 50.4976 -35.7675 215.727 +v 213.278 35.7675 60.0071 +v 213.278 -35.7675 60.0071 +v 23.8916 35.7675 220.267 +v 23.8916 -35.7675 220.267 +v 206.909 35.7675 79.2277 +v 206.909 -35.7675 79.2277 +v -16.5571 35.7675 220.939 +v -16.5571 -35.7675 220.939 +v 211.351 35.7675 66.4777 +v 211.351 -35.7675 66.4777 +v -75.7776 35.7675 208.197 +v 169.329 35.7675 142.885 +v -75.7776 -35.7675 208.197 +v 169.329 -35.7675 142.885 +v 220.634 35.7675 20.2272 +v 220.634 -35.7675 20.2272 +v 112.899 35.7675 190.636 +v 173.604 35.7675 137.659 +v 160.311 35.7675 152.934 +v 173.604 -35.7675 137.659 +v 160.311 -35.7675 152.934 +v 112.899 -35.7675 190.636 +v 17.1691 35.7675 220.893 +v 17.1691 -35.7675 220.893 +v 192.486 35.7675 109.715 +v 192.486 -35.7675 109.715 +v 145.68 35.7675 166.93 +v 145.68 -35.7675 166.93 +v -49.8997 35.7675 215.867 +v -49.8997 -35.7675 215.867 +v 181.666 35.7675 126.829 +v 181.666 -35.7675 126.829 +v 218.992 35.7675 33.6285 +v 218.992 -35.7675 33.6285 +v 177.718 35.7675 132.306 +v 135.242 35.7675 175.494 +v 177.718 -35.7675 132.306 +v 135.242 -35.7675 175.494 +v -3.0689 35.7675 221.538 +v -3.0689 -35.7675 221.538 +v -29.9839 35.7675 219.521 +v -29.9839 -35.7675 219.521 +v 118.655 35.7675 187.108 +v 95.0233 35.7675 200.147 +v 118.655 -35.7675 187.108 +v 95.0233 -35.7675 200.147 +v 30.5919 35.7675 219.437 +v 30.5919 -35.7675 219.437 +v 43.9011 35.7675 217.166 +v 43.9011 -35.7675 217.166 +v 10.4307 35.7675 221.313 +v 10.4307 -35.7675 221.313 +v 37.2638 35.7675 218.403 +v 37.2638 -35.7675 218.403 +v 140.526 35.7675 171.292 +v -36.6586 35.7675 218.505 +v 140.526 -35.7675 171.292 +v -36.6586 -35.7675 218.505 +v 217.866 35.7675 40.2854 +v 217.866 -35.7675 40.2854 +v 76.3541 35.7675 207.987 +v 76.3541 -35.7675 207.987 +v 221.456 35.7675 6.75074 +v 221.456 -35.7675 6.75074 +v 107.038 35.7675 193.988 +v 195.74 35.7675 103.799 +v 107.038 -35.7675 193.988 +v 195.74 -35.7675 103.799 +v 198.812 35.7675 97.7865 +v 164.897 35.7675 147.978 +v 150.698 35.7675 162.414 +v 198.812 -35.7675 97.7865 +v 164.897 -35.7675 147.978 +v 150.698 -35.7675 162.414 +v -62.9556 35.7675 212.426 +v -62.9556 -35.7675 212.426 +v -43.2993 35.7675 217.287 +v -43.2993 -35.7675 217.287 +v 216.537 35.7675 46.9049 +v 216.537 -35.7675 46.9049 +v 221.148 35.7675 13.4952 +v 221.148 -35.7675 13.4952 +v 215.007 35.7675 53.4808 +v 215.007 -35.7675 53.4808 +v -56.4539 35.7675 214.246 +v -56.4539 -35.7675 214.246 +v -23.2813 35.7675 220.332 +v -23.2813 -35.7675 220.332 +v 219.915 35.7675 26.9403 +v 69.9815 35.7675 210.217 +v 219.915 -35.7675 26.9403 +v 69.9815 -35.7675 210.217 +v 201.699 35.7675 91.6835 +v 201.699 -35.7675 91.6835 +v 185.446 35.7675 121.235 +v 129.831 35.7675 179.533 +v 185.446 -35.7675 121.235 +v 129.831 -35.7675 179.533 +v 209.227 35.7675 72.8865 +v 82.6559 35.7675 205.564 +v 209.227 -35.7675 72.8865 +v 82.6559 -35.7675 205.564 +v 88.8809 35.7675 202.95 +v 88.8809 -35.7675 202.95 +v 101.078 35.7675 197.159 +v 124.301 35.7675 183.406 +v 101.078 -35.7675 197.159 +v 124.301 -35.7675 183.406 +v 63.5438 35.7675 212.251 +v 63.5438 -35.7675 212.251 +v 3.68262 35.7675 221.528 +v 3.68262 -35.7675 221.528 +v 221.559 35.7675 0 +v 221.559 -35.7675 0 +v 57.0472 35.7675 214.089 +v 57.0472 -35.7675 214.089 +v 204.399 35.7675 85.4953 +v 204.399 -35.7675 85.4953 +v 156.803 32.0363 158.99 +v 156.803 -32.0363 158.99 +v 10.5129 32.0363 223.058 +v 10.5129 -32.0363 223.058 +v -16.6876 32.0363 222.681 +v -16.6876 -32.0363 222.681 +v 107.882 32.0363 195.517 +v 107.882 -32.0363 195.517 +v 208.54 32.0363 79.8522 +v 208.54 -32.0363 79.8522 +v 24.0799 32.0363 222.003 +v 24.0799 -32.0363 222.003 +v -30.2202 32.0363 221.251 +v -30.2202 -32.0363 221.251 +v 216.702 32.0363 53.9024 +v -36.9475 32.0363 220.227 +v 216.702 -32.0363 53.9024 +v -36.9475 -32.0363 220.227 +v 222.891 32.0363 13.6016 +v 222.891 -32.0363 13.6016 +v -50.293 32.0363 217.568 +v -50.293 -32.0363 217.568 +v -3.09309 32.0363 223.284 +v -3.09309 -32.0363 223.284 +v 101.874 32.0363 198.713 +v 203.289 32.0363 92.4062 +v 101.874 -32.0363 198.713 +v 203.289 -32.0363 92.4062 +v -56.8988 32.0363 215.935 +v -56.8988 -32.0363 215.935 +v 37.5575 32.0363 220.124 +v 37.5575 -32.0363 220.124 +v -9.89495 32.0363 223.086 +v -9.89495 -32.0363 223.086 +v 179.118 32.0363 133.349 +v 151.886 32.0363 163.694 +v 95.7723 32.0363 201.725 +v 179.118 -32.0363 133.349 +v 151.886 -32.0363 163.694 +v 95.7723 -32.0363 201.725 +v 136.307 32.0363 176.877 +v 136.307 -32.0363 176.877 +v 119.59 32.0363 188.583 +v 186.908 32.0363 122.191 +v 174.972 32.0363 138.744 +v 141.633 32.0363 172.642 +v 119.59 -32.0363 188.583 +v 186.908 -32.0363 122.191 +v 174.972 -32.0363 138.744 +v 141.633 -32.0363 172.642 +v 222.373 32.0363 20.3866 +v 222.373 -32.0363 20.3866 +v 190.544 32.0363 116.439 +v 190.544 -32.0363 116.439 +v -43.6405 32.0363 218.999 +v -43.6405 -32.0363 218.999 +v 3.71165 32.0363 223.275 +v 3.71165 -32.0363 223.275 +v -76.3749 32.0363 209.838 +v 76.956 32.0363 209.626 +v -76.3749 -32.0363 209.838 +v 76.956 -32.0363 209.626 +v 221.648 32.0363 27.1527 +v 221.648 -32.0363 27.1527 +v 125.281 32.0363 184.851 +v 161.575 32.0363 154.139 +v 146.828 32.0363 168.246 +v 125.281 -32.0363 184.851 +v 161.575 -32.0363 154.139 +v 146.828 -32.0363 168.246 +v -63.4518 32.0363 214.101 +v -63.4518 -32.0363 214.101 +v -23.4648 32.0363 222.069 +v -23.4648 -32.0363 222.069 +v 170.663 32.0363 144.011 +v 170.663 -32.0363 144.011 +v 206.01 32.0363 86.1692 +v 206.01 -32.0363 86.1692 +v 200.379 32.0363 98.5573 +v 64.0447 32.0363 213.924 +v 200.379 -32.0363 98.5573 +v 64.0447 -32.0363 213.924 +v 218.244 32.0363 47.2746 +v 218.244 -32.0363 47.2746 +v 219.583 32.0363 40.6029 +v 219.583 -32.0363 40.6029 +v 83.3074 32.0363 207.184 +v 83.3074 -32.0363 207.184 +v 89.5815 32.0363 204.549 +v 89.5815 -32.0363 204.549 +v 113.789 32.0363 192.139 +v 113.789 -32.0363 192.139 +v 183.098 32.0363 127.829 +v 166.196 32.0363 149.144 +v 183.098 -32.0363 127.829 +v 166.196 -32.0363 149.144 +v 223.202 32.0363 6.80396 +v 223.202 -32.0363 6.80396 +v 130.855 32.0363 180.948 +v 130.855 -32.0363 180.948 +v 220.718 32.0363 33.8935 +v 220.718 -32.0363 33.8935 +v 50.8956 32.0363 217.428 +v 50.8956 -32.0363 217.428 +v 17.3045 32.0363 222.634 +v 17.3045 -32.0363 222.634 +v 30.833 32.0363 221.167 +v 30.833 -32.0363 221.167 +v 197.283 32.0363 104.617 +v 194.004 32.0363 110.579 +v 197.283 -32.0363 104.617 +v 194.004 -32.0363 110.579 +v 70.5331 32.0363 211.874 +v 70.5331 -32.0363 211.874 +v -69.9458 32.0363 212.068 +v -69.9458 -32.0363 212.068 +v 210.876 32.0363 73.4611 +v 210.876 -32.0363 73.4611 +v 44.2471 32.0363 218.878 +v 44.2471 -32.0363 218.878 +v 213.017 32.0363 67.0017 +v 213.017 -32.0363 67.0017 +v 57.4968 32.0363 215.776 +v 57.4968 -32.0363 215.776 +v 214.959 32.0363 60.4801 +v 214.959 -32.0363 60.4801 +v 223.305 32.0363 0 +v 223.305 -32.0363 0 +v 129.334 29.9857 183.096 +v 127.819 -29.9857 184.156 +v 129.597 -29.9742 182.915 +v 127.559 29.9742 184.342 +v 130.748 29.8843 182.139 +v 126.436 -29.8843 185.158 +v 131.391 -29.8064 181.714 +v 125.816 29.8064 185.617 +v 132.166 29.6864 181.21 +v 125.079 -29.6864 186.173 +v 133.188 -29.4849 180.561 +v 124.119 29.4849 186.911 +v 123.752 -29.3939 187.197 +v 133.582 29.3939 180.314 +v 122.781 -29.114 187.967 +v 134.637 29.114 179.665 +v -159.358 -68.5852 145.452 +v -159.358 68.5852 145.452 +v 191.183 -68.5852 -100 +v 191.183 68.5852 -100 +v 134.972 -29.0143 179.462 +v 122.477 29.0143 188.212 +v 121.832 -28.7837 188.736 +v 135.685 28.7837 179.036 +v 137.002 -28.2928 178.266 +v 120.658 28.2928 189.71 +v 157.893 28.2202 160.096 +v 157.893 -28.2202 160.096 +v -30.4302 28.2202 222.789 +v -30.4302 -28.2202 222.789 +v 224.857 28.2202 0 +v -50.6426 28.2202 219.08 +v 224.857 -28.2202 0 +v -50.6426 -28.2202 219.08 +v -70.432 28.2202 213.542 +v 214.497 28.2202 67.4674 +v -70.432 -28.2202 213.542 +v 214.497 -28.2202 67.4674 +v 224.753 28.2202 6.85124 +v 224.753 -28.2202 6.85124 +v 191.869 28.2202 117.248 +v 191.869 -28.2202 117.248 +v 216.453 28.2202 60.9005 +v 216.453 -28.2202 60.9005 +v 224.44 28.2202 13.6961 +v 224.44 -28.2202 13.6961 +v 137.255 28.2202 178.107 +v 162.698 28.2202 155.21 +v 137.255 -28.2202 178.107 +v 162.698 -28.2202 155.21 +v 57.8965 28.2202 217.276 +v 57.8965 -28.2202 217.276 +v 83.8864 28.2202 208.624 +v 83.8864 -28.2202 208.624 +v 201.772 28.2202 99.2423 +v 201.772 -28.2202 99.2423 +v 218.208 28.2202 54.277 +v 218.208 -28.2202 54.277 +v 102.582 28.2202 200.094 +v 102.582 -28.2202 200.094 +v 184.371 28.2202 128.718 +v 184.371 -28.2202 128.718 +v 223.918 28.2202 20.5283 +v 223.918 -28.2202 20.5283 +v 77.4908 28.2202 211.083 +v 77.4908 -28.2202 211.083 +v 10.586 28.2202 224.608 +v 10.586 -28.2202 224.608 +v -37.2043 28.2202 221.758 +v -37.2043 -28.2202 221.758 +v 195.352 28.2202 111.348 +v 152.942 28.2202 164.832 +v 96.438 28.2202 203.127 +v 195.352 -28.2202 111.348 +v 152.942 -28.2202 164.832 +v 96.438 -28.2202 203.127 +v 71.0233 28.2202 213.346 +v 71.0233 -28.2202 213.346 +v 209.989 28.2202 80.4072 +v 209.989 -28.2202 80.4072 +v 167.351 28.2202 150.181 +v 167.351 -28.2202 150.181 +v 90.2041 28.2202 205.971 +v 90.2041 -28.2202 205.971 +v 147.848 28.2202 169.416 +v 108.631 28.2202 196.876 +v 171.85 28.2202 145.012 +v 147.848 -28.2202 169.416 +v 108.631 -28.2202 196.876 +v 171.85 -28.2202 145.012 +v -63.8928 28.2202 215.589 +v -63.8928 -28.2202 215.589 +v 204.702 28.2202 93.0484 +v 204.702 -28.2202 93.0484 +v 51.2493 28.2202 218.939 +v 51.2493 -28.2202 218.939 +v 37.8185 28.2202 221.654 +v 37.8185 -28.2202 221.654 +v 221.109 28.2202 40.8851 +v 219.761 28.2202 47.6032 +v 31.0473 28.2202 222.704 +v 221.109 -28.2202 40.8851 +v 219.761 -28.2202 47.6032 +v 31.0473 -28.2202 222.704 +v -23.6279 28.2202 223.613 +v -23.6279 -28.2202 223.613 +v 114.58 28.2202 193.474 +v 180.363 28.2202 134.275 +v 114.58 -28.2202 193.474 +v 180.363 -28.2202 134.275 +v -76.9057 28.2202 211.297 +v -76.9057 -28.2202 211.297 +v 198.654 28.2202 105.344 +v 198.654 -28.2202 105.344 +v -16.8036 28.2202 224.229 +v -16.8036 -28.2202 224.229 +v 3.73745 28.2202 224.826 +v 3.73745 -28.2202 224.826 +v -57.2943 28.2202 217.436 +v -57.2943 -28.2202 217.436 +v 17.4247 28.2202 224.181 +v 17.4247 -28.2202 224.181 +v 44.5546 28.2202 220.399 +v 44.5546 -28.2202 220.399 +v 64.4898 28.2202 215.411 +v 64.4898 -28.2202 215.411 +v 176.188 28.2202 139.709 +v 176.188 -28.2202 139.709 +v -9.96372 28.2202 224.637 +v -9.96372 -28.2202 224.637 +v 222.252 28.2202 34.1291 +v 222.252 -28.2202 34.1291 +v 207.442 28.2202 86.7681 +v 207.442 -28.2202 86.7681 +v 223.189 28.2202 27.3414 +v 223.189 -28.2202 27.3414 +v 24.2473 28.2202 223.546 +v 24.2473 -28.2202 223.546 +v -3.11458 28.2202 224.836 +v -3.11458 -28.2202 224.836 +v 142.618 28.2202 173.842 +v 142.618 -28.2202 173.842 +v 212.342 28.2202 73.9716 +v 212.342 -28.2202 73.9716 +v 188.207 28.2202 123.04 +v 188.207 -28.2202 123.04 +v -43.9439 28.2202 220.522 +v -43.9439 -28.2202 220.522 +v 120.422 28.2202 189.893 +v 120.422 -28.2202 189.893 +v 120.372 -28.1585 189.952 +v 137.327 28.1585 178.08 +v 118.978 -27.4165 191.152 +v 138.931 27.4165 177.181 +v 118.938 27.3927 191.188 +v 138.979 -27.3927 177.155 +v 140.49 26.5651 176.338 +v 117.653 -26.5651 192.328 +v 117.322 26.3275 192.628 +v 140.885 -26.3275 176.129 +v 116.401 -25.6118 193.473 +v 141.994 25.6118 175.553 +v 115.971 25.2482 193.873 +v 142.516 -25.2482 175.286 +v 115.091 -24.4383 194.704 +v 143.598 24.4383 174.743 +v 189.34 24.3292 123.781 +v 189.34 -24.3292 123.781 +v -77.3687 24.3292 212.569 +v -77.3687 -24.3292 212.569 +v -10.0237 24.3292 225.989 +v -10.0237 -24.3292 225.989 +v 103.2 24.3292 201.299 +v 103.2 -24.3292 201.299 +v 226.211 24.3292 0 +v 226.211 -24.3292 0 +v 44.8228 24.3292 221.726 +v 44.8228 -24.3292 221.726 +v 177.249 24.3292 140.55 +v 177.249 -24.3292 140.55 +v 217.756 24.3292 61.2671 +v 217.756 -24.3292 61.2671 +v -3.13333 24.3292 226.189 +v -3.13333 -24.3292 226.189 +v 208.691 24.3292 87.2903 +v 208.691 -24.3292 87.2903 +v 193.024 24.3292 117.954 +v 168.359 24.3292 151.085 +v 193.024 -24.3292 117.954 +v 168.359 -24.3292 151.085 +v 224.532 24.3292 27.506 +v 224.532 -24.3292 27.506 +v -70.8559 24.3292 214.827 +v 222.44 24.3292 41.1312 +v 196.528 24.3292 112.018 +v -70.8559 -24.3292 214.827 +v 222.44 -24.3292 41.1312 +v 196.528 -24.3292 112.018 +v 225.791 24.3292 13.7786 +v 225.791 -24.3292 13.7786 +v 31.2342 24.3292 224.044 +v 31.2342 -24.3292 224.044 +v 211.253 24.3292 80.8912 +v 153.862 24.3292 165.824 +v 211.253 -24.3292 80.8912 +v 153.862 -24.3292 165.824 +v 17.5296 24.3292 225.531 +v 17.5296 -24.3292 225.531 +v 213.62 24.3292 74.4169 +v 213.62 -24.3292 74.4169 +v 148.738 24.3292 170.435 +v 185.481 24.3292 129.492 +v 148.738 -24.3292 170.435 +v 185.481 -24.3292 129.492 +v 97.0184 24.3292 204.35 +v 97.0184 -24.3292 204.35 +v -16.9048 24.3292 225.578 +v -16.9048 -24.3292 225.578 +v 90.747 24.3292 207.211 +v 90.747 -24.3292 207.211 +v 221.083 24.3292 47.8897 +v 64.878 24.3292 216.708 +v 221.083 -24.3292 47.8897 +v 64.878 -24.3292 216.708 +v 38.0462 24.3292 222.988 +v 38.0462 -24.3292 222.988 +v 84.3913 24.3292 209.88 +v 84.3913 -24.3292 209.88 +v -57.6392 24.3292 218.744 +v -57.6392 -24.3292 218.744 +v 77.9573 24.3292 212.354 +v -64.2774 24.3292 216.887 +v 77.9573 -24.3292 212.354 +v -64.2774 -24.3292 216.887 +v 71.4508 24.3292 214.63 +v 71.4508 -24.3292 214.63 +v 172.884 24.3292 145.885 +v 172.884 -24.3292 145.885 +v 226.106 24.3292 6.89248 +v 226.106 -24.3292 6.89248 +v 10.6497 24.3292 225.96 +v 10.6497 -24.3292 225.96 +v -23.7701 24.3292 224.958 +v -23.7701 -24.3292 224.958 +v 219.522 24.3292 54.6037 +v 219.522 -24.3292 54.6037 +v 181.449 24.3292 135.084 +v 181.449 -24.3292 135.084 +v 3.75994 24.3292 226.18 +v 3.75994 -24.3292 226.18 +v 223.59 24.3292 34.3345 +v 223.59 -24.3292 34.3345 +v 24.3932 24.3292 224.892 +v 24.3932 -24.3292 224.892 +v 215.788 24.3292 67.8735 +v 215.788 -24.3292 67.8735 +v -30.6134 24.3292 224.13 +v -30.6134 -24.3292 224.13 +v 58.2449 24.3292 218.584 +v 58.2449 -24.3292 218.584 +v 158.844 24.3292 161.059 +v 158.844 -24.3292 161.059 +v -44.2084 24.3292 221.849 +v -44.2084 -24.3292 221.849 +v 51.5578 24.3292 220.257 +v 51.5578 -24.3292 220.257 +v 202.986 24.3292 99.8397 +v 202.986 -24.3292 99.8397 +v 109.285 24.3292 198.061 +v -50.9474 24.3292 220.399 +v 109.285 -24.3292 198.061 +v -50.9474 -24.3292 220.399 +v 199.85 24.3292 105.978 +v 199.85 -24.3292 105.978 +v 205.934 24.3292 93.6085 +v 205.934 -24.3292 93.6085 +v 225.266 24.3292 20.6518 +v 225.266 -24.3292 20.6518 +v -37.4283 24.3292 223.093 +v -37.4283 -24.3292 223.093 +v 163.677 24.3292 156.145 +v 163.677 -24.3292 156.145 +v 114.71 24.0583 195.069 +v 144.072 -24.0583 174.51 +v 113.874 -23.1575 195.88 +v 145.12 23.1575 174.002 +v 113.539 22.7673 196.21 +v 145.544 -22.7673 173.799 +v 146.551 21.7792 173.326 +v 112.75 -21.7792 196.994 +v 112.457 21.3845 197.288 +v 146.928 -21.3845 173.152 +v 78.354 20.3737 213.434 +v 78.354 -20.3737 213.434 +v 204.019 20.3737 100.348 +v 204.019 -20.3737 100.348 +v 71.8145 20.3737 215.723 +v 71.8145 -20.3737 215.723 +v -44.4334 20.3737 222.978 +v -44.4334 -20.3737 222.978 +v 58.5414 20.3737 219.696 +v 58.5414 -20.3737 219.696 +v 209.753 20.3737 87.7346 +v 206.982 20.3737 94.0849 +v 209.753 -20.3737 87.7346 +v 206.982 -20.3737 94.0849 +v 226.413 20.3737 20.757 +v 226.413 -20.3737 20.757 +v 224.728 20.3737 34.5093 +v 224.728 -20.3737 34.5093 +v 17.6189 20.3737 226.678 +v 17.6189 -20.3737 226.678 +v -64.6046 20.3737 217.99 +v -64.6046 -20.3737 217.99 +v 65.2082 20.3737 217.811 +v 65.2082 -20.3737 217.811 +v 97.5123 20.3737 205.39 +v 97.5123 -20.3737 205.39 +v 220.639 20.3737 54.8817 +v 220.639 -20.3737 54.8817 +v 214.707 20.3737 74.7956 +v 214.707 -20.3737 74.7956 +v 227.362 20.3737 0 +v 159.652 20.3737 161.879 +v 227.362 -20.3737 0 +v 159.652 -20.3737 161.879 +v 3.77908 20.3737 227.331 +v 3.77908 -20.3737 227.331 +v 103.725 20.3737 202.323 +v 103.725 -20.3737 202.323 +v 182.372 20.3737 135.771 +v 182.372 -20.3737 135.771 +v 223.572 20.3737 41.3406 +v 223.572 -20.3737 41.3406 +v -3.14928 20.3737 227.34 +v -3.14928 -20.3737 227.34 +v 10.7039 20.3737 227.11 +v 10.7039 -20.3737 227.11 +v -23.8911 20.3737 226.104 +v -23.8911 -20.3737 226.104 +v 197.528 20.3737 112.588 +v 197.528 -20.3737 112.588 +v 222.209 20.3737 48.1335 +v 178.151 20.3737 141.265 +v 173.764 20.3737 146.628 +v 222.209 -20.3737 48.1335 +v 178.151 -20.3737 141.265 +v 173.764 -20.3737 146.628 +v 38.2398 20.3737 224.123 +v 38.2398 -20.3737 224.123 +v 216.887 20.3737 68.2189 +v 216.887 -20.3737 68.2189 +v -10.0747 20.3737 227.139 +v -10.0747 -20.3737 227.139 +v -77.7625 20.3737 213.651 +v 186.425 20.3737 130.152 +v 164.51 20.3737 156.939 +v -77.7625 -20.3737 213.651 +v 186.425 -20.3737 130.152 +v 164.51 -20.3737 156.939 +v 91.2089 20.3737 208.266 +v 91.2089 -20.3737 208.266 +v 45.0509 20.3737 222.854 +v 45.0509 -20.3737 222.854 +v 218.864 20.3737 61.5789 +v 194.006 20.3737 118.555 +v 218.864 -20.3737 61.5789 +v 194.006 -20.3737 118.555 +v -57.9325 20.3737 219.858 +v -57.9325 -20.3737 219.858 +v 154.646 20.3737 166.668 +v 154.646 -20.3737 166.668 +v 31.3932 20.3737 225.184 +v 31.3932 -20.3737 225.184 +v 149.495 20.3737 171.303 +v 149.495 -20.3737 171.303 +v -30.7692 20.3737 225.271 +v -30.7692 -20.3737 225.271 +v 200.867 20.3737 106.518 +v 200.867 -20.3737 106.518 +v 226.94 20.3737 13.8487 +v 226.94 -20.3737 13.8487 +v 169.216 20.3737 151.854 +v 169.216 -20.3737 151.854 +v 212.329 20.3737 81.3029 +v 212.329 -20.3737 81.3029 +v -16.9908 20.3737 226.727 +v -16.9908 -20.3737 226.727 +v -37.6188 20.3737 224.229 +v -37.6188 -20.3737 224.229 +v -71.2166 20.3737 215.921 +v -71.2166 -20.3737 215.921 +v -51.2067 20.3737 221.521 +v -51.2067 -20.3737 221.521 +v 225.675 20.3737 27.646 +v 225.675 -20.3737 27.646 +v 227.257 20.3737 6.92757 +v 227.257 -20.3737 6.92757 +v 84.8209 20.3737 210.948 +v 84.8209 -20.3737 210.948 +v 51.8202 20.3737 221.378 +v 51.8202 -20.3737 221.378 +v 109.842 20.3737 199.069 +v 109.842 -20.3737 199.069 +v 24.5174 20.3737 226.036 +v 24.5174 -20.3737 226.036 +v 190.304 20.3737 124.411 +v 190.304 -20.3737 124.411 +v 147.887 20.3127 172.714 +v 111.718 -20.3127 198.04 +v 111.262 19.5911 198.51 +v 148.484 -19.5911 172.447 +v 149.38 18.4181 172.051 +v 110.584 -18.4181 199.217 +v -160.547 -66.3742 148.718 +v -160.547 66.3742 148.718 +v 194.66 -66.3742 -100 +v 194.66 66.3742 -100 +v 110.198 17.6893 199.623 +v 149.894 -17.6893 171.828 +v 150.718 16.4201 171.474 +v 109.585 -16.4201 200.276 +v -3.16239 16.3642 228.286 +v -3.16239 -16.3642 228.286 +v 31.5238 16.3642 226.122 +v 31.5238 -16.3642 226.122 +v 91.5885 16.3642 209.132 +v 91.5885 -16.3642 209.132 +v 217.789 16.3642 68.5029 +v 217.789 -16.3642 68.5029 +v 183.132 16.3642 136.336 +v 183.132 -16.3642 136.336 +v 227.885 16.3642 13.9063 +v 227.885 -16.3642 13.9063 +v 178.892 16.3642 141.853 +v 178.892 -16.3642 141.853 +v -44.6183 16.3642 223.906 +v -44.6183 -16.3642 223.906 +v 201.703 16.3642 106.961 +v 201.703 -16.3642 106.961 +v 227.355 16.3642 20.8434 +v 227.355 -16.3642 20.8434 +v 72.1134 16.3642 216.62 +v 72.1134 -16.3642 216.62 +v 155.289 16.3642 167.362 +v 213.212 16.3642 81.6413 +v 155.289 -16.3642 167.362 +v 213.212 -16.3642 81.6413 +v 187.201 16.3642 130.693 +v 78.6802 16.3642 214.323 +v 187.201 -16.3642 130.693 +v 78.6802 -16.3642 214.323 +v 17.6922 16.3642 227.622 +v 17.6922 -16.3642 227.622 +v 3.79481 16.3642 228.277 +v 3.79481 -16.3642 228.277 +v 204.868 16.3642 100.766 +v 204.868 -16.3642 100.766 +v -30.8973 16.3642 226.208 +v -30.8973 -16.3642 226.208 +v 174.487 16.3642 147.238 +v 174.487 -16.3642 147.238 +v 10.7485 16.3642 228.055 +v 10.7485 -16.3642 228.055 +v -10.1166 16.3642 228.084 +v -10.1166 -16.3642 228.084 +v 97.9181 16.3642 206.245 +v 97.9181 -16.3642 206.245 +v -23.9905 16.3642 227.044 +v -23.9905 -16.3642 227.044 +v 225.663 16.3642 34.6529 +v 225.663 -16.3642 34.6529 +v 65.4796 16.3642 218.717 +v 65.4796 -16.3642 218.717 +v 194.814 16.3642 119.048 +v 165.195 16.3642 157.592 +v 194.814 -16.3642 119.048 +v 165.195 -16.3642 157.592 +v 215.601 16.3642 75.1069 +v 52.0359 16.3642 222.299 +v 215.601 -16.3642 75.1069 +v 52.0359 -16.3642 222.299 +v 191.096 16.3642 124.929 +v 169.92 16.3642 152.486 +v 191.096 -16.3642 124.929 +v 169.92 -16.3642 152.486 +v -71.513 16.3642 216.819 +v 221.557 16.3642 55.1101 +v -71.513 -16.3642 216.819 +v 221.557 -16.3642 55.1101 +v 210.626 16.3642 88.0998 +v 210.626 -16.3642 88.0998 +v 224.503 16.3642 41.5126 +v 224.503 -16.3642 41.5126 +v -51.4198 16.3642 222.443 +v -51.4198 -16.3642 222.443 +v 85.1739 16.3642 211.826 +v -58.1736 16.3642 220.773 +v 85.1739 -16.3642 211.826 +v -58.1736 -16.3642 220.773 +v 223.134 16.3642 48.3338 +v 223.134 -16.3642 48.3338 +v 160.316 16.3642 162.553 +v 160.316 -16.3642 162.553 +v 226.614 16.3642 27.761 +v 226.614 -16.3642 27.761 +v -78.0861 16.3642 214.54 +v -78.0861 -16.3642 214.54 +v 45.2384 16.3642 223.782 +v 45.2384 -16.3642 223.782 +v 58.785 16.3642 220.611 +v 58.785 -16.3642 220.611 +v -37.7753 16.3642 225.162 +v -37.7753 -16.3642 225.162 +v 207.844 16.3642 94.4765 +v 198.35 16.3642 113.057 +v 207.844 -16.3642 94.4765 +v 198.35 -16.3642 113.057 +v -64.8734 16.3642 218.898 +v -64.8734 -16.3642 218.898 +v 24.6194 16.3642 226.977 +v 24.6194 -16.3642 226.977 +v 228.202 16.3642 6.9564 +v 228.202 -16.3642 6.9564 +v -17.0615 16.3642 227.67 +v -17.0615 -16.3642 227.67 +v 219.775 16.3642 61.8352 +v 219.775 -16.3642 61.8352 +v 228.309 16.3642 0 +v 228.309 -16.3642 0 +v 38.399 16.3642 225.056 +v 38.399 -16.3642 225.056 +v 104.157 16.3642 203.165 +v 104.157 -16.3642 203.165 +v 109.264 15.6929 200.621 +v 151.152 -15.6929 171.291 +v 151.895 14.3329 170.98 +v 108.718 -14.3329 201.213 +v 108.456 13.6152 201.499 +v 152.253 -13.6152 170.832 +v 225.229 12.3112 41.6469 +v 225.229 -12.3112 41.6469 +v 216.298 12.3112 75.3499 +v 216.298 -12.3112 75.3499 +v 58.9752 12.3112 221.324 +v 58.9752 -12.3112 221.324 +v 228.622 12.3112 13.9513 +v 228.622 -12.3112 13.9513 +v 179.471 12.3112 142.312 +v 170.47 12.3112 152.979 +v 179.471 -12.3112 142.312 +v 170.47 -12.3112 152.979 +v 31.6258 12.3112 226.853 +v 31.6258 -12.3112 226.853 +v 24.6991 12.3112 227.711 +v 24.6991 -12.3112 227.711 +v 195.444 12.3112 119.433 +v 195.444 -12.3112 119.433 +v 229.047 12.3112 0 +v 85.4494 12.3112 212.511 +v 229.047 -12.3112 0 +v 85.4494 -12.3112 212.511 +v 208.516 12.3112 94.7821 +v 160.835 12.3112 163.079 +v 208.516 -12.3112 94.7821 +v 160.835 -12.3112 163.079 +v 183.724 12.3112 136.777 +v 183.724 -12.3112 136.777 +v 226.393 12.3112 34.765 +v 226.393 -12.3112 34.765 +v 223.855 12.3112 48.4901 +v 222.274 12.3112 55.2883 +v 223.855 -12.3112 48.4901 +v 222.274 -12.3112 55.2883 +v 52.2042 12.3112 223.018 +v 52.2042 -12.3112 223.018 +v 220.486 12.3112 62.0352 +v 165.729 12.3112 158.102 +v 220.486 -12.3112 62.0352 +v 165.729 -12.3112 158.102 +v 187.806 12.3112 131.116 +v 98.2349 12.3112 206.912 +v 187.806 -12.3112 131.116 +v 98.2349 -12.3112 206.912 +v -78.3387 12.3112 215.234 +v -78.3387 -12.3112 215.234 +v 228.09 12.3112 20.9108 +v 228.09 -12.3112 20.9108 +v 38.5232 12.3112 225.784 +v 38.5232 -12.3112 225.784 +v 72.3466 12.3112 217.321 +v 72.3466 -12.3112 217.321 +v 104.494 12.3112 203.822 +v 104.494 -12.3112 203.822 +v -71.7443 12.3112 217.521 +v -71.7443 -12.3112 217.521 +v 155.792 12.3112 167.903 +v 155.792 -12.3112 167.903 +v -30.9972 12.3112 226.94 +v -30.9972 -12.3112 226.94 +v 45.3848 12.3112 224.506 +v 45.3848 -12.3112 224.506 +v 3.80709 12.3112 229.015 +v 3.80709 -12.3112 229.015 +v 205.531 12.3112 101.091 +v 205.531 -12.3112 101.091 +v -65.0833 12.3112 219.606 +v -65.0833 -12.3112 219.606 +v -51.5862 12.3112 223.162 +v -51.5862 -12.3112 223.162 +v 218.494 12.3112 68.7245 +v 218.494 -12.3112 68.7245 +v -58.3618 12.3112 221.487 +v -58.3618 -12.3112 221.487 +v 213.902 12.3112 81.9054 +v 213.902 -12.3112 81.9054 +v 175.052 12.3112 147.714 +v 175.052 -12.3112 147.714 +v 91.8848 12.3112 209.809 +v 91.8848 -12.3112 209.809 +v 228.941 12.3112 6.9789 +v 228.941 -12.3112 6.9789 +v -24.0681 12.3112 227.779 +v -24.0681 -12.3112 227.779 +v -44.7626 12.3112 224.63 +v -44.7626 -12.3112 224.63 +v 227.348 12.3112 27.8508 +v 227.348 -12.3112 27.8508 +v -17.1167 12.3112 228.407 +v -17.1167 -12.3112 228.407 +v 17.7494 12.3112 228.358 +v 17.7494 -12.3112 228.358 +v -10.1494 12.3112 228.822 +v -10.1494 -12.3112 228.822 +v 211.307 12.3112 88.3848 +v 211.307 -12.3112 88.3848 +v -3.17262 12.3112 229.025 +v -3.17262 -12.3112 229.025 +v 65.6914 12.3112 219.425 +v 65.6914 -12.3112 219.425 +v 202.356 12.3112 107.307 +v -37.8975 12.3112 225.89 +v 202.356 -12.3112 107.307 +v -37.8975 -12.3112 225.89 +v 10.7832 12.3112 228.793 +v 10.7832 -12.3112 228.793 +v 198.992 12.3112 113.423 +v 198.992 -12.3112 113.423 +v 78.9347 12.3112 215.016 +v 78.9347 -12.3112 215.016 +v 191.714 12.3112 125.333 +v 191.714 -12.3112 125.333 +v 107.982 -12.17 202.021 +v 152.905 12.17 170.565 +v 153.191 -11.4687 170.449 +v 107.775 11.4687 202.25 +v 153.746 9.94438 170.226 +v 107.376 -9.94438 202.695 +v 107.214 9.24381 202.876 +v 153.972 -9.24381 170.136 +v 222.787 8.22568 55.416 +v 222.787 -8.22568 55.416 +v 211.795 8.22568 88.5889 +v 211.795 -8.22568 88.5889 +v 10.8082 8.22568 229.321 +v 10.8082 -8.22568 229.321 +v 31.6989 8.22568 227.377 +v 31.6989 -8.22568 227.377 +v 17.7904 8.22568 228.886 +v 17.7904 -8.22568 228.886 +v -71.91 8.22568 218.023 +v -71.91 -8.22568 218.023 +v -24.1237 8.22568 228.305 +v -24.1237 -8.22568 228.305 +v -37.9851 8.22568 226.412 +v -37.9851 -8.22568 226.412 +v 170.863 8.22568 153.333 +v 170.863 -8.22568 153.333 +v -44.866 8.22568 225.149 +v -44.866 -8.22568 225.149 +v 38.6121 8.22568 226.306 +v 38.6121 -8.22568 226.306 +v 229.15 8.22568 13.9835 +v 229.15 -8.22568 13.9835 +v 206.006 8.22568 101.325 +v 206.006 -8.22568 101.325 +v 156.151 8.22568 168.291 +v 156.151 -8.22568 168.291 +v 199.452 8.22568 113.685 +v 92.097 8.22568 210.293 +v 199.452 -8.22568 113.685 +v 92.097 -8.22568 210.293 +v 85.6467 8.22568 213.002 +v 85.6467 -8.22568 213.002 +v 227.872 8.22568 27.9151 +v 227.872 -8.22568 27.9151 +v 104.735 8.22568 204.293 +v 220.995 8.22568 62.1785 +v 195.895 8.22568 119.709 +v 79.117 8.22568 215.512 +v 220.995 -8.22568 62.1785 +v 195.895 -8.22568 119.709 +v 104.735 -8.22568 204.293 +v 79.117 -8.22568 215.512 +v 24.7561 8.22568 228.237 +v 24.7561 -8.22568 228.237 +v 192.157 8.22568 125.622 +v 184.148 8.22568 137.093 +v 192.157 -8.22568 125.622 +v 184.148 -8.22568 137.093 +v -10.1728 8.22568 229.35 +v -10.1728 -8.22568 229.35 +v 161.206 8.22568 163.455 +v 161.206 -8.22568 163.455 +v 229.469 8.22568 6.99502 +v 229.469 -8.22568 6.99502 +v 65.8431 8.22568 219.931 +v 65.8431 -8.22568 219.931 +v 229.576 8.22568 0 +v 229.576 -8.22568 0 +v 225.749 8.22568 41.7431 +v 179.886 8.22568 142.641 +v 225.749 -8.22568 41.7431 +v 179.886 -8.22568 142.641 +v 3.81588 8.22568 229.544 +v 3.81588 -8.22568 229.544 +v -58.4966 8.22568 221.998 +v -58.4966 -8.22568 221.998 +v 224.372 8.22568 48.6021 +v 224.372 -8.22568 48.6021 +v 208.997 8.22568 95.001 +v 175.456 8.22568 148.055 +v 208.997 -8.22568 95.001 +v 175.456 -8.22568 148.055 +v 72.5137 8.22568 217.823 +v 72.5137 -8.22568 217.823 +v 202.823 8.22568 107.555 +v 202.823 -8.22568 107.555 +v -31.0688 8.22568 227.464 +v -31.0688 -8.22568 227.464 +v 59.1114 8.22568 221.835 +v 59.1114 -8.22568 221.835 +v 45.4896 8.22568 225.024 +v 45.4896 -8.22568 225.024 +v 218.998 8.22568 68.8832 +v 218.998 -8.22568 68.8832 +v 228.617 8.22568 20.9591 +v 228.617 -8.22568 20.9591 +v 216.798 8.22568 75.5239 +v 216.798 -8.22568 75.5239 +v -3.17994 8.22568 229.554 +v -3.17994 -8.22568 229.554 +v -78.5196 8.22568 215.731 +v -78.5196 -8.22568 215.731 +v 166.112 8.22568 158.467 +v 166.112 -8.22568 158.467 +v 52.3248 8.22568 223.534 +v 52.3248 -8.22568 223.534 +v 214.396 8.22568 82.0945 +v 214.396 -8.22568 82.0945 +v 226.916 8.22568 34.8453 +v 226.916 -8.22568 34.8453 +v -51.7053 8.22568 223.678 +v -51.7053 -8.22568 223.678 +v 188.24 8.22568 131.419 +v 188.24 -8.22568 131.419 +v -17.1562 8.22568 228.934 +v -17.1562 -8.22568 228.934 +v -65.2336 8.22568 220.113 +v -65.2336 -8.22568 220.113 +v 98.4617 8.22568 207.39 +v 98.4617 -8.22568 207.39 +v 106.959 -7.99956 203.163 +v 154.329 7.99956 169.995 +v 106.779 6.97284 203.367 +v 154.582 -6.97284 169.895 +v 106.636 -6.02528 203.53 +v 154.784 6.02528 169.816 +v 155.019 -4.66752 169.724 +v 106.469 4.66752 203.72 +v 184.403 4.1183 137.283 +v 184.403 -4.1183 137.283 +v 92.2245 4.1183 210.585 +v 92.2245 -4.1183 210.585 +v 72.6141 4.1183 218.125 +v 72.6141 -4.1183 218.125 +v 31.7428 4.1183 227.692 +v -44.9282 4.1183 225.461 +v 31.7428 -4.1183 227.692 +v -44.9282 -4.1183 225.461 +v 38.6656 4.1183 226.619 +v 38.6656 -4.1183 226.619 +v 52.3973 4.1183 223.843 +v 52.3973 -4.1183 223.843 +v 180.135 4.1183 142.838 +v 180.135 -4.1183 142.838 +v 206.291 4.1183 101.465 +v -51.7769 4.1183 223.987 +v 229.894 4.1183 0 +v 206.291 -4.1183 101.465 +v -51.7769 -4.1183 223.987 +v 229.894 -4.1183 0 +v -78.6284 4.1183 216.03 +v -78.6284 -4.1183 216.03 +v 224.683 4.1183 48.6694 +v 224.683 -4.1183 48.6694 +v 226.062 4.1183 41.8009 +v -58.5776 4.1183 222.306 +v 226.062 -4.1183 41.8009 +v -58.5776 -4.1183 222.306 +v -10.1869 4.1183 229.668 +v -10.1869 -4.1183 229.668 +v 188.501 4.1183 131.601 +v 188.501 -4.1183 131.601 +v 17.815 4.1183 229.203 +v 17.815 -4.1183 229.203 +v 209.287 4.1183 95.1326 +v 209.287 -4.1183 95.1326 +v 227.23 4.1183 34.8936 +v 227.23 -4.1183 34.8936 +v 161.43 4.1183 163.682 +v 161.43 -4.1183 163.682 +v 217.098 4.1183 75.6285 +v 217.098 -4.1183 75.6285 +v 104.88 4.1183 204.576 +v 104.88 -4.1183 204.576 +v 45.5526 4.1183 225.336 +v 45.5526 -4.1183 225.336 +v 10.8231 4.1183 229.639 +v 10.8231 -4.1183 229.639 +v 171.1 4.1183 153.545 +v 171.1 -4.1183 153.545 +v -17.18 4.1183 229.251 +v -17.18 -4.1183 229.251 +v 85.7654 4.1183 213.297 +v 85.7654 -4.1183 213.297 +v 199.728 4.1183 113.842 +v 192.423 4.1183 125.796 +v 199.728 -4.1183 113.842 +v 192.423 -4.1183 125.796 +v -24.1571 4.1183 228.621 +v -24.1571 -4.1183 228.621 +v 175.699 4.1183 148.26 +v 175.699 -4.1183 148.26 +v 196.166 4.1183 119.875 +v 196.166 -4.1183 119.875 +v 229.787 4.1183 7.0047 +v 229.787 -4.1183 7.0047 +v -38.0377 4.1183 226.725 +v -38.0377 -4.1183 226.725 +v 59.1933 4.1183 222.143 +v 59.1933 -4.1183 222.143 +v -31.1118 4.1183 227.779 +v -31.1118 -4.1183 227.779 +v 228.188 4.1183 27.9538 +v 228.188 -4.1183 27.9538 +v 24.7904 4.1183 228.553 +v 24.7904 -4.1183 228.553 +v -65.3239 4.1183 220.418 +v -65.3239 -4.1183 220.418 +v 65.9343 4.1183 220.236 +v 65.9343 -4.1183 220.236 +v 166.342 4.1183 158.687 +v 166.342 -4.1183 158.687 +v 223.096 4.1183 55.4928 +v 223.096 -4.1183 55.4928 +v 221.301 4.1183 62.2646 +v -72.0096 4.1183 218.325 +v 221.301 -4.1183 62.2646 +v -72.0096 -4.1183 218.325 +v -3.18435 4.1183 229.872 +v -3.18435 -4.1183 229.872 +v 3.82116 4.1183 229.862 +v 3.82116 -4.1183 229.862 +v 228.934 4.1183 20.9881 +v 228.934 -4.1183 20.9881 +v 156.368 4.1183 168.524 +v 212.088 4.1183 88.7116 +v 156.368 -4.1183 168.524 +v 212.088 -4.1183 88.7116 +v 214.693 4.1183 82.2082 +v 214.693 -4.1183 82.2082 +v 229.467 4.1183 14.0029 +v 229.467 -4.1183 14.0029 +v 79.2265 4.1183 215.811 +v 79.2265 -4.1183 215.811 +v 219.302 4.1183 68.9786 +v 98.5981 4.1183 207.677 +v 219.302 -4.1183 68.9786 +v 98.5981 -4.1183 207.677 +v 203.104 4.1183 107.704 +v 203.104 -4.1183 107.704 +v 106.405 -4.02901 203.792 +v 155.109 4.02901 169.689 +v 106.283 2.33943 203.932 +v 155.282 -2.33943 169.622 +v 155.305 2.01815 169.613 +v 106.267 -2.01815 203.95 +v 32.6111 1.95944e-14 227.676 +v 221.272 1.95944e-14 62.76 +v 53.4178 1.95944e-14 223.711 +v 195.749 1.95944e-14 120.757 +v -58.4483 1.95944e-14 222.449 +v -30.7524 1.95944e-14 227.935 +v -9.65326 1.95944e-14 229.797 +v 224.707 1.95944e-14 49.0605 +v 226.107 1.95944e-14 42.1381 +v 39.5861 1.95944e-14 226.568 +v 211.915 1.95944e-14 89.3983 +v 202.792 1.95944e-14 108.514 +v 11.5278 1.95944e-14 229.711 +v 165.486 1.95944e-14 159.732 +v -16.7043 1.95944e-14 229.393 +v 155.37 1.95944e-14 169.588 +v -51.5908 1.95944e-14 224.139 +v 80.4253 1.95944e-14 215.48 +v -78.6646 1.95944e-14 216.129 +v 93.4995 1.95944e-14 210.138 +v 230 0 0 +v 179.479 1.95944e-14 143.831 +v 227.294 1.95944e-14 35.1759 +v 106.221 1.95944e-14 204.003 +v -65.2507 1.95944e-14 220.55 +v 87.0034 1.95944e-14 212.909 +v -2.59314 1.95944e-14 229.985 +v 174.978 1.95944e-14 149.274 +v 206.028 1.95944e-14 102.237 +v 25.6052 1.95944e-14 228.57 +v 46.5239 1.95944e-14 225.245 +v 191.949 1.95944e-14 126.71 +v 67.048 1.95944e-14 220.01 +v 18.5753 1.95944e-14 229.249 +v 229.025 1.95944e-14 21.1588 +v 160.504 1.95944e-14 164.738 +v 199.365 1.95944e-14 114.689 +v -71.9916 1.95944e-14 218.443 +v 99.9073 1.95944e-14 207.168 +v 209.07 1.95944e-14 95.8627 +v 219.24 1.95944e-14 69.5242 +v 217.003 1.95944e-14 76.2229 +v 4.46943 1.95944e-14 229.957 +v -37.7363 1.95944e-14 226.883 +v -23.7395 1.95944e-14 228.772 +v 183.81 1.95944e-14 138.253 +v 60.2613 1.95944e-14 221.965 +v 223.094 1.95944e-14 55.9366 +v -44.6846 1.95944e-14 225.618 +v 229.892 1.95944e-14 7.0618 +v 73.7714 1.95944e-14 217.848 +v 228.267 1.95944e-14 28.1806 +v 214.56 1.95944e-14 82.8497 +v 229.566 1.95944e-14 14.1169 +v 187.969 1.95944e-14 132.544 +v 170.312 1.95944e-14 154.576 +v -161.695 -63.9871 151.873 +v -161.695 63.9871 151.873 +v 198.017 -63.9871 -100 +v 198.017 63.9871 -100 +v -162.8 -61.4304 154.909 +v -162.8 61.4304 154.909 +v 201.247 -61.4304 -100 +v 201.247 61.4304 -100 +v -163.858 -58.7108 157.816 +v -163.858 58.7108 157.816 +v 204.342 -58.7108 -100 +v 204.342 58.7108 -100 +v -164.867 -55.8355 160.589 +v -164.867 55.8355 160.589 +v 207.292 -55.8355 -100 +v 207.292 55.8355 -100 +v -165.824 -52.8122 163.219 +v -165.824 52.8122 163.219 +v 210.091 -52.8122 -100 +v 210.091 52.8122 -100 +v -166.727 -49.6488 165.698 +v -166.727 49.6488 165.698 +v 212.73 -49.6488 -100 +v 212.73 49.6488 -100 +v 215.202 -46.3537 -100 +v 215.202 46.3537 -100 +v -167.573 -46.3537 168.022 +v -167.573 46.3537 168.022 +v 217.502 -42.9357 -100 +v 217.502 42.9357 -100 +v -168.359 -42.9357 170.183 +v -168.359 42.9357 170.183 +v 219.623 -39.4039 -100 +v 219.623 39.4039 -100 +v -169.085 -39.4039 172.176 +v -169.085 39.4039 172.176 +v -169.747 -35.7675 173.995 +v -169.747 35.7675 173.995 +v 221.559 -35.7675 -100 +v 221.559 35.7675 -100 +v -170.344 -32.0363 175.636 +v -170.344 32.0363 175.636 +v 223.305 -32.0363 -100 +v 223.305 32.0363 -100 +v 224.857 -28.2202 -100 +v 224.857 28.2202 -100 +v -170.875 -28.2202 177.095 +v -170.875 28.2202 177.095 +v -171.338 -24.3292 178.367 +v -171.338 24.3292 178.367 +v 226.211 -24.3292 -100 +v 226.211 24.3292 -100 +v 227.362 -20.3737 -100 +v 227.362 20.3737 -100 +v -171.732 -20.3737 179.449 +v -171.732 20.3737 179.449 +v 228.309 -16.3642 -100 +v 228.309 16.3642 -100 +v -172.055 -16.3642 180.338 +v -172.055 16.3642 180.338 +v 229.047 -12.3112 -100 +v 229.047 12.3112 -100 +v -172.308 -12.3112 181.032 +v -172.308 12.3112 181.032 +v 229.576 -8.22568 -100 +v 229.576 8.22568 -100 +v -172.489 -8.22568 181.529 +v -172.489 8.22568 181.529 +v -172.598 -4.1183 181.828 +v -172.598 4.1183 181.828 +v 229.894 -4.1183 -100 +v 229.894 4.1183 -100 +v 230 0 -100 +v -172.634 0 181.927 +g CATIASTL +f 17 1 39 +f 5 163 27 +f 7904 7807 7919 +f 7904 7877 7807 +f 7141 7089 7145 +f 7141 7137 7089 +f 7896 7859 7879 +f 7896 7916 7859 +f 7865 7934 7930 +f 7865 7930 7829 +f 14 61 1 +f 7857 7915 7934 +f 7857 7934 7865 +f 7837 7932 7915 +f 7837 7915 7857 +f 2 59 14 +f 7801 7903 7932 +f 7801 7932 7837 +f 7789 7889 7903 +f 7789 7903 7801 +f 7 93 2 +f 7787 7888 7889 +f 7787 7889 7789 +f 8 123 7 +f 7847 7928 7888 +f 7847 7888 7787 +f 7849 7882 7928 +f 7849 7928 7847 +f 29 147 8 +f 7869 7921 7882 +f 7869 7882 7849 +f 7805 7922 7921 +f 7805 7921 7869 +f 6 63 29 +f 7863 7933 7922 +f 7863 7922 7805 +f 7860 7891 7933 +f 7860 7933 7863 +f 30 77 6 +f 7799 7920 7891 +f 7799 7891 7860 +f 7779 7909 7920 +f 7779 7920 7799 +f 25 53 30 +f 7873 7892 7909 +f 7873 7909 7779 +f 11 101 25 +f 7819 7917 7892 +f 7819 7892 7873 +f 7827 7884 7917 +f 7827 7917 7819 +f 21 95 11 +f 7820 7912 7884 +f 7820 7884 7827 +f 7795 7935 7912 +f 7795 7912 7820 +f 4 113 21 +f 7763 7926 7935 +f 7763 7935 7795 +f 7777 7902 7926 +f 7777 7926 7763 +f 26 78 4 +f 7825 7908 7902 +f 7825 7902 7777 +f 7813 7936 7908 +f 7813 7908 7825 +f 33 79 26 +f 7845 7894 7936 +f 7845 7936 7813 +f 9 69 33 +f 7803 7916 7894 +f 7803 7894 7845 +f 7859 7916 7803 +f 12 80 9 +f 7357 7395 7403 +f 7357 7403 7353 +f 13 43 12 +f 7029 7006 7134 +f 6953 6987 6991 +f 28 102 13 +f 7131 7089 7137 +f 10 103 28 +f 7265 7145 7089 +f 32 127 10 +f 7517 7401 7385 +f 19 128 32 +f 7870 7900 7919 +f 7870 7919 7807 +f 7765 7906 7900 +f 7765 7900 7870 +f 15 44 19 +f 7817 7898 7906 +f 7817 7906 7765 +f 7867 7931 7898 +f 7867 7898 7817 +f 3 114 15 +f 7767 7913 7931 +f 7767 7931 7867 +f 7843 7927 7913 +f 7843 7913 7767 +f 35 57 3 +f 7833 7883 7927 +f 7833 7927 7843 +f 36 73 35 +f 7775 7911 7883 +f 7775 7883 7833 +f 7809 7890 7911 +f 7809 7911 7775 +f 34 135 36 +f 7773 7881 7890 +f 7773 7890 7809 +f 7769 7910 7881 +f 7769 7881 7773 +f 16 139 34 +f 7839 7914 7910 +f 7839 7910 7769 +f 7797 7893 7914 +f 7797 7914 7839 +f 22 153 16 +f 7811 7923 7893 +f 7811 7893 7797 +f 7855 7907 7923 +f 7855 7923 7811 +f 18 143 22 +f 7853 7887 7907 +f 7853 7907 7855 +f 20 119 18 +f 7793 7895 7887 +f 7793 7887 7853 +f 7815 7925 7895 +f 7815 7895 7793 +f 31 111 20 +f 7823 7886 7925 +f 7823 7925 7815 +f 7835 7924 7886 +f 7835 7886 7823 +f 23 67 31 +f 7831 7929 7924 +f 7831 7924 7835 +f 7770 7897 7929 +f 7770 7929 7831 +f 24 161 23 +f 7780 7885 7897 +f 7780 7897 7770 +f 7790 7905 7885 +f 7790 7885 7780 +f 27 37 24 +f 7841 7918 7905 +f 7841 7905 7790 +f 7850 7918 7841 +f 7859 7876 7879 +f 7519 7636 7579 +f 7579 7427 7519 +f 7519 7427 7403 +f 7353 7403 7427 +f 7357 7391 7395 +f 7268 7193 7148 +f 7067 7148 7193 +f 6953 6983 6987 +f 6897 7004 6994 +f 7385 7401 7393 +f 7251 7269 7265 +f 7757 7641 7679 +f 7123 7029 7134 +f 7123 7134 7136 +f 7123 7136 7139 +f 7123 7139 7144 +f 7123 7144 7148 +f 7123 7148 7067 +f 6895 6953 6991 +f 6895 6991 6996 +f 6895 6996 6998 +f 6895 6998 7006 +f 6895 7006 7029 +f 6919 6897 6994 +f 6919 6994 6990 +f 6919 6990 6986 +f 6919 6986 6983 +f 6919 6983 6953 +f 7899 7918 7785 +f 7785 7918 7850 +f 7785 7850 7735 +f 7735 7850 7653 +f 7735 7653 7567 +f 7567 7653 7577 +f 7567 7577 7489 +f 7489 7577 7469 +f 7489 7469 7337 +f 7337 7469 7373 +f 7337 7373 7151 +f 7151 7373 7175 +f 7151 7175 7093 +f 7093 7175 7017 +f 7093 7017 6913 +f 6913 7017 6969 +f 6913 6969 6747 +f 6747 6969 6731 +f 6747 6731 6607 +f 6607 6731 6619 +f 6607 6619 6573 +f 6573 6619 6529 +f 6573 6529 6413 +f 6413 6529 6349 +f 6413 6349 6237 +f 6237 6349 6295 +f 6237 6295 6081 +f 6081 6295 6177 +f 6081 6177 5963 +f 5963 6177 5991 +f 5963 5991 5813 +f 5813 5991 5907 +f 5813 5907 5697 +f 5697 5907 5779 +f 5697 5779 5553 +f 5553 5779 5595 +f 5553 5595 5515 +f 5515 5595 5431 +f 5515 5431 5409 +f 5409 5431 5377 +f 5409 5377 5243 +f 5243 5377 5193 +f 5243 5193 5035 +f 5035 5193 5123 +f 5035 5123 4997 +f 4997 5123 4943 +f 4997 4943 4833 +f 4833 4943 4873 +f 4833 4873 4641 +f 4641 4873 4693 +f 4641 4693 4591 +f 4591 4693 4595 +f 4591 4595 4423 +f 4423 4595 4383 +f 4423 4383 4301 +f 4301 4383 4329 +f 4301 4329 4173 +f 4173 4329 4221 +f 4173 4221 4027 +f 4027 4221 4053 +f 4027 4053 3911 +f 3911 4053 3857 +f 3911 3857 3783 +f 3783 3857 3811 +f 3783 3811 3643 +f 3643 3811 3691 +f 3643 3691 3533 +f 3533 3691 3497 +f 3533 3497 3327 +f 3327 3497 3393 +f 3327 3393 3175 +f 3175 3393 3213 +f 3175 3213 3133 +f 3133 3213 3141 +f 3133 3141 2931 +f 2931 3141 2937 +f 2931 2937 2893 +f 2893 2937 2894 +f 2893 2894 2701 +f 2701 2894 2665 +f 2701 2665 2521 +f 2521 2665 2505 +f 2521 2505 2417 +f 2417 2505 2435 +f 2417 2435 2283 +f 2283 2435 2219 +f 2283 2219 2185 +f 2185 2219 2205 +f 2185 2205 1967 +f 1967 2205 1989 +f 1967 1989 1881 +f 1881 1989 1843 +f 1881 1843 1763 +f 1763 1843 1769 +f 1763 1769 1599 +f 1599 1769 1693 +f 1599 1693 1549 +f 1549 1693 1455 +f 1549 1455 1349 +f 1349 1455 1327 +f 1349 1327 1283 +f 1283 1327 1279 +f 1283 1279 1077 +f 1077 1279 1145 +f 1077 1145 1007 +f 1007 1145 937 +f 1007 937 875 +f 875 937 855 +f 875 855 761 +f 761 855 753 +f 761 753 571 +f 571 753 557 +f 571 557 527 +f 527 557 437 +f 527 437 337 +f 337 437 329 +f 337 329 291 +f 291 329 249 +f 291 249 74 +f 74 249 163 +f 74 163 5 +f 7930 7901 7829 +f 7829 7901 7781 +f 7829 7781 7697 +f 7697 7781 7701 +f 7697 7701 7603 +f 7603 7701 7541 +f 7603 7541 7505 +f 7505 7541 7511 +f 7505 7511 7379 +f 7379 7511 7305 +f 7379 7305 7221 +f 7221 7305 7157 +f 7221 7157 7021 +f 7021 7157 7013 +f 7021 7013 6951 +f 6951 7013 6981 +f 6951 6981 6799 +f 6799 6981 6849 +f 6799 6849 6595 +f 6595 6849 6635 +f 6595 6635 6571 +f 6571 6635 6479 +f 6571 6479 6459 +f 6459 6479 6445 +f 6459 6445 6231 +f 6231 6445 6287 +f 6231 6287 6105 +f 6105 6287 6199 +f 6105 6199 5971 +f 5971 6199 6039 +f 5971 6039 5865 +f 5865 6039 5908 +f 5865 5908 5729 +f 5729 5908 5795 +f 5729 5795 5621 +f 5621 5795 5573 +f 5621 5573 5465 +f 5465 5573 5485 +f 5465 5485 5403 +f 5403 5485 5309 +f 5403 5309 5169 +f 5169 5309 5163 +f 5169 5163 5139 +f 5139 5163 5023 +f 5139 5023 4971 +f 4971 5023 4919 +f 4971 4919 4771 +f 4771 4919 4839 +f 4771 4839 4651 +f 4651 4839 4753 +f 4651 4753 4501 +f 4501 4753 4521 +f 4501 4521 4487 +f 4487 4521 4471 +f 4487 4471 4231 +f 4231 4471 4333 +f 4231 4333 4127 +f 4127 4333 4103 +f 4127 4103 3989 +f 3989 4103 3981 +f 3989 3981 3943 +f 3943 3981 3945 +f 3943 3945 3785 +f 3785 3945 3825 +f 3785 3825 3695 +f 3695 3825 3593 +f 3695 3593 3565 +f 3565 3593 3445 +f 3565 3445 3409 +f 3409 3445 3381 +f 3409 3381 3251 +f 3251 3381 3297 +f 3251 3297 3155 +f 3155 3297 3087 +f 3155 3087 2923 +f 2923 3087 3011 +f 2923 3011 2897 +f 2897 3011 2773 +f 2897 2773 2737 +f 2737 2773 2755 +f 2737 2755 2623 +f 2623 2755 2609 +f 2623 2609 2463 +f 2463 2609 2405 +f 2463 2405 2223 +f 2223 2405 2339 +f 2223 2339 2211 +f 2211 2339 2155 +f 2211 2155 2067 +f 2067 2155 1968 +f 2067 1968 1907 +f 1907 1968 1831 +f 1907 1831 1723 +f 1723 1831 1771 +f 1723 1771 1619 +f 1619 1771 1623 +f 1619 1623 1533 +f 1533 1623 1467 +f 1533 1467 1339 +f 1339 1467 1439 +f 1339 1439 1233 +f 1233 1439 1261 +f 1233 1261 1179 +f 1179 1261 1111 +f 1179 1111 1039 +f 1039 1111 1021 +f 1039 1021 927 +f 927 1021 813 +f 927 813 779 +f 779 813 715 +f 779 715 623 +f 623 715 581 +f 623 581 451 +f 451 581 439 +f 451 439 389 +f 389 439 293 +f 389 293 195 +f 195 293 251 +f 195 251 39 +f 39 251 81 +f 39 81 17 +f 7251 7265 7068 +f 7068 7265 7089 +f 7068 7089 6861 +f 6861 7089 6945 +f 6861 6945 6801 +f 6801 6945 6753 +f 6801 6753 6717 +f 6717 6753 6636 +f 6717 6636 6530 +f 6530 6636 6475 +f 6530 6475 6373 +f 6373 6475 6335 +f 6373 6335 6203 +f 6203 6335 6275 +f 6203 6275 6115 +f 6115 6275 6193 +f 6115 6193 6057 +f 6057 6193 5945 +f 6057 5945 5843 +f 5843 5945 5889 +f 5843 5889 5791 +f 5791 5889 5741 +f 5791 5741 5583 +f 5583 5741 5617 +f 5583 5617 5453 +f 5453 5617 5505 +f 5453 5505 5331 +f 5331 5505 5397 +f 5331 5397 5229 +f 5229 5397 5257 +f 5229 5257 5117 +f 5117 5257 5101 +f 5117 5101 4941 +f 4941 5101 4920 +f 4941 4920 4857 +f 4857 4920 4817 +f 4857 4817 4689 +f 4689 4817 4683 +f 4689 4683 4515 +f 4515 4683 4551 +f 4515 4551 4433 +f 4433 4551 4481 +f 4433 4481 4239 +f 4239 4481 4313 +f 4239 4313 4215 +f 4215 4313 4191 +f 4215 4191 3995 +f 3995 4191 4043 +f 3995 4043 3863 +f 3863 4043 3903 +f 3863 3903 3751 +f 3751 3903 3755 +f 3751 3755 3611 +f 3611 3755 3633 +f 3611 3633 3543 +f 3543 3633 3457 +f 3543 3457 3329 +f 3329 3457 3361 +f 3329 3361 3283 +f 3283 3361 3255 +f 3283 3255 3105 +f 3105 3255 3137 +f 3105 3137 3021 +f 3021 3137 3015 +f 3021 3015 2863 +f 2863 3015 2864 +f 2863 2864 2717 +f 2717 2864 2683 +f 2717 2683 2591 +f 2591 2683 2559 +f 2591 2559 2395 +f 2395 2559 2397 +f 2395 2397 2237 +f 2237 2397 2305 +f 2237 2305 2186 +f 2186 2305 2109 +f 2186 2109 1963 +f 1963 2109 2039 +f 1963 2039 1882 +f 1882 2039 1955 +f 1882 1955 1707 +f 1707 1955 1789 +f 1707 1789 1647 +f 1647 1789 1683 +f 1647 1683 1507 +f 1507 1683 1517 +f 1507 1517 1440 +f 1440 1517 1381 +f 1440 1381 1227 +f 1227 1381 1309 +f 1227 1309 1183 +f 1183 1309 1171 +f 1183 1171 949 +f 949 1171 991 +f 949 991 867 +f 867 991 817 +f 867 817 727 +f 727 817 762 +f 727 762 659 +f 659 762 572 +f 659 572 453 +f 453 572 465 +f 453 465 379 +f 379 465 399 +f 379 399 241 +f 241 399 197 +f 241 197 127 +f 127 197 103 +f 127 103 10 +f 7575 7521 7515 +f 7515 7521 7517 +f 7515 7517 7311 +f 7311 7517 7385 +f 7311 7385 7155 +f 7155 7385 7251 +f 7155 7251 7041 +f 7041 7251 7068 +f 7041 7068 6879 +f 6879 7068 6861 +f 6879 6861 6841 +f 6841 6861 6801 +f 6841 6801 6715 +f 6715 6801 6717 +f 6715 6717 6493 +f 6493 6717 6530 +f 6493 6530 6359 +f 6359 6530 6373 +f 6359 6373 6303 +f 6303 6373 6203 +f 6303 6203 6178 +f 6178 6203 6115 +f 6178 6115 6040 +f 6040 6115 6057 +f 6040 6057 5921 +f 5921 6057 5843 +f 5921 5843 5705 +f 5705 5843 5791 +f 5705 5791 5649 +f 5649 5791 5583 +f 5649 5583 5489 +f 5489 5583 5453 +f 5489 5453 5289 +f 5289 5453 5331 +f 5289 5331 5219 +f 5219 5331 5229 +f 5219 5229 5053 +f 5053 5229 5117 +f 5053 5117 4907 +f 4907 5117 4941 +f 4907 4941 4797 +f 4797 4941 4857 +f 4797 4857 4727 +f 4727 4857 4689 +f 4727 4689 4565 +f 4565 4689 4515 +f 4565 4515 4385 +f 4385 4515 4433 +f 4385 4433 4289 +f 4289 4433 4239 +f 4289 4239 4192 +f 4192 4239 4215 +f 4192 4215 4083 +f 4083 4215 3995 +f 4083 3995 3917 +f 3917 3995 3863 +f 3917 3863 3805 +f 3805 3863 3751 +f 3805 3751 3599 +f 3599 3751 3611 +f 3599 3611 3477 +f 3477 3611 3543 +f 3477 3543 3417 +f 3417 3543 3329 +f 3417 3329 3277 +f 3277 3329 3283 +f 3277 3283 3063 +f 3063 3283 3105 +f 3063 3105 2949 +f 2949 3105 3021 +f 2949 3021 2813 +f 2813 3021 2863 +f 2813 2863 2641 +f 2641 2863 2717 +f 2641 2717 2567 +f 2567 2717 2591 +f 2567 2591 2406 +f 2406 2591 2395 +f 2406 2395 2299 +f 2299 2395 2237 +f 2299 2237 2195 +f 2195 2237 2186 +f 2195 2186 1957 +f 1957 2186 1963 +f 1957 1963 1873 +f 1873 1963 1882 +f 1873 1882 1799 +f 1799 1882 1707 +f 1799 1707 1579 +f 1579 1707 1647 +f 1579 1647 1463 +f 1463 1647 1507 +f 1463 1507 1441 +f 1441 1507 1440 +f 1441 1440 1305 +f 1305 1440 1227 +f 1305 1227 1172 +f 1172 1227 1183 +f 1172 1183 1037 +f 1037 1183 949 +f 1037 949 909 +f 909 949 867 +f 909 867 769 +f 769 867 727 +f 769 727 573 +f 573 727 659 +f 573 659 440 +f 440 659 453 +f 440 453 363 +f 363 453 379 +f 363 379 242 +f 242 379 241 +f 242 241 155 +f 155 241 127 +f 155 127 32 +f 7865 7829 7665 +f 7665 7829 7697 +f 7665 7697 7529 +f 7529 7697 7603 +f 7529 7603 7415 +f 7415 7603 7505 +f 7415 7505 7363 +f 7363 7505 7379 +f 7363 7379 7181 +f 7181 7379 7221 +f 7181 7221 7027 +f 7027 7221 7021 +f 7027 7021 6873 +f 6873 7021 6951 +f 6873 6951 6817 +f 6817 6951 6799 +f 6817 6799 6617 +f 6617 6799 6595 +f 6617 6595 6547 +f 6547 6595 6571 +f 6547 6571 6419 +f 6419 6571 6459 +f 6419 6459 6259 +f 6259 6459 6231 +f 6259 6231 6173 +f 6173 6231 6105 +f 6173 6105 6017 +f 6017 6105 5971 +f 6017 5971 5811 +f 5811 5971 5865 +f 5811 5865 5753 +f 5753 5865 5729 +f 5753 5729 5667 +f 5667 5729 5621 +f 5667 5621 5527 +f 5527 5621 5465 +f 5527 5465 5287 +f 5287 5465 5403 +f 5287 5403 5199 +f 5199 5403 5169 +f 5199 5169 5125 +f 5125 5169 5139 +f 5125 5139 5013 +f 5013 5139 4971 +f 5013 4971 4849 +f 4849 4971 4771 +f 4849 4771 4671 +f 4671 4771 4651 +f 4671 4651 4555 +f 4555 4651 4501 +f 4555 4501 4381 +f 4381 4501 4487 +f 4381 4487 4319 +f 4319 4487 4231 +f 4319 4231 4209 +f 4209 4231 4127 +f 4209 4127 4035 +f 4035 4127 3989 +f 4035 3989 3935 +f 3935 3989 3943 +f 3935 3943 3739 +f 3739 3943 3785 +f 3739 3785 3657 +f 3657 3785 3695 +f 3657 3695 3563 +f 3563 3695 3565 +f 3563 3565 3375 +f 3375 3565 3409 +f 3375 3409 3293 +f 3293 3409 3251 +f 3293 3251 3115 +f 3115 3251 3155 +f 3115 3155 2933 +f 2933 3155 2923 +f 2933 2923 2827 +f 2827 2923 2897 +f 2827 2897 2753 +f 2753 2897 2737 +f 2753 2737 2531 +f 2531 2737 2623 +f 2531 2623 2385 +f 2385 2623 2463 +f 2385 2463 2269 +f 2269 2463 2223 +f 2269 2223 2105 +f 2105 2223 2211 +f 2105 2211 2053 +f 2053 2211 2067 +f 2053 2067 1879 +f 1879 2067 1907 +f 1879 1907 1797 +f 1797 1907 1723 +f 1797 1723 1689 +f 1689 1723 1619 +f 1689 1619 1475 +f 1475 1619 1533 +f 1475 1533 1401 +f 1401 1533 1339 +f 1401 1339 1303 +f 1303 1339 1233 +f 1303 1233 1101 +f 1101 1233 1179 +f 1101 1179 1057 +f 1057 1179 1039 +f 1057 1039 929 +f 929 1039 927 +f 929 927 723 +f 723 927 779 +f 723 779 555 +f 555 779 623 +f 555 623 499 +f 499 623 451 +f 499 451 387 +f 387 451 389 +f 387 389 239 +f 239 389 195 +f 239 195 137 +f 137 195 39 +f 137 39 1 +f 7857 7865 7729 +f 7729 7865 7665 +f 7729 7665 7569 +f 7569 7665 7529 +f 7569 7529 7423 +f 7423 7529 7415 +f 7423 7415 7289 +f 7289 7415 7363 +f 7289 7363 7259 +f 7259 7363 7181 +f 7259 7181 7045 +f 7045 7181 7027 +f 7045 7027 6905 +f 6905 7027 6873 +f 6905 6873 6751 +f 6751 6873 6817 +f 6751 6817 6709 +f 6709 6817 6617 +f 6709 6617 6485 +f 6485 6617 6547 +f 6485 6547 6449 +f 6449 6547 6419 +f 6449 6419 6257 +f 6257 6419 6259 +f 6257 6259 6117 +f 6117 6259 6173 +f 6117 6173 5983 +f 5983 6173 6017 +f 5983 6017 5827 +f 5827 6017 5811 +f 5827 5811 5711 +f 5711 5811 5753 +f 5711 5753 5613 +f 5613 5753 5667 +f 5613 5667 5517 +f 5517 5667 5527 +f 5517 5527 5303 +f 5303 5527 5287 +f 5303 5287 5189 +f 5189 5287 5199 +f 5189 5199 5055 +f 5055 5199 5125 +f 5055 5125 5011 +f 5011 5125 5013 +f 5011 5013 4799 +f 4799 5013 4849 +f 4799 4849 4739 +f 4739 4849 4671 +f 4739 4671 4593 +f 4593 4671 4555 +f 4593 4555 4489 +f 4489 4555 4381 +f 4489 4381 4347 +f 4347 4381 4319 +f 4347 4319 4109 +f 4109 4319 4209 +f 4109 4209 4015 +f 4015 4209 4035 +f 4015 4035 3957 +f 3957 4035 3935 +f 3957 3935 3719 +f 3719 3935 3739 +f 3719 3739 3627 +f 3627 3739 3657 +f 3627 3657 3483 +f 3483 3657 3563 +f 3483 3563 3353 +f 3353 3563 3375 +f 3353 3375 3219 +f 3219 3375 3293 +f 3219 3293 3161 +f 3161 3293 3115 +f 3161 3115 2927 +f 2927 3115 2933 +f 2927 2933 2891 +f 2891 2933 2827 +f 2891 2827 2751 +f 2751 2827 2753 +f 2751 2753 2625 +f 2625 2753 2531 +f 2625 2531 2441 +f 2441 2531 2385 +f 2441 2385 2329 +f 2329 2385 2269 +f 2329 2269 2189 +f 2189 2269 2105 +f 2189 2105 2027 +f 2027 2105 2053 +f 2027 2053 1935 +f 1935 2053 1879 +f 1935 1879 1729 +f 1729 1879 1797 +f 1729 1797 1659 +f 1659 1797 1689 +f 1659 1689 1537 +f 1537 1689 1475 +f 1537 1475 1317 +f 1317 1475 1401 +f 1317 1401 1281 +f 1281 1401 1303 +f 1281 1303 1099 +f 1099 1303 1101 +f 1099 1101 1027 +f 1027 1101 1057 +f 1027 1057 856 +f 856 1057 929 +f 856 929 701 +f 701 929 723 +f 701 723 629 +f 629 723 555 +f 629 555 523 +f 523 555 499 +f 523 499 317 +f 317 499 387 +f 317 387 205 +f 205 387 239 +f 205 239 61 +f 61 239 137 +f 61 137 1 +f 7837 7857 7677 +f 7677 7857 7729 +f 7677 7729 7609 +f 7609 7729 7569 +f 7609 7569 7487 +f 7487 7569 7423 +f 7487 7423 7377 +f 7377 7423 7289 +f 7377 7289 7173 +f 7173 7289 7259 +f 7173 7259 7117 +f 7117 7259 7045 +f 7117 7045 6917 +f 6917 7045 6905 +f 6917 6905 6825 +f 6825 6905 6751 +f 6825 6751 6655 +f 6655 6751 6709 +f 6655 6709 6593 +f 6593 6709 6485 +f 6593 6485 6343 +f 6343 6485 6449 +f 6343 6449 6253 +f 6253 6449 6257 +f 6253 6257 6169 +f 6169 6257 6117 +f 6169 6117 5951 +f 5951 6117 5983 +f 5951 5983 5835 +f 5835 5983 5827 +f 5835 5827 5769 +f 5769 5827 5711 +f 5769 5711 5587 +f 5587 5711 5613 +f 5587 5613 5483 +f 5483 5613 5517 +f 5483 5517 5333 +f 5333 5517 5303 +f 5333 5303 5167 +f 5167 5303 5189 +f 5167 5189 5091 +f 5091 5189 5055 +f 5091 5055 4995 +f 4995 5055 5011 +f 4995 5011 4761 +f 4761 5011 4799 +f 4761 4799 4649 +f 4649 4799 4739 +f 4649 4739 4609 +f 4609 4739 4593 +f 4609 4593 4401 +f 4401 4593 4489 +f 4401 4489 4249 +f 4249 4489 4347 +f 4249 4347 4139 +f 4139 4347 4109 +f 4139 4109 3997 +f 3997 4109 4015 +f 3997 4015 3875 +f 3875 4015 3957 +f 3875 3957 3827 +f 3827 3957 3719 +f 3827 3719 3587 +f 3587 3719 3627 +f 3587 3627 3439 +f 3439 3627 3483 +f 3439 3483 3347 +f 3347 3483 3353 +f 3347 3353 3187 +f 3187 3353 3219 +f 3187 3219 3069 +f 3069 3219 3161 +f 3069 3161 2999 +f 2999 3161 2927 +f 2999 2927 2887 +f 2887 2927 2891 +f 2887 2891 2657 +f 2657 2891 2751 +f 2657 2751 2509 +f 2509 2751 2625 +f 2509 2625 2477 +f 2477 2625 2441 +f 2477 2441 2215 +f 2215 2441 2329 +f 2215 2329 2135 +f 2135 2329 2189 +f 2135 2189 2047 +f 2047 2189 2027 +f 2047 2027 1909 +f 1909 2027 1935 +f 1909 1935 1809 +f 1809 1935 1729 +f 1809 1729 1679 +f 1679 1729 1659 +f 1679 1659 1569 +f 1569 1659 1537 +f 1569 1537 1399 +f 1399 1537 1317 +f 1399 1317 1221 +f 1221 1317 1281 +f 1221 1281 1165 +f 1165 1281 1099 +f 1165 1099 945 +f 945 1099 1027 +f 945 1027 823 +f 823 1027 856 +f 823 856 801 +f 801 856 701 +f 801 701 587 +f 587 701 629 +f 587 629 427 +f 427 629 523 +f 427 523 377 +f 377 523 317 +f 377 317 259 +f 259 317 205 +f 259 205 97 +f 97 205 61 +f 97 61 14 +f 7801 7837 7743 +f 7743 7837 7677 +f 7743 7677 7551 +f 7551 7677 7609 +f 7551 7609 7453 +f 7453 7609 7487 +f 7453 7487 7291 +f 7291 7487 7377 +f 7291 7377 7233 +f 7233 7377 7173 +f 7233 7173 7113 +f 7113 7173 7117 +f 7113 7117 6955 +f 6955 7117 6917 +f 6955 6917 6769 +f 6769 6917 6825 +f 6769 6825 6647 +f 6647 6825 6655 +f 6647 6655 6545 +f 6545 6655 6593 +f 6545 6593 6441 +f 6441 6593 6343 +f 6441 6343 6207 +f 6207 6343 6253 +f 6207 6253 6155 +f 6155 6253 6169 +f 6155 6169 5979 +f 5979 6169 5951 +f 5979 5951 5869 +f 5869 5951 5835 +f 5869 5835 5717 +f 5717 5835 5769 +f 5717 5769 5567 +f 5567 5769 5587 +f 5567 5587 5511 +f 5511 5587 5483 +f 5511 5483 5357 +f 5357 5483 5333 +f 5357 5333 5279 +f 5279 5333 5167 +f 5279 5167 5133 +f 5133 5167 5091 +f 5133 5091 4981 +f 4981 5091 4995 +f 4981 4995 4831 +f 4831 4995 4761 +f 4831 4761 4653 +f 4653 4761 4649 +f 4653 4649 4619 +f 4619 4649 4609 +f 4619 4609 4413 +f 4413 4609 4401 +f 4413 4401 4309 +f 4309 4401 4249 +f 4309 4249 4115 +f 4115 4249 4139 +f 4115 4139 4041 +f 4041 4139 3997 +f 4041 3997 3953 +f 3953 3997 3875 +f 3953 3875 3743 +f 3743 3875 3827 +f 3743 3827 3685 +f 3685 3827 3587 +f 3685 3587 3465 +f 3465 3587 3439 +f 3465 3439 3379 +f 3379 3439 3347 +f 3379 3347 3215 +f 3215 3347 3187 +f 3215 3187 3041 +f 3041 3187 3069 +f 3041 3069 3007 +f 3007 3069 2999 +f 3007 2999 2875 +f 2875 2999 2887 +f 2875 2887 2727 +f 2727 2887 2657 +f 2727 2657 2511 +f 2511 2657 2509 +f 2511 2509 2365 +f 2365 2509 2477 +f 2365 2477 2293 +f 2293 2477 2215 +f 2293 2215 2167 +f 2167 2215 2135 +f 2167 2135 1987 +f 1987 2135 2047 +f 1987 2047 1835 +f 1835 2047 1909 +f 1835 1909 1779 +f 1779 1909 1809 +f 1779 1809 1699 +f 1699 1809 1679 +f 1699 1679 1485 +f 1485 1679 1569 +f 1485 1569 1319 +f 1319 1569 1399 +f 1319 1399 1231 +f 1231 1399 1221 +f 1231 1221 1135 +f 1135 1221 1165 +f 1135 1165 1059 +f 1059 1165 945 +f 1059 945 821 +f 821 945 823 +f 821 823 711 +f 711 823 801 +f 711 801 609 +f 609 801 587 +f 609 587 487 +f 487 587 427 +f 487 427 297 +f 297 427 377 +f 297 377 277 +f 277 377 259 +f 277 259 59 +f 59 259 97 +f 59 97 14 +f 7789 7801 7703 +f 7703 7801 7743 +f 7703 7743 7523 +f 7523 7743 7551 +f 7523 7551 7475 +f 7475 7551 7453 +f 7475 7453 7315 +f 7315 7453 7291 +f 7315 7291 7176 +f 7176 7291 7233 +f 7176 7233 7081 +f 7081 7233 7113 +f 7081 7113 6939 +f 6939 7113 6955 +f 6939 6955 6795 +f 6795 6955 6769 +f 6795 6769 6633 +f 6633 6769 6647 +f 6633 6647 6527 +f 6527 6647 6545 +f 6527 6545 6447 +f 6447 6545 6441 +f 6447 6441 6265 +f 6265 6441 6207 +f 6265 6207 6187 +f 6187 6207 6155 +f 6187 6155 5969 +f 5969 6155 5979 +f 5969 5979 5847 +f 5847 5979 5869 +f 5847 5869 5789 +f 5789 5869 5717 +f 5789 5717 5593 +f 5593 5717 5567 +f 5593 5567 5433 +f 5433 5567 5511 +f 5433 5511 5363 +f 5363 5511 5357 +f 5363 5357 5233 +f 5233 5357 5279 +f 5233 5279 5051 +f 5051 5279 5133 +f 5051 5133 4939 +f 4939 5133 4981 +f 4939 4981 4765 +f 4765 4981 4831 +f 4765 4831 4673 +f 4673 4831 4653 +f 4673 4653 4543 +f 4543 4653 4619 +f 4543 4619 4469 +f 4469 4619 4413 +f 4469 4413 4275 +f 4275 4413 4309 +f 4275 4309 4151 +f 4151 4309 4115 +f 4151 4115 4063 +f 4063 4115 4041 +f 4063 4041 3927 +f 3927 4041 3953 +f 3927 3953 3815 +f 3815 3953 3743 +f 3815 3743 3579 +f 3579 3743 3685 +f 3579 3685 3491 +f 3491 3685 3465 +f 3491 3465 3397 +f 3397 3465 3379 +f 3397 3379 3179 +f 3179 3379 3215 +f 3179 3215 3059 +f 3059 3215 3041 +f 3059 3041 2913 +f 2913 3041 3007 +f 2913 3007 2783 +f 2783 3007 2875 +f 2783 2875 2729 +f 2729 2875 2727 +f 2729 2727 2613 +f 2613 2727 2511 +f 2613 2511 2375 +f 2375 2511 2365 +f 2375 2365 2335 +f 2335 2365 2293 +f 2335 2293 2107 +f 2107 2293 2167 +f 2107 2167 2059 +f 2059 2167 1987 +f 2059 1987 1903 +f 1903 1987 1835 +f 1903 1835 1825 +f 1825 1835 1779 +f 1825 1779 1631 +f 1631 1779 1699 +f 1631 1699 1491 +f 1491 1699 1485 +f 1491 1485 1350 +f 1350 1485 1319 +f 1350 1319 1262 +f 1262 1319 1231 +f 1262 1231 1079 +f 1079 1231 1135 +f 1079 1135 1019 +f 1019 1135 1059 +f 1019 1059 893 +f 893 1059 821 +f 893 821 703 +f 703 821 711 +f 703 711 591 +f 591 711 609 +f 591 609 537 +f 537 609 487 +f 537 487 303 +f 303 487 297 +f 303 297 189 +f 189 297 277 +f 189 277 148 +f 148 277 59 +f 148 59 2 +f 7787 7789 7711 +f 7711 7789 7703 +f 7711 7703 7553 +f 7553 7703 7523 +f 7553 7523 7483 +f 7483 7523 7475 +f 7483 7475 7325 +f 7325 7475 7315 +f 7325 7315 7203 +f 7203 7315 7176 +f 7203 7176 7082 +f 7082 7176 7081 +f 7082 7081 6937 +f 6937 7081 6939 +f 6937 6939 6815 +f 6815 6939 6795 +f 6815 6795 6649 +f 6649 6795 6633 +f 6649 6633 6511 +f 6511 6633 6527 +f 6511 6527 6431 +f 6431 6527 6447 +f 6431 6447 6233 +f 6233 6447 6265 +f 6233 6265 6093 +f 6093 6265 6187 +f 6093 6187 6063 +f 6063 6187 5969 +f 6063 5969 5829 +f 5829 5969 5847 +f 5829 5847 5685 +f 5685 5847 5789 +f 5685 5789 5669 +f 5669 5789 5593 +f 5669 5593 5463 +f 5463 5593 5433 +f 5463 5433 5323 +f 5323 5433 5363 +f 5323 5363 5185 +f 5185 5363 5233 +f 5185 5233 5149 +f 5149 5233 5051 +f 5149 5051 4979 +f 4979 5051 4939 +f 4979 4939 4795 +f 4795 4939 4765 +f 4795 4765 4645 +f 4645 4765 4673 +f 4645 4673 4531 +f 4531 4673 4543 +f 4531 4543 4363 +f 4363 4543 4469 +f 4363 4469 4267 +f 4267 4469 4275 +f 4267 4275 4197 +f 4197 4275 4151 +f 4197 4151 4011 +f 4011 4151 4063 +f 4011 4063 3847 +f 3847 4063 3927 +f 3847 3927 3779 +f 3779 3927 3815 +f 3779 3815 3591 +f 3591 3815 3579 +f 3591 3579 3511 +f 3511 3579 3491 +f 3511 3491 3429 +f 3429 3491 3397 +f 3429 3397 3211 +f 3211 3397 3179 +f 3211 3179 3057 +f 3057 3179 3059 +f 3057 3059 3005 +f 3005 3059 2913 +f 3005 2913 2819 +f 2819 2913 2783 +f 2819 2783 2639 +f 2639 2783 2729 +f 2639 2729 2535 +f 2535 2729 2613 +f 2535 2613 2361 +f 2361 2613 2375 +f 2361 2375 2273 +f 2273 2375 2335 +f 2273 2335 2203 +f 2203 2335 2107 +f 2203 2107 1995 +f 1995 2107 2059 +f 1995 2059 1949 +f 1949 2059 1903 +f 1949 1903 1701 +f 1701 1903 1825 +f 1701 1825 1691 +f 1691 1825 1631 +f 1691 1631 1449 +f 1449 1631 1491 +f 1449 1491 1321 +f 1321 1491 1350 +f 1321 1350 1293 +f 1293 1350 1262 +f 1293 1262 1129 +f 1129 1262 1079 +f 1129 1079 1049 +f 1049 1079 1019 +f 1049 1019 889 +f 889 1019 893 +f 889 893 707 +f 707 893 703 +f 707 703 641 +f 641 703 591 +f 641 591 425 +f 425 591 537 +f 425 537 411 +f 411 537 303 +f 411 303 185 +f 185 303 189 +f 185 189 93 +f 93 189 148 +f 93 148 2 +f 7847 7787 7643 +f 7643 7787 7711 +f 7643 7711 7554 +f 7554 7711 7553 +f 7554 7553 7470 +f 7470 7553 7483 +f 7470 7483 7301 +f 7301 7483 7325 +f 7301 7325 7227 +f 7227 7325 7203 +f 7227 7203 7039 +f 7039 7203 7082 +f 7039 7082 6869 +f 6869 7082 6937 +f 6869 6937 6819 +f 6819 6937 6815 +f 6819 6815 6665 +f 6665 6815 6649 +f 6665 6649 6501 +f 6501 6649 6511 +f 6501 6511 6453 +f 6453 6511 6431 +f 6453 6431 6273 +f 6273 6431 6233 +f 6273 6233 6129 +f 6129 6233 6093 +f 6129 6093 6059 +f 6059 6093 6063 +f 6059 6063 5845 +f 5845 6063 5829 +f 5845 5829 5742 +f 5742 5829 5685 +f 5742 5685 5607 +f 5607 5685 5669 +f 5607 5669 5425 +f 5425 5669 5463 +f 5425 5463 5413 +f 5413 5463 5323 +f 5413 5323 5227 +f 5227 5323 5185 +f 5227 5185 5113 +f 5113 5185 5149 +f 5113 5149 4983 +f 4983 5149 4979 +f 4983 4979 4789 +f 4789 4979 4795 +f 4789 4795 4643 +f 4643 4795 4645 +f 4643 4645 4547 +f 4547 4645 4531 +f 4547 4531 4434 +f 4434 4531 4363 +f 4434 4363 4327 +f 4327 4363 4267 +f 4327 4267 4131 +f 4131 4267 4197 +f 4131 4197 4079 +f 4079 4197 4011 +f 4079 4011 3883 +f 3883 4011 3847 +f 3883 3847 3791 +f 3791 3847 3779 +f 3791 3779 3601 +f 3601 3779 3591 +f 3601 3591 3531 +f 3531 3591 3511 +f 3531 3511 3395 +f 3395 3511 3429 +f 3395 3429 3291 +f 3291 3429 3211 +f 3291 3211 3147 +f 3147 3211 3057 +f 3147 3057 2941 +f 2941 3057 3005 +f 2941 3005 2805 +f 2805 3005 2819 +f 2805 2819 2723 +f 2723 2819 2639 +f 2723 2639 2529 +f 2529 2639 2535 +f 2529 2535 2369 +f 2369 2535 2361 +f 2369 2361 2317 +f 2317 2361 2273 +f 2317 2273 2191 +f 2191 2273 2203 +f 2191 2203 1973 +f 1973 2203 1995 +f 1973 1995 1939 +f 1939 1995 1949 +f 1939 1949 1815 +f 1815 1949 1701 +f 1815 1701 1635 +f 1635 1701 1691 +f 1635 1691 1518 +f 1518 1691 1449 +f 1518 1449 1341 +f 1341 1449 1321 +f 1341 1321 1253 +f 1253 1321 1293 +f 1253 1293 1187 +f 1187 1293 1129 +f 1187 1129 995 +f 995 1129 1049 +f 995 1049 807 +f 807 1049 889 +f 807 889 716 +f 716 889 707 +f 716 707 595 +f 595 707 641 +f 595 641 535 +f 535 641 425 +f 535 425 313 +f 313 425 411 +f 313 411 289 +f 289 411 185 +f 289 185 123 +f 123 185 93 +f 123 93 7 +f 7849 7847 7680 +f 7680 7847 7643 +f 7680 7643 7559 +f 7559 7643 7554 +f 7559 7554 7509 +f 7509 7554 7470 +f 7509 7470 7347 +f 7347 7470 7301 +f 7347 7301 7163 +f 7163 7301 7227 +f 7163 7227 7025 +f 7025 7227 7039 +f 7025 7039 6979 +f 6979 7039 6869 +f 6979 6869 6737 +f 6737 6869 6819 +f 6737 6819 6601 +f 6601 6819 6665 +f 6601 6665 6477 +f 6477 6665 6501 +f 6477 6501 6379 +f 6379 6501 6453 +f 6379 6453 6317 +f 6317 6453 6273 +f 6317 6273 6167 +f 6167 6273 6129 +f 6167 6129 6015 +f 6015 6129 6059 +f 6015 6059 5831 +f 5831 6059 5845 +f 5831 5845 5759 +f 5759 5845 5742 +f 5759 5742 5623 +f 5623 5742 5607 +f 5623 5607 5541 +f 5541 5607 5425 +f 5541 5425 5351 +f 5351 5425 5413 +f 5351 5413 5197 +f 5197 5413 5227 +f 5197 5227 5145 +f 5145 5227 5113 +f 5145 5113 4915 +f 4915 5113 4983 +f 4915 4983 4863 +f 4863 4983 4789 +f 4863 4789 4679 +f 4679 4789 4643 +f 4679 4643 4569 +f 4569 4643 4547 +f 4569 4547 4371 +f 4371 4547 4434 +f 4371 4434 4311 +f 4311 4434 4327 +f 4311 4327 4133 +f 4133 4327 4131 +f 4133 4131 4047 +f 4047 4131 4079 +f 4047 4079 3909 +f 3909 4079 3883 +f 3909 3883 3819 +f 3819 3883 3791 +f 3819 3791 3665 +f 3665 3791 3601 +f 3665 3601 3453 +f 3453 3601 3531 +f 3453 3531 3357 +f 3357 3531 3395 +f 3357 3395 3273 +f 3273 3395 3291 +f 3273 3291 3091 +f 3091 3291 3147 +f 3091 3147 2903 +f 2903 3147 2941 +f 2903 2941 2815 +f 2815 2941 2805 +f 2815 2805 2756 +f 2756 2805 2723 +f 2756 2723 2607 +f 2607 2723 2529 +f 2607 2529 2379 +f 2379 2529 2369 +f 2379 2369 2245 +f 2245 2369 2317 +f 2245 2317 2110 +f 2110 2317 2191 +f 2110 2191 1991 +f 1991 2191 1973 +f 1991 1973 1855 +f 1855 1973 1939 +f 1855 1939 1772 +f 1772 1939 1815 +f 1772 1815 1661 +f 1661 1815 1635 +f 1661 1635 1550 +f 1550 1635 1518 +f 1550 1518 1435 +f 1435 1518 1341 +f 1435 1341 1189 +f 1189 1341 1253 +f 1189 1253 1103 +f 1103 1253 1187 +f 1103 1187 1041 +f 1041 1187 995 +f 1041 995 825 +f 825 995 807 +f 825 807 725 +f 725 807 716 +f 725 716 603 +f 603 716 595 +f 603 595 431 +f 431 595 535 +f 431 535 333 +f 333 535 313 +f 333 313 265 +f 265 313 289 +f 265 289 141 +f 141 289 123 +f 141 123 8 +f 7869 7849 7727 +f 7727 7849 7680 +f 7727 7680 7593 +f 7593 7680 7559 +f 7593 7559 7411 +f 7411 7559 7509 +f 7411 7509 7333 +f 7333 7509 7347 +f 7333 7347 7237 +f 7237 7347 7163 +f 7237 7163 7018 +f 7018 7163 7025 +f 7018 7025 6975 +f 6975 7025 6979 +f 6975 6979 6745 +f 6745 6979 6737 +f 6745 6737 6653 +f 6653 6737 6601 +f 6653 6601 6494 +f 6494 6601 6477 +f 6494 6477 6374 +f 6374 6477 6379 +f 6374 6379 6305 +f 6305 6379 6317 +f 6305 6317 6087 +f 6087 6317 6167 +f 6087 6167 6009 +f 6009 6167 6015 +f 6009 6015 5839 +f 5839 6015 5831 +f 5839 5831 5777 +f 5777 5831 5759 +f 5777 5759 5601 +f 5601 5759 5623 +f 5601 5623 5529 +f 5529 5623 5541 +f 5529 5541 5295 +f 5295 5541 5351 +f 5295 5351 5277 +f 5277 5351 5197 +f 5277 5197 5027 +f 5027 5197 5145 +f 5027 5145 5001 +f 5001 5145 4915 +f 5001 4915 4781 +f 4781 4915 4863 +f 4781 4863 4680 +f 4680 4863 4679 +f 4680 4679 4503 +f 4503 4679 4569 +f 4503 4569 4457 +f 4457 4569 4371 +f 4457 4371 4241 +f 4241 4371 4311 +f 4241 4311 4135 +f 4135 4311 4133 +f 4135 4133 4061 +f 4061 4133 4047 +f 4061 4047 3871 +f 3871 4047 3909 +f 3871 3909 3795 +f 3795 3909 3819 +f 3795 3819 3697 +f 3697 3819 3665 +f 3697 3665 3489 +f 3489 3665 3453 +f 3489 3453 3418 +f 3418 3453 3357 +f 3418 3357 3259 +f 3259 3357 3273 +f 3259 3273 3151 +f 3151 3273 3091 +f 3151 3091 2917 +f 2917 3091 2903 +f 2917 2903 2779 +f 2779 2903 2815 +f 2779 2815 2637 +f 2637 2815 2756 +f 2637 2756 2499 +f 2499 2756 2607 +f 2499 2607 2371 +f 2371 2607 2379 +f 2371 2379 2253 +f 2253 2379 2245 +f 2253 2245 2175 +f 2175 2245 2110 +f 2175 2110 2011 +f 2011 2110 1991 +f 2011 1991 1904 +f 1904 1991 1855 +f 1904 1855 1783 +f 1783 1855 1772 +f 1783 1772 1611 +f 1611 1772 1661 +f 1611 1661 1535 +f 1535 1661 1550 +f 1535 1550 1343 +f 1343 1550 1435 +f 1343 1435 1213 +f 1213 1435 1189 +f 1213 1189 1071 +f 1071 1189 1103 +f 1071 1103 1008 +f 1008 1103 1041 +f 1008 1041 879 +f 879 1041 825 +f 879 825 803 +f 803 825 725 +f 803 725 596 +f 596 725 603 +f 596 603 511 +f 511 603 431 +f 511 431 315 +f 315 431 333 +f 315 333 225 +f 225 333 265 +f 225 265 147 +f 147 265 141 +f 147 141 8 +f 7805 7869 7731 +f 7731 7869 7727 +f 7731 7727 7525 +f 7525 7727 7593 +f 7525 7593 7461 +f 7461 7593 7411 +f 7461 7411 7303 +f 7303 7411 7333 +f 7303 7333 7191 +f 7191 7333 7237 +f 7191 7237 7125 +f 7125 7237 7018 +f 7125 7018 6971 +f 6971 7018 6975 +f 6971 6975 6835 +f 6835 6975 6745 +f 6835 6745 6675 +f 6675 6745 6653 +f 6675 6653 6581 +f 6581 6653 6494 +f 6581 6494 6421 +f 6421 6494 6374 +f 6421 6374 6219 +f 6219 6374 6305 +f 6219 6305 6127 +f 6127 6305 6087 +f 6127 6087 6025 +f 6025 6087 6009 +f 6025 6009 5879 +f 5879 6009 5839 +f 5879 5839 5747 +f 5747 5839 5777 +f 5747 5777 5625 +f 5625 5777 5601 +f 5625 5601 5441 +f 5441 5601 5529 +f 5441 5529 5297 +f 5297 5529 5295 +f 5297 5295 5205 +f 5205 5295 5277 +f 5205 5277 5041 +f 5041 5277 5027 +f 5041 5027 4929 +f 4929 5027 5001 +f 4929 5001 4773 +f 4773 5001 4781 +f 4773 4781 4749 +f 4749 4781 4680 +f 4749 4680 4605 +f 4605 4680 4503 +f 4605 4503 4367 +f 4367 4503 4457 +f 4367 4457 4281 +f 4281 4457 4241 +f 4281 4241 4183 +f 4183 4241 4135 +f 4183 4135 4081 +f 4081 4135 4061 +f 4081 4061 3885 +f 3885 4061 3871 +f 3885 3871 3761 +f 3761 3871 3795 +f 3761 3795 3693 +f 3693 3795 3697 +f 3693 3697 3463 +f 3463 3697 3489 +f 3463 3489 3331 +f 3331 3489 3418 +f 3331 3418 3183 +f 3183 3418 3259 +f 3183 3259 3049 +f 3049 3259 3151 +f 3049 3151 3027 +f 3027 3151 2917 +f 3027 2917 2774 +f 2774 2917 2779 +f 2774 2779 2745 +f 2745 2779 2637 +f 2745 2637 2523 +f 2523 2637 2499 +f 2523 2499 2423 +f 2423 2499 2371 +f 2423 2371 2235 +f 2235 2371 2253 +f 2235 2253 2093 +f 2093 2253 2175 +f 2093 2175 2007 +f 2007 2175 2011 +f 2007 2011 1874 +f 1874 2011 1904 +f 1874 1904 1811 +f 1811 1904 1783 +f 1811 1783 1669 +f 1669 1783 1611 +f 1669 1611 1468 +f 1468 1611 1535 +f 1468 1535 1373 +f 1373 1535 1343 +f 1373 1343 1284 +f 1284 1343 1213 +f 1284 1213 1085 +f 1085 1213 1071 +f 1085 1071 1033 +f 1033 1071 1008 +f 1033 1008 915 +f 915 1008 879 +f 915 879 754 +f 754 879 803 +f 754 803 588 +f 588 803 596 +f 588 596 461 +f 461 596 511 +f 461 511 391 +f 391 511 315 +f 391 315 229 +f 229 315 225 +f 229 225 45 +f 45 225 147 +f 45 147 29 +f 7863 7805 7741 +f 7741 7805 7731 +f 7741 7731 7597 +f 7597 7731 7525 +f 7597 7525 7428 +f 7428 7525 7461 +f 7428 7461 7367 +f 7367 7461 7303 +f 7367 7303 7185 +f 7185 7303 7191 +f 7185 7191 7061 +f 7061 7191 7125 +f 7061 7125 6863 +f 6863 7125 6971 +f 6863 6971 6741 +f 6741 6971 6835 +f 6741 6835 6657 +f 6657 6835 6675 +f 6657 6675 6577 +f 6577 6675 6581 +f 6577 6581 6455 +f 6455 6581 6421 +f 6455 6421 6299 +f 6299 6421 6219 +f 6299 6219 6089 +f 6089 6219 6127 +f 6089 6127 6011 +f 6011 6127 6025 +f 6011 6025 5909 +f 5909 6025 5879 +f 5909 5879 5785 +f 5785 5879 5747 +f 5785 5747 5579 +f 5579 5747 5625 +f 5579 5625 5461 +f 5461 5625 5441 +f 5461 5441 5378 +f 5378 5441 5297 +f 5378 5297 5261 +f 5261 5297 5205 +f 5261 5205 5033 +f 5033 5205 5041 +f 5033 5041 4931 +f 4931 5041 4929 +f 4931 4929 4851 +f 4851 4929 4773 +f 4851 4773 4657 +f 4657 4773 4749 +f 4657 4749 4525 +f 4525 4749 4605 +f 4525 4605 4421 +f 4421 4605 4367 +f 4421 4367 4334 +f 4334 4367 4281 +f 4334 4281 4167 +f 4167 4281 4183 +f 4167 4183 4001 +f 4001 4183 4081 +f 4001 4081 3947 +f 3947 4081 3885 +f 3947 3885 3767 +f 3767 3885 3761 +f 3767 3761 3603 +f 3603 3761 3693 +f 3603 3693 3539 +f 3539 3693 3463 +f 3539 3463 3405 +f 3405 3463 3331 +f 3405 3331 3289 +f 3289 3331 3183 +f 3289 3183 3089 +f 3089 3183 3049 +f 3089 3049 3017 +f 3017 3049 3027 +f 3017 3027 2777 +f 2777 3027 2774 +f 2777 2774 2659 +f 2659 2774 2745 +f 2659 2745 2577 +f 2577 2745 2523 +f 2577 2523 2467 +f 2467 2523 2423 +f 2467 2423 2271 +f 2271 2423 2235 +f 2271 2235 2089 +f 2089 2235 2093 +f 2089 2093 2012 +f 2012 2093 2007 +f 2012 2007 1943 +f 1943 2007 1874 +f 1943 1874 1741 +f 1741 1874 1811 +f 1741 1811 1694 +f 1694 1811 1669 +f 1694 1669 1459 +f 1459 1669 1468 +f 1459 1468 1397 +f 1397 1468 1373 +f 1397 1373 1273 +f 1273 1373 1284 +f 1273 1284 1095 +f 1095 1284 1085 +f 1095 1085 1034 +f 1034 1085 1033 +f 1034 1033 811 +f 811 1033 915 +f 811 915 755 +f 755 915 754 +f 755 754 627 +f 627 754 588 +f 627 588 539 +f 539 588 461 +f 539 461 339 +f 339 461 391 +f 339 391 279 +f 279 391 229 +f 279 229 63 +f 63 229 45 +f 63 45 29 +f 7860 7863 7645 +f 7645 7863 7741 +f 7645 7741 7617 +f 7617 7741 7597 +f 7617 7597 7473 +f 7473 7597 7428 +f 7473 7428 7285 +f 7285 7428 7367 +f 7285 7367 7167 +f 7167 7367 7185 +f 7167 7185 7115 +f 7115 7185 7061 +f 7115 7061 6931 +f 6931 7061 6863 +f 6931 6863 6853 +f 6853 6863 6741 +f 6853 6741 6699 +f 6699 6741 6657 +f 6699 6657 6585 +f 6585 6657 6577 +f 6585 6577 6407 +f 6407 6577 6455 +f 6407 6455 6249 +f 6249 6455 6299 +f 6249 6299 6145 +f 6145 6299 6089 +f 6145 6089 5957 +f 5957 6089 6011 +f 5957 6011 5821 +f 5821 6011 5909 +f 5821 5909 5755 +f 5755 5909 5785 +f 5755 5785 5643 +f 5643 5785 5579 +f 5643 5579 5521 +f 5521 5579 5461 +f 5521 5461 5321 +f 5321 5461 5378 +f 5321 5378 5181 +f 5181 5378 5261 +f 5181 5261 5143 +f 5143 5261 5033 +f 5143 5033 4959 +f 4959 5033 4931 +f 4959 4931 4791 +f 4791 4931 4851 +f 4791 4851 4631 +f 4631 4851 4657 +f 4631 4657 4575 +f 4575 4657 4525 +f 4575 4525 4386 +f 4386 4525 4421 +f 4386 4421 4282 +f 4282 4421 4334 +f 4282 4334 4201 +f 4201 4334 4167 +f 4201 4167 4009 +f 4009 4167 4001 +f 4009 4001 3861 +f 3861 4001 3947 +f 3861 3947 3799 +f 3799 3947 3767 +f 3799 3767 3617 +f 3617 3767 3603 +f 3617 3603 3517 +f 3517 3603 3539 +f 3517 3539 3401 +f 3401 3539 3405 +f 3401 3405 3253 +f 3253 3405 3289 +f 3253 3289 3092 +f 3092 3289 3089 +f 3092 3089 2921 +f 2921 3089 3017 +f 2921 3017 2877 +f 2877 3017 2777 +f 2877 2777 2681 +f 2681 2777 2659 +f 2681 2659 2585 +f 2585 2659 2577 +f 2585 2577 2469 +f 2469 2577 2467 +f 2469 2467 2255 +f 2255 2467 2271 +f 2255 2271 2156 +f 2156 2271 2089 +f 2156 2089 1996 +f 1996 2089 2012 +f 1996 2012 1856 +f 1856 2012 1943 +f 1856 1943 1751 +f 1751 1943 1741 +f 1751 1741 1684 +f 1684 1741 1694 +f 1684 1694 1479 +f 1479 1694 1459 +f 1479 1459 1419 +f 1419 1459 1397 +f 1419 1397 1294 +f 1294 1397 1273 +f 1294 1273 1072 +f 1072 1273 1095 +f 1072 1095 950 +f 950 1095 1034 +f 950 1034 841 +f 841 1034 811 +f 841 811 763 +f 763 811 755 +f 763 755 549 +f 549 755 627 +f 549 627 473 +f 473 627 539 +f 473 539 340 +f 340 539 339 +f 340 339 177 +f 177 339 279 +f 177 279 70 +f 70 279 63 +f 70 63 6 +f 7799 7860 7713 +f 7713 7860 7645 +f 7713 7645 7545 +f 7545 7645 7617 +f 7545 7617 7497 +f 7497 7617 7473 +f 7497 7473 7286 +f 7286 7473 7285 +f 7286 7285 7257 +f 7257 7285 7167 +f 7257 7167 7075 +f 7075 7167 7115 +f 7075 7115 6880 +f 6880 7115 6931 +f 6880 6931 6829 +f 6829 6931 6853 +f 6829 6853 6679 +f 6679 6853 6699 +f 6679 6699 6517 +f 6517 6699 6585 +f 6517 6585 6435 +f 6435 6585 6407 +f 6435 6407 6220 +f 6220 6407 6249 +f 6220 6249 6189 +f 6189 6249 6145 +f 6189 6145 5985 +f 5985 6145 5957 +f 5985 5957 5895 +f 5895 5957 5821 +f 5895 5821 5725 +f 5725 5821 5755 +f 5725 5755 5663 +f 5663 5755 5643 +f 5663 5643 5509 +f 5509 5643 5521 +f 5509 5521 5347 +f 5347 5521 5321 +f 5347 5321 5225 +f 5225 5321 5181 +f 5225 5181 5069 +f 5069 5181 5143 +f 5069 5143 4991 +f 4991 5143 4959 +f 4991 4959 4865 +f 4865 4959 4791 +f 4865 4791 4691 +f 4691 4791 4631 +f 4691 4631 4566 +f 4566 4631 4575 +f 4566 4575 4449 +f 4449 4575 4386 +f 4449 4386 4321 +f 4321 4386 4282 +f 4321 4282 4101 +f 4101 4282 4201 +f 4101 4201 3983 +f 3983 4201 4009 +f 3983 4009 3839 +f 3839 4009 3861 +f 3839 3861 3737 +f 3737 3861 3799 +f 3737 3799 3618 +f 3618 3799 3617 +f 3618 3617 3509 +f 3509 3617 3517 +f 3509 3517 3349 +f 3349 3517 3401 +f 3349 3401 3265 +f 3265 3401 3253 +f 3265 3253 3073 +f 3073 3253 3092 +f 3073 3092 2943 +f 2943 3092 2921 +f 2943 2921 2881 +f 2881 2921 2877 +f 2881 2877 2731 +f 2731 2877 2681 +f 2731 2681 2545 +f 2545 2681 2585 +f 2545 2585 2418 +f 2418 2585 2469 +f 2418 2469 2309 +f 2309 2469 2255 +f 2309 2255 2145 +f 2145 2255 2156 +f 2145 2156 1979 +f 1979 2156 1996 +f 1979 1996 1947 +f 1947 1996 1856 +f 1947 1856 1773 +f 1773 1856 1751 +f 1773 1751 1573 +f 1573 1751 1684 +f 1573 1684 1547 +f 1547 1684 1479 +f 1547 1479 1361 +f 1361 1479 1419 +f 1361 1419 1306 +f 1306 1419 1294 +f 1306 1294 1155 +f 1155 1294 1072 +f 1155 1072 983 +f 983 1072 950 +f 983 950 903 +f 903 950 841 +f 903 841 747 +f 747 841 763 +f 747 763 617 +f 617 763 549 +f 617 549 501 +f 501 549 473 +f 501 473 392 +f 392 473 340 +f 392 340 243 +f 243 340 177 +f 243 177 77 +f 77 177 70 +f 77 70 6 +f 7779 7799 7667 +f 7667 7799 7713 +f 7667 7713 7587 +f 7587 7713 7545 +f 7587 7545 7439 +f 7439 7545 7497 +f 7439 7497 7277 +f 7277 7497 7286 +f 7277 7286 7249 +f 7249 7286 7257 +f 7249 7257 7037 +f 7037 7257 7075 +f 7037 7075 6933 +f 6933 7075 6880 +f 6933 6880 6805 +f 6805 6880 6829 +f 6805 6829 6621 +f 6621 6829 6679 +f 6621 6679 6521 +f 6521 6679 6517 +f 6521 6517 6371 +f 6371 6517 6435 +f 6371 6435 6261 +f 6261 6435 6220 +f 6261 6220 6101 +f 6101 6220 6189 +f 6101 6189 5946 +f 5946 6189 5985 +f 5946 5985 5815 +f 5815 5985 5895 +f 5815 5895 5709 +f 5709 5895 5725 +f 5709 5725 5655 +f 5655 5725 5663 +f 5655 5663 5435 +f 5435 5663 5509 +f 5435 5509 5395 +f 5395 5509 5347 +f 5395 5347 5258 +f 5258 5347 5225 +f 5258 5225 5077 +f 5077 5225 5069 +f 5077 5069 5007 +f 5007 5069 4991 +f 5007 4991 4840 +f 4840 4991 4865 +f 4840 4865 4735 +f 4735 4865 4691 +f 4735 4691 4617 +f 4617 4691 4566 +f 4617 4566 4409 +f 4409 4566 4449 +f 4409 4449 4257 +f 4257 4449 4321 +f 4257 4321 4123 +f 4123 4321 4101 +f 4123 4101 4028 +f 4028 4101 3983 +f 4028 3983 3897 +f 3897 3983 3839 +f 3897 3839 3756 +f 3756 3839 3737 +f 3756 3737 3653 +f 3653 3737 3618 +f 3653 3618 3478 +f 3478 3618 3509 +f 3478 3509 3389 +f 3389 3509 3349 +f 3389 3349 3285 +f 3285 3349 3265 +f 3285 3265 3045 +f 3045 3265 3073 +f 3045 3073 3003 +f 3003 3073 2943 +f 3003 2943 2821 +f 2821 2943 2881 +f 2821 2881 2743 +f 2743 2881 2731 +f 2743 2731 2561 +f 2561 2731 2545 +f 2561 2545 2461 +f 2461 2545 2418 +f 2461 2418 2297 +f 2297 2418 2309 +f 2297 2309 2137 +f 2137 2309 2145 +f 2137 2145 2029 +f 2029 2145 1979 +f 2029 1979 1833 +f 1833 1979 1947 +f 1833 1947 1764 +f 1764 1947 1773 +f 1764 1773 1639 +f 1639 1773 1573 +f 1639 1573 1508 +f 1508 1573 1547 +f 1508 1547 1362 +f 1362 1547 1361 +f 1362 1361 1235 +f 1235 1361 1306 +f 1235 1306 1112 +f 1112 1306 1155 +f 1112 1155 1022 +f 1022 1155 983 +f 1022 983 837 +f 837 983 903 +f 837 903 695 +f 695 903 747 +f 695 747 660 +f 660 747 617 +f 660 617 491 +f 491 617 501 +f 491 501 355 +f 355 501 392 +f 355 392 213 +f 213 392 243 +f 213 243 159 +f 159 243 77 +f 159 77 30 +f 7873 7779 7719 +f 7719 7779 7667 +f 7719 7667 7623 +f 7623 7667 7587 +f 7623 7587 7421 +f 7421 7587 7439 +f 7421 7439 7361 +f 7361 7439 7277 +f 7361 7277 7255 +f 7255 7277 7249 +f 7255 7249 7095 +f 7095 7249 7037 +f 7095 7037 6963 +f 6963 7037 6933 +f 6963 6933 6802 +f 6802 6933 6805 +f 6802 6805 6680 +f 6680 6805 6621 +f 6680 6621 6467 +f 6467 6621 6521 +f 6467 6521 6436 +f 6436 6521 6371 +f 6436 6371 6223 +f 6223 6371 6261 +f 6223 6261 6079 +f 6079 6261 6101 +f 6079 6101 6055 +f 6055 6101 5946 +f 6055 5946 5922 +f 5922 5946 5815 +f 5922 5815 5701 +f 5701 5815 5709 +f 5701 5709 5659 +f 5659 5709 5655 +f 5659 5655 5477 +f 5477 5655 5435 +f 5477 5435 5349 +f 5349 5435 5395 +f 5349 5395 5191 +f 5191 5395 5258 +f 5191 5258 5028 +f 5028 5258 5077 +f 5028 5077 4908 +f 4908 5077 5007 +f 4908 5007 4819 +f 4819 5007 4840 +f 4819 4840 4713 +f 4713 4840 4735 +f 4713 4735 4527 +f 4527 4735 4617 +f 4527 4617 4427 +f 4427 4617 4409 +f 4427 4409 4349 +f 4349 4409 4257 +f 4349 4257 4217 +f 4217 4257 4123 +f 4217 4123 4064 +f 4064 4123 4028 +f 4064 4028 3899 +f 3899 4028 3897 +f 3899 3897 3721 +f 3721 3897 3756 +f 3721 3756 3585 +f 3585 3756 3653 +f 3585 3653 3505 +f 3505 3653 3478 +f 3505 3478 3402 +f 3402 3478 3389 +f 3402 3389 3261 +f 3261 3389 3285 +f 3261 3285 3139 +f 3139 3285 3045 +f 3139 3045 3025 +f 3025 3045 3003 +f 3025 3003 2793 +f 2793 3003 2821 +f 2793 2821 2713 +f 2713 2821 2743 +f 2713 2743 2571 +f 2571 2743 2561 +f 2571 2561 2398 +f 2398 2561 2461 +f 2398 2461 2256 +f 2256 2461 2297 +f 2256 2297 2087 +f 2087 2297 2137 +f 2087 2137 2035 +f 2035 2137 2029 +f 2035 2029 1839 +f 1839 2029 1833 +f 1839 1833 1742 +f 1742 1833 1764 +f 1742 1764 1681 +f 1681 1764 1639 +f 1681 1639 1519 +f 1519 1639 1508 +f 1519 1508 1374 +f 1374 1508 1362 +f 1374 1362 1315 +f 1315 1362 1235 +f 1315 1235 1104 +f 1104 1235 1112 +f 1104 1112 951 +f 951 1112 1022 +f 951 1022 904 +f 904 1022 837 +f 904 837 797 +f 797 837 695 +f 797 695 582 +f 582 695 660 +f 582 660 541 +f 541 660 491 +f 541 491 413 +f 413 491 355 +f 413 355 230 +f 230 355 213 +f 230 213 53 +f 53 213 159 +f 53 159 30 +f 7819 7873 7671 +f 7671 7873 7719 +f 7671 7719 7629 +f 7629 7719 7623 +f 7629 7623 7498 +f 7498 7623 7421 +f 7498 7421 7323 +f 7323 7421 7361 +f 7323 7361 7177 +f 7177 7361 7255 +f 7177 7255 7053 +f 7053 7255 7095 +f 7053 7095 6964 +f 6964 7095 6963 +f 6964 6963 6761 +f 6761 6963 6802 +f 6761 6802 6713 +f 6713 6802 6680 +f 6713 6680 6591 +f 6591 6680 6467 +f 6591 6467 6461 +f 6461 6467 6436 +f 6461 6436 6217 +f 6217 6436 6223 +f 6217 6223 6157 +f 6157 6223 6079 +f 6157 6079 5973 +f 5973 6079 6055 +f 5973 6055 5851 +f 5851 6055 5922 +f 5851 5922 5786 +f 5786 5922 5701 +f 5786 5701 5591 +f 5591 5701 5659 +f 5591 5659 5535 +f 5535 5659 5477 +f 5535 5477 5353 +f 5353 5477 5349 +f 5353 5349 5244 +f 5244 5349 5191 +f 5244 5191 5065 +f 5065 5191 5028 +f 5065 5028 4917 +f 4917 5028 4908 +f 4917 4908 4792 +f 4792 4908 4819 +f 4792 4819 4629 +f 4629 4819 4713 +f 4629 4713 4576 +f 4576 4713 4527 +f 4576 4527 4373 +f 4373 4527 4427 +f 4373 4427 4299 +f 4299 4427 4349 +f 4299 4349 4203 +f 4203 4349 4217 +f 4203 4217 4025 +f 4025 4217 4064 +f 4025 4064 3879 +f 3879 4064 3899 +f 3879 3899 3801 +f 3801 3899 3721 +f 3801 3721 3577 +f 3577 3721 3585 +f 3577 3585 3527 +f 3527 3585 3505 +f 3527 3505 3385 +f 3385 3505 3402 +f 3385 3402 3245 +f 3245 3402 3261 +f 3245 3261 3064 +f 3064 3261 3139 +f 3064 3139 2961 +f 2961 3139 3025 +f 2961 3025 2807 +f 2807 3025 2793 +f 2807 2793 2691 +f 2691 2793 2713 +f 2691 2713 2579 +f 2579 2713 2571 +f 2579 2571 2429 +f 2429 2571 2398 +f 2429 2398 2279 +f 2279 2398 2256 +f 2279 2256 2157 +f 2157 2256 2087 +f 2157 2087 2040 +f 2040 2087 2035 +f 2040 2035 1857 +f 1857 2035 1839 +f 1857 1839 1743 +f 1743 1839 1742 +f 1743 1742 1624 +f 1624 1742 1681 +f 1624 1681 1457 +f 1457 1681 1519 +f 1457 1519 1427 +f 1427 1519 1374 +f 1427 1374 1193 +f 1193 1374 1315 +f 1193 1315 1089 +f 1089 1315 1104 +f 1089 1104 1031 +f 1031 1104 951 +f 1031 951 916 +f 916 951 904 +f 916 904 798 +f 798 904 797 +f 798 797 631 +f 631 797 582 +f 631 582 503 +f 503 582 541 +f 503 541 295 +f 295 541 413 +f 295 413 173 +f 173 413 230 +f 173 230 101 +f 101 230 53 +f 101 53 25 +f 7827 7819 7681 +f 7681 7819 7671 +f 7681 7671 7539 +f 7539 7671 7629 +f 7539 7629 7457 +f 7457 7629 7498 +f 7457 7498 7348 +f 7348 7498 7323 +f 7348 7323 7169 +f 7169 7323 7177 +f 7169 7177 7023 +f 7023 7177 7053 +f 7023 7053 6907 +f 6907 7053 6964 +f 6907 6964 6729 +f 6729 6964 6761 +f 6729 6761 6623 +f 6623 6761 6713 +f 6623 6713 6495 +f 6495 6713 6591 +f 6495 6591 6337 +f 6337 6591 6461 +f 6337 6461 6243 +f 6243 6461 6217 +f 6243 6217 6175 +f 6175 6217 6157 +f 6175 6157 5952 +f 5952 6157 5973 +f 5952 5973 5883 +f 5883 5973 5851 +f 5883 5851 5719 +f 5719 5851 5786 +f 5719 5786 5589 +f 5589 5786 5591 +f 5589 5591 5506 +f 5506 5591 5535 +f 5506 5535 5387 +f 5387 5535 5353 +f 5387 5353 5237 +f 5237 5353 5244 +f 5237 5244 5059 +f 5059 5244 5065 +f 5059 5065 4945 +f 4945 5065 4917 +f 4945 4917 4811 +f 4811 4917 4792 +f 4811 4792 4661 +f 4661 4792 4629 +f 4661 4629 4581 +f 4581 4629 4576 +f 4581 4576 4405 +f 4405 4576 4373 +f 4405 4373 4285 +f 4285 4373 4299 +f 4285 4299 4179 +f 4179 4299 4203 +f 4179 4203 4067 +f 4067 4203 4025 +f 4067 4025 3905 +f 3905 4025 3879 +f 3905 3879 3787 +f 3787 3879 3801 +f 3787 3801 3581 +f 3581 3801 3577 +f 3581 3577 3449 +f 3449 3577 3527 +f 3449 3527 3369 +f 3369 3527 3385 +f 3369 3385 3195 +f 3195 3385 3245 +f 3195 3245 3153 +f 3153 3245 3064 +f 3153 3064 3022 +f 3022 3064 2961 +f 3022 2961 2825 +f 2825 2961 2807 +f 2825 2807 2714 +f 2714 2807 2691 +f 2714 2691 2603 +f 2603 2691 2579 +f 2603 2579 2451 +f 2451 2579 2429 +f 2451 2429 2231 +f 2231 2429 2279 +f 2231 2279 2127 +f 2127 2279 2157 +f 2127 2157 1975 +f 1975 2157 2040 +f 1975 2040 1915 +f 1915 2040 1857 +f 1915 1857 1752 +f 1752 1857 1743 +f 1752 1743 1625 +f 1625 1743 1624 +f 1625 1624 1486 +f 1486 1624 1457 +f 1486 1457 1403 +f 1403 1457 1427 +f 1403 1427 1255 +f 1255 1427 1193 +f 1255 1193 1173 +f 1173 1193 1089 +f 1173 1089 992 +f 992 1089 1031 +f 992 1031 931 +f 931 1031 916 +f 931 916 770 +f 770 916 798 +f 770 798 661 +f 661 798 631 +f 661 631 495 +f 495 631 503 +f 495 503 380 +f 380 503 295 +f 380 295 281 +f 281 295 173 +f 281 173 46 +f 46 173 101 +f 46 101 11 +f 7820 7827 7689 +f 7689 7827 7681 +f 7689 7681 7633 +f 7633 7681 7539 +f 7633 7539 7465 +f 7465 7539 7457 +f 7465 7457 7389 +f 7389 7457 7348 +f 7389 7348 7149 +f 7149 7348 7169 +f 7149 7169 7127 +f 7127 7169 7023 +f 7127 7023 6898 +f 6898 7023 6907 +f 6898 6907 6831 +f 6831 6907 6729 +f 6831 6729 6627 +f 6627 6729 6623 +f 6627 6623 6491 +f 6491 6623 6495 +f 6491 6495 6391 +f 6391 6495 6337 +f 6391 6337 6227 +f 6227 6337 6243 +f 6227 6243 6165 +f 6165 6243 6175 +f 6165 6175 6033 +f 6033 6175 5952 +f 6033 5952 5910 +f 5910 5952 5883 +f 5910 5883 5689 +f 5689 5883 5719 +f 5689 5719 5563 +f 5563 5719 5589 +f 5563 5589 5543 +f 5543 5589 5506 +f 5543 5506 5405 +f 5405 5506 5387 +f 5405 5387 5281 +f 5281 5387 5237 +f 5281 5237 5135 +f 5135 5237 5059 +f 5135 5059 4895 +f 4895 5059 4945 +f 4895 4945 4805 +f 4805 4945 4811 +f 4805 4811 4633 +f 4633 4811 4661 +f 4633 4661 4601 +f 4601 4661 4581 +f 4601 4581 4453 +f 4453 4581 4405 +f 4453 4405 4322 +f 4322 4405 4285 +f 4322 4285 4211 +f 4211 4285 4179 +f 4211 4179 3991 +f 3991 4179 4067 +f 3991 4067 3955 +f 3955 4067 3905 +f 3955 3905 3727 +f 3727 3905 3787 +f 3727 3787 3612 +f 3612 3787 3581 +f 3612 3581 3513 +f 3513 3581 3449 +f 3513 3449 3333 +f 3333 3449 3369 +f 3333 3369 3201 +f 3201 3369 3195 +f 3201 3195 3145 +f 3145 3195 3153 +f 3145 3153 2919 +f 2919 3153 3022 +f 2919 3022 2855 +f 2855 3022 2825 +f 2855 2825 2699 +f 2699 2825 2714 +f 2699 2714 2580 +f 2580 2714 2603 +f 2580 2603 2424 +f 2424 2603 2451 +f 2424 2451 2246 +f 2246 2451 2231 +f 2246 2231 2111 +f 2111 2231 2127 +f 2111 2127 2013 +f 2013 2127 1975 +f 2013 1975 1844 +f 1844 1975 1915 +f 1844 1915 1753 +f 1753 1915 1752 +f 1753 1752 1589 +f 1589 1752 1625 +f 1589 1625 1492 +f 1492 1625 1486 +f 1492 1486 1329 +f 1329 1486 1403 +f 1329 1403 1263 +f 1263 1403 1255 +f 1263 1255 1167 +f 1167 1255 1173 +f 1167 1173 959 +f 959 1173 992 +f 959 992 842 +f 842 992 931 +f 842 931 748 +f 748 931 770 +f 748 770 611 +f 611 770 661 +f 611 661 481 +f 481 661 495 +f 481 495 414 +f 414 495 380 +f 414 380 169 +f 169 380 281 +f 169 281 95 +f 95 281 46 +f 95 46 11 +f 7795 7820 7747 +f 7747 7820 7689 +f 7747 7689 7563 +f 7563 7689 7633 +f 7563 7633 7431 +f 7431 7633 7465 +f 7431 7465 7338 +f 7338 7465 7389 +f 7338 7389 7194 +f 7194 7389 7149 +f 7194 7149 7043 +f 7043 7149 7127 +f 7043 7127 6947 +f 6947 7127 6898 +f 6947 6898 6767 +f 6767 6898 6831 +f 6767 6831 6691 +f 6691 6831 6627 +f 6691 6627 6522 +f 6522 6627 6491 +f 6522 6491 6363 +f 6363 6491 6391 +f 6363 6391 6244 +f 6244 6391 6227 +f 6244 6227 6171 +f 6171 6227 6165 +f 6171 6165 5974 +f 5974 6165 6033 +f 5974 6033 5923 +f 5923 6033 5910 +f 5923 5910 5715 +f 5715 5910 5689 +f 5715 5689 5615 +f 5615 5689 5563 +f 5615 5563 5429 +f 5429 5563 5543 +f 5429 5543 5325 +f 5325 5543 5405 +f 5325 5405 5213 +f 5213 5405 5281 +f 5213 5281 5099 +f 5099 5281 5135 +f 5099 5135 4951 +f 4951 5135 4895 +f 4951 4895 4821 +f 4821 4895 4805 +f 4821 4805 4701 +f 4701 4805 4633 +f 4701 4633 4561 +f 4561 4633 4601 +f 4561 4601 4429 +f 4429 4601 4453 +f 4429 4453 4251 +f 4251 4453 4322 +f 4251 4322 4113 +f 4113 4322 4211 +f 4113 4211 4021 +f 4021 4211 3991 +f 4021 3991 3889 +f 3889 3991 3955 +f 3889 3955 3769 +f 3769 3955 3727 +f 3769 3727 3647 +f 3647 3727 3612 +f 3647 3612 3473 +f 3473 3612 3513 +f 3473 3513 3309 +f 3309 3513 3333 +f 3309 3333 3199 +f 3199 3333 3201 +f 3199 3201 3099 +f 3099 3201 3145 +f 3099 3145 2989 +f 2989 3145 2919 +f 2989 2919 2859 +f 2859 2919 2855 +f 2859 2855 2702 +f 2702 2855 2699 +f 2702 2699 2546 +f 2546 2699 2580 +f 2546 2580 2430 +f 2430 2580 2424 +f 2430 2424 2221 +f 2221 2424 2246 +f 2221 2246 2169 +f 2169 2246 2111 +f 2169 2111 1980 +f 1980 2111 2013 +f 1980 2013 1889 +f 1889 2013 1844 +f 1889 1844 1731 +f 1731 1844 1753 +f 1731 1753 1603 +f 1603 1753 1589 +f 1603 1589 1539 +f 1539 1589 1492 +f 1539 1492 1423 +f 1423 1492 1329 +f 1423 1329 1285 +f 1285 1329 1263 +f 1285 1263 1090 +f 1090 1263 1167 +f 1090 1167 977 +f 977 1167 959 +f 977 959 843 +f 843 959 842 +f 843 842 771 +f 771 842 748 +f 771 748 597 +f 597 748 611 +f 597 611 515 +f 515 611 481 +f 515 481 364 +f 364 481 414 +f 364 414 260 +f 260 414 169 +f 260 169 157 +f 157 169 95 +f 157 95 21 +f 7763 7795 7690 +f 7690 7795 7747 +f 7690 7747 7549 +f 7549 7747 7563 +f 7549 7563 7413 +f 7413 7563 7431 +f 7413 7431 7313 +f 7313 7431 7338 +f 7313 7338 7229 +f 7229 7338 7194 +f 7229 7194 7090 +f 7090 7194 7043 +f 7090 7043 6889 +f 6889 7043 6947 +f 6889 6947 6771 +f 6771 6947 6767 +f 6771 6767 6719 +f 6719 6767 6691 +f 6719 6691 6480 +f 6480 6691 6522 +f 6480 6522 6380 +f 6380 6522 6363 +f 6380 6363 6224 +f 6224 6363 6244 +f 6224 6244 6135 +f 6135 6244 6171 +f 6135 6171 6027 +f 6027 6171 5974 +f 6027 5974 5816 +f 5816 5974 5923 +f 5816 5923 5679 +f 5679 5923 5715 +f 5679 5715 5554 +f 5554 5715 5615 +f 5554 5615 5495 +f 5495 5615 5429 +f 5495 5429 5388 +f 5388 5429 5325 +f 5388 5325 5173 +f 5173 5325 5213 +f 5173 5213 5060 +f 5060 5213 5099 +f 5060 5099 5009 +f 5009 5099 4951 +f 5009 4951 4785 +f 4785 4951 4821 +f 4785 4821 4705 +f 4705 4821 4701 +f 4705 4701 4545 +f 4545 4701 4561 +f 4545 4561 4431 +f 4431 4561 4429 +f 4431 4429 4314 +f 4314 4429 4251 +f 4314 4251 4136 +f 4136 4251 4113 +f 4136 4113 4019 +f 4019 4113 4021 +f 4019 4021 3855 +f 3855 4021 3889 +f 3855 3889 3711 +f 3711 3889 3769 +f 3711 3769 3671 +f 3671 3769 3647 +f 3671 3647 3559 +f 3559 3647 3473 +f 3559 3473 3421 +f 3421 3473 3309 +f 3421 3309 3207 +f 3207 3309 3199 +f 3207 3199 3106 +f 3106 3199 3099 +f 3106 3099 2975 +f 2975 3099 2989 +f 2975 2989 2831 +f 2831 2989 2859 +f 2831 2859 2673 +f 2673 2859 2702 +f 2673 2702 2572 +f 2572 2702 2546 +f 2572 2546 2452 +f 2452 2546 2430 +f 2452 2430 2287 +f 2287 2430 2221 +f 2287 2221 2128 +f 2128 2221 2169 +f 2128 2169 2041 +f 2041 2169 1980 +f 2041 1980 1916 +f 1916 1980 1889 +f 1916 1889 1732 +f 1732 1889 1731 +f 1732 1731 1685 +f 1685 1731 1603 +f 1685 1603 1520 +f 1520 1603 1539 +f 1520 1539 1337 +f 1337 1539 1423 +f 1337 1423 1207 +f 1207 1423 1285 +f 1207 1285 1113 +f 1113 1285 1090 +f 1113 1090 967 +f 967 1090 977 +f 967 977 910 +f 910 977 843 +f 910 843 696 +f 696 843 771 +f 696 771 574 +f 574 771 597 +f 574 597 454 +f 454 597 515 +f 454 515 311 +f 311 515 364 +f 311 364 191 +f 191 364 260 +f 191 260 113 +f 113 260 157 +f 113 157 21 +f 7777 7763 7704 +f 7704 7763 7690 +f 7704 7690 7531 +f 7531 7690 7549 +f 7531 7549 7417 +f 7417 7549 7413 +f 7417 7413 7326 +f 7326 7413 7313 +f 7326 7313 7161 +f 7161 7313 7229 +f 7161 7229 7109 +f 7109 7229 7090 +f 7109 7090 6899 +f 6899 7090 6889 +f 6899 6889 6754 +f 6754 6889 6771 +f 6754 6771 6658 +f 6658 6771 6719 +f 6658 6719 6561 +f 6561 6719 6480 +f 6561 6480 6423 +f 6423 6480 6380 +f 6423 6380 6306 +f 6306 6380 6224 +f 6306 6224 6194 +f 6194 6224 6135 +f 6194 6135 6053 +f 6053 6135 6027 +f 6053 6027 5927 +f 5927 6027 5816 +f 5927 5816 5761 +f 5761 5816 5679 +f 5761 5679 5641 +f 5641 5679 5554 +f 5641 5554 5496 +f 5496 5554 5495 +f 5496 5495 5407 +f 5407 5495 5388 +f 5407 5388 5179 +f 5179 5388 5173 +f 5179 5173 5093 +f 5093 5173 5060 +f 5093 5060 4891 +f 4891 5060 5009 +f 4891 5009 4885 +f 4885 5009 4785 +f 4885 4785 4687 +f 4687 4785 4705 +f 4687 4705 4519 +f 4519 4705 4545 +f 4519 4545 4447 +f 4447 4545 4431 +f 4447 4431 4255 +f 4255 4431 4314 +f 4255 4314 4193 +f 4193 4314 4136 +f 4193 4136 4071 +f 4071 4136 4019 +f 4071 4019 3937 +f 3937 4019 3855 +f 3937 3855 3817 +f 3817 3855 3711 +f 3817 3711 3667 +f 3667 3711 3671 +f 3667 3671 3447 +f 3447 3671 3559 +f 3447 3559 3339 +f 3339 3559 3421 +f 3339 3421 3269 +f 3269 3421 3207 +f 3269 3207 3125 +f 3125 3207 3106 +f 3125 3106 2967 +f 2967 3106 2975 +f 2967 2975 2832 +f 2832 2975 2831 +f 2832 2831 2674 +f 2674 2831 2673 +f 2674 2673 2553 +f 2553 2673 2572 +f 2553 2572 2457 +f 2457 2572 2452 +f 2457 2452 2301 +f 2301 2452 2287 +f 2301 2287 2112 +f 2112 2287 2128 +f 2112 2128 2014 +f 2014 2128 2041 +f 2014 2041 1845 +f 1845 2041 1916 +f 1845 1916 1819 +f 1819 1916 1732 +f 1819 1732 1648 +f 1648 1732 1685 +f 1648 1685 1567 +f 1567 1685 1520 +f 1567 1520 1351 +f 1351 1520 1337 +f 1351 1337 1236 +f 1236 1337 1207 +f 1236 1207 1091 +f 1091 1207 1113 +f 1091 1113 1045 +f 1045 1113 967 +f 1045 967 844 +f 844 967 910 +f 844 910 691 +f 691 910 696 +f 691 696 553 +f 553 696 574 +f 553 574 466 +f 466 574 454 +f 466 454 351 +f 351 454 311 +f 351 311 252 +f 252 311 191 +f 252 191 115 +f 115 191 113 +f 115 113 4 +f 7825 7777 7714 +f 7714 7777 7704 +f 7714 7704 7599 +f 7599 7704 7531 +f 7599 7531 7443 +f 7443 7531 7417 +f 7443 7417 7327 +f 7327 7417 7326 +f 7327 7326 7219 +f 7219 7326 7161 +f 7219 7161 7069 +f 7069 7161 7109 +f 7069 7109 6929 +f 6929 7109 6899 +f 6929 6899 6748 +f 6748 6899 6754 +f 6748 6754 6683 +f 6683 6754 6658 +f 6683 6658 6586 +f 6586 6658 6561 +f 6586 6561 6339 +f 6339 6561 6423 +f 6339 6423 6315 +f 6315 6423 6306 +f 6315 6306 6201 +f 6201 6306 6194 +f 6201 6194 5981 +f 5981 6194 6053 +f 5981 6053 5929 +f 5929 6053 5927 +f 5929 5927 5733 +f 5733 5927 5761 +f 5733 5761 5585 +f 5585 5761 5641 +f 5585 5641 5426 +f 5426 5641 5496 +f 5426 5496 5369 +f 5369 5496 5407 +f 5369 5407 5207 +f 5207 5407 5179 +f 5207 5179 5043 +f 5043 5179 5093 +f 5043 5093 5005 +f 5005 5093 4891 +f 5005 4891 4881 +f 4881 4891 4885 +f 4881 4885 4706 +f 4706 4885 4687 +f 4706 4687 4537 +f 4537 4687 4519 +f 4537 4519 4463 +f 4463 4519 4447 +f 4463 4447 4295 +f 4295 4447 4255 +f 4295 4255 4174 +f 4174 4255 4193 +f 4174 4193 4075 +f 4075 4193 4071 +f 4075 4071 3938 +f 3938 4071 3937 +f 3938 3937 3731 +f 3731 3937 3817 +f 3731 3817 3595 +f 3595 3817 3667 +f 3595 3667 3469 +f 3469 3667 3447 +f 3469 3447 3355 +f 3355 3447 3339 +f 3355 3339 3227 +f 3227 3339 3269 +f 3227 3269 3107 +f 3107 3269 3125 +f 3107 3125 2968 +f 2968 3125 2967 +f 2968 2967 2823 +f 2823 2967 2832 +f 2823 2832 2669 +f 2669 2832 2674 +f 2669 2674 2573 +f 2573 2674 2553 +f 2573 2553 2407 +f 2407 2553 2457 +f 2407 2457 2257 +f 2257 2457 2301 +f 2257 2301 2091 +f 2091 2301 2112 +f 2091 2112 2061 +f 2061 2112 2014 +f 2061 2014 1890 +f 1890 2014 1845 +f 1890 1845 1713 +f 1713 1845 1819 +f 1713 1819 1590 +f 1590 1819 1648 +f 1590 1648 1521 +f 1521 1648 1567 +f 1521 1567 1383 +f 1383 1567 1351 +f 1383 1351 1194 +f 1194 1351 1236 +f 1194 1236 1114 +f 1114 1236 1091 +f 1114 1091 999 +f 999 1091 1045 +f 999 1045 845 +f 845 1045 844 +f 845 844 781 +f 781 844 691 +f 781 691 632 +f 632 691 553 +f 632 553 482 +f 482 553 466 +f 482 466 365 +f 365 466 351 +f 365 351 269 +f 269 351 252 +f 269 252 78 +f 78 252 115 +f 78 115 4 +f 7813 7825 7659 +f 7659 7825 7714 +f 7659 7714 7532 +f 7532 7714 7599 +f 7532 7599 7466 +f 7466 7599 7443 +f 7466 7443 7365 +f 7365 7443 7327 +f 7365 7327 7170 +f 7170 7327 7219 +f 7170 7219 7063 +f 7063 7219 7069 +f 7063 7069 6948 +f 6948 7069 6929 +f 6948 6929 6806 +f 6806 6929 6748 +f 6806 6748 6692 +f 6692 6748 6683 +f 6692 6683 6513 +f 6513 6683 6586 +f 6513 6586 6424 +f 6424 6586 6339 +f 6424 6339 6288 +f 6288 6339 6315 +f 6288 6315 6158 +f 6158 6315 6201 +f 6158 6201 6061 +f 6061 6201 5981 +f 6061 5981 5911 +f 5911 5981 5929 +f 5911 5929 5681 +f 5681 5929 5733 +f 5681 5733 5629 +f 5629 5733 5585 +f 5629 5585 5478 +f 5478 5585 5426 +f 5478 5426 5291 +f 5291 5426 5369 +f 5291 5369 5155 +f 5155 5369 5207 +f 5155 5207 5141 +f 5141 5207 5043 +f 5141 5043 4977 +f 4977 5043 5005 +f 4977 5005 4847 +f 4847 5005 4881 +f 4847 4881 4669 +f 4669 4881 4706 +f 4669 4706 4505 +f 4505 4706 4537 +f 4505 4537 4435 +f 4435 4537 4463 +f 4435 4463 4303 +f 4303 4463 4295 +f 4303 4295 4218 +f 4218 4295 4174 +f 4218 4174 3975 +f 3975 4174 4075 +f 3975 4075 3939 +f 3939 4075 3938 +f 3939 3938 3707 +f 3707 3938 3731 +f 3707 3731 3631 +f 3631 3731 3595 +f 3631 3595 3450 +f 3450 3595 3469 +f 3450 3469 3350 +f 3350 3469 3355 +f 3350 3355 3235 +f 3235 3355 3227 +f 3235 3227 3126 +f 3126 3227 3107 +f 3126 3107 2976 +f 2976 3107 2968 +f 2976 2968 2847 +f 2847 2968 2823 +f 2847 2823 2703 +f 2703 2823 2669 +f 2703 2669 2599 +f 2599 2669 2573 +f 2599 2573 2408 +f 2408 2573 2407 +f 2408 2407 2258 +f 2258 2407 2257 +f 2258 2257 2201 +f 2201 2257 2091 +f 2201 2091 2069 +f 2069 2091 2061 +f 2069 2061 1917 +f 1917 2061 1890 +f 1917 1890 1717 +f 1717 1890 1713 +f 1717 1713 1575 +f 1575 1713 1590 +f 1575 1590 1522 +f 1522 1590 1521 +f 1522 1521 1325 +f 1325 1521 1383 +f 1325 1383 1264 +f 1264 1383 1194 +f 1264 1194 1136 +f 1136 1194 1114 +f 1136 1114 1051 +f 1051 1114 999 +f 1051 999 826 +f 826 999 845 +f 826 845 679 +f 679 845 781 +f 679 781 651 +f 651 781 632 +f 651 632 433 +f 433 632 482 +f 433 482 319 +f 319 482 365 +f 319 365 178 +f 178 365 269 +f 178 269 129 +f 129 269 78 +f 129 78 26 +f 7845 7813 7737 +f 7737 7813 7659 +f 7737 7659 7560 +f 7560 7659 7532 +f 7560 7532 7458 +f 7458 7532 7466 +f 7458 7466 7339 +f 7339 7466 7365 +f 7339 7365 7263 +f 7263 7365 7170 +f 7263 7170 7030 +f 7030 7170 7063 +f 7030 7063 6920 +f 6920 7063 6948 +f 6920 6948 6755 +f 6755 6948 6806 +f 6755 6806 6608 +f 6608 6806 6692 +f 6608 6692 6469 +f 6469 6692 6513 +f 6469 6513 6414 +f 6414 6513 6424 +f 6414 6424 6309 +f 6309 6424 6288 +f 6309 6288 6179 +f 6179 6288 6158 +f 6179 6158 6067 +f 6067 6158 6061 +f 6067 6061 5935 +f 5935 6061 5911 +f 5935 5911 5762 +f 5762 5911 5681 +f 5762 5681 5618 +f 5618 5681 5629 +f 5618 5629 5523 +f 5523 5629 5478 +f 5523 5478 5335 +f 5335 5478 5291 +f 5335 5291 5238 +f 5238 5291 5155 +f 5238 5155 5031 +f 5031 5155 5141 +f 5031 5141 4967 +f 4967 5141 4977 +f 4967 4977 4871 +f 4871 4977 4847 +f 4871 4847 4655 +f 4655 4847 4669 +f 4655 4669 4621 +f 4621 4669 4505 +f 4621 4505 4424 +f 4424 4505 4435 +f 4424 4435 4293 +f 4293 4435 4303 +f 4293 4303 4147 +f 4147 4303 4218 +f 4147 4218 3976 +f 3976 4218 3975 +f 3976 3975 3918 +f 3918 3975 3939 +f 3918 3939 3725 +f 3725 3939 3707 +f 3725 3707 3609 +f 3609 3707 3631 +f 3609 3631 3487 +f 3487 3631 3450 +f 3487 3450 3362 +f 3362 3450 3350 +f 3362 3350 3236 +f 3236 3350 3235 +f 3236 3235 3108 +f 3108 3235 3126 +f 3108 3126 2983 +f 2983 3126 2976 +f 2983 2976 2848 +f 2848 2976 2847 +f 2848 2847 2684 +f 2684 2847 2703 +f 2684 2703 2554 +f 2554 2703 2599 +f 2554 2599 2458 +f 2458 2599 2408 +f 2458 2408 2238 +f 2238 2408 2258 +f 2238 2258 2085 +f 2085 2258 2201 +f 2085 2201 2042 +f 2042 2201 2069 +f 2042 2069 1891 +f 1891 2069 1917 +f 1891 1917 1803 +f 1803 1917 1717 +f 1803 1717 1649 +f 1649 1717 1575 +f 1649 1575 1540 +f 1540 1575 1522 +f 1540 1522 1384 +f 1384 1522 1325 +f 1384 1325 1215 +f 1215 1325 1264 +f 1215 1264 1137 +f 1137 1264 1136 +f 1137 1136 939 +f 939 1136 1051 +f 939 1051 868 +f 868 1051 826 +f 868 826 717 +f 717 826 679 +f 717 679 652 +f 652 679 651 +f 652 651 529 +f 529 651 433 +f 529 433 415 +f 415 433 319 +f 415 319 231 +f 231 319 178 +f 231 178 79 +f 79 178 129 +f 79 129 26 +f 7803 7845 7695 +f 7695 7845 7737 +f 7695 7737 7546 +f 7546 7737 7560 +f 7546 7560 7485 +f 7485 7560 7458 +f 7485 7458 7306 +f 7306 7458 7339 +f 7306 7339 7243 +f 7243 7339 7263 +f 7243 7263 7009 +f 7009 7263 7030 +f 7009 7030 6855 +f 6855 7030 6920 +f 6855 6920 6727 +f 6727 6920 6755 +f 6727 6755 6641 +f 6641 6755 6608 +f 6641 6608 6569 +f 6569 6608 6469 +f 6569 6469 6425 +f 6425 6469 6414 +f 6425 6414 6209 +f 6209 6414 6309 +f 6209 6309 6146 +f 6146 6309 6179 +f 6146 6179 6019 +f 6019 6179 6067 +f 6019 6067 5853 +f 5853 6067 5935 +f 5853 5935 5781 +f 5781 5935 5762 +f 5781 5762 5677 +f 5677 5762 5618 +f 5677 5618 5479 +f 5479 5618 5523 +f 5479 5523 5359 +f 5359 5523 5335 +f 5359 5335 5249 +f 5249 5335 5238 +f 5249 5238 5044 +f 5044 5238 5031 +f 5044 5031 4953 +f 4953 5031 4967 +f 4953 4967 4837 +f 4837 4967 4871 +f 4837 4871 4723 +f 4723 4871 4655 +f 4723 4655 4615 +f 4615 4655 4621 +f 4615 4621 4365 +f 4365 4621 4424 +f 4365 4424 4296 +f 4296 4424 4293 +f 4296 4293 4117 +f 4117 4293 4147 +f 4117 4147 4022 +f 4022 4147 3976 +f 4022 3976 3933 +f 3933 3976 3918 +f 3933 3918 3708 +f 3708 3918 3725 +f 3708 3725 3623 +f 3623 3725 3609 +f 3623 3609 3534 +f 3534 3609 3487 +f 3534 3487 3343 +f 3343 3487 3362 +f 3343 3362 3221 +f 3221 3362 3236 +f 3221 3236 3109 +f 3109 3236 3108 +f 3109 3108 2962 +f 2962 3108 2983 +f 2962 2983 2839 +f 2839 2983 2848 +f 2839 2848 2685 +f 2685 2848 2684 +f 2685 2684 2600 +f 2600 2684 2554 +f 2600 2554 2409 +f 2409 2554 2458 +f 2409 2458 2288 +f 2288 2458 2238 +f 2288 2238 2129 +f 2129 2238 2085 +f 2129 2085 2075 +f 2075 2085 2042 +f 2075 2042 1931 +f 1931 2042 1891 +f 1931 1891 1804 +f 1804 1891 1803 +f 1804 1803 1591 +f 1591 1803 1649 +f 1591 1649 1557 +f 1557 1649 1540 +f 1557 1540 1385 +f 1385 1540 1384 +f 1385 1384 1237 +f 1237 1384 1215 +f 1237 1215 1115 +f 1115 1215 1137 +f 1115 1137 985 +f 985 1137 939 +f 985 939 827 +f 827 939 868 +f 827 868 735 +f 735 868 717 +f 735 717 669 +f 669 717 652 +f 669 652 530 +f 530 652 529 +f 530 529 320 +f 320 529 415 +f 320 415 207 +f 207 415 231 +f 207 231 69 +f 69 231 79 +f 69 79 33 +f 7859 7803 7669 +f 7669 7803 7695 +f 7669 7695 7579 +f 7579 7695 7546 +f 7579 7546 7427 +f 7427 7546 7485 +f 7427 7485 7353 +f 7353 7485 7306 +f 7353 7306 7186 +f 7186 7306 7243 +f 7186 7243 7054 +f 7054 7243 7009 +f 7054 7009 6890 +f 6890 7009 6855 +f 6890 6855 6807 +f 6807 6855 6727 +f 6807 6727 6684 +f 6684 6727 6641 +f 6684 6641 6587 +f 6587 6641 6569 +f 6587 6569 6351 +f 6351 6569 6425 +f 6351 6425 6276 +f 6276 6425 6209 +f 6276 6209 6180 +f 6180 6209 6146 +f 6180 6146 5993 +f 5993 6146 6019 +f 5993 6019 5890 +f 5890 6019 5853 +f 5890 5853 5690 +f 5690 5853 5781 +f 5690 5781 5608 +f 5608 5781 5677 +f 5608 5677 5486 +f 5486 5677 5479 +f 5486 5479 5411 +f 5411 5479 5359 +f 5411 5359 5214 +f 5214 5359 5249 +f 5214 5249 5097 +f 5097 5249 5044 +f 5097 5044 4985 +f 4985 5044 4953 +f 4985 4953 4883 +f 4883 4953 4837 +f 4883 4837 4731 +f 4731 4837 4723 +f 4731 4723 4529 +f 4529 4723 4615 +f 4529 4615 4410 +f 4410 4615 4365 +f 4410 4365 4350 +f 4350 4365 4296 +f 4350 4296 4175 +f 4175 4296 4117 +f 4175 4117 4031 +f 4031 4117 4022 +f 4031 4022 3912 +f 3912 4022 3933 +f 3912 3933 3773 +f 3773 3933 3708 +f 3773 3708 3675 +f 3675 3708 3623 +f 3675 3623 3521 +f 3521 3623 3534 +f 3521 3534 3363 +f 3363 3534 3343 +f 3363 3343 3229 +f 3229 3343 3221 +f 3229 3221 3101 +f 3101 3221 3109 +f 3101 3109 2973 +f 2973 3109 2962 +f 2973 2962 2833 +f 2833 2962 2839 +f 2833 2839 2692 +f 2692 2839 2685 +f 2692 2685 2595 +f 2595 2685 2600 +f 2595 2600 2389 +f 2389 2600 2409 +f 2389 2409 2259 +f 2259 2409 2288 +f 2259 2288 2158 +f 2158 2288 2129 +f 2158 2129 2076 +f 2076 2129 2075 +f 2076 2075 1892 +f 1892 2075 1931 +f 1892 1931 1733 +f 1733 1931 1804 +f 1733 1804 1626 +f 1626 1804 1591 +f 1626 1591 1493 +f 1493 1591 1557 +f 1493 1557 1386 +f 1386 1557 1385 +f 1386 1385 1216 +f 1216 1385 1237 +f 1216 1237 1159 +f 1159 1237 1115 +f 1159 1115 968 +f 968 1115 985 +f 968 985 895 +f 895 985 827 +f 895 827 736 +f 736 827 735 +f 736 735 583 +f 583 735 669 +f 583 669 434 +f 434 669 530 +f 434 530 321 +f 321 530 320 +f 321 320 208 +f 208 320 207 +f 208 207 130 +f 130 207 69 +f 130 69 9 +f 7669 7756 7859 +f 7859 7756 7760 +f 7859 7760 7876 +f 7579 7636 7669 +f 7669 7636 7639 +f 7669 7639 7756 +f 7357 7353 7193 +f 7193 7353 7186 +f 7193 7186 7067 +f 7067 7186 7054 +f 7067 7054 6921 +f 6921 7054 6890 +f 6921 6890 6763 +f 6763 6890 6807 +f 6763 6807 6628 +f 6628 6807 6684 +f 6628 6684 6553 +f 6553 6684 6587 +f 6553 6587 6395 +f 6395 6587 6351 +f 6395 6351 6310 +f 6310 6351 6276 +f 6310 6276 6141 +f 6141 6276 6180 +f 6141 6180 5987 +f 5987 6180 5993 +f 5987 5993 5825 +f 5825 5993 5890 +f 5825 5890 5782 +f 5782 5890 5690 +f 5782 5690 5597 +f 5597 5690 5608 +f 5597 5608 5537 +f 5537 5608 5486 +f 5537 5486 5317 +f 5317 5486 5411 +f 5317 5411 5255 +f 5255 5411 5214 +f 5255 5214 5102 +f 5102 5214 5097 +f 5102 5097 4913 +f 4913 5097 4985 +f 4913 4985 4806 +f 4806 4985 4883 +f 4806 4883 4627 +f 4627 4883 4731 +f 4627 4731 4587 +f 4587 4731 4529 +f 4587 4529 4436 +f 4436 4529 4410 +f 4436 4410 4337 +f 4337 4410 4350 +f 4337 4350 4155 +f 4155 4350 4175 +f 4155 4175 3999 +f 3999 4175 4031 +f 3999 4031 3873 +f 3873 4031 3912 +f 3873 3912 3717 +f 3717 3912 3773 +f 3717 3773 3641 +f 3641 3773 3675 +f 3641 3675 3551 +f 3551 3675 3521 +f 3551 3521 3340 +f 3340 3521 3363 +f 3340 3363 3241 +f 3241 3363 3229 +f 3241 3229 3102 +f 3102 3229 3101 +f 3102 3101 2984 +f 2984 3101 2973 +f 2984 2973 2834 +f 2834 2973 2833 +f 2834 2833 2675 +f 2675 2833 2692 +f 2675 2692 2547 +f 2547 2692 2595 +f 2547 2595 2443 +f 2443 2595 2389 +f 2443 2389 2260 +f 2260 2389 2259 +f 2260 2259 2130 +f 2130 2259 2158 +f 2130 2158 2062 +f 2062 2158 2076 +f 2062 2076 1846 +f 1846 2076 1892 +f 1846 1892 1708 +f 1708 1892 1733 +f 1708 1733 1604 +f 1604 1733 1626 +f 1604 1626 1558 +f 1558 1626 1493 +f 1558 1493 1404 +f 1404 1493 1386 +f 1404 1386 1208 +f 1208 1386 1216 +f 1208 1216 1138 +f 1138 1216 1159 +f 1138 1159 1000 +f 1000 1159 968 +f 1000 968 846 +f 846 968 895 +f 846 895 782 +f 782 895 736 +f 782 736 563 +f 563 736 583 +f 563 583 441 +f 441 583 434 +f 441 434 400 +f 400 434 321 +f 400 321 232 +f 232 321 208 +f 232 208 80 +f 80 208 130 +f 80 130 9 +f 7193 7268 7357 +f 7357 7268 7271 +f 7357 7271 7391 +f 7123 7067 6900 +f 6900 7067 6921 +f 6900 6921 6791 +f 6791 6921 6763 +f 6791 6763 6721 +f 6721 6763 6628 +f 6721 6628 6470 +f 6470 6628 6553 +f 6470 6553 6381 +f 6381 6553 6395 +f 6381 6395 6329 +f 6329 6395 6310 +f 6329 6310 6147 +f 6147 6310 6141 +f 6147 6141 5994 +f 5994 6141 5987 +f 5994 5987 5937 +f 5937 5987 5825 +f 5937 5825 5756 +f 5756 5825 5782 +f 5756 5782 5605 +f 5605 5782 5597 +f 5605 5597 5449 +f 5449 5597 5537 +f 5449 5537 5381 +f 5381 5537 5317 +f 5381 5317 5208 +f 5208 5317 5255 +f 5208 5255 5136 +f 5136 5255 5102 +f 5136 5102 4965 +f 4965 5102 4913 +f 4965 4913 4853 +f 4853 4913 4806 +f 4853 4806 4647 +f 4647 4806 4627 +f 4647 4627 4495 +f 4495 4627 4587 +f 4495 4587 4479 +f 4479 4587 4436 +f 4479 4436 4237 +f 4237 4436 4337 +f 4237 4337 4148 +f 4148 4337 4155 +f 4148 4155 3992 +f 3992 4155 3999 +f 3992 3999 3851 +f 3851 3999 3873 +f 3851 3873 3807 +f 3807 3873 3717 +f 3807 3717 3583 +f 3583 3717 3641 +f 3583 3641 3528 +f 3528 3641 3551 +f 3528 3551 3317 +f 3317 3551 3340 +f 3317 3340 3237 +f 3237 3340 3241 +f 3237 3241 3117 +f 3117 3241 3102 +f 3117 3102 2965 +f 2965 3102 2984 +f 2965 2984 2860 +f 2860 2984 2834 +f 2860 2834 2704 +f 2704 2834 2675 +f 2704 2675 2562 +f 2562 2675 2547 +f 2562 2547 2431 +f 2431 2547 2443 +f 2431 2443 2289 +f 2289 2443 2260 +f 2289 2260 2209 +f 2209 2260 2130 +f 2209 2130 2070 +f 2070 2130 2062 +f 2070 2062 1918 +f 1918 2062 1846 +f 1918 1846 1754 +f 1754 1846 1708 +f 1754 1708 1650 +f 1650 1708 1604 +f 1650 1604 1565 +f 1565 1604 1558 +f 1565 1558 1405 +f 1405 1558 1404 +f 1405 1404 1265 +f 1265 1404 1208 +f 1265 1208 1139 +f 1139 1208 1138 +f 1139 1138 969 +f 969 1138 1000 +f 969 1000 896 +f 896 1000 846 +f 896 846 737 +f 737 846 782 +f 737 782 633 +f 633 782 563 +f 633 563 504 +f 504 563 441 +f 504 441 341 +f 341 441 400 +f 341 400 214 +f 214 400 232 +f 214 232 151 +f 151 232 80 +f 151 80 12 +f 7029 7123 6895 +f 6895 7123 6900 +f 6895 6900 6772 +f 6772 6900 6791 +f 6772 6791 6599 +f 6599 6791 6721 +f 6599 6721 6549 +f 6549 6721 6470 +f 6549 6470 6426 +f 6426 6470 6381 +f 6426 6381 6238 +f 6238 6381 6329 +f 6238 6329 6102 +f 6102 6329 6147 +f 6102 6147 6001 +f 6001 6147 5994 +f 6001 5994 5871 +f 5871 5994 5937 +f 5871 5937 5727 +f 5727 5937 5756 +f 5727 5756 5675 +f 5675 5756 5605 +f 5675 5605 5454 +f 5454 5605 5449 +f 5454 5449 5399 +f 5399 5449 5381 +f 5399 5381 5209 +f 5209 5381 5208 +f 5209 5208 5147 +f 5147 5208 5136 +f 5147 5136 4954 +f 4954 5136 4965 +f 4954 4965 4786 +f 4786 4965 4853 +f 4786 4853 4719 +f 4719 4853 4647 +f 4719 4647 4497 +f 4497 4647 4495 +f 4497 4495 4403 +f 4403 4495 4479 +f 4403 4479 4279 +f 4279 4479 4237 +f 4279 4237 4165 +f 4165 4237 4148 +f 4165 4148 4057 +f 4057 4148 3992 +f 4057 3992 3843 +f 3843 3992 3851 +f 3843 3851 3712 +f 3712 3851 3807 +f 3712 3807 3629 +f 3629 3807 3583 +f 3629 3583 3458 +f 3458 3583 3528 +f 3458 3528 3344 +f 3344 3528 3317 +f 3344 3317 3274 +f 3274 3317 3237 +f 3274 3237 3118 +f 3118 3237 3117 +f 3118 3117 2969 +f 2969 3117 2965 +f 2969 2965 2849 +f 2849 2965 2860 +f 2849 2860 2705 +f 2705 2860 2704 +f 2705 2704 2555 +f 2555 2704 2562 +f 2555 2562 2444 +f 2444 2562 2431 +f 2444 2431 2247 +f 2247 2431 2289 +f 2247 2289 2159 +f 2159 2289 2209 +f 2159 2209 1997 +f 1997 2209 2070 +f 1997 2070 1919 +f 1919 2070 1918 +f 1919 1918 1718 +f 1718 1918 1754 +f 1718 1754 1673 +f 1673 1754 1650 +f 1673 1650 1494 +f 1494 1650 1565 +f 1494 1565 1429 +f 1429 1565 1405 +f 1429 1405 1286 +f 1286 1405 1265 +f 1286 1265 1116 +f 1116 1265 1139 +f 1116 1139 986 +f 986 1139 969 +f 986 969 911 +f 911 969 896 +f 911 896 791 +f 791 896 737 +f 791 737 662 +f 662 737 633 +f 662 633 442 +f 442 633 504 +f 442 504 401 +f 401 504 341 +f 401 341 270 +f 270 341 214 +f 270 214 43 +f 43 214 151 +f 43 151 12 +f 6953 6895 6832 +f 6832 6895 6772 +f 6832 6772 6659 +f 6659 6772 6599 +f 6659 6599 6583 +f 6583 6599 6549 +f 6583 6549 6355 +f 6355 6549 6426 +f 6355 6426 6327 +f 6327 6426 6238 +f 6327 6238 6097 +f 6097 6238 6102 +f 6097 6102 5977 +f 5977 6102 6001 +f 5977 6001 5861 +f 5861 6001 5871 +f 5861 5871 5797 +f 5797 5871 5727 +f 5797 5727 5603 +f 5603 5727 5675 +f 5603 5675 5455 +f 5455 5675 5454 +f 5455 5454 5310 +f 5310 5454 5399 +f 5310 5399 5239 +f 5239 5399 5209 +f 5239 5209 5103 +f 5103 5209 5147 +f 5103 5147 4927 +f 4927 5147 4954 +f 4927 4954 4841 +f 4841 4954 4786 +f 4841 4786 4675 +f 4675 4786 4719 +f 4675 4719 4588 +f 4588 4719 4497 +f 4588 4497 4415 +f 4415 4497 4403 +f 4415 4403 4261 +f 4261 4403 4279 +f 4261 4279 4163 +f 4163 4279 4165 +f 4163 4165 4051 +f 4051 4165 4057 +f 4051 4057 3852 +f 3852 4057 3843 +f 3852 3843 3735 +f 3735 3843 3712 +f 3735 3712 3659 +f 3659 3712 3629 +f 3659 3629 3501 +f 3501 3629 3458 +f 3501 3458 3407 +f 3407 3458 3344 +f 3407 3344 3249 +f 3249 3344 3274 +f 3249 3274 3163 +f 3163 3274 3118 +f 3163 3118 2951 +f 2951 3118 2969 +f 2951 2969 2867 +f 2867 2969 2849 +f 2867 2849 2676 +f 2676 2849 2705 +f 2676 2705 2541 +f 2541 2705 2555 +f 2541 2555 2465 +f 2465 2555 2444 +f 2465 2444 2306 +f 2306 2444 2247 +f 2306 2247 2170 +f 2170 2247 2159 +f 2170 2159 2071 +f 2071 2159 1997 +f 2071 1997 1953 +f 1953 1997 1919 +f 1953 1919 1813 +f 1813 1919 1718 +f 1813 1718 1651 +f 1651 1718 1673 +f 1651 1673 1451 +f 1451 1673 1494 +f 1451 1494 1430 +f 1430 1494 1429 +f 1430 1429 1238 +f 1238 1429 1286 +f 1238 1286 1117 +f 1117 1286 1116 +f 1117 1116 1001 +f 1001 1116 986 +f 1001 986 880 +f 880 986 911 +f 880 911 697 +f 697 911 791 +f 697 791 598 +f 598 791 662 +f 598 662 531 +f 531 662 442 +f 531 442 409 +f 409 442 401 +f 409 401 174 +f 174 401 270 +f 174 270 47 +f 47 270 43 +f 47 43 13 +f 6919 6953 6842 +f 6842 6953 6832 +f 6842 6832 6660 +f 6660 6832 6659 +f 6660 6659 6539 +f 6539 6659 6583 +f 6539 6583 6389 +f 6389 6583 6355 +f 6389 6355 6255 +f 6255 6355 6327 +f 6255 6327 6191 +f 6191 6327 6097 +f 6191 6097 6020 +f 6020 6097 5977 +f 6020 5977 5833 +f 5833 5977 5861 +f 5833 5861 5745 +f 5745 5861 5797 +f 5745 5797 5551 +f 5551 5797 5603 +f 5551 5603 5491 +f 5491 5603 5455 +f 5491 5455 5318 +f 5318 5455 5310 +f 5318 5310 5203 +f 5203 5310 5239 +f 5203 5239 5085 +f 5085 5239 5103 +f 5085 5103 4955 +f 4955 5103 4927 +f 4955 4927 4801 +f 4801 4927 4841 +f 4801 4841 4697 +f 4697 4841 4675 +f 4697 4675 4552 +f 4552 4675 4588 +f 4552 4588 4461 +f 4461 4588 4415 +f 4461 4415 4247 +f 4247 4415 4261 +f 4247 4261 4185 +f 4185 4261 4163 +f 4185 4163 3971 +f 3971 4163 4051 +f 3971 4051 3890 +f 3890 4051 3852 +f 3890 3852 3781 +f 3781 3852 3735 +f 3781 3735 3621 +f 3621 3735 3659 +f 3621 3659 3515 +f 3515 3659 3501 +f 3515 3501 3411 +f 3411 3501 3407 +f 3411 3407 3266 +f 3266 3407 3249 +f 3266 3249 3050 +f 3050 3249 3163 +f 3050 3163 2985 +f 2985 3163 2951 +f 2985 2951 2840 +f 2840 2951 2867 +f 2840 2867 2693 +f 2693 2867 2676 +f 2693 2676 2563 +f 2563 2676 2541 +f 2563 2541 2445 +f 2445 2541 2465 +f 2445 2465 2227 +f 2227 2465 2306 +f 2227 2306 2099 +f 2099 2306 2170 +f 2099 2170 2030 +f 2030 2170 2071 +f 2030 2071 1893 +f 1893 2071 1953 +f 1893 1953 1734 +f 1734 1953 1813 +f 1734 1813 1665 +f 1665 1813 1651 +f 1665 1651 1460 +f 1460 1651 1451 +f 1460 1451 1406 +f 1406 1451 1430 +f 1406 1430 1295 +f 1295 1430 1238 +f 1295 1238 1118 +f 1118 1238 1117 +f 1118 1117 1046 +f 1046 1117 1001 +f 1046 1001 828 +f 828 1001 880 +f 828 880 718 +f 718 880 697 +f 718 697 634 +f 634 697 598 +f 634 598 496 +f 496 598 531 +f 496 531 402 +f 402 531 409 +f 402 409 273 +f 273 409 174 +f 273 174 102 +f 102 174 47 +f 102 47 13 +f 7004 6897 7008 +f 7008 6897 7131 +f 7008 7131 7137 +f 6897 6919 6779 +f 6779 6919 6842 +f 6779 6842 6631 +f 6631 6842 6660 +f 6631 6660 6559 +f 6559 6660 6539 +f 6559 6539 6369 +f 6369 6539 6389 +f 6369 6389 6251 +f 6251 6389 6255 +f 6251 6255 6098 +f 6098 6255 6191 +f 6098 6191 5989 +f 5989 6191 6020 +f 5989 6020 5837 +f 5837 6020 5833 +f 5837 5833 5765 +f 5765 5833 5745 +f 5765 5745 5653 +f 5653 5745 5551 +f 5653 5551 5439 +f 5439 5551 5491 +f 5439 5491 5375 +f 5375 5491 5318 +f 5375 5318 5156 +f 5156 5318 5203 +f 5156 5203 5119 +f 5119 5203 5085 +f 5119 5085 4946 +f 4946 5085 4955 +f 4946 4955 4854 +f 4854 4955 4801 +f 4854 4801 4724 +f 4724 4801 4697 +f 4724 4697 4522 +f 4522 4697 4552 +f 4522 4552 4419 +f 4419 4552 4461 +f 4419 4461 4343 +f 4343 4461 4247 +f 4343 4247 4129 +f 4129 4247 4185 +f 4129 4185 3984 +f 3984 4185 3971 +f 3984 3971 3951 +f 3951 3971 3890 +f 3951 3890 3770 +f 3770 3890 3781 +f 3770 3781 3573 +f 3573 3781 3621 +f 3573 3621 3498 +f 3498 3621 3515 +f 3498 3515 3370 +f 3370 3515 3411 +f 3370 3411 3217 +f 3217 3411 3266 +f 3217 3266 3074 +f 3074 3266 3050 +f 3074 3050 2993 +f 2993 3050 2985 +f 2993 2985 2856 +f 2856 2985 2840 +f 2856 2840 2719 +f 2719 2840 2693 +f 2719 2693 2596 +f 2596 2693 2563 +f 2596 2563 2437 +f 2437 2563 2445 +f 2437 2445 2261 +f 2261 2445 2227 +f 2261 2227 2146 +f 2146 2227 2099 +f 2146 2099 2015 +f 2015 2099 2030 +f 2015 2030 1858 +f 1858 2030 1893 +f 1858 1893 1790 +f 1790 1893 1734 +f 1790 1734 1674 +f 1674 1734 1665 +f 1674 1665 1495 +f 1495 1665 1460 +f 1495 1460 1407 +f 1407 1460 1406 +f 1407 1406 1266 +f 1266 1406 1295 +f 1266 1295 1168 +f 1168 1295 1118 +f 1168 1118 978 +f 978 1118 1046 +f 978 1046 869 +f 869 1046 828 +f 869 828 772 +f 772 828 718 +f 772 718 564 +f 564 718 634 +f 564 634 516 +f 516 634 496 +f 516 496 381 +f 381 496 402 +f 381 402 215 +f 215 402 273 +f 215 273 82 +f 82 273 102 +f 82 102 28 +f 7089 7131 6945 +f 6945 7131 6897 +f 6945 6897 6753 +f 6753 6897 6779 +f 6753 6779 6636 +f 6636 6779 6631 +f 6636 6631 6475 +f 6475 6631 6559 +f 6475 6559 6335 +f 6335 6559 6369 +f 6335 6369 6275 +f 6275 6369 6251 +f 6275 6251 6193 +f 6193 6251 6098 +f 6193 6098 5945 +f 5945 6098 5989 +f 5945 5989 5889 +f 5889 5989 5837 +f 5889 5837 5741 +f 5741 5837 5765 +f 5741 5765 5617 +f 5617 5765 5653 +f 5617 5653 5505 +f 5505 5653 5439 +f 5505 5439 5397 +f 5397 5439 5375 +f 5397 5375 5257 +f 5257 5375 5156 +f 5257 5156 5101 +f 5101 5156 5119 +f 5101 5119 4920 +f 4920 5119 4946 +f 4920 4946 4817 +f 4817 4946 4854 +f 4817 4854 4683 +f 4683 4854 4724 +f 4683 4724 4551 +f 4551 4724 4522 +f 4551 4522 4481 +f 4481 4522 4419 +f 4481 4419 4313 +f 4313 4419 4343 +f 4313 4343 4191 +f 4191 4343 4129 +f 4191 4129 4043 +f 4043 4129 3984 +f 4043 3984 3903 +f 3903 3984 3951 +f 3903 3951 3755 +f 3755 3951 3770 +f 3755 3770 3633 +f 3633 3770 3573 +f 3633 3573 3457 +f 3457 3573 3498 +f 3457 3498 3361 +f 3361 3498 3370 +f 3361 3370 3255 +f 3255 3370 3217 +f 3255 3217 3137 +f 3137 3217 3074 +f 3137 3074 3015 +f 3015 3074 2993 +f 3015 2993 2864 +f 2864 2993 2856 +f 2864 2856 2683 +f 2683 2856 2719 +f 2683 2719 2559 +f 2559 2719 2596 +f 2559 2596 2397 +f 2397 2596 2437 +f 2397 2437 2305 +f 2305 2437 2261 +f 2305 2261 2109 +f 2109 2261 2146 +f 2109 2146 2039 +f 2039 2146 2015 +f 2039 2015 1955 +f 1955 2015 1858 +f 1955 1858 1789 +f 1789 1858 1790 +f 1789 1790 1683 +f 1683 1790 1674 +f 1683 1674 1517 +f 1517 1674 1495 +f 1517 1495 1381 +f 1381 1495 1407 +f 1381 1407 1309 +f 1309 1407 1266 +f 1309 1266 1171 +f 1171 1266 1168 +f 1171 1168 991 +f 991 1168 978 +f 991 978 817 +f 817 978 869 +f 817 869 762 +f 762 869 772 +f 762 772 572 +f 572 772 564 +f 572 564 465 +f 465 564 516 +f 465 516 399 +f 399 516 381 +f 399 381 197 +f 197 381 215 +f 197 215 103 +f 103 215 82 +f 103 82 28 +f 7269 7251 7273 +f 7273 7251 7385 +f 7273 7385 7393 +f 7757 7679 7762 +f 7762 7679 7807 +f 7762 7807 7877 +f 7679 7641 7575 +f 7575 7641 7638 +f 7575 7638 7521 +f 7870 7807 7753 +f 7753 7807 7679 +f 7753 7679 7564 +f 7564 7679 7575 +f 7564 7575 7449 +f 7449 7575 7515 +f 7449 7515 7299 +f 7299 7515 7311 +f 7299 7311 7197 +f 7197 7311 7155 +f 7197 7155 7055 +f 7055 7155 7041 +f 7055 7041 6891 +f 6891 7041 6879 +f 6891 6879 6780 +f 6780 6879 6841 +f 6780 6841 6701 +f 6701 6841 6715 +f 6701 6715 6487 +f 6487 6715 6493 +f 6487 6493 6393 +f 6393 6493 6359 +f 6393 6359 6271 +f 6271 6359 6303 +f 6271 6303 6121 +f 6121 6303 6178 +f 6121 6178 6031 +f 6031 6178 6040 +f 6031 6040 5885 +f 5885 6040 5921 +f 5885 5921 5735 +f 5735 5921 5705 +f 5735 5705 5639 +f 5639 5705 5649 +f 5639 5649 5459 +f 5459 5649 5489 +f 5459 5489 5391 +f 5391 5489 5289 +f 5391 5289 5253 +f 5253 5289 5219 +f 5253 5219 5081 +f 5081 5219 5053 +f 5081 5053 4969 +f 4969 5053 4907 +f 4969 4907 4822 +f 4822 4907 4797 +f 4822 4797 4663 +f 4663 4797 4727 +f 4663 4727 4549 +f 4549 4727 4565 +f 4549 4565 4477 +f 4477 4565 4385 +f 4477 4385 4353 +f 4353 4385 4289 +f 4353 4289 4125 +f 4125 4289 4192 +f 4125 4192 3985 +f 3985 4192 4083 +f 3985 4083 3906 +f 3906 4083 3917 +f 3906 3917 3777 +f 3777 3917 3805 +f 3777 3805 3673 +f 3673 3805 3599 +f 3673 3599 3553 +f 3553 3599 3477 +f 3553 3477 3337 +f 3337 3477 3417 +f 3337 3417 3247 +f 3247 3417 3277 +f 3247 3277 3071 +f 3071 3277 3063 +f 3071 3063 2938 +f 2938 3063 2949 +f 2938 2949 2845 +f 2845 2949 2813 +f 2845 2813 2647 +f 2647 2813 2641 +f 2647 2641 2583 +f 2583 2641 2567 +f 2583 2567 2399 +f 2399 2567 2406 +f 2399 2406 2248 +f 2248 2406 2299 +f 2248 2299 2138 +f 2138 2299 2195 +f 2138 2195 2016 +f 2016 2195 1957 +f 2016 1957 1875 +f 1875 1957 1873 +f 1875 1873 1774 +f 1774 1873 1799 +f 1774 1799 1605 +f 1605 1799 1579 +f 1605 1579 1487 +f 1487 1579 1463 +f 1487 1463 1433 +f 1433 1463 1441 +f 1433 1441 1203 +f 1203 1441 1305 +f 1203 1305 1160 +f 1160 1305 1172 +f 1160 1172 1011 +f 1011 1172 1037 +f 1011 1037 847 +f 847 1037 909 +f 847 909 681 +f 681 909 769 +f 681 769 558 +f 558 769 573 +f 558 573 462 +f 462 573 440 +f 462 440 366 +f 366 440 363 +f 366 363 274 +f 274 363 242 +f 274 242 128 +f 128 242 155 +f 128 155 32 +f 7765 7870 7672 +f 7672 7870 7753 +f 7672 7753 7601 +f 7601 7753 7564 +f 7601 7564 7409 +f 7409 7564 7449 +f 7409 7449 7343 +f 7343 7449 7299 +f 7343 7299 7201 +f 7201 7299 7197 +f 7201 7197 7065 +f 7065 7197 7055 +f 7065 7055 6943 +f 6943 7055 6891 +f 6943 6891 6839 +f 6839 6891 6780 +f 6839 6780 6615 +f 6615 6780 6701 +f 6615 6701 6541 +f 6541 6701 6487 +f 6541 6487 6437 +f 6437 6487 6393 +f 6437 6393 6269 +f 6269 6393 6271 +f 6269 6271 6113 +f 6113 6271 6121 +f 6113 6121 6013 +f 6013 6121 6031 +f 6013 6031 5880 +f 5880 6031 5885 +f 5880 5885 5773 +f 5773 5885 5735 +f 5773 5735 5644 +f 5644 5735 5639 +f 5644 5639 5539 +f 5539 5639 5459 +f 5539 5459 5292 +f 5292 5459 5391 +f 5292 5391 5220 +f 5220 5391 5253 +f 5220 5253 5071 +f 5071 5253 5081 +f 5071 5081 5002 +f 5002 5081 4969 +f 5002 4969 4825 +f 4825 4969 4822 +f 4825 4822 4717 +f 4717 4822 4663 +f 4717 4663 4585 +f 4585 4663 4549 +f 4585 4549 4397 +f 4397 4549 4477 +f 4397 4477 4263 +f 4263 4477 4353 +f 4263 4353 4168 +f 4168 4353 4125 +f 4168 4125 3979 +f 3979 4125 3985 +f 3979 3985 3901 +f 3901 3985 3906 +f 3901 3906 3821 +f 3821 3906 3777 +f 3821 3777 3615 +f 3615 3777 3673 +f 3615 3673 3481 +f 3481 3673 3553 +f 3481 3553 3412 +f 3412 3553 3337 +f 3412 3337 3171 +f 3171 3337 3247 +f 3171 3247 3053 +f 3053 3247 3071 +f 3053 3071 3001 +f 3001 3071 2938 +f 3001 2938 2809 +f 2809 2938 2845 +f 2809 2845 2643 +f 2643 2845 2647 +f 2643 2647 2589 +f 2589 2647 2583 +f 2589 2583 2419 +f 2419 2583 2399 +f 2419 2399 2284 +f 2284 2399 2248 +f 2284 2248 2177 +f 2177 2248 2138 +f 2177 2138 2083 +f 2083 2138 2016 +f 2083 2016 1932 +f 1932 2016 1875 +f 1932 1875 1714 +f 1714 1875 1774 +f 1714 1774 1652 +f 1652 1774 1605 +f 1652 1605 1447 +f 1447 1605 1487 +f 1447 1487 1352 +f 1352 1487 1433 +f 1352 1433 1277 +f 1277 1433 1203 +f 1277 1203 1119 +f 1119 1203 1160 +f 1119 1160 979 +f 979 1160 1011 +f 979 1011 857 +f 857 1011 847 +f 857 847 738 +f 738 847 681 +f 738 681 607 +f 607 681 558 +f 607 558 505 +f 505 558 462 +f 505 462 305 +f 305 462 366 +f 305 366 198 +f 198 366 274 +f 198 274 64 +f 64 274 128 +f 64 128 19 +f 7817 7765 7675 +f 7675 7765 7672 +f 7675 7672 7542 +f 7542 7672 7601 +f 7542 7601 7479 +f 7479 7601 7409 +f 7479 7409 7381 +f 7381 7409 7343 +f 7381 7343 7209 +f 7209 7343 7201 +f 7209 7201 7035 +f 7035 7201 7065 +f 7035 7065 6941 +f 6941 7065 6943 +f 6941 6943 6836 +f 6836 6943 6839 +f 6836 6839 6645 +f 6645 6839 6615 +f 6645 6615 6488 +f 6488 6615 6541 +f 6488 6541 6401 +f 6401 6541 6437 +f 6401 6437 6215 +f 6215 6437 6269 +f 6215 6269 6091 +f 6091 6269 6113 +f 6091 6113 6045 +f 6045 6113 6013 +f 6045 6013 5901 +f 5901 6013 5880 +f 5901 5880 5698 +f 5698 5880 5773 +f 5698 5773 5571 +f 5571 5773 5644 +f 5571 5644 5471 +f 5471 5644 5539 +f 5471 5539 5365 +f 5365 5539 5292 +f 5365 5292 5175 +f 5175 5292 5220 +f 5175 5220 5107 +f 5107 5220 5071 +f 5107 5071 4961 +f 4961 5071 5002 +f 4961 5002 4874 +f 4874 5002 4825 +f 4874 4825 4747 +f 4747 4825 4717 +f 4747 4717 4507 +f 4507 4717 4585 +f 4507 4585 4416 +f 4416 4585 4397 +f 4416 4397 4307 +f 4307 4397 4263 +f 4307 4263 4159 +f 4159 4263 4168 +f 4159 4168 4017 +f 4017 4168 3979 +f 4017 3979 3948 +f 3948 3979 3901 +f 3948 3901 3796 +f 3796 3901 3821 +f 3796 3821 3644 +f 3644 3821 3615 +f 3644 3615 3547 +f 3547 3615 3481 +f 3547 3481 3305 +f 3305 3481 3412 +f 3305 3412 3193 +f 3193 3412 3171 +f 3193 3171 3061 +f 3061 3171 3053 +f 3061 3053 2997 +f 2997 3053 3001 +f 2997 3001 2871 +f 2871 3001 2809 +f 2871 2809 2655 +f 2655 2809 2643 +f 2655 2643 2605 +f 2605 2643 2589 +f 2605 2589 2427 +f 2427 2589 2419 +f 2427 2419 2243 +f 2243 2419 2284 +f 2243 2284 2151 +f 2151 2284 2177 +f 2151 2177 2036 +f 2036 2177 2083 +f 2036 2083 1945 +f 1945 2083 1932 +f 1945 1932 1805 +f 1805 1932 1714 +f 1805 1714 1606 +f 1606 1714 1652 +f 1606 1652 1509 +f 1509 1652 1447 +f 1509 1447 1387 +f 1387 1447 1352 +f 1387 1352 1259 +f 1259 1352 1277 +f 1259 1277 1105 +f 1105 1277 1119 +f 1105 1119 1002 +f 1002 1119 979 +f 1002 979 919 +f 919 979 857 +f 919 857 783 +f 783 857 738 +f 783 738 551 +f 551 738 607 +f 551 607 474 +f 474 607 505 +f 474 505 419 +f 419 505 305 +f 419 305 253 +f 253 305 198 +f 253 198 44 +f 44 198 64 +f 44 64 19 +f 7867 7817 7682 +f 7682 7817 7675 +f 7682 7675 7631 +f 7631 7675 7542 +f 7631 7542 7432 +f 7432 7542 7479 +f 7432 7479 7275 +f 7275 7479 7381 +f 7275 7381 7213 +f 7213 7381 7209 +f 7213 7209 7047 +f 7047 7209 7035 +f 7047 7035 6914 +f 6914 7035 6941 +f 6914 6941 6797 +f 6797 6941 6836 +f 6797 6836 6703 +f 6703 6836 6645 +f 6703 6645 6550 +f 6550 6645 6488 +f 6550 6488 6396 +f 6396 6488 6401 +f 6396 6401 6281 +f 6281 6401 6215 +f 6281 6215 6095 +f 6095 6215 6091 +f 6095 6091 6037 +f 6037 6091 6045 +f 6037 6045 5877 +f 5877 6045 5901 +f 5877 5901 5695 +f 5695 5901 5698 +f 5695 5698 5611 +f 5611 5698 5571 +f 5611 5571 5544 +f 5544 5571 5471 +f 5544 5471 5341 +f 5341 5471 5365 +f 5341 5365 5273 +f 5273 5365 5175 +f 5273 5175 5078 +f 5078 5175 5107 +f 5078 5107 4911 +f 4911 5107 4961 +f 4911 4961 4779 +f 4779 4961 4874 +f 4779 4874 4694 +f 4694 4874 4747 +f 4694 4747 4517 +f 4517 4747 4507 +f 4517 4507 4445 +f 4445 4507 4416 +f 4445 4416 4355 +f 4355 4416 4307 +f 4355 4307 4225 +f 4225 4307 4159 +f 4225 4159 4073 +f 4073 4159 4017 +f 4073 4017 3929 +f 3929 4017 3948 +f 3929 3948 3745 +f 3745 3948 3796 +f 3745 3796 3624 +f 3624 3796 3644 +f 3624 3644 3560 +f 3560 3644 3547 +f 3560 3547 3323 +f 3323 3547 3305 +f 3323 3305 3176 +f 3176 3305 3193 +f 3176 3193 3079 +f 3079 3193 3061 +f 3079 3061 2945 +f 2945 3061 2997 +f 2945 2997 2787 +f 2787 2997 2871 +f 2787 2871 2720 +f 2720 2871 2655 +f 2720 2655 2513 +f 2513 2655 2605 +f 2513 2605 2410 +f 2410 2605 2427 +f 2410 2427 2280 +f 2280 2427 2243 +f 2280 2243 2103 +f 2103 2243 2151 +f 2103 2151 2065 +f 2065 2151 2036 +f 2065 2036 1853 +f 1853 2036 1945 +f 1853 1945 1817 +f 1817 1945 1805 +f 1817 1805 1663 +f 1663 1805 1606 +f 1663 1606 1551 +f 1551 1606 1509 +f 1551 1509 1363 +f 1363 1509 1387 +f 1363 1387 1211 +f 1211 1387 1259 +f 1211 1259 1146 +f 1146 1259 1105 +f 1146 1105 933 +f 933 1105 1002 +f 933 1002 897 +f 897 1002 919 +f 897 919 767 +f 767 919 783 +f 767 783 653 +f 653 783 551 +f 653 551 443 +f 443 551 474 +f 443 474 382 +f 382 474 419 +f 382 419 193 +f 193 419 253 +f 193 253 54 +f 54 253 44 +f 54 44 15 +f 7767 7867 7717 +f 7717 7867 7682 +f 7717 7682 7573 +f 7573 7682 7631 +f 7573 7631 7425 +f 7425 7631 7432 +f 7425 7432 7279 +f 7279 7432 7275 +f 7279 7275 7217 +f 7217 7275 7213 +f 7217 7213 7059 +f 7059 7213 7047 +f 7059 7047 6967 +f 6967 7047 6914 +f 6967 6914 6826 +f 6826 6914 6797 +f 6826 6797 6705 +f 6705 6797 6703 +f 6705 6703 6473 +f 6473 6703 6550 +f 6473 6550 6382 +f 6382 6550 6396 +f 6382 6396 6234 +f 6234 6396 6281 +f 6234 6281 6151 +f 6151 6281 6095 +f 6151 6095 6051 +f 6051 6095 6037 +f 6051 6037 5862 +f 5862 6037 5877 +f 5862 5877 5739 +f 5739 5877 5695 +f 5739 5695 5665 +f 5665 5695 5611 +f 5665 5611 5493 +f 5493 5611 5544 +f 5493 5544 5367 +f 5367 5544 5341 +f 5367 5341 5161 +f 5161 5341 5273 +f 5161 5273 5073 +f 5073 5273 5078 +f 5073 5078 4901 +f 4901 5078 4911 +f 4901 4911 4763 +f 4763 4911 4779 +f 4763 4779 4665 +f 4665 4779 4694 +f 4665 4694 4511 +f 4511 4694 4517 +f 4511 4517 4395 +f 4395 4517 4445 +f 4395 4445 4269 +f 4269 4445 4355 +f 4269 4355 4189 +f 4189 4355 4225 +f 4189 4225 4045 +f 4045 4225 4073 +f 4045 4073 3869 +f 3869 4073 3929 +f 3869 3929 3722 +f 3722 3929 3745 +f 3722 3745 3651 +f 3651 3745 3624 +f 3651 3624 3540 +f 3540 3624 3560 +f 3540 3560 3387 +f 3387 3560 3323 +f 3387 3323 3243 +f 3243 3323 3176 +f 3243 3176 3159 +f 3159 3176 3079 +f 3159 3079 3009 +f 3009 3079 2945 +f 3009 2945 2829 +f 2829 2945 2787 +f 2829 2787 2741 +f 2741 2787 2720 +f 2741 2720 2533 +f 2533 2720 2513 +f 2533 2513 2403 +f 2403 2513 2410 +f 2403 2410 2225 +f 2225 2410 2280 +f 2225 2280 2097 +f 2097 2280 2103 +f 2097 2103 2055 +f 2055 2103 2065 +f 2055 2065 1927 +f 1927 2065 1853 +f 1927 1853 1827 +f 1827 1853 1817 +f 1827 1817 1617 +f 1617 1817 1663 +f 1617 1663 1452 +f 1452 1663 1551 +f 1452 1551 1408 +f 1408 1551 1363 +f 1408 1363 1222 +f 1222 1363 1211 +f 1222 1211 1106 +f 1106 1211 1146 +f 1106 1146 960 +f 960 1146 933 +f 960 933 923 +f 923 933 897 +f 923 897 792 +f 792 897 767 +f 792 767 618 +f 618 767 653 +f 618 653 455 +f 455 653 443 +f 455 443 325 +f 325 443 382 +f 325 382 285 +f 285 382 193 +f 285 193 114 +f 114 193 54 +f 114 54 15 +f 7843 7767 7699 +f 7699 7767 7717 +f 7699 7717 7621 +f 7621 7717 7573 +f 7621 7573 7455 +f 7455 7573 7425 +f 7455 7425 7297 +f 7297 7425 7279 +f 7297 7279 7204 +f 7204 7279 7217 +f 7204 7217 7107 +f 7107 7217 7059 +f 7107 7059 6934 +f 6934 7059 6967 +f 6934 6967 6845 +f 6845 6967 6826 +f 6845 6826 6697 +f 6697 6826 6705 +f 6697 6705 6554 +f 6554 6705 6473 +f 6554 6473 6377 +f 6377 6473 6382 +f 6377 6382 6229 +f 6229 6382 6234 +f 6229 6234 6077 +f 6077 6234 6151 +f 6077 6151 5961 +f 5961 6151 6051 +f 5961 6051 5919 +f 5919 6051 5862 +f 5919 5862 5801 +f 5801 5862 5739 +f 5801 5739 5569 +f 5569 5739 5665 +f 5569 5665 5533 +f 5533 5665 5493 +f 5533 5493 5342 +f 5342 5493 5367 +f 5342 5367 5275 +f 5275 5367 5161 +f 5275 5161 5127 +f 5127 5161 5073 +f 5127 5073 4905 +f 4905 5073 4901 +f 4905 4901 4767 +f 4767 4901 4763 +f 4767 4763 4729 +f 4729 4763 4665 +f 4729 4665 4541 +f 4541 4665 4511 +f 4541 4511 4483 +f 4483 4511 4395 +f 4483 4395 4339 +f 4339 4395 4269 +f 4339 4269 4171 +f 4171 4269 4189 +f 4171 4189 4013 +f 4013 4189 4045 +f 4013 4045 3864 +f 3864 4045 3869 +f 3864 3869 3813 +f 3813 3869 3722 +f 3813 3722 3639 +f 3639 3722 3651 +f 3639 3651 3507 +f 3507 3651 3540 +f 3507 3540 3425 +f 3425 3540 3387 +f 3425 3387 3256 +f 3256 3387 3243 +f 3256 3243 3085 +f 3085 3243 3159 +f 3085 3159 2925 +f 2925 3159 3009 +f 2925 3009 2872 +f 2872 3009 2829 +f 2872 2829 2689 +f 2689 2829 2741 +f 2689 2741 2519 +f 2519 2741 2533 +f 2519 2533 2455 +f 2455 2533 2403 +f 2455 2403 2274 +f 2274 2403 2225 +f 2274 2225 2101 +f 2101 2225 2097 +f 2101 2097 2008 +f 2008 2097 2055 +f 2008 2055 1951 +f 1951 2055 1927 +f 1951 1927 1784 +f 1784 1927 1827 +f 1784 1827 1612 +f 1612 1827 1617 +f 1612 1617 1464 +f 1464 1617 1452 +f 1464 1452 1344 +f 1344 1452 1408 +f 1344 1408 1313 +f 1313 1408 1222 +f 1313 1222 1174 +f 1174 1222 1106 +f 1174 1106 1015 +f 1015 1106 960 +f 1015 960 925 +f 925 960 923 +f 925 923 689 +f 689 923 792 +f 689 792 673 +f 673 792 618 +f 673 618 475 +f 475 618 455 +f 475 455 326 +f 326 455 325 +f 326 325 186 +f 186 325 285 +f 186 285 83 +f 83 285 114 +f 83 114 3 +f 7833 7843 7723 +f 7723 7843 7699 +f 7723 7699 7527 +f 7527 7699 7621 +f 7527 7621 7493 +f 7493 7621 7455 +f 7493 7455 7283 +f 7283 7455 7297 +f 7283 7297 7241 +f 7241 7297 7204 +f 7241 7204 7033 +f 7033 7204 7107 +f 7033 7107 6977 +f 6977 7107 6934 +f 6977 6934 6851 +f 6851 6934 6845 +f 6851 6845 6671 +f 6671 6845 6697 +f 6671 6697 6507 +f 6507 6697 6554 +f 6507 6554 6405 +f 6405 6554 6377 +f 6405 6377 6300 +f 6300 6377 6229 +f 6300 6229 6109 +f 6109 6229 6077 +f 6109 6077 5997 +f 5997 6077 5961 +f 5997 5961 5897 +f 5897 5961 5919 +f 5897 5919 5771 +f 5771 5919 5801 +f 5771 5801 5633 +f 5633 5801 5569 +f 5633 5569 5436 +f 5436 5569 5533 +f 5436 5533 5385 +f 5385 5533 5342 +f 5385 5342 5251 +f 5251 5342 5275 +f 5251 5275 5049 +f 5049 5275 5127 +f 5049 5127 4989 +f 4989 5127 4905 +f 4989 4905 4813 +f 4813 4905 4767 +f 4813 4767 4711 +f 4711 4767 4729 +f 4711 4729 4559 +f 4559 4729 4541 +f 4559 4541 4443 +f 4443 4541 4483 +f 4443 4483 4233 +f 4233 4483 4339 +f 4233 4339 4181 +f 4181 4339 4171 +f 4181 4171 4048 +f 4048 4171 4013 +f 4048 4013 3858 +f 3858 4013 3864 +f 3858 3864 3705 +f 3705 3864 3813 +f 3705 3813 3669 +f 3669 3813 3639 +f 3669 3639 3461 +f 3461 3639 3507 +f 3461 3507 3313 +f 3313 3507 3425 +f 3313 3425 3202 +f 3202 3425 3256 +f 3202 3256 3095 +f 3095 3256 3085 +f 3095 3085 2911 +f 2911 3085 2925 +f 2911 2925 2853 +f 2853 2925 2872 +f 2853 2872 2761 +f 2761 2872 2689 +f 2761 2689 2617 +f 2617 2689 2519 +f 2617 2519 2475 +f 2475 2519 2455 +f 2475 2455 2241 +f 2241 2455 2274 +f 2241 2274 2121 +f 2121 2274 2101 +f 2121 2101 2005 +f 2005 2101 2008 +f 2005 2008 1885 +f 1885 2008 1951 +f 1885 1951 1820 +f 1820 1951 1784 +f 1820 1784 1671 +f 1671 1784 1612 +f 1671 1612 1471 +f 1471 1612 1464 +f 1471 1464 1388 +f 1388 1464 1344 +f 1388 1344 1256 +f 1256 1344 1313 +f 1256 1313 1147 +f 1147 1313 1174 +f 1147 1174 943 +f 943 1174 1015 +f 943 1015 876 +f 876 1015 925 +f 876 925 692 +f 692 925 689 +f 692 689 619 +f 619 689 673 +f 619 673 517 +f 517 673 475 +f 517 475 352 +f 352 475 326 +f 352 326 221 +f 221 326 186 +f 221 186 57 +f 57 186 83 +f 57 83 3 +f 7775 7833 7739 +f 7739 7833 7723 +f 7739 7723 7557 +f 7557 7723 7527 +f 7557 7527 7462 +f 7462 7527 7493 +f 7462 7493 7383 +f 7383 7493 7283 +f 7383 7283 7247 +f 7247 7283 7241 +f 7247 7241 7077 +f 7077 7241 7033 +f 7077 7033 6957 +f 6957 7033 6977 +f 6957 6977 6735 +f 6735 6977 6851 +f 6735 6851 6602 +f 6602 6851 6671 +f 6602 6671 6535 +f 6535 6671 6507 +f 6535 6507 6341 +f 6341 6507 6405 +f 6341 6405 6325 +f 6325 6405 6300 +f 6325 6300 6159 +f 6159 6300 6109 +f 6159 6109 6069 +f 6069 6109 5997 +f 6069 5997 5857 +f 5857 5997 5897 +f 5857 5897 5721 +f 5721 5897 5771 +f 5721 5771 5577 +f 5577 5771 5633 +f 5577 5633 5531 +f 5531 5633 5436 +f 5531 5436 5382 +f 5382 5436 5385 +f 5382 5385 5267 +f 5267 5385 5251 +f 5267 5251 5131 +f 5131 5251 5049 +f 5131 5049 4973 +f 4973 5049 4989 +f 4973 4989 4809 +f 4809 4989 4813 +f 4809 4813 4737 +f 4737 4813 4711 +f 4737 4711 4557 +f 4557 4711 4559 +f 4557 4559 4459 +f 4459 4559 4443 +f 4459 4443 4271 +f 4271 4443 4233 +f 4271 4233 4118 +f 4118 4233 4181 +f 4118 4181 4007 +f 4007 4181 4048 +f 4007 4048 3921 +f 3921 4048 3858 +f 3921 3858 3803 +f 3803 3858 3705 +f 3803 3705 3661 +f 3661 3705 3669 +f 3661 3669 3455 +f 3455 3669 3461 +f 3455 3461 3335 +f 3335 3461 3313 +f 3335 3313 3181 +f 3181 3313 3202 +f 3181 3202 3135 +f 3135 3202 3095 +f 3135 3095 2952 +f 2952 3095 2911 +f 2952 2911 2780 +f 2780 2911 2853 +f 2780 2853 2635 +f 2635 2853 2761 +f 2635 2761 2527 +f 2527 2761 2617 +f 2527 2617 2367 +f 2367 2617 2475 +f 2367 2475 2229 +f 2229 2475 2241 +f 2229 2241 2147 +f 2147 2241 2121 +f 2147 2121 2003 +f 2003 2121 2005 +f 2003 2005 1865 +f 1865 2005 1885 +f 1865 1885 1765 +f 1765 1885 1820 +f 1765 1820 1583 +f 1583 1820 1671 +f 1583 1671 1483 +f 1483 1671 1471 +f 1483 1471 1333 +f 1333 1471 1388 +f 1333 1388 1299 +f 1299 1388 1256 +f 1299 1256 1067 +f 1067 1256 1147 +f 1067 1147 1016 +f 1016 1147 943 +f 1016 943 885 +f 885 943 876 +f 885 876 731 +f 731 876 692 +f 731 692 657 +f 657 692 619 +f 657 619 513 +f 513 619 517 +f 513 517 342 +f 342 517 352 +f 342 352 203 +f 203 352 221 +f 203 221 73 +f 73 221 57 +f 73 57 35 +f 7809 7775 7725 +f 7725 7775 7739 +f 7725 7739 7583 +f 7583 7739 7557 +f 7583 7557 7491 +f 7491 7557 7462 +f 7491 7462 7345 +f 7345 7462 7383 +f 7345 7383 7159 +f 7159 7383 7247 +f 7159 7247 7105 +f 7105 7247 7077 +f 7105 7077 6973 +f 6973 7077 6957 +f 6973 6957 6785 +f 6785 6957 6735 +f 6785 6735 6605 +f 6605 6735 6602 +f 6605 6602 6499 +f 6499 6602 6535 +f 6499 6535 6353 +f 6353 6535 6341 +f 6353 6341 6285 +f 6285 6341 6325 +f 6285 6325 6153 +f 6153 6325 6159 +f 6153 6159 6005 +f 6005 6159 6069 +f 6005 6069 5886 +f 5886 6069 5857 +f 5886 5857 5722 +f 5722 5857 5721 +f 5722 5721 5673 +f 5673 5721 5577 +f 5673 5577 5519 +f 5519 5577 5531 +f 5519 5531 5305 +f 5305 5531 5382 +f 5305 5382 5165 +f 5165 5382 5267 +f 5165 5267 5075 +f 5075 5267 5131 +f 5075 5131 4903 +f 4903 5131 4973 +f 4903 4973 4783 +f 4783 4973 4809 +f 4783 4809 4709 +f 4709 4809 4737 +f 4709 4737 4613 +f 4613 4737 4557 +f 4613 4557 4472 +f 4472 4557 4459 +f 4472 4459 4331 +f 4331 4459 4271 +f 4331 4271 4160 +f 4160 4271 4118 +f 4160 4118 4089 +f 4089 4118 4007 +f 4089 4007 3925 +f 3925 4007 3921 +f 3925 3921 3829 +f 3829 3921 3803 +f 3829 3803 3681 +f 3681 3803 3661 +f 3681 3661 3545 +f 3545 3661 3455 +f 3545 3455 3377 +f 3377 3455 3335 +f 3377 3335 3173 +f 3173 3335 3181 +f 3173 3181 3081 +f 3081 3181 3135 +f 3081 3135 2955 +f 2955 3135 2952 +f 2955 2952 2791 +f 2791 2952 2780 +f 2791 2780 2671 +f 2671 2780 2635 +f 2671 2635 2537 +f 2537 2635 2527 +f 2537 2527 2481 +f 2481 2527 2367 +f 2481 2367 2277 +f 2277 2367 2229 +f 2277 2229 2199 +f 2199 2229 2147 +f 2199 2147 1981 +f 1981 2147 2003 +f 1981 2003 1899 +f 1899 2003 1865 +f 1899 1865 1725 +f 1725 1865 1765 +f 1725 1765 1641 +f 1641 1765 1583 +f 1641 1583 1480 +f 1480 1583 1483 +f 1480 1483 1417 +f 1417 1483 1333 +f 1417 1333 1245 +f 1245 1333 1299 +f 1245 1299 1133 +f 1133 1299 1067 +f 1133 1067 975 +f 975 1067 1016 +f 975 1016 890 +f 890 1016 885 +f 890 885 708 +f 708 885 731 +f 708 731 671 +f 671 731 657 +f 671 657 476 +f 476 657 513 +f 476 513 393 +f 393 513 342 +f 393 342 247 +f 247 342 203 +f 247 203 91 +f 91 203 73 +f 91 73 36 +f 7773 7809 7663 +f 7663 7809 7725 +f 7663 7725 7571 +f 7571 7725 7583 +f 7571 7583 7513 +f 7513 7583 7491 +f 7513 7491 7331 +f 7331 7491 7345 +f 7331 7345 7207 +f 7207 7345 7159 +f 7207 7159 7079 +f 7079 7159 7105 +f 7079 7105 6885 +f 6885 7105 6973 +f 6885 6973 6789 +f 6789 6973 6785 +f 6789 6785 6611 +f 6611 6785 6605 +f 6611 6605 6567 +f 6567 6605 6499 +f 6567 6499 6450 +f 6450 6499 6353 +f 6450 6353 6267 +f 6267 6353 6285 +f 6267 6285 6163 +f 6163 6285 6153 +f 6163 6153 5955 +f 5955 6153 6005 +f 5955 6005 5899 +f 5899 6005 5886 +f 5899 5886 5707 +f 5707 5886 5722 +f 5707 5722 5575 +f 5575 5722 5673 +f 5575 5673 5447 +f 5447 5673 5519 +f 5447 5519 5401 +f 5401 5519 5305 +f 5401 5305 5263 +f 5263 5305 5165 +f 5263 5165 5129 +f 5129 5165 5075 +f 5129 5075 4933 +f 4933 5075 4903 +f 4933 4903 4835 +f 4835 4903 4783 +f 4835 4783 4741 +f 4741 4783 4709 +f 4741 4709 4573 +f 4573 4709 4613 +f 4573 4613 4475 +f 4475 4613 4472 +f 4475 4472 4345 +f 4345 4472 4331 +f 4345 4331 4143 +f 4143 4331 4160 +f 4143 4160 4033 +f 4033 4160 4089 +f 4033 4089 3877 +f 3877 4089 3925 +f 3877 3925 3729 +f 3729 3925 3829 +f 3729 3829 3679 +f 3679 3829 3681 +f 3679 3681 3557 +f 3557 3681 3545 +f 3557 3545 3427 +f 3427 3545 3377 +f 3427 3377 3270 +f 3270 3377 3173 +f 3270 3173 3047 +f 3047 3173 3081 +f 3047 3081 2935 +f 2935 3081 2955 +f 2935 2955 2889 +f 2889 2955 2791 +f 2889 2791 2739 +f 2739 2791 2671 +f 2739 2671 2621 +f 2621 2671 2537 +f 2621 2537 2393 +f 2393 2537 2481 +f 2393 2481 2310 +f 2310 2481 2277 +f 2310 2277 2095 +f 2095 2277 2199 +f 2095 2199 2051 +f 2051 2199 1981 +f 2051 1981 1851 +f 1851 1981 1899 +f 1851 1899 1721 +f 1721 1899 1725 +f 1721 1725 1621 +f 1621 1725 1641 +f 1621 1641 1472 +f 1472 1641 1480 +f 1472 1480 1323 +f 1323 1480 1417 +f 1323 1417 1301 +f 1301 1417 1245 +f 1301 1245 1157 +f 1157 1245 1133 +f 1157 1133 965 +f 965 1133 975 +f 965 975 839 +f 839 975 890 +f 839 890 787 +f 787 890 708 +f 787 708 649 +f 649 708 671 +f 649 671 459 +f 459 671 476 +f 459 476 397 +f 397 476 393 +f 397 393 263 +f 263 393 247 +f 263 247 135 +f 135 247 91 +f 135 91 36 +f 7769 7773 7649 +f 7649 7773 7663 +f 7649 7663 7535 +f 7535 7663 7571 +f 7535 7571 7407 +f 7407 7571 7513 +f 7407 7513 7355 +f 7355 7513 7331 +f 7355 7331 7183 +f 7183 7331 7207 +f 7183 7207 7083 +f 7083 7207 7079 +f 7083 7079 6961 +f 6961 7079 6885 +f 6961 6885 6783 +f 6783 6885 6789 +f 6783 6789 6651 +f 6651 6789 6611 +f 6651 6611 6483 +f 6483 6611 6567 +f 6483 6567 6409 +f 6409 6567 6450 +f 6409 6450 6279 +f 6279 6450 6267 +f 6279 6267 6083 +f 6083 6267 6163 +f 6083 6163 6043 +f 6043 6163 5955 +f 6043 5955 5841 +f 5841 5955 5899 +f 5841 5899 5683 +f 5683 5899 5707 +f 5683 5707 5651 +f 5651 5707 5575 +f 5651 5575 5501 +f 5501 5575 5447 +f 5501 5447 5354 +f 5354 5447 5401 +f 5354 5401 5271 +f 5271 5401 5263 +f 5271 5263 5111 +f 5111 5263 5129 +f 5111 5129 4937 +f 4937 5129 4933 +f 4937 4933 4829 +f 4829 4933 4835 +f 4829 4835 4635 +f 4635 4835 4741 +f 4635 4741 4583 +f 4583 4741 4573 +f 4583 4573 4369 +f 4369 4573 4475 +f 4369 4475 4245 +f 4245 4475 4345 +f 4245 4345 4099 +f 4099 4345 4143 +f 4099 4143 4085 +f 4085 4143 4033 +f 4085 4033 3837 +f 3837 4033 3877 +f 3837 3877 3703 +f 3703 3877 3729 +f 3703 3729 3677 +f 3677 3729 3679 +f 3677 3679 3549 +f 3549 3679 3557 +f 3549 3557 3314 +f 3314 3557 3427 +f 3314 3427 3287 +f 3287 3427 3270 +f 3287 3270 3083 +f 3083 3270 3047 +f 3083 3047 2981 +f 2981 3047 2935 +f 2981 2935 2789 +f 2789 2935 2889 +f 2789 2889 2645 +f 2645 2889 2739 +f 2645 2739 2587 +f 2587 2739 2621 +f 2587 2621 2381 +f 2381 2621 2393 +f 2381 2393 2213 +f 2213 2393 2310 +f 2213 2310 2165 +f 2165 2310 2095 +f 2165 2095 1993 +f 1993 2095 2051 +f 1993 2051 1871 +f 1871 2051 1851 +f 1871 1851 1761 +f 1761 1851 1721 +f 1761 1721 1597 +f 1597 1721 1621 +f 1597 1621 1505 +f 1505 1621 1472 +f 1505 1472 1377 +f 1377 1472 1323 +f 1377 1323 1219 +f 1219 1323 1301 +f 1219 1301 1083 +f 1083 1301 1157 +f 1083 1157 947 +f 947 1157 965 +f 947 965 861 +f 861 965 839 +f 861 839 687 +f 687 839 787 +f 687 787 565 +f 565 787 649 +f 565 649 449 +f 449 649 459 +f 449 459 375 +f 375 459 397 +f 375 397 287 +f 287 397 263 +f 287 263 145 +f 145 263 135 +f 145 135 34 +f 7839 7769 7687 +f 7687 7769 7649 +f 7687 7649 7537 +f 7537 7649 7535 +f 7537 7535 7503 +f 7503 7535 7407 +f 7503 7407 7387 +f 7387 7407 7355 +f 7387 7355 7235 +f 7235 7355 7183 +f 7235 7183 7119 +f 7119 7183 7083 +f 7119 7083 6865 +f 6865 7083 6961 +f 6865 6961 6739 +f 6739 6961 6783 +f 6739 6783 6677 +f 6677 6783 6651 +f 6677 6651 6565 +f 6565 6651 6483 +f 6565 6483 6399 +f 6399 6483 6409 +f 6399 6409 6210 +f 6210 6409 6279 +f 6210 6279 6119 +f 6119 6279 6083 +f 6119 6083 5965 +f 5965 6083 6043 +f 5965 6043 5823 +f 5823 6043 5841 +f 5823 5841 5805 +f 5805 5841 5683 +f 5805 5683 5635 +f 5635 5683 5651 +f 5635 5651 5451 +f 5451 5651 5501 +f 5451 5501 5345 +f 5345 5501 5354 +f 5345 5354 5171 +f 5171 5354 5271 +f 5171 5271 5039 +f 5039 5271 5111 +f 5039 5111 4923 +f 4923 5111 4937 +f 4923 4937 4859 +f 4859 4937 4829 +f 4859 4829 4703 +f 4703 4829 4635 +f 4703 4635 4535 +f 4535 4635 4583 +f 4535 4583 4467 +f 4467 4583 4369 +f 4467 4369 4291 +f 4291 4369 4245 +f 4291 4245 4199 +f 4199 4245 4099 +f 4199 4099 4093 +f 4093 4099 4085 +f 4093 4085 3881 +f 3881 4085 3837 +f 3881 3837 3763 +f 3763 3837 3703 +f 3763 3703 3689 +f 3689 3703 3677 +f 3689 3677 3493 +f 3493 3677 3549 +f 3493 3549 3415 +f 3415 3549 3314 +f 3415 3314 3281 +f 3281 3314 3287 +f 3281 3287 3097 +f 3097 3287 3083 +f 3097 3083 2909 +f 2909 3083 2981 +f 2909 2981 2785 +f 2785 2981 2789 +f 2785 2789 2649 +f 2649 2789 2645 +f 2649 2645 2615 +f 2615 2645 2587 +f 2615 2587 2359 +f 2359 2587 2381 +f 2359 2381 2315 +f 2315 2381 2213 +f 2315 2213 2181 +f 2181 2213 2165 +f 2181 2165 2031 +f 2031 2165 1993 +f 2031 1993 1929 +f 1929 1993 1871 +f 1929 1871 1801 +f 1801 1871 1761 +f 1801 1761 1697 +f 1697 1761 1597 +f 1697 1597 1501 +f 1501 1597 1505 +f 1501 1505 1359 +f 1359 1505 1377 +f 1359 1377 1249 +f 1249 1377 1219 +f 1249 1219 1069 +f 1069 1219 1083 +f 1069 1083 1013 +f 1013 1083 947 +f 1013 947 863 +f 863 947 861 +f 863 861 677 +f 677 861 687 +f 677 687 675 +f 675 687 565 +f 675 565 543 +f 543 565 449 +f 543 449 407 +f 407 449 375 +f 407 375 211 +f 211 375 287 +f 211 287 139 +f 139 287 145 +f 139 145 34 +f 7797 7839 7651 +f 7651 7839 7687 +f 7651 7687 7613 +f 7613 7687 7537 +f 7613 7537 7435 +f 7435 7537 7503 +f 7435 7503 7293 +f 7293 7503 7387 +f 7293 7387 7189 +f 7189 7387 7235 +f 7189 7235 7103 +f 7103 7235 7119 +f 7103 7119 6959 +f 6959 7119 6865 +f 6959 6865 6759 +f 6759 6865 6739 +f 6759 6739 6673 +f 6673 6739 6677 +f 6673 6677 6537 +f 6537 6677 6565 +f 6537 6565 6345 +f 6345 6565 6399 +f 6345 6399 6283 +f 6283 6399 6210 +f 6283 6210 6131 +f 6131 6210 6119 +f 6131 6119 5949 +f 5949 6119 5965 +f 5949 5965 5867 +f 5867 5965 5823 +f 5867 5823 5751 +f 5751 5823 5805 +f 5751 5805 5637 +f 5637 5805 5635 +f 5637 5635 5419 +f 5419 5635 5451 +f 5419 5451 5327 +f 5327 5451 5345 +f 5327 5345 5177 +f 5177 5345 5171 +f 5177 5171 5083 +f 5083 5171 5039 +f 5083 5039 4897 +f 4897 5039 4923 +f 4897 4923 4827 +f 4827 4923 4859 +f 4827 4859 4745 +f 4745 4859 4703 +f 4745 4703 4533 +f 4533 4703 4535 +f 4533 4535 4455 +f 4455 4535 4467 +f 4455 4467 4277 +f 4277 4467 4291 +f 4277 4291 4145 +f 4145 4291 4199 +f 4145 4199 4055 +f 4055 4199 4093 +f 4055 4093 3895 +f 3895 4093 3881 +f 3895 3881 3793 +f 3793 3881 3763 +f 3793 3763 3687 +f 3687 3763 3689 +f 3687 3689 3495 +f 3495 3689 3493 +f 3495 3493 3399 +f 3399 3493 3415 +f 3399 3415 3197 +f 3197 3415 3281 +f 3197 3281 3131 +f 3131 3281 3097 +f 3131 3097 2905 +f 2905 3097 2909 +f 2905 2909 2885 +f 2885 2909 2785 +f 2885 2785 2759 +f 2759 2785 2649 +f 2759 2649 2619 +f 2619 2649 2615 +f 2619 2615 2363 +f 2363 2615 2359 +f 2363 2359 2321 +f 2321 2359 2315 +f 2321 2315 2122 +f 2122 2315 2181 +f 2122 2181 2023 +f 2023 2181 2031 +f 2023 2031 1925 +f 1925 2031 1929 +f 1925 1929 1711 +f 1711 1929 1801 +f 1711 1801 1633 +f 1633 1801 1697 +f 1633 1697 1531 +f 1531 1697 1501 +f 1531 1501 1367 +f 1367 1501 1359 +f 1367 1359 1291 +f 1291 1359 1249 +f 1291 1249 1061 +f 1061 1249 1069 +f 1061 1069 955 +f 955 1069 1013 +f 955 1013 805 +f 805 1013 863 +f 805 863 751 +f 751 863 677 +f 751 677 647 +f 647 677 675 +f 647 675 521 +f 521 675 543 +f 521 543 347 +f 347 543 407 +f 347 407 223 +f 223 407 211 +f 223 211 125 +f 125 211 139 +f 125 139 16 +f 7811 7797 7647 +f 7647 7797 7651 +f 7647 7651 7627 +f 7627 7651 7613 +f 7627 7613 7445 +f 7445 7613 7435 +f 7445 7435 7319 +f 7319 7435 7293 +f 7319 7293 7223 +f 7223 7293 7189 +f 7223 7189 7049 +f 7049 7189 7103 +f 7049 7103 6857 +f 6857 7103 6959 +f 6857 6959 6787 +f 6787 6959 6759 +f 6787 6759 6669 +f 6669 6759 6673 +f 6669 6673 6557 +f 6557 6673 6537 +f 6557 6537 6457 +f 6457 6537 6345 +f 6457 6345 6247 +f 6247 6345 6283 +f 6247 6283 6139 +f 6139 6283 6131 +f 6139 6131 5967 +f 5967 6131 5949 +f 5967 5949 5875 +f 5875 5949 5867 +f 5875 5867 5749 +f 5749 5867 5751 +f 5749 5751 5661 +f 5661 5751 5637 +f 5661 5637 5421 +f 5421 5637 5419 +f 5421 5419 5315 +f 5315 5419 5327 +f 5315 5327 5183 +f 5183 5327 5177 +f 5183 5177 5047 +f 5047 5177 5083 +f 5047 5083 4987 +f 4987 5083 4897 +f 4987 4897 4803 +f 4803 4897 4827 +f 4803 4827 4637 +f 4637 4827 4745 +f 4637 4745 4513 +f 4513 4745 4533 +f 4513 4533 4379 +f 4379 4533 4455 +f 4379 4455 4341 +f 4341 4455 4277 +f 4341 4277 4207 +f 4207 4277 4145 +f 4207 4145 4005 +f 4005 4145 4055 +f 4005 4055 3845 +f 3845 4055 3895 +f 3845 3895 3789 +f 3789 3895 3793 +f 3789 3793 3635 +f 3635 3793 3687 +f 3635 3687 3475 +f 3475 3687 3495 +f 3475 3495 3325 +f 3325 3495 3399 +f 3325 3399 3209 +f 3209 3399 3197 +f 3209 3197 3055 +f 3055 3197 3131 +f 3055 3131 3013 +f 3013 3131 2905 +f 3013 2905 2795 +f 2795 2905 2885 +f 2795 2885 2653 +f 2653 2885 2759 +f 2653 2759 2539 +f 2539 2759 2619 +f 2539 2619 2439 +f 2439 2619 2363 +f 2439 2363 2325 +f 2325 2363 2321 +f 2325 2321 2119 +f 2119 2321 2122 +f 2119 2122 1965 +f 1965 2122 2023 +f 1965 2023 1841 +f 1841 2023 1925 +f 1841 1925 1795 +f 1795 1925 1711 +f 1795 1711 1667 +f 1667 1711 1633 +f 1667 1633 1445 +f 1445 1633 1531 +f 1445 1531 1347 +f 1347 1531 1367 +f 1347 1367 1311 +f 1311 1367 1291 +f 1311 1291 1153 +f 1153 1291 1061 +f 1153 1061 935 +f 935 1061 955 +f 935 955 883 +f 883 955 805 +f 883 805 777 +f 777 805 751 +f 777 751 667 +f 667 751 647 +f 667 647 489 +f 489 647 521 +f 489 521 301 +f 301 521 347 +f 301 347 167 +f 167 347 223 +f 167 223 153 +f 153 223 125 +f 153 125 16 +f 7855 7811 7707 +f 7707 7811 7647 +f 7707 7647 7585 +f 7585 7647 7627 +f 7585 7627 7437 +f 7437 7627 7445 +f 7437 7445 7309 +f 7309 7445 7319 +f 7309 7319 7231 +f 7231 7319 7223 +f 7231 7223 7099 +f 7099 7223 7049 +f 7099 7049 6911 +f 6911 7049 6857 +f 6911 6857 6847 +f 6847 6857 6787 +f 6847 6787 6689 +f 6689 6787 6669 +f 6689 6669 6525 +f 6525 6669 6557 +f 6525 6557 6347 +f 6347 6557 6457 +f 6347 6457 6263 +f 6263 6457 6247 +f 6263 6247 6085 +f 6085 6247 6139 +f 6085 6139 5959 +f 5959 6139 5967 +f 5959 5967 5819 +f 5819 5967 5875 +f 5819 5875 5799 +f 5799 5875 5749 +f 5799 5749 5647 +f 5647 5749 5661 +f 5647 5661 5469 +f 5469 5661 5421 +f 5469 5421 5329 +f 5329 5421 5315 +f 5329 5315 5187 +f 5187 5315 5183 +f 5187 5183 5025 +f 5025 5183 5047 +f 5025 5047 4893 +f 4893 5047 4987 +f 4893 4987 4775 +f 4775 4987 4803 +f 4775 4803 4659 +f 4659 4803 4637 +f 4659 4637 4611 +f 4611 4637 4513 +f 4611 4513 4465 +f 4465 4513 4379 +f 4465 4379 4253 +f 4253 4379 4341 +f 4253 4341 4205 +f 4205 4341 4207 +f 4205 4207 4003 +f 4003 4207 4005 +f 4003 4005 3849 +f 3849 4005 3845 +f 3849 3845 3775 +f 3775 3845 3789 +f 3775 3789 3589 +f 3589 3789 3635 +f 3589 3635 3503 +f 3503 3635 3475 +f 3503 3475 3359 +f 3359 3475 3325 +f 3359 3325 3205 +f 3205 3325 3209 +f 3205 3209 3067 +f 3067 3209 3055 +f 3067 3055 2947 +f 2947 3055 3013 +f 2947 3013 2811 +f 2811 3013 2795 +f 2811 2795 2651 +f 2651 2795 2653 +f 2651 2653 2501 +f 2501 2653 2539 +f 2501 2539 2483 +f 2483 2539 2439 +f 2483 2439 2331 +f 2331 2439 2325 +f 2331 2325 2197 +f 2197 2325 2119 +f 2197 2119 2057 +f 2057 2119 1965 +f 2057 1965 1829 +f 1829 1965 1841 +f 1829 1841 1823 +f 1823 1841 1795 +f 1823 1795 1637 +f 1637 1795 1667 +f 1637 1667 1529 +f 1529 1667 1445 +f 1529 1445 1369 +f 1369 1445 1347 +f 1369 1347 1205 +f 1205 1347 1311 +f 1205 1311 1131 +f 1131 1311 1153 +f 1131 1153 989 +f 989 1153 935 +f 989 935 819 +f 819 935 883 +f 819 883 745 +f 745 883 777 +f 745 777 605 +f 605 777 667 +f 605 667 485 +f 485 667 489 +f 485 489 361 +f 361 489 301 +f 361 301 257 +f 257 301 167 +f 257 167 121 +f 121 167 153 +f 121 153 22 +f 7853 7855 7733 +f 7733 7855 7707 +f 7733 7707 7619 +f 7619 7707 7585 +f 7619 7585 7405 +f 7405 7585 7437 +f 7405 7437 7317 +f 7317 7437 7309 +f 7317 7309 7165 +f 7165 7309 7231 +f 7165 7231 7121 +f 7121 7231 7099 +f 7121 7099 6877 +f 6877 7099 6911 +f 6877 6911 6775 +f 6775 6911 6847 +f 6775 6847 6597 +f 6597 6847 6689 +f 6597 6689 6563 +f 6563 6689 6525 +f 6563 6525 6357 +f 6357 6525 6347 +f 6357 6347 6293 +f 6293 6347 6263 +f 6293 6263 6137 +f 6137 6263 6085 +f 6137 6085 6003 +f 6003 6085 5959 +f 6003 5959 5905 +f 5905 5959 5819 +f 5905 5819 5693 +f 5693 5819 5799 +f 5693 5799 5561 +f 5561 5799 5647 +f 5561 5647 5443 +f 5443 5647 5469 +f 5443 5469 5371 +f 5371 5469 5329 +f 5371 5329 5159 +f 5159 5329 5187 +f 5159 5187 5063 +f 5063 5187 5025 +f 5063 5025 5017 +f 5017 5025 4893 +f 5017 4893 4845 +f 4845 4893 4775 +f 4845 4775 4685 +f 4685 4775 4659 +f 4685 4659 4603 +f 4603 4659 4611 +f 4603 4611 4441 +f 4441 4611 4465 +f 4441 4465 4305 +f 4305 4465 4253 +f 4305 4253 4223 +f 4223 4253 4205 +f 4223 4205 3967 +f 3967 4205 4003 +f 3967 4003 3931 +f 3931 4003 3849 +f 3931 3849 3809 +f 3809 3849 3775 +f 3809 3775 3605 +f 3605 3775 3589 +f 3605 3589 3467 +f 3467 3589 3503 +f 3467 3503 3423 +f 3423 3503 3359 +f 3423 3359 3223 +f 3223 3359 3205 +f 3223 3205 3039 +f 3039 3205 3067 +f 3039 3067 3019 +f 3019 3067 2947 +f 3019 2947 2803 +f 2803 2947 2811 +f 2803 2811 2735 +f 2735 2811 2651 +f 2735 2651 2515 +f 2515 2651 2501 +f 2515 2501 2449 +f 2449 2501 2483 +f 2449 2483 2327 +f 2327 2483 2331 +f 2327 2331 2153 +f 2153 2331 2197 +f 2153 2197 2001 +f 2001 2197 2057 +f 2001 2057 1901 +f 1901 2057 1829 +f 1901 1829 1747 +f 1747 1829 1823 +f 1747 1823 1677 +f 1677 1823 1637 +f 1677 1637 1515 +f 1515 1637 1529 +f 1515 1529 1420 +f 1420 1529 1369 +f 1420 1369 1243 +f 1243 1369 1205 +f 1243 1205 1151 +f 1151 1205 1131 +f 1151 1131 957 +f 957 1131 989 +f 957 989 809 +f 809 989 819 +f 809 819 733 +f 733 819 745 +f 733 745 593 +f 593 745 605 +f 593 605 509 +f 509 605 485 +f 509 485 307 +f 307 485 361 +f 307 361 201 +f 201 361 257 +f 201 257 143 +f 143 257 121 +f 143 121 22 +f 7793 7853 7693 +f 7693 7853 7733 +f 7693 7733 7615 +f 7615 7733 7619 +f 7615 7619 7447 +f 7447 7619 7405 +f 7447 7405 7335 +f 7335 7405 7317 +f 7335 7317 7153 +f 7153 7317 7165 +f 7153 7165 7111 +f 7111 7165 7121 +f 7111 7121 6887 +f 6887 7121 6877 +f 6887 6877 6733 +f 6733 6877 6775 +f 6733 6775 6667 +f 6667 6775 6597 +f 6667 6597 6515 +f 6515 6597 6563 +f 6515 6563 6411 +f 6411 6563 6357 +f 6411 6357 6205 +f 6205 6357 6293 +f 6205 6293 6143 +f 6143 6293 6137 +f 6143 6137 6023 +f 6023 6137 6003 +f 6023 6003 5933 +f 5933 6003 5905 +f 5933 5905 5767 +f 5767 5905 5693 +f 5767 5693 5565 +f 5565 5693 5561 +f 5565 5561 5503 +f 5503 5561 5443 +f 5503 5443 5301 +f 5301 5443 5371 +f 5301 5371 5247 +f 5247 5371 5159 +f 5247 5159 5087 +f 5087 5159 5063 +f 5087 5063 4975 +f 4975 5063 5017 +f 4975 5017 4769 +f 4769 5017 4845 +f 4769 4845 4751 +f 4751 4845 4685 +f 4751 4685 4499 +f 4499 4685 4603 +f 4499 4603 4375 +f 4375 4603 4441 +f 4375 4441 4235 +f 4235 4441 4305 +f 4235 4305 4111 +f 4111 4305 4223 +f 4111 4223 4077 +f 4077 4223 3967 +f 4077 3967 3959 +f 3959 3967 3931 +f 3959 3931 3759 +f 3759 3931 3809 +f 3759 3809 3655 +f 3655 3809 3605 +f 3655 3605 3537 +f 3537 3605 3467 +f 3537 3467 3367 +f 3367 3467 3423 +f 3367 3423 3263 +f 3263 3423 3223 +f 3263 3223 3129 +f 3129 3223 3039 +f 3129 3039 2915 +f 2915 3039 3019 +f 2915 3019 2799 +f 2799 3019 2803 +f 2799 2803 2749 +f 2749 2803 2735 +f 2749 2735 2593 +f 2593 2735 2515 +f 2593 2515 2373 +f 2373 2515 2449 +f 2373 2449 2313 +f 2313 2449 2327 +f 2313 2327 2141 +f 2141 2327 2153 +f 2141 2153 2025 +f 2025 2153 2001 +f 2025 2001 1913 +f 1913 2001 1901 +f 1913 1901 1787 +f 1787 1901 1747 +f 1787 1747 1581 +f 1581 1747 1677 +f 1581 1677 1477 +f 1477 1677 1515 +f 1477 1515 1379 +f 1379 1515 1420 +f 1379 1420 1275 +f 1275 1420 1243 +f 1275 1243 1096 +f 1096 1243 1151 +f 1096 1151 1055 +f 1055 1151 957 +f 1055 957 901 +f 901 957 809 +f 901 809 713 +f 713 809 733 +f 713 733 639 +f 639 733 593 +f 639 593 421 +f 421 593 509 +f 421 509 349 +f 349 509 307 +f 349 307 267 +f 267 307 201 +f 267 201 119 +f 119 201 143 +f 119 143 18 +f 7815 7793 7749 +f 7749 7793 7693 +f 7749 7693 7611 +f 7611 7693 7615 +f 7611 7615 7507 +f 7507 7615 7447 +f 7507 7447 7369 +f 7369 7447 7335 +f 7369 7335 7199 +f 7199 7335 7153 +f 7199 7153 7097 +f 7097 7153 7111 +f 7097 7111 6859 +f 6859 7111 6887 +f 6859 6887 6743 +f 6743 6887 6733 +f 6743 6733 6639 +f 6639 6733 6667 +f 6639 6667 6579 +f 6579 6667 6515 +f 6579 6515 6361 +f 6361 6515 6411 +f 6361 6411 6323 +f 6323 6411 6205 +f 6323 6205 6125 +f 6125 6205 6143 +f 6125 6143 5943 +f 5943 6143 6023 +f 5943 6023 5873 +f 5873 6023 5933 +f 5873 5933 5713 +f 5713 5933 5767 +f 5713 5767 5559 +f 5559 5767 5565 +f 5559 5565 5513 +f 5513 5565 5503 +f 5513 5503 5299 +f 5299 5503 5301 +f 5299 5301 5235 +f 5235 5301 5247 +f 5235 5247 5095 +f 5095 5247 5087 +f 5095 5087 4935 +f 4935 5087 4975 +f 4935 4975 4861 +f 4861 4975 4769 +f 4861 4769 4715 +f 4715 4769 4751 +f 4715 4751 4539 +f 4539 4751 4499 +f 4539 4499 4391 +f 4391 4499 4375 +f 4391 4375 4287 +f 4287 4375 4235 +f 4287 4235 4105 +f 4105 4235 4111 +f 4105 4111 3969 +f 3969 4111 4077 +f 3969 4077 3915 +f 3915 4077 3959 +f 3915 3959 3753 +f 3753 3959 3759 +f 3753 3759 3607 +f 3607 3759 3655 +f 3607 3655 3485 +f 3485 3655 3537 +f 3485 3537 3321 +f 3321 3537 3367 +f 3321 3367 3185 +f 3185 3367 3263 +f 3185 3263 3142 +f 3142 3263 3129 +f 3142 3129 2959 +f 2959 3129 2915 +f 2959 2915 2771 +f 2771 2915 2799 +f 2771 2799 2747 +f 2747 2799 2749 +f 2747 2749 2551 +f 2551 2749 2593 +f 2551 2593 2485 +f 2485 2593 2373 +f 2485 2373 2303 +f 2303 2373 2313 +f 2303 2313 2117 +f 2117 2313 2141 +f 2117 2141 2081 +f 2081 2141 2025 +f 2081 2025 1863 +f 1863 2025 1913 +f 1863 1913 1781 +f 1781 1913 1787 +f 1781 1787 1643 +f 1643 1787 1581 +f 1643 1581 1545 +f 1545 1581 1477 +f 1545 1477 1371 +f 1371 1477 1379 +f 1371 1379 1225 +f 1225 1379 1275 +f 1225 1275 1063 +f 1063 1275 1096 +f 1063 1096 941 +f 941 1096 1055 +f 941 1055 887 +f 887 1055 901 +f 887 901 759 +f 759 901 713 +f 759 713 569 +f 569 713 639 +f 569 639 471 +f 471 639 421 +f 471 421 331 +f 331 421 349 +f 331 349 226 +f 226 349 267 +f 226 267 99 +f 99 267 119 +f 99 119 20 +f 7823 7815 7655 +f 7655 7815 7749 +f 7655 7749 7605 +f 7605 7749 7611 +f 7605 7611 7451 +f 7451 7611 7507 +f 7451 7507 7321 +f 7321 7507 7369 +f 7321 7369 7225 +f 7225 7369 7199 +f 7225 7199 7087 +f 7087 7199 7097 +f 7087 7097 6927 +f 6927 7097 6859 +f 6927 6859 6823 +f 6823 6859 6743 +f 6823 6743 6711 +f 6711 6743 6639 +f 6711 6639 6509 +f 6509 6639 6579 +f 6509 6579 6433 +f 6433 6579 6361 +f 6433 6361 6291 +f 6291 6361 6323 +f 6291 6323 6197 +f 6197 6323 6125 +f 6197 6125 6047 +f 6047 6125 5943 +f 6047 5943 5859 +f 5859 5943 5873 +f 5859 5873 5731 +f 5731 5873 5713 +f 5731 5713 5631 +f 5631 5713 5559 +f 5631 5559 5445 +f 5445 5559 5513 +f 5445 5513 5361 +f 5361 5513 5299 +f 5361 5299 5264 +f 5264 5299 5235 +f 5264 5235 5115 +f 5115 5235 5095 +f 5115 5095 5015 +f 5015 5095 4935 +f 5015 4935 4759 +f 4759 4935 4861 +f 4759 4861 4639 +f 4639 4861 4715 +f 4639 4715 4599 +f 4599 4715 4539 +f 4599 4539 4377 +f 4377 4539 4391 +f 4377 4391 4325 +f 4325 4391 4287 +f 4325 4287 4121 +f 4121 4287 4105 +f 4121 4105 4037 +f 4037 4105 3969 +f 4037 3969 3835 +f 3835 3969 3915 +f 3835 3915 3733 +f 3733 3915 3753 +f 3733 3753 3683 +f 3683 3753 3607 +f 3683 3607 3471 +f 3471 3607 3485 +f 3471 3485 3383 +f 3383 3485 3321 +f 3383 3321 3225 +f 3225 3321 3185 +f 3225 3185 3123 +f 3123 3185 3142 +f 3123 3142 2977 +f 2977 3142 2959 +f 2977 2959 2879 +f 2879 2959 2771 +f 2879 2771 2733 +f 2733 2771 2747 +f 2733 2747 2503 +f 2503 2747 2551 +f 2503 2551 2383 +f 2383 2551 2485 +f 2383 2485 2333 +f 2333 2485 2303 +f 2333 2303 2143 +f 2143 2303 2117 +f 2143 2117 2079 +f 2079 2117 2081 +f 2079 2081 1941 +f 1941 2081 1863 +f 1941 1863 1739 +f 1739 1863 1781 +f 1739 1781 1615 +f 1615 1781 1643 +f 1615 1643 1502 +f 1502 1643 1545 +f 1502 1545 1331 +f 1331 1545 1371 +f 1331 1371 1250 +f 1250 1371 1225 +f 1250 1225 1081 +f 1081 1225 1063 +f 1081 1063 973 +f 973 1063 941 +f 973 941 815 +f 815 941 887 +f 815 887 729 +f 729 887 759 +f 729 759 625 +f 625 759 569 +f 625 569 469 +f 469 569 471 +f 469 471 309 +f 309 471 331 +f 309 331 181 +f 181 331 226 +f 181 226 111 +f 111 226 99 +f 111 99 20 +f 7835 7823 7721 +f 7721 7823 7655 +f 7721 7655 7581 +f 7581 7655 7605 +f 7581 7605 7441 +f 7441 7605 7451 +f 7441 7451 7359 +f 7359 7451 7321 +f 7359 7321 7239 +f 7239 7321 7225 +f 7239 7225 7011 +f 7011 7225 7087 +f 7011 7087 6867 +f 6867 7087 6927 +f 6867 6927 6777 +f 6777 6927 6823 +f 6777 6823 6687 +f 6687 6823 6711 +f 6687 6711 6505 +f 6505 6711 6509 +f 6505 6509 6402 +f 6402 6509 6433 +f 6402 6433 6319 +f 6319 6433 6291 +f 6319 6291 6133 +f 6133 6291 6197 +f 6133 6197 6028 +f 6028 6197 6047 +f 6028 6047 5855 +f 5855 6047 5859 +f 5855 5859 5793 +f 5793 5859 5731 +f 5793 5731 5657 +f 5657 5731 5631 +f 5657 5631 5473 +f 5473 5631 5445 +f 5473 5445 5339 +f 5339 5445 5361 +f 5339 5361 5201 +f 5201 5361 5264 +f 5201 5264 5056 +f 5056 5264 5115 +f 5056 5115 4925 +f 4925 5115 5015 +f 4925 5015 4877 +f 4877 5015 4759 +f 4877 4759 4667 +f 4667 4759 4639 +f 4667 4639 4509 +f 4509 4639 4599 +f 4509 4599 4451 +f 4451 4599 4377 +f 4451 4377 4243 +f 4243 4377 4325 +f 4243 4325 4157 +f 4157 4325 4121 +f 4157 4121 3973 +f 3973 4121 4037 +f 3973 4037 3923 +f 3923 4037 3835 +f 3923 3835 3741 +f 3741 3835 3733 +f 3741 3733 3663 +f 3663 3733 3683 +f 3663 3683 3443 +f 3443 3683 3471 +f 3443 3471 3373 +f 3373 3471 3383 +f 3373 3383 3233 +f 3233 3383 3225 +f 3233 3225 3149 +f 3149 3225 3123 +f 3149 3123 2995 +f 2995 3123 2977 +f 2995 2977 2843 +f 2843 2977 2879 +f 2843 2879 2663 +f 2663 2879 2733 +f 2663 2733 2543 +f 2543 2733 2503 +f 2543 2503 2387 +f 2387 2503 2383 +f 2387 2383 2337 +f 2337 2383 2333 +f 2337 2333 2173 +f 2173 2333 2143 +f 2173 2143 1961 +f 1961 2143 2079 +f 1961 2079 1911 +f 1911 2079 1941 +f 1911 1941 1749 +f 1749 1941 1739 +f 1749 1739 1587 +f 1587 1739 1615 +f 1587 1615 1563 +f 1563 1615 1502 +f 1563 1502 1425 +f 1425 1502 1331 +f 1425 1331 1247 +f 1247 1331 1250 +f 1247 1250 1181 +f 1181 1250 1081 +f 1181 1081 1029 +f 1029 1081 973 +f 1029 973 829 +f 829 973 815 +f 829 815 685 +f 685 815 729 +f 685 729 615 +f 615 729 625 +f 615 625 493 +f 493 625 469 +f 493 469 373 +f 373 469 309 +f 373 309 237 +f 237 309 181 +f 237 181 109 +f 109 181 111 +f 109 111 31 +f 7831 7835 7657 +f 7657 7835 7721 +f 7657 7721 7624 +f 7624 7721 7581 +f 7624 7581 7495 +f 7495 7581 7441 +f 7495 7441 7371 +f 7371 7441 7359 +f 7371 7359 7261 +f 7261 7359 7239 +f 7261 7239 7051 +f 7051 7239 7011 +f 7051 7011 6870 +f 6870 7011 6867 +f 6870 6867 6792 +f 6792 6867 6777 +f 6792 6777 6613 +f 6613 6777 6687 +f 6613 6687 6519 +f 6519 6687 6505 +f 6519 6505 6367 +f 6367 6505 6402 +f 6367 6402 6241 +f 6241 6402 6319 +f 6241 6319 6185 +f 6185 6319 6133 +f 6185 6133 6065 +f 6065 6133 6028 +f 6065 6028 5848 +f 5848 6028 5855 +f 5848 5855 5687 +f 5687 5855 5793 +f 5687 5793 5671 +f 5671 5793 5657 +f 5671 5657 5499 +f 5499 5657 5473 +f 5499 5473 5313 +f 5313 5473 5339 +f 5313 5339 5269 +f 5269 5339 5201 +f 5269 5201 5121 +f 5121 5201 5056 +f 5121 5056 4993 +f 4993 5056 4925 +f 4993 4925 4867 +f 4867 4925 4877 +f 4867 4877 4677 +f 4677 4877 4667 +f 4677 4667 4563 +f 4563 4667 4509 +f 4563 4509 4399 +f 4399 4509 4451 +f 4399 4451 4265 +f 4265 4451 4243 +f 4265 4243 4187 +f 4187 4243 4157 +f 4187 4157 4069 +f 4069 4157 3973 +f 4069 3973 3893 +f 3893 3973 3923 +f 3893 3923 3749 +f 3749 3923 3741 +f 3749 3741 3575 +f 3575 3741 3663 +f 3575 3663 3555 +f 3555 3663 3443 +f 3555 3443 3390 +f 3390 3443 3373 +f 3390 3373 3279 +f 3279 3373 3233 +f 3279 3233 3077 +f 3077 3233 3149 +f 3077 3149 2957 +f 2957 3149 2995 +f 2957 2995 2801 +f 2801 2995 2843 +f 2801 2843 2661 +f 2661 2843 2663 +f 2661 2663 2507 +f 2507 2663 2543 +f 2507 2543 2473 +f 2473 2543 2387 +f 2473 2387 2217 +f 2217 2387 2337 +f 2217 2337 2179 +f 2179 2337 2173 +f 2179 2173 1971 +f 1971 2173 1961 +f 1971 1961 1867 +f 1867 1961 1911 +f 1867 1911 1793 +f 1793 1911 1749 +f 1793 1749 1595 +f 1595 1749 1587 +f 1595 1587 1513 +f 1513 1587 1563 +f 1513 1563 1335 +f 1335 1563 1425 +f 1335 1425 1201 +f 1201 1425 1247 +f 1201 1247 1163 +f 1163 1247 1181 +f 1163 1181 963 +f 963 1181 1029 +f 963 1029 835 +f 835 1029 829 +f 835 829 789 +f 789 829 685 +f 789 685 643 +f 643 685 615 +f 643 615 423 +f 423 615 493 +f 423 493 367 +f 367 493 373 +f 367 373 171 +f 171 373 237 +f 171 237 67 +f 67 237 109 +f 67 109 31 +f 7770 7831 7661 +f 7661 7831 7657 +f 7661 7657 7607 +f 7607 7657 7624 +f 7607 7624 7419 +f 7419 7624 7495 +f 7419 7495 7281 +f 7281 7495 7371 +f 7281 7371 7245 +f 7245 7371 7261 +f 7245 7261 7129 +f 7129 7261 7051 +f 7129 7051 6909 +f 6909 7051 6870 +f 6909 6870 6813 +f 6813 6870 6792 +f 6813 6792 6695 +f 6695 6792 6613 +f 6695 6613 6543 +f 6543 6613 6519 +f 6543 6519 6443 +f 6443 6519 6367 +f 6443 6367 6313 +f 6313 6367 6241 +f 6313 6241 6107 +f 6107 6241 6185 +f 6107 6185 5999 +f 5999 6185 6065 +f 5999 6065 5893 +f 5893 6065 5848 +f 5893 5848 5703 +f 5703 5848 5687 +f 5703 5687 5598 +f 5598 5687 5671 +f 5598 5671 5475 +f 5475 5671 5499 +f 5475 5499 5393 +f 5393 5499 5313 +f 5393 5313 5223 +f 5223 5313 5269 +f 5223 5269 5109 +f 5109 5269 5121 +f 5109 5121 4899 +f 4899 5121 4993 +f 4899 4993 4777 +f 4777 4993 4867 +f 4777 4867 4733 +f 4733 4867 4677 +f 4733 4677 4607 +f 4607 4677 4563 +f 4607 4563 4485 +f 4485 4563 4399 +f 4485 4399 4357 +f 4357 4399 4265 +f 4357 4265 4107 +f 4107 4265 4187 +f 4107 4187 4091 +f 4091 4187 4069 +f 4091 4069 3841 +f 3841 4069 3893 +f 3841 3893 3823 +f 3823 3893 3749 +f 3823 3749 3571 +f 3571 3749 3575 +f 3571 3575 3441 +f 3441 3575 3555 +f 3441 3555 3307 +f 3307 3555 3390 +f 3307 3390 3189 +f 3189 3390 3279 +f 3189 3279 3157 +f 3157 3279 3077 +f 3157 3077 3029 +f 3029 3077 2957 +f 3029 2957 2797 +f 2797 2957 2801 +f 2797 2801 2725 +f 2725 2801 2661 +f 2725 2661 2517 +f 2517 2661 2507 +f 2517 2507 2471 +f 2471 2507 2473 +f 2471 2473 2323 +f 2323 2473 2217 +f 2323 2217 2207 +f 2207 2217 2179 +f 2207 2179 1977 +f 1977 2179 1971 +f 1977 1971 1869 +f 1869 1971 1867 +f 1869 1867 1759 +f 1759 1867 1793 +f 1759 1793 1645 +f 1645 1793 1595 +f 1645 1595 1571 +f 1571 1595 1513 +f 1571 1513 1389 +f 1389 1513 1335 +f 1389 1335 1199 +f 1199 1335 1201 +f 1199 1201 1065 +f 1065 1201 1163 +f 1065 1163 997 +f 997 1163 963 +f 997 963 921 +f 921 963 835 +f 921 835 704 +f 704 835 789 +f 704 789 579 +f 579 789 643 +f 579 643 547 +f 547 643 423 +f 547 423 359 +f 359 423 367 +f 359 367 219 +f 219 367 171 +f 219 171 41 +f 41 171 67 +f 41 67 23 +f 7780 7770 7745 +f 7745 7770 7661 +f 7745 7661 7591 +f 7591 7661 7607 +f 7591 7607 7477 +f 7477 7607 7419 +f 7477 7419 7375 +f 7375 7419 7281 +f 7375 7281 7252 +f 7252 7281 7245 +f 7252 7245 7014 +f 7014 7245 7129 +f 7014 7129 6875 +f 6875 7129 6909 +f 6875 6909 6765 +f 6765 6909 6813 +f 6765 6813 6643 +f 6643 6813 6695 +f 6643 6695 6503 +f 6503 6695 6543 +f 6503 6543 6365 +f 6365 6543 6443 +f 6365 6443 6297 +f 6297 6443 6313 +f 6297 6313 6075 +f 6075 6313 6107 +f 6075 6107 6049 +f 6049 6107 5999 +f 6049 5999 5931 +f 5931 5999 5893 +f 5931 5893 5803 +f 5803 5893 5703 +f 5803 5703 5581 +f 5581 5703 5598 +f 5581 5598 5423 +f 5423 5598 5475 +f 5423 5475 5373 +f 5373 5475 5393 +f 5373 5393 5217 +f 5217 5393 5223 +f 5217 5223 5089 +f 5089 5223 5109 +f 5089 5109 4999 +f 4999 5109 4899 +f 4999 4899 4869 +f 4869 4899 4777 +f 4869 4777 4743 +f 4743 4777 4733 +f 4743 4733 4571 +f 4571 4733 4607 +f 4571 4607 4393 +f 4393 4607 4485 +f 4393 4485 4273 +f 4273 4485 4357 +f 4273 4357 4213 +f 4213 4357 4107 +f 4213 4107 4087 +f 4087 4107 4091 +f 4087 4091 3961 +f 3961 4091 3841 +f 3961 3841 3715 +f 3715 3841 3823 +f 3715 3823 3637 +f 3637 3823 3571 +f 3637 3571 3523 +f 3523 3571 3441 +f 3523 3441 3311 +f 3311 3441 3307 +f 3311 3307 3295 +f 3295 3307 3189 +f 3295 3189 3043 +f 3043 3189 3157 +f 3043 3157 2907 +f 2907 3157 3029 +f 2907 3029 2817 +f 2817 3029 2797 +f 2817 2797 2711 +f 2711 2797 2725 +f 2711 2725 2525 +f 2525 2725 2517 +f 2525 2517 2479 +f 2479 2517 2471 +f 2479 2471 2319 +f 2319 2471 2323 +f 2319 2323 2193 +f 2193 2323 2207 +f 2193 2207 1959 +f 1959 2207 1977 +f 1959 1977 1937 +f 1937 1977 1869 +f 1937 1869 1703 +f 1703 1869 1759 +f 1703 1759 1600 +f 1600 1759 1645 +f 1600 1645 1555 +f 1555 1645 1571 +f 1555 1571 1436 +f 1436 1571 1389 +f 1436 1389 1229 +f 1229 1389 1199 +f 1229 1199 1075 +f 1075 1199 1065 +f 1075 1065 1025 +f 1025 1065 997 +f 1025 997 870 +f 870 997 921 +f 870 921 743 +f 743 921 704 +f 743 704 645 +f 645 704 579 +f 645 579 429 +f 429 579 547 +f 429 547 299 +f 299 547 359 +f 299 359 165 +f 165 359 219 +f 165 219 161 +f 161 219 41 +f 161 41 23 +f 7790 7780 7709 +f 7709 7780 7745 +f 7709 7745 7595 +f 7595 7745 7591 +f 7595 7591 7480 +f 7480 7591 7477 +f 7480 7477 7351 +f 7351 7477 7375 +f 7351 7375 7211 +f 7211 7375 7252 +f 7211 7252 7101 +f 7101 7252 7014 +f 7101 7014 6883 +f 6883 7014 6875 +f 6883 6875 6821 +f 6821 6875 6765 +f 6821 6765 6625 +f 6625 6765 6643 +f 6625 6643 6575 +f 6575 6643 6503 +f 6575 6503 6415 +f 6415 6503 6365 +f 6415 6365 6213 +f 6213 6365 6297 +f 6213 6297 6123 +f 6123 6297 6075 +f 6123 6075 6007 +f 6007 6075 6049 +f 6007 6049 5917 +f 5917 6049 5931 +f 5917 5931 5775 +f 5775 5931 5803 +f 5775 5803 5627 +f 5627 5803 5581 +f 5627 5581 5525 +f 5525 5581 5423 +f 5525 5423 5307 +f 5307 5423 5373 +f 5307 5373 5230 +f 5230 5373 5217 +f 5230 5217 5037 +f 5037 5217 5089 +f 5037 5089 4949 +f 4949 5089 4999 +f 4949 4999 4815 +f 4815 4999 4869 +f 4815 4869 4699 +f 4699 4869 4743 +f 4699 4743 4597 +f 4597 4743 4571 +f 4597 4571 4407 +f 4407 4571 4393 +f 4407 4393 4317 +f 4317 4393 4273 +f 4317 4273 4141 +f 4141 4273 4213 +f 4141 4213 4039 +f 4039 4213 4087 +f 4039 4087 3887 +f 3887 4087 3961 +f 3887 3961 3765 +f 3765 3961 3715 +f 3765 3715 3597 +f 3597 3715 3637 +f 3597 3637 3518 +f 3518 3637 3523 +f 3518 3523 3318 +f 3318 3523 3311 +f 3318 3311 3230 +f 3230 3311 3295 +f 3230 3295 3121 +f 3121 3295 3043 +f 3121 3043 2991 +f 2991 3043 2907 +f 2991 2907 2882 +f 2882 2907 2817 +f 2882 2817 2667 +f 2667 2817 2711 +f 2667 2711 2611 +f 2611 2711 2525 +f 2611 2525 2377 +f 2377 2525 2479 +f 2377 2479 2232 +f 2232 2479 2319 +f 2232 2319 2125 +f 2125 2319 2193 +f 2125 2193 2049 +f 2049 2193 1959 +f 2049 1959 1886 +f 1886 1959 1937 +f 1886 1937 1726 +f 1726 1937 1703 +f 1726 1703 1577 +f 1577 1703 1600 +f 1577 1600 1561 +f 1561 1600 1555 +f 1561 1555 1415 +f 1415 1555 1436 +f 1415 1436 1197 +f 1197 1436 1229 +f 1197 1229 1087 +f 1087 1229 1075 +f 1087 1075 1043 +f 1043 1075 1025 +f 1043 1025 865 +f 865 1025 870 +f 865 870 683 +f 683 870 743 +f 683 743 613 +f 613 743 645 +f 613 645 545 +f 545 645 429 +f 545 429 334 +f 334 429 299 +f 334 299 283 +f 283 299 165 +f 283 165 104 +f 104 165 161 +f 104 161 24 +f 7841 7790 7751 +f 7751 7790 7709 +f 7751 7709 7589 +f 7589 7709 7595 +f 7589 7595 7501 +f 7501 7595 7480 +f 7501 7480 7295 +f 7295 7480 7351 +f 7295 7351 7214 +f 7214 7351 7211 +f 7214 7211 7073 +f 7073 7211 7101 +f 7073 7101 6925 +f 6925 7101 6883 +f 6925 6883 6811 +f 6811 6883 6821 +f 6811 6821 6707 +f 6707 6821 6625 +f 6707 6625 6531 +f 6531 6625 6575 +f 6531 6575 6387 +f 6387 6575 6415 +f 6387 6415 6321 +f 6321 6415 6213 +f 6321 6213 6111 +f 6111 6213 6123 +f 6111 6123 6035 +f 6035 6123 6007 +f 6035 6007 5902 +f 5902 6007 5917 +f 5902 5917 5736 +f 5736 5917 5775 +f 5736 5775 5557 +f 5557 5775 5627 +f 5557 5627 5467 +f 5467 5627 5525 +f 5467 5525 5337 +f 5337 5525 5307 +f 5337 5307 5195 +f 5195 5307 5230 +f 5195 5230 5066 +f 5066 5230 5037 +f 5066 5037 4963 +f 4963 5037 4949 +f 4963 4949 4879 +f 4879 4949 4815 +f 4879 4815 4721 +f 4721 4815 4699 +f 4721 4699 4577 +f 4577 4699 4597 +f 4577 4597 4389 +f 4389 4597 4407 +f 4389 4407 4259 +f 4259 4407 4317 +f 4259 4317 4153 +f 4153 4317 4141 +f 4153 4141 4059 +f 4059 4141 4039 +f 4059 4039 3865 +f 3865 4039 3887 +f 3865 3887 3747 +f 3747 3887 3765 +f 3747 3765 3648 +f 3648 3765 3597 +f 3648 3597 3525 +f 3525 3597 3518 +f 3525 3518 3303 +f 3303 3518 3318 +f 3303 3318 3190 +f 3190 3318 3230 +f 3190 3230 3165 +f 3165 3230 3121 +f 3165 3121 2929 +f 2929 3121 2991 +f 2929 2991 2869 +f 2869 2991 2882 +f 2869 2882 2697 +f 2697 2882 2667 +f 2697 2667 2569 +f 2569 2667 2611 +f 2569 2611 2391 +f 2391 2611 2377 +f 2391 2377 2295 +f 2295 2377 2232 +f 2295 2232 2183 +f 2183 2232 2125 +f 2183 2125 1985 +f 1985 2125 2049 +f 1985 2049 1837 +f 1837 2049 1886 +f 1837 1886 1705 +f 1705 1886 1726 +f 1705 1726 1584 +f 1584 1726 1577 +f 1584 1577 1543 +f 1543 1577 1561 +f 1543 1561 1353 +f 1353 1561 1415 +f 1353 1415 1191 +f 1191 1415 1197 +f 1191 1197 1185 +f 1185 1197 1087 +f 1185 1087 1052 +f 1052 1087 1043 +f 1052 1043 907 +f 907 1043 865 +f 907 865 795 +f 795 865 683 +f 795 683 561 +f 561 683 613 +f 561 613 524 +f 524 613 545 +f 524 545 356 +f 356 545 334 +f 356 334 183 +f 183 334 283 +f 183 283 37 +f 37 283 104 +f 37 104 24 +f 7850 7841 7653 +f 7653 7841 7751 +f 7653 7751 7577 +f 7577 7751 7589 +f 7577 7589 7469 +f 7469 7589 7501 +f 7469 7501 7373 +f 7373 7501 7295 +f 7373 7295 7175 +f 7175 7295 7214 +f 7175 7214 7017 +f 7017 7214 7073 +f 7017 7073 6969 +f 6969 7073 6925 +f 6969 6925 6731 +f 6731 6925 6811 +f 6731 6811 6619 +f 6619 6811 6707 +f 6619 6707 6529 +f 6529 6707 6531 +f 6529 6531 6349 +f 6349 6531 6387 +f 6349 6387 6295 +f 6295 6387 6321 +f 6295 6321 6177 +f 6177 6321 6111 +f 6177 6111 5991 +f 5991 6111 6035 +f 5991 6035 5907 +f 5907 6035 5902 +f 5907 5902 5779 +f 5779 5902 5736 +f 5779 5736 5595 +f 5595 5736 5557 +f 5595 5557 5431 +f 5431 5557 5467 +f 5431 5467 5377 +f 5377 5467 5337 +f 5377 5337 5193 +f 5193 5337 5195 +f 5193 5195 5123 +f 5123 5195 5066 +f 5123 5066 4943 +f 4943 5066 4963 +f 4943 4963 4873 +f 4873 4963 4879 +f 4873 4879 4693 +f 4693 4879 4721 +f 4693 4721 4595 +f 4595 4721 4577 +f 4595 4577 4383 +f 4383 4577 4389 +f 4383 4389 4329 +f 4329 4389 4259 +f 4329 4259 4221 +f 4221 4259 4153 +f 4221 4153 4053 +f 4053 4153 4059 +f 4053 4059 3857 +f 3857 4059 3865 +f 3857 3865 3811 +f 3811 3865 3747 +f 3811 3747 3691 +f 3691 3747 3648 +f 3691 3648 3497 +f 3497 3648 3525 +f 3497 3525 3393 +f 3393 3525 3303 +f 3393 3303 3213 +f 3213 3303 3190 +f 3213 3190 3141 +f 3141 3190 3165 +f 3141 3165 2937 +f 2937 3165 2929 +f 2937 2929 2894 +f 2894 2929 2869 +f 2894 2869 2665 +f 2665 2869 2697 +f 2665 2697 2505 +f 2505 2697 2569 +f 2505 2569 2435 +f 2435 2569 2391 +f 2435 2391 2219 +f 2219 2391 2295 +f 2219 2295 2205 +f 2205 2295 2183 +f 2205 2183 1989 +f 1989 2183 1985 +f 1989 1985 1843 +f 1843 1985 1837 +f 1843 1837 1769 +f 1769 1837 1705 +f 1769 1705 1693 +f 1693 1705 1584 +f 1693 1584 1455 +f 1455 1584 1543 +f 1455 1543 1327 +f 1327 1543 1353 +f 1327 1353 1279 +f 1279 1353 1191 +f 1279 1191 1145 +f 1145 1191 1185 +f 1145 1185 937 +f 937 1185 1052 +f 937 1052 855 +f 855 1052 907 +f 855 907 753 +f 753 907 795 +f 753 795 557 +f 557 795 561 +f 557 561 437 +f 437 561 524 +f 437 524 329 +f 329 524 356 +f 329 356 249 +f 249 356 183 +f 249 183 163 +f 163 183 37 +f 163 37 27 +f 5 27 164 +f 17 40 1 +f 7896 7861 7916 +f 7896 7878 7861 +f 7904 7808 7880 +f 7904 7919 7808 +f 7934 7866 7930 +f 7915 7858 7934 +f 62 14 1 +f 138 62 1 +f 138 1 40 +f 7932 7838 7915 +f 7903 7802 7932 +f 60 2 14 +f 98 60 14 +f 98 14 62 +f 7889 7791 7903 +f 7888 7788 7889 +f 94 7 2 +f 149 94 2 +f 149 2 60 +f 7928 7848 7888 +f 124 8 7 +f 124 7 94 +f 7882 7851 7928 +f 7921 7871 7882 +f 150 29 8 +f 150 8 142 +f 7922 7806 7921 +f 7933 7864 7922 +f 65 6 29 +f 48 65 29 +f 48 29 150 +f 7891 7862 7933 +f 7920 7800 7891 +f 84 30 6 +f 71 84 6 +f 71 6 65 +f 7909 7782 7920 +f 7892 7874 7909 +f 55 25 30 +f 160 55 30 +f 160 30 84 +f 7917 7821 7892 +f 105 11 25 +f 105 25 55 +f 7884 7828 7917 +f 7912 7822 7884 +f 96 21 11 +f 96 11 49 +f 7935 7796 7912 +f 7926 7764 7935 +f 116 4 21 +f 158 116 21 +f 158 21 96 +f 7902 7778 7926 +f 7908 7826 7902 +f 85 26 4 +f 117 85 4 +f 117 4 116 +f 7936 7814 7908 +f 7894 7846 7936 +f 86 33 26 +f 131 86 26 +f 131 26 85 +f 7916 7804 7894 +f 72 9 33 +f 72 33 86 +f 87 12 9 +f 87 9 132 +f 7138 7007 7031 +f 50 13 12 +f 6993 6989 6954 +f 6992 6922 6988 +f 106 28 13 +f 51 106 13 +f 51 13 50 +f 7133 7132 7005 +f 107 10 28 +f 7404 7386 7396 +f 133 32 10 +f 7808 7875 7880 +f 7900 7872 7919 +f 134 19 32 +f 134 32 156 +f 7906 7766 7900 +f 7898 7818 7906 +f 52 15 19 +f 66 52 19 +f 66 19 134 +f 7931 7868 7898 +f 7913 7768 7931 +f 118 3 15 +f 56 118 15 +f 56 15 52 +f 7927 7844 7913 +f 7883 7834 7927 +f 58 35 3 +f 88 58 3 +f 88 3 118 +f 7911 7776 7883 +f 75 36 35 +f 75 35 58 +f 7890 7810 7911 +f 7881 7774 7890 +f 136 34 36 +f 136 36 92 +f 7910 7771 7881 +f 7914 7840 7910 +f 140 16 34 +f 146 140 34 +f 146 34 136 +f 7893 7798 7914 +f 7923 7812 7893 +f 154 22 16 +f 126 154 16 +f 126 16 140 +f 7907 7856 7923 +f 7887 7854 7907 +f 144 18 22 +f 122 144 22 +f 122 22 154 +f 7895 7794 7887 +f 120 20 18 +f 120 18 144 +f 7925 7816 7895 +f 7886 7824 7925 +f 112 31 20 +f 112 20 100 +f 7924 7836 7886 +f 7929 7832 7924 +f 68 23 31 +f 110 68 31 +f 110 31 112 +f 7897 7772 7929 +f 7885 7783 7897 +f 162 24 23 +f 42 162 23 +f 42 23 68 +f 7905 7792 7885 +f 7918 7842 7905 +f 38 27 24 +f 108 38 24 +f 108 24 162 +f 164 27 38 +f 8 124 142 +f 11 105 49 +f 9 72 132 +f 7274 7358 7394 +f 7358 7402 7394 +f 6954 7003 6993 +f 6989 6985 6922 +f 6985 6984 6922 +f 6988 6922 6984 +f 7272 7392 7386 +f 7396 7386 7392 +f 32 133 156 +f 7516 7520 7576 +f 7759 7875 7808 +f 36 75 92 +f 20 120 100 +f 7124 7070 7195 +f 7124 7195 7266 +f 7124 7266 7146 +f 7124 7146 7142 +f 7124 7142 7138 +f 7124 7138 7031 +f 6901 6922 6992 +f 6901 6992 6995 +f 6901 6995 6997 +f 6901 6997 7005 +f 6901 7005 7132 +f 7091 7132 7133 +f 7091 7133 7135 +f 7091 7135 7140 +f 7091 7140 7143 +f 7091 7143 7147 +f 7091 7147 7253 +f 7091 7253 7071 +f 7901 7930 7784 +f 7784 7930 7830 +f 7784 7830 7702 +f 7702 7830 7698 +f 7702 7698 7543 +f 7543 7698 7604 +f 7543 7604 7512 +f 7512 7604 7506 +f 7512 7506 7307 +f 7307 7506 7380 +f 7307 7380 7158 +f 7158 7380 7222 +f 7158 7222 7015 +f 7015 7222 7022 +f 7015 7022 6982 +f 6982 7022 6952 +f 6982 6952 6850 +f 6850 6952 6800 +f 6850 6800 6637 +f 6637 6800 6596 +f 6637 6596 6481 +f 6481 6596 6572 +f 6481 6572 6446 +f 6446 6572 6460 +f 6446 6460 6289 +f 6289 6460 6232 +f 6289 6232 6200 +f 6200 6232 6106 +f 6200 6106 6041 +f 6041 6106 5972 +f 6041 5972 5912 +f 5912 5972 5866 +f 5912 5866 5796 +f 5796 5866 5730 +f 5796 5730 5574 +f 5574 5730 5622 +f 5574 5622 5487 +f 5487 5622 5466 +f 5487 5466 5311 +f 5311 5466 5404 +f 5311 5404 5164 +f 5164 5404 5170 +f 5164 5170 5024 +f 5024 5170 5140 +f 5024 5140 4921 +f 4921 5140 4972 +f 4921 4972 4842 +f 4842 4972 4772 +f 4842 4772 4754 +f 4754 4772 4652 +f 4754 4652 4523 +f 4523 4652 4502 +f 4523 4502 4473 +f 4473 4502 4488 +f 4473 4488 4335 +f 4335 4488 4232 +f 4335 4232 4104 +f 4104 4232 4128 +f 4104 4128 3982 +f 3982 4128 3990 +f 3982 3990 3946 +f 3946 3990 3944 +f 3946 3944 3826 +f 3826 3944 3786 +f 3826 3786 3594 +f 3594 3786 3696 +f 3594 3696 3446 +f 3446 3696 3566 +f 3446 3566 3382 +f 3382 3566 3410 +f 3382 3410 3298 +f 3298 3410 3252 +f 3298 3252 3088 +f 3088 3252 3156 +f 3088 3156 3012 +f 3012 3156 2924 +f 3012 2924 2775 +f 2775 2924 2898 +f 2775 2898 2757 +f 2757 2898 2738 +f 2757 2738 2610 +f 2610 2738 2624 +f 2610 2624 2411 +f 2411 2624 2464 +f 2411 2464 2340 +f 2340 2464 2224 +f 2340 2224 2160 +f 2160 2224 2212 +f 2160 2212 1969 +f 1969 2212 2068 +f 1969 2068 1832 +f 1832 2068 1908 +f 1832 1908 1775 +f 1775 1908 1724 +f 1775 1724 1627 +f 1627 1724 1620 +f 1627 1620 1469 +f 1469 1620 1534 +f 1469 1534 1442 +f 1442 1534 1340 +f 1442 1340 1267 +f 1267 1340 1234 +f 1267 1234 1120 +f 1120 1234 1180 +f 1120 1180 1023 +f 1023 1180 1040 +f 1023 1040 814 +f 814 1040 928 +f 814 928 719 +f 719 928 780 +f 719 780 584 +f 584 780 624 +f 584 624 444 +f 444 624 452 +f 444 452 294 +f 294 452 390 +f 294 390 254 +f 254 390 196 +f 254 196 89 +f 89 196 40 +f 89 40 17 +f 7402 7358 7518 +f 7518 7358 7429 +f 7518 7429 7522 +f 7522 7429 7580 +f 7522 7580 7637 +f 156 133 244 +f 244 133 245 +f 244 245 368 +f 368 245 383 +f 368 383 445 +f 445 383 456 +f 445 456 575 +f 575 456 663 +f 575 663 773 +f 773 663 728 +f 773 728 912 +f 912 728 871 +f 912 871 1038 +f 1038 871 952 +f 1038 952 1175 +f 1175 952 1184 +f 1175 1184 1307 +f 1307 1184 1228 +f 1307 1228 1443 +f 1443 1228 1444 +f 1443 1444 1465 +f 1465 1444 1510 +f 1465 1510 1580 +f 1580 1510 1653 +f 1580 1653 1800 +f 1800 1653 1709 +f 1800 1709 1876 +f 1876 1709 1883 +f 1876 1883 1958 +f 1958 1883 1964 +f 1958 1964 2196 +f 2196 1964 2187 +f 2196 2187 2300 +f 2300 2187 2239 +f 2300 2239 2412 +f 2412 2239 2396 +f 2412 2396 2568 +f 2568 2396 2592 +f 2568 2592 2642 +f 2642 2592 2718 +f 2642 2718 2814 +f 2814 2718 2865 +f 2814 2865 2950 +f 2950 2865 3023 +f 2950 3023 3065 +f 3065 3023 3110 +f 3065 3110 3278 +f 3278 3110 3284 +f 3278 3284 3419 +f 3419 3284 3330 +f 3419 3330 3479 +f 3479 3330 3544 +f 3479 3544 3600 +f 3600 3544 3613 +f 3600 3613 3806 +f 3806 3613 3752 +f 3806 3752 3919 +f 3919 3752 3866 +f 3919 3866 4084 +f 4084 3866 3996 +f 4084 3996 4194 +f 4194 3996 4216 +f 4194 4216 4290 +f 4290 4216 4240 +f 4290 4240 4387 +f 4387 4240 4437 +f 4387 4437 4567 +f 4567 4437 4516 +f 4567 4516 4728 +f 4728 4516 4690 +f 4728 4690 4798 +f 4798 4690 4858 +f 4798 4858 4909 +f 4909 4858 4942 +f 4909 4942 5054 +f 5054 4942 5118 +f 5054 5118 5221 +f 5221 5118 5231 +f 5221 5231 5290 +f 5290 5231 5332 +f 5290 5332 5490 +f 5490 5332 5456 +f 5490 5456 5650 +f 5650 5456 5584 +f 5650 5584 5706 +f 5706 5584 5792 +f 5706 5792 5924 +f 5924 5792 5844 +f 5924 5844 6042 +f 6042 5844 6058 +f 6042 6058 6181 +f 6181 6058 6116 +f 6181 6116 6304 +f 6304 6116 6204 +f 6304 6204 6360 +f 6360 6204 6375 +f 6360 6375 6496 +f 6496 6375 6532 +f 6496 6532 6716 +f 6716 6532 6718 +f 6716 6718 6843 +f 6843 6718 6803 +f 6843 6803 6881 +f 6881 6803 6862 +f 6881 6862 7042 +f 7042 6862 7071 +f 7042 7071 7156 +f 7156 7071 7253 +f 7156 7253 7312 +f 7312 7253 7386 +f 7312 7386 7516 +f 7516 7386 7404 +f 7516 7404 7520 +f 7918 7899 7852 +f 7852 7899 7786 +f 7852 7786 7654 +f 7654 7786 7736 +f 7654 7736 7578 +f 7578 7736 7568 +f 7578 7568 7471 +f 7471 7568 7490 +f 7471 7490 7374 +f 7374 7490 7340 +f 7374 7340 7178 +f 7178 7340 7152 +f 7178 7152 7019 +f 7019 7152 7094 +f 7019 7094 6970 +f 6970 7094 6915 +f 6970 6915 6732 +f 6732 6915 6749 +f 6732 6749 6620 +f 6620 6749 6609 +f 6620 6609 6533 +f 6533 6609 6574 +f 6533 6574 6350 +f 6350 6574 6416 +f 6350 6416 6296 +f 6296 6416 6239 +f 6296 6239 6182 +f 6182 6239 6082 +f 6182 6082 5992 +f 5992 6082 5964 +f 5992 5964 5913 +f 5913 5964 5814 +f 5913 5814 5780 +f 5780 5814 5699 +f 5780 5699 5596 +f 5596 5699 5555 +f 5596 5555 5432 +f 5432 5555 5516 +f 5432 5516 5379 +f 5379 5516 5410 +f 5379 5410 5194 +f 5194 5410 5245 +f 5194 5245 5124 +f 5124 5245 5036 +f 5124 5036 4944 +f 4944 5036 4998 +f 4944 4998 4875 +f 4875 4998 4834 +f 4875 4834 4695 +f 4695 4834 4642 +f 4695 4642 4596 +f 4596 4642 4592 +f 4596 4592 4384 +f 4384 4592 4425 +f 4384 4425 4330 +f 4330 4425 4302 +f 4330 4302 4222 +f 4222 4302 4176 +f 4222 4176 4054 +f 4054 4176 4029 +f 4054 4029 3859 +f 3859 4029 3913 +f 3859 3913 3812 +f 3812 3913 3784 +f 3812 3784 3692 +f 3692 3784 3645 +f 3692 3645 3499 +f 3499 3645 3535 +f 3499 3535 3394 +f 3394 3535 3328 +f 3394 3328 3214 +f 3214 3328 3177 +f 3214 3177 3143 +f 3143 3177 3134 +f 3143 3134 2939 +f 2939 3134 2932 +f 2939 2932 2895 +f 2895 2932 2896 +f 2895 2896 2666 +f 2666 2896 2706 +f 2666 2706 2506 +f 2506 2706 2522 +f 2506 2522 2436 +f 2436 2522 2420 +f 2436 2420 2220 +f 2220 2420 2285 +f 2220 2285 2206 +f 2206 2285 2188 +f 2206 2188 1990 +f 1990 2188 1970 +f 1990 1970 1847 +f 1847 1970 1884 +f 1847 1884 1770 +f 1770 1884 1766 +f 1770 1766 1695 +f 1695 1766 1601 +f 1695 1601 1456 +f 1456 1601 1552 +f 1456 1552 1328 +f 1328 1552 1354 +f 1328 1354 1280 +f 1280 1354 1287 +f 1280 1287 1148 +f 1148 1287 1078 +f 1148 1078 938 +f 938 1078 1009 +f 938 1009 858 +f 858 1009 877 +f 858 877 756 +f 756 877 764 +f 756 764 559 +f 559 764 576 +f 559 576 438 +f 438 576 528 +f 438 528 330 +f 330 528 338 +f 330 338 250 +f 250 338 292 +f 250 292 164 +f 164 292 76 +f 164 76 5 +f 138 40 240 +f 240 40 196 +f 240 196 388 +f 388 196 390 +f 388 390 500 +f 500 390 452 +f 500 452 556 +f 556 452 624 +f 556 624 724 +f 724 624 780 +f 724 780 930 +f 930 780 928 +f 930 928 1058 +f 1058 928 1040 +f 1058 1040 1102 +f 1102 1040 1180 +f 1102 1180 1304 +f 1304 1180 1234 +f 1304 1234 1402 +f 1402 1234 1340 +f 1402 1340 1476 +f 1476 1340 1534 +f 1476 1534 1690 +f 1690 1534 1620 +f 1690 1620 1798 +f 1798 1620 1724 +f 1798 1724 1880 +f 1880 1724 1908 +f 1880 1908 2054 +f 2054 1908 2068 +f 2054 2068 2106 +f 2106 2068 2212 +f 2106 2212 2270 +f 2270 2212 2224 +f 2270 2224 2386 +f 2386 2224 2464 +f 2386 2464 2532 +f 2532 2464 2624 +f 2532 2624 2754 +f 2754 2624 2738 +f 2754 2738 2828 +f 2828 2738 2898 +f 2828 2898 2934 +f 2934 2898 2924 +f 2934 2924 3116 +f 3116 2924 3156 +f 3116 3156 3294 +f 3294 3156 3252 +f 3294 3252 3376 +f 3376 3252 3410 +f 3376 3410 3564 +f 3564 3410 3566 +f 3564 3566 3658 +f 3658 3566 3696 +f 3658 3696 3740 +f 3740 3696 3786 +f 3740 3786 3936 +f 3936 3786 3944 +f 3936 3944 4036 +f 4036 3944 3990 +f 4036 3990 4210 +f 4210 3990 4128 +f 4210 4128 4320 +f 4320 4128 4232 +f 4320 4232 4382 +f 4382 4232 4488 +f 4382 4488 4556 +f 4556 4488 4502 +f 4556 4502 4672 +f 4672 4502 4652 +f 4672 4652 4850 +f 4850 4652 4772 +f 4850 4772 5014 +f 5014 4772 4972 +f 5014 4972 5126 +f 5126 4972 5140 +f 5126 5140 5200 +f 5200 5140 5170 +f 5200 5170 5288 +f 5288 5170 5404 +f 5288 5404 5528 +f 5528 5404 5466 +f 5528 5466 5668 +f 5668 5466 5622 +f 5668 5622 5754 +f 5754 5622 5730 +f 5754 5730 5812 +f 5812 5730 5866 +f 5812 5866 6018 +f 6018 5866 5972 +f 6018 5972 6174 +f 6174 5972 6106 +f 6174 6106 6260 +f 6260 6106 6232 +f 6260 6232 6420 +f 6420 6232 6460 +f 6420 6460 6548 +f 6548 6460 6572 +f 6548 6572 6618 +f 6618 6572 6596 +f 6618 6596 6818 +f 6818 6596 6800 +f 6818 6800 6874 +f 6874 6800 6952 +f 6874 6952 7028 +f 7028 6952 7022 +f 7028 7022 7182 +f 7182 7022 7222 +f 7182 7222 7364 +f 7364 7222 7380 +f 7364 7380 7416 +f 7416 7380 7506 +f 7416 7506 7530 +f 7530 7506 7604 +f 7530 7604 7666 +f 7666 7604 7698 +f 7666 7698 7866 +f 7866 7698 7830 +f 7866 7830 7930 +f 62 138 206 +f 206 138 240 +f 206 240 318 +f 318 240 388 +f 318 388 525 +f 525 388 500 +f 525 500 630 +f 630 500 556 +f 630 556 702 +f 702 556 724 +f 702 724 859 +f 859 724 930 +f 859 930 1028 +f 1028 930 1058 +f 1028 1058 1100 +f 1100 1058 1102 +f 1100 1102 1282 +f 1282 1102 1304 +f 1282 1304 1318 +f 1318 1304 1402 +f 1318 1402 1538 +f 1538 1402 1476 +f 1538 1476 1660 +f 1660 1476 1690 +f 1660 1690 1730 +f 1730 1690 1798 +f 1730 1798 1936 +f 1936 1798 1880 +f 1936 1880 2028 +f 2028 1880 2054 +f 2028 2054 2190 +f 2190 2054 2106 +f 2190 2106 2330 +f 2330 2106 2270 +f 2330 2270 2442 +f 2442 2270 2386 +f 2442 2386 2626 +f 2626 2386 2532 +f 2626 2532 2752 +f 2752 2532 2754 +f 2752 2754 2892 +f 2892 2754 2828 +f 2892 2828 2928 +f 2928 2828 2934 +f 2928 2934 3162 +f 3162 2934 3116 +f 3162 3116 3220 +f 3220 3116 3294 +f 3220 3294 3354 +f 3354 3294 3376 +f 3354 3376 3484 +f 3484 3376 3564 +f 3484 3564 3628 +f 3628 3564 3658 +f 3628 3658 3720 +f 3720 3658 3740 +f 3720 3740 3958 +f 3958 3740 3936 +f 3958 3936 4016 +f 4016 3936 4036 +f 4016 4036 4110 +f 4110 4036 4210 +f 4110 4210 4348 +f 4348 4210 4320 +f 4348 4320 4490 +f 4490 4320 4382 +f 4490 4382 4594 +f 4594 4382 4556 +f 4594 4556 4740 +f 4740 4556 4672 +f 4740 4672 4800 +f 4800 4672 4850 +f 4800 4850 5012 +f 5012 4850 5014 +f 5012 5014 5057 +f 5057 5014 5126 +f 5057 5126 5190 +f 5190 5126 5200 +f 5190 5200 5304 +f 5304 5200 5288 +f 5304 5288 5518 +f 5518 5288 5528 +f 5518 5528 5614 +f 5614 5528 5668 +f 5614 5668 5712 +f 5712 5668 5754 +f 5712 5754 5828 +f 5828 5754 5812 +f 5828 5812 5984 +f 5984 5812 6018 +f 5984 6018 6118 +f 6118 6018 6174 +f 6118 6174 6258 +f 6258 6174 6260 +f 6258 6260 6451 +f 6451 6260 6420 +f 6451 6420 6486 +f 6486 6420 6548 +f 6486 6548 6710 +f 6710 6548 6618 +f 6710 6618 6752 +f 6752 6618 6818 +f 6752 6818 6906 +f 6906 6818 6874 +f 6906 6874 7046 +f 7046 6874 7028 +f 7046 7028 7260 +f 7260 7028 7182 +f 7260 7182 7290 +f 7290 7182 7364 +f 7290 7364 7424 +f 7424 7364 7416 +f 7424 7416 7570 +f 7570 7416 7530 +f 7570 7530 7730 +f 7730 7530 7666 +f 7730 7666 7858 +f 7858 7666 7866 +f 7858 7866 7934 +f 98 62 261 +f 261 62 206 +f 261 206 378 +f 378 206 318 +f 378 318 428 +f 428 318 525 +f 428 525 589 +f 589 525 630 +f 589 630 802 +f 802 630 702 +f 802 702 824 +f 824 702 859 +f 824 859 946 +f 946 859 1028 +f 946 1028 1166 +f 1166 1028 1100 +f 1166 1100 1223 +f 1223 1100 1282 +f 1223 1282 1400 +f 1400 1282 1318 +f 1400 1318 1570 +f 1570 1318 1538 +f 1570 1538 1680 +f 1680 1538 1660 +f 1680 1660 1810 +f 1810 1660 1730 +f 1810 1730 1910 +f 1910 1730 1936 +f 1910 1936 2048 +f 2048 1936 2028 +f 2048 2028 2136 +f 2136 2028 2190 +f 2136 2190 2216 +f 2216 2190 2330 +f 2216 2330 2478 +f 2478 2330 2442 +f 2478 2442 2510 +f 2510 2442 2626 +f 2510 2626 2658 +f 2658 2626 2752 +f 2658 2752 2888 +f 2888 2752 2892 +f 2888 2892 3000 +f 3000 2892 2928 +f 3000 2928 3070 +f 3070 2928 3162 +f 3070 3162 3188 +f 3188 3162 3220 +f 3188 3220 3348 +f 3348 3220 3354 +f 3348 3354 3440 +f 3440 3354 3484 +f 3440 3484 3588 +f 3588 3484 3628 +f 3588 3628 3828 +f 3828 3628 3720 +f 3828 3720 3876 +f 3876 3720 3958 +f 3876 3958 3998 +f 3998 3958 4016 +f 3998 4016 4140 +f 4140 4016 4110 +f 4140 4110 4250 +f 4250 4110 4348 +f 4250 4348 4402 +f 4402 4348 4490 +f 4402 4490 4610 +f 4610 4490 4594 +f 4610 4594 4650 +f 4650 4594 4740 +f 4650 4740 4762 +f 4762 4740 4800 +f 4762 4800 4996 +f 4996 4800 5012 +f 4996 5012 5092 +f 5092 5012 5057 +f 5092 5057 5168 +f 5168 5057 5190 +f 5168 5190 5334 +f 5334 5190 5304 +f 5334 5304 5484 +f 5484 5304 5518 +f 5484 5518 5588 +f 5588 5518 5614 +f 5588 5614 5770 +f 5770 5614 5712 +f 5770 5712 5836 +f 5836 5712 5828 +f 5836 5828 5953 +f 5953 5828 5984 +f 5953 5984 6170 +f 6170 5984 6118 +f 6170 6118 6254 +f 6254 6118 6258 +f 6254 6258 6344 +f 6344 6258 6451 +f 6344 6451 6594 +f 6594 6451 6486 +f 6594 6486 6656 +f 6656 6486 6710 +f 6656 6710 6827 +f 6827 6710 6752 +f 6827 6752 6918 +f 6918 6752 6906 +f 6918 6906 7118 +f 7118 6906 7046 +f 7118 7046 7174 +f 7174 7046 7260 +f 7174 7260 7378 +f 7378 7260 7290 +f 7378 7290 7488 +f 7488 7290 7424 +f 7488 7424 7610 +f 7610 7424 7570 +f 7610 7570 7678 +f 7678 7570 7730 +f 7678 7730 7838 +f 7838 7730 7858 +f 7838 7858 7915 +f 60 98 278 +f 278 98 261 +f 278 261 298 +f 298 261 378 +f 298 378 488 +f 488 378 428 +f 488 428 610 +f 610 428 589 +f 610 589 712 +f 712 589 802 +f 712 802 822 +f 822 802 824 +f 822 824 1060 +f 1060 824 946 +f 1060 946 1140 +f 1140 946 1166 +f 1140 1166 1232 +f 1232 1166 1223 +f 1232 1223 1320 +f 1320 1223 1400 +f 1320 1400 1488 +f 1488 1400 1570 +f 1488 1570 1700 +f 1700 1570 1680 +f 1700 1680 1780 +f 1780 1680 1810 +f 1780 1810 1836 +f 1836 1810 1910 +f 1836 1910 1988 +f 1988 1910 2048 +f 1988 2048 2168 +f 2168 2048 2136 +f 2168 2136 2294 +f 2294 2136 2216 +f 2294 2216 2366 +f 2366 2216 2478 +f 2366 2478 2512 +f 2512 2478 2510 +f 2512 2510 2728 +f 2728 2510 2658 +f 2728 2658 2876 +f 2876 2658 2888 +f 2876 2888 3008 +f 3008 2888 3000 +f 3008 3000 3042 +f 3042 3000 3070 +f 3042 3070 3216 +f 3216 3070 3188 +f 3216 3188 3380 +f 3380 3188 3348 +f 3380 3348 3466 +f 3466 3348 3440 +f 3466 3440 3686 +f 3686 3440 3588 +f 3686 3588 3744 +f 3744 3588 3828 +f 3744 3828 3954 +f 3954 3828 3876 +f 3954 3876 4042 +f 4042 3876 3998 +f 4042 3998 4116 +f 4116 3998 4140 +f 4116 4140 4310 +f 4310 4140 4250 +f 4310 4250 4414 +f 4414 4250 4402 +f 4414 4402 4620 +f 4620 4402 4610 +f 4620 4610 4654 +f 4654 4610 4650 +f 4654 4650 4832 +f 4832 4650 4762 +f 4832 4762 4982 +f 4982 4762 4996 +f 4982 4996 5134 +f 5134 4996 5092 +f 5134 5092 5280 +f 5280 5092 5168 +f 5280 5168 5358 +f 5358 5168 5334 +f 5358 5334 5512 +f 5512 5334 5484 +f 5512 5484 5568 +f 5568 5484 5588 +f 5568 5588 5718 +f 5718 5588 5770 +f 5718 5770 5870 +f 5870 5770 5836 +f 5870 5836 5980 +f 5980 5836 5953 +f 5980 5953 6156 +f 6156 5953 6170 +f 6156 6170 6208 +f 6208 6170 6254 +f 6208 6254 6442 +f 6442 6254 6344 +f 6442 6344 6546 +f 6546 6344 6594 +f 6546 6594 6648 +f 6648 6594 6656 +f 6648 6656 6770 +f 6770 6656 6827 +f 6770 6827 6956 +f 6956 6827 6918 +f 6956 6918 7114 +f 7114 6918 7118 +f 7114 7118 7234 +f 7234 7118 7174 +f 7234 7174 7292 +f 7292 7174 7378 +f 7292 7378 7454 +f 7454 7378 7488 +f 7454 7488 7552 +f 7552 7488 7610 +f 7552 7610 7744 +f 7744 7610 7678 +f 7744 7678 7802 +f 7802 7678 7838 +f 7802 7838 7932 +f 149 60 190 +f 190 60 278 +f 190 278 304 +f 304 278 298 +f 304 298 538 +f 538 298 488 +f 538 488 592 +f 592 488 610 +f 592 610 705 +f 705 610 712 +f 705 712 894 +f 894 712 822 +f 894 822 1020 +f 1020 822 1060 +f 1020 1060 1080 +f 1080 1060 1140 +f 1080 1140 1268 +f 1268 1140 1232 +f 1268 1232 1355 +f 1355 1232 1320 +f 1355 1320 1496 +f 1496 1320 1488 +f 1496 1488 1632 +f 1632 1488 1700 +f 1632 1700 1826 +f 1826 1700 1780 +f 1826 1780 1905 +f 1905 1780 1836 +f 1905 1836 2060 +f 2060 1836 1988 +f 2060 1988 2108 +f 2108 1988 2168 +f 2108 2168 2336 +f 2336 2168 2294 +f 2336 2294 2376 +f 2376 2294 2366 +f 2376 2366 2614 +f 2614 2366 2512 +f 2614 2512 2730 +f 2730 2512 2728 +f 2730 2728 2784 +f 2784 2728 2876 +f 2784 2876 2914 +f 2914 2876 3008 +f 2914 3008 3060 +f 3060 3008 3042 +f 3060 3042 3180 +f 3180 3042 3216 +f 3180 3216 3398 +f 3398 3216 3380 +f 3398 3380 3492 +f 3492 3380 3466 +f 3492 3466 3580 +f 3580 3466 3686 +f 3580 3686 3816 +f 3816 3686 3744 +f 3816 3744 3928 +f 3928 3744 3954 +f 3928 3954 4065 +f 4065 3954 4042 +f 4065 4042 4152 +f 4152 4042 4116 +f 4152 4116 4276 +f 4276 4116 4310 +f 4276 4310 4470 +f 4470 4310 4414 +f 4470 4414 4544 +f 4544 4414 4620 +f 4544 4620 4674 +f 4674 4620 4654 +f 4674 4654 4766 +f 4766 4654 4832 +f 4766 4832 4940 +f 4940 4832 4982 +f 4940 4982 5052 +f 5052 4982 5134 +f 5052 5134 5234 +f 5234 5134 5280 +f 5234 5280 5364 +f 5364 5280 5358 +f 5364 5358 5434 +f 5434 5358 5512 +f 5434 5512 5594 +f 5594 5512 5568 +f 5594 5568 5790 +f 5790 5568 5718 +f 5790 5718 5849 +f 5849 5718 5870 +f 5849 5870 5970 +f 5970 5870 5980 +f 5970 5980 6188 +f 6188 5980 6156 +f 6188 6156 6266 +f 6266 6156 6208 +f 6266 6208 6448 +f 6448 6208 6442 +f 6448 6442 6528 +f 6528 6442 6546 +f 6528 6546 6634 +f 6634 6546 6648 +f 6634 6648 6796 +f 6796 6648 6770 +f 6796 6770 6940 +f 6940 6770 6956 +f 6940 6956 7084 +f 7084 6956 7114 +f 7084 7114 7179 +f 7179 7114 7234 +f 7179 7234 7316 +f 7316 7234 7292 +f 7316 7292 7476 +f 7476 7292 7454 +f 7476 7454 7524 +f 7524 7454 7552 +f 7524 7552 7705 +f 7705 7552 7744 +f 7705 7744 7791 +f 7791 7744 7802 +f 7791 7802 7903 +f 94 149 187 +f 187 149 190 +f 187 190 412 +f 412 190 304 +f 412 304 426 +f 426 304 538 +f 426 538 642 +f 642 538 592 +f 642 592 709 +f 709 592 705 +f 709 705 891 +f 891 705 894 +f 891 894 1050 +f 1050 894 1020 +f 1050 1020 1130 +f 1130 1020 1080 +f 1130 1080 1296 +f 1296 1080 1268 +f 1296 1268 1322 +f 1322 1268 1355 +f 1322 1355 1450 +f 1450 1355 1496 +f 1450 1496 1692 +f 1692 1496 1632 +f 1692 1632 1702 +f 1702 1632 1826 +f 1702 1826 1950 +f 1950 1826 1905 +f 1950 1905 1998 +f 1998 1905 2060 +f 1998 2060 2204 +f 2204 2060 2108 +f 2204 2108 2275 +f 2275 2108 2336 +f 2275 2336 2362 +f 2362 2336 2376 +f 2362 2376 2536 +f 2536 2376 2614 +f 2536 2614 2640 +f 2640 2614 2730 +f 2640 2730 2820 +f 2820 2730 2784 +f 2820 2784 3006 +f 3006 2784 2914 +f 3006 2914 3058 +f 3058 2914 3060 +f 3058 3060 3212 +f 3212 3060 3180 +f 3212 3180 3430 +f 3430 3180 3398 +f 3430 3398 3512 +f 3512 3398 3492 +f 3512 3492 3592 +f 3592 3492 3580 +f 3592 3580 3780 +f 3780 3580 3816 +f 3780 3816 3848 +f 3848 3816 3928 +f 3848 3928 4012 +f 4012 3928 4065 +f 4012 4065 4198 +f 4198 4065 4152 +f 4198 4152 4268 +f 4268 4152 4276 +f 4268 4276 4364 +f 4364 4276 4470 +f 4364 4470 4532 +f 4532 4470 4544 +f 4532 4544 4646 +f 4646 4544 4674 +f 4646 4674 4796 +f 4796 4674 4766 +f 4796 4766 4980 +f 4980 4766 4940 +f 4980 4940 5150 +f 5150 4940 5052 +f 5150 5052 5186 +f 5186 5052 5234 +f 5186 5234 5324 +f 5324 5234 5364 +f 5324 5364 5464 +f 5464 5364 5434 +f 5464 5434 5670 +f 5670 5434 5594 +f 5670 5594 5686 +f 5686 5594 5790 +f 5686 5790 5830 +f 5830 5790 5849 +f 5830 5849 6064 +f 6064 5849 5970 +f 6064 5970 6094 +f 6094 5970 6188 +f 6094 6188 6235 +f 6235 6188 6266 +f 6235 6266 6432 +f 6432 6266 6448 +f 6432 6448 6512 +f 6512 6448 6528 +f 6512 6528 6650 +f 6650 6528 6634 +f 6650 6634 6816 +f 6816 6634 6796 +f 6816 6796 6938 +f 6938 6796 6940 +f 6938 6940 7085 +f 7085 6940 7084 +f 7085 7084 7205 +f 7205 7084 7179 +f 7205 7179 7328 +f 7328 7179 7316 +f 7328 7316 7484 +f 7484 7316 7476 +f 7484 7476 7555 +f 7555 7476 7524 +f 7555 7524 7712 +f 7712 7524 7705 +f 7712 7705 7788 +f 7788 7705 7791 +f 7788 7791 7889 +f 124 94 290 +f 290 94 187 +f 290 187 314 +f 314 187 412 +f 314 412 536 +f 536 412 426 +f 536 426 599 +f 599 426 642 +f 599 642 720 +f 720 642 709 +f 720 709 808 +f 808 709 891 +f 808 891 996 +f 996 891 1050 +f 996 1050 1188 +f 1188 1050 1130 +f 1188 1130 1254 +f 1254 1130 1296 +f 1254 1296 1342 +f 1342 1296 1322 +f 1342 1322 1523 +f 1523 1322 1450 +f 1523 1450 1636 +f 1636 1450 1692 +f 1636 1692 1816 +f 1816 1692 1702 +f 1816 1702 1940 +f 1940 1702 1950 +f 1940 1950 1974 +f 1974 1950 1998 +f 1974 1998 2192 +f 2192 1998 2204 +f 2192 2204 2318 +f 2318 2204 2275 +f 2318 2275 2370 +f 2370 2275 2362 +f 2370 2362 2530 +f 2530 2362 2536 +f 2530 2536 2724 +f 2724 2536 2640 +f 2724 2640 2806 +f 2806 2640 2820 +f 2806 2820 2942 +f 2942 2820 3006 +f 2942 3006 3148 +f 3148 3006 3058 +f 3148 3058 3292 +f 3292 3058 3212 +f 3292 3212 3396 +f 3396 3212 3430 +f 3396 3430 3532 +f 3532 3430 3512 +f 3532 3512 3602 +f 3602 3512 3592 +f 3602 3592 3792 +f 3792 3592 3780 +f 3792 3780 3884 +f 3884 3780 3848 +f 3884 3848 4080 +f 4080 3848 4012 +f 4080 4012 4132 +f 4132 4012 4198 +f 4132 4198 4328 +f 4328 4198 4268 +f 4328 4268 4438 +f 4438 4268 4364 +f 4438 4364 4548 +f 4548 4364 4532 +f 4548 4532 4644 +f 4644 4532 4646 +f 4644 4646 4790 +f 4790 4646 4796 +f 4790 4796 4984 +f 4984 4796 4980 +f 4984 4980 5114 +f 5114 4980 5150 +f 5114 5150 5228 +f 5228 5150 5186 +f 5228 5186 5414 +f 5414 5186 5324 +f 5414 5324 5427 +f 5427 5324 5464 +f 5427 5464 5609 +f 5609 5464 5670 +f 5609 5670 5743 +f 5743 5670 5686 +f 5743 5686 5846 +f 5846 5686 5830 +f 5846 5830 6060 +f 6060 5830 6064 +f 6060 6064 6130 +f 6130 6064 6094 +f 6130 6094 6274 +f 6274 6094 6235 +f 6274 6235 6454 +f 6454 6235 6432 +f 6454 6432 6502 +f 6502 6432 6512 +f 6502 6512 6666 +f 6666 6512 6650 +f 6666 6650 6820 +f 6820 6650 6816 +f 6820 6816 6871 +f 6871 6816 6938 +f 6871 6938 7040 +f 7040 6938 7085 +f 7040 7085 7228 +f 7228 7085 7205 +f 7228 7205 7302 +f 7302 7205 7328 +f 7302 7328 7472 +f 7472 7328 7484 +f 7472 7484 7556 +f 7556 7484 7555 +f 7556 7555 7644 +f 7644 7555 7712 +f 7644 7712 7848 +f 7848 7712 7788 +f 7848 7788 7888 +f 142 124 266 +f 266 124 290 +f 266 290 335 +f 335 290 314 +f 335 314 432 +f 432 314 536 +f 432 536 604 +f 604 536 599 +f 604 599 726 +f 726 599 720 +f 726 720 830 +f 830 720 808 +f 830 808 1042 +f 1042 808 996 +f 1042 996 1107 +f 1107 996 1188 +f 1107 1188 1190 +f 1190 1188 1254 +f 1190 1254 1437 +f 1437 1254 1342 +f 1437 1342 1553 +f 1553 1342 1523 +f 1553 1523 1662 +f 1662 1523 1636 +f 1662 1636 1776 +f 1776 1636 1816 +f 1776 1816 1859 +f 1859 1816 1940 +f 1859 1940 1992 +f 1992 1940 1974 +f 1992 1974 2113 +f 2113 1974 2192 +f 2113 2192 2249 +f 2249 2192 2318 +f 2249 2318 2380 +f 2380 2318 2370 +f 2380 2370 2608 +f 2608 2370 2530 +f 2608 2530 2758 +f 2758 2530 2724 +f 2758 2724 2816 +f 2816 2724 2806 +f 2816 2806 2904 +f 2904 2806 2942 +f 2904 2942 3093 +f 3093 2942 3148 +f 3093 3148 3275 +f 3275 3148 3292 +f 3275 3292 3358 +f 3358 3292 3396 +f 3358 3396 3454 +f 3454 3396 3532 +f 3454 3532 3666 +f 3666 3532 3602 +f 3666 3602 3820 +f 3820 3602 3792 +f 3820 3792 3910 +f 3910 3792 3884 +f 3910 3884 4049 +f 4049 3884 4080 +f 4049 4080 4134 +f 4134 4080 4132 +f 4134 4132 4312 +f 4312 4132 4328 +f 4312 4328 4372 +f 4372 4328 4438 +f 4372 4438 4570 +f 4570 4438 4548 +f 4570 4548 4681 +f 4681 4548 4644 +f 4681 4644 4864 +f 4864 4644 4790 +f 4864 4790 4916 +f 4916 4790 4984 +f 4916 4984 5146 +f 5146 4984 5114 +f 5146 5114 5198 +f 5198 5114 5228 +f 5198 5228 5352 +f 5352 5228 5414 +f 5352 5414 5542 +f 5542 5414 5427 +f 5542 5427 5624 +f 5624 5427 5609 +f 5624 5609 5760 +f 5760 5609 5743 +f 5760 5743 5832 +f 5832 5743 5846 +f 5832 5846 6016 +f 6016 5846 6060 +f 6016 6060 6168 +f 6168 6060 6130 +f 6168 6130 6318 +f 6318 6130 6274 +f 6318 6274 6383 +f 6383 6274 6454 +f 6383 6454 6478 +f 6478 6454 6502 +f 6478 6502 6603 +f 6603 6502 6666 +f 6603 6666 6738 +f 6738 6666 6820 +f 6738 6820 6980 +f 6980 6820 6871 +f 6980 6871 7026 +f 7026 6871 7040 +f 7026 7040 7164 +f 7164 7040 7228 +f 7164 7228 7349 +f 7349 7228 7302 +f 7349 7302 7510 +f 7510 7302 7472 +f 7510 7472 7561 +f 7561 7472 7556 +f 7561 7556 7683 +f 7683 7556 7644 +f 7683 7644 7851 +f 7851 7644 7848 +f 7851 7848 7928 +f 150 142 227 +f 227 142 266 +f 227 266 316 +f 316 266 335 +f 316 335 512 +f 512 335 432 +f 512 432 600 +f 600 432 604 +f 600 604 804 +f 804 604 726 +f 804 726 881 +f 881 726 830 +f 881 830 1010 +f 1010 830 1042 +f 1010 1042 1073 +f 1073 1042 1107 +f 1073 1107 1214 +f 1214 1107 1190 +f 1214 1190 1345 +f 1345 1190 1437 +f 1345 1437 1536 +f 1536 1437 1553 +f 1536 1553 1613 +f 1613 1553 1662 +f 1613 1662 1785 +f 1785 1662 1776 +f 1785 1776 1906 +f 1906 1776 1859 +f 1906 1859 2017 +f 2017 1859 1992 +f 2017 1992 2176 +f 2176 1992 2113 +f 2176 2113 2254 +f 2254 2113 2249 +f 2254 2249 2372 +f 2372 2249 2380 +f 2372 2380 2500 +f 2500 2380 2608 +f 2500 2608 2638 +f 2638 2608 2758 +f 2638 2758 2781 +f 2781 2758 2816 +f 2781 2816 2918 +f 2918 2816 2904 +f 2918 2904 3152 +f 3152 2904 3093 +f 3152 3093 3260 +f 3260 3093 3275 +f 3260 3275 3420 +f 3420 3275 3358 +f 3420 3358 3490 +f 3490 3358 3454 +f 3490 3454 3698 +f 3698 3454 3666 +f 3698 3666 3797 +f 3797 3666 3820 +f 3797 3820 3872 +f 3872 3820 3910 +f 3872 3910 4062 +f 4062 3910 4049 +f 4062 4049 4137 +f 4137 4049 4134 +f 4137 4134 4242 +f 4242 4134 4312 +f 4242 4312 4458 +f 4458 4312 4372 +f 4458 4372 4504 +f 4504 4372 4570 +f 4504 4570 4682 +f 4682 4570 4681 +f 4682 4681 4782 +f 4782 4681 4864 +f 4782 4864 5003 +f 5003 4864 4916 +f 5003 4916 5029 +f 5029 4916 5146 +f 5029 5146 5278 +f 5278 5146 5198 +f 5278 5198 5296 +f 5296 5198 5352 +f 5296 5352 5530 +f 5530 5352 5542 +f 5530 5542 5602 +f 5602 5542 5624 +f 5602 5624 5778 +f 5778 5624 5760 +f 5778 5760 5840 +f 5840 5760 5832 +f 5840 5832 6010 +f 6010 5832 6016 +f 6010 6016 6088 +f 6088 6016 6168 +f 6088 6168 6307 +f 6307 6168 6318 +f 6307 6318 6376 +f 6376 6318 6383 +f 6376 6383 6497 +f 6497 6383 6478 +f 6497 6478 6654 +f 6654 6478 6603 +f 6654 6603 6746 +f 6746 6603 6738 +f 6746 6738 6976 +f 6976 6738 6980 +f 6976 6980 7020 +f 7020 6980 7026 +f 7020 7026 7238 +f 7238 7026 7164 +f 7238 7164 7334 +f 7334 7164 7349 +f 7334 7349 7412 +f 7412 7349 7510 +f 7412 7510 7594 +f 7594 7510 7561 +f 7594 7561 7728 +f 7728 7561 7683 +f 7728 7683 7871 +f 7871 7683 7851 +f 7871 7851 7882 +f 48 150 233 +f 233 150 227 +f 233 227 394 +f 394 227 316 +f 394 316 463 +f 463 316 512 +f 463 512 590 +f 590 512 600 +f 590 600 757 +f 757 600 804 +f 757 804 917 +f 917 804 881 +f 917 881 1035 +f 1035 881 1010 +f 1035 1010 1086 +f 1086 1010 1073 +f 1086 1073 1288 +f 1288 1073 1214 +f 1288 1214 1375 +f 1375 1214 1345 +f 1375 1345 1470 +f 1470 1345 1536 +f 1470 1536 1670 +f 1670 1536 1613 +f 1670 1613 1812 +f 1812 1613 1785 +f 1812 1785 1877 +f 1877 1785 1906 +f 1877 1906 2009 +f 2009 1906 2017 +f 2009 2017 2094 +f 2094 2017 2176 +f 2094 2176 2236 +f 2236 2176 2254 +f 2236 2254 2425 +f 2425 2254 2372 +f 2425 2372 2524 +f 2524 2372 2500 +f 2524 2500 2746 +f 2746 2500 2638 +f 2746 2638 2776 +f 2776 2638 2781 +f 2776 2781 3028 +f 3028 2781 2918 +f 3028 2918 3051 +f 3051 2918 3152 +f 3051 3152 3184 +f 3184 3152 3260 +f 3184 3260 3332 +f 3332 3260 3420 +f 3332 3420 3464 +f 3464 3420 3490 +f 3464 3490 3694 +f 3694 3490 3698 +f 3694 3698 3762 +f 3762 3698 3797 +f 3762 3797 3886 +f 3886 3797 3872 +f 3886 3872 4082 +f 4082 3872 4062 +f 4082 4062 4184 +f 4184 4062 4137 +f 4184 4137 4283 +f 4283 4137 4242 +f 4283 4242 4368 +f 4368 4242 4458 +f 4368 4458 4606 +f 4606 4458 4504 +f 4606 4504 4750 +f 4750 4504 4682 +f 4750 4682 4774 +f 4774 4682 4782 +f 4774 4782 4930 +f 4930 4782 5003 +f 4930 5003 5042 +f 5042 5003 5029 +f 5042 5029 5206 +f 5206 5029 5278 +f 5206 5278 5298 +f 5298 5278 5296 +f 5298 5296 5442 +f 5442 5296 5530 +f 5442 5530 5626 +f 5626 5530 5602 +f 5626 5602 5748 +f 5748 5602 5778 +f 5748 5778 5881 +f 5881 5778 5840 +f 5881 5840 6026 +f 6026 5840 6010 +f 6026 6010 6128 +f 6128 6010 6088 +f 6128 6088 6221 +f 6221 6088 6307 +f 6221 6307 6422 +f 6422 6307 6376 +f 6422 6376 6582 +f 6582 6376 6497 +f 6582 6497 6676 +f 6676 6497 6654 +f 6676 6654 6837 +f 6837 6654 6746 +f 6837 6746 6972 +f 6972 6746 6976 +f 6972 6976 7126 +f 7126 6976 7020 +f 7126 7020 7192 +f 7192 7020 7238 +f 7192 7238 7304 +f 7304 7238 7334 +f 7304 7334 7463 +f 7463 7334 7412 +f 7463 7412 7526 +f 7526 7412 7594 +f 7526 7594 7732 +f 7732 7594 7728 +f 7732 7728 7806 +f 7806 7728 7871 +f 7806 7871 7921 +f 65 48 280 +f 280 48 233 +f 280 233 343 +f 343 233 394 +f 343 394 540 +f 540 394 463 +f 540 463 628 +f 628 463 590 +f 628 590 758 +f 758 590 757 +f 758 757 812 +f 812 757 917 +f 812 917 1036 +f 1036 917 1035 +f 1036 1035 1097 +f 1097 1035 1086 +f 1097 1086 1274 +f 1274 1086 1288 +f 1274 1288 1398 +f 1398 1288 1375 +f 1398 1375 1461 +f 1461 1375 1470 +f 1461 1470 1696 +f 1696 1470 1670 +f 1696 1670 1744 +f 1744 1670 1812 +f 1744 1812 1944 +f 1944 1812 1877 +f 1944 1877 2018 +f 2018 1877 2009 +f 2018 2009 2090 +f 2090 2009 2094 +f 2090 2094 2272 +f 2272 2094 2236 +f 2272 2236 2468 +f 2468 2236 2425 +f 2468 2425 2578 +f 2578 2425 2524 +f 2578 2524 2660 +f 2660 2524 2746 +f 2660 2746 2778 +f 2778 2746 2776 +f 2778 2776 3018 +f 3018 2776 3028 +f 3018 3028 3090 +f 3090 3028 3051 +f 3090 3051 3290 +f 3290 3051 3184 +f 3290 3184 3406 +f 3406 3184 3332 +f 3406 3332 3541 +f 3541 3332 3464 +f 3541 3464 3604 +f 3604 3464 3694 +f 3604 3694 3768 +f 3768 3694 3762 +f 3768 3762 3949 +f 3949 3762 3886 +f 3949 3886 4002 +f 4002 3886 4082 +f 4002 4082 4169 +f 4169 4082 4184 +f 4169 4184 4336 +f 4336 4184 4283 +f 4336 4283 4422 +f 4422 4283 4368 +f 4422 4368 4526 +f 4526 4368 4606 +f 4526 4606 4658 +f 4658 4606 4750 +f 4658 4750 4852 +f 4852 4750 4774 +f 4852 4774 4932 +f 4932 4774 4930 +f 4932 4930 5034 +f 5034 4930 5042 +f 5034 5042 5262 +f 5262 5042 5206 +f 5262 5206 5380 +f 5380 5206 5298 +f 5380 5298 5462 +f 5462 5298 5442 +f 5462 5442 5580 +f 5580 5442 5626 +f 5580 5626 5787 +f 5787 5626 5748 +f 5787 5748 5914 +f 5914 5748 5881 +f 5914 5881 6012 +f 6012 5881 6026 +f 6012 6026 6090 +f 6090 6026 6128 +f 6090 6128 6301 +f 6301 6128 6221 +f 6301 6221 6456 +f 6456 6221 6422 +f 6456 6422 6578 +f 6578 6422 6582 +f 6578 6582 6661 +f 6661 6582 6676 +f 6661 6676 6742 +f 6742 6676 6837 +f 6742 6837 6864 +f 6864 6837 6972 +f 6864 6972 7062 +f 7062 6972 7126 +f 7062 7126 7187 +f 7187 7126 7192 +f 7187 7192 7368 +f 7368 7192 7304 +f 7368 7304 7430 +f 7430 7304 7463 +f 7430 7463 7598 +f 7598 7463 7526 +f 7598 7526 7742 +f 7742 7526 7732 +f 7742 7732 7864 +f 7864 7732 7806 +f 7864 7806 7922 +f 71 65 179 +f 179 65 280 +f 179 280 344 +f 344 280 343 +f 344 343 477 +f 477 343 540 +f 477 540 550 +f 550 540 628 +f 550 628 765 +f 765 628 758 +f 765 758 848 +f 848 758 812 +f 848 812 953 +f 953 812 1036 +f 953 1036 1074 +f 1074 1036 1097 +f 1074 1097 1297 +f 1297 1097 1274 +f 1297 1274 1421 +f 1421 1274 1398 +f 1421 1398 1481 +f 1481 1398 1461 +f 1481 1461 1686 +f 1686 1461 1696 +f 1686 1696 1755 +f 1755 1696 1744 +f 1755 1744 1860 +f 1860 1744 1944 +f 1860 1944 1999 +f 1999 1944 2018 +f 1999 2018 2161 +f 2161 2018 2090 +f 2161 2090 2262 +f 2262 2090 2272 +f 2262 2272 2470 +f 2470 2272 2468 +f 2470 2468 2586 +f 2586 2468 2578 +f 2586 2578 2682 +f 2682 2578 2660 +f 2682 2660 2878 +f 2878 2660 2778 +f 2878 2778 2922 +f 2922 2778 3018 +f 2922 3018 3094 +f 3094 3018 3090 +f 3094 3090 3254 +f 3254 3090 3290 +f 3254 3290 3403 +f 3403 3290 3406 +f 3403 3406 3519 +f 3519 3406 3541 +f 3519 3541 3619 +f 3619 3541 3604 +f 3619 3604 3800 +f 3800 3604 3768 +f 3800 3768 3862 +f 3862 3768 3949 +f 3862 3949 4010 +f 4010 3949 4002 +f 4010 4002 4202 +f 4202 4002 4169 +f 4202 4169 4284 +f 4284 4169 4336 +f 4284 4336 4388 +f 4388 4336 4422 +f 4388 4422 4578 +f 4578 4422 4526 +f 4578 4526 4632 +f 4632 4526 4658 +f 4632 4658 4793 +f 4793 4658 4852 +f 4793 4852 4960 +f 4960 4852 4932 +f 4960 4932 5144 +f 5144 4932 5034 +f 5144 5034 5182 +f 5182 5034 5262 +f 5182 5262 5322 +f 5322 5262 5380 +f 5322 5380 5522 +f 5522 5380 5462 +f 5522 5462 5645 +f 5645 5462 5580 +f 5645 5580 5757 +f 5757 5580 5787 +f 5757 5787 5822 +f 5822 5787 5914 +f 5822 5914 5958 +f 5958 5914 6012 +f 5958 6012 6148 +f 6148 6012 6090 +f 6148 6090 6250 +f 6250 6090 6301 +f 6250 6301 6408 +f 6408 6301 6456 +f 6408 6456 6588 +f 6588 6456 6578 +f 6588 6578 6700 +f 6700 6578 6661 +f 6700 6661 6854 +f 6854 6661 6742 +f 6854 6742 6932 +f 6932 6742 6864 +f 6932 6864 7116 +f 7116 6864 7062 +f 7116 7062 7168 +f 7168 7062 7187 +f 7168 7187 7287 +f 7287 7187 7368 +f 7287 7368 7474 +f 7474 7368 7430 +f 7474 7430 7618 +f 7618 7430 7598 +f 7618 7598 7646 +f 7646 7598 7742 +f 7646 7742 7862 +f 7862 7742 7864 +f 7862 7864 7933 +f 84 71 246 +f 246 71 179 +f 246 179 395 +f 395 179 344 +f 395 344 502 +f 502 344 477 +f 502 477 620 +f 620 477 550 +f 620 550 749 +f 749 550 765 +f 749 765 905 +f 905 765 848 +f 905 848 984 +f 984 848 953 +f 984 953 1156 +f 1156 953 1074 +f 1156 1074 1308 +f 1308 1074 1297 +f 1308 1297 1364 +f 1364 1297 1421 +f 1364 1421 1548 +f 1548 1421 1481 +f 1548 1481 1574 +f 1574 1481 1686 +f 1574 1686 1777 +f 1777 1686 1755 +f 1777 1755 1948 +f 1948 1755 1860 +f 1948 1860 1982 +f 1982 1860 1999 +f 1982 1999 2148 +f 2148 1999 2161 +f 2148 2161 2311 +f 2311 2161 2262 +f 2311 2262 2421 +f 2421 2262 2470 +f 2421 2470 2548 +f 2548 2470 2586 +f 2548 2586 2732 +f 2732 2586 2682 +f 2732 2682 2883 +f 2883 2682 2878 +f 2883 2878 2944 +f 2944 2878 2922 +f 2944 2922 3075 +f 3075 2922 3094 +f 3075 3094 3267 +f 3267 3094 3254 +f 3267 3254 3351 +f 3351 3254 3403 +f 3351 3403 3510 +f 3510 3403 3519 +f 3510 3519 3620 +f 3620 3519 3619 +f 3620 3619 3738 +f 3738 3619 3800 +f 3738 3800 3840 +f 3840 3800 3862 +f 3840 3862 3986 +f 3986 3862 4010 +f 3986 4010 4102 +f 4102 4010 4202 +f 4102 4202 4323 +f 4323 4202 4284 +f 4323 4284 4450 +f 4450 4284 4388 +f 4450 4388 4568 +f 4568 4388 4578 +f 4568 4578 4692 +f 4692 4578 4632 +f 4692 4632 4866 +f 4866 4632 4793 +f 4866 4793 4992 +f 4992 4793 4960 +f 4992 4960 5070 +f 5070 4960 5144 +f 5070 5144 5226 +f 5226 5144 5182 +f 5226 5182 5348 +f 5348 5182 5322 +f 5348 5322 5510 +f 5510 5322 5522 +f 5510 5522 5664 +f 5664 5522 5645 +f 5664 5645 5726 +f 5726 5645 5757 +f 5726 5757 5896 +f 5896 5757 5822 +f 5896 5822 5986 +f 5986 5822 5958 +f 5986 5958 6190 +f 6190 5958 6148 +f 6190 6148 6222 +f 6222 6148 6250 +f 6222 6250 6438 +f 6438 6250 6408 +f 6438 6408 6518 +f 6518 6408 6588 +f 6518 6588 6681 +f 6681 6588 6700 +f 6681 6700 6830 +f 6830 6700 6854 +f 6830 6854 6882 +f 6882 6854 6932 +f 6882 6932 7076 +f 7076 6932 7116 +f 7076 7116 7258 +f 7258 7116 7168 +f 7258 7168 7288 +f 7288 7168 7287 +f 7288 7287 7499 +f 7499 7287 7474 +f 7499 7474 7547 +f 7547 7474 7618 +f 7547 7618 7715 +f 7715 7618 7646 +f 7715 7646 7800 +f 7800 7646 7862 +f 7800 7862 7891 +f 160 84 216 +f 216 84 246 +f 216 246 357 +f 357 246 395 +f 357 395 492 +f 492 395 502 +f 492 502 664 +f 664 502 620 +f 664 620 698 +f 698 620 749 +f 698 749 838 +f 838 749 905 +f 838 905 1024 +f 1024 905 984 +f 1024 984 1121 +f 1121 984 1156 +f 1121 1156 1239 +f 1239 1156 1308 +f 1239 1308 1365 +f 1365 1308 1364 +f 1365 1364 1511 +f 1511 1364 1548 +f 1511 1548 1640 +f 1640 1548 1574 +f 1640 1574 1767 +f 1767 1574 1777 +f 1767 1777 1834 +f 1834 1777 1948 +f 1834 1948 2032 +f 2032 1948 1982 +f 2032 1982 2139 +f 2139 1982 2148 +f 2139 2148 2298 +f 2298 2148 2311 +f 2298 2311 2462 +f 2462 2311 2421 +f 2462 2421 2564 +f 2564 2421 2548 +f 2564 2548 2744 +f 2744 2548 2732 +f 2744 2732 2822 +f 2822 2732 2883 +f 2822 2883 3004 +f 3004 2883 2944 +f 3004 2944 3046 +f 3046 2944 3075 +f 3046 3075 3286 +f 3286 3075 3267 +f 3286 3267 3391 +f 3391 3267 3351 +f 3391 3351 3480 +f 3480 3351 3510 +f 3480 3510 3654 +f 3654 3510 3620 +f 3654 3620 3757 +f 3757 3620 3738 +f 3757 3738 3898 +f 3898 3738 3840 +f 3898 3840 4030 +f 4030 3840 3986 +f 4030 3986 4124 +f 4124 3986 4102 +f 4124 4102 4258 +f 4258 4102 4323 +f 4258 4323 4411 +f 4411 4323 4450 +f 4411 4450 4618 +f 4618 4450 4568 +f 4618 4568 4736 +f 4736 4568 4692 +f 4736 4692 4843 +f 4843 4692 4866 +f 4843 4866 5008 +f 5008 4866 4992 +f 5008 4992 5079 +f 5079 4992 5070 +f 5079 5070 5259 +f 5259 5070 5226 +f 5259 5226 5396 +f 5396 5226 5348 +f 5396 5348 5437 +f 5437 5348 5510 +f 5437 5510 5656 +f 5656 5510 5664 +f 5656 5664 5710 +f 5710 5664 5726 +f 5710 5726 5817 +f 5817 5726 5896 +f 5817 5896 5947 +f 5947 5896 5986 +f 5947 5986 6103 +f 6103 5986 6190 +f 6103 6190 6262 +f 6262 6190 6222 +f 6262 6222 6372 +f 6372 6222 6438 +f 6372 6438 6523 +f 6523 6438 6518 +f 6523 6518 6622 +f 6622 6518 6681 +f 6622 6681 6808 +f 6808 6681 6830 +f 6808 6830 6935 +f 6935 6830 6882 +f 6935 6882 7038 +f 7038 6882 7076 +f 7038 7076 7250 +f 7250 7076 7258 +f 7250 7258 7278 +f 7278 7258 7288 +f 7278 7288 7440 +f 7440 7288 7499 +f 7440 7499 7588 +f 7588 7499 7547 +f 7588 7547 7668 +f 7668 7547 7715 +f 7668 7715 7782 +f 7782 7715 7800 +f 7782 7800 7920 +f 55 160 234 +f 234 160 216 +f 234 216 416 +f 416 216 357 +f 416 357 542 +f 542 357 492 +f 542 492 585 +f 585 492 664 +f 585 664 799 +f 799 664 698 +f 799 698 906 +f 906 698 838 +f 906 838 954 +f 954 838 1024 +f 954 1024 1108 +f 1108 1024 1121 +f 1108 1121 1316 +f 1316 1121 1239 +f 1316 1239 1376 +f 1376 1239 1365 +f 1376 1365 1524 +f 1524 1365 1511 +f 1524 1511 1682 +f 1682 1511 1640 +f 1682 1640 1745 +f 1745 1640 1767 +f 1745 1767 1840 +f 1840 1767 1834 +f 1840 1834 2037 +f 2037 1834 2032 +f 2037 2032 2088 +f 2088 2032 2139 +f 2088 2139 2263 +f 2263 2139 2298 +f 2263 2298 2400 +f 2400 2298 2462 +f 2400 2462 2574 +f 2574 2462 2564 +f 2574 2564 2715 +f 2715 2564 2744 +f 2715 2744 2794 +f 2794 2744 2822 +f 2794 2822 3026 +f 3026 2822 3004 +f 3026 3004 3140 +f 3140 3004 3046 +f 3140 3046 3262 +f 3262 3046 3286 +f 3262 3286 3404 +f 3404 3286 3391 +f 3404 3391 3506 +f 3506 3391 3480 +f 3506 3480 3586 +f 3586 3480 3654 +f 3586 3654 3723 +f 3723 3654 3757 +f 3723 3757 3900 +f 3900 3757 3898 +f 3900 3898 4066 +f 4066 3898 4030 +f 4066 4030 4219 +f 4219 4030 4124 +f 4219 4124 4351 +f 4351 4124 4258 +f 4351 4258 4428 +f 4428 4258 4411 +f 4428 4411 4528 +f 4528 4411 4618 +f 4528 4618 4714 +f 4714 4618 4736 +f 4714 4736 4820 +f 4820 4736 4843 +f 4820 4843 4910 +f 4910 4843 5008 +f 4910 5008 5030 +f 5030 5008 5079 +f 5030 5079 5192 +f 5192 5079 5259 +f 5192 5259 5350 +f 5350 5259 5396 +f 5350 5396 5480 +f 5480 5396 5437 +f 5480 5437 5660 +f 5660 5437 5656 +f 5660 5656 5702 +f 5702 5656 5710 +f 5702 5710 5925 +f 5925 5710 5817 +f 5925 5817 6056 +f 6056 5817 5947 +f 6056 5947 6080 +f 6080 5947 6103 +f 6080 6103 6225 +f 6225 6103 6262 +f 6225 6262 6439 +f 6439 6262 6372 +f 6439 6372 6468 +f 6468 6372 6523 +f 6468 6523 6682 +f 6682 6523 6622 +f 6682 6622 6804 +f 6804 6622 6808 +f 6804 6808 6965 +f 6965 6808 6935 +f 6965 6935 7096 +f 7096 6935 7038 +f 7096 7038 7256 +f 7256 7038 7250 +f 7256 7250 7362 +f 7362 7250 7278 +f 7362 7278 7422 +f 7422 7278 7440 +f 7422 7440 7625 +f 7625 7440 7588 +f 7625 7588 7720 +f 7720 7588 7668 +f 7720 7668 7874 +f 7874 7668 7782 +f 7874 7782 7909 +f 105 55 175 +f 175 55 234 +f 175 234 296 +f 296 234 416 +f 296 416 506 +f 506 416 542 +f 506 542 635 +f 635 542 585 +f 635 585 800 +f 800 585 799 +f 800 799 918 +f 918 799 906 +f 918 906 1032 +f 1032 906 954 +f 1032 954 1092 +f 1092 954 1108 +f 1092 1108 1195 +f 1195 1108 1316 +f 1195 1316 1428 +f 1428 1316 1376 +f 1428 1376 1458 +f 1458 1376 1524 +f 1458 1524 1628 +f 1628 1524 1682 +f 1628 1682 1746 +f 1746 1682 1745 +f 1746 1745 1861 +f 1861 1745 1840 +f 1861 1840 2043 +f 2043 1840 2037 +f 2043 2037 2162 +f 2162 2037 2088 +f 2162 2088 2281 +f 2281 2088 2263 +f 2281 2263 2432 +f 2432 2263 2400 +f 2432 2400 2581 +f 2581 2400 2574 +f 2581 2574 2694 +f 2694 2574 2715 +f 2694 2715 2808 +f 2808 2715 2794 +f 2808 2794 2963 +f 2963 2794 3026 +f 2963 3026 3066 +f 3066 3026 3140 +f 3066 3140 3246 +f 3246 3140 3262 +f 3246 3262 3386 +f 3386 3262 3404 +f 3386 3404 3529 +f 3529 3404 3506 +f 3529 3506 3578 +f 3578 3506 3586 +f 3578 3586 3802 +f 3802 3586 3723 +f 3802 3723 3880 +f 3880 3723 3900 +f 3880 3900 4026 +f 4026 3900 4066 +f 4026 4066 4204 +f 4204 4066 4219 +f 4204 4219 4300 +f 4300 4219 4351 +f 4300 4351 4374 +f 4374 4351 4428 +f 4374 4428 4579 +f 4579 4428 4528 +f 4579 4528 4630 +f 4630 4528 4714 +f 4630 4714 4794 +f 4794 4714 4820 +f 4794 4820 4918 +f 4918 4820 4910 +f 4918 4910 5067 +f 5067 4910 5030 +f 5067 5030 5246 +f 5246 5030 5192 +f 5246 5192 5355 +f 5355 5192 5350 +f 5355 5350 5536 +f 5536 5350 5480 +f 5536 5480 5592 +f 5592 5480 5660 +f 5592 5660 5788 +f 5788 5660 5702 +f 5788 5702 5852 +f 5852 5702 5925 +f 5852 5925 5975 +f 5975 5925 6056 +f 5975 6056 6160 +f 6160 6056 6080 +f 6160 6080 6218 +f 6218 6080 6225 +f 6218 6225 6462 +f 6462 6225 6439 +f 6462 6439 6592 +f 6592 6439 6468 +f 6592 6468 6714 +f 6714 6468 6682 +f 6714 6682 6762 +f 6762 6682 6804 +f 6762 6804 6966 +f 6966 6804 6965 +f 6966 6965 7056 +f 7056 6965 7096 +f 7056 7096 7180 +f 7180 7096 7256 +f 7180 7256 7324 +f 7324 7256 7362 +f 7324 7362 7500 +f 7500 7362 7422 +f 7500 7422 7630 +f 7630 7422 7625 +f 7630 7625 7673 +f 7673 7625 7720 +f 7673 7720 7821 +f 7821 7720 7874 +f 7821 7874 7892 +f 49 105 282 +f 282 105 175 +f 282 175 384 +f 384 175 296 +f 384 296 497 +f 497 296 506 +f 497 506 665 +f 665 506 635 +f 665 635 774 +f 774 635 800 +f 774 800 932 +f 932 800 918 +f 932 918 993 +f 993 918 1032 +f 993 1032 1176 +f 1176 1032 1092 +f 1176 1092 1257 +f 1257 1092 1195 +f 1257 1195 1409 +f 1409 1195 1428 +f 1409 1428 1489 +f 1489 1428 1458 +f 1489 1458 1629 +f 1629 1458 1628 +f 1629 1628 1756 +f 1756 1628 1746 +f 1756 1746 1920 +f 1920 1746 1861 +f 1920 1861 1976 +f 1976 1861 2043 +f 1976 2043 2131 +f 2131 2043 2162 +f 2131 2162 2233 +f 2233 2162 2281 +f 2233 2281 2453 +f 2453 2281 2432 +f 2453 2432 2604 +f 2604 2432 2581 +f 2604 2581 2716 +f 2716 2581 2694 +f 2716 2694 2826 +f 2826 2694 2808 +f 2826 2808 3024 +f 3024 2808 2963 +f 3024 2963 3154 +f 3154 2963 3066 +f 3154 3066 3196 +f 3196 3066 3246 +f 3196 3246 3371 +f 3371 3246 3386 +f 3371 3386 3451 +f 3451 3386 3529 +f 3451 3529 3582 +f 3582 3529 3578 +f 3582 3578 3788 +f 3788 3578 3802 +f 3788 3802 3907 +f 3907 3802 3880 +f 3907 3880 4068 +f 4068 3880 4026 +f 4068 4026 4180 +f 4180 4026 4204 +f 4180 4204 4286 +f 4286 4204 4300 +f 4286 4300 4406 +f 4406 4300 4374 +f 4406 4374 4582 +f 4582 4374 4579 +f 4582 4579 4662 +f 4662 4579 4630 +f 4662 4630 4812 +f 4812 4630 4794 +f 4812 4794 4947 +f 4947 4794 4918 +f 4947 4918 5061 +f 5061 4918 5067 +f 5061 5067 5240 +f 5240 5067 5246 +f 5240 5246 5389 +f 5389 5246 5355 +f 5389 5355 5507 +f 5507 5355 5536 +f 5507 5536 5590 +f 5590 5536 5592 +f 5590 5592 5720 +f 5720 5592 5788 +f 5720 5788 5884 +f 5884 5788 5852 +f 5884 5852 5954 +f 5954 5852 5975 +f 5954 5975 6176 +f 6176 5975 6160 +f 6176 6160 6245 +f 6245 6160 6218 +f 6245 6218 6338 +f 6338 6218 6462 +f 6338 6462 6498 +f 6498 6462 6592 +f 6498 6592 6624 +f 6624 6592 6714 +f 6624 6714 6730 +f 6730 6714 6762 +f 6730 6762 6908 +f 6908 6762 6966 +f 6908 6966 7024 +f 7024 6966 7056 +f 7024 7056 7171 +f 7171 7056 7180 +f 7171 7180 7350 +f 7350 7180 7324 +f 7350 7324 7459 +f 7459 7324 7500 +f 7459 7500 7540 +f 7540 7500 7630 +f 7540 7630 7684 +f 7684 7630 7673 +f 7684 7673 7828 +f 7828 7673 7821 +f 7828 7821 7917 +f 96 49 170 +f 170 49 282 +f 170 282 417 +f 417 282 384 +f 417 384 483 +f 483 384 497 +f 483 497 612 +f 612 497 665 +f 612 665 750 +f 750 665 774 +f 750 774 849 +f 849 774 932 +f 849 932 961 +f 961 932 993 +f 961 993 1169 +f 1169 993 1176 +f 1169 1176 1269 +f 1269 1176 1257 +f 1269 1257 1330 +f 1330 1257 1409 +f 1330 1409 1497 +f 1497 1409 1489 +f 1497 1489 1592 +f 1592 1489 1629 +f 1592 1629 1757 +f 1757 1629 1756 +f 1757 1756 1848 +f 1848 1756 1920 +f 1848 1920 2019 +f 2019 1920 1976 +f 2019 1976 2114 +f 2114 1976 2131 +f 2114 2131 2250 +f 2250 2131 2233 +f 2250 2233 2426 +f 2426 2233 2453 +f 2426 2453 2582 +f 2582 2453 2604 +f 2582 2604 2700 +f 2700 2604 2716 +f 2700 2716 2857 +f 2857 2716 2826 +f 2857 2826 2920 +f 2920 2826 3024 +f 2920 3024 3146 +f 3146 3024 3154 +f 3146 3154 3203 +f 3203 3154 3196 +f 3203 3196 3334 +f 3334 3196 3371 +f 3334 3371 3514 +f 3514 3371 3451 +f 3514 3451 3614 +f 3614 3451 3582 +f 3614 3582 3728 +f 3728 3582 3788 +f 3728 3788 3956 +f 3956 3788 3907 +f 3956 3907 3993 +f 3993 3907 4068 +f 3993 4068 4212 +f 4212 4068 4180 +f 4212 4180 4324 +f 4324 4180 4286 +f 4324 4286 4454 +f 4454 4286 4406 +f 4454 4406 4602 +f 4602 4406 4582 +f 4602 4582 4634 +f 4634 4582 4662 +f 4634 4662 4807 +f 4807 4662 4812 +f 4807 4812 4896 +f 4896 4812 4947 +f 4896 4947 5137 +f 5137 4947 5061 +f 5137 5061 5282 +f 5282 5061 5240 +f 5282 5240 5406 +f 5406 5240 5389 +f 5406 5389 5545 +f 5545 5389 5507 +f 5545 5507 5564 +f 5564 5507 5590 +f 5564 5590 5691 +f 5691 5590 5720 +f 5691 5720 5915 +f 5915 5720 5884 +f 5915 5884 6034 +f 6034 5884 5954 +f 6034 5954 6166 +f 6166 5954 6176 +f 6166 6176 6228 +f 6228 6176 6245 +f 6228 6245 6392 +f 6392 6245 6338 +f 6392 6338 6492 +f 6492 6338 6498 +f 6492 6498 6629 +f 6629 6498 6624 +f 6629 6624 6833 +f 6833 6624 6730 +f 6833 6730 6902 +f 6902 6730 6908 +f 6902 6908 7128 +f 7128 6908 7024 +f 7128 7024 7150 +f 7150 7024 7171 +f 7150 7171 7390 +f 7390 7171 7350 +f 7390 7350 7467 +f 7467 7350 7459 +f 7467 7459 7634 +f 7634 7459 7540 +f 7634 7540 7691 +f 7691 7540 7684 +f 7691 7684 7822 +f 7822 7684 7828 +f 7822 7828 7884 +f 158 96 262 +f 262 96 170 +f 262 170 369 +f 369 170 417 +f 369 417 518 +f 518 417 483 +f 518 483 601 +f 601 483 612 +f 601 612 775 +f 775 612 750 +f 775 750 850 +f 850 750 849 +f 850 849 980 +f 980 849 961 +f 980 961 1093 +f 1093 961 1169 +f 1093 1169 1289 +f 1289 1169 1269 +f 1289 1269 1424 +f 1424 1269 1330 +f 1424 1330 1541 +f 1541 1330 1497 +f 1541 1497 1607 +f 1607 1497 1592 +f 1607 1592 1735 +f 1735 1592 1757 +f 1735 1757 1894 +f 1894 1757 1848 +f 1894 1848 1983 +f 1983 1848 2019 +f 1983 2019 2171 +f 2171 2019 2114 +f 2171 2114 2222 +f 2222 2114 2250 +f 2222 2250 2433 +f 2433 2250 2426 +f 2433 2426 2549 +f 2549 2426 2582 +f 2549 2582 2707 +f 2707 2582 2700 +f 2707 2700 2861 +f 2861 2700 2857 +f 2861 2857 2990 +f 2990 2857 2920 +f 2990 2920 3100 +f 3100 2920 3146 +f 3100 3146 3200 +f 3200 3146 3203 +f 3200 3203 3310 +f 3310 3203 3334 +f 3310 3334 3474 +f 3474 3334 3514 +f 3474 3514 3649 +f 3649 3514 3614 +f 3649 3614 3771 +f 3771 3614 3728 +f 3771 3728 3891 +f 3891 3728 3956 +f 3891 3956 4023 +f 4023 3956 3993 +f 4023 3993 4114 +f 4114 3993 4212 +f 4114 4212 4252 +f 4252 4212 4324 +f 4252 4324 4430 +f 4430 4324 4454 +f 4430 4454 4562 +f 4562 4454 4602 +f 4562 4602 4702 +f 4702 4602 4634 +f 4702 4634 4823 +f 4823 4634 4807 +f 4823 4807 4952 +f 4952 4807 4896 +f 4952 4896 5100 +f 5100 4896 5137 +f 5100 5137 5215 +f 5215 5137 5282 +f 5215 5282 5326 +f 5326 5282 5406 +f 5326 5406 5430 +f 5430 5406 5545 +f 5430 5545 5616 +f 5616 5545 5564 +f 5616 5564 5716 +f 5716 5564 5691 +f 5716 5691 5926 +f 5926 5691 5915 +f 5926 5915 5976 +f 5976 5915 6034 +f 5976 6034 6172 +f 6172 6034 6166 +f 6172 6166 6246 +f 6246 6166 6228 +f 6246 6228 6364 +f 6364 6228 6392 +f 6364 6392 6524 +f 6524 6392 6492 +f 6524 6492 6693 +f 6693 6492 6629 +f 6693 6629 6768 +f 6768 6629 6833 +f 6768 6833 6949 +f 6949 6833 6902 +f 6949 6902 7044 +f 7044 6902 7128 +f 7044 7128 7196 +f 7196 7128 7150 +f 7196 7150 7341 +f 7341 7150 7390 +f 7341 7390 7433 +f 7433 7390 7467 +f 7433 7467 7565 +f 7565 7467 7634 +f 7565 7634 7748 +f 7748 7634 7691 +f 7748 7691 7796 +f 7796 7691 7822 +f 7796 7822 7912 +f 116 158 192 +f 192 158 262 +f 192 262 312 +f 312 262 369 +f 312 369 457 +f 457 369 518 +f 457 518 577 +f 577 518 601 +f 577 601 699 +f 699 601 775 +f 699 775 913 +f 913 775 850 +f 913 850 970 +f 970 850 980 +f 970 980 1122 +f 1122 980 1093 +f 1122 1093 1209 +f 1209 1093 1289 +f 1209 1289 1338 +f 1338 1289 1424 +f 1338 1424 1525 +f 1525 1424 1541 +f 1525 1541 1687 +f 1687 1541 1607 +f 1687 1607 1736 +f 1736 1607 1735 +f 1736 1735 1921 +f 1921 1735 1894 +f 1921 1894 2044 +f 2044 1894 1983 +f 2044 1983 2132 +f 2132 1983 2171 +f 2132 2171 2290 +f 2290 2171 2222 +f 2290 2222 2454 +f 2454 2222 2433 +f 2454 2433 2575 +f 2575 2433 2549 +f 2575 2549 2677 +f 2677 2549 2707 +f 2677 2707 2835 +f 2835 2707 2861 +f 2835 2861 2978 +f 2978 2861 2990 +f 2978 2990 3111 +f 3111 2990 3100 +f 3111 3100 3208 +f 3208 3100 3200 +f 3208 3200 3422 +f 3422 3200 3310 +f 3422 3310 3561 +f 3561 3310 3474 +f 3561 3474 3672 +f 3672 3474 3649 +f 3672 3649 3713 +f 3713 3649 3771 +f 3713 3771 3856 +f 3856 3771 3891 +f 3856 3891 4020 +f 4020 3891 4023 +f 4020 4023 4138 +f 4138 4023 4114 +f 4138 4114 4315 +f 4315 4114 4252 +f 4315 4252 4432 +f 4432 4252 4430 +f 4432 4430 4546 +f 4546 4430 4562 +f 4546 4562 4707 +f 4707 4562 4702 +f 4707 4702 4787 +f 4787 4702 4823 +f 4787 4823 5010 +f 5010 4823 4952 +f 5010 4952 5062 +f 5062 4952 5100 +f 5062 5100 5174 +f 5174 5100 5215 +f 5174 5215 5390 +f 5390 5215 5326 +f 5390 5326 5497 +f 5497 5326 5430 +f 5497 5430 5556 +f 5556 5430 5616 +f 5556 5616 5680 +f 5680 5616 5716 +f 5680 5716 5818 +f 5818 5716 5926 +f 5818 5926 6029 +f 6029 5926 5976 +f 6029 5976 6136 +f 6136 5976 6172 +f 6136 6172 6226 +f 6226 6172 6246 +f 6226 6246 6384 +f 6384 6246 6364 +f 6384 6364 6482 +f 6482 6364 6524 +f 6482 6524 6720 +f 6720 6524 6693 +f 6720 6693 6773 +f 6773 6693 6768 +f 6773 6768 6892 +f 6892 6768 6949 +f 6892 6949 7092 +f 7092 6949 7044 +f 7092 7044 7230 +f 7230 7044 7196 +f 7230 7196 7314 +f 7314 7196 7341 +f 7314 7341 7414 +f 7414 7341 7433 +f 7414 7433 7550 +f 7550 7433 7565 +f 7550 7565 7692 +f 7692 7565 7748 +f 7692 7748 7764 +f 7764 7748 7796 +f 7764 7796 7935 +f 117 116 255 +f 255 116 192 +f 255 192 353 +f 353 192 312 +f 353 312 467 +f 467 312 457 +f 467 457 554 +f 554 457 577 +f 554 577 693 +f 693 577 699 +f 693 699 851 +f 851 699 913 +f 851 913 1047 +f 1047 913 970 +f 1047 970 1094 +f 1094 970 1122 +f 1094 1122 1240 +f 1240 1122 1209 +f 1240 1209 1356 +f 1356 1209 1338 +f 1356 1338 1568 +f 1568 1338 1525 +f 1568 1525 1654 +f 1654 1525 1687 +f 1654 1687 1821 +f 1821 1687 1736 +f 1821 1736 1849 +f 1849 1736 1921 +f 1849 1921 2020 +f 2020 1921 2044 +f 2020 2044 2115 +f 2115 2044 2132 +f 2115 2132 2302 +f 2302 2132 2290 +f 2302 2290 2459 +f 2459 2290 2454 +f 2459 2454 2556 +f 2556 2454 2575 +f 2556 2575 2678 +f 2678 2575 2677 +f 2678 2677 2836 +f 2836 2677 2835 +f 2836 2835 2970 +f 2970 2835 2978 +f 2970 2978 3127 +f 3127 2978 3111 +f 3127 3111 3271 +f 3271 3111 3208 +f 3271 3208 3341 +f 3341 3208 3422 +f 3341 3422 3448 +f 3448 3422 3561 +f 3448 3561 3668 +f 3668 3561 3672 +f 3668 3672 3818 +f 3818 3672 3713 +f 3818 3713 3940 +f 3940 3713 3856 +f 3940 3856 4072 +f 4072 3856 4020 +f 4072 4020 4195 +f 4195 4020 4138 +f 4195 4138 4256 +f 4256 4138 4315 +f 4256 4315 4448 +f 4448 4315 4432 +f 4448 4432 4520 +f 4520 4432 4546 +f 4520 4546 4688 +f 4688 4546 4707 +f 4688 4707 4886 +f 4886 4707 4787 +f 4886 4787 4892 +f 4892 4787 5010 +f 4892 5010 5094 +f 5094 5010 5062 +f 5094 5062 5180 +f 5180 5062 5174 +f 5180 5174 5408 +f 5408 5174 5390 +f 5408 5390 5498 +f 5498 5390 5497 +f 5498 5497 5642 +f 5642 5497 5556 +f 5642 5556 5763 +f 5763 5556 5680 +f 5763 5680 5928 +f 5928 5680 5818 +f 5928 5818 6054 +f 6054 5818 6029 +f 6054 6029 6195 +f 6195 6029 6136 +f 6195 6136 6308 +f 6308 6136 6226 +f 6308 6226 6427 +f 6427 6226 6384 +f 6427 6384 6562 +f 6562 6384 6482 +f 6562 6482 6662 +f 6662 6482 6720 +f 6662 6720 6756 +f 6756 6720 6773 +f 6756 6773 6903 +f 6903 6773 6892 +f 6903 6892 7110 +f 7110 6892 7092 +f 7110 7092 7162 +f 7162 7092 7230 +f 7162 7230 7329 +f 7329 7230 7314 +f 7329 7314 7418 +f 7418 7314 7414 +f 7418 7414 7533 +f 7533 7414 7550 +f 7533 7550 7706 +f 7706 7550 7692 +f 7706 7692 7778 +f 7778 7692 7764 +f 7778 7764 7926 +f 85 117 271 +f 271 117 255 +f 271 255 370 +f 370 255 353 +f 370 353 484 +f 484 353 467 +f 484 467 636 +f 636 467 554 +f 636 554 784 +f 784 554 693 +f 784 693 852 +f 852 693 851 +f 852 851 1003 +f 1003 851 1047 +f 1003 1047 1123 +f 1123 1047 1094 +f 1123 1094 1196 +f 1196 1094 1240 +f 1196 1240 1390 +f 1390 1240 1356 +f 1390 1356 1526 +f 1526 1356 1568 +f 1526 1568 1593 +f 1593 1568 1654 +f 1593 1654 1715 +f 1715 1654 1821 +f 1715 1821 1895 +f 1895 1821 1849 +f 1895 1849 2063 +f 2063 1849 2020 +f 2063 2020 2092 +f 2092 2020 2115 +f 2092 2115 2264 +f 2264 2115 2302 +f 2264 2302 2413 +f 2413 2302 2459 +f 2413 2459 2576 +f 2576 2459 2556 +f 2576 2556 2670 +f 2670 2556 2678 +f 2670 2678 2824 +f 2824 2678 2836 +f 2824 2836 2971 +f 2971 2836 2970 +f 2971 2970 3112 +f 3112 2970 3127 +f 3112 3127 3228 +f 3228 3127 3271 +f 3228 3271 3356 +f 3356 3271 3341 +f 3356 3341 3470 +f 3470 3341 3448 +f 3470 3448 3596 +f 3596 3448 3668 +f 3596 3668 3732 +f 3732 3668 3818 +f 3732 3818 3941 +f 3941 3818 3940 +f 3941 3940 4076 +f 4076 3940 4072 +f 4076 4072 4177 +f 4177 4072 4195 +f 4177 4195 4297 +f 4297 4195 4256 +f 4297 4256 4464 +f 4464 4256 4448 +f 4464 4448 4538 +f 4538 4448 4520 +f 4538 4520 4708 +f 4708 4520 4688 +f 4708 4688 4882 +f 4882 4688 4886 +f 4882 4886 5006 +f 5006 4886 4892 +f 5006 4892 5045 +f 5045 4892 5094 +f 5045 5094 5210 +f 5210 5094 5180 +f 5210 5180 5370 +f 5370 5180 5408 +f 5370 5408 5428 +f 5428 5408 5498 +f 5428 5498 5586 +f 5586 5498 5642 +f 5586 5642 5734 +f 5734 5642 5763 +f 5734 5763 5930 +f 5930 5763 5928 +f 5930 5928 5982 +f 5982 5928 6054 +f 5982 6054 6202 +f 6202 6054 6195 +f 6202 6195 6316 +f 6316 6195 6308 +f 6316 6308 6340 +f 6340 6308 6427 +f 6340 6427 6589 +f 6589 6427 6562 +f 6589 6562 6685 +f 6685 6562 6662 +f 6685 6662 6750 +f 6750 6662 6756 +f 6750 6756 6930 +f 6930 6756 6903 +f 6930 6903 7072 +f 7072 6903 7110 +f 7072 7110 7220 +f 7220 7110 7162 +f 7220 7162 7330 +f 7330 7162 7329 +f 7330 7329 7444 +f 7444 7329 7418 +f 7444 7418 7600 +f 7600 7418 7533 +f 7600 7533 7716 +f 7716 7533 7706 +f 7716 7706 7826 +f 7826 7706 7778 +f 7826 7778 7902 +f 131 85 180 +f 180 85 271 +f 180 271 322 +f 322 271 370 +f 322 370 435 +f 435 370 484 +f 435 484 654 +f 654 484 636 +f 654 636 680 +f 680 636 784 +f 680 784 831 +f 831 784 852 +f 831 852 1053 +f 1053 852 1003 +f 1053 1003 1141 +f 1141 1003 1123 +f 1141 1123 1270 +f 1270 1123 1196 +f 1270 1196 1326 +f 1326 1196 1390 +f 1326 1390 1527 +f 1527 1390 1526 +f 1527 1526 1576 +f 1576 1526 1593 +f 1576 1593 1719 +f 1719 1593 1715 +f 1719 1715 1922 +f 1922 1715 1895 +f 1922 1895 2072 +f 2072 1895 2063 +f 2072 2063 2202 +f 2202 2063 2092 +f 2202 2092 2265 +f 2265 2092 2264 +f 2265 2264 2414 +f 2414 2264 2413 +f 2414 2413 2601 +f 2601 2413 2576 +f 2601 2576 2708 +f 2708 2576 2670 +f 2708 2670 2850 +f 2850 2670 2824 +f 2850 2824 2979 +f 2979 2824 2971 +f 2979 2971 3128 +f 3128 2971 3112 +f 3128 3112 3238 +f 3238 3112 3228 +f 3238 3228 3352 +f 3352 3228 3356 +f 3352 3356 3452 +f 3452 3356 3470 +f 3452 3470 3632 +f 3632 3470 3596 +f 3632 3596 3709 +f 3709 3596 3732 +f 3709 3732 3942 +f 3942 3732 3941 +f 3942 3941 3977 +f 3977 3941 4076 +f 3977 4076 4220 +f 4220 4076 4177 +f 4220 4177 4304 +f 4304 4177 4297 +f 4304 4297 4439 +f 4439 4297 4464 +f 4439 4464 4506 +f 4506 4464 4538 +f 4506 4538 4670 +f 4670 4538 4708 +f 4670 4708 4848 +f 4848 4708 4882 +f 4848 4882 4978 +f 4978 4882 5006 +f 4978 5006 5142 +f 5142 5006 5045 +f 5142 5045 5157 +f 5157 5045 5210 +f 5157 5210 5293 +f 5293 5210 5370 +f 5293 5370 5481 +f 5481 5370 5428 +f 5481 5428 5630 +f 5630 5428 5586 +f 5630 5586 5682 +f 5682 5586 5734 +f 5682 5734 5916 +f 5916 5734 5930 +f 5916 5930 6062 +f 6062 5930 5982 +f 6062 5982 6161 +f 6161 5982 6202 +f 6161 6202 6290 +f 6290 6202 6316 +f 6290 6316 6428 +f 6428 6316 6340 +f 6428 6340 6514 +f 6514 6340 6589 +f 6514 6589 6694 +f 6694 6589 6685 +f 6694 6685 6809 +f 6809 6685 6750 +f 6809 6750 6950 +f 6950 6750 6930 +f 6950 6930 7064 +f 7064 6930 7072 +f 7064 7072 7172 +f 7172 7072 7220 +f 7172 7220 7366 +f 7366 7220 7330 +f 7366 7330 7468 +f 7468 7330 7444 +f 7468 7444 7534 +f 7534 7444 7600 +f 7534 7600 7660 +f 7660 7600 7716 +f 7660 7716 7814 +f 7814 7716 7826 +f 7814 7826 7908 +f 86 131 235 +f 235 131 180 +f 235 180 418 +f 418 180 322 +f 418 322 532 +f 532 322 435 +f 532 435 655 +f 655 435 654 +f 655 654 721 +f 721 654 680 +f 721 680 872 +f 872 680 831 +f 872 831 940 +f 940 831 1053 +f 940 1053 1142 +f 1142 1053 1141 +f 1142 1141 1217 +f 1217 1141 1270 +f 1217 1270 1391 +f 1391 1270 1326 +f 1391 1326 1542 +f 1542 1326 1527 +f 1542 1527 1655 +f 1655 1527 1576 +f 1655 1576 1806 +f 1806 1576 1719 +f 1806 1719 1896 +f 1896 1719 1922 +f 1896 1922 2045 +f 2045 1922 2072 +f 2045 2072 2086 +f 2086 2072 2202 +f 2086 2202 2240 +f 2240 2202 2265 +f 2240 2265 2460 +f 2460 2265 2414 +f 2460 2414 2557 +f 2557 2414 2601 +f 2557 2601 2686 +f 2686 2601 2708 +f 2686 2708 2851 +f 2851 2708 2850 +f 2851 2850 2986 +f 2986 2850 2979 +f 2986 2979 3113 +f 3113 2979 3128 +f 3113 3128 3239 +f 3239 3128 3238 +f 3239 3238 3364 +f 3364 3238 3352 +f 3364 3352 3488 +f 3488 3352 3452 +f 3488 3452 3610 +f 3610 3452 3632 +f 3610 3632 3726 +f 3726 3632 3709 +f 3726 3709 3920 +f 3920 3709 3942 +f 3920 3942 3978 +f 3978 3942 3977 +f 3978 3977 4149 +f 4149 3977 4220 +f 4149 4220 4294 +f 4294 4220 4304 +f 4294 4304 4426 +f 4426 4304 4439 +f 4426 4439 4622 +f 4622 4439 4506 +f 4622 4506 4656 +f 4656 4506 4670 +f 4656 4670 4872 +f 4872 4670 4848 +f 4872 4848 4968 +f 4968 4848 4978 +f 4968 4978 5032 +f 5032 4978 5142 +f 5032 5142 5241 +f 5241 5142 5157 +f 5241 5157 5336 +f 5336 5157 5293 +f 5336 5293 5524 +f 5524 5293 5481 +f 5524 5481 5619 +f 5619 5481 5630 +f 5619 5630 5764 +f 5764 5630 5682 +f 5764 5682 5936 +f 5936 5682 5916 +f 5936 5916 6068 +f 6068 5916 6062 +f 6068 6062 6183 +f 6183 6062 6161 +f 6183 6161 6311 +f 6311 6161 6290 +f 6311 6290 6417 +f 6417 6290 6428 +f 6417 6428 6471 +f 6471 6428 6514 +f 6471 6514 6610 +f 6610 6514 6694 +f 6610 6694 6757 +f 6757 6694 6809 +f 6757 6809 6923 +f 6923 6809 6950 +f 6923 6950 7032 +f 7032 6950 7064 +f 7032 7064 7264 +f 7264 7064 7172 +f 7264 7172 7342 +f 7342 7172 7366 +f 7342 7366 7460 +f 7460 7366 7468 +f 7460 7468 7562 +f 7562 7468 7534 +f 7562 7534 7738 +f 7738 7534 7660 +f 7738 7660 7846 +f 7846 7660 7814 +f 7846 7814 7936 +f 72 86 209 +f 209 86 235 +f 209 235 323 +f 323 235 418 +f 323 418 533 +f 533 418 532 +f 533 532 670 +f 670 532 655 +f 670 655 739 +f 739 655 721 +f 739 721 832 +f 832 721 872 +f 832 872 987 +f 987 872 940 +f 987 940 1124 +f 1124 940 1142 +f 1124 1142 1241 +f 1241 1142 1217 +f 1241 1217 1392 +f 1392 1217 1391 +f 1392 1391 1559 +f 1559 1391 1542 +f 1559 1542 1594 +f 1594 1542 1655 +f 1594 1655 1807 +f 1807 1655 1806 +f 1807 1806 1933 +f 1933 1806 1896 +f 1933 1896 2077 +f 2077 1896 2045 +f 2077 2045 2133 +f 2133 2045 2086 +f 2133 2086 2291 +f 2291 2086 2240 +f 2291 2240 2415 +f 2415 2240 2460 +f 2415 2460 2602 +f 2602 2460 2557 +f 2602 2557 2687 +f 2687 2557 2686 +f 2687 2686 2841 +f 2841 2686 2851 +f 2841 2851 2964 +f 2964 2851 2986 +f 2964 2986 3114 +f 3114 2986 3113 +f 3114 3113 3222 +f 3222 3113 3239 +f 3222 3239 3345 +f 3345 3239 3364 +f 3345 3364 3536 +f 3536 3364 3488 +f 3536 3488 3625 +f 3625 3488 3610 +f 3625 3610 3710 +f 3710 3610 3726 +f 3710 3726 3934 +f 3934 3726 3920 +f 3934 3920 4024 +f 4024 3920 3978 +f 4024 3978 4119 +f 4119 3978 4149 +f 4119 4149 4298 +f 4298 4149 4294 +f 4298 4294 4366 +f 4366 4294 4426 +f 4366 4426 4616 +f 4616 4426 4622 +f 4616 4622 4725 +f 4725 4622 4656 +f 4725 4656 4838 +f 4838 4656 4872 +f 4838 4872 4956 +f 4956 4872 4968 +f 4956 4968 5046 +f 5046 4968 5032 +f 5046 5032 5250 +f 5250 5032 5241 +f 5250 5241 5360 +f 5360 5241 5336 +f 5360 5336 5482 +f 5482 5336 5524 +f 5482 5524 5678 +f 5678 5524 5619 +f 5678 5619 5783 +f 5783 5619 5764 +f 5783 5764 5854 +f 5854 5764 5936 +f 5854 5936 6021 +f 6021 5936 6068 +f 6021 6068 6149 +f 6149 6068 6183 +f 6149 6183 6211 +f 6211 6183 6311 +f 6211 6311 6429 +f 6429 6311 6417 +f 6429 6417 6570 +f 6570 6417 6471 +f 6570 6471 6642 +f 6642 6471 6610 +f 6642 6610 6728 +f 6728 6610 6757 +f 6728 6757 6856 +f 6856 6757 6923 +f 6856 6923 7010 +f 7010 6923 7032 +f 7010 7032 7244 +f 7244 7032 7264 +f 7244 7264 7308 +f 7308 7264 7342 +f 7308 7342 7486 +f 7486 7342 7460 +f 7486 7460 7548 +f 7548 7460 7562 +f 7548 7562 7696 +f 7696 7562 7738 +f 7696 7738 7804 +f 7804 7738 7846 +f 7804 7846 7894 +f 132 72 210 +f 210 72 209 +f 210 209 324 +f 324 209 323 +f 324 323 436 +f 436 323 533 +f 436 533 586 +f 586 533 670 +f 586 670 740 +f 740 670 739 +f 740 739 898 +f 898 739 832 +f 898 832 971 +f 971 832 987 +f 971 987 1161 +f 1161 987 1124 +f 1161 1124 1218 +f 1218 1124 1241 +f 1218 1241 1393 +f 1393 1241 1392 +f 1393 1392 1498 +f 1498 1392 1559 +f 1498 1559 1630 +f 1630 1559 1594 +f 1630 1594 1737 +f 1737 1594 1807 +f 1737 1807 1897 +f 1897 1807 1933 +f 1897 1933 2078 +f 2078 1933 2077 +f 2078 2077 2163 +f 2163 2077 2133 +f 2163 2133 2266 +f 2266 2133 2291 +f 2266 2291 2390 +f 2390 2291 2415 +f 2390 2415 2597 +f 2597 2415 2602 +f 2597 2602 2695 +f 2695 2602 2687 +f 2695 2687 2837 +f 2837 2687 2841 +f 2837 2841 2974 +f 2974 2841 2964 +f 2974 2964 3103 +f 3103 2964 3114 +f 3103 3114 3231 +f 3231 3114 3222 +f 3231 3222 3365 +f 3365 3222 3345 +f 3365 3345 3522 +f 3522 3345 3536 +f 3522 3536 3676 +f 3676 3536 3625 +f 3676 3625 3774 +f 3774 3625 3710 +f 3774 3710 3914 +f 3914 3710 3934 +f 3914 3934 4032 +f 4032 3934 4024 +f 4032 4024 4178 +f 4178 4024 4119 +f 4178 4119 4352 +f 4352 4119 4298 +f 4352 4298 4412 +f 4412 4298 4366 +f 4412 4366 4530 +f 4530 4366 4616 +f 4530 4616 4732 +f 4732 4616 4725 +f 4732 4725 4884 +f 4884 4725 4838 +f 4884 4838 4986 +f 4986 4838 4956 +f 4986 4956 5098 +f 5098 4956 5046 +f 5098 5046 5216 +f 5216 5046 5250 +f 5216 5250 5412 +f 5412 5250 5360 +f 5412 5360 5488 +f 5488 5360 5482 +f 5488 5482 5610 +f 5610 5482 5678 +f 5610 5678 5692 +f 5692 5678 5783 +f 5692 5783 5891 +f 5891 5783 5854 +f 5891 5854 5995 +f 5995 5854 6021 +f 5995 6021 6184 +f 6184 6021 6149 +f 6184 6149 6277 +f 6277 6149 6211 +f 6277 6211 6352 +f 6352 6211 6429 +f 6352 6429 6590 +f 6590 6429 6570 +f 6590 6570 6686 +f 6686 6570 6642 +f 6686 6642 6810 +f 6810 6642 6728 +f 6810 6728 6893 +f 6893 6728 6856 +f 6893 6856 7057 +f 7057 6856 7010 +f 7057 7010 7188 +f 7188 7010 7244 +f 7188 7244 7354 +f 7354 7244 7308 +f 7354 7308 7429 +f 7429 7308 7486 +f 7429 7486 7580 +f 7580 7486 7548 +f 7580 7548 7670 +f 7670 7548 7696 +f 7670 7696 7861 +f 7861 7696 7804 +f 7861 7804 7916 +f 87 132 236 +f 236 132 210 +f 236 210 403 +f 403 210 324 +f 403 324 446 +f 446 324 436 +f 446 436 566 +f 566 436 586 +f 566 586 785 +f 785 586 740 +f 785 740 853 +f 853 740 898 +f 853 898 1004 +f 1004 898 971 +f 1004 971 1143 +f 1143 971 1161 +f 1143 1161 1210 +f 1210 1161 1218 +f 1210 1218 1410 +f 1410 1218 1393 +f 1410 1393 1560 +f 1560 1393 1498 +f 1560 1498 1608 +f 1608 1498 1630 +f 1608 1630 1710 +f 1710 1630 1737 +f 1710 1737 1850 +f 1850 1737 1897 +f 1850 1897 2064 +f 2064 1897 2078 +f 2064 2078 2134 +f 2134 2078 2163 +f 2134 2163 2267 +f 2267 2163 2266 +f 2267 2266 2446 +f 2446 2266 2390 +f 2446 2390 2550 +f 2550 2390 2597 +f 2550 2597 2679 +f 2679 2597 2695 +f 2679 2695 2838 +f 2838 2695 2837 +f 2838 2837 2987 +f 2987 2837 2974 +f 2987 2974 3104 +f 3104 2974 3103 +f 3104 3103 3242 +f 3242 3103 3231 +f 3242 3231 3342 +f 3342 3231 3365 +f 3342 3365 3552 +f 3552 3365 3522 +f 3552 3522 3642 +f 3642 3522 3676 +f 3642 3676 3718 +f 3718 3676 3774 +f 3718 3774 3874 +f 3874 3774 3914 +f 3874 3914 4000 +f 4000 3914 4032 +f 4000 4032 4156 +f 4156 4032 4178 +f 4156 4178 4338 +f 4338 4178 4352 +f 4338 4352 4440 +f 4440 4352 4412 +f 4440 4412 4589 +f 4589 4412 4530 +f 4589 4530 4628 +f 4628 4530 4732 +f 4628 4732 4808 +f 4808 4732 4884 +f 4808 4884 4914 +f 4914 4884 4986 +f 4914 4986 5104 +f 5104 4986 5098 +f 5104 5098 5256 +f 5256 5098 5216 +f 5256 5216 5319 +f 5319 5216 5412 +f 5319 5412 5538 +f 5538 5412 5488 +f 5538 5488 5599 +f 5599 5488 5610 +f 5599 5610 5784 +f 5784 5610 5692 +f 5784 5692 5826 +f 5826 5692 5891 +f 5826 5891 5988 +f 5988 5891 5995 +f 5988 5995 6142 +f 6142 5995 6184 +f 6142 6184 6312 +f 6312 6184 6277 +f 6312 6277 6397 +f 6397 6277 6352 +f 6397 6352 6555 +f 6555 6352 6590 +f 6555 6590 6630 +f 6630 6590 6686 +f 6630 6686 6764 +f 6764 6686 6810 +f 6764 6810 6924 +f 6924 6810 6893 +f 6924 6893 7070 +f 7070 6893 7057 +f 7070 7057 7195 +f 7195 7057 7188 +f 7195 7188 7358 +f 7358 7188 7354 +f 7358 7354 7429 +f 7637 7580 7642 +f 7642 7580 7670 +f 7642 7670 7758 +f 7758 7670 7761 +f 7761 7670 7861 +f 7761 7861 7878 +f 7070 7124 6924 +f 6924 7124 6904 +f 6924 6904 6764 +f 6764 6904 6793 +f 6764 6793 6630 +f 6630 6793 6722 +f 6630 6722 6555 +f 6555 6722 6472 +f 6555 6472 6397 +f 6397 6472 6385 +f 6397 6385 6312 +f 6312 6385 6330 +f 6312 6330 6142 +f 6142 6330 6150 +f 6142 6150 5988 +f 5988 6150 5996 +f 5988 5996 5826 +f 5826 5996 5938 +f 5826 5938 5784 +f 5784 5938 5758 +f 5784 5758 5599 +f 5599 5758 5606 +f 5599 5606 5538 +f 5538 5606 5450 +f 5538 5450 5319 +f 5319 5450 5383 +f 5319 5383 5256 +f 5256 5383 5211 +f 5256 5211 5104 +f 5104 5211 5138 +f 5104 5138 4914 +f 4914 5138 4966 +f 4914 4966 4808 +f 4808 4966 4855 +f 4808 4855 4628 +f 4628 4855 4648 +f 4628 4648 4589 +f 4589 4648 4496 +f 4589 4496 4440 +f 4440 4496 4480 +f 4440 4480 4338 +f 4338 4480 4238 +f 4338 4238 4156 +f 4156 4238 4150 +f 4156 4150 4000 +f 4000 4150 3994 +f 4000 3994 3874 +f 3874 3994 3853 +f 3874 3853 3718 +f 3718 3853 3808 +f 3718 3808 3642 +f 3642 3808 3584 +f 3642 3584 3552 +f 3552 3584 3530 +f 3552 3530 3342 +f 3342 3530 3319 +f 3342 3319 3242 +f 3242 3319 3240 +f 3242 3240 3104 +f 3104 3240 3119 +f 3104 3119 2987 +f 2987 3119 2966 +f 2987 2966 2838 +f 2838 2966 2862 +f 2838 2862 2679 +f 2679 2862 2709 +f 2679 2709 2550 +f 2550 2709 2565 +f 2550 2565 2446 +f 2446 2565 2434 +f 2446 2434 2267 +f 2267 2434 2292 +f 2267 2292 2134 +f 2134 2292 2210 +f 2134 2210 2064 +f 2064 2210 2073 +f 2064 2073 1850 +f 1850 2073 1923 +f 1850 1923 1710 +f 1710 1923 1758 +f 1710 1758 1608 +f 1608 1758 1656 +f 1608 1656 1560 +f 1560 1656 1566 +f 1560 1566 1410 +f 1410 1566 1411 +f 1410 1411 1210 +f 1210 1411 1271 +f 1210 1271 1143 +f 1143 1271 1144 +f 1143 1144 1004 +f 1004 1144 972 +f 1004 972 853 +f 853 972 899 +f 853 899 785 +f 785 899 741 +f 785 741 566 +f 566 741 637 +f 566 637 446 +f 446 637 507 +f 446 507 403 +f 403 507 345 +f 403 345 236 +f 236 345 217 +f 236 217 87 +f 87 217 152 +f 87 152 12 +f 7266 7195 7270 +f 7270 7195 7358 +f 7270 7358 7274 +f 7124 7031 6904 +f 6904 7031 6896 +f 6904 6896 6793 +f 6793 6896 6774 +f 6793 6774 6722 +f 6722 6774 6600 +f 6722 6600 6472 +f 6472 6600 6551 +f 6472 6551 6385 +f 6385 6551 6430 +f 6385 6430 6330 +f 6330 6430 6240 +f 6330 6240 6150 +f 6150 6240 6104 +f 6150 6104 5996 +f 5996 6104 6002 +f 5996 6002 5938 +f 5938 6002 5872 +f 5938 5872 5758 +f 5758 5872 5728 +f 5758 5728 5606 +f 5606 5728 5676 +f 5606 5676 5450 +f 5450 5676 5457 +f 5450 5457 5383 +f 5383 5457 5400 +f 5383 5400 5211 +f 5211 5400 5212 +f 5211 5212 5138 +f 5138 5212 5148 +f 5138 5148 4966 +f 4966 5148 4957 +f 4966 4957 4855 +f 4855 4957 4788 +f 4855 4788 4648 +f 4648 4788 4720 +f 4648 4720 4496 +f 4496 4720 4498 +f 4496 4498 4480 +f 4480 4498 4404 +f 4480 4404 4238 +f 4238 4404 4280 +f 4238 4280 4150 +f 4150 4280 4166 +f 4150 4166 3994 +f 3994 4166 4058 +f 3994 4058 3853 +f 3853 4058 3844 +f 3853 3844 3808 +f 3808 3844 3714 +f 3808 3714 3584 +f 3584 3714 3630 +f 3584 3630 3530 +f 3530 3630 3459 +f 3530 3459 3319 +f 3319 3459 3346 +f 3319 3346 3240 +f 3240 3346 3276 +f 3240 3276 3119 +f 3119 3276 3120 +f 3119 3120 2966 +f 2966 3120 2972 +f 2966 2972 2862 +f 2862 2972 2852 +f 2862 2852 2709 +f 2709 2852 2710 +f 2709 2710 2565 +f 2565 2710 2558 +f 2565 2558 2434 +f 2434 2558 2447 +f 2434 2447 2292 +f 2292 2447 2251 +f 2292 2251 2210 +f 2210 2251 2164 +f 2210 2164 2073 +f 2073 2164 2000 +f 2073 2000 1923 +f 1923 2000 1924 +f 1923 1924 1758 +f 1758 1924 1720 +f 1758 1720 1656 +f 1656 1720 1675 +f 1656 1675 1566 +f 1566 1675 1499 +f 1566 1499 1411 +f 1411 1499 1431 +f 1411 1431 1271 +f 1271 1431 1290 +f 1271 1290 1144 +f 1144 1290 1125 +f 1144 1125 972 +f 972 1125 988 +f 972 988 899 +f 899 988 914 +f 899 914 741 +f 741 914 793 +f 741 793 637 +f 637 793 666 +f 637 666 507 +f 507 666 447 +f 507 447 345 +f 345 447 404 +f 345 404 217 +f 217 404 272 +f 217 272 152 +f 152 272 50 +f 152 50 12 +f 51 50 176 +f 176 50 272 +f 176 272 410 +f 410 272 404 +f 410 404 534 +f 534 404 447 +f 534 447 602 +f 602 447 666 +f 602 666 700 +f 700 666 793 +f 700 793 882 +f 882 793 914 +f 882 914 1005 +f 1005 914 988 +f 1005 988 1126 +f 1126 988 1125 +f 1126 1125 1242 +f 1242 1125 1290 +f 1242 1290 1432 +f 1432 1290 1431 +f 1432 1431 1453 +f 1453 1431 1499 +f 1453 1499 1657 +f 1657 1499 1675 +f 1657 1675 1814 +f 1814 1675 1720 +f 1814 1720 1954 +f 1954 1720 1924 +f 1954 1924 2074 +f 2074 1924 2000 +f 2074 2000 2172 +f 2172 2000 2164 +f 2172 2164 2307 +f 2307 2164 2251 +f 2307 2251 2466 +f 2466 2251 2447 +f 2466 2447 2542 +f 2542 2447 2558 +f 2542 2558 2680 +f 2680 2558 2710 +f 2680 2710 2868 +f 2868 2710 2852 +f 2868 2852 2953 +f 2953 2852 2972 +f 2953 2972 3164 +f 3164 2972 3120 +f 3164 3120 3250 +f 3250 3120 3276 +f 3250 3276 3408 +f 3408 3276 3346 +f 3408 3346 3502 +f 3502 3346 3459 +f 3502 3459 3660 +f 3660 3459 3630 +f 3660 3630 3736 +f 3736 3630 3714 +f 3736 3714 3854 +f 3854 3714 3844 +f 3854 3844 4052 +f 4052 3844 4058 +f 4052 4058 4164 +f 4164 4058 4166 +f 4164 4166 4262 +f 4262 4166 4280 +f 4262 4280 4417 +f 4417 4280 4404 +f 4417 4404 4590 +f 4590 4404 4498 +f 4590 4498 4676 +f 4676 4498 4720 +f 4676 4720 4844 +f 4844 4720 4788 +f 4844 4788 4928 +f 4928 4788 4957 +f 4928 4957 5105 +f 5105 4957 5148 +f 5105 5148 5242 +f 5242 5148 5212 +f 5242 5212 5312 +f 5312 5212 5400 +f 5312 5400 5458 +f 5458 5400 5457 +f 5458 5457 5604 +f 5604 5457 5676 +f 5604 5676 5798 +f 5798 5676 5728 +f 5798 5728 5863 +f 5863 5728 5872 +f 5863 5872 5978 +f 5978 5872 6002 +f 5978 6002 6099 +f 6099 6002 6104 +f 6099 6104 6328 +f 6328 6104 6240 +f 6328 6240 6356 +f 6356 6240 6430 +f 6356 6430 6584 +f 6584 6430 6551 +f 6584 6551 6663 +f 6663 6551 6600 +f 6663 6600 6834 +f 6834 6600 6774 +f 6834 6774 6954 +f 6954 6774 6896 +f 6954 6896 7003 +f 7003 6896 7031 +f 7003 7031 7007 +f 106 51 275 +f 275 51 176 +f 275 176 405 +f 405 176 410 +f 405 410 498 +f 498 410 534 +f 498 534 638 +f 638 534 602 +f 638 602 722 +f 722 602 700 +f 722 700 833 +f 833 700 882 +f 833 882 1048 +f 1048 882 1005 +f 1048 1005 1127 +f 1127 1005 1126 +f 1127 1126 1298 +f 1298 1126 1242 +f 1298 1242 1412 +f 1412 1242 1432 +f 1412 1432 1462 +f 1462 1432 1453 +f 1462 1453 1666 +f 1666 1453 1657 +f 1666 1657 1738 +f 1738 1657 1814 +f 1738 1814 1898 +f 1898 1814 1954 +f 1898 1954 2033 +f 2033 1954 2074 +f 2033 2074 2100 +f 2100 2074 2172 +f 2100 2172 2228 +f 2228 2172 2307 +f 2228 2307 2448 +f 2448 2307 2466 +f 2448 2466 2566 +f 2566 2466 2542 +f 2566 2542 2696 +f 2696 2542 2680 +f 2696 2680 2842 +f 2842 2680 2868 +f 2842 2868 2988 +f 2988 2868 2953 +f 2988 2953 3052 +f 3052 2953 3164 +f 3052 3164 3268 +f 3268 3164 3250 +f 3268 3250 3413 +f 3413 3250 3408 +f 3413 3408 3516 +f 3516 3408 3502 +f 3516 3502 3622 +f 3622 3502 3660 +f 3622 3660 3782 +f 3782 3660 3736 +f 3782 3736 3892 +f 3892 3736 3854 +f 3892 3854 3972 +f 3972 3854 4052 +f 3972 4052 4186 +f 4186 4052 4164 +f 4186 4164 4248 +f 4248 4164 4262 +f 4248 4262 4462 +f 4462 4262 4417 +f 4462 4417 4553 +f 4553 4417 4590 +f 4553 4590 4698 +f 4698 4590 4676 +f 4698 4676 4802 +f 4802 4676 4844 +f 4802 4844 4958 +f 4958 4844 4928 +f 4958 4928 5086 +f 5086 4928 5105 +f 5086 5105 5204 +f 5204 5105 5242 +f 5204 5242 5320 +f 5320 5242 5312 +f 5320 5312 5492 +f 5492 5312 5458 +f 5492 5458 5552 +f 5552 5458 5604 +f 5552 5604 5746 +f 5746 5604 5798 +f 5746 5798 5834 +f 5834 5798 5863 +f 5834 5863 6022 +f 6022 5863 5978 +f 6022 5978 6192 +f 6192 5978 6099 +f 6192 6099 6256 +f 6256 6099 6328 +f 6256 6328 6390 +f 6390 6328 6356 +f 6390 6356 6540 +f 6540 6356 6584 +f 6540 6584 6664 +f 6664 6584 6663 +f 6664 6663 6844 +f 6844 6663 6834 +f 6844 6834 6922 +f 6922 6834 6954 +f 6922 6954 6989 +f 6922 6901 6844 +f 6844 6901 6781 +f 6844 6781 6664 +f 6664 6781 6632 +f 6664 6632 6540 +f 6540 6632 6560 +f 6540 6560 6390 +f 6390 6560 6370 +f 6390 6370 6256 +f 6256 6370 6252 +f 6256 6252 6192 +f 6192 6252 6100 +f 6192 6100 6022 +f 6022 6100 5990 +f 6022 5990 5834 +f 5834 5990 5838 +f 5834 5838 5746 +f 5746 5838 5766 +f 5746 5766 5552 +f 5552 5766 5654 +f 5552 5654 5492 +f 5492 5654 5440 +f 5492 5440 5320 +f 5320 5440 5376 +f 5320 5376 5204 +f 5204 5376 5158 +f 5204 5158 5086 +f 5086 5158 5120 +f 5086 5120 4958 +f 4958 5120 4948 +f 4958 4948 4802 +f 4802 4948 4856 +f 4802 4856 4698 +f 4698 4856 4726 +f 4698 4726 4553 +f 4553 4726 4524 +f 4553 4524 4462 +f 4462 4524 4420 +f 4462 4420 4248 +f 4248 4420 4344 +f 4248 4344 4186 +f 4186 4344 4130 +f 4186 4130 3972 +f 3972 4130 3987 +f 3972 3987 3892 +f 3892 3987 3952 +f 3892 3952 3782 +f 3782 3952 3772 +f 3782 3772 3622 +f 3622 3772 3574 +f 3622 3574 3516 +f 3516 3574 3500 +f 3516 3500 3413 +f 3413 3500 3372 +f 3413 3372 3268 +f 3268 3372 3218 +f 3268 3218 3052 +f 3052 3218 3076 +f 3052 3076 2988 +f 2988 3076 2994 +f 2988 2994 2842 +f 2842 2994 2858 +f 2842 2858 2696 +f 2696 2858 2721 +f 2696 2721 2566 +f 2566 2721 2598 +f 2566 2598 2448 +f 2448 2598 2438 +f 2448 2438 2228 +f 2228 2438 2268 +f 2228 2268 2100 +f 2100 2268 2149 +f 2100 2149 2033 +f 2033 2149 2021 +f 2033 2021 1898 +f 1898 2021 1862 +f 1898 1862 1738 +f 1738 1862 1791 +f 1738 1791 1666 +f 1666 1791 1676 +f 1666 1676 1462 +f 1462 1676 1500 +f 1462 1500 1412 +f 1412 1500 1413 +f 1412 1413 1298 +f 1298 1413 1272 +f 1298 1272 1127 +f 1127 1272 1170 +f 1127 1170 1048 +f 1048 1170 981 +f 1048 981 833 +f 833 981 873 +f 833 873 722 +f 722 873 776 +f 722 776 638 +f 638 776 567 +f 638 567 498 +f 498 567 519 +f 498 519 405 +f 405 519 385 +f 405 385 275 +f 275 385 218 +f 275 218 106 +f 106 218 90 +f 106 90 28 +f 7132 7091 6901 +f 6901 7091 6946 +f 6901 6946 6781 +f 6781 6946 6758 +f 6781 6758 6632 +f 6632 6758 6638 +f 6632 6638 6560 +f 6560 6638 6476 +f 6560 6476 6370 +f 6370 6476 6336 +f 6370 6336 6252 +f 6252 6336 6278 +f 6252 6278 6100 +f 6100 6278 6196 +f 6100 6196 5990 +f 5990 6196 5948 +f 5990 5948 5838 +f 5838 5948 5892 +f 5838 5892 5766 +f 5766 5892 5744 +f 5766 5744 5654 +f 5654 5744 5620 +f 5654 5620 5440 +f 5440 5620 5508 +f 5440 5508 5376 +f 5376 5508 5398 +f 5376 5398 5158 +f 5158 5398 5260 +f 5158 5260 5120 +f 5120 5260 5106 +f 5120 5106 4948 +f 4948 5106 4922 +f 4948 4922 4856 +f 4856 4922 4818 +f 4856 4818 4726 +f 4726 4818 4684 +f 4726 4684 4524 +f 4524 4684 4554 +f 4524 4554 4420 +f 4420 4554 4482 +f 4420 4482 4344 +f 4344 4482 4316 +f 4344 4316 4130 +f 4130 4316 4196 +f 4130 4196 3987 +f 3987 4196 4044 +f 3987 4044 3952 +f 3952 4044 3904 +f 3952 3904 3772 +f 3772 3904 3758 +f 3772 3758 3574 +f 3574 3758 3634 +f 3574 3634 3500 +f 3500 3634 3460 +f 3500 3460 3372 +f 3372 3460 3366 +f 3372 3366 3218 +f 3218 3366 3257 +f 3218 3257 3076 +f 3076 3257 3138 +f 3076 3138 2994 +f 2994 3138 3016 +f 2994 3016 2858 +f 2858 3016 2866 +f 2858 2866 2721 +f 2721 2866 2688 +f 2721 2688 2598 +f 2598 2688 2560 +f 2598 2560 2438 +f 2438 2560 2401 +f 2438 2401 2268 +f 2268 2401 2308 +f 2268 2308 2149 +f 2149 2308 2116 +f 2149 2116 2021 +f 2021 2116 2046 +f 2021 2046 1862 +f 1862 2046 1956 +f 1862 1956 1791 +f 1791 1956 1792 +f 1791 1792 1676 +f 1676 1792 1688 +f 1676 1688 1500 +f 1500 1688 1528 +f 1500 1528 1413 +f 1413 1528 1382 +f 1413 1382 1272 +f 1272 1382 1310 +f 1272 1310 1170 +f 1170 1310 1177 +f 1170 1177 981 +f 981 1177 994 +f 981 994 873 +f 873 994 818 +f 873 818 776 +f 776 818 766 +f 776 766 567 +f 567 766 578 +f 567 578 519 +f 519 578 468 +f 519 468 385 +f 385 468 406 +f 385 406 218 +f 218 406 199 +f 218 199 90 +f 90 199 107 +f 90 107 28 +f 7091 7071 6946 +f 6946 7071 6862 +f 6946 6862 6758 +f 6758 6862 6803 +f 6758 6803 6638 +f 6638 6803 6718 +f 6638 6718 6476 +f 6476 6718 6532 +f 6476 6532 6336 +f 6336 6532 6375 +f 6336 6375 6278 +f 6278 6375 6204 +f 6278 6204 6196 +f 6196 6204 6116 +f 6196 6116 5948 +f 5948 6116 6058 +f 5948 6058 5892 +f 5892 6058 5844 +f 5892 5844 5744 +f 5744 5844 5792 +f 5744 5792 5620 +f 5620 5792 5584 +f 5620 5584 5508 +f 5508 5584 5456 +f 5508 5456 5398 +f 5398 5456 5332 +f 5398 5332 5260 +f 5260 5332 5231 +f 5260 5231 5106 +f 5106 5231 5118 +f 5106 5118 4922 +f 4922 5118 4942 +f 4922 4942 4818 +f 4818 4942 4858 +f 4818 4858 4684 +f 4684 4858 4690 +f 4684 4690 4554 +f 4554 4690 4516 +f 4554 4516 4482 +f 4482 4516 4437 +f 4482 4437 4316 +f 4316 4437 4240 +f 4316 4240 4196 +f 4196 4240 4216 +f 4196 4216 4044 +f 4044 4216 3996 +f 4044 3996 3904 +f 3904 3996 3866 +f 3904 3866 3758 +f 3758 3866 3752 +f 3758 3752 3634 +f 3634 3752 3613 +f 3634 3613 3460 +f 3460 3613 3544 +f 3460 3544 3366 +f 3366 3544 3330 +f 3366 3330 3257 +f 3257 3330 3284 +f 3257 3284 3138 +f 3138 3284 3110 +f 3138 3110 3016 +f 3016 3110 3023 +f 3016 3023 2866 +f 2866 3023 2865 +f 2866 2865 2688 +f 2688 2865 2718 +f 2688 2718 2560 +f 2560 2718 2592 +f 2560 2592 2401 +f 2401 2592 2396 +f 2401 2396 2308 +f 2308 2396 2239 +f 2308 2239 2116 +f 2116 2239 2187 +f 2116 2187 2046 +f 2046 2187 1964 +f 2046 1964 1956 +f 1956 1964 1883 +f 1956 1883 1792 +f 1792 1883 1709 +f 1792 1709 1688 +f 1688 1709 1653 +f 1688 1653 1528 +f 1528 1653 1510 +f 1528 1510 1382 +f 1382 1510 1444 +f 1382 1444 1310 +f 1310 1444 1228 +f 1310 1228 1177 +f 1177 1228 1184 +f 1177 1184 994 +f 994 1184 952 +f 994 952 818 +f 818 952 871 +f 818 871 766 +f 766 871 728 +f 766 728 578 +f 578 728 663 +f 578 663 468 +f 468 663 456 +f 468 456 406 +f 406 456 383 +f 406 383 199 +f 199 383 245 +f 199 245 107 +f 107 245 133 +f 107 133 10 +f 7272 7386 7267 +f 7267 7386 7253 +f 7267 7253 7147 +f 7640 7685 7635 +f 7635 7685 7576 +f 7635 7576 7520 +f 7759 7808 7755 +f 7755 7808 7685 +f 7755 7685 7640 +f 134 156 276 +f 276 156 244 +f 276 244 371 +f 371 244 368 +f 371 368 464 +f 464 368 445 +f 464 445 560 +f 560 445 575 +f 560 575 682 +f 682 575 773 +f 682 773 854 +f 854 773 912 +f 854 912 1012 +f 1012 912 1038 +f 1012 1038 1162 +f 1162 1038 1175 +f 1162 1175 1204 +f 1204 1175 1307 +f 1204 1307 1434 +f 1434 1307 1443 +f 1434 1443 1490 +f 1490 1443 1465 +f 1490 1465 1609 +f 1609 1465 1580 +f 1609 1580 1778 +f 1778 1580 1800 +f 1778 1800 1878 +f 1878 1800 1876 +f 1878 1876 2022 +f 2022 1876 1958 +f 2022 1958 2140 +f 2140 1958 2196 +f 2140 2196 2252 +f 2252 2196 2300 +f 2252 2300 2402 +f 2402 2300 2412 +f 2402 2412 2584 +f 2584 2412 2568 +f 2584 2568 2648 +f 2648 2568 2642 +f 2648 2642 2846 +f 2846 2642 2814 +f 2846 2814 2940 +f 2940 2814 2950 +f 2940 2950 3072 +f 3072 2950 3065 +f 3072 3065 3248 +f 3248 3065 3278 +f 3248 3278 3338 +f 3338 3278 3419 +f 3338 3419 3554 +f 3554 3419 3479 +f 3554 3479 3674 +f 3674 3479 3600 +f 3674 3600 3778 +f 3778 3600 3806 +f 3778 3806 3908 +f 3908 3806 3919 +f 3908 3919 3988 +f 3988 3919 4084 +f 3988 4084 4126 +f 4126 4084 4194 +f 4126 4194 4354 +f 4354 4194 4290 +f 4354 4290 4478 +f 4478 4290 4387 +f 4478 4387 4550 +f 4550 4387 4567 +f 4550 4567 4664 +f 4664 4567 4728 +f 4664 4728 4824 +f 4824 4728 4798 +f 4824 4798 4970 +f 4970 4798 4909 +f 4970 4909 5082 +f 5082 4909 5054 +f 5082 5054 5254 +f 5254 5054 5221 +f 5254 5221 5392 +f 5392 5221 5290 +f 5392 5290 5460 +f 5460 5290 5490 +f 5460 5490 5640 +f 5640 5490 5650 +f 5640 5650 5737 +f 5737 5650 5706 +f 5737 5706 5887 +f 5887 5706 5924 +f 5887 5924 6032 +f 6032 5924 6042 +f 6032 6042 6122 +f 6122 6042 6181 +f 6122 6181 6272 +f 6272 6181 6304 +f 6272 6304 6394 +f 6394 6304 6360 +f 6394 6360 6489 +f 6489 6360 6496 +f 6489 6496 6702 +f 6702 6496 6716 +f 6702 6716 6782 +f 6782 6716 6843 +f 6782 6843 6894 +f 6894 6843 6881 +f 6894 6881 7058 +f 7058 6881 7042 +f 7058 7042 7198 +f 7198 7042 7156 +f 7198 7156 7300 +f 7300 7156 7312 +f 7300 7312 7450 +f 7450 7312 7516 +f 7450 7516 7566 +f 7566 7516 7576 +f 7566 7576 7754 +f 7754 7576 7685 +f 7754 7685 7872 +f 7872 7685 7808 +f 7872 7808 7919 +f 66 134 200 +f 200 134 276 +f 200 276 306 +f 306 276 371 +f 306 371 508 +f 508 371 464 +f 508 464 608 +f 608 464 560 +f 608 560 742 +f 742 560 682 +f 742 682 860 +f 860 682 854 +f 860 854 982 +f 982 854 1012 +f 982 1012 1128 +f 1128 1012 1162 +f 1128 1162 1278 +f 1278 1162 1204 +f 1278 1204 1357 +f 1357 1204 1434 +f 1357 1434 1448 +f 1448 1434 1490 +f 1448 1490 1658 +f 1658 1490 1609 +f 1658 1609 1716 +f 1716 1609 1778 +f 1716 1778 1934 +f 1934 1778 1878 +f 1934 1878 2084 +f 2084 1878 2022 +f 2084 2022 2178 +f 2178 2022 2140 +f 2178 2140 2286 +f 2286 2140 2252 +f 2286 2252 2422 +f 2422 2252 2402 +f 2422 2402 2590 +f 2590 2402 2584 +f 2590 2584 2644 +f 2644 2584 2648 +f 2644 2648 2810 +f 2810 2648 2846 +f 2810 2846 3002 +f 3002 2846 2940 +f 3002 2940 3054 +f 3054 2940 3072 +f 3054 3072 3172 +f 3172 3072 3248 +f 3172 3248 3414 +f 3414 3248 3338 +f 3414 3338 3482 +f 3482 3338 3554 +f 3482 3554 3616 +f 3616 3554 3674 +f 3616 3674 3822 +f 3822 3674 3778 +f 3822 3778 3902 +f 3902 3778 3908 +f 3902 3908 3980 +f 3980 3908 3988 +f 3980 3988 4170 +f 4170 3988 4126 +f 4170 4126 4264 +f 4264 4126 4354 +f 4264 4354 4398 +f 4398 4354 4478 +f 4398 4478 4586 +f 4586 4478 4550 +f 4586 4550 4718 +f 4718 4550 4664 +f 4718 4664 4826 +f 4826 4664 4824 +f 4826 4824 5004 +f 5004 4824 4970 +f 5004 4970 5072 +f 5072 4970 5082 +f 5072 5082 5222 +f 5222 5082 5254 +f 5222 5254 5294 +f 5294 5254 5392 +f 5294 5392 5540 +f 5540 5392 5460 +f 5540 5460 5646 +f 5646 5460 5640 +f 5646 5640 5774 +f 5774 5640 5737 +f 5774 5737 5882 +f 5882 5737 5887 +f 5882 5887 6014 +f 6014 5887 6032 +f 6014 6032 6114 +f 6114 6032 6122 +f 6114 6122 6270 +f 6270 6122 6272 +f 6270 6272 6440 +f 6440 6272 6394 +f 6440 6394 6542 +f 6542 6394 6489 +f 6542 6489 6616 +f 6616 6489 6702 +f 6616 6702 6840 +f 6840 6702 6782 +f 6840 6782 6944 +f 6944 6782 6894 +f 6944 6894 7066 +f 7066 6894 7058 +f 7066 7058 7202 +f 7202 7058 7198 +f 7202 7198 7344 +f 7344 7198 7300 +f 7344 7300 7410 +f 7410 7300 7450 +f 7410 7450 7602 +f 7602 7450 7566 +f 7602 7566 7674 +f 7674 7566 7754 +f 7674 7754 7766 +f 7766 7754 7872 +f 7766 7872 7900 +f 52 66 256 +f 256 66 200 +f 256 200 420 +f 420 200 306 +f 420 306 478 +f 478 306 508 +f 478 508 552 +f 552 508 608 +f 552 608 786 +f 786 608 742 +f 786 742 920 +f 920 742 860 +f 920 860 1006 +f 1006 860 982 +f 1006 982 1109 +f 1109 982 1128 +f 1109 1128 1260 +f 1260 1128 1278 +f 1260 1278 1394 +f 1394 1278 1357 +f 1394 1357 1512 +f 1512 1357 1448 +f 1512 1448 1610 +f 1610 1448 1658 +f 1610 1658 1808 +f 1808 1658 1716 +f 1808 1716 1946 +f 1946 1716 1934 +f 1946 1934 2038 +f 2038 1934 2084 +f 2038 2084 2152 +f 2152 2084 2178 +f 2152 2178 2244 +f 2244 2178 2286 +f 2244 2286 2428 +f 2428 2286 2422 +f 2428 2422 2606 +f 2606 2422 2590 +f 2606 2590 2656 +f 2656 2590 2644 +f 2656 2644 2873 +f 2873 2644 2810 +f 2873 2810 2998 +f 2998 2810 3002 +f 2998 3002 3062 +f 3062 3002 3054 +f 3062 3054 3194 +f 3194 3054 3172 +f 3194 3172 3306 +f 3306 3172 3414 +f 3306 3414 3548 +f 3548 3414 3482 +f 3548 3482 3646 +f 3646 3482 3616 +f 3646 3616 3798 +f 3798 3616 3822 +f 3798 3822 3950 +f 3950 3822 3902 +f 3950 3902 4018 +f 4018 3902 3980 +f 4018 3980 4161 +f 4161 3980 4170 +f 4161 4170 4308 +f 4308 4170 4264 +f 4308 4264 4418 +f 4418 4264 4398 +f 4418 4398 4508 +f 4508 4398 4586 +f 4508 4586 4748 +f 4748 4586 4718 +f 4748 4718 4876 +f 4876 4718 4826 +f 4876 4826 4962 +f 4962 4826 5004 +f 4962 5004 5108 +f 5108 5004 5072 +f 5108 5072 5176 +f 5176 5072 5222 +f 5176 5222 5366 +f 5366 5222 5294 +f 5366 5294 5472 +f 5472 5294 5540 +f 5472 5540 5572 +f 5572 5540 5646 +f 5572 5646 5700 +f 5700 5646 5774 +f 5700 5774 5903 +f 5903 5774 5882 +f 5903 5882 6046 +f 6046 5882 6014 +f 6046 6014 6092 +f 6092 6014 6114 +f 6092 6114 6216 +f 6216 6114 6270 +f 6216 6270 6403 +f 6403 6270 6440 +f 6403 6440 6490 +f 6490 6440 6542 +f 6490 6542 6646 +f 6646 6542 6616 +f 6646 6616 6838 +f 6838 6616 6840 +f 6838 6840 6942 +f 6942 6840 6944 +f 6942 6944 7036 +f 7036 6944 7066 +f 7036 7066 7210 +f 7210 7066 7202 +f 7210 7202 7382 +f 7382 7202 7344 +f 7382 7344 7481 +f 7481 7344 7410 +f 7481 7410 7544 +f 7544 7410 7602 +f 7544 7602 7676 +f 7676 7602 7674 +f 7676 7674 7818 +f 7818 7674 7766 +f 7818 7766 7906 +f 56 52 194 +f 194 52 256 +f 194 256 386 +f 386 256 420 +f 386 420 448 +f 448 420 478 +f 448 478 656 +f 656 478 552 +f 656 552 768 +f 768 552 786 +f 768 786 900 +f 900 786 920 +f 900 920 934 +f 934 920 1006 +f 934 1006 1149 +f 1149 1006 1109 +f 1149 1109 1212 +f 1212 1109 1260 +f 1212 1260 1366 +f 1366 1260 1394 +f 1366 1394 1554 +f 1554 1394 1512 +f 1554 1512 1664 +f 1664 1512 1610 +f 1664 1610 1818 +f 1818 1610 1808 +f 1818 1808 1854 +f 1854 1808 1946 +f 1854 1946 2066 +f 2066 1946 2038 +f 2066 2038 2104 +f 2104 2038 2152 +f 2104 2152 2282 +f 2282 2152 2244 +f 2282 2244 2416 +f 2416 2244 2428 +f 2416 2428 2514 +f 2514 2428 2606 +f 2514 2606 2722 +f 2722 2606 2656 +f 2722 2656 2788 +f 2788 2656 2873 +f 2788 2873 2946 +f 2946 2873 2998 +f 2946 2998 3080 +f 3080 2998 3062 +f 3080 3062 3178 +f 3178 3062 3194 +f 3178 3194 3324 +f 3324 3194 3306 +f 3324 3306 3562 +f 3562 3306 3548 +f 3562 3548 3626 +f 3626 3548 3646 +f 3626 3646 3746 +f 3746 3646 3798 +f 3746 3798 3930 +f 3930 3798 3950 +f 3930 3950 4074 +f 4074 3950 4018 +f 4074 4018 4226 +f 4226 4018 4161 +f 4226 4161 4356 +f 4356 4161 4308 +f 4356 4308 4446 +f 4446 4308 4418 +f 4446 4418 4518 +f 4518 4418 4508 +f 4518 4508 4696 +f 4696 4508 4748 +f 4696 4748 4780 +f 4780 4748 4876 +f 4780 4876 4912 +f 4912 4876 4962 +f 4912 4962 5080 +f 5080 4962 5108 +f 5080 5108 5274 +f 5274 5108 5176 +f 5274 5176 5343 +f 5343 5176 5366 +f 5343 5366 5546 +f 5546 5366 5472 +f 5546 5472 5612 +f 5612 5472 5572 +f 5612 5572 5696 +f 5696 5572 5700 +f 5696 5700 5878 +f 5878 5700 5903 +f 5878 5903 6038 +f 6038 5903 6046 +f 6038 6046 6096 +f 6096 6046 6092 +f 6096 6092 6282 +f 6282 6092 6216 +f 6282 6216 6398 +f 6398 6216 6403 +f 6398 6403 6552 +f 6552 6403 6490 +f 6552 6490 6704 +f 6704 6490 6646 +f 6704 6646 6798 +f 6798 6646 6838 +f 6798 6838 6916 +f 6916 6838 6942 +f 6916 6942 7048 +f 7048 6942 7036 +f 7048 7036 7215 +f 7215 7036 7210 +f 7215 7210 7276 +f 7276 7210 7382 +f 7276 7382 7434 +f 7434 7382 7481 +f 7434 7481 7632 +f 7632 7481 7544 +f 7632 7544 7686 +f 7686 7544 7676 +f 7686 7676 7868 +f 7868 7676 7818 +f 7868 7818 7898 +f 118 56 286 +f 286 56 194 +f 286 194 327 +f 327 194 386 +f 327 386 458 +f 458 386 448 +f 458 448 621 +f 621 448 656 +f 621 656 794 +f 794 656 768 +f 794 768 924 +f 924 768 900 +f 924 900 962 +f 962 900 934 +f 962 934 1110 +f 1110 934 1149 +f 1110 1149 1224 +f 1224 1149 1212 +f 1224 1212 1414 +f 1414 1212 1366 +f 1414 1366 1454 +f 1454 1366 1554 +f 1454 1554 1618 +f 1618 1554 1664 +f 1618 1664 1828 +f 1828 1664 1818 +f 1828 1818 1928 +f 1928 1818 1854 +f 1928 1854 2056 +f 2056 1854 2066 +f 2056 2066 2098 +f 2098 2066 2104 +f 2098 2104 2226 +f 2226 2104 2282 +f 2226 2282 2404 +f 2404 2282 2416 +f 2404 2416 2534 +f 2534 2416 2514 +f 2534 2514 2742 +f 2742 2514 2722 +f 2742 2722 2830 +f 2830 2722 2788 +f 2830 2788 3010 +f 3010 2788 2946 +f 3010 2946 3160 +f 3160 2946 3080 +f 3160 3080 3244 +f 3244 3080 3178 +f 3244 3178 3388 +f 3388 3178 3324 +f 3388 3324 3542 +f 3542 3324 3562 +f 3542 3562 3652 +f 3652 3562 3626 +f 3652 3626 3724 +f 3724 3626 3746 +f 3724 3746 3870 +f 3870 3746 3930 +f 3870 3930 4046 +f 4046 3930 4074 +f 4046 4074 4190 +f 4190 4074 4226 +f 4190 4226 4270 +f 4270 4226 4356 +f 4270 4356 4396 +f 4396 4356 4446 +f 4396 4446 4512 +f 4512 4446 4518 +f 4512 4518 4666 +f 4666 4518 4696 +f 4666 4696 4764 +f 4764 4696 4780 +f 4764 4780 4902 +f 4902 4780 4912 +f 4902 4912 5074 +f 5074 4912 5080 +f 5074 5080 5162 +f 5162 5080 5274 +f 5162 5274 5368 +f 5368 5274 5343 +f 5368 5343 5494 +f 5494 5343 5546 +f 5494 5546 5666 +f 5666 5546 5612 +f 5666 5612 5740 +f 5740 5612 5696 +f 5740 5696 5864 +f 5864 5696 5878 +f 5864 5878 6052 +f 6052 5878 6038 +f 6052 6038 6152 +f 6152 6038 6096 +f 6152 6096 6236 +f 6236 6096 6282 +f 6236 6282 6386 +f 6386 6282 6398 +f 6386 6398 6474 +f 6474 6398 6552 +f 6474 6552 6706 +f 6706 6552 6704 +f 6706 6704 6828 +f 6828 6704 6798 +f 6828 6798 6968 +f 6968 6798 6916 +f 6968 6916 7060 +f 7060 6916 7048 +f 7060 7048 7218 +f 7218 7048 7215 +f 7218 7215 7280 +f 7280 7215 7276 +f 7280 7276 7426 +f 7426 7276 7434 +f 7426 7434 7574 +f 7574 7434 7632 +f 7574 7632 7718 +f 7718 7632 7686 +f 7718 7686 7768 +f 7768 7686 7868 +f 7768 7868 7931 +f 88 118 188 +f 188 118 286 +f 188 286 328 +f 328 286 327 +f 328 327 479 +f 479 327 458 +f 479 458 674 +f 674 458 621 +f 674 621 690 +f 690 621 794 +f 690 794 926 +f 926 794 924 +f 926 924 1017 +f 1017 924 962 +f 1017 962 1178 +f 1178 962 1110 +f 1178 1110 1314 +f 1314 1110 1224 +f 1314 1224 1346 +f 1346 1224 1414 +f 1346 1414 1466 +f 1466 1414 1454 +f 1466 1454 1614 +f 1614 1454 1618 +f 1614 1618 1786 +f 1786 1618 1828 +f 1786 1828 1952 +f 1952 1828 1928 +f 1952 1928 2010 +f 2010 1928 2056 +f 2010 2056 2102 +f 2102 2056 2098 +f 2102 2098 2276 +f 2276 2098 2226 +f 2276 2226 2456 +f 2456 2226 2404 +f 2456 2404 2520 +f 2520 2404 2534 +f 2520 2534 2690 +f 2690 2534 2742 +f 2690 2742 2874 +f 2874 2742 2830 +f 2874 2830 2926 +f 2926 2830 3010 +f 2926 3010 3086 +f 3086 3010 3160 +f 3086 3160 3258 +f 3258 3160 3244 +f 3258 3244 3426 +f 3426 3244 3388 +f 3426 3388 3508 +f 3508 3388 3542 +f 3508 3542 3640 +f 3640 3542 3652 +f 3640 3652 3814 +f 3814 3652 3724 +f 3814 3724 3867 +f 3867 3724 3870 +f 3867 3870 4014 +f 4014 3870 4046 +f 4014 4046 4172 +f 4172 4046 4190 +f 4172 4190 4340 +f 4340 4190 4270 +f 4340 4270 4484 +f 4484 4270 4396 +f 4484 4396 4542 +f 4542 4396 4512 +f 4542 4512 4730 +f 4730 4512 4666 +f 4730 4666 4768 +f 4768 4666 4764 +f 4768 4764 4906 +f 4906 4764 4902 +f 4906 4902 5128 +f 5128 4902 5074 +f 5128 5074 5276 +f 5276 5074 5162 +f 5276 5162 5344 +f 5344 5162 5368 +f 5344 5368 5534 +f 5534 5368 5494 +f 5534 5494 5570 +f 5570 5494 5666 +f 5570 5666 5802 +f 5802 5666 5740 +f 5802 5740 5920 +f 5920 5740 5864 +f 5920 5864 5962 +f 5962 5864 6052 +f 5962 6052 6078 +f 6078 6052 6152 +f 6078 6152 6230 +f 6230 6152 6236 +f 6230 6236 6378 +f 6378 6236 6386 +f 6378 6386 6556 +f 6556 6386 6474 +f 6556 6474 6698 +f 6698 6474 6706 +f 6698 6706 6846 +f 6846 6706 6828 +f 6846 6828 6936 +f 6936 6828 6968 +f 6936 6968 7108 +f 7108 6968 7060 +f 7108 7060 7206 +f 7206 7060 7218 +f 7206 7218 7298 +f 7298 7218 7280 +f 7298 7280 7456 +f 7456 7280 7426 +f 7456 7426 7622 +f 7622 7426 7574 +f 7622 7574 7700 +f 7700 7574 7718 +f 7700 7718 7844 +f 7844 7718 7768 +f 7844 7768 7913 +f 58 88 222 +f 222 88 188 +f 222 188 354 +f 354 188 328 +f 354 328 520 +f 520 328 479 +f 520 479 622 +f 622 479 674 +f 622 674 694 +f 694 674 690 +f 694 690 878 +f 878 690 926 +f 878 926 944 +f 944 926 1017 +f 944 1017 1150 +f 1150 1017 1178 +f 1150 1178 1258 +f 1258 1178 1314 +f 1258 1314 1395 +f 1395 1314 1346 +f 1395 1346 1473 +f 1473 1346 1466 +f 1473 1466 1672 +f 1672 1466 1614 +f 1672 1614 1822 +f 1822 1614 1786 +f 1822 1786 1887 +f 1887 1786 1952 +f 1887 1952 2006 +f 2006 1952 2010 +f 2006 2010 2123 +f 2123 2010 2102 +f 2123 2102 2242 +f 2242 2102 2276 +f 2242 2276 2476 +f 2476 2276 2456 +f 2476 2456 2618 +f 2618 2456 2520 +f 2618 2520 2762 +f 2762 2520 2690 +f 2762 2690 2854 +f 2854 2690 2874 +f 2854 2874 2912 +f 2912 2874 2926 +f 2912 2926 3096 +f 3096 2926 3086 +f 3096 3086 3204 +f 3204 3086 3258 +f 3204 3258 3315 +f 3315 3258 3426 +f 3315 3426 3462 +f 3462 3426 3508 +f 3462 3508 3670 +f 3670 3508 3640 +f 3670 3640 3706 +f 3706 3640 3814 +f 3706 3814 3860 +f 3860 3814 3867 +f 3860 3867 4050 +f 4050 3867 4014 +f 4050 4014 4182 +f 4182 4014 4172 +f 4182 4172 4234 +f 4234 4172 4340 +f 4234 4340 4444 +f 4444 4340 4484 +f 4444 4484 4560 +f 4560 4484 4542 +f 4560 4542 4712 +f 4712 4542 4730 +f 4712 4730 4814 +f 4814 4730 4768 +f 4814 4768 4990 +f 4990 4768 4906 +f 4990 4906 5050 +f 5050 4906 5128 +f 5050 5128 5252 +f 5252 5128 5276 +f 5252 5276 5386 +f 5386 5276 5344 +f 5386 5344 5438 +f 5438 5344 5534 +f 5438 5534 5634 +f 5634 5534 5570 +f 5634 5570 5772 +f 5772 5570 5802 +f 5772 5802 5898 +f 5898 5802 5920 +f 5898 5920 5998 +f 5998 5920 5962 +f 5998 5962 6110 +f 6110 5962 6078 +f 6110 6078 6302 +f 6302 6078 6230 +f 6302 6230 6406 +f 6406 6230 6378 +f 6406 6378 6508 +f 6508 6378 6556 +f 6508 6556 6672 +f 6672 6556 6698 +f 6672 6698 6852 +f 6852 6698 6846 +f 6852 6846 6978 +f 6978 6846 6936 +f 6978 6936 7034 +f 7034 6936 7108 +f 7034 7108 7242 +f 7242 7108 7206 +f 7242 7206 7284 +f 7284 7206 7298 +f 7284 7298 7494 +f 7494 7298 7456 +f 7494 7456 7528 +f 7528 7456 7622 +f 7528 7622 7724 +f 7724 7622 7700 +f 7724 7700 7834 +f 7834 7700 7844 +f 7834 7844 7927 +f 75 58 204 +f 204 58 222 +f 204 222 346 +f 346 222 354 +f 346 354 514 +f 514 354 520 +f 514 520 658 +f 658 520 622 +f 658 622 732 +f 732 622 694 +f 732 694 886 +f 886 694 878 +f 886 878 1018 +f 1018 878 944 +f 1018 944 1068 +f 1068 944 1150 +f 1068 1150 1300 +f 1300 1150 1258 +f 1300 1258 1334 +f 1334 1258 1395 +f 1334 1395 1484 +f 1484 1395 1473 +f 1484 1473 1585 +f 1585 1473 1672 +f 1585 1672 1768 +f 1768 1672 1822 +f 1768 1822 1866 +f 1866 1822 1887 +f 1866 1887 2004 +f 2004 1887 2006 +f 2004 2006 2150 +f 2150 2006 2123 +f 2150 2123 2230 +f 2230 2123 2242 +f 2230 2242 2368 +f 2368 2242 2476 +f 2368 2476 2528 +f 2528 2476 2618 +f 2528 2618 2636 +f 2636 2618 2762 +f 2636 2762 2782 +f 2782 2762 2854 +f 2782 2854 2954 +f 2954 2854 2912 +f 2954 2912 3136 +f 3136 2912 3096 +f 3136 3096 3182 +f 3182 3096 3204 +f 3182 3204 3336 +f 3336 3204 3315 +f 3336 3315 3456 +f 3456 3315 3462 +f 3456 3462 3662 +f 3662 3462 3670 +f 3662 3670 3804 +f 3804 3670 3706 +f 3804 3706 3922 +f 3922 3706 3860 +f 3922 3860 4008 +f 4008 3860 4050 +f 4008 4050 4120 +f 4120 4050 4182 +f 4120 4182 4272 +f 4272 4182 4234 +f 4272 4234 4460 +f 4460 4234 4444 +f 4460 4444 4558 +f 4558 4444 4560 +f 4558 4560 4738 +f 4738 4560 4712 +f 4738 4712 4810 +f 4810 4712 4814 +f 4810 4814 4974 +f 4974 4814 4990 +f 4974 4990 5132 +f 5132 4990 5050 +f 5132 5050 5268 +f 5268 5050 5252 +f 5268 5252 5384 +f 5384 5252 5386 +f 5384 5386 5532 +f 5532 5386 5438 +f 5532 5438 5578 +f 5578 5438 5634 +f 5578 5634 5723 +f 5723 5634 5772 +f 5723 5772 5858 +f 5858 5772 5898 +f 5858 5898 6070 +f 6070 5898 5998 +f 6070 5998 6162 +f 6162 5998 6110 +f 6162 6110 6326 +f 6326 6110 6302 +f 6326 6302 6342 +f 6342 6302 6406 +f 6342 6406 6536 +f 6536 6406 6508 +f 6536 6508 6604 +f 6604 6508 6672 +f 6604 6672 6736 +f 6736 6672 6852 +f 6736 6852 6958 +f 6958 6852 6978 +f 6958 6978 7078 +f 7078 6978 7034 +f 7078 7034 7248 +f 7248 7034 7242 +f 7248 7242 7384 +f 7384 7242 7284 +f 7384 7284 7464 +f 7464 7284 7494 +f 7464 7494 7558 +f 7558 7494 7528 +f 7558 7528 7740 +f 7740 7528 7724 +f 7740 7724 7776 +f 7776 7724 7834 +f 7776 7834 7883 +f 92 75 248 +f 248 75 204 +f 248 204 396 +f 396 204 346 +f 396 346 480 +f 480 346 514 +f 480 514 672 +f 672 514 658 +f 672 658 710 +f 710 658 732 +f 710 732 892 +f 892 732 886 +f 892 886 976 +f 976 886 1018 +f 976 1018 1134 +f 1134 1018 1068 +f 1134 1068 1246 +f 1246 1068 1300 +f 1246 1300 1418 +f 1418 1300 1334 +f 1418 1334 1482 +f 1482 1334 1484 +f 1482 1484 1642 +f 1642 1484 1585 +f 1642 1585 1727 +f 1727 1585 1768 +f 1727 1768 1900 +f 1900 1768 1866 +f 1900 1866 1984 +f 1984 1866 2004 +f 1984 2004 2200 +f 2200 2004 2150 +f 2200 2150 2278 +f 2278 2150 2230 +f 2278 2230 2482 +f 2482 2230 2368 +f 2482 2368 2538 +f 2538 2368 2528 +f 2538 2528 2672 +f 2672 2528 2636 +f 2672 2636 2792 +f 2792 2636 2782 +f 2792 2782 2956 +f 2956 2782 2954 +f 2956 2954 3082 +f 3082 2954 3136 +f 3082 3136 3174 +f 3174 3136 3182 +f 3174 3182 3378 +f 3378 3182 3336 +f 3378 3336 3546 +f 3546 3336 3456 +f 3546 3456 3682 +f 3682 3456 3662 +f 3682 3662 3830 +f 3830 3662 3804 +f 3830 3804 3926 +f 3926 3804 3922 +f 3926 3922 4090 +f 4090 3922 4008 +f 4090 4008 4162 +f 4162 4008 4120 +f 4162 4120 4332 +f 4332 4120 4272 +f 4332 4272 4474 +f 4474 4272 4460 +f 4474 4460 4614 +f 4614 4460 4558 +f 4614 4558 4710 +f 4710 4558 4738 +f 4710 4738 4784 +f 4784 4738 4810 +f 4784 4810 4904 +f 4904 4810 4974 +f 4904 4974 5076 +f 5076 4974 5132 +f 5076 5132 5166 +f 5166 5132 5268 +f 5166 5268 5306 +f 5306 5268 5384 +f 5306 5384 5520 +f 5520 5384 5532 +f 5520 5532 5674 +f 5674 5532 5578 +f 5674 5578 5724 +f 5724 5578 5723 +f 5724 5723 5888 +f 5888 5723 5858 +f 5888 5858 6006 +f 6006 5858 6070 +f 6006 6070 6154 +f 6154 6070 6162 +f 6154 6162 6286 +f 6286 6162 6326 +f 6286 6326 6354 +f 6354 6326 6342 +f 6354 6342 6500 +f 6500 6342 6536 +f 6500 6536 6606 +f 6606 6536 6604 +f 6606 6604 6786 +f 6786 6604 6736 +f 6786 6736 6974 +f 6974 6736 6958 +f 6974 6958 7106 +f 7106 6958 7078 +f 7106 7078 7160 +f 7160 7078 7248 +f 7160 7248 7346 +f 7346 7248 7384 +f 7346 7384 7492 +f 7492 7384 7464 +f 7492 7464 7584 +f 7584 7464 7558 +f 7584 7558 7726 +f 7726 7558 7740 +f 7726 7740 7810 +f 7810 7740 7776 +f 7810 7776 7911 +f 136 92 264 +f 264 92 248 +f 264 248 398 +f 398 248 396 +f 398 396 460 +f 460 396 480 +f 460 480 650 +f 650 480 672 +f 650 672 788 +f 788 672 710 +f 788 710 840 +f 840 710 892 +f 840 892 966 +f 966 892 976 +f 966 976 1158 +f 1158 976 1134 +f 1158 1134 1302 +f 1302 1134 1246 +f 1302 1246 1324 +f 1324 1246 1418 +f 1324 1418 1474 +f 1474 1418 1482 +f 1474 1482 1622 +f 1622 1482 1642 +f 1622 1642 1722 +f 1722 1642 1727 +f 1722 1727 1852 +f 1852 1727 1900 +f 1852 1900 2052 +f 2052 1900 1984 +f 2052 1984 2096 +f 2096 1984 2200 +f 2096 2200 2312 +f 2312 2200 2278 +f 2312 2278 2394 +f 2394 2278 2482 +f 2394 2482 2622 +f 2622 2482 2538 +f 2622 2538 2740 +f 2740 2538 2672 +f 2740 2672 2890 +f 2890 2672 2792 +f 2890 2792 2936 +f 2936 2792 2956 +f 2936 2956 3048 +f 3048 2956 3082 +f 3048 3082 3272 +f 3272 3082 3174 +f 3272 3174 3428 +f 3428 3174 3378 +f 3428 3378 3558 +f 3558 3378 3546 +f 3558 3546 3680 +f 3680 3546 3682 +f 3680 3682 3730 +f 3730 3682 3830 +f 3730 3830 3878 +f 3878 3830 3926 +f 3878 3926 4034 +f 4034 3926 4090 +f 4034 4090 4144 +f 4144 4090 4162 +f 4144 4162 4346 +f 4346 4162 4332 +f 4346 4332 4476 +f 4476 4332 4474 +f 4476 4474 4574 +f 4574 4474 4614 +f 4574 4614 4742 +f 4742 4614 4710 +f 4742 4710 4836 +f 4836 4710 4784 +f 4836 4784 4934 +f 4934 4784 4904 +f 4934 4904 5130 +f 5130 4904 5076 +f 5130 5076 5265 +f 5265 5076 5166 +f 5265 5166 5402 +f 5402 5166 5306 +f 5402 5306 5448 +f 5448 5306 5520 +f 5448 5520 5576 +f 5576 5520 5674 +f 5576 5674 5708 +f 5708 5674 5724 +f 5708 5724 5900 +f 5900 5724 5888 +f 5900 5888 5956 +f 5956 5888 6006 +f 5956 6006 6164 +f 6164 6006 6154 +f 6164 6154 6268 +f 6268 6154 6286 +f 6268 6286 6452 +f 6452 6286 6354 +f 6452 6354 6568 +f 6568 6354 6500 +f 6568 6500 6612 +f 6612 6500 6606 +f 6612 6606 6790 +f 6790 6606 6786 +f 6790 6786 6886 +f 6886 6786 6974 +f 6886 6974 7080 +f 7080 6974 7106 +f 7080 7106 7208 +f 7208 7106 7160 +f 7208 7160 7332 +f 7332 7160 7346 +f 7332 7346 7514 +f 7514 7346 7492 +f 7514 7492 7572 +f 7572 7492 7584 +f 7572 7584 7664 +f 7664 7584 7726 +f 7664 7726 7774 +f 7774 7726 7810 +f 7774 7810 7890 +f 146 136 288 +f 288 136 264 +f 288 264 376 +f 376 264 398 +f 376 398 450 +f 450 398 460 +f 450 460 568 +f 568 460 650 +f 568 650 688 +f 688 650 788 +f 688 788 862 +f 862 788 840 +f 862 840 948 +f 948 840 966 +f 948 966 1084 +f 1084 966 1158 +f 1084 1158 1220 +f 1220 1158 1302 +f 1220 1302 1378 +f 1378 1302 1324 +f 1378 1324 1506 +f 1506 1324 1474 +f 1506 1474 1598 +f 1598 1474 1622 +f 1598 1622 1762 +f 1762 1622 1722 +f 1762 1722 1872 +f 1872 1722 1852 +f 1872 1852 1994 +f 1994 1852 2052 +f 1994 2052 2166 +f 2166 2052 2096 +f 2166 2096 2214 +f 2214 2096 2312 +f 2214 2312 2382 +f 2382 2312 2394 +f 2382 2394 2588 +f 2588 2394 2622 +f 2588 2622 2646 +f 2646 2622 2740 +f 2646 2740 2790 +f 2790 2740 2890 +f 2790 2890 2982 +f 2982 2890 2936 +f 2982 2936 3084 +f 3084 2936 3048 +f 3084 3048 3288 +f 3288 3048 3272 +f 3288 3272 3316 +f 3316 3272 3428 +f 3316 3428 3550 +f 3550 3428 3558 +f 3550 3558 3678 +f 3678 3558 3680 +f 3678 3680 3704 +f 3704 3680 3730 +f 3704 3730 3838 +f 3838 3730 3878 +f 3838 3878 4086 +f 4086 3878 4034 +f 4086 4034 4100 +f 4100 4034 4144 +f 4100 4144 4246 +f 4246 4144 4346 +f 4246 4346 4370 +f 4370 4346 4476 +f 4370 4476 4584 +f 4584 4476 4574 +f 4584 4574 4636 +f 4636 4574 4742 +f 4636 4742 4830 +f 4830 4742 4836 +f 4830 4836 4938 +f 4938 4836 4934 +f 4938 4934 5112 +f 5112 4934 5130 +f 5112 5130 5272 +f 5272 5130 5265 +f 5272 5265 5356 +f 5356 5265 5402 +f 5356 5402 5502 +f 5502 5402 5448 +f 5502 5448 5652 +f 5652 5448 5576 +f 5652 5576 5684 +f 5684 5576 5708 +f 5684 5708 5842 +f 5842 5708 5900 +f 5842 5900 6044 +f 6044 5900 5956 +f 6044 5956 6084 +f 6084 5956 6164 +f 6084 6164 6280 +f 6280 6164 6268 +f 6280 6268 6410 +f 6410 6268 6452 +f 6410 6452 6484 +f 6484 6452 6568 +f 6484 6568 6652 +f 6652 6568 6612 +f 6652 6612 6784 +f 6784 6612 6790 +f 6784 6790 6962 +f 6962 6790 6886 +f 6962 6886 7086 +f 7086 6886 7080 +f 7086 7080 7184 +f 7184 7080 7208 +f 7184 7208 7356 +f 7356 7208 7332 +f 7356 7332 7408 +f 7408 7332 7514 +f 7408 7514 7536 +f 7536 7514 7572 +f 7536 7572 7650 +f 7650 7572 7664 +f 7650 7664 7771 +f 7771 7664 7774 +f 7771 7774 7881 +f 140 146 212 +f 212 146 288 +f 212 288 408 +f 408 288 376 +f 408 376 544 +f 544 376 450 +f 544 450 676 +f 676 450 568 +f 676 568 678 +f 678 568 688 +f 678 688 864 +f 864 688 862 +f 864 862 1014 +f 1014 862 948 +f 1014 948 1070 +f 1070 948 1084 +f 1070 1084 1251 +f 1251 1084 1220 +f 1251 1220 1360 +f 1360 1220 1378 +f 1360 1378 1503 +f 1503 1378 1506 +f 1503 1506 1698 +f 1698 1506 1598 +f 1698 1598 1802 +f 1802 1598 1762 +f 1802 1762 1930 +f 1930 1762 1872 +f 1930 1872 2034 +f 2034 1872 1994 +f 2034 1994 2182 +f 2182 1994 2166 +f 2182 2166 2316 +f 2316 2166 2214 +f 2316 2214 2360 +f 2360 2214 2382 +f 2360 2382 2616 +f 2616 2382 2588 +f 2616 2588 2650 +f 2650 2588 2646 +f 2650 2646 2786 +f 2786 2646 2790 +f 2786 2790 2910 +f 2910 2790 2982 +f 2910 2982 3098 +f 3098 2982 3084 +f 3098 3084 3282 +f 3282 3084 3288 +f 3282 3288 3416 +f 3416 3288 3316 +f 3416 3316 3494 +f 3494 3316 3550 +f 3494 3550 3690 +f 3690 3550 3678 +f 3690 3678 3764 +f 3764 3678 3704 +f 3764 3704 3882 +f 3882 3704 3838 +f 3882 3838 4094 +f 4094 3838 4086 +f 4094 4086 4200 +f 4200 4086 4100 +f 4200 4100 4292 +f 4292 4100 4246 +f 4292 4246 4468 +f 4468 4246 4370 +f 4468 4370 4536 +f 4536 4370 4584 +f 4536 4584 4704 +f 4704 4584 4636 +f 4704 4636 4860 +f 4860 4636 4830 +f 4860 4830 4924 +f 4924 4830 4938 +f 4924 4938 5040 +f 5040 4938 5112 +f 5040 5112 5172 +f 5172 5112 5272 +f 5172 5272 5346 +f 5346 5272 5356 +f 5346 5356 5452 +f 5452 5356 5502 +f 5452 5502 5636 +f 5636 5502 5652 +f 5636 5652 5806 +f 5806 5652 5684 +f 5806 5684 5824 +f 5824 5684 5842 +f 5824 5842 5966 +f 5966 5842 6044 +f 5966 6044 6120 +f 6120 6044 6084 +f 6120 6084 6212 +f 6212 6084 6280 +f 6212 6280 6400 +f 6400 6280 6410 +f 6400 6410 6566 +f 6566 6410 6484 +f 6566 6484 6678 +f 6678 6484 6652 +f 6678 6652 6740 +f 6740 6652 6784 +f 6740 6784 6866 +f 6866 6784 6962 +f 6866 6962 7120 +f 7120 6962 7086 +f 7120 7086 7236 +f 7236 7086 7184 +f 7236 7184 7388 +f 7388 7184 7356 +f 7388 7356 7504 +f 7504 7356 7408 +f 7504 7408 7538 +f 7538 7408 7536 +f 7538 7536 7688 +f 7688 7536 7650 +f 7688 7650 7840 +f 7840 7650 7771 +f 7840 7771 7910 +f 126 140 224 +f 224 140 212 +f 224 212 348 +f 348 212 408 +f 348 408 522 +f 522 408 544 +f 522 544 648 +f 648 544 676 +f 648 676 752 +f 752 676 678 +f 752 678 806 +f 806 678 864 +f 806 864 956 +f 956 864 1014 +f 956 1014 1062 +f 1062 1014 1070 +f 1062 1070 1292 +f 1292 1070 1251 +f 1292 1251 1368 +f 1368 1251 1360 +f 1368 1360 1532 +f 1532 1360 1503 +f 1532 1503 1634 +f 1634 1503 1698 +f 1634 1698 1712 +f 1712 1698 1802 +f 1712 1802 1926 +f 1926 1802 1930 +f 1926 1930 2024 +f 2024 1930 2034 +f 2024 2034 2124 +f 2124 2034 2182 +f 2124 2182 2322 +f 2322 2182 2316 +f 2322 2316 2364 +f 2364 2316 2360 +f 2364 2360 2620 +f 2620 2360 2616 +f 2620 2616 2760 +f 2760 2616 2650 +f 2760 2650 2886 +f 2886 2650 2786 +f 2886 2786 2906 +f 2906 2786 2910 +f 2906 2910 3132 +f 3132 2910 3098 +f 3132 3098 3198 +f 3198 3098 3282 +f 3198 3282 3400 +f 3400 3282 3416 +f 3400 3416 3496 +f 3496 3416 3494 +f 3496 3494 3688 +f 3688 3494 3690 +f 3688 3690 3794 +f 3794 3690 3764 +f 3794 3764 3896 +f 3896 3764 3882 +f 3896 3882 4056 +f 4056 3882 4094 +f 4056 4094 4146 +f 4146 4094 4200 +f 4146 4200 4278 +f 4278 4200 4292 +f 4278 4292 4456 +f 4456 4292 4468 +f 4456 4468 4534 +f 4534 4468 4536 +f 4534 4536 4746 +f 4746 4536 4704 +f 4746 4704 4828 +f 4828 4704 4860 +f 4828 4860 4898 +f 4898 4860 4924 +f 4898 4924 5084 +f 5084 4924 5040 +f 5084 5040 5178 +f 5178 5040 5172 +f 5178 5172 5328 +f 5328 5172 5346 +f 5328 5346 5420 +f 5420 5346 5452 +f 5420 5452 5638 +f 5638 5452 5636 +f 5638 5636 5752 +f 5752 5636 5806 +f 5752 5806 5868 +f 5868 5806 5824 +f 5868 5824 5950 +f 5950 5824 5966 +f 5950 5966 6132 +f 6132 5966 6120 +f 6132 6120 6284 +f 6284 6120 6212 +f 6284 6212 6346 +f 6346 6212 6400 +f 6346 6400 6538 +f 6538 6400 6566 +f 6538 6566 6674 +f 6674 6566 6678 +f 6674 6678 6760 +f 6760 6678 6740 +f 6760 6740 6960 +f 6960 6740 6866 +f 6960 6866 7104 +f 7104 6866 7120 +f 7104 7120 7190 +f 7190 7120 7236 +f 7190 7236 7294 +f 7294 7236 7388 +f 7294 7388 7436 +f 7436 7388 7504 +f 7436 7504 7614 +f 7614 7504 7538 +f 7614 7538 7652 +f 7652 7538 7688 +f 7652 7688 7798 +f 7798 7688 7840 +f 7798 7840 7914 +f 154 126 168 +f 168 126 224 +f 168 224 302 +f 302 224 348 +f 302 348 490 +f 490 348 522 +f 490 522 668 +f 668 522 648 +f 668 648 778 +f 778 648 752 +f 778 752 884 +f 884 752 806 +f 884 806 936 +f 936 806 956 +f 936 956 1154 +f 1154 956 1062 +f 1154 1062 1312 +f 1312 1062 1292 +f 1312 1292 1348 +f 1348 1292 1368 +f 1348 1368 1446 +f 1446 1368 1532 +f 1446 1532 1668 +f 1668 1532 1634 +f 1668 1634 1796 +f 1796 1634 1712 +f 1796 1712 1842 +f 1842 1712 1926 +f 1842 1926 1966 +f 1966 1926 2024 +f 1966 2024 2120 +f 2120 2024 2124 +f 2120 2124 2326 +f 2326 2124 2322 +f 2326 2322 2440 +f 2440 2322 2364 +f 2440 2364 2540 +f 2540 2364 2620 +f 2540 2620 2654 +f 2654 2620 2760 +f 2654 2760 2796 +f 2796 2760 2886 +f 2796 2886 3014 +f 3014 2886 2906 +f 3014 2906 3056 +f 3056 2906 3132 +f 3056 3132 3210 +f 3210 3132 3198 +f 3210 3198 3326 +f 3326 3198 3400 +f 3326 3400 3476 +f 3476 3400 3496 +f 3476 3496 3636 +f 3636 3496 3688 +f 3636 3688 3790 +f 3790 3688 3794 +f 3790 3794 3846 +f 3846 3794 3896 +f 3846 3896 4006 +f 4006 3896 4056 +f 4006 4056 4208 +f 4208 4056 4146 +f 4208 4146 4342 +f 4342 4146 4278 +f 4342 4278 4380 +f 4380 4278 4456 +f 4380 4456 4514 +f 4514 4456 4534 +f 4514 4534 4638 +f 4638 4534 4746 +f 4638 4746 4804 +f 4804 4746 4828 +f 4804 4828 4988 +f 4988 4828 4898 +f 4988 4898 5048 +f 5048 4898 5084 +f 5048 5084 5184 +f 5184 5084 5178 +f 5184 5178 5316 +f 5316 5178 5328 +f 5316 5328 5422 +f 5422 5328 5420 +f 5422 5420 5662 +f 5662 5420 5638 +f 5662 5638 5750 +f 5750 5638 5752 +f 5750 5752 5876 +f 5876 5752 5868 +f 5876 5868 5968 +f 5968 5868 5950 +f 5968 5950 6140 +f 6140 5950 6132 +f 6140 6132 6248 +f 6248 6132 6284 +f 6248 6284 6458 +f 6458 6284 6346 +f 6458 6346 6558 +f 6558 6346 6538 +f 6558 6538 6670 +f 6670 6538 6674 +f 6670 6674 6788 +f 6788 6674 6760 +f 6788 6760 6858 +f 6858 6760 6960 +f 6858 6960 7050 +f 7050 6960 7104 +f 7050 7104 7224 +f 7224 7104 7190 +f 7224 7190 7320 +f 7320 7190 7294 +f 7320 7294 7446 +f 7446 7294 7436 +f 7446 7436 7628 +f 7628 7436 7614 +f 7628 7614 7648 +f 7648 7614 7652 +f 7648 7652 7812 +f 7812 7652 7798 +f 7812 7798 7893 +f 122 154 258 +f 258 154 168 +f 258 168 362 +f 362 168 302 +f 362 302 486 +f 486 302 490 +f 486 490 606 +f 606 490 668 +f 606 668 746 +f 746 668 778 +f 746 778 820 +f 820 778 884 +f 820 884 990 +f 990 884 936 +f 990 936 1132 +f 1132 936 1154 +f 1132 1154 1206 +f 1206 1154 1312 +f 1206 1312 1370 +f 1370 1312 1348 +f 1370 1348 1530 +f 1530 1348 1446 +f 1530 1446 1638 +f 1638 1446 1668 +f 1638 1668 1824 +f 1824 1668 1796 +f 1824 1796 1830 +f 1830 1796 1842 +f 1830 1842 2058 +f 2058 1842 1966 +f 2058 1966 2198 +f 2198 1966 2120 +f 2198 2120 2332 +f 2332 2120 2326 +f 2332 2326 2484 +f 2484 2326 2440 +f 2484 2440 2502 +f 2502 2440 2540 +f 2502 2540 2652 +f 2652 2540 2654 +f 2652 2654 2812 +f 2812 2654 2796 +f 2812 2796 2948 +f 2948 2796 3014 +f 2948 3014 3068 +f 3068 3014 3056 +f 3068 3056 3206 +f 3206 3056 3210 +f 3206 3210 3360 +f 3360 3210 3326 +f 3360 3326 3504 +f 3504 3326 3476 +f 3504 3476 3590 +f 3590 3476 3636 +f 3590 3636 3776 +f 3776 3636 3790 +f 3776 3790 3850 +f 3850 3790 3846 +f 3850 3846 4004 +f 4004 3846 4006 +f 4004 4006 4206 +f 4206 4006 4208 +f 4206 4208 4254 +f 4254 4208 4342 +f 4254 4342 4466 +f 4466 4342 4380 +f 4466 4380 4612 +f 4612 4380 4514 +f 4612 4514 4660 +f 4660 4514 4638 +f 4660 4638 4776 +f 4776 4638 4804 +f 4776 4804 4894 +f 4894 4804 4988 +f 4894 4988 5026 +f 5026 4988 5048 +f 5026 5048 5188 +f 5188 5048 5184 +f 5188 5184 5330 +f 5330 5184 5316 +f 5330 5316 5470 +f 5470 5316 5422 +f 5470 5422 5648 +f 5648 5422 5662 +f 5648 5662 5800 +f 5800 5662 5750 +f 5800 5750 5820 +f 5820 5750 5876 +f 5820 5876 5960 +f 5960 5876 5968 +f 5960 5968 6086 +f 6086 5968 6140 +f 6086 6140 6264 +f 6264 6140 6248 +f 6264 6248 6348 +f 6348 6248 6458 +f 6348 6458 6526 +f 6526 6458 6558 +f 6526 6558 6690 +f 6690 6558 6670 +f 6690 6670 6848 +f 6848 6670 6788 +f 6848 6788 6912 +f 6912 6788 6858 +f 6912 6858 7100 +f 7100 6858 7050 +f 7100 7050 7232 +f 7232 7050 7224 +f 7232 7224 7310 +f 7310 7224 7320 +f 7310 7320 7438 +f 7438 7320 7446 +f 7438 7446 7586 +f 7586 7446 7628 +f 7586 7628 7708 +f 7708 7628 7648 +f 7708 7648 7856 +f 7856 7648 7812 +f 7856 7812 7923 +f 144 122 202 +f 202 122 258 +f 202 258 308 +f 308 258 362 +f 308 362 510 +f 510 362 486 +f 510 486 594 +f 594 486 606 +f 594 606 734 +f 734 606 746 +f 734 746 810 +f 810 746 820 +f 810 820 958 +f 958 820 990 +f 958 990 1152 +f 1152 990 1132 +f 1152 1132 1244 +f 1244 1132 1206 +f 1244 1206 1422 +f 1422 1206 1370 +f 1422 1370 1516 +f 1516 1370 1530 +f 1516 1530 1678 +f 1678 1530 1638 +f 1678 1638 1748 +f 1748 1638 1824 +f 1748 1824 1902 +f 1902 1824 1830 +f 1902 1830 2002 +f 2002 1830 2058 +f 2002 2058 2154 +f 2154 2058 2198 +f 2154 2198 2328 +f 2328 2198 2332 +f 2328 2332 2450 +f 2450 2332 2484 +f 2450 2484 2516 +f 2516 2484 2502 +f 2516 2502 2736 +f 2736 2502 2652 +f 2736 2652 2804 +f 2804 2652 2812 +f 2804 2812 3020 +f 3020 2812 2948 +f 3020 2948 3040 +f 3040 2948 3068 +f 3040 3068 3224 +f 3224 3068 3206 +f 3224 3206 3424 +f 3424 3206 3360 +f 3424 3360 3468 +f 3468 3360 3504 +f 3468 3504 3606 +f 3606 3504 3590 +f 3606 3590 3810 +f 3810 3590 3776 +f 3810 3776 3932 +f 3932 3776 3850 +f 3932 3850 3968 +f 3968 3850 4004 +f 3968 4004 4224 +f 4224 4004 4206 +f 4224 4206 4306 +f 4306 4206 4254 +f 4306 4254 4442 +f 4442 4254 4466 +f 4442 4466 4604 +f 4604 4466 4612 +f 4604 4612 4686 +f 4686 4612 4660 +f 4686 4660 4846 +f 4846 4660 4776 +f 4846 4776 5018 +f 5018 4776 4894 +f 5018 4894 5064 +f 5064 4894 5026 +f 5064 5026 5160 +f 5160 5026 5188 +f 5160 5188 5372 +f 5372 5188 5330 +f 5372 5330 5444 +f 5444 5330 5470 +f 5444 5470 5562 +f 5562 5470 5648 +f 5562 5648 5694 +f 5694 5648 5800 +f 5694 5800 5906 +f 5906 5800 5820 +f 5906 5820 6004 +f 6004 5820 5960 +f 6004 5960 6138 +f 6138 5960 6086 +f 6138 6086 6294 +f 6294 6086 6264 +f 6294 6264 6358 +f 6358 6264 6348 +f 6358 6348 6564 +f 6564 6348 6526 +f 6564 6526 6598 +f 6598 6526 6690 +f 6598 6690 6776 +f 6776 6690 6848 +f 6776 6848 6878 +f 6878 6848 6912 +f 6878 6912 7122 +f 7122 6912 7100 +f 7122 7100 7166 +f 7166 7100 7232 +f 7166 7232 7318 +f 7318 7232 7310 +f 7318 7310 7406 +f 7406 7310 7438 +f 7406 7438 7620 +f 7620 7438 7586 +f 7620 7586 7734 +f 7734 7586 7708 +f 7734 7708 7854 +f 7854 7708 7856 +f 7854 7856 7907 +f 120 144 268 +f 268 144 202 +f 268 202 350 +f 350 202 308 +f 350 308 422 +f 422 308 510 +f 422 510 640 +f 640 510 594 +f 640 594 714 +f 714 594 734 +f 714 734 902 +f 902 734 810 +f 902 810 1056 +f 1056 810 958 +f 1056 958 1098 +f 1098 958 1152 +f 1098 1152 1276 +f 1276 1152 1244 +f 1276 1244 1380 +f 1380 1244 1422 +f 1380 1422 1478 +f 1478 1422 1516 +f 1478 1516 1582 +f 1582 1516 1678 +f 1582 1678 1788 +f 1788 1678 1748 +f 1788 1748 1914 +f 1914 1748 1902 +f 1914 1902 2026 +f 2026 1902 2002 +f 2026 2002 2142 +f 2142 2002 2154 +f 2142 2154 2314 +f 2314 2154 2328 +f 2314 2328 2374 +f 2374 2328 2450 +f 2374 2450 2594 +f 2594 2450 2516 +f 2594 2516 2750 +f 2750 2516 2736 +f 2750 2736 2800 +f 2800 2736 2804 +f 2800 2804 2916 +f 2916 2804 3020 +f 2916 3020 3130 +f 3130 3020 3040 +f 3130 3040 3264 +f 3264 3040 3224 +f 3264 3224 3368 +f 3368 3224 3424 +f 3368 3424 3538 +f 3538 3424 3468 +f 3538 3468 3656 +f 3656 3468 3606 +f 3656 3606 3760 +f 3760 3606 3810 +f 3760 3810 3960 +f 3960 3810 3932 +f 3960 3932 4078 +f 4078 3932 3968 +f 4078 3968 4112 +f 4112 3968 4224 +f 4112 4224 4236 +f 4236 4224 4306 +f 4236 4306 4376 +f 4376 4306 4442 +f 4376 4442 4500 +f 4500 4442 4604 +f 4500 4604 4752 +f 4752 4604 4686 +f 4752 4686 4770 +f 4770 4686 4846 +f 4770 4846 4976 +f 4976 4846 5018 +f 4976 5018 5088 +f 5088 5018 5064 +f 5088 5064 5248 +f 5248 5064 5160 +f 5248 5160 5302 +f 5302 5160 5372 +f 5302 5372 5504 +f 5504 5372 5444 +f 5504 5444 5566 +f 5566 5444 5562 +f 5566 5562 5768 +f 5768 5562 5694 +f 5768 5694 5934 +f 5934 5694 5906 +f 5934 5906 6024 +f 6024 5906 6004 +f 6024 6004 6144 +f 6144 6004 6138 +f 6144 6138 6206 +f 6206 6138 6294 +f 6206 6294 6412 +f 6412 6294 6358 +f 6412 6358 6516 +f 6516 6358 6564 +f 6516 6564 6668 +f 6668 6564 6598 +f 6668 6598 6734 +f 6734 6598 6776 +f 6734 6776 6888 +f 6888 6776 6878 +f 6888 6878 7112 +f 7112 6878 7122 +f 7112 7122 7154 +f 7154 7122 7166 +f 7154 7166 7336 +f 7336 7166 7318 +f 7336 7318 7448 +f 7448 7318 7406 +f 7448 7406 7616 +f 7616 7406 7620 +f 7616 7620 7694 +f 7694 7620 7734 +f 7694 7734 7794 +f 7794 7734 7854 +f 7794 7854 7887 +f 100 120 228 +f 228 120 268 +f 228 268 332 +f 332 268 350 +f 332 350 472 +f 472 350 422 +f 472 422 570 +f 570 422 640 +f 570 640 760 +f 760 640 714 +f 760 714 888 +f 888 714 902 +f 888 902 942 +f 942 902 1056 +f 942 1056 1064 +f 1064 1056 1098 +f 1064 1098 1226 +f 1226 1098 1276 +f 1226 1276 1372 +f 1372 1276 1380 +f 1372 1380 1546 +f 1546 1380 1478 +f 1546 1478 1644 +f 1644 1478 1582 +f 1644 1582 1782 +f 1782 1582 1788 +f 1782 1788 1864 +f 1864 1788 1914 +f 1864 1914 2082 +f 2082 1914 2026 +f 2082 2026 2118 +f 2118 2026 2142 +f 2118 2142 2304 +f 2304 2142 2314 +f 2304 2314 2486 +f 2486 2314 2374 +f 2486 2374 2552 +f 2552 2374 2594 +f 2552 2594 2748 +f 2748 2594 2750 +f 2748 2750 2772 +f 2772 2750 2800 +f 2772 2800 2960 +f 2960 2800 2916 +f 2960 2916 3144 +f 3144 2916 3130 +f 3144 3130 3186 +f 3186 3130 3264 +f 3186 3264 3322 +f 3322 3264 3368 +f 3322 3368 3486 +f 3486 3368 3538 +f 3486 3538 3608 +f 3608 3538 3656 +f 3608 3656 3754 +f 3754 3656 3760 +f 3754 3760 3916 +f 3916 3760 3960 +f 3916 3960 3970 +f 3970 3960 4078 +f 3970 4078 4106 +f 4106 4078 4112 +f 4106 4112 4288 +f 4288 4112 4236 +f 4288 4236 4392 +f 4392 4236 4376 +f 4392 4376 4540 +f 4540 4376 4500 +f 4540 4500 4716 +f 4716 4500 4752 +f 4716 4752 4862 +f 4862 4752 4770 +f 4862 4770 4936 +f 4936 4770 4976 +f 4936 4976 5096 +f 5096 4976 5088 +f 5096 5088 5236 +f 5236 5088 5248 +f 5236 5248 5300 +f 5300 5248 5302 +f 5300 5302 5514 +f 5514 5302 5504 +f 5514 5504 5560 +f 5560 5504 5566 +f 5560 5566 5714 +f 5714 5566 5768 +f 5714 5768 5874 +f 5874 5768 5934 +f 5874 5934 5944 +f 5944 5934 6024 +f 5944 6024 6126 +f 6126 6024 6144 +f 6126 6144 6324 +f 6324 6144 6206 +f 6324 6206 6362 +f 6362 6206 6412 +f 6362 6412 6580 +f 6580 6412 6516 +f 6580 6516 6640 +f 6640 6516 6668 +f 6640 6668 6744 +f 6744 6668 6734 +f 6744 6734 6860 +f 6860 6734 6888 +f 6860 6888 7098 +f 7098 6888 7112 +f 7098 7112 7200 +f 7200 7112 7154 +f 7200 7154 7370 +f 7370 7154 7336 +f 7370 7336 7508 +f 7508 7336 7448 +f 7508 7448 7612 +f 7612 7448 7616 +f 7612 7616 7750 +f 7750 7616 7694 +f 7750 7694 7816 +f 7816 7694 7794 +f 7816 7794 7895 +f 112 100 182 +f 182 100 228 +f 182 228 310 +f 310 228 332 +f 310 332 470 +f 470 332 472 +f 470 472 626 +f 626 472 570 +f 626 570 730 +f 730 570 760 +f 730 760 816 +f 816 760 888 +f 816 888 974 +f 974 888 942 +f 974 942 1082 +f 1082 942 1064 +f 1082 1064 1252 +f 1252 1064 1226 +f 1252 1226 1332 +f 1332 1226 1372 +f 1332 1372 1504 +f 1504 1372 1546 +f 1504 1546 1616 +f 1616 1546 1644 +f 1616 1644 1740 +f 1740 1644 1782 +f 1740 1782 1942 +f 1942 1782 1864 +f 1942 1864 2080 +f 2080 1864 2082 +f 2080 2082 2144 +f 2144 2082 2118 +f 2144 2118 2334 +f 2334 2118 2304 +f 2334 2304 2384 +f 2384 2304 2486 +f 2384 2486 2504 +f 2504 2486 2552 +f 2504 2552 2734 +f 2734 2552 2748 +f 2734 2748 2880 +f 2880 2748 2772 +f 2880 2772 2980 +f 2980 2772 2960 +f 2980 2960 3124 +f 3124 2960 3144 +f 3124 3144 3226 +f 3226 3144 3186 +f 3226 3186 3384 +f 3384 3186 3322 +f 3384 3322 3472 +f 3472 3322 3486 +f 3472 3486 3684 +f 3684 3486 3608 +f 3684 3608 3734 +f 3734 3608 3754 +f 3734 3754 3836 +f 3836 3754 3916 +f 3836 3916 4038 +f 4038 3916 3970 +f 4038 3970 4122 +f 4122 3970 4106 +f 4122 4106 4326 +f 4326 4106 4288 +f 4326 4288 4378 +f 4378 4288 4392 +f 4378 4392 4600 +f 4600 4392 4540 +f 4600 4540 4640 +f 4640 4540 4716 +f 4640 4716 4760 +f 4760 4716 4862 +f 4760 4862 5016 +f 5016 4862 4936 +f 5016 4936 5116 +f 5116 4936 5096 +f 5116 5096 5266 +f 5266 5096 5236 +f 5266 5236 5362 +f 5362 5236 5300 +f 5362 5300 5446 +f 5446 5300 5514 +f 5446 5514 5632 +f 5632 5514 5560 +f 5632 5560 5732 +f 5732 5560 5714 +f 5732 5714 5860 +f 5860 5714 5874 +f 5860 5874 6048 +f 6048 5874 5944 +f 6048 5944 6198 +f 6198 5944 6126 +f 6198 6126 6292 +f 6292 6126 6324 +f 6292 6324 6434 +f 6434 6324 6362 +f 6434 6362 6510 +f 6510 6362 6580 +f 6510 6580 6712 +f 6712 6580 6640 +f 6712 6640 6824 +f 6824 6640 6744 +f 6824 6744 6928 +f 6928 6744 6860 +f 6928 6860 7088 +f 7088 6860 7098 +f 7088 7098 7226 +f 7226 7098 7200 +f 7226 7200 7322 +f 7322 7200 7370 +f 7322 7370 7452 +f 7452 7370 7508 +f 7452 7508 7606 +f 7606 7508 7612 +f 7606 7612 7656 +f 7656 7612 7750 +f 7656 7750 7824 +f 7824 7750 7816 +f 7824 7816 7925 +f 110 112 238 +f 238 112 182 +f 238 182 374 +f 374 182 310 +f 374 310 494 +f 494 310 470 +f 494 470 616 +f 616 470 626 +f 616 626 686 +f 686 626 730 +f 686 730 834 +f 834 730 816 +f 834 816 1030 +f 1030 816 974 +f 1030 974 1182 +f 1182 974 1082 +f 1182 1082 1248 +f 1248 1082 1252 +f 1248 1252 1426 +f 1426 1252 1332 +f 1426 1332 1564 +f 1564 1332 1504 +f 1564 1504 1588 +f 1588 1504 1616 +f 1588 1616 1750 +f 1750 1616 1740 +f 1750 1740 1912 +f 1912 1740 1942 +f 1912 1942 1962 +f 1962 1942 2080 +f 1962 2080 2174 +f 2174 2080 2144 +f 2174 2144 2338 +f 2338 2144 2334 +f 2338 2334 2388 +f 2388 2334 2384 +f 2388 2384 2544 +f 2544 2384 2504 +f 2544 2504 2664 +f 2664 2504 2734 +f 2664 2734 2844 +f 2844 2734 2880 +f 2844 2880 2996 +f 2996 2880 2980 +f 2996 2980 3150 +f 3150 2980 3124 +f 3150 3124 3234 +f 3234 3124 3226 +f 3234 3226 3374 +f 3374 3226 3384 +f 3374 3384 3444 +f 3444 3384 3472 +f 3444 3472 3664 +f 3664 3472 3684 +f 3664 3684 3742 +f 3742 3684 3734 +f 3742 3734 3924 +f 3924 3734 3836 +f 3924 3836 3974 +f 3974 3836 4038 +f 3974 4038 4158 +f 4158 4038 4122 +f 4158 4122 4244 +f 4244 4122 4326 +f 4244 4326 4452 +f 4452 4326 4378 +f 4452 4378 4510 +f 4510 4378 4600 +f 4510 4600 4668 +f 4668 4600 4640 +f 4668 4640 4878 +f 4878 4640 4760 +f 4878 4760 4926 +f 4926 4760 5016 +f 4926 5016 5058 +f 5058 5016 5116 +f 5058 5116 5202 +f 5202 5116 5266 +f 5202 5266 5340 +f 5340 5266 5362 +f 5340 5362 5474 +f 5474 5362 5446 +f 5474 5446 5658 +f 5658 5446 5632 +f 5658 5632 5794 +f 5794 5632 5732 +f 5794 5732 5856 +f 5856 5732 5860 +f 5856 5860 6030 +f 6030 5860 6048 +f 6030 6048 6134 +f 6134 6048 6198 +f 6134 6198 6320 +f 6320 6198 6292 +f 6320 6292 6404 +f 6404 6292 6434 +f 6404 6434 6506 +f 6506 6434 6510 +f 6506 6510 6688 +f 6688 6510 6712 +f 6688 6712 6778 +f 6778 6712 6824 +f 6778 6824 6868 +f 6868 6824 6928 +f 6868 6928 7012 +f 7012 6928 7088 +f 7012 7088 7240 +f 7240 7088 7226 +f 7240 7226 7360 +f 7360 7226 7322 +f 7360 7322 7442 +f 7442 7322 7452 +f 7442 7452 7582 +f 7582 7452 7606 +f 7582 7606 7722 +f 7722 7606 7656 +f 7722 7656 7836 +f 7836 7656 7824 +f 7836 7824 7886 +f 68 110 172 +f 172 110 238 +f 172 238 372 +f 372 238 374 +f 372 374 424 +f 424 374 494 +f 424 494 644 +f 644 494 616 +f 644 616 790 +f 790 616 686 +f 790 686 836 +f 836 686 834 +f 836 834 964 +f 964 834 1030 +f 964 1030 1164 +f 1164 1030 1182 +f 1164 1182 1202 +f 1202 1182 1248 +f 1202 1248 1336 +f 1336 1248 1426 +f 1336 1426 1514 +f 1514 1426 1564 +f 1514 1564 1596 +f 1596 1564 1588 +f 1596 1588 1794 +f 1794 1588 1750 +f 1794 1750 1868 +f 1868 1750 1912 +f 1868 1912 1972 +f 1972 1912 1962 +f 1972 1962 2180 +f 2180 1962 2174 +f 2180 2174 2218 +f 2218 2174 2338 +f 2218 2338 2474 +f 2474 2338 2388 +f 2474 2388 2508 +f 2508 2388 2544 +f 2508 2544 2662 +f 2662 2544 2664 +f 2662 2664 2802 +f 2802 2664 2844 +f 2802 2844 2958 +f 2958 2844 2996 +f 2958 2996 3078 +f 3078 2996 3150 +f 3078 3150 3280 +f 3280 3150 3234 +f 3280 3234 3392 +f 3392 3234 3374 +f 3392 3374 3556 +f 3556 3374 3444 +f 3556 3444 3576 +f 3576 3444 3664 +f 3576 3664 3750 +f 3750 3664 3742 +f 3750 3742 3894 +f 3894 3742 3924 +f 3894 3924 4070 +f 4070 3924 3974 +f 4070 3974 4188 +f 4188 3974 4158 +f 4188 4158 4266 +f 4266 4158 4244 +f 4266 4244 4400 +f 4400 4244 4452 +f 4400 4452 4564 +f 4564 4452 4510 +f 4564 4510 4678 +f 4678 4510 4668 +f 4678 4668 4868 +f 4868 4668 4878 +f 4868 4878 4994 +f 4994 4878 4926 +f 4994 4926 5122 +f 5122 4926 5058 +f 5122 5058 5270 +f 5270 5058 5202 +f 5270 5202 5314 +f 5314 5202 5340 +f 5314 5340 5500 +f 5500 5340 5474 +f 5500 5474 5672 +f 5672 5474 5658 +f 5672 5658 5688 +f 5688 5658 5794 +f 5688 5794 5850 +f 5850 5794 5856 +f 5850 5856 6066 +f 6066 5856 6030 +f 6066 6030 6186 +f 6186 6030 6134 +f 6186 6134 6242 +f 6242 6134 6320 +f 6242 6320 6368 +f 6368 6320 6404 +f 6368 6404 6520 +f 6520 6404 6506 +f 6520 6506 6614 +f 6614 6506 6688 +f 6614 6688 6794 +f 6794 6688 6778 +f 6794 6778 6872 +f 6872 6778 6868 +f 6872 6868 7052 +f 7052 6868 7012 +f 7052 7012 7262 +f 7262 7012 7240 +f 7262 7240 7372 +f 7372 7240 7360 +f 7372 7360 7496 +f 7496 7360 7442 +f 7496 7442 7626 +f 7626 7442 7582 +f 7626 7582 7658 +f 7658 7582 7722 +f 7658 7722 7832 +f 7832 7722 7836 +f 7832 7836 7924 +f 42 68 220 +f 220 68 172 +f 220 172 360 +f 360 172 372 +f 360 372 548 +f 548 372 424 +f 548 424 580 +f 580 424 644 +f 580 644 706 +f 706 644 790 +f 706 790 922 +f 922 790 836 +f 922 836 998 +f 998 836 964 +f 998 964 1066 +f 1066 964 1164 +f 1066 1164 1200 +f 1200 1164 1202 +f 1200 1202 1396 +f 1396 1202 1336 +f 1396 1336 1572 +f 1572 1336 1514 +f 1572 1514 1646 +f 1646 1514 1596 +f 1646 1596 1760 +f 1760 1596 1794 +f 1760 1794 1870 +f 1870 1794 1868 +f 1870 1868 1978 +f 1978 1868 1972 +f 1978 1972 2208 +f 2208 1972 2180 +f 2208 2180 2324 +f 2324 2180 2218 +f 2324 2218 2472 +f 2472 2218 2474 +f 2472 2474 2518 +f 2518 2474 2508 +f 2518 2508 2726 +f 2726 2508 2662 +f 2726 2662 2798 +f 2798 2662 2802 +f 2798 2802 3030 +f 3030 2802 2958 +f 3030 2958 3158 +f 3158 2958 3078 +f 3158 3078 3191 +f 3191 3078 3280 +f 3191 3280 3308 +f 3308 3280 3392 +f 3308 3392 3442 +f 3442 3392 3556 +f 3442 3556 3572 +f 3572 3556 3576 +f 3572 3576 3824 +f 3824 3576 3750 +f 3824 3750 3842 +f 3842 3750 3894 +f 3842 3894 4092 +f 4092 3894 4070 +f 4092 4070 4108 +f 4108 4070 4188 +f 4108 4188 4358 +f 4358 4188 4266 +f 4358 4266 4486 +f 4486 4266 4400 +f 4486 4400 4608 +f 4608 4400 4564 +f 4608 4564 4734 +f 4734 4564 4678 +f 4734 4678 4778 +f 4778 4678 4868 +f 4778 4868 4900 +f 4900 4868 4994 +f 4900 4994 5110 +f 5110 4994 5122 +f 5110 5122 5224 +f 5224 5122 5270 +f 5224 5270 5394 +f 5394 5270 5314 +f 5394 5314 5476 +f 5476 5314 5500 +f 5476 5500 5600 +f 5600 5500 5672 +f 5600 5672 5704 +f 5704 5672 5688 +f 5704 5688 5894 +f 5894 5688 5850 +f 5894 5850 6000 +f 6000 5850 6066 +f 6000 6066 6108 +f 6108 6066 6186 +f 6108 6186 6314 +f 6314 6186 6242 +f 6314 6242 6444 +f 6444 6242 6368 +f 6444 6368 6544 +f 6544 6368 6520 +f 6544 6520 6696 +f 6696 6520 6614 +f 6696 6614 6814 +f 6814 6614 6794 +f 6814 6794 6910 +f 6910 6794 6872 +f 6910 6872 7130 +f 7130 6872 7052 +f 7130 7052 7246 +f 7246 7052 7262 +f 7246 7262 7282 +f 7282 7262 7372 +f 7282 7372 7420 +f 7420 7372 7496 +f 7420 7496 7608 +f 7608 7496 7626 +f 7608 7626 7662 +f 7662 7626 7658 +f 7662 7658 7772 +f 7772 7658 7832 +f 7772 7832 7929 +f 162 42 166 +f 166 42 220 +f 166 220 300 +f 300 220 360 +f 300 360 430 +f 430 360 548 +f 430 548 646 +f 646 548 580 +f 646 580 744 +f 744 580 706 +f 744 706 874 +f 874 706 922 +f 874 922 1026 +f 1026 922 998 +f 1026 998 1076 +f 1076 998 1066 +f 1076 1066 1230 +f 1230 1066 1200 +f 1230 1200 1438 +f 1438 1200 1396 +f 1438 1396 1556 +f 1556 1396 1572 +f 1556 1572 1602 +f 1602 1572 1646 +f 1602 1646 1704 +f 1704 1646 1760 +f 1704 1760 1938 +f 1938 1760 1870 +f 1938 1870 1960 +f 1960 1870 1978 +f 1960 1978 2194 +f 2194 1978 2208 +f 2194 2208 2320 +f 2320 2208 2324 +f 2320 2324 2480 +f 2480 2324 2472 +f 2480 2472 2526 +f 2526 2472 2518 +f 2526 2518 2712 +f 2712 2518 2726 +f 2712 2726 2818 +f 2818 2726 2798 +f 2818 2798 2908 +f 2908 2798 3030 +f 2908 3030 3044 +f 3044 3030 3158 +f 3044 3158 3296 +f 3296 3158 3191 +f 3296 3191 3312 +f 3312 3191 3308 +f 3312 3308 3524 +f 3524 3308 3442 +f 3524 3442 3638 +f 3638 3442 3572 +f 3638 3572 3716 +f 3716 3572 3824 +f 3716 3824 3962 +f 3962 3824 3842 +f 3962 3842 4088 +f 4088 3842 4092 +f 4088 4092 4214 +f 4214 4092 4108 +f 4214 4108 4274 +f 4274 4108 4358 +f 4274 4358 4394 +f 4394 4358 4486 +f 4394 4486 4572 +f 4572 4486 4608 +f 4572 4608 4744 +f 4744 4608 4734 +f 4744 4734 4870 +f 4870 4734 4778 +f 4870 4778 5000 +f 5000 4778 4900 +f 5000 4900 5090 +f 5090 4900 5110 +f 5090 5110 5218 +f 5218 5110 5224 +f 5218 5224 5374 +f 5374 5224 5394 +f 5374 5394 5424 +f 5424 5394 5476 +f 5424 5476 5582 +f 5582 5476 5600 +f 5582 5600 5804 +f 5804 5600 5704 +f 5804 5704 5932 +f 5932 5704 5894 +f 5932 5894 6050 +f 6050 5894 6000 +f 6050 6000 6076 +f 6076 6000 6108 +f 6076 6108 6298 +f 6298 6108 6314 +f 6298 6314 6366 +f 6366 6314 6444 +f 6366 6444 6504 +f 6504 6444 6544 +f 6504 6544 6644 +f 6644 6544 6696 +f 6644 6696 6766 +f 6766 6696 6814 +f 6766 6814 6876 +f 6876 6814 6910 +f 6876 6910 7016 +f 7016 6910 7130 +f 7016 7130 7254 +f 7254 7130 7246 +f 7254 7246 7376 +f 7376 7246 7282 +f 7376 7282 7478 +f 7478 7282 7420 +f 7478 7420 7592 +f 7592 7420 7608 +f 7592 7608 7746 +f 7746 7608 7662 +f 7746 7662 7783 +f 7783 7662 7772 +f 7783 7772 7897 +f 108 162 284 +f 284 162 166 +f 284 166 336 +f 336 166 300 +f 336 300 546 +f 546 300 430 +f 546 430 614 +f 614 430 646 +f 614 646 684 +f 684 646 744 +f 684 744 866 +f 866 744 874 +f 866 874 1044 +f 1044 874 1026 +f 1044 1026 1088 +f 1088 1026 1076 +f 1088 1076 1198 +f 1198 1076 1230 +f 1198 1230 1416 +f 1416 1230 1438 +f 1416 1438 1562 +f 1562 1438 1556 +f 1562 1556 1578 +f 1578 1556 1602 +f 1578 1602 1728 +f 1728 1602 1704 +f 1728 1704 1888 +f 1888 1704 1938 +f 1888 1938 2050 +f 2050 1938 1960 +f 2050 1960 2126 +f 2126 1960 2194 +f 2126 2194 2234 +f 2234 2194 2320 +f 2234 2320 2378 +f 2378 2320 2480 +f 2378 2480 2612 +f 2612 2480 2526 +f 2612 2526 2668 +f 2668 2526 2712 +f 2668 2712 2884 +f 2884 2712 2818 +f 2884 2818 2992 +f 2992 2818 2908 +f 2992 2908 3122 +f 3122 2908 3044 +f 3122 3044 3232 +f 3232 3044 3296 +f 3232 3296 3320 +f 3320 3296 3312 +f 3320 3312 3520 +f 3520 3312 3524 +f 3520 3524 3598 +f 3598 3524 3638 +f 3598 3638 3766 +f 3766 3638 3716 +f 3766 3716 3888 +f 3888 3716 3962 +f 3888 3962 4040 +f 4040 3962 4088 +f 4040 4088 4142 +f 4142 4088 4214 +f 4142 4214 4318 +f 4318 4214 4274 +f 4318 4274 4408 +f 4408 4274 4394 +f 4408 4394 4598 +f 4598 4394 4572 +f 4598 4572 4700 +f 4700 4572 4744 +f 4700 4744 4816 +f 4816 4744 4870 +f 4816 4870 4950 +f 4950 4870 5000 +f 4950 5000 5038 +f 5038 5000 5090 +f 5038 5090 5232 +f 5232 5090 5218 +f 5232 5218 5308 +f 5308 5218 5374 +f 5308 5374 5526 +f 5526 5374 5424 +f 5526 5424 5628 +f 5628 5424 5582 +f 5628 5582 5776 +f 5776 5582 5804 +f 5776 5804 5918 +f 5918 5804 5932 +f 5918 5932 6008 +f 6008 5932 6050 +f 6008 6050 6124 +f 6124 6050 6076 +f 6124 6076 6214 +f 6214 6076 6298 +f 6214 6298 6418 +f 6418 6298 6366 +f 6418 6366 6576 +f 6576 6366 6504 +f 6576 6504 6626 +f 6626 6504 6644 +f 6626 6644 6822 +f 6822 6644 6766 +f 6822 6766 6884 +f 6884 6766 6876 +f 6884 6876 7102 +f 7102 6876 7016 +f 7102 7016 7212 +f 7212 7016 7254 +f 7212 7254 7352 +f 7352 7254 7376 +f 7352 7376 7482 +f 7482 7376 7478 +f 7482 7478 7596 +f 7596 7478 7592 +f 7596 7592 7710 +f 7710 7592 7746 +f 7710 7746 7792 +f 7792 7746 7783 +f 7792 7783 7885 +f 38 108 184 +f 184 108 284 +f 184 284 358 +f 358 284 336 +f 358 336 526 +f 526 336 546 +f 526 546 562 +f 562 546 614 +f 562 614 796 +f 796 614 684 +f 796 684 908 +f 908 684 866 +f 908 866 1054 +f 1054 866 1044 +f 1054 1044 1186 +f 1186 1044 1088 +f 1186 1088 1192 +f 1192 1088 1198 +f 1192 1198 1358 +f 1358 1198 1416 +f 1358 1416 1544 +f 1544 1416 1562 +f 1544 1562 1586 +f 1586 1562 1578 +f 1586 1578 1706 +f 1706 1578 1728 +f 1706 1728 1838 +f 1838 1728 1888 +f 1838 1888 1986 +f 1986 1888 2050 +f 1986 2050 2184 +f 2184 2050 2126 +f 2184 2126 2296 +f 2296 2126 2234 +f 2296 2234 2392 +f 2392 2234 2378 +f 2392 2378 2570 +f 2570 2378 2612 +f 2570 2612 2698 +f 2698 2612 2668 +f 2698 2668 2870 +f 2870 2668 2884 +f 2870 2884 2930 +f 2930 2884 2992 +f 2930 2992 3166 +f 3166 2992 3122 +f 3166 3122 3192 +f 3192 3122 3232 +f 3192 3232 3304 +f 3304 3232 3320 +f 3304 3320 3526 +f 3526 3320 3520 +f 3526 3520 3650 +f 3650 3520 3598 +f 3650 3598 3748 +f 3748 3598 3766 +f 3748 3766 3868 +f 3868 3766 3888 +f 3868 3888 4060 +f 4060 3888 4040 +f 4060 4040 4154 +f 4154 4040 4142 +f 4154 4142 4260 +f 4260 4142 4318 +f 4260 4318 4390 +f 4390 4318 4408 +f 4390 4408 4580 +f 4580 4408 4598 +f 4580 4598 4722 +f 4722 4598 4700 +f 4722 4700 4880 +f 4880 4700 4816 +f 4880 4816 4964 +f 4964 4816 4950 +f 4964 4950 5068 +f 5068 4950 5038 +f 5068 5038 5196 +f 5196 5038 5232 +f 5196 5232 5338 +f 5338 5232 5308 +f 5338 5308 5468 +f 5468 5308 5526 +f 5468 5526 5558 +f 5558 5526 5628 +f 5558 5628 5738 +f 5738 5628 5776 +f 5738 5776 5904 +f 5904 5776 5918 +f 5904 5918 6036 +f 6036 5918 6008 +f 6036 6008 6112 +f 6112 6008 6124 +f 6112 6124 6322 +f 6322 6124 6214 +f 6322 6214 6388 +f 6388 6214 6418 +f 6388 6418 6534 +f 6534 6418 6576 +f 6534 6576 6708 +f 6708 6576 6626 +f 6708 6626 6812 +f 6812 6626 6822 +f 6812 6822 6926 +f 6926 6822 6884 +f 6926 6884 7074 +f 7074 6884 7102 +f 7074 7102 7216 +f 7216 7102 7212 +f 7216 7212 7296 +f 7296 7212 7352 +f 7296 7352 7502 +f 7502 7352 7482 +f 7502 7482 7590 +f 7590 7482 7596 +f 7590 7596 7752 +f 7752 7596 7710 +f 7752 7710 7842 +f 7842 7710 7792 +f 7842 7792 7905 +f 164 38 250 +f 250 38 184 +f 250 184 330 +f 330 184 358 +f 330 358 438 +f 438 358 526 +f 438 526 559 +f 559 526 562 +f 559 562 756 +f 756 562 796 +f 756 796 858 +f 858 796 908 +f 858 908 938 +f 938 908 1054 +f 938 1054 1148 +f 1148 1054 1186 +f 1148 1186 1280 +f 1280 1186 1192 +f 1280 1192 1328 +f 1328 1192 1358 +f 1328 1358 1456 +f 1456 1358 1544 +f 1456 1544 1695 +f 1695 1544 1586 +f 1695 1586 1770 +f 1770 1586 1706 +f 1770 1706 1847 +f 1847 1706 1838 +f 1847 1838 1990 +f 1990 1838 1986 +f 1990 1986 2206 +f 2206 1986 2184 +f 2206 2184 2220 +f 2220 2184 2296 +f 2220 2296 2436 +f 2436 2296 2392 +f 2436 2392 2506 +f 2506 2392 2570 +f 2506 2570 2666 +f 2666 2570 2698 +f 2666 2698 2895 +f 2895 2698 2870 +f 2895 2870 2939 +f 2939 2870 2930 +f 2939 2930 3143 +f 3143 2930 3166 +f 3143 3166 3214 +f 3214 3166 3192 +f 3214 3192 3394 +f 3394 3192 3304 +f 3394 3304 3499 +f 3499 3304 3526 +f 3499 3526 3692 +f 3692 3526 3650 +f 3692 3650 3812 +f 3812 3650 3748 +f 3812 3748 3859 +f 3859 3748 3868 +f 3859 3868 4054 +f 4054 3868 4060 +f 4054 4060 4222 +f 4222 4060 4154 +f 4222 4154 4330 +f 4330 4154 4260 +f 4330 4260 4384 +f 4384 4260 4390 +f 4384 4390 4596 +f 4596 4390 4580 +f 4596 4580 4695 +f 4695 4580 4722 +f 4695 4722 4875 +f 4875 4722 4880 +f 4875 4880 4944 +f 4944 4880 4964 +f 4944 4964 5124 +f 5124 4964 5068 +f 5124 5068 5194 +f 5194 5068 5196 +f 5194 5196 5379 +f 5379 5196 5338 +f 5379 5338 5432 +f 5432 5338 5468 +f 5432 5468 5596 +f 5596 5468 5558 +f 5596 5558 5780 +f 5780 5558 5738 +f 5780 5738 5913 +f 5913 5738 5904 +f 5913 5904 5992 +f 5992 5904 6036 +f 5992 6036 6182 +f 6182 6036 6112 +f 6182 6112 6296 +f 6296 6112 6322 +f 6296 6322 6350 +f 6350 6322 6388 +f 6350 6388 6533 +f 6533 6388 6534 +f 6533 6534 6620 +f 6620 6534 6708 +f 6620 6708 6732 +f 6732 6708 6812 +f 6732 6812 6970 +f 6970 6812 6926 +f 6970 6926 7019 +f 7019 6926 7074 +f 7019 7074 7178 +f 7178 7074 7216 +f 7178 7216 7374 +f 7374 7216 7296 +f 7374 7296 7471 +f 7471 7296 7502 +f 7471 7502 7578 +f 7578 7502 7590 +f 7578 7590 7654 +f 7654 7590 7752 +f 7654 7752 7852 +f 7852 7752 7842 +f 7852 7842 7918 +f 7899 8010 7786 +f 7786 8010 8005 +f 7786 8005 7736 +f 7736 8005 8003 +f 7736 8003 7568 +f 7568 8003 7999 +f 7568 7999 7490 +f 7490 7999 7995 +f 7490 7995 7340 +f 7340 7995 7991 +f 7340 7991 7152 +f 7152 7991 7985 +f 7152 7985 7094 +f 7094 7985 7983 +f 7094 7983 6915 +f 6915 7983 7977 +f 6915 7977 6749 +f 6749 7977 7973 +f 6749 7973 6609 +f 6609 7973 7971 +f 6609 7971 6574 +f 6574 7971 7967 +f 6574 7967 6416 +f 6416 7967 7963 +f 6416 7963 6239 +f 6239 7963 7957 +f 6239 7957 6082 +f 6082 7957 7953 +f 6082 7953 5964 +f 5964 7953 7949 +f 5964 7949 5814 +f 5814 7949 7945 +f 5814 7945 5699 +f 5699 7945 7941 +f 5699 7941 5555 +f 5555 7941 7937 +f 5555 7937 5516 +f 5516 7937 7397 +f 5516 7397 5410 +f 5410 7397 6999 +f 5410 6999 5245 +f 5245 6999 6725 +f 5245 6725 5036 +f 5036 6725 6465 +f 5036 6465 4998 +f 4998 6465 6333 +f 4998 6333 4834 +f 4834 6333 6071 +f 4834 6071 4642 +f 4642 6071 5939 +f 4642 5939 4592 +f 4592 5939 5807 +f 4592 5807 4425 +f 4425 5807 5547 +f 4425 5547 4302 +f 4302 5547 5417 +f 4302 5417 4176 +f 4176 5417 5285 +f 4176 5285 4029 +f 4029 5285 5153 +f 4029 5153 3913 +f 3913 5153 5021 +f 3913 5021 3784 +f 3784 5021 4887 +f 3784 4887 3645 +f 3645 4887 4757 +f 3645 4757 3535 +f 3535 4757 4625 +f 3535 4625 3328 +f 3328 4625 4493 +f 3328 4493 3177 +f 3177 4493 4359 +f 3177 4359 3134 +f 3134 4359 4227 +f 3134 4227 2932 +f 2932 4227 4095 +f 2932 4095 2896 +f 2896 4095 3965 +f 2896 3965 2706 +f 2706 3965 3831 +f 2706 3831 2522 +f 2522 3831 3699 +f 2522 3699 2420 +f 2420 3699 3567 +f 2420 3567 2285 +f 2285 3567 3437 +f 2285 3437 2188 +f 2188 3437 3431 +f 2188 3431 1970 +f 1970 3431 3301 +f 1970 3301 1884 +f 1884 3301 3167 +f 1884 3167 1766 +f 1766 3167 3035 +f 1766 3035 1601 +f 1601 3035 3031 +f 1601 3031 1552 +f 1552 3031 2901 +f 1552 2901 1354 +f 1354 2901 2767 +f 1354 2767 1287 +f 1287 2767 2765 +f 1287 2765 1078 +f 1078 2765 2633 +f 1078 2633 1009 +f 1009 2633 2629 +f 1009 2629 877 +f 877 2629 2497 +f 877 2497 764 +f 764 2497 2491 +f 764 2491 576 +f 576 2491 2487 +f 576 2487 528 +f 528 2487 2355 +f 528 2355 338 +f 338 2355 2353 +f 338 2353 292 +f 292 2353 2349 +f 292 2349 76 +f 76 2349 2345 +f 76 2345 5 +f 5 2345 2342 +f 5 2342 74 +f 74 2342 2346 +f 74 2346 291 +f 291 2346 2350 +f 291 2350 337 +f 337 2350 2354 +f 337 2354 527 +f 527 2354 2356 +f 527 2356 571 +f 571 2356 2488 +f 571 2488 761 +f 761 2488 2492 +f 761 2492 875 +f 875 2492 2498 +f 875 2498 1007 +f 1007 2498 2630 +f 1007 2630 1077 +f 1077 2630 2634 +f 1077 2634 1283 +f 1283 2634 2766 +f 1283 2766 1349 +f 1349 2766 2768 +f 1349 2768 1549 +f 1549 2768 2902 +f 1549 2902 1599 +f 1599 2902 3032 +f 1599 3032 1763 +f 1763 3032 3036 +f 1763 3036 1881 +f 1881 3036 3168 +f 1881 3168 1967 +f 1967 3168 3302 +f 1967 3302 2185 +f 2185 3302 3432 +f 2185 3432 2283 +f 2283 3432 3438 +f 2283 3438 2417 +f 2417 3438 3568 +f 2417 3568 2521 +f 2521 3568 3700 +f 2521 3700 2701 +f 2701 3700 3832 +f 2701 3832 2893 +f 2893 3832 3966 +f 2893 3966 2931 +f 2931 3966 4096 +f 2931 4096 3133 +f 3133 4096 4228 +f 3133 4228 3175 +f 3175 4228 4360 +f 3175 4360 3327 +f 3327 4360 4494 +f 3327 4494 3533 +f 3533 4494 4626 +f 3533 4626 3643 +f 3643 4626 4758 +f 3643 4758 3783 +f 3783 4758 4888 +f 3783 4888 3911 +f 3911 4888 5022 +f 3911 5022 4027 +f 4027 5022 5154 +f 4027 5154 4173 +f 4173 5154 5286 +f 4173 5286 4301 +f 4301 5286 5418 +f 4301 5418 4423 +f 4423 5418 5548 +f 4423 5548 4591 +f 4591 5548 5808 +f 4591 5808 4641 +f 4641 5808 5940 +f 4641 5940 4833 +f 4833 5940 6072 +f 4833 6072 4997 +f 4997 6072 6334 +f 4997 6334 5035 +f 5035 6334 6466 +f 5035 6466 5243 +f 5243 6466 6726 +f 5243 6726 5409 +f 5409 6726 7000 +f 5409 7000 5515 +f 5515 7000 7398 +f 5515 7398 5553 +f 5553 7398 7938 +f 5553 7938 5697 +f 5697 7938 7942 +f 5697 7942 5813 +f 5813 7942 7946 +f 5813 7946 5963 +f 5963 7946 7950 +f 5963 7950 6081 +f 6081 7950 7954 +f 6081 7954 6237 +f 6237 7954 7958 +f 6237 7958 6413 +f 6413 7958 7964 +f 6413 7964 6573 +f 6573 7964 7968 +f 6573 7968 6607 +f 6607 7968 7972 +f 6607 7972 6747 +f 6747 7972 7974 +f 6747 7974 6913 +f 6913 7974 7978 +f 6913 7978 7093 +f 7093 7978 7984 +f 7093 7984 7151 +f 7151 7984 7986 +f 7151 7986 7337 +f 7337 7986 7992 +f 7337 7992 7489 +f 7489 7992 7996 +f 7489 7996 7567 +f 7567 7996 8000 +f 7567 8000 7735 +f 7735 8000 8004 +f 7735 8004 7785 +f 7785 8004 8006 +f 7785 8006 7899 +f 7899 8006 8010 +f 8009 7901 8007 +f 8007 7901 7784 +f 8007 7784 8001 +f 8001 7784 7702 +f 8001 7702 7997 +f 7997 7702 7543 +f 7997 7543 7993 +f 7993 7543 7512 +f 7993 7512 7989 +f 7989 7512 7307 +f 7989 7307 7987 +f 7987 7307 7158 +f 7987 7158 7981 +f 7981 7158 7015 +f 7981 7015 7979 +f 7979 7015 6982 +f 7979 6982 7975 +f 7975 6982 6850 +f 7975 6850 7969 +f 7969 6850 6637 +f 7969 6637 7965 +f 7965 6637 6481 +f 7965 6481 7961 +f 7961 6481 6446 +f 7961 6446 7959 +f 7959 6446 6289 +f 7959 6289 7955 +f 7955 6289 6200 +f 7955 6200 7951 +f 7951 6200 6041 +f 7951 6041 7947 +f 7947 6041 5912 +f 7947 5912 7943 +f 7943 5912 5796 +f 7943 5796 7939 +f 7939 5796 5574 +f 7939 5574 7399 +f 7399 5574 5487 +f 7399 5487 7001 +f 7001 5487 5311 +f 7001 5311 6723 +f 6723 5311 5164 +f 6723 5164 6463 +f 6463 5164 5024 +f 6463 5024 6331 +f 6331 5024 4921 +f 6331 4921 6073 +f 6073 4921 4842 +f 6073 4842 5941 +f 5941 4842 4754 +f 5941 4754 5809 +f 5809 4754 4523 +f 5809 4523 5549 +f 5549 4523 4473 +f 5549 4473 5415 +f 5415 4473 4335 +f 5415 4335 5283 +f 5283 4335 4104 +f 5283 4104 5151 +f 5151 4104 3982 +f 5151 3982 5019 +f 5019 3982 3946 +f 5019 3946 4889 +f 4889 3946 3826 +f 4889 3826 4755 +f 4755 3826 3594 +f 4755 3594 4623 +f 4623 3594 3446 +f 4623 3446 4491 +f 4491 3446 3382 +f 4491 3382 4361 +f 4361 3382 3298 +f 4361 3298 4229 +f 4229 3298 3088 +f 4229 3088 4097 +f 4097 3088 3012 +f 4097 3012 3963 +f 3963 3012 2775 +f 3963 2775 3833 +f 3833 2775 2757 +f 3833 2757 3701 +f 3701 2757 2610 +f 3701 2610 3569 +f 3569 2610 2411 +f 3569 2411 3435 +f 3435 2411 2340 +f 3435 2340 3433 +f 3433 2340 2160 +f 3433 2160 3299 +f 3299 2160 1969 +f 3299 1969 3169 +f 3169 1969 1832 +f 3169 1832 3037 +f 3037 1832 1775 +f 3037 1775 3033 +f 3033 1775 1627 +f 3033 1627 2899 +f 2899 1627 1469 +f 2899 1469 2769 +f 2769 1469 1442 +f 2769 1442 2763 +f 2763 1442 1267 +f 2763 1267 2631 +f 2631 1267 1120 +f 2631 1120 2627 +f 2627 1120 1023 +f 2627 1023 2495 +f 2495 1023 814 +f 2495 814 2493 +f 2493 814 719 +f 2493 719 2489 +f 2489 719 584 +f 2489 584 2357 +f 2357 584 444 +f 2357 444 2351 +f 2351 444 294 +f 2351 294 2347 +f 2347 294 254 +f 2347 254 2343 +f 2343 254 89 +f 2343 89 2341 +f 2341 89 17 +f 2341 17 2344 +f 2344 17 81 +f 2344 81 2348 +f 2348 81 251 +f 2348 251 2352 +f 2352 251 293 +f 2352 293 2358 +f 2358 293 439 +f 2358 439 2490 +f 2490 439 581 +f 2490 581 2494 +f 2494 581 715 +f 2494 715 2496 +f 2496 715 813 +f 2496 813 2628 +f 2628 813 1021 +f 2628 1021 2632 +f 2632 1021 1111 +f 2632 1111 2764 +f 2764 1111 1261 +f 2764 1261 2770 +f 2770 1261 1439 +f 2770 1439 2900 +f 2900 1439 1467 +f 2900 1467 3034 +f 3034 1467 1623 +f 3034 1623 3038 +f 3038 1623 1771 +f 3038 1771 3170 +f 3170 1771 1831 +f 3170 1831 3300 +f 3300 1831 1968 +f 3300 1968 3434 +f 3434 1968 2155 +f 3434 2155 3436 +f 3436 2155 2339 +f 3436 2339 3570 +f 3570 2339 2405 +f 3570 2405 3702 +f 3702 2405 2609 +f 3702 2609 3834 +f 3834 2609 2755 +f 3834 2755 3964 +f 3964 2755 2773 +f 3964 2773 4098 +f 4098 2773 3011 +f 4098 3011 4230 +f 4230 3011 3087 +f 4230 3087 4362 +f 4362 3087 3297 +f 4362 3297 4492 +f 4492 3297 3381 +f 4492 3381 4624 +f 4624 3381 3445 +f 4624 3445 4756 +f 4756 3445 3593 +f 4756 3593 4890 +f 4890 3593 3825 +f 4890 3825 5020 +f 5020 3825 3945 +f 5020 3945 5152 +f 5152 3945 3981 +f 5152 3981 5284 +f 5284 3981 4103 +f 5284 4103 5416 +f 5416 4103 4333 +f 5416 4333 5550 +f 5550 4333 4471 +f 5550 4471 5810 +f 5810 4471 4521 +f 5810 4521 5942 +f 5942 4521 4753 +f 5942 4753 6074 +f 6074 4753 4839 +f 6074 4839 6332 +f 6332 4839 4919 +f 6332 4919 6464 +f 6464 4919 5023 +f 6464 5023 6724 +f 6724 5023 5163 +f 6724 5163 7002 +f 7002 5163 5309 +f 7002 5309 7400 +f 7400 5309 5485 +f 7400 5485 7940 +f 7940 5485 5573 +f 7940 5573 7944 +f 7944 5573 5795 +f 7944 5795 7948 +f 7948 5795 5908 +f 7948 5908 7952 +f 7952 5908 6039 +f 7952 6039 7956 +f 7956 6039 6199 +f 7956 6199 7960 +f 7960 6199 6287 +f 7960 6287 7962 +f 7962 6287 6445 +f 7962 6445 7966 +f 7966 6445 6479 +f 7966 6479 7970 +f 7970 6479 6635 +f 7970 6635 7976 +f 7976 6635 6849 +f 7976 6849 7980 +f 7980 6849 6981 +f 7980 6981 7982 +f 7982 6981 7013 +f 7982 7013 7988 +f 7988 7013 7157 +f 7988 7157 7990 +f 7990 7157 7305 +f 7990 7305 7994 +f 7994 7305 7511 +f 7994 7511 7998 +f 7998 7511 7541 +f 7998 7541 8002 +f 8002 7541 7701 +f 8002 7701 8008 +f 8008 7701 7781 +f 8008 7781 8009 +f 8009 7781 7901 diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/Inlet.obj b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/Inlet.obj new file mode 100644 index 0000000000000000000000000000000000000000..aa3fbb7ccefb306e1000298945a69d7f5bf2af2a --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/Inlet.obj @@ -0,0 +1,382 @@ +# Wavefront OBJ file +# Regions: +# 0 CATIASTL +# +# points : 188 +# triangles : 186 +# +v -117.911 9.79717e-15 31.5765 +v -117.926 2.6732 31.6185 +v -117.926 -2.6732 31.6185 +v -117.972 5.34341 31.7443 +v -117.972 -5.34341 31.7443 +v -118.048 8.00766 31.954 +v -118.048 -8.00766 31.954 +v -118.155 10.663 32.2472 +v -118.155 -10.663 32.2472 +v -118.292 13.3063 32.6236 +v -118.292 -13.3063 32.6236 +v -118.459 15.9349 33.0829 +v -118.459 -15.9349 33.0829 +v -118.656 18.5456 33.6244 +v -118.656 -18.5456 33.6244 +v -118.883 21.1356 34.2475 +v -118.883 -21.1356 34.2475 +v -119.139 23.702 34.9517 +v -119.139 -23.702 34.9517 +v -119.425 26.242 35.736 +v -119.425 -26.242 35.736 +v -119.739 28.7526 36.5996 +v -119.739 -28.7526 36.5996 +v -120.082 31.2311 37.5416 +v -120.082 -31.2311 37.5416 +v -120.453 33.6748 38.561 +v -120.453 -33.6748 38.561 +v -120.852 36.0808 39.6564 +v -120.852 -36.0808 39.6564 +v -121.277 38.4465 40.8268 +v -121.277 -38.4465 40.8268 +v -121.73 40.7693 42.0708 +v -121.73 -40.7693 42.0708 +v -122.209 43.0466 43.3871 +v -122.209 -43.0466 43.3871 +v -122.714 45.2758 44.7742 +v -122.714 -45.2758 44.7742 +v -123.244 47.4544 46.2304 +v -123.244 -47.4544 46.2304 +v -123.799 49.58 47.7543 +v -123.799 -49.58 47.7543 +v -124.378 51.6502 49.344 +v -124.378 -51.6502 49.344 +v -124.979 53.6628 50.9979 +v -124.979 -53.6628 50.9979 +v -125.604 55.6154 52.714 +v -125.604 -55.6154 52.714 +v -126.251 57.5059 54.4905 +v -126.251 -57.5059 54.4905 +v -126.919 59.3322 56.3254 +v -126.919 -59.3322 56.3254 +v -127.607 61.0922 58.2165 +v -127.607 -61.0922 58.2165 +v -128.315 62.784 60.1619 +v -128.315 -62.784 60.1619 +v -129.042 64.4056 62.1594 +v -129.042 -64.4056 62.1594 +v -129.787 65.9553 64.2066 +v -129.787 -65.9553 64.2066 +v -130.549 67.4314 66.3013 +v -130.549 -67.4314 66.3013 +v -131.328 68.8321 68.4412 +v -131.328 -68.8321 68.4412 +v -132.123 70.156 70.6239 +v -132.123 -70.156 70.6239 +v -132.932 71.4015 72.847 +v -132.932 -71.4015 72.847 +v -133.755 72.5673 75.1079 +v -133.755 -72.5673 75.1079 +v -134.591 73.652 77.4042 +v -134.591 -73.652 77.4042 +v -135.438 74.6544 79.7333 +v -135.438 -74.6544 79.7333 +v -136.297 75.5735 82.0925 +v -136.297 -75.5735 82.0925 +v -137.166 76.4082 84.4792 +v -137.166 -76.4082 84.4792 +v -138.044 77.1575 86.8909 +v -138.044 -77.1575 86.8909 +v -138.929 77.8207 89.3247 +v -138.929 -77.8207 89.3247 +v -139.822 78.3969 91.778 +v -139.822 -78.3969 91.778 +v -140.721 78.8856 94.248 +v -140.721 -78.8856 94.248 +v -141.625 79.2862 96.732 +v -141.625 -79.2862 96.732 +v -142.533 79.5982 99.2271 +v -142.533 -79.5982 99.2271 +v -143.445 79.8214 101.731 +v -143.445 -79.8214 101.731 +v -144.358 79.9553 104.24 +v -144.358 -79.9553 104.24 +v -145.272 80 106.752 +v -145.272 -80 106.752 +v -146.187 79.9553 109.264 +v -146.187 -79.9553 109.264 +v -147.1 79.8214 111.773 +v -147.1 -79.8214 111.773 +v -148.011 79.5982 114.277 +v -148.011 -79.5982 114.277 +v -148.919 79.2862 116.772 +v -148.919 -79.2862 116.772 +v -149.823 78.8856 119.256 +v -149.823 -78.8856 119.256 +v -150.722 78.3969 121.726 +v -150.722 -78.3969 121.726 +v -151.615 77.8207 124.179 +v -151.615 -77.8207 124.179 +v -152.501 77.1575 126.613 +v -152.501 -77.1575 126.613 +v -153.379 76.4082 129.025 +v -153.379 -76.4082 129.025 +v -154.248 75.5735 131.411 +v -154.248 -75.5735 131.411 +v -155.106 74.6544 133.77 +v -155.106 -74.6544 133.77 +v -155.954 73.652 136.1 +v -155.954 -73.652 136.1 +v -156.79 72.5673 138.396 +v -156.79 -72.5673 138.396 +v -157.613 71.4015 140.657 +v -157.613 -71.4015 140.657 +v -158.422 70.156 142.88 +v -158.422 -70.156 142.88 +v -159.216 68.8321 145.062 +v -159.216 -68.8321 145.062 +v -159.995 67.4314 147.202 +v -159.995 -67.4314 147.202 +v -160.758 65.9553 149.297 +v -160.758 -65.9553 149.297 +v -161.503 64.4056 151.344 +v -161.503 -64.4056 151.344 +v -162.23 62.784 153.342 +v -162.23 -62.784 153.342 +v -162.938 61.0922 155.287 +v -162.938 -61.0922 155.287 +v -163.626 59.3322 157.178 +v -163.626 -59.3322 157.178 +v -164.294 57.5059 159.013 +v -164.294 -57.5059 159.013 +v -164.941 55.6154 160.79 +v -164.941 -55.6154 160.79 +v -165.565 53.6628 162.506 +v -165.565 -53.6628 162.506 +v -166.167 51.6502 164.16 +v -166.167 -51.6502 164.16 +v -166.746 49.58 165.749 +v -166.746 -49.58 165.749 +v -167.3 47.4544 167.273 +v -167.3 -47.4544 167.273 +v -167.83 45.2758 168.73 +v -167.83 -45.2758 168.73 +v -168.335 43.0466 170.117 +v -168.335 -43.0466 170.117 +v -168.814 40.7693 171.433 +v -168.814 -40.7693 171.433 +v -169.267 38.4465 172.677 +v -169.267 -38.4465 172.677 +v -169.693 36.0808 173.847 +v -169.693 -36.0808 173.847 +v -170.092 33.6748 174.943 +v -170.092 -33.6748 174.943 +v -170.463 31.2311 175.962 +v -170.463 -31.2311 175.962 +v -170.806 28.7526 176.904 +v -170.806 -28.7526 176.904 +v -171.12 26.242 177.768 +v -171.12 -26.242 177.768 +v -171.405 23.702 178.552 +v -171.405 -23.702 178.552 +v -171.662 21.1356 179.256 +v -171.662 -21.1356 179.256 +v -171.889 18.5456 179.879 +v -171.889 -18.5456 179.879 +v -172.086 15.9349 180.421 +v -172.086 -15.9349 180.421 +v -172.253 13.3063 180.88 +v -172.253 -13.3063 180.88 +v -172.39 10.663 181.257 +v -172.39 -10.663 181.257 +v -172.497 8.00766 181.55 +v -172.497 -8.00766 181.55 +v -172.573 5.34341 181.759 +v -172.573 -5.34341 181.759 +v -172.619 2.6732 181.885 +v -172.619 -2.6732 181.885 +v -172.634 0 181.927 +g CATIASTL +f 92 96 94 +f 96 92 98 +f 98 92 90 +f 98 90 100 +f 100 90 88 +f 100 88 102 +f 102 88 86 +f 102 86 104 +f 104 86 84 +f 104 84 106 +f 106 84 82 +f 106 82 108 +f 108 82 80 +f 108 80 110 +f 110 80 78 +f 110 78 112 +f 112 78 76 +f 112 76 114 +f 114 76 74 +f 114 74 116 +f 116 74 72 +f 116 72 118 +f 118 72 70 +f 118 70 120 +f 120 70 68 +f 120 68 122 +f 122 68 66 +f 122 66 124 +f 124 66 64 +f 124 64 126 +f 126 64 62 +f 126 62 128 +f 128 62 60 +f 128 60 130 +f 130 60 58 +f 130 58 132 +f 132 58 56 +f 132 56 134 +f 134 56 54 +f 134 54 136 +f 136 54 52 +f 136 52 138 +f 138 52 50 +f 138 50 140 +f 140 50 48 +f 140 48 142 +f 142 48 46 +f 142 46 144 +f 144 46 44 +f 144 44 146 +f 146 44 42 +f 146 42 148 +f 148 42 40 +f 148 40 150 +f 150 40 38 +f 150 38 152 +f 152 38 36 +f 152 36 154 +f 154 36 34 +f 154 34 156 +f 156 34 32 +f 156 32 158 +f 158 32 30 +f 158 30 160 +f 160 30 28 +f 160 28 162 +f 162 28 26 +f 162 26 164 +f 164 26 24 +f 164 24 166 +f 166 24 22 +f 166 22 168 +f 168 22 20 +f 168 20 170 +f 170 20 18 +f 170 18 172 +f 172 18 16 +f 172 16 174 +f 174 16 14 +f 174 14 176 +f 176 14 12 +f 176 12 178 +f 178 12 10 +f 178 10 180 +f 180 10 8 +f 180 8 182 +f 182 8 6 +f 182 6 184 +f 184 6 4 +f 184 4 186 +f 186 4 2 +f 186 2 188 +f 188 2 1 +f 188 1 187 +f 187 1 3 +f 187 3 185 +f 185 3 5 +f 185 5 183 +f 183 5 7 +f 183 7 181 +f 181 7 9 +f 181 9 179 +f 179 9 11 +f 179 11 177 +f 177 11 13 +f 177 13 175 +f 175 13 15 +f 175 15 173 +f 173 15 17 +f 173 17 171 +f 171 17 19 +f 171 19 169 +f 169 19 21 +f 169 21 167 +f 167 21 23 +f 167 23 165 +f 165 23 25 +f 165 25 163 +f 163 25 27 +f 163 27 161 +f 161 27 29 +f 161 29 159 +f 159 29 31 +f 159 31 157 +f 157 31 33 +f 157 33 155 +f 155 33 35 +f 155 35 153 +f 153 35 37 +f 153 37 151 +f 151 37 39 +f 151 39 149 +f 149 39 41 +f 149 41 147 +f 147 41 43 +f 147 43 145 +f 145 43 45 +f 145 45 143 +f 143 45 47 +f 143 47 141 +f 141 47 49 +f 141 49 139 +f 139 49 51 +f 139 51 137 +f 137 51 53 +f 137 53 135 +f 135 53 55 +f 135 55 133 +f 133 55 57 +f 133 57 131 +f 131 57 59 +f 131 59 129 +f 129 59 61 +f 129 61 127 +f 127 61 63 +f 127 63 125 +f 125 63 65 +f 125 65 123 +f 123 65 67 +f 123 67 121 +f 121 67 69 +f 121 69 119 +f 119 69 71 +f 119 71 117 +f 117 71 73 +f 117 73 115 +f 115 73 75 +f 115 75 113 +f 113 75 77 +f 113 77 111 +f 111 77 79 +f 111 79 109 +f 109 79 81 +f 109 81 107 +f 107 81 83 +f 107 83 105 +f 105 83 85 +f 105 85 103 +f 103 85 87 +f 103 87 101 +f 101 87 89 +f 101 89 99 +f 99 89 91 +f 99 91 97 +f 97 91 93 +f 97 93 95 diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/InletSmall.obj b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/InletSmall.obj new file mode 100644 index 0000000000000000000000000000000000000000..6c661397fc9204a1786d7274d1fe56ce3cefc62e --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/InletSmall.obj @@ -0,0 +1,250 @@ +# Wavefront OBJ file +# Regions: +# 0 CATIASTL +# +# points : 122 +# triangles : 120 +# +v 174.966 29.7913 243.719 +v 149.662 -12.308 261.438 +v 175.49 -29.7086 243.353 +v 170.439 -29.9337 246.889 +v 150.21 -13.7001 261.054 +v 181.086 27.9095 239.435 +v 186.01 -24.7091 235.987 +v 196.6 1.86591 228.572 +v 148.377 -7.95114 262.337 +v 187.612 23.2414 234.865 +v 180.395 -28.2272 239.918 +v 149.975 13.124 261.219 +v 192.949 -15.8282 231.128 +v 177.46 29.2702 241.973 +v 184.497 25.8838 237.046 +v 193.329 15.0559 230.862 +v 159.649 -25.8838 254.445 +v 194.171 -13.124 230.272 +v 196.072 6.45146 228.941 +v 148.073 -6.45146 262.55 +v 193.589 -14.4953 230.68 +v 148.243 7.32825 262.432 +v 150.817 -15.0559 260.629 +v 189.487 21.1678 233.552 +v 157.535 -24.1871 255.925 +v 164.249 -28.4389 251.224 +v 147.546 -1.86591 262.92 +v 174.232 -29.8839 244.234 +v 151.48 -16.3717 260.165 +v 166.686 -29.2702 249.518 +v 193.935 13.7001 230.437 +v 182.251 27.306 238.619 +v 157.113 23.8005 256.221 +v 195.16 -10.2806 229.58 +v 195.903 -7.32825 229.06 +v 188.017 -22.8288 234.581 +v 179.194 -28.7128 240.759 +v 195.562 -8.81611 229.298 +v 167.927 -29.57 248.649 +v 147.833 -4.93468 262.719 +v 147.603 2.7641 262.88 +v 158.136 24.7091 255.504 +v 173.706 29.9337 244.602 +v 149.451 11.7178 261.586 +v 196.18 -5.82096 228.865 +v 161.417 27.033 253.207 +v 151.197 15.8282 260.363 +v 160.757 -26.6302 253.669 +v 156.534 -23.2414 256.626 +v 147.519 1.22264 262.939 +v 196.489 3.40481 228.65 +v 191.505 -18.3647 232.139 +v 171.704 -29.9966 246.004 +v 150.557 14.4953 260.811 +v 163.75 28.2272 251.573 +v 160.291 26.3275 253.995 +v 163.06 -27.9095 252.057 +v 147.5 -0.322061 262.952 +v 191.948 17.6441 231.829 +v 167.408 29.4545 249.012 +v 183.855 -26.3275 237.496 +v 155.575 -22.2341 257.298 +v 168.656 29.7086 248.138 +v 147.965 5.82096 262.626 +v 171.176 29.98 246.373 +v 195.402 9.42973 229.411 +v 154.659 -21.1678 257.939 +v 188.571 22.2341 234.193 +v 162.571 27.6668 252.399 +v 187.033 -23.8005 235.27 +v 196.627 -1.22264 228.553 +v 190.356 20.0453 232.943 +v 176.738 -29.4545 242.479 +v 169.179 -29.7913 247.772 +v 155.187 21.7965 257.569 +v 166.172 29.1223 249.878 +v 148.583 8.81611 262.193 +v 181.575 -27.6668 239.092 +v 152.198 -17.6441 259.662 +v 194.695 -11.7178 229.905 +v 147.657 -3.40481 262.842 +v 177.974 -29.1223 241.614 +v 172.969 -29.98 245.118 +v 183.389 26.6302 237.822 +v 196.543 -2.7641 228.611 +v 147.752 4.29823 262.775 +v 182.729 -27.033 238.284 +v 161.895 -27.306 252.872 +v 196.646 0.322061 228.539 +v 188.958 -21.7965 233.922 +v 164.952 28.7128 250.732 +v 156.129 22.8288 256.91 +v 186.611 24.1871 235.566 +v 179.897 28.4389 240.267 +v 148.986 10.2806 261.911 +v 149.173 -10.8833 261.781 +v 158.574 -25.0687 255.198 +v 176.219 29.57 242.843 +v 148.744 -9.42973 262.081 +v 154.291 20.7065 258.197 +v 153.789 -20.0453 258.548 +v 196.313 4.93468 228.773 +v 169.913 29.8839 247.258 +v 172.442 29.9966 245.487 +v 192.666 16.3717 231.327 +v 152.641 18.3647 259.352 +v 192.254 -17.1191 231.615 +v 184.949 -25.5522 236.73 +v 165.458 -28.8929 250.377 +v 152.968 -18.8697 259.123 +v 195.769 7.95114 229.154 +v 153.441 19.5615 258.792 +v 190.705 -19.5615 232.699 +v 191.178 18.8697 232.368 +v 159.197 25.5522 254.762 +v 194.484 12.308 230.053 +v 178.688 28.8929 241.114 +v 189.855 -20.7065 233.294 +v 185.572 25.0687 236.294 +v 151.892 17.1191 259.876 +v 194.973 10.8833 229.711 +v 196.394 -4.29823 228.716 +g CATIASTL +f 104 65 43 +f 43 65 103 +f 43 103 1 +f 1 103 63 +f 1 63 98 +f 98 63 60 +f 98 60 14 +f 14 60 76 +f 14 76 117 +f 117 76 91 +f 117 91 94 +f 94 91 55 +f 94 55 6 +f 6 55 69 +f 6 69 32 +f 32 69 46 +f 32 46 84 +f 84 46 56 +f 84 56 15 +f 15 56 115 +f 15 115 119 +f 119 115 42 +f 119 42 93 +f 93 42 33 +f 93 33 10 +f 10 33 92 +f 10 92 68 +f 68 92 75 +f 68 75 24 +f 24 75 100 +f 24 100 72 +f 72 100 112 +f 72 112 114 +f 114 112 106 +f 114 106 59 +f 59 106 120 +f 59 120 105 +f 105 120 47 +f 105 47 16 +f 16 47 54 +f 16 54 31 +f 31 54 12 +f 31 12 116 +f 116 12 44 +f 116 44 121 +f 121 44 95 +f 121 95 66 +f 66 95 77 +f 66 77 111 +f 111 77 22 +f 111 22 19 +f 19 22 64 +f 19 64 102 +f 102 64 86 +f 102 86 51 +f 51 86 41 +f 51 41 8 +f 8 41 50 +f 8 50 89 +f 89 50 58 +f 89 58 71 +f 71 58 27 +f 71 27 85 +f 85 27 81 +f 85 81 122 +f 122 81 40 +f 122 40 45 +f 45 40 20 +f 45 20 35 +f 35 20 9 +f 35 9 38 +f 38 9 99 +f 38 99 34 +f 34 99 96 +f 34 96 80 +f 80 96 2 +f 80 2 18 +f 18 2 5 +f 18 5 21 +f 21 5 23 +f 21 23 13 +f 13 23 29 +f 13 29 107 +f 107 29 79 +f 107 79 52 +f 52 79 110 +f 52 110 113 +f 113 110 101 +f 113 101 118 +f 118 101 67 +f 118 67 90 +f 90 67 62 +f 90 62 36 +f 36 62 49 +f 36 49 70 +f 70 49 25 +f 70 25 7 +f 7 25 97 +f 7 97 108 +f 108 97 17 +f 108 17 61 +f 61 17 48 +f 61 48 87 +f 87 48 88 +f 87 88 78 +f 78 88 57 +f 78 57 11 +f 11 57 26 +f 11 26 37 +f 37 26 109 +f 37 109 82 +f 82 109 30 +f 82 30 73 +f 73 30 39 +f 73 39 3 +f 3 39 74 +f 3 74 28 +f 28 74 4 +f 28 4 83 +f 83 4 53 diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/Outlet.obj b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/Outlet.obj new file mode 100644 index 0000000000000000000000000000000000000000..ce035e4315f6a70e461689abbb6aa11de7e743d6 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/Outlet.obj @@ -0,0 +1,382 @@ +# Wavefront OBJ file +# Regions: +# 0 CATIASTL +# +# points : 188 +# triangles : 186 +# +v 70 9.79717e-15 -100 +v 70.0447 -2.6732 -100 +v 70.0447 2.6732 -100 +v 70.1786 -5.34341 -100 +v 70.1786 5.34341 -100 +v 70.4018 -8.00766 -100 +v 70.4018 8.00766 -100 +v 70.7138 -10.663 -100 +v 70.7138 10.663 -100 +v 71.1144 -13.3063 -100 +v 71.1144 13.3063 -100 +v 71.6031 -15.9349 -100 +v 71.6031 15.9349 -100 +v 72.1793 -18.5456 -100 +v 72.1793 18.5456 -100 +v 72.8425 -21.1356 -100 +v 72.8425 21.1356 -100 +v 73.5918 -23.702 -100 +v 73.5918 23.702 -100 +v 74.4265 -26.242 -100 +v 74.4265 26.242 -100 +v 75.3456 -28.7526 -100 +v 75.3456 28.7526 -100 +v 76.348 -31.2311 -100 +v 76.348 31.2311 -100 +v 77.4327 -33.6748 -100 +v 77.4327 33.6748 -100 +v 78.5985 -36.0808 -100 +v 78.5985 36.0808 -100 +v 79.844 -38.4465 -100 +v 79.844 38.4465 -100 +v 81.1679 -40.7693 -100 +v 81.1679 40.7693 -100 +v 82.5686 -43.0466 -100 +v 82.5686 43.0466 -100 +v 84.0447 -45.2758 -100 +v 84.0447 45.2758 -100 +v 85.5944 -47.4544 -100 +v 85.5944 47.4544 -100 +v 87.216 -49.58 -100 +v 87.216 49.58 -100 +v 88.9078 -51.6502 -100 +v 88.9078 51.6502 -100 +v 90.6678 -53.6628 -100 +v 90.6678 53.6628 -100 +v 92.4941 -55.6154 -100 +v 92.4941 55.6154 -100 +v 94.3846 -57.5059 -100 +v 94.3846 57.5059 -100 +v 96.3372 -59.3322 -100 +v 96.3372 59.3322 -100 +v 98.3498 -61.0922 -100 +v 98.3498 61.0922 -100 +v 100.42 -62.784 -100 +v 100.42 62.784 -100 +v 102.546 -64.4056 -100 +v 102.546 64.4056 -100 +v 104.724 -65.9553 -100 +v 104.724 65.9553 -100 +v 106.953 -67.4314 -100 +v 106.953 67.4314 -100 +v 109.231 -68.8321 -100 +v 109.231 68.8321 -100 +v 111.553 -70.156 -100 +v 111.553 70.156 -100 +v 113.919 -71.4015 -100 +v 113.919 71.4015 -100 +v 116.325 -72.5673 -100 +v 116.325 72.5673 -100 +v 118.769 -73.652 -100 +v 118.769 73.652 -100 +v 121.247 -74.6544 -100 +v 121.247 74.6544 -100 +v 123.758 -75.5735 -100 +v 123.758 75.5735 -100 +v 126.298 -76.4082 -100 +v 126.298 76.4082 -100 +v 128.864 -77.1575 -100 +v 128.864 77.1575 -100 +v 131.454 -77.8207 -100 +v 131.454 77.8207 -100 +v 134.065 -78.3969 -100 +v 134.065 78.3969 -100 +v 136.694 -78.8856 -100 +v 136.694 78.8856 -100 +v 139.337 -79.2862 -100 +v 139.337 79.2862 -100 +v 141.992 -79.5982 -100 +v 141.992 79.5982 -100 +v 144.657 -79.8214 -100 +v 144.657 79.8214 -100 +v 147.327 79.9553 -100 +v 147.327 -79.9553 -100 +v 150 80 -100 +v 150 -80 -100 +v 152.673 79.9553 -100 +v 152.673 -79.9553 -100 +v 155.343 -79.8214 -100 +v 155.343 79.8214 -100 +v 158.008 -79.5982 -100 +v 158.008 79.5982 -100 +v 160.663 -79.2862 -100 +v 160.663 79.2862 -100 +v 163.306 -78.8856 -100 +v 163.306 78.8856 -100 +v 165.935 -78.3969 -100 +v 165.935 78.3969 -100 +v 168.546 -77.8207 -100 +v 168.546 77.8207 -100 +v 171.136 -77.1575 -100 +v 171.136 77.1575 -100 +v 173.702 -76.4082 -100 +v 173.702 76.4082 -100 +v 176.242 -75.5735 -100 +v 176.242 75.5735 -100 +v 178.753 -74.6544 -100 +v 178.753 74.6544 -100 +v 181.231 -73.652 -100 +v 181.231 73.652 -100 +v 183.675 -72.5673 -100 +v 183.675 72.5673 -100 +v 186.081 -71.4015 -100 +v 186.081 71.4015 -100 +v 188.447 -70.156 -100 +v 188.447 70.156 -100 +v 190.769 -68.8321 -100 +v 190.769 68.8321 -100 +v 193.047 -67.4314 -100 +v 193.047 67.4314 -100 +v 195.276 -65.9553 -100 +v 195.276 65.9553 -100 +v 197.454 -64.4056 -100 +v 197.454 64.4056 -100 +v 199.58 -62.784 -100 +v 199.58 62.784 -100 +v 201.65 -61.0922 -100 +v 201.65 61.0922 -100 +v 203.663 -59.3322 -100 +v 203.663 59.3322 -100 +v 205.615 -57.5059 -100 +v 205.615 57.5059 -100 +v 207.506 -55.6154 -100 +v 207.506 55.6154 -100 +v 209.332 -53.6628 -100 +v 209.332 53.6628 -100 +v 211.092 -51.6502 -100 +v 211.092 51.6502 -100 +v 212.784 -49.58 -100 +v 212.784 49.58 -100 +v 214.406 -47.4544 -100 +v 214.406 47.4544 -100 +v 215.955 -45.2758 -100 +v 215.955 45.2758 -100 +v 217.431 -43.0466 -100 +v 217.431 43.0466 -100 +v 218.832 -40.7693 -100 +v 218.832 40.7693 -100 +v 220.156 -38.4465 -100 +v 220.156 38.4465 -100 +v 221.402 -36.0808 -100 +v 221.402 36.0808 -100 +v 222.567 -33.6748 -100 +v 222.567 33.6748 -100 +v 223.652 -31.2311 -100 +v 223.652 31.2311 -100 +v 224.654 -28.7526 -100 +v 224.654 28.7526 -100 +v 225.574 -26.242 -100 +v 225.574 26.242 -100 +v 226.408 -23.702 -100 +v 226.408 23.702 -100 +v 227.158 -21.1356 -100 +v 227.158 21.1356 -100 +v 227.821 -18.5456 -100 +v 227.821 18.5456 -100 +v 228.397 -15.9349 -100 +v 228.397 15.9349 -100 +v 228.886 -13.3063 -100 +v 228.886 13.3063 -100 +v 229.286 -10.663 -100 +v 229.286 10.663 -100 +v 229.598 -8.00766 -100 +v 229.598 8.00766 -100 +v 229.821 -5.34341 -100 +v 229.821 5.34341 -100 +v 229.955 -2.6732 -100 +v 229.955 2.6732 -100 +v 230 0 -100 +g CATIASTL +f 94 96 92 +f 95 93 97 +f 97 93 90 +f 97 90 98 +f 98 90 88 +f 98 88 100 +f 100 88 86 +f 100 86 102 +f 102 86 84 +f 102 84 104 +f 104 84 82 +f 104 82 106 +f 106 82 80 +f 106 80 108 +f 108 80 78 +f 108 78 110 +f 110 78 76 +f 110 76 112 +f 112 76 74 +f 112 74 114 +f 114 74 72 +f 114 72 116 +f 116 72 70 +f 116 70 118 +f 118 70 68 +f 118 68 120 +f 120 68 66 +f 120 66 122 +f 122 66 64 +f 122 64 124 +f 124 64 62 +f 124 62 126 +f 126 62 60 +f 126 60 128 +f 128 60 58 +f 128 58 130 +f 130 58 56 +f 130 56 132 +f 132 56 54 +f 132 54 134 +f 134 54 52 +f 134 52 136 +f 136 52 50 +f 136 50 138 +f 138 50 48 +f 138 48 140 +f 140 48 46 +f 140 46 142 +f 142 46 44 +f 142 44 144 +f 144 44 42 +f 144 42 146 +f 146 42 40 +f 146 40 148 +f 148 40 38 +f 148 38 150 +f 150 38 36 +f 150 36 152 +f 152 36 34 +f 152 34 154 +f 154 34 32 +f 154 32 156 +f 156 32 30 +f 156 30 158 +f 158 30 28 +f 158 28 160 +f 160 28 26 +f 160 26 162 +f 162 26 24 +f 162 24 164 +f 164 24 22 +f 164 22 166 +f 166 22 20 +f 166 20 168 +f 168 20 18 +f 168 18 170 +f 170 18 16 +f 170 16 172 +f 172 16 14 +f 172 14 174 +f 174 14 12 +f 174 12 176 +f 176 12 10 +f 176 10 178 +f 178 10 8 +f 178 8 180 +f 180 8 6 +f 180 6 182 +f 182 6 4 +f 182 4 184 +f 184 4 2 +f 184 2 186 +f 186 2 1 +f 186 1 188 +f 188 1 3 +f 188 3 187 +f 187 3 5 +f 187 5 185 +f 185 5 7 +f 185 7 183 +f 183 7 9 +f 183 9 181 +f 181 9 11 +f 181 11 179 +f 179 11 13 +f 179 13 177 +f 177 13 15 +f 177 15 175 +f 175 15 17 +f 175 17 173 +f 173 17 19 +f 173 19 171 +f 171 19 21 +f 171 21 169 +f 169 21 23 +f 169 23 167 +f 167 23 25 +f 167 25 165 +f 165 25 27 +f 165 27 163 +f 163 27 29 +f 163 29 161 +f 161 29 31 +f 161 31 159 +f 159 31 33 +f 159 33 157 +f 157 33 35 +f 157 35 155 +f 155 35 37 +f 155 37 153 +f 153 37 39 +f 153 39 151 +f 151 39 41 +f 151 41 149 +f 149 41 43 +f 149 43 147 +f 147 43 45 +f 147 45 145 +f 145 45 47 +f 145 47 143 +f 143 47 49 +f 143 49 141 +f 141 49 51 +f 141 51 139 +f 139 51 53 +f 139 53 137 +f 137 53 55 +f 137 55 135 +f 135 55 57 +f 135 57 133 +f 133 57 59 +f 133 59 131 +f 131 59 61 +f 131 61 129 +f 129 61 63 +f 129 63 127 +f 127 63 65 +f 127 65 125 +f 125 65 67 +f 125 67 123 +f 123 67 69 +f 123 69 121 +f 121 69 71 +f 121 71 119 +f 119 71 73 +f 119 73 117 +f 117 73 75 +f 117 75 115 +f 115 75 77 +f 115 77 113 +f 113 77 79 +f 113 79 111 +f 111 79 81 +f 111 81 109 +f 109 81 83 +f 109 83 107 +f 107 83 85 +f 107 85 105 +f 105 85 87 +f 105 87 103 +f 103 87 89 +f 103 89 101 +f 101 89 91 +f 101 91 99 +f 99 91 92 +f 99 92 96 diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/SmallPipe.obj b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/SmallPipe.obj new file mode 100644 index 0000000000000000000000000000000000000000..9956423edb8494e0a9a47261dfc4580bb00ee43d --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/constant/triSurface/SmallPipe.obj @@ -0,0 +1,536 @@ +# Wavefront OBJ file +# Regions: +# 0 CATIASTL +# +# points : 264 +# triangles : 264 +# +v 129.002 -29.9955 183.325 +v 128.148 29.9955 183.923 +v 129.334 29.9857 183.096 +v 127.819 -29.9857 184.156 +v 130.194 -29.9355 182.51 +v 126.974 29.9355 184.764 +v 130.287 29.9279 182.447 +v 126.883 -29.9279 184.831 +v 125.958 -29.826 185.512 +v 131.244 29.826 181.811 +v 131.391 -29.8064 181.714 +v 125.816 29.8064 185.617 +v 125.045 -29.6803 186.199 +v 132.202 29.6803 181.188 +v 124.679 29.6089 186.478 +v 132.59 -29.6089 180.939 +v 133.158 29.4915 180.58 +v 124.147 -29.4915 186.889 +v 123.565 29.3443 187.344 +v 133.784 -29.3443 180.188 +v 133.793 29.3421 180.183 +v 123.556 -29.3421 187.351 +v 134.427 29.1741 179.793 +v 122.974 -29.1741 187.813 +v 134.972 -29.0143 179.462 +v 122.477 29.0143 188.212 +v 121.832 -28.7837 188.736 +v 135.685 28.7837 179.036 +v 121.374 28.6035 189.113 +v 136.195 -28.6035 178.735 +v 120.948 -28.423 189.467 +v 136.674 28.423 178.456 +v 120.306 28.1266 190.008 +v 137.402 -28.1266 178.037 +v 120.088 -28.0192 190.194 +v 137.651 28.0192 177.896 +v 119.273 27.5863 190.895 +v 138.588 -27.5863 177.37 +v 138.614 27.5739 177.356 +v 119.252 -27.5739 190.914 +v 118.44 -27.0887 191.626 +v 139.561 27.0887 176.837 +v 139.751 -26.9856 176.734 +v 118.278 26.9856 191.769 +v 117.914 -26.7451 192.094 +v 140.18 26.7451 176.503 +v 140.791 26.385 176.179 +v 117.401 -26.385 192.557 +v 117.322 26.3275 192.628 +v 140.885 -26.3275 176.129 +v 141.397 26.0063 175.861 +v 116.895 -26.0063 193.018 +v 116.411 25.6208 193.463 +v 141.98 -25.6208 175.559 +v 116.401 -25.6118 193.473 +v 141.994 25.6118 175.553 +v 143.043 -24.8634 175.02 +v 115.541 24.8634 194.277 +v 115.517 -24.8419 194.299 +v 143.072 24.8419 175.005 +v 114.71 24.0583 195.069 +v 144.072 -24.0583 174.51 +v 144.115 24.0228 174.488 +v 114.675 -24.0228 195.102 +v 113.919 23.2083 195.836 +v 145.063 -23.2083 174.029 +v 113.874 -23.1575 195.88 +v 145.12 23.1575 174.002 +v 113.168 22.3161 196.576 +v 146.016 -22.3161 173.576 +v 146.084 22.2488 173.544 +v 113.114 -22.2488 196.63 +v 112.457 21.3845 197.288 +v 146.928 -21.3845 173.152 +v 112.396 -21.2997 197.35 +v 147.007 21.2997 173.115 +v 147.887 20.3127 172.714 +v 111.718 -20.3127 198.04 +v 111.695 20.2771 198.064 +v 147.917 -20.2771 172.701 +v 148.368 19.7356 172.499 +v 111.351 -19.7356 198.418 +v 110.997 -19.1474 198.785 +v 148.834 19.1474 172.292 +v 148.851 -19.1253 172.284 +v 110.984 19.1253 198.798 +v 149.289 18.5427 172.091 +v 110.653 -18.5427 199.145 +v 110.324 17.9325 199.49 +v 149.726 -17.9325 171.9 +v 110.322 -17.9277 199.493 +v 149.73 17.9277 171.899 +v 150.542 -16.7021 171.549 +v 109.715 16.7021 200.137 +v 109.702 -16.675 200.15 +v 150.56 16.675 171.542 +v 109.156 15.4374 200.738 +v 151.298 -15.4374 171.229 +v 109.135 -15.3868 200.76 +v 151.327 15.3868 171.217 +v 151.992 -14.1415 170.94 +v 108.646 14.1415 201.291 +v 152.03 14.0664 170.924 +v 108.619 -14.0664 201.321 +v 108.186 12.8177 201.795 +v 152.624 -12.8177 170.68 +v 108.154 -12.7171 201.831 +v 152.669 12.7171 170.662 +v 153.191 -11.4687 170.449 +v 107.775 11.4687 202.25 +v 107.74 -11.3421 202.29 +v 153.241 11.3421 170.429 +v 153.699 -10.0842 170.245 +v 107.41 10.0842 202.657 +v 153.746 9.94438 170.226 +v 107.376 -9.94438 202.695 +v 154.141 -8.67993 170.069 +v 107.094 8.67993 203.012 +v 154.176 8.55855 170.056 +v 107.069 -8.55855 203.04 +v 154.515 -7.25883 169.921 +v 106.827 7.25883 203.314 +v 106.809 -7.15661 203.333 +v 154.54 7.15661 169.912 +v 154.822 -5.82374 169.801 +v 106.608 5.82374 203.561 +v 154.838 5.74127 169.795 +v 106.597 -5.74127 203.574 +v 106.439 4.37752 203.754 +v 155.062 -4.37752 169.708 +v 155.071 4.31526 169.704 +v 106.433 -4.31526 203.761 +v 106.318 2.92296 203.892 +v 155.233 -2.92296 169.641 +v 155.237 2.88126 169.64 +v 106.315 -2.88126 203.895 +v 155.336 -1.46286 169.601 +v 106.245 1.46286 203.975 +v 106.244 -1.44195 203.976 +v 155.337 1.44195 169.601 +v 155.37 1.95944e-14 169.588 +v 106.221 1.95944e-14 204.003 +v 174.966 29.7913 243.719 +v 149.662 -12.308 261.438 +v 175.49 -29.7086 243.353 +v 170.439 -29.9337 246.889 +v 150.21 -13.7001 261.054 +v 181.086 27.9095 239.435 +v 186.01 -24.7091 235.987 +v 196.6 1.86591 228.572 +v 148.377 -7.95114 262.337 +v 187.612 23.2414 234.865 +v 180.395 -28.2272 239.918 +v 149.975 13.124 261.219 +v 192.949 -15.8282 231.128 +v 177.46 29.2702 241.973 +v 159.649 -25.8838 254.445 +v 184.497 25.8838 237.046 +v 193.329 15.0559 230.862 +v 194.171 -13.124 230.272 +v 148.073 -6.45146 262.55 +v 196.072 6.45146 228.941 +v 193.589 -14.4953 230.68 +v 148.243 7.32825 262.432 +v 150.817 -15.0559 260.629 +v 189.487 21.1678 233.552 +v 157.535 -24.1871 255.925 +v 164.249 -28.4389 251.224 +v 147.546 -1.86591 262.92 +v 174.232 -29.8839 244.234 +v 151.48 -16.3717 260.165 +v 166.686 -29.2702 249.518 +v 193.935 13.7001 230.437 +v 182.251 27.306 238.619 +v 157.113 23.8005 256.221 +v 195.16 -10.2806 229.58 +v 195.903 -7.32825 229.06 +v 179.194 -28.7128 240.759 +v 188.017 -22.8288 234.581 +v 195.562 -8.81611 229.298 +v 167.927 -29.57 248.649 +v 147.833 -4.93468 262.719 +v 147.603 2.7641 262.88 +v 158.136 24.7091 255.504 +v 173.706 29.9337 244.602 +v 149.451 11.7178 261.586 +v 196.18 -5.82096 228.865 +v 161.417 27.033 253.207 +v 151.197 15.8282 260.363 +v 160.757 -26.6302 253.669 +v 156.534 -23.2414 256.626 +v 147.519 1.22264 262.939 +v 196.489 3.40481 228.65 +v 191.505 -18.3647 232.139 +v 171.704 -29.9966 246.004 +v 150.557 14.4953 260.811 +v 163.75 28.2272 251.573 +v 160.291 26.3275 253.995 +v 163.06 -27.9095 252.057 +v 147.5 -0.322061 262.952 +v 191.948 17.6441 231.829 +v 167.408 29.4545 249.012 +v 183.855 -26.3275 237.496 +v 155.575 -22.2341 257.298 +v 168.656 29.7086 248.138 +v 147.965 5.82096 262.626 +v 171.176 29.98 246.373 +v 195.402 9.42973 229.411 +v 154.659 -21.1678 257.939 +v 188.571 22.2341 234.193 +v 162.571 27.6668 252.399 +v 187.033 -23.8005 235.27 +v 196.627 -1.22264 228.553 +v 190.356 20.0453 232.943 +v 176.738 -29.4545 242.479 +v 169.179 -29.7913 247.772 +v 155.187 21.7965 257.569 +v 166.172 29.1223 249.878 +v 148.583 8.81611 262.193 +v 181.575 -27.6668 239.092 +v 152.198 -17.6441 259.662 +v 194.695 -11.7178 229.905 +v 147.657 -3.40481 262.842 +v 177.974 -29.1223 241.614 +v 172.969 -29.98 245.118 +v 183.389 26.6302 237.822 +v 196.543 -2.7641 228.611 +v 147.752 4.29823 262.775 +v 182.729 -27.033 238.284 +v 161.895 -27.306 252.872 +v 196.646 0.322061 228.539 +v 188.958 -21.7965 233.922 +v 156.129 22.8288 256.91 +v 164.952 28.7128 250.732 +v 186.611 24.1871 235.566 +v 179.897 28.4389 240.267 +v 148.986 10.2806 261.911 +v 149.173 -10.8833 261.781 +v 158.574 -25.0687 255.198 +v 176.219 29.57 242.843 +v 148.744 -9.42973 262.081 +v 154.291 20.7065 258.197 +v 153.789 -20.0453 258.548 +v 196.313 4.93468 228.773 +v 169.913 29.8839 247.258 +v 172.442 29.9966 245.487 +v 192.666 16.3717 231.327 +v 152.641 18.3647 259.352 +v 192.254 -17.1191 231.615 +v 184.949 -25.5522 236.73 +v 165.458 -28.8929 250.377 +v 152.968 -18.8697 259.123 +v 195.769 7.95114 229.154 +v 153.441 19.5615 258.792 +v 190.705 -19.5615 232.699 +v 191.178 18.8697 232.368 +v 159.197 25.5522 254.762 +v 194.484 12.308 230.053 +v 178.688 28.8929 241.114 +v 189.855 -20.7065 233.294 +v 185.572 25.0687 236.294 +v 151.892 17.1191 259.876 +v 194.973 10.8833 229.711 +v 196.394 -4.29823 228.716 +g CATIASTL +f 229 220 38 +f 34 38 220 +f 220 153 34 +f 30 34 153 +f 153 178 30 +f 25 30 178 +f 178 224 25 +f 20 25 224 +f 224 215 20 +f 16 20 215 +f 215 145 16 +f 11 16 145 +f 145 170 11 +f 11 170 5 +f 5 170 225 +f 5 225 1 +f 1 225 195 +f 1 195 4 +f 4 195 146 +f 13 9 216 +f 216 181 13 +f 24 22 172 +f 172 251 24 +f 24 251 27 +f 27 251 168 +f 40 35 199 +f 199 230 40 +f 55 52 157 +f 157 239 55 +f 55 239 59 +f 59 239 167 +f 59 167 64 +f 64 167 191 +f 75 72 204 +f 204 209 75 +f 78 75 209 +f 209 243 78 +f 95 91 221 +f 221 171 95 +f 99 95 171 +f 171 165 99 +f 104 99 165 +f 165 147 104 +f 107 104 147 +f 147 144 107 +f 111 107 144 +f 144 238 111 +f 116 111 238 +f 238 241 116 +f 120 116 241 +f 241 151 120 +f 123 120 151 +f 151 161 123 +f 128 123 161 +f 161 182 128 +f 128 182 132 +f 132 182 223 +f 132 223 136 +f 136 223 169 +f 136 169 139 +f 139 169 200 +f 138 192 183 +f 138 183 133 +f 133 183 228 +f 133 228 129 +f 164 219 118 +f 114 118 219 +f 219 237 114 +f 110 114 237 +f 237 186 110 +f 105 110 186 +f 186 154 105 +f 102 105 154 +f 154 196 102 +f 97 102 196 +f 196 189 97 +f 94 97 189 +f 189 262 94 +f 89 94 262 +f 262 248 89 +f 86 89 248 +f 248 254 86 +f 79 86 254 +f 254 242 79 +f 73 79 242 +f 242 217 73 +f 69 73 217 +f 217 233 69 +f 69 233 65 +f 65 233 175 +f 65 175 61 +f 61 175 184 +f 61 184 58 +f 58 184 257 +f 142 139 200 +f 142 200 192 +f 142 192 138 +f 50 203 43 +f 43 203 229 +f 43 229 38 +f 216 9 146 +f 146 9 8 +f 146 8 4 +f 172 22 181 +f 181 22 18 +f 181 18 13 +f 199 35 168 +f 168 35 31 +f 168 31 27 +f 190 45 230 +f 230 45 41 +f 230 41 40 +f 157 52 190 +f 190 52 48 +f 190 48 45 +f 204 72 191 +f 191 72 67 +f 191 67 64 +f 252 83 243 +f 243 83 82 +f 243 82 78 +f 221 91 252 +f 252 91 88 +f 252 88 83 +f 129 228 126 +f 126 228 206 +f 126 206 122 +f 122 206 164 +f 122 164 118 +f 198 49 257 +f 257 49 53 +f 257 53 58 +f 188 211 37 +f 33 37 211 +f 211 197 33 +f 29 33 197 +f 197 234 29 +f 26 29 234 +f 234 218 26 +f 19 26 218 +f 218 202 19 +f 15 19 202 +f 202 205 15 +f 12 15 205 +f 205 245 12 +f 12 245 6 +f 6 245 207 +f 6 207 2 +f 2 207 246 +f 2 246 3 +f 3 246 185 +f 14 10 143 +f 143 240 14 +f 23 21 156 +f 156 259 23 +f 23 259 28 +f 28 259 236 +f 39 36 148 +f 148 174 39 +f 56 51 158 +f 158 261 56 +f 56 261 60 +f 60 261 235 +f 60 235 63 +f 63 235 152 +f 76 71 210 +f 210 166 76 +f 77 76 166 +f 166 214 77 +f 96 92 201 +f 201 247 96 +f 100 96 247 +f 247 159 100 +f 103 100 159 +f 159 173 103 +f 108 103 173 +f 173 258 108 +f 112 108 258 +f 258 263 112 +f 115 112 263 +f 263 208 115 +f 119 115 208 +f 208 253 119 +f 124 119 253 +f 253 162 124 +f 127 124 162 +f 162 244 127 +f 127 244 131 +f 131 244 193 +f 131 193 135 +f 135 193 150 +f 135 150 140 +f 140 150 231 +f 137 213 227 +f 137 227 134 +f 134 227 264 +f 134 264 130 +f 177 180 117 +f 113 117 180 +f 180 176 113 +f 109 113 176 +f 176 222 109 +f 106 109 222 +f 222 160 106 +f 101 106 160 +f 160 163 101 +f 98 101 163 +f 163 155 98 +f 93 98 155 +f 155 249 93 +f 90 93 249 +f 249 194 90 +f 85 90 194 +f 194 255 85 +f 80 85 255 +f 255 260 80 +f 74 80 260 +f 260 232 74 +f 70 74 232 +f 232 179 70 +f 70 179 66 +f 66 179 212 +f 66 212 62 +f 62 212 149 +f 62 149 57 +f 57 149 250 +f 141 140 231 +f 141 231 213 +f 141 213 137 +f 49 198 44 +f 44 198 188 +f 44 188 37 +f 143 10 185 +f 185 10 7 +f 185 7 3 +f 156 21 240 +f 240 21 17 +f 240 17 14 +f 148 36 236 +f 236 36 32 +f 236 32 28 +f 226 46 174 +f 174 46 42 +f 174 42 39 +f 158 51 226 +f 226 51 47 +f 226 47 46 +f 210 71 152 +f 152 71 68 +f 152 68 63 +f 256 84 214 +f 214 84 81 +f 214 81 77 +f 201 92 256 +f 256 92 87 +f 256 87 84 +f 130 264 125 +f 125 264 187 +f 125 187 121 +f 121 187 177 +f 121 177 117 +f 203 50 250 +f 250 50 54 +f 250 54 57 diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/system/blockMeshDict b/tutorials/mesh/moveDynamicMesh/bendJunction/system/blockMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..8e0ce196b4078e775beb782db64e3b532dc8cb72 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/system/blockMeshDict @@ -0,0 +1,346 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2006 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +// Nb of cells +/* +// 2260 +d0 5; +d1 1; +d2 2; +d3 10; +d4 3; +d5 10; +d6 2; +d7 2; +d8 2; +d9 5; +*/ + +// 100000 +d0 17; +d1 3; +d2 5; +d3 30; +d4 8; +d5 30; +d6 7; +d7 5; +d8 5; +d9 17; + +#inputMode merge + +vertices +( + ( 163.03320099 -11.03547257 252.075300317) // 0 + ( 163.03320099 11.03547257 252.075300317) // 1 + ( 181.112660821 11.03547257 239.415926257) // 2 + ( 181.112660821 -11.03547257 239.415926257) // 3 + ( 186.820645067 -25 235.419152659) // 4 + ( 157.325216744 -25 256.072073914) // 5 + ( 157.325216744 25 256.072073914) // 6 + ( 186.820645067 25 235.419152659) // 7 + ( 121.715728415 28.2842709103 -100) // 8 + ( 178.28427091 28.2842709103 -100) // 9 + ( 178.28427091 13.2842713871 -100) // 10 + ( 178.28427091 -28.2842715846 -100) // 11 + ( 121.715728415 -28.2842715846 -100) // 12 + ( 121.715728415 -13.2842713871 -100) // 13 + ( 206.56854183 -56.568543179 -100) // 14 + ( 93.4314568307 -56.5685431693 -100) // 15 + ( 93.4314568307 56.5685418206 -100) // 16 + ( 206.568541821 56.5685418206 -100) // 17 + ( 206.568541821 25 -100) // 18 + ( 121.715728415 13.2842713871 -100) // 19 + ( 93.4314568307 30 -100) // 20 + ( 206.568541821 -25 -100) // 21 + ( 178.28427091 -13.2842713871 -100) // 22 + ( 93.4314568307 -30 -100) // 23 + ( 144.25122796 25 174.623724471) // 24 + ( 114.755799637 25 195.276645725) // 25 + ( 114.755799637 -25 195.276645725) // 26 + ( 144.25122796 -25 174.623724471) // 27 + ( -135.598492956 28.2842709103 80.1733574929) // 28 + ( -154.946073968 28.2842709103 133.330399444) // 29 + ( -154.946073968 13.2842713871 133.330399444) // 30 + ( -154.946073968 -28.2842715846 133.330399444) // 31 + ( -135.598492956 -28.2842715846 80.1733574929) // 32 + ( -135.598492956 -13.2842713871 80.1733574929) // 33 + ( -164.619864362 -56.568543179 159.908920112) // 34 + ( -125.924702335 -56.5685431693 53.5948362005) // 35 + ( -125.924702335 56.5685418206 53.5948362005) // 36 + ( -164.619864359 56.5685418206 159.908920103) // 37 + ( -164.619864359 25 159.908920103) // 38 + ( -135.598492956 13.2842713871 80.1733574929) // 39 + ( -125.924702335 30 53.5948362005) // 40 + ( -164.619864359 -25 159.908920103) // 41 + ( -154.946073968 -13.2842713871 133.330399444) // 42 + ( -125.924702335 -30 53.5948362005) // 43 + ( 126.07044907 13.2842713871 152.956715912) // 44 + ( 100.613664182 13.2842713871 170.781748589) // 45 + ( 89.7088908564 13.2842713871 109.622698279) // 46 + ( 72.3293929347 13.2842713871 121.791953734) // 47 + ( 126.07044907 28.2842715846 152.956715912) // 48 + ( 100.613664182 28.2842715846 170.781748589) // 49 + ( 89.7088908564 28.2842715846 109.622698279) // 50 + ( 72.3293929347 28.2842715846 121.791953734) // 51 + ( 126.07044907 -13.2842713871 152.956715912) // 52 + ( 100.613664182 -13.2842713871 170.781748589) // 53 + ( 89.7088908564 -13.2842713871 109.622698279) // 54 + ( 72.3293929347 -13.2842713871 121.791953734) // 55 + ( 126.07044907 -28.2842715846 152.956715912) // 56 + ( 100.613664182 -28.2842715846 170.781748589) // 57 + ( 89.7088908564 -28.2842715846 109.622698279) // 58 + ( 72.3293929347 -28.2842715846 121.791953734) // 59 + ( 144.251227967 -56.568543179 174.623724478) // 60 + ( 71.5281115328 -56.5685431693 87.9556892035) // 61 + ( 71.5281115328 56.5685418206 87.9556892035) // 62 + ( 144.25122796 56.5685418206 174.623724471) // 63 + ( 71.5281115328 30 87.9556892035) // 64 + ( 71.5281115328 -30 87.9556892035) // 65 + ( 114.755799642 -56.568543179 195.276645734) // 66 + ( 58.1872571424 -56.5685431693 97.2970560138) // 67 + ( 58.1872571424 56.5685418206 97.2970560138) // 68 + ( 114.755799637 56.5685418206 195.276645725) // 69 + ( 58.1872571424 30 97.2970560138) // 70 + ( 58.1872571424 -30 97.2970560138) // 71 + ( 138.543243714 -11.03547257 178.620498068) // 72 + ( 120.463783883 -11.03547257 191.279872128) // 73 + ( 120.463783883 11.03547257 191.279872128) // 74 + ( 138.543243714 11.03547257 178.620498068) // 75 + ( 106.977860404 -6.64213569356 166.32549042) // 76 + ( 106.977860404 6.64213569356 166.32549042) // 77 + ( 119.706252848 6.64213569356 157.412974081) // 78 + ( 119.706252848 -6.64213569356 157.412974081) // 79 + ( 76.6742674151 -6.64213569356 118.74963987) // 80 + ( 76.6742674151 6.64213569356 118.74963987) // 81 + ( 85.364016376 6.64213569356 112.665012142) // 82 + ( 85.364016376 -6.64213569356 112.665012142) // 83 + ( 68.1928979352 -15 90.291030906) // 84 + ( 68.1928979352 15 90.291030906) // 85 + ( 61.52247074 -15 94.9617143112) // 86 + ( 61.52247074 15 94.9617143112) // 87 +); + +edges +( +); + +blocks +( + // 0 + hex ( 72 75 74 73 3 2 1 0) ($d6 $d8 $d0 ) simpleGrading (1 1 1) + // 1 + hex ( 26 27 72 73 5 4 3 0) ($d8 $d1 $d0 ) simpleGrading (1 1 1) + // 2 + hex ( 25 26 73 74 6 5 0 1) ($d6 $d1 $d0 ) simpleGrading (1 1 1) + // 3 + hex ( 24 25 74 75 7 6 1 2) ($d8 $d1 $d0 ) simpleGrading (1 1 1) + // 4 + hex ( 24 75 72 27 7 2 3 4) ($d1 $d6 $d0 ) simpleGrading (1 1 1) + // 5 + hex ( 44 46 50 48 10 19 8 9) ($d9 $d2 $d3 ) simpleGrading (1 1 1) + // 6 + hex ( 48 50 62 63 9 8 16 17) ($d9 $d4 $d3 ) simpleGrading (1 1 1) + // 7 + hex ( 46 64 62 50 19 20 16 8) ($d4 $d2 $d3 ) simpleGrading (1 1 1) + // 8 + hex ( 24 44 48 63 18 10 9 17) ($d4 $d2 $d3 ) simpleGrading (1 1 1) + // 9 + hex ( 44 52 54 46 10 22 13 19) ($d6 $d9 $d3 ) simpleGrading (1 1 1) + // 10 + hex ( 24 27 52 44 18 21 22 10) ($d6 $d4 $d3 ) simpleGrading (1 1 1) + // 11 + hex ( 52 56 58 54 22 11 12 13) ($d7 $d9 $d3 ) simpleGrading (1 1 1) + // 12 + hex ( 56 60 61 58 11 14 15 12) ($d4 $d9 $d3 ) simpleGrading (1 1 1) + // 13 + hex ( 27 60 56 52 21 14 11 22) ($d7 $d4 $d3 ) simpleGrading (1 1 1) + // 14 + hex ( 54 58 61 65 13 12 15 23) ($d7 $d4 $d3 ) simpleGrading (1 1 1) + // 15 + hex ( 46 54 65 64 19 13 23 20) ($d6 $d4 $d3 ) simpleGrading (1 1 1) + // 16 + hex ( 48 63 69 49 44 24 25 45) ($d4 $d8 $d2 ) simpleGrading (1 1 1) + // 17 + hex ( 74 75 78 77 25 24 44 45) ($d8 $d4 $d1 ) simpleGrading (1 1 1) + // 18 + hex ( 72 79 78 75 27 52 44 24) ($d4 $d6 $d1 ) simpleGrading (1 1 1) + // 19 + hex ( 26 53 42 41 25 45 30 38) ($d4 $d5 $d6 ) simpleGrading (1 1 1) + // 20 + hex ( 29 49 69 37 30 45 25 38) ($d5 $d4 $d2 ) simpleGrading (1 1 1) + // 21 + hex ( 73 74 77 76 26 25 45 53) ($d6 $d4 $d1 ) simpleGrading (1 1 1) + // 22 + hex ( 31 57 53 42 34 66 26 41) ($d5 $d7 $d4 ) simpleGrading (1 1 1) + // 23 + hex ( 56 57 66 60 52 53 26 27) ($d8 $d4 $d7 ) simpleGrading (1 1 1) + // 24 + hex ( 72 73 76 79 27 26 53 52) ($d8 $d4 $d1 ) simpleGrading (1 1 1) + // 25 + hex ( 45 49 51 47 30 29 28 39) ($d2 $d9 $d5 ) simpleGrading (1 1 1) + // 26 + hex ( 49 69 68 51 29 37 36 28) ($d4 $d9 $d5 ) simpleGrading (1 1 1) + // 27 + hex ( 47 51 68 70 39 28 36 40) ($d2 $d4 $d5 ) simpleGrading (1 1 1) + // 28 + hex ( 45 47 55 53 30 39 33 42) ($d9 $d6 $d5 ) simpleGrading (1 1 1) + // 29 + hex ( 53 55 59 57 42 33 32 31) ($d9 $d7 $d5 ) simpleGrading (1 1 1) + // 30 + hex ( 57 59 67 66 31 32 35 34) ($d9 $d4 $d5 ) simpleGrading (1 1 1) + // 31 + hex ( 55 71 67 59 33 43 35 32) ($d4 $d7 $d5 ) simpleGrading (1 1 1) + // 32 + hex ( 47 70 71 55 39 40 43 33) ($d4 $d6 $d5 ) simpleGrading (1 1 1) + // 33 + hex ( 48 49 51 50 44 45 47 46) ($d8 $d9 $d2 ) simpleGrading (1 1 1) + // 34 + hex ( 77 78 82 81 45 44 46 47) ($d8 $d9 $d1 ) simpleGrading (1 1 1) + // 35 + hex ( 78 79 83 82 44 52 54 46) ($d6 $d9 $d1 ) simpleGrading (1 1 1) + // 36 + hex ( 76 77 81 80 53 45 47 55) ($d6 $d9 $d1 ) simpleGrading (1 1 1) + // 37 + hex ( 62 68 70 64 50 51 47 46) ($d8 $d2 $d4 ) simpleGrading (1 1 1) + // 38 + hex ( 82 83 84 85 46 54 65 64) ($d6 $d4 $d1 ) simpleGrading (1 1 1) + // 39 + hex ( 81 82 85 87 47 46 64 70) ($d8 $d4 $d1 ) simpleGrading (1 1 1) + // 40 + hex ( 80 81 87 86 55 47 70 71) ($d6 $d4 $d1 ) simpleGrading (1 1 1) + // 41 + hex ( 62 63 69 68 50 48 49 51) ($d9 $d8 $d4 ) simpleGrading (1 1 1) + // 42 + hex ( 56 58 59 57 52 54 55 53) ($d9 $d8 $d7 ) simpleGrading (1 1 1) + // 43 + hex ( 76 80 83 79 53 55 54 52) ($d9 $d8 $d1 ) simpleGrading (1 1 1) + // 44 + hex ( 61 65 71 67 58 54 55 59) ($d7 $d8 $d4 ) simpleGrading (1 1 1) + // 45 + hex ( 80 86 84 83 55 71 65 54) ($d4 $d8 $d1 ) simpleGrading (1 1 1) + // 46 + hex ( 60 61 67 66 56 58 59 57) ($d9 $d8 $d4 ) simpleGrading (1 1 1) + // 47 + hex ( 76 79 78 77 73 72 75 74) ($d8 $d6 $d4 ) simpleGrading (1 1 1) + // 48 + hex ( 80 83 82 81 76 79 78 77) ($d8 $d6 $d9 ) simpleGrading (1 1 1) + // 49 + hex ( 84 85 87 86 83 82 81 80) ($d6 $d8 $d4 ) simpleGrading (1 1 1) +); + +boundary +( + InletSmall + { + type patch; + faces + ( + ( 0 1 2 3) // 0 + ( 0 3 4 5) // 1 + ( 0 5 6 1) // 2 + ( 1 6 7 2) // 3 + ( 2 7 4 3) // 4 + ); + } + Outlet + { + type patch; + faces + ( + ( 8 19 10 9) // 0 + ( 8 9 17 16) // 1 + ( 8 16 20 19) // 2 + ( 9 10 18 17) // 3 + ( 10 19 13 22) // 4 + ( 10 22 21 18) // 5 + ( 11 22 13 12) // 6 + ( 11 12 15 14) // 7 + ( 11 14 21 22) // 8 + ( 12 13 23 15) // 9 + ( 13 19 20 23) // 10 + ); + } + SmallPipe + { + type wall; + faces + ( + ( 4 7 24 27) // 0 + ( 4 27 26 5) // 1 + ( 5 26 25 6) // 2 + ( 6 25 24 7) // 3 + ); + } + Inlet + { + type patch; + faces + ( + ( 28 29 30 39) // 0 + ( 28 36 37 29) // 1 + ( 28 39 40 36) // 2 + ( 29 37 38 30) // 3 + ( 30 42 33 39) // 4 + ( 30 38 41 42) // 5 + ( 31 32 33 42) // 6 + ( 31 34 35 32) // 7 + ( 31 42 41 34) // 8 + ( 32 35 43 33) // 9 + ( 33 43 40 39) // 10 + ); + } + BigPipe + { + type wall; + faces + ( + ( 14 21 27 60) // 0 + ( 14 15 61 60) // 1 + ( 15 23 65 61) // 2 + ( 16 17 63 62) // 3 + ( 16 62 64 20) // 4 + ( 17 63 24 18) // 5 + ( 18 24 27 21) // 6 + ( 20 64 65 23) // 7 + ( 24 63 69 25) // 8 + ( 25 69 37 38) // 9 + ( 25 38 41 26) // 10 + ( 26 41 34 66) // 11 + ( 26 66 60 27) // 12 + ( 34 66 67 35) // 13 + ( 35 67 71 43) // 14 + ( 36 68 69 37) // 15 + ( 36 40 70 68) // 16 + ( 40 43 71 70) // 17 + ( 60 61 67 66) // 18 + ( 61 65 71 67) // 19 + ( 62 63 69 68) // 20 + ( 62 68 70 64) // 21 + ( 64 85 84 65) // 22 + ( 64 70 87 85) // 23 + ( 65 84 86 71) // 24 + ( 70 71 86 87) // 25 + ( 84 85 87 86) // 26 + ); + } +); + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/system/controlDict b/tutorials/mesh/moveDynamicMesh/bendJunction/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..2fdd223f837d9143fa3b915d4f187e34c3fe39cc --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/system/controlDict @@ -0,0 +1,59 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2006 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +DebugSwitches +{ + pointBoundaryMesh 1; +} + +application moveDynamicMesh; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 10; + +deltaT 1; + +writeControl timeStep; +writeInterval 1; + +purgeWrite 0; + +writeFormat ascii; //binary; + +writePrecision 16; + +writeCompression false; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable yes; + +adjustTimeStep yes; + +maxCo 0.1; +maxAlphaCo 0.1; +maxDeltaT 1; + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/system/decomposeParDict b/tutorials/mesh/moveDynamicMesh/bendJunction/system/decomposeParDict new file mode 100644 index 0000000000000000000000000000000000000000..a3282112ad11ad20a8a9873519a3900c94de32d6 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/system/decomposeParDict @@ -0,0 +1,24 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + note "mesh decomposition control dictionary"; + object decomposeParDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- The total number of domains (mandatory) +numberOfSubdomains 2; + +//- The decomposition method (mandatory) +method scotch; + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/system/fvSchemes b/tutorials/mesh/moveDynamicMesh/bendJunction/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..59150f323dd356adce54d01b366712a60524c87c --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/system/fvSchemes @@ -0,0 +1,45 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2006 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +ddtSchemes +{} + +gradSchemes +{ + default Gauss linear; +} + +divSchemes +{} + +laplacianSchemes +{ + default Gauss linear orthogonal; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default orthogonal; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/system/fvSolution b/tutorials/mesh/moveDynamicMesh/bendJunction/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..96c25bcf0cbf1c05b209c9411e0bdee12df3910b --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/system/fvSolution @@ -0,0 +1,33 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2006 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ + "cellDisplacement.*" + { + solver GAMG; + tolerance 1e-08; + relTol 0; + smoother GaussSeidel; + } +} + +PIMPLE +{} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/bendJunction/system/surfaceFeatureExtractDict b/tutorials/mesh/moveDynamicMesh/bendJunction/system/surfaceFeatureExtractDict new file mode 100644 index 0000000000000000000000000000000000000000..846e80c94de1594e52f0d0693bd358d609f8f68b --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/bendJunction/system/surfaceFeatureExtractDict @@ -0,0 +1,32 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object surfaceFeatureExtractDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +geometry.obj +{ + // How to obtain raw features (extractFromFile || extractFromSurface) + extractionMethod extractFromSurface; + + // Mark edges whose adjacent surface normals are at an angle less + // than includedAngle as features + // - 0 : selects no edges + // - 180: selects all edges + includedAngle 135; + + // Write features to obj format for postprocessing + writeObj yes; +} + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/0/pointDisplacement b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/0/pointDisplacement new file mode 100644 index 0000000000000000000000000000000000000000..038119bc3eba906ee07c7d33edabeac433c07ca3 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/0/pointDisplacement @@ -0,0 +1,68 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 2309 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + arch "LSB;label=32;scalar=64"; + class pointVectorField; + location "0"; + object pointDisplacement; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [0 1 0 0 0 0 0]; + +internalField uniform (0 0 0); + +boundaryField +{ + movingZone + { + type uniformFixedValue; + uniformValue table + ( + ( 0.0 (0 0 0)) + ( 5.0 (0.2 0 0)) + (10.0 (0 0 0)) + ); + } + movingZoneEdges + { + //type slip; + ${movingZone} + } + + minX + { + type slip; + } + maxX + { + $minX + } + minY + { + $minX + } + maxY + { + $minX + } + minZ + { + $minX + } + maxZ + { + $minX + } +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/Allclean b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..5ef46f9d35db1f707b94b73f1b5c3903b6e47332 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/Allclean @@ -0,0 +1,17 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +cleanCase + +rm -rf constant/extendedFeatureEdgeMesh + +#- From pointMesh generation +rm -rf constant/pointMesh +rm -f constant/triSurface/blockMesh.obj + +#- From surfaceFeatureExtract +rm -f constant/triSurface/box222.eMesh + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/Allrun b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..5a120500ec10cbf6ed53c3a0e833affe90b5f23f --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/Allrun @@ -0,0 +1,47 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + +#- Generate mesh +runApplication blockMesh + +#- Create faceZone (on unrotated mesh so is easy to select box of faces) +runApplication topoSet + +#- Rotate a bit +#runApplication transformPoints -rotate-z -45 + +#- Generate pointMesh with additional feature patches +# (in constant/pointMesh/boundary) +# - extracted surface is not used +# - specify illegal patchname so none will be extracted (could use +# '-excludePatches' instead) +# - extract feature points of faceZone +# - additionally extract all points of faceZone (-extractZonePoints) +runApplication surfaceMeshExtract \ + -featureAngle 45 \ + -patches '(ZZZZZZ)' \ + -faceZones '(movingZone)' -extractZonePoints \ + constant/triSurface/blockMesh.obj + +#- For postprocessing: extract new pointPatches as vtk files +setSet <<EOF +pointSet p0 new patchToPoint movingZone +pointSet p1 new patchToPoint movingZoneEdges +EOF + +#- TBD. move triSurfaces to resources +#mkdir -p constant/triSurface +#cp -f \ +# "$FOAM_TUTORIALS"/resources/geometry/box222.obj \ +# constant/triSurface/ + +#- Extract features from surface. Writes .eMesh +runApplication surfaceFeatureExtract + +#- Morph mesh to the surface (.obj file) and feature-edges (.eMesh file) +#- Note: needs point-based motion solver +runApplication moveDynamicMesh + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/README.txt b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a21ff07233062b83c03301bc5e81b3f7bec6ab9 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/README.txt @@ -0,0 +1,2 @@ +Demo of applying mesh motion to internal faces. Note: using point-based +motion-solver since no boundary faces to put motion bcs on. diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/constant/dynamicMeshDict b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..deeaf753bc4abf1ffa393c19ab632f93392b330a --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/constant/dynamicMeshDict @@ -0,0 +1,31 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicMotionSolverFvMesh; + +// For point-bcs +motionSolverLibs (fvMotionSolvers); + +motionSolver displacementPointSmoothing; +displacementPointSmoothingCoeffs +{ + // Use geometricElementTransform to maintain relative sizes + pointSmoother geometricElementTransform; + transformationParameter 0.667; + nPointSmootherIter 10; +} + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/constant/triSurface/box222.obj b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/constant/triSurface/box222.obj new file mode 100644 index 0000000000000000000000000000000000000000..f1aceeca48a77cbe62aea577f651b129de3fa96d --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/constant/triSurface/box222.obj @@ -0,0 +1,79 @@ +# Generated by Visualization Toolkit +v -1 -1 -1 +v -1 -1 1 +v -1 1 -1 +v -1 1 1 +v 1 -1 -1 +v 1 -1 1 +v 1 1 -1 +v 1 1 1 +v -1 -1 -1 +v -1 -1 1 +v 1 -1 -1 +v 1 -1 1 +v -1 1 -1 +v -1 1 1 +v 1 1 -1 +v 1 1 1 +v -1 -1 -1 +v 1 -1 -1 +v -1 1 -1 +v 1 1 -1 +v -1 -1 1 +v 1 -1 1 +v -1 1 1 +v 1 1 1 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn -1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 1 0 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 -1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 1 0 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 -1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vn 0 0 1 +vt -0.5 -0.5 +vt 1.5 -0.5 +vt -0.5 1.5 +vt 1.5 1.5 +vt 0.5 -0.5 +vt -1.5 -0.5 +vt 0.5 1.5 +vt -1.5 1.5 +vt 0.5 0.5 +vt 0.5 -1.5 +vt -1.5 0.5 +vt -1.5 -1.5 +vt -0.5 0.5 +vt -0.5 -1.5 +vt 1.5 0.5 +vt 1.5 -1.5 +vt 0.5 -0.5 +vt -1.5 -0.5 +vt 0.5 1.5 +vt -1.5 1.5 +vt -0.5 -0.5 +vt 1.5 -0.5 +vt -0.5 1.5 +vt 1.5 1.5 +f 1/1/1 2/2/2 4/4/4 3/3/3 +f 5/5/5 7/7/7 8/8/8 6/6/6 +f 9/9/9 11/11/11 12/12/12 10/10/10 +f 13/13/13 14/14/14 16/16/16 15/15/15 +f 17/17/17 19/19/19 20/20/20 18/18/18 +f 21/21/21 22/22/22 24/24/24 23/23/23 diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/blockMeshDict b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/blockMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..29c9c50eea362de74a6f67c3e9c0a4a447c2157b --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/blockMeshDict @@ -0,0 +1,95 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +vertices +( + // Inner block + (-2 -2 -2) + ( 2 -2 -2) + ( 2 2 -2) + (-2 2 -2) + (-2 -2 2) + ( 2 -2 2) + ( 2 2 2) + (-2 2 2) +); + +blocks +( + hex (0 1 2 3 4 5 6 7) (20 20 20) grading (1 10 1) // Inner block +); + +boundary +( + minX + { + type patch; + faces + ( + (0 0) // block 0: x-min + ); + } + + maxX + { + type patch; + faces + ( + (0 1) // block 0: x-max + ); + } + + minY + { + type patch; + faces + ( + (0 2) // block 0: y-min + ); + } + + maxY + { + type patch; + faces + ( + (0 3) // block 0: y-max + ); + } + + minZ + { + type patch; + faces + ( + (0 4) // block 0: z-min + ); + } + + maxZ + { + type patch; + faces + ( + (0 5) // block 0: z-max + ); + } +); + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/controlDict b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..f7bf44fca761a8dfcc42bf1e0743c56cd3362daa --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/controlDict @@ -0,0 +1,53 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +DebugSwitches +{ + pointBoundaryMesh 1; +} + +application moveDynamicMesh; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 10; + +deltaT 1; + +writeControl timeStep; + +writeInterval 1; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 6; + +writeCompression off; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable true; + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/fvSchemes b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..dce45d04ae700d8dc803ec1a4749fef42b01ad9a --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/fvSchemes @@ -0,0 +1,44 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +ddtSchemes +{} + +gradSchemes +{ + default Gauss linear; +} + +divSchemes +{} + +laplacianSchemes +{ + default Gauss linear corrected; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default corrected; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/fvSolution b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..eaff818230d35f16dff830ce18b781ad43ace4d3 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/fvSolution @@ -0,0 +1,33 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ + "cellDisplacement.*" + { + solver GAMG; + tolerance 1e-08; + relTol 0; + smoother GaussSeidel; + } +} + + +PIMPLE +{} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/surfaceFeatureExtractDict b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/surfaceFeatureExtractDict new file mode 100644 index 0000000000000000000000000000000000000000..9039408675c88bdcb9ca01631b684db47c22448a --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/surfaceFeatureExtractDict @@ -0,0 +1,33 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object surfaceFeatureExtractDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +box222.obj +{ + // How to obtain raw features (extractFromFile || extractFromSurface) + extractionMethod extractFromSurface; + + // Mark edges whose adjacent surface normals are at an angle less + // than includedAngle as features + // - 0 : selects no edges + // - 180: selects all edges + includedAngle 135; + + // Write features to obj format for postprocessing + writeObj yes; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/topoSetDict b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/topoSetDict new file mode 100644 index 0000000000000000000000000000000000000000..3438cbf62d83886265b1abdbcf79e418c4a719b8 --- /dev/null +++ b/tutorials/mesh/moveDynamicMesh/faceZoneBlock/system/topoSetDict @@ -0,0 +1,43 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object topoSetDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +actions +( + { + name c0; + type cellSet; + action new; + source boxToCell; + box (-1 -1 -1)(1 1 1); + } + { + name movingZoneFaces; + type faceSet; + action new; + source cellToFace; + set c0; + option outside; + } + { + name movingZone; + type faceZoneSet; + action new; + source setToFaceZone; + faceSet movingZoneFaces; + } +); + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/blockMeshDict b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/blockMeshDict index a4f374de0b4180b9015f7f7cac1d71ce40df03ca..84172915a09b9ca78f1207b4d709081624d4c669 100644 --- a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/blockMeshDict +++ b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/blockMeshDict @@ -18,14 +18,14 @@ scale 1; vertices ( - (-1 -1 -1) - ( 2 -1 -1) - ( 2 0 -1) - (-1 0 -1) - (-1 -1 1) - ( 2 -1 1) - ( 2 0 1) - (-1 0 1) + (-1 -0.8 -1) + ( 2 -0.8 -1) + ( 2 -0.2 -1) + (-1 -0.2 -1) + (-1 -0.8 1) + ( 2 -0.8 1) + ( 2 -0.2 1) + (-1 -0.2 1) ); blocks @@ -44,14 +44,30 @@ boundary type patch; faces ( - (3 7 6 2) - (1 5 4 0) //back (2 6 5 1) //outlet (0 4 7 3) //inlet (0 3 2 1) //lowerWall (4 5 6 7) //upperWall ); } + + front + { + type symmetryPlane; + faces + ( + (3 7 6 2) + ); + } + + back + { + type symmetryPlane; + faces + ( + (1 5 4 0) //back + ); + } ); diff --git a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSchemes b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSchemes index 3475759928b38316ad4e0134f29ddc794551f1ec..9994fe78511e4476b32099aa2868f3993e877f8c 100644 --- a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSchemes +++ b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSchemes @@ -5,14 +5,14 @@ | \\ / A nd | Website: www.openfoam.com | | \\/ M anipulation | | \*---------------------------------------------------------------------------*/ +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // FoamFile { - version 2.0; - format ascii; - class dictionary; - object fvSchemes; + version 2; + format ascii; + class dictionary; + object fvSchemes; } -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ddtSchemes { @@ -20,6 +20,7 @@ ddtSchemes gradSchemes { + default Gauss linear; } divSchemes @@ -28,14 +29,17 @@ divSchemes laplacianSchemes { + default Gauss linear corrected; } interpolationSchemes { + default linear; } snGradSchemes { + default corrected; } wallDist diff --git a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSolution b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSolution index c89b4c70181b9c46cda8e2e104927bd749728cd2..5771a4eb9e8a9c657308c3ac77af37bf0087ffc9 100644 --- a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSolution +++ b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/fvSolution @@ -16,6 +16,13 @@ FoamFile solvers { + "cellDisplacement.*" + { + solver GAMG; + tolerance 1e-08; + relTol 0; + smoother GaussSeidel; + } } diff --git a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/snappyHexMeshDict index a6ad5526da27b94f000b4d8ded2df29d2e3b34b1..97fd5130dc7fa7ec3316250939fe80018e6cd0aa 100644 --- a/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/snappyHexMeshDict +++ b/tutorials/mesh/snappyHexMesh/airfoilWithLayers/system/snappyHexMeshDict @@ -14,6 +14,11 @@ FoamFile } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Type of mesh generation: +// - castellated (default) +// - castellatedBufferLayer +//type castellatedBufferLayer; + // Which of the steps to run castellatedMesh true; snap true; @@ -427,6 +432,31 @@ castellatedMeshControls //nCellZoneErodeIter 2; } + +// Internal macro for mesh-motion solver to use +_meshMotionSolver +{ + solver displacementPointSmoothing; + displacementPointSmoothingCoeffs + { + //// Use geometricElementTransform to maintain relative sizes + //pointSmoother geometricElementTransform; + //transformationParameter 0.667; + //nPointSmootherIter 10; + + // Use laplacian to untangle problem areas + pointSmoother laplacian; + nPointSmootherIter 10; + + //relaxationFactors (1.0 0.8 0.6 0.4 0.2 0.0); + //meshQuality + //{ + // #includeEtc "caseDicts/meshQualityDict" + //} + } +} + + // Settings for the snapping. snapControls { @@ -501,6 +531,10 @@ snapControls //- Attract points only to the surface they originate from. Default // false. This can improve snapping of intersecting surfaces. strictRegionSnap true; + + + // Motion solver to use (when in castellatedBufferLayer) + ${_meshMotionSolver} } // Settings for the layer addition. @@ -601,19 +635,27 @@ addLayersControls // motion solvers. It needs specification of the solver to use and // its control dictionary. //meshShrinker displacementMotionSolver; - //solver displacementLaplacian; - //displacementLaplacianCoeffs + //solver multiDisplacement; + //solvers //{ - // diffusivity quadratic inverseDistance - // ( - // sphere.stl_firstSolid - // maxY - // ); + // displacementLaplacian + // { + // // Note that e.g. displacementLaplacian needs entries in + // // fvSchemes, fvSolution. Also specify a minIter > 1 when + // // solving + // // cellDisplacement since otherwise solution might not be + // // sufficiently accurate on points. + // solver displacementLaplacian; + // diffusivity quadratic inverseDistance + // ( + // aerofoil + // ); + // } + // displacementPointSmoothing + // { + // ${_meshMotionSolver} + // } //} - // Note that e.g. displacementLaplacian needs entries in - // fvSchemes, fvSolution. Also specify a minIter > 1 when solving - // cellDisplacement since otherwise solution might not be sufficiently - // accurate on points. // Medial axis analysis (for use with default displacementMedialAxis) diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/Allclean b/tutorials/mesh/snappyHexMesh/rotated_block/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..5574bad3101ee40ee0d5117a5615dea54af4e839 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/Allclean @@ -0,0 +1,10 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +rm -rf constant/extendedFeatureEdgeMesh +rm -rf constant/triSurface/block.eMesh +cleanCase0 + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/Allrun b/tutorials/mesh/snappyHexMesh/rotated_block/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..f40a167c84ce598bf8ab52d7ba5a9c310fe9cfc9 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/Allrun @@ -0,0 +1,24 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + +#mkdir -p constant/triSurface +#cp -f \ +# "$FOAM_TUTORIALS"/resources/geometry/flange.stl.gz \ +# constant/triSurface + +runApplication blockMesh + +runApplication surfaceFeatureExtract + +runApplication snappyHexMesh + +runApplication checkMesh -writeFields '(nonOrthoAngle)' + +# Run parallel a bit as well +runApplication decomposePar +runParallel -s parallel snappyHexMesh +runParallel -s parallel checkMesh -writeFields '(nonOrthoAngle)' + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/README.txt b/tutorials/mesh/snappyHexMesh/rotated_block/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..19009dfc524e2249e7a37692996d45812d8a21fc --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/README.txt @@ -0,0 +1,2 @@ +- rotated block inside regular blockMesh +- set up to add buffer layers after smoothing outside diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/constant/dynamicMeshDict b/tutorials/mesh/snappyHexMesh/rotated_block/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..fdf87f68acae84535f75c22673ea84691e3681b8 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/constant/dynamicMeshDict @@ -0,0 +1,41 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicMotionSolverFvMesh; + +solver displacementPointSmoothing; + +displacementPointSmoothingCoeffs +{ + //// Use geometricElementTransform to maintain relative sizes + //pointSmoother geometricElementTransform; + //transformationParameter 0.667; + //nPointSmootherIter 10; + + // Use laplacian to untangle problem areas + pointSmoother laplacian; + nPointSmootherIter 100; + + //relaxationFactors (1.0 0.8 0.6 0.4 0.2 0.0); + //meshQuality + //{ + // #includeEtc "caseDicts/meshQualityDict" + //} +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/constant/transportProperties b/tutorials/mesh/snappyHexMesh/rotated_block/constant/transportProperties new file mode 100644 index 0000000000000000000000000000000000000000..fc05a376222c9ce0fd94d4e4134855e949ee5d28 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/constant/transportProperties @@ -0,0 +1,21 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object transportProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +nu 0.01; + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/constant/triSurface/block.obj b/tutorials/mesh/snappyHexMesh/rotated_block/constant/triSurface/block.obj new file mode 100644 index 0000000000000000000000000000000000000000..b8fa074e6ed3e01a4155021920ee05abb2198910 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/constant/triSurface/block.obj @@ -0,0 +1,38 @@ +# Wavefront OBJ file written 2024-01-24T16:36:27 +o block + +# points : 8 +# faces : 6 +# zones : 6 +# 0 maxY (nFaces: 1) +# 1 minX (nFaces: 1) +# 2 minZ (nFaces: 1) +# 3 maxX (nFaces: 1) +# 4 maxZ (nFaces: 1) +# 5 minY (nFaces: 1) + +# <points count="8"> +v 0 0 0 +v -0.5773502691896258 -0.2113248654051871 0.7886751345948129 +v -1.154700538379252 0.5773502691896258 0.5773502691896258 +v -0.5773502691896258 0.7886751345948129 -0.2113248654051871 +v 0.5773502691896258 0.5773502691896258 0.5773502691896258 +v 0 1.366025403784439 0.3660254037844388 +v -0.5773502691896258 1.154700538379252 1.154700538379252 +v 0 0.3660254037844388 1.366025403784439 +# </points> + +# <faces count="6"> +g maxY +f 4 3 7 6 +g minX +f 1 2 3 4 +g minZ +f 1 4 6 5 +g maxX +f 5 6 7 8 +g maxZ +f 2 8 7 3 +g minY +f 1 5 8 2 +# </faces> diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/blockMeshDict b/tutorials/mesh/snappyHexMesh/rotated_block/system/blockMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..bcfd580bf0617a579a6b3b3cac2ea219a132eaad --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/blockMeshDict @@ -0,0 +1,96 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +vertices +( + (-2 -1 -1) + ( 1 -1 -1) + ( 1 2 -1) + (-2 2 -1) + (-2 -1 2) + ( 1 -1 2) + ( 1 2 2) + (-2 2 2) +); + +blocks +( + hex (0 1 2 3 4 5 6 7) (20 20 20) simpleGrading (1 1 1) +); + +edges +( +); + +boundary +( + minX + { + type wall; + faces + ( + (0 4 7 3) + ); + } + maxX + { + type wall; + faces + ( + (2 6 5 1) + ); + } + + + minY + { + type wall; + faces + ( + (1 5 4 0) + ); + } + maxY + { + type wall; + faces + ( + (3 7 6 2) + ); + } + + + minZ + { + type wall; + faces + ( + (0 3 2 1) + ); + } + maxZ + { + type wall; + faces + ( + (4 5 6 7) + ); + } +); + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/blockMeshDict.block b/tutorials/mesh/snappyHexMesh/rotated_block/system/blockMeshDict.block new file mode 100644 index 0000000000000000000000000000000000000000..20b44b2bf6c039ae96de2581af638fddaa8ddc6e --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/blockMeshDict.block @@ -0,0 +1,97 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +vertices +( + (0 0 0) + (1 0 0) + (1 1 0) + (0 1 0) + (0 0 1) + (1 0 1) + (1 1 1) + (0 1 1) +); + +blocks +( + //hex (0 1 2 3 4 5 6 7) (20 20 10) simpleGrading (100 100 1) + hex (0 1 2 3 4 5 6 7) (1 1 1) simpleGrading (1 1 1) +); + +edges +( +); + +boundary +( + minX + { + type wall; + faces + ( + (0 4 7 3) + ); + } + maxX + { + type wall; + faces + ( + (2 6 5 1) + ); + } + + + minY + { + type wall; + faces + ( + (1 5 4 0) + ); + } + maxY + { + type wall; + faces + ( + (3 7 6 2) + ); + } + + + minZ + { + type wall; + faces + ( + (0 3 2 1) + ); + } + maxZ + { + type wall; + faces + ( + (4 5 6 7) + ); + } +); + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/controlDict b/tutorials/mesh/snappyHexMesh/rotated_block/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..953725e2fb32b82dd05f7740e7c1c51b43a13dec --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/controlDict @@ -0,0 +1,49 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +application snappyHexMesh; + +startFrom startTime; + +startTime 0; + +stopAt writeNow; + +endTime 30; + +deltaT 1; + +writeControl timeStep; + +writeInterval 1; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 16; + +writeCompression off; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable true; + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/decomposeParDict b/tutorials/mesh/snappyHexMesh/rotated_block/system/decomposeParDict new file mode 100644 index 0000000000000000000000000000000000000000..1577bf4039ae4980f51693f4376c5570f4a883d4 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/decomposeParDict @@ -0,0 +1,24 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1806 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + note "mesh decomposition control dictionary"; + object decomposeParDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- The total number of domains (mandatory) +numberOfSubdomains 5; + +//- The decomposition method (mandatory) +method scotch; //random; + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/fvSchemes b/tutorials/mesh/snappyHexMesh/rotated_block/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..fd610a97b38961fd361d0cc2ba623c7c139a09da --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/fvSchemes @@ -0,0 +1,59 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//geometry +//{ +// type highAspectRatio; +// minAspect 0; +// maxAspect 0; +//} + + +ddtSchemes +{ + default Euler; +} + +gradSchemes +{ + default Gauss linear; + grad(p) Gauss linear; +} + +divSchemes +{ + default none; + div(phi,U) Gauss linear; +} + +laplacianSchemes +{ + default Gauss linear orthogonal; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default orthogonal; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/fvSolution b/tutorials/mesh/snappyHexMesh/rotated_block/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..fa297c1118f4b55e8bbdcaffbd0116aea0463b39 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/fvSolution @@ -0,0 +1,52 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ + p + { + solver PCG; + preconditioner DIC; + tolerance 1e-06; + relTol 0.05; + } + + pFinal + { + $p; + relTol 0; + } + + U + { + solver smoothSolver; + smoother symGaussSeidel; + tolerance 1e-05; + relTol 0; + } +} + +PISO +{ + nCorrectors 2; + nNonOrthogonalCorrectors 0; + pRefCell 0; + pRefValue 0; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/meshQualityDict b/tutorials/mesh/snappyHexMesh/rotated_block/system/meshQualityDict new file mode 100644 index 0000000000000000000000000000000000000000..1a0afa5f754e90e763ba4fee639cdef03495e87f --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/meshQualityDict @@ -0,0 +1,32 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object meshQualityDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Include defaults parameters from master dictionary +#includeEtc "caseDicts/meshQualityDict" + +//maxNonOrtho 180; +//maxConcave 180; +//minVol -1e30; +maxBoundarySkewness -1; +maxInternalSkewness -1; +//minTetQuality -1e30; +//minDeterminant -1e30; +//minTwist -1; +//minFaceWeight -1; +//minVolRatio -1; +//minDeterminant -1; + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/rotated_block/system/snappyHexMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..b6bf90d2eff4a15abdac8a4fea1e3508b6c55bc2 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/snappyHexMeshDict @@ -0,0 +1,364 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object snappyHexMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Type of mesh generation: +// - castellated (default) +// - castellatedBufferLayer +type castellatedBufferLayer; + +// Which of the steps to run +castellatedMesh true; +snap true; +addLayers false; //true; + + +// Geometry. Definition of all surfaces. All surfaces are of class +// searchableSurface. +// Surfaces are used +// - to specify refinement for any mesh cell intersecting it +// - to specify refinement for any mesh cell inside/outside/near +// - to 'snap' the mesh boundary to the surface +geometry +{ + block + { + type triSurfaceMesh; + file "block.obj"; + } +} + + +// Settings for the castellatedMesh generation. +castellatedMeshControls +{ + + // Refinement parameters + // ~~~~~~~~~~~~~~~~~~~~~ + + // If local number of cells is >= maxLocalCells on any processor + // switches from from refinement followed by balancing + // (current method) to (weighted) balancing before refinement. + maxLocalCells 100000; + + // Overall cell limit (approximately). Refinement will stop immediately + // upon reaching this number so a refinement level might not complete. + // Note that this is the number of cells before removing the part which + // is not 'visible' from the keepPoint. The final number of cells might + // actually be a lot less. + maxGlobalCells 2000000; + + // The surface refinement loop might spend lots of iterations refining just a + // few cells. This setting will cause refinement to stop if <= minimumRefine + // are selected for refinement. Note: it will at least do one iteration + // (unless the number of cells to refine is 0) + minRefinementCells 0; + + // Number of buffer layers between different levels. + // 1 means normal 2:1 refinement restriction, larger means slower + // refinement. + nCellsBetweenLevels 1; + + + + // Explicit feature edge refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies a level for any cell intersected by its edges. + // This is a featureEdgeMesh, read from constant/triSurface for now. + features + ( + { + file "block.eMesh"; + level 0; + } + ); + + + + // Surface based refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies two levels for every surface. The first is the minimum level, + // every cell intersecting a surface gets refined up to the minimum level. + // The second level is the maximum level. Cells that 'see' multiple + // intersections where the intersections make an + // angle > resolveFeatureAngle get refined up to the maximum level. + + refinementSurfaces + { + block + { + // Surface-wise min and max refinement level + level (2 2); + faceZone block; + faceType internal; + //addBufferLayers true; + } + } + + resolveFeatureAngle 180; + + + // Region-wise refinement + // ~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies refinement level for cells in relation to a surface. One of + // three modes + // - distance. 'levels' specifies per distance to the surface the + // wanted refinement level. The distances need to be specified in + // descending order. + // - inside. 'levels' is only one entry and only the level is used. All + // cells inside the surface get refined up to the level. The surface + // needs to be closed for this to be possible. + // - outside. Same but cells outside. + + refinementRegions + { + } + + + // Mesh selection + // ~~~~~~~~~~~~~~ + + // After refinement patches get added for all refinementSurfaces and + // all cells intersecting the surfaces get put into these patches. The + // section reachable from the locationInMesh is kept. + // NOTE: This point should never be on a face, always inside a cell, even + // after refinement. + // This is an outside point locationInMesh (-0.033 -0.033 0.0033); + locationInMesh (0.00013 0.00013 0.00013); // Inside point + + // Whether any faceZones (as specified in the refinementSurfaces) + // are only on the boundary of corresponding cellZones or also allow + // free-standing zone faces. Not used if there are no faceZones. + allowFreeStandingZoneFaces false; + + nCellZoneErodeIter -1; +} + + + +// Internal macro for mesh-motion solver to use +_meshMotionSolver +{ + solver displacementPointSmoothing; + displacementPointSmoothingCoeffs + { + //// Use geometricElementTransform to maintain relative sizes + //pointSmoother geometricElementTransform; + //transformationParameter 0.667; + //nPointSmootherIter 10; + + // Use laplacian to untangle problem areas + pointSmoother laplacian; + nPointSmootherIter 10; + + //relaxationFactors (1.0 0.8 0.6 0.4 0.2 0.0); + //meshQuality + //{ + // #includeEtc "caseDicts/meshQualityDict" + //} + } +} + + +// Settings for the snapping. +snapControls +{ + //- Number of patch smoothing iterations before finding correspondence + // to surface + nSmoothPatch 3; + + //- Relative distance for points to be attracted by surface feature point + // or edge. True distance is this factor times local + // maximum edge length. + tolerance 1.0; + + //- When to split face with diagonal attraction: + // 0 : only if perfect alignment (angle = 0) with feature itself + // 180 : always + concaveAngle 180; + + //- When to split distorted face: not split if areas would differ too + // much (ideal is equal size i.e. area-ratio 1). -1 : disable check + minAreaRatio -1; + + //- Number of mesh displacement relaxation iterations. + nSolveIter 300; + + //- Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + // Feature snapping + + //- Number of feature edge snapping iterations. + // Leave out altogether to disable. + nFeatureSnapIter 10; + + //- Detect (geometric) features by sampling the surface + implicitFeatureSnap true; + + //- Use castellatedMeshControls::features + explicitFeatureSnap true; + + //- Detect features between multiple surfaces + // (only for explicitFeatureSnap, default = false) + multiRegionFeatureSnap true; + + + // Motion solver to use + ${_meshMotionSolver} +} + + + +// Settings for the layer addition. +addLayersControls +{ + // Are the thickness parameters below relative to the undistorted + // size of the refined cell outside layer (true) or absolute sizes (false). + relativeSizes true; + + // Per final patch (so not geometry!) the layer information + layers + { + "block_.*" + { + nSurfaceLayers 1; + } + } + + // Expansion factor for layer mesh + expansionRatio 1.0; + + + // Wanted thickness of final added cell layer. If multiple layers + // is the thickness of the layer furthest away from the wall. + // Relative to undistorted size of cell outside layer. + // See relativeSizes parameter. + finalLayerThickness 0.5; + + // Minimum thickness of cell layer. If for any reason layer + // cannot be above minThickness do not add layer. + // See relativeSizes parameter. + minThickness 0.1; + + // If points get not extruded do nGrow layers of connected faces that are + // also not grown. This helps convergence of the layer addition process + // close to features. + nGrow 0; + + + // Advanced settings + + // When not to extrude surface. 0 is flat surface, 90 is when two faces + // are perpendicular + featureAngle 30; + + // Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + // Number of smoothing iterations of surface normals + nSmoothSurfaceNormals 1; + + // Number of smoothing iterations of interior mesh movement direction + nSmoothNormals 3; + + // Smooth layer thickness over surface patches + nSmoothThickness 10; + + // Stop layer growth on highly warped cells + maxFaceThicknessRatio 0.5; + + // Reduce layer growth where ratio thickness to medial + // distance is large + maxThicknessToMedialRatio 0.3; + + // Angle used to pick up medial axis points + minMedialAxisAngle 90; + + // Create buffer region for new layer terminations + nBufferCellsNoExtrude 0; + + + + //- Use displacementMotionSolver to shrink mesh + meshShrinker displacementMotionSolver; + + // Motion solver to use + ${_meshMotionSolver} + + + // Overall max number of layer addition iterations. The mesher will exit + // if it reaches this number of iterations; possibly with an illegal + // mesh. + nLayerIter 50; + + // Max number of iterations after which relaxed meshQuality controls + // get used. Up to nRelaxIter it uses the settings in meshQualityControls, + // after nRelaxIter it uses the values in meshQualityControls::relaxed. + nRelaxedIter 20; +} + + + +// Generic mesh quality settings. At any undoable phase these determine +// where to undo. +meshQualityControls +{ + #include "meshQualityDict" + + // Optional : some meshing phases allow usage of relaxed rules. + // See e.g. addLayersControls::nRelaxedIter. + relaxed + { + //- Maximum non-orthogonality allowed. Set to 180 to disable. + maxNonOrtho 75; + } + + // Advanced + + //- Number of error distribution iterations + nSmoothScale 4; + //- Amount to scale back displacement at error points + errorReduction 0.75; +} + + +// Advanced + +// Write flags +writeFlags +( +// scalarLevels // write volScalarField with cellLevel for postprocessing +// layerSets // write cellSets, faceSets of faces in layer +// layerFields // write volScalarField for layer coverage +); + +//debugFlags +//( +// mesh +// attraction +//); + +// Merge tolerance. Is fraction of overall bounding box of initial mesh. +// Note: the write tolerance needs to be higher than this. +mergeTolerance 1E-6; + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/rotated_block/system/surfaceFeatureExtractDict b/tutorials/mesh/snappyHexMesh/rotated_block/system/surfaceFeatureExtractDict new file mode 100644 index 0000000000000000000000000000000000000000..603b48fb73cee64cda011c4b214c37cd7b59d4a2 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/rotated_block/system/surfaceFeatureExtractDict @@ -0,0 +1,35 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object surfaceFeatureExtractDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +block.obj +{ + // How to obtain raw features (extractFromFile || extractFromSurface) + extractionMethod extractFromSurface; + + // Mark edges whose adjacent surface normals are at an angle less + // than includedAngle as features + // - 0 : selects no edges + // - 180: selects all edges + includedAngle 150; + + // Write options + + // Write features to obj format for postprocessing + writeObj yes; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/Allclean b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..f158c3703aafa62a5c0b40356ebfd4fcc74b0460 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/Allclean @@ -0,0 +1,9 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +cleanCase0 +rm -f *.obj + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/Allrun b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..9b1617bc41a2469f79ee6fffc5b7c9be46c53bc1 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/Allrun @@ -0,0 +1,12 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + +runApplication blockMesh + +runApplication snappyHexMesh + +runApplication checkMesh -writeFields '(nonOrthoAngle)' + +#------------------------------------------------------------------------------ diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/README.txt b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..98188ecdffa4ae577d3af548b41da33ae27d6535 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/README.txt @@ -0,0 +1,2 @@ +- sphere with inside and outside meshed +- demonstrates buffer layers diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/constant/dynamicMeshDict b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..fdf87f68acae84535f75c22673ea84691e3681b8 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/constant/dynamicMeshDict @@ -0,0 +1,41 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicMotionSolverFvMesh; + +solver displacementPointSmoothing; + +displacementPointSmoothingCoeffs +{ + //// Use geometricElementTransform to maintain relative sizes + //pointSmoother geometricElementTransform; + //transformationParameter 0.667; + //nPointSmootherIter 10; + + // Use laplacian to untangle problem areas + pointSmoother laplacian; + nPointSmootherIter 100; + + //relaxationFactors (1.0 0.8 0.6 0.4 0.2 0.0); + //meshQuality + //{ + // #includeEtc "caseDicts/meshQualityDict" + //} +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/constant/transportProperties b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/constant/transportProperties new file mode 100644 index 0000000000000000000000000000000000000000..fc05a376222c9ce0fd94d4e4134855e949ee5d28 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/constant/transportProperties @@ -0,0 +1,21 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object transportProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +nu 0.01; + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/blockMeshDict b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/blockMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..154b6ad584b0c2103a91b54246242eb399d9d932 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/blockMeshDict @@ -0,0 +1,96 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +scale 1; + +vertices +( + (-1 -1 -1) + ( 1 -1 -1) + ( 1 1 -1) + (-1 1 -1) + (-1 -1 1) + ( 1 -1 1) + ( 1 1 1) + (-1 1 1) +); + +blocks +( + hex (0 1 2 3 4 5 6 7) (20 20 20) simpleGrading (1 1 1) +); + +edges +( +); + +boundary +( + minX + { + type wall; + faces + ( + (0 4 7 3) + ); + } + maxX + { + type wall; + faces + ( + (2 6 5 1) + ); + } + + + minY + { + type wall; + faces + ( + (1 5 4 0) + ); + } + maxY + { + type wall; + faces + ( + (3 7 6 2) + ); + } + + + minZ + { + type wall; + faces + ( + (0 3 2 1) + ); + } + maxZ + { + type wall; + faces + ( + (4 5 6 7) + ); + } +); + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/controlDict b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..b5e76eec7a348962a1ed39dbee640b02d7c42308 --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/controlDict @@ -0,0 +1,49 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +application snappyHexMesh; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 30; + +deltaT 1; + +writeControl timeStep; + +writeInterval 1; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 16; + +writeCompression off; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable true; + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/decomposeParDict b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/decomposeParDict new file mode 100644 index 0000000000000000000000000000000000000000..1aa9426aaec602bb2e572903b579b36889356d1e --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/decomposeParDict @@ -0,0 +1,30 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1806 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + note "mesh decomposition control dictionary"; + object decomposeParDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +////- The total number of domains (mandatory) +//numberOfSubdomains 2; +// +////- The decomposition method (mandatory) +//method random; + +//- The total number of domains (mandatory) +numberOfSubdomains 11; + +//- The decomposition method (mandatory) +method scotch; + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/fvSchemes b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..58d3cb94a88175bb2fdf1549a860411c3a2411eb --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/fvSchemes @@ -0,0 +1,59 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//geometry +//{ +// type highAspectRatio; +// minAspect 0; +// maxAspect 0; +//} + + +ddtSchemes +{ + default Euler; +} + +gradSchemes +{ + default Gauss linear; + grad(p) Gauss linear; +} + +divSchemes +{ + default none; + div(phi,U) Gauss linear; +} + +laplacianSchemes +{ + default Gauss linear corrected; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default corrected; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/fvSolution b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..16f43147ae24c76b5860a3db8f8ee46517c3e10c --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/fvSolution @@ -0,0 +1,57 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solvers +{ + p + { + solver PCG; + preconditioner DIC; + tolerance 1e-06; + relTol 0.05; + } + + pFinal + { + $p; + relTol 0; + } + + U + { + solver smoothSolver; + smoother symGaussSeidel; + tolerance 1e-05; + relTol 0; + } + + cellDisplacement + { + $pFinal; + } +} + +PISO +{ + nCorrectors 2; + nNonOrthogonalCorrectors 0; + pRefCell 0; + pRefValue 0; +} + + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/meshQualityDict b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/meshQualityDict new file mode 100644 index 0000000000000000000000000000000000000000..1a0afa5f754e90e763ba4fee639cdef03495e87f --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/meshQualityDict @@ -0,0 +1,32 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object meshQualityDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Include defaults parameters from master dictionary +#includeEtc "caseDicts/meshQualityDict" + +//maxNonOrtho 180; +//maxConcave 180; +//minVol -1e30; +maxBoundarySkewness -1; +maxInternalSkewness -1; +//minTetQuality -1e30; +//minDeterminant -1e30; +//minTwist -1; +//minFaceWeight -1; +//minVolRatio -1; +//minDeterminant -1; + +// ************************************************************************* // diff --git a/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/snappyHexMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..c6ceef408c60a102630e7fc3806c1a83a0a95cbc --- /dev/null +++ b/tutorials/mesh/snappyHexMesh/sphere_multiRegion/system/snappyHexMeshDict @@ -0,0 +1,380 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2312 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object snappyHexMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Type of mesh generation: +// - castellated (default) +// - castellatedBufferLayer (adds single layer of cells before snapping) +type castellatedBufferLayer; + +// Which of the steps to run +castellatedMesh true; +snap true; +addLayers true; + + +// Geometry. Definition of all surfaces. All surfaces are of class +// searchableSurface. +// Surfaces are used +// - to specify refinement for any mesh cell intersecting it +// - to specify refinement for any mesh cell inside/outside/near +// - to 'snap' the mesh boundary to the surface +geometry +{ + sphere + { + type sphere; + origin (0.0 0 0); + radius 0.5; + } + + outside + { + type box; + min (-0.91 -0.91 -0.91); + max ( 0.91 0.91 0.91); + } +} + + +// Settings for the castellatedMesh generation. +castellatedMeshControls +{ + + // Refinement parameters + // ~~~~~~~~~~~~~~~~~~~~~ + + // If local number of cells is >= maxLocalCells on any processor + // switches from from refinement followed by balancing + // (current method) to (weighted) balancing before refinement. + maxLocalCells 100000; + + // Overall cell limit (approximately). Refinement will stop immediately + // upon reaching this number so a refinement level might not complete. + // Note that this is the number of cells before removing the part which + // is not 'visible' from the keepPoint. The final number of cells might + // actually be a lot less. + maxGlobalCells 2000000; + + // The surface refinement loop might spend lots of iterations refining just a + // few cells. This setting will cause refinement to stop if <= minimumRefine + // are selected for refinement. Note: it will at least do one iteration + // (unless the number of cells to refine is 0) + minRefinementCells 0; + + // Number of buffer layers between different levels. + // 1 means normal 2:1 refinement restriction, larger means slower + // refinement. + nCellsBetweenLevels 1; + + + + // Explicit feature edge refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies a level for any cell intersected by its edges. + // This is a featureEdgeMesh, read from constant/triSurface for now. + features + ( + ); + + + + // Surface based refinement + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies two levels for every surface. The first is the minimum level, + // every cell intersecting a surface gets refined up to the minimum level. + // The second level is the maximum level. Cells that 'see' multiple + // intersections where the intersections make an + // angle > resolveFeatureAngle get refined up to the maximum level. + + refinementSurfaces + { + sphere + { + // Surface-wise min and max refinement level + level (1 1); + addBufferLayers true; + } + outside + { + // Surface-wise min and max refinement level + level (1 1); + // Disable buffer layers + addBufferLayers false; + } + } + + resolveFeatureAngle 180; + + + // Region-wise refinement + // ~~~~~~~~~~~~~~~~~~~~~~ + + // Specifies refinement level for cells in relation to a surface. One of + // three modes + // - distance. 'levels' specifies per distance to the surface the + // wanted refinement level. The distances need to be specified in + // descending order. + // - inside. 'levels' is only one entry and only the level is used. All + // cells inside the surface get refined up to the level. The surface + // needs to be closed for this to be possible. + // - outside. Same but cells outside. + + refinementRegions + { + } + + + // Mesh selection + // ~~~~~~~~~~~~~~ + + // After refinement patches get added for all refinementSurfaces and + // all cells intersecting the surfaces get put into these patches. The + // section reachable from the locationInMesh is kept. + // NOTE: This point should never be on a face, always inside a cell, even + // after refinement. + // This is an outside point locationInMesh (-0.033 -0.033 0.0033); + locationsInMesh + ( + (( 0.001 0.001 0.001) sphere) + (( 0.701 0.701 0.701) outside) + ); + + // Whether any faceZones (as specified in the refinementSurfaces) + // are only on the boundary of corresponding cellZones or also allow + // free-standing zone faces. Not used if there are no faceZones. + allowFreeStandingZoneFaces false; +} + + + +// Internal macro for mesh-motion solver to use +_meshMotionSolver +{ + solver displacementPointSmoothing; + displacementPointSmoothingCoeffs + { + //// Use geometricElementTransform to maintain relative sizes + //pointSmoother geometricElementTransform; + //transformationParameter 0.667; + //nPointSmootherIter 10; + + // Use laplacian to untangle problem areas + pointSmoother laplacian; + nPointSmootherIter 10; + + //relaxationFactors (1.0 0.8 0.6 0.4 0.2 0.0); + //meshQuality + //{ + // #includeEtc "caseDicts/meshQualityDict" + //} + } +} + + +// Settings for the snapping. +snapControls +{ + //- Number of patch smoothing iterations before finding correspondence + // to surface + nSmoothPatch 3; + + //- Relative distance for points to be attracted by surface feature point + // or edge. True distance is this factor times local + // maximum edge length. + tolerance 1.0; + + //- When to split face with diagonal attraction: + // 0 : only if perfect alignment (angle = 0) with feature itself + // 180 : always + concaveAngle 180; + + //- When to split distorted face: not split if areas would differ too + // much (ideal is equal size i.e. area-ratio 1). -1 : disable check + minAreaRatio -1; + + //- Number of mesh displacement relaxation iterations. + nSolveIter 10; + + //- Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + // Feature snapping + + //- Number of feature edge snapping iterations. + // Leave out altogether to disable. + nFeatureSnapIter 10; + + //- Detect (geometric) features by sampling the surface + implicitFeatureSnap true; + + //- Use castellatedMeshControls::features + explicitFeatureSnap true; + + //- Detect features between multiple surfaces + // (only for explicitFeatureSnap, default = false) + multiRegionFeatureSnap true; + + + // Motion solver to use + ${_meshMotionSolver} +} + + +// Settings for the layer addition. +addLayersControls +{ + // Are the thickness parameters below relative to the undistorted + // size of the refined cell outside layer (true) or absolute sizes (false). + relativeSizes true; + + // Per final patch (so not geometry!) the layer information + layers + { + "(sphere_to_outside|outside_to_sphere)" + { + nSurfaceLayers 3; + } + } + + // Expansion factor for layer mesh + expansionRatio 1.4; + + + // Wanted thickness of final added cell layer. If multiple layers + // is the thickness of the layer furthest away from the wall. + // Relative to undistorted size of cell outside layer. + // See relativeSizes parameter. + finalLayerThickness 0.5; + + // Minimum thickness of cell layer. If for any reason layer + // cannot be above minThickness do not add layer. + // See relativeSizes parameter. + minThickness 0.01; + + // If points get not extruded do nGrow layers of connected faces that are + // also not grown. This helps convergence of the layer addition process + // close to features. + nGrow 0; + + + // Advanced settings + + // When not to extrude surface. 0 is flat surface, 90 is when two faces + // are perpendicular + featureAngle 30; + + // Maximum number of snapping relaxation iterations. Should stop + // before upon reaching a correct mesh. + nRelaxIter 5; + + // Number of smoothing iterations of surface normals + nSmoothSurfaceNormals 1; + + // Number of smoothing iterations of interior mesh movement direction + nSmoothNormals 3; + + // Smooth layer thickness over surface patches + nSmoothThickness 10; + + // Stop layer growth on highly warped cells + maxFaceThicknessRatio 0.5; + + // Reduce layer growth where ratio thickness to medial + // distance is large + maxThicknessToMedialRatio 0.3; + + // Angle used to pick up medial axis points + minMedialAxisAngle 90; + + // Create buffer region for new layer terminations + nBufferCellsNoExtrude 0; + + + + //- Use displacementMotionSolver to shrink mesh + meshShrinker displacementMotionSolver; + + // Motion solver to use + ${_meshMotionSolver} + // Do some more iterations since shrinking is over a larger distance. + // Note: laplacian smoothing does destroy the cell sizing - maybe use + // the geometricElementTransform smoother instead. + displacementPointSmoothingCoeffs + { + nPointSmootherIter 100; + } + + // Overall max number of layer addition iterations. The mesher will exit + // if it reaches this number of iterations; possibly with an illegal + // mesh. + nLayerIter 50; + + // Max number of iterations after which relaxed meshQuality controls + // get used. Up to nRelaxIter it uses the settings in meshQualityControls, + // after nRelaxIter it uses the values in meshQualityControls::relaxed. + nRelaxedIter 20; +} + + + +// Generic mesh quality settings. At any undoable phase these determine +// where to undo. +meshQualityControls +{ + #include "meshQualityDict" + + // Optional : some meshing phases allow usage of relaxed rules. + // See e.g. addLayersControls::nRelaxedIter. + relaxed + { + //- Maximum non-orthogonality allowed. Set to 180 to disable. + maxNonOrtho 75; + } + + // Advanced + + //- Number of error distribution iterations + nSmoothScale 4; + //- Amount to scale back displacement at error points + errorReduction 0.75; +} + + +// Advanced + +// Write flags +writeFlags +( +// scalarLevels // write volScalarField with cellLevel for postprocessing +// layerSets // write cellSets, faceSets of faces in layer +// layerFields // write volScalarField for layer coverage +); + +debugFlags +( +// mesh +// attraction +); + +// Merge tolerance. Is fraction of overall bounding box of initial mesh. +// Note: the write tolerance needs to be higher than this. +mergeTolerance 1E-6; + + +// ************************************************************************* //