From 95cea012a966e0a783a0ccbf8f4681cdac80eda1 Mon Sep 17 00:00:00 2001 From: Peter Munch Date: Sat, 6 Mar 2021 22:56:12 +0100 Subject: [PATCH] GridOut::write_mesh_per_processor_as_vtu() for simplex --- source/base/data_out_base.cc | 119 +++++--- source/grid/grid_out.cc | 11 +- .../write_mesh_per_processor_as_vtu_01.cc | 105 +++++++ ...01.mpirun=3.with_simplex_support=on.output | 278 ++++++++++++++++++ 4 files changed, 466 insertions(+), 47 deletions(-) create mode 100644 tests/simplex/write_mesh_per_processor_as_vtu_01.cc create mode 100644 tests/simplex/write_mesh_per_processor_as_vtu_01.mpirun=3.with_simplex_support=on.output diff --git a/source/base/data_out_base.cc b/source/base/data_out_base.cc index e9cdbe4b2e..860b01c470 100644 --- a/source/base/data_out_base.cc +++ b/source/base/data_out_base.cc @@ -697,14 +697,14 @@ namespace //----------------------------------------------------------------------// // For a given patch, compute the node interpolating the corner nodes linearly // at the point (xstep, ystep, zstep)*1./n_subdivisions. If the points are - // saved in the patch.data member, return the saved point instead + // saved in the patch.data member, return the saved point instead. template inline Point - compute_node(const DataOutBase::Patch &patch, - const unsigned int xstep, - const unsigned int ystep, - const unsigned int zstep, - const unsigned int n_subdivisions) + compute_hypercube_node(const DataOutBase::Patch &patch, + const unsigned int xstep, + const unsigned int ystep, + const unsigned int zstep, + const unsigned int n_subdivisions) { Point node; if (patch.points_are_available) @@ -771,6 +771,36 @@ namespace return node; } + // For a given patch, compute the nodes for arbitrary (non-hypercube) cells. + // If the points are saved in the patch.data member, return the saved point + // instead. + template + inline Point + compute_arbitrary_node(const DataOutBase::Patch &patch, + const unsigned int point_no) + { + Point node; + + if (patch.points_are_available) + { + for (unsigned int d = 0; d < spacedim; ++d) + node[d] = patch.data(patch.data.size(0) - spacedim + d, point_no); + return node; + } + else + { + AssertDimension(patch.n_subdivisions, 1); + Assert( + patch.reference_cell != ReferenceCells::Pyramid, + ExcMessage( + "Pyramids need different ordering of the vertices, which is not implemented yet here.")); + + node = patch.vertices[point_no]; + } + + return node; + } + /** * Given (i,j,k) coordinates within the Lagrange quadrilateral, return an * offset into the local connectivity array. @@ -2626,22 +2656,12 @@ namespace DataOutBase for (const auto &patch : patches) { - // special treatment of simplices since they are not subdivided, such - // that no new nodes have to be created, but the precomputed ones can be - // used + // special treatment of non-hypercube cells if (patch.reference_cell != ReferenceCells::get_hypercube()) { - Point node; - for (unsigned int point_no = 0; point_no < patch.data.n_cols(); ++point_no) - { - for (unsigned int d = 0; d < spacedim; ++d) - node[d] = - patch.data(patch.data.size(0) - spacedim + d, point_no); - - out.write_point(count++, node); - } + out.write_point(count++, compute_arbitrary_node(patch, point_no)); } else { @@ -2657,7 +2677,8 @@ namespace DataOutBase for (unsigned int i2 = 0; i2 < n2; ++i2) for (unsigned int i1 = 0; i1 < n1; ++i1) out.write_point( - count++, compute_node(patch, i1, i2, i3, n_subdivisions)); + count++, + compute_hypercube_node(patch, i1, i2, i3, n_subdivisions)); } } out.flush_points(); @@ -3585,7 +3606,8 @@ namespace DataOutBase for (unsigned int i1 = 0; i1 < n1; ++i1) { // compute coordinates for this patch point - out << compute_node(patch, i1, i2, 0, n_subdivisions) + out << compute_hypercube_node( + patch, i1, i2, 0, n_subdivisions) << ' '; for (unsigned int data_set = 0; data_set < n_data_sets; @@ -3612,7 +3634,7 @@ namespace DataOutBase { // compute coordinates for this patch point this_point = - compute_node(patch, i1, i2, i3, n_subdivisions); + compute_hypercube_node(patch, i1, i2, i3, n_subdivisions); // line into positive x-direction if possible if (i1 < n_subdivisions) { @@ -3626,7 +3648,7 @@ namespace DataOutBase out << '\n'; // write point there and its data - out << compute_node( + out << compute_hypercube_node( patch, i1 + 1, i2, i3, n_subdivisions); for (unsigned int data_set = 0; data_set < n_data_sets; @@ -3653,7 +3675,7 @@ namespace DataOutBase out << '\n'; // write point there and its data - out << compute_node( + out << compute_hypercube_node( patch, i1, i2 + 1, i3, n_subdivisions); for (unsigned int data_set = 0; data_set < n_data_sets; @@ -3680,7 +3702,7 @@ namespace DataOutBase out << '\n'; // write point there and its data - out << compute_node( + out << compute_hypercube_node( patch, i1, i2, i3 + 1, n_subdivisions); for (unsigned int data_set = 0; data_set < n_data_sets; @@ -3866,7 +3888,7 @@ namespace DataOutBase { // compute coordinates for this patch point, storing in ver ver[i1 * d1 + i2 * d2] = - compute_node(patch, i1, i2, 0, n_subdivisions); + compute_hypercube_node(patch, i1, i2, 0, n_subdivisions); } @@ -4108,11 +4130,14 @@ namespace DataOutBase for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1) { Point points[4]; - points[0] = compute_node(patch, i1, i2, 0, n_subdivisions); - points[1] = compute_node(patch, i1 + 1, i2, 0, n_subdivisions); - points[2] = compute_node(patch, i1, i2 + 1, 0, n_subdivisions); - points[3] = - compute_node(patch, i1 + 1, i2 + 1, 0, n_subdivisions); + points[0] = + compute_hypercube_node(patch, i1, i2, 0, n_subdivisions); + points[1] = + compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions); + points[2] = + compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions); + points[3] = compute_hypercube_node( + patch, i1 + 1, i2 + 1, 0, n_subdivisions); switch (spacedim) { @@ -6058,7 +6083,8 @@ namespace DataOutBase Point<2> projection_decomposition; std::array, 4> projection_decompositions; - projected_point = compute_node(first_patch, 0, 0, 0, n_subdivisions); + projected_point = + compute_hypercube_node(first_patch, 0, 0, 0, n_subdivisions); if (first_patch.data.n_rows() != 0) { @@ -6085,13 +6111,13 @@ namespace DataOutBase for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1) { projected_points[0] = - compute_node(patch, i1, i2, 0, n_subdivisions); + compute_hypercube_node(patch, i1, i2, 0, n_subdivisions); projected_points[1] = - compute_node(patch, i1 + 1, i2, 0, n_subdivisions); + compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions); projected_points[2] = - compute_node(patch, i1, i2 + 1, 0, n_subdivisions); - projected_points[3] = - compute_node(patch, i1 + 1, i2 + 1, 0, n_subdivisions); + compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions); + projected_points[3] = compute_hypercube_node( + patch, i1 + 1, i2 + 1, 0, n_subdivisions); x_min = std::min(x_min, projected_points[0][0]); x_min = std::min(x_min, projected_points[1][0]); @@ -6266,7 +6292,8 @@ namespace DataOutBase Point<3> point; - projected_point = compute_node(first_patch, 0, 0, 0, n_subdivisions); + projected_point = + compute_hypercube_node(first_patch, 0, 0, 0, n_subdivisions); if (first_patch.data.n_rows() != 0) { @@ -6299,10 +6326,11 @@ namespace DataOutBase for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1) { const std::array, 4> projected_vertices{ - {compute_node(patch, i1, i2, 0, n_subdivisions), - compute_node(patch, i1 + 1, i2, 0, n_subdivisions), - compute_node(patch, i1, i2 + 1, 0, n_subdivisions), - compute_node(patch, i1 + 1, i2 + 1, 0, n_subdivisions)}}; + {compute_hypercube_node(patch, i1, i2, 0, n_subdivisions), + compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions), + compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions), + compute_hypercube_node( + patch, i1 + 1, i2 + 1, 0, n_subdivisions)}}; Assert((flags.height_vector < patch.data.n_rows()) || patch.data.n_rows() == 0, @@ -6440,10 +6468,11 @@ namespace DataOutBase for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1) { const std::array, 4> projected_vertices = { - {compute_node(patch, i1, i2, 0, n_subdivisions), - compute_node(patch, i1 + 1, i2, 0, n_subdivisions), - compute_node(patch, i1, i2 + 1, 0, n_subdivisions), - compute_node(patch, i1 + 1, i2 + 1, 0, n_subdivisions)}}; + {compute_hypercube_node(patch, i1, i2, 0, n_subdivisions), + compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions), + compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions), + compute_hypercube_node( + patch, i1 + 1, i2 + 1, 0, n_subdivisions)}}; Assert((flags.height_vector < patch.data.n_rows()) || patch.data.n_rows() == 0, diff --git a/source/grid/grid_out.cc b/source/grid/grid_out.cc index b2edc78eb1..d182011905 100644 --- a/source/grid/grid_out.cc +++ b/source/grid/grid_out.cc @@ -3649,7 +3649,13 @@ GridOut::write_mesh_per_processor_as_vtu( data_names.emplace_back("level_subdomain"); data_names.emplace_back("proc_writing"); - const unsigned int n_q_points = GeometryInfo::vertices_per_cell; + const auto reference_cells = tria.get_reference_cells(); + + AssertDimension(reference_cells.size(), 1); + + const auto &reference_cell = reference_cells[0]; + + const unsigned int n_q_points = reference_cell.n_vertices(); for (const auto &cell : tria.cell_iterators()) { @@ -3676,6 +3682,7 @@ GridOut::write_mesh_per_processor_as_vtu( DataOutBase::Patch patch; patch.data.reinit(n_datasets, n_q_points); patch.points_are_available = false; + patch.reference_cell = reference_cell; for (unsigned int vertex = 0; vertex < n_q_points; ++vertex) { @@ -3693,7 +3700,7 @@ GridOut::write_mesh_per_processor_as_vtu( patch.data(3, vertex) = tria.locally_owned_subdomain(); } - for (auto f : GeometryInfo::face_indices()) + for (auto f : reference_cell.face_indices()) patch.neighbors[f] = numbers::invalid_unsigned_int; patches.push_back(patch); } diff --git a/tests/simplex/write_mesh_per_processor_as_vtu_01.cc b/tests/simplex/write_mesh_per_processor_as_vtu_01.cc new file mode 100644 index 0000000000..d8babf8539 --- /dev/null +++ b/tests/simplex/write_mesh_per_processor_as_vtu_01.cc @@ -0,0 +1,105 @@ +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + + + +// check GriOut::write_mesh_per_processor_as_vtu() + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include "../tests.h" + + +template +void +output(const Triangulation &tr, + const std::string & filename, + const bool view_levels, + const bool include_artificial) +{ + GridOut out; + out.write_mesh_per_processor_as_vtu(tr, + filename, + view_levels, + include_artificial); + + // copy the .pvtu and .vtu files + // into the logstream + int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + if (myid == 0) + { + cat_file((std::string(filename) + ".pvtu").c_str()); + cat_file((std::string(filename) + ".proc0000.vtu").c_str()); + } + else if (myid == 1) + cat_file((std::string(filename) + ".proc0001.vtu").c_str()); + else if (myid == 2) + cat_file((std::string(filename) + ".proc0002.vtu").c_str()); + else + AssertThrow(false, ExcNotImplemented()); +} + +template +void +test() +{ + unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + if (myid == 0) + deallog << "hyper_cube" << std::endl; + + + parallel::shared::Triangulation triangulation( + MPI_COMM_WORLD, + ::Triangulation::none, + true, + parallel::shared::Triangulation::Settings::partition_zorder); + + Triangulation temp; + GridGenerator::hyper_cube(temp); + GridGenerator::convert_hypercube_to_simplex_mesh(temp, triangulation); + + triangulation.refine_global(2); + + DoFHandler dofh(triangulation); + + output(triangulation, "file1", false, true); + output(triangulation, "file2", true, false); +} + + +int +main(int argc, char *argv[]) +{ + Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); + + MPILogInitAll init; + + deallog.push("2d"); + test<2>(); + deallog.pop(); +} diff --git a/tests/simplex/write_mesh_per_processor_as_vtu_01.mpirun=3.with_simplex_support=on.output b/tests/simplex/write_mesh_per_processor_as_vtu_01.mpirun=3.with_simplex_support=on.output new file mode 100644 index 0000000000..940ebda3a2 --- /dev/null +++ b/tests/simplex/write_mesh_per_processor_as_vtu_01.mpirun=3.with_simplex_support=on.output @@ -0,0 +1,278 @@ + +DEAL:0:2d::hyper_cube + + + + + + + + + + + + + + + + + + + + + + + + +AQAAAAASAAAAEgAABgIAAA==eNqNltFtAzEMQz2KJnE0ikfRaDda0aJAGIYvuX6lDEnzKCG+tV7+9sr/Cz7bvt/AT5obWvW/3GO/4+th/A18wSf4kNbzx3yCq/8vfgE/PsMN7UAnC/J7nkkz2sE3+Eft45n/L+PjiV/7HZ/9yr925is+wYe06r/sXO1f90b56pPm5X1+1Vr+0d4C/rafwH/B17sPaQc6uSC/55nA9+eanf0H5pt2pgBX/wK+4v3Bn85KMyrAtf8CvuL9wT9pNX9L5gO4+h/gKz4f/JPW+6dZTMjT0H/DvOqGdqT/kQ4P4GP9JP6xeaE/nDVylnaY8IG5HJhjf/BPWs3fvm8Bb9jbgj1fn/yD1vunWdD+pP4b5nVuaH2Hjt7FCdczNvAFn83+dFZ71/+ciNv9FfmCz2b/pNX8I5kvwNX/Ar7if78n4J+03j/NokOe2bn/oXnd0Pr9VfAuVPJZ+0n8y+ZF/nRWy2ftMOHav3ee5jib/ZPW3zcK3s3ifgL/BV/sH7XWP82C9qdgRgXvt9+0y+67NOuyO1r5Bfy0b3VD23Yf6bkVcL+/CviK9yO/kySt50+7p3gb/wA/7X/d0DZ0UpC/IX+ZtsPzNnBUO5L/6G+pZFa8jX+Ar3gHH9K29annnoB7/wf4B/r8pvX8LXgF3PezgF+w/9+0DZ0cyN+Q/5i2w/M2cJ7aH7k+iCA= + + + + + +AQAAAAAGAAAABgAARwIAAA==eNol02O7HgQAANB3xp1tm3e272zbtm3VbNRWs70aa0bNZs22VeN5nn04P+EEAoFAKEIThrCEIzwRiEgkIhNEFKISjejEICaxiE0c4hKP+CQgIYlITBKSkozkpCAlqUhNGtKSjvRkICOZyEwWspKN7ASTg5zkIjd5yEs+8lOAghSiMEUoSjGKU4KSlCKE0pShLOUoTwUqUonKVKEq1ahODWpSi9rUoS71qE8DGtKIxjShKc1oTgta0orWtKEt7WhPBzrSic50oSvd6E4PetKL3vShL/3ozwAGMojBDGEowxjOCEYyitH8wI+MYSzjGM8EJjKJyUxhKtOYzgxmMovZ/MTPzGEuv/Ar85jPAhayiMUsYSnLWM4KVrKK1axhLetYzwY28hu/s4nNbGEr29jOH/zJDnayi93sYS/72M8BDvIXf3OIwxzhKMc4zglOcorTnOEs5zjPBS5yicv8w79c4SrXuM4NbnKL29zhLve4zwMe8ojHPOEpz3jOC17yite84S3veM8H/uN/PvKJz3zha+B7/lCEJgxhCUd4IhCRSEQmiChEJRrRiUFMYhGbOMQlHvFJQEISkZgkJCUZyUlBSlKRmjSkJR3pyUBGMpGZLGQlG9kJJgc5yUVu8pCXfOSnAAUpRGGKUJRiFKcEJSlFCKUpQ1nKUZ4KVKQSlalCVapRnRrUpBa1qUNd6lGfBjSkEY1pQlOa0ZwWtKQVrWlDW9rRng50pBOd6UJXutGdHvSkF73pQ1/60Z8BDGQQgxnCUL4Bn7GfwQ== + + +AQAAAAACAAAAAgAA6gAAAA==eNoNwwFEGAEAAMCvlFJKKaWUpimllFJKs5SylFJKKaWUUkoppTSbjRERERERERERETEiIiIiIiIiIiIiou64sCAIIowyxjgTTDLFNDP84ldzzLPAIksss8JvVlljnfU22myr7Xbaba/9DjrsqONOOu2s8/70t3/956JLLrviqmuuu+GmW26746577nvgoUf+99gTTz3z3AsvvfLaG2+9894HH33y2RdfffPdD0NDgiDcSKONNd5Ek0013UyzzDbXfAstttRyK/1utbX+sMEmW2yzwy577HPAIUccc8IpZ5xzwV/+8RPNizXs + + +AQAAAIAAAACAAAAADAAAAA==eNpjZR1YAAChwAKB + + + + +AQAAAAAGAAAABgAAFwAAAA==eNpjYGBwYBjFo3gUj+JRPOIwALbRYAE= + +AQAAAAAGAAAABgAAPwAAAA==eNpjYBgFowAZNNiThhkOkI9JNZ8S9ZS4kxj308J8StxAtfhyQMK4xHGpoZY5DkRgYuyixL+DDVPFnQAUpKrU + +AQAAAAAGAAAABgAAFAAAAA==eNpjYBgFo2AUjIJRMBIBAAYAAAE= + +AQAAAAAGAAAABgAAFAAAAA==eNpjYBgFo2AUjIJRMBIBAAYAAAE= + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +AQAAAKAXAACgFwAAnwIAAA==eNqNWMF1xSAMYxRPQjyKR/FojNZL2ycUCfJvX5Fkx3YCZIzt9wz9/6Frj+A/Gm/A2+Act02sfnQsx9/iCn6TZys+5jX1/w1/9ut4DflKw1yl3e5r0n1NgZM/+sh8KP+b9tWLXzwNjv5p+Ij3wV9pecY2jsDbxE2T5zj4Ky3nlFhPgXO/FB9xnv+8aLlfaWZJ+bOnypOfwbxoB9VfadM8y0l5psH70TOmtE18fCekwNk/DT9N/jft9pvm/zTvqEmaqfEWPk6L/os95hvH52VN8pkab+HjtJy/zG+ad90UMQT+fw8ftG1qMkz+nE+rHh3WkXHTwrwteu7WfOP4bC68R+IvsRasD9rt2ae4WH+535i7j+oX1/Oqpfy397zAX/Np+GPq+b9p29Rkmfw5nxb8dVj310XL68UfHgZH/zB8xPPg72KpHoXBsf5h+IjnwV9peU35y7kMjv5l+Ij3wV9puf6uF27fouqfpl/xQfva82POAm+qj+IX9cv6m1i498MaKrxNX8r0MQ/+Ssv7zG3eBJ5mbsPM+Tj5Cy3X3/XC7nun6ZG43/qg5RkqXIsVjjGm4QPe0/u7WMm1/uVInNYvyQe8p/dXWj4XFKy/Ckf/ZfiI8/6/Llquv+uFOxeU6ZHs1wctr19h9kIhzgJrav6ifjl/FwvPHVhDhWP9ueaqjz29v9LyfiPM3kzOp+Fv+PD+Ukv1d71w8xOmR2H2tzftoPVO9TrMGTZorsLg+eg9ktImrUcYNwTO61cYfohzaH3Qcv5q9sKchYPmvAzewsdp09QkTP5p8g/Suu8McdHi94Si7wkl8CR+GX6JbwX1QZtUT4xbAuf6l+GXqedNy/njN5AQOM9nGH6Y+b9p09SkTP5p8i/Suu9CddT+APxz8CQ= + + + + + +AQAAAOAHAADgBwAA4QIAAA==eNol08MSLAYAALB9tm3btm3btm3btm3btm3brtvM9JBPSCAQCAQhKMEITghCEorQhCEs4QhPBCISichEISrRiE4MYhKL2MQhLvGITwISkojEJCEpyUhOClKSitSkIS3pSE8GMpKJzGQhK9nITg5ykovc5CEv+chPAQpSiMIUoSjFKE4JSlKK0pShLOUoTwUqUonKVKEq1ahODWpSi9rUoS71qE8DGtKIxjShKc1oTgta0orWtKEt7WhPBzrSic50oSvd6E4PetKL3vShL/3ozwAGMojBDGEowxjOCEYyitGMYSzjGM8EJjKJyUxhKtOYzgxmMovZzGEu85jPAhayiMUsYSnLWM4KVrKK1axhLetYzwY2sonNbGEr29jODnayi93sYS/72M8BDnKIwxzhKMc4zglOcorTnOEs5zjPBS5yictc4SrXuM4NbnKL29zhLve4zwMe8ojHPOEpz3jOC17yite84S3veM8HPvKJz3zhK9/4zg9+8ovf+J0/+JO/+Jt/+Dfwf/4gBCUYwQlBSEIRmjCEJRzhiUBEIhGZKEQlGtGJQUxiEZs4xCUe8UlAQhKRmCQkJRnJSUFKUpGaNKQlHenJQEYykZksZCUb2clBTnKRmzzkJR/5KUBBClGYIhSlGMUpQUlKUZoylKUc5alARSpRmSpUpRrVqUFNalGbOtSlHvVpQEMa0ZgmNKUZzWlBS1rRmja0pR3t6UBHOtGZLnSlG93pQU960Zs+9KUf/RnAQAYxmCEMZRjDGcFIRjGaMYxlHOOZwEQmMZkpTGUa05nBTGYxmznMZR7zWcBCFrGYJSxlGctZwUpWsZo1rGUd69nARjaxmS1sZRvb2cFOdrGbPexlH/s5wEEOcZgjHOUYxznBSU5xmjOc5RznucBFLnGZK1zlGte5wU1ucZs73OUe93nAQx7xmCc85RnPecFLXvGaN7zlHe/5wEc+8ZkvfOUb3/nBT37xH/wj+B0= + + +AQAAAKACAACgAgAAMwEAAA==eNoNwwFoCAEAAMCfRUTWRERkTWRZW5a1RUS0ZdE0TVuTNW1NW1tbW1tbExGRRWSRtUWTtbW1RbRlbdFEWxbR1rRlbdFE1rQ1teKuLjQIgmWucJVhrnGdG9zkFiPc5g6jjDbWOONNdJ8HPOQRk03xuCc86SkzPW22Z83znIUWW2q5lVZ73ote9qrXrfWWd6zzvvU2+sjHNttqu50+84Xd9tjna9/4zkGH/OhnR/ziuBNO+d0f/nLGP87710X/uSQkCJa63JWuNty1rnejm91qpNvd6S5j3O0eE9zrfg962CSPesxU00w3wyzPmGOu+RZYZIllVlhljRe85BWvecOb3vau93xggw9t8oktttnhU5/b5Ut7fWW/bx3wvR/85LCjjvnVSb857U9/O+ucC/4HElhTsA== + + +AQAAAKgAAACoAAAADAAAAA==eNpjZR0aAAAV+wNJ + + + + +AQAAAOAHAADgBwAAHgAAAA==eNpjYKA1aLAfxQOJGRxG8SgexaN4FI88DAA1baeh + +AQAAAOAHAADgBwAARgAAAA==eNpjYGjYzzCKhzEeBaMAGTTYk4YZDpCPSTWfEvWUuJMY99PCfErcQLX4ckDCuMRxqaGWOQ5EYGLsosS/gw1TxZ0AWT9Aaw== + +AQAAAOAHAADgBwAAFwAAAA==eNpjYBgFo2AUjIJRMApGwXADAAfgAAE= + +AQAAAOAHAADgBwAAFwAAAA==eNpjYBgFo2AUjIJRMApGwXADAAfgAAE= + + + + + + + + + + + + + +AQAAAAASAAAAEgAABgIAAA==eNqNltFtAzEMQz2KJnE0ikfRaDda0aJAGIYvuX6lDEnzKCG+tV7+9sr/Cz7bvt/AT5obWvW/3GO/4+th/A18wSf4kNbzx3yCq/8vfgE/PsMN7UAnC/J7nkkz2sE3+Eft45n/L+PjiV/7HZ/9yr925is+wYe06r/sXO1f90b56pPm5X1+1Vr+0d4C/rafwH/B17sPaQc6uSC/55nA9+eanf0H5pt2pgBX/wK+4v3Bn85KMyrAtf8CvuL9wT9pNX9L5gO4+h/gKz4f/JPW+6dZTMjT0H/DvOqGdqT/kQ4P4GP9JP6xeaE/nDVylnaY8IG5HJhjf/BPWs3fvm8Bb9jbgj1fn/yD1vunWdD+pP4b5nVuaH2Hjt7FCdczNvAFn83+dFZ71/+ciNv9FfmCz2b/pNX8I5kvwNX/Ar7if78n4J+03j/NokOe2bn/oXnd0Pr9VfAuVPJZ+0n8y+ZF/nRWy2ftMOHav3ee5jib/ZPW3zcK3s3ifgL/BV/sH7XWP82C9qdgRgXvt9+0y+67NOuyO1r5Bfy0b3VD23Yf6bkVcL+/CviK9yO/kySt50+7p3gb/wA/7X/d0DZ0UpC/IX+ZtsPzNnBUO5L/6G+pZFa8jX+Ar3gHH9K29annnoB7/wf4B/r8pvX8LXgF3PezgF+w/9+0DZ0cyN+Q/5i2w/M2cJ7aH7k+iCA= + + + + + +AQAAAAAGAAAABgAARwIAAA==eNol02O7HgQAANB3xp1tm3e272zbtm3VbNRWs70aa0bNZs22VeN5nn04P+EEAoFAKEIThrCEIzwRiEgkIhNEFKISjejEICaxiE0c4hKP+CQgIYlITBKSkozkpCAlqUhNGtKSjvRkICOZyEwWspKN7ASTg5zkIjd5yEs+8lOAghSiMEUoSjGKU4KSlCKE0pShLOUoTwUqUonKVKEq1ahODWpSi9rUoS71qE8DGtKIxjShKc1oTgta0orWtKEt7WhPBzrSic50oSvd6E4PetKL3vShL/3ozwAGMojBDGEowxjOCEYyitH8wI+MYSzjGM8EJjKJyUxhKtOYzgxmMovZ/MTPzGEuv/Ar85jPAhayiMUsYSnLWM4KVrKK1axhLetYzwY28hu/s4nNbGEr29jOH/zJDnayi93sYS/72M8BDvIXf3OIwxzhKMc4zglOcorTnOEs5zjPBS5yicv8w79c4SrXuM4NbnKL29zhLve4zwMe8ojHPOEpz3jOC17yite84S3veM8H/uN/PvKJz3zha+B7/lCEJgxhCUd4IhCRSEQmiChEJRrRiUFMYhGbOMQlHvFJQEISkZgkJCUZyUlBSlKRmjSkJR3pyUBGMpGZLGQlG9kJJgc5yUVu8pCXfOSnAAUpRGGKUJRiFKcEJSlFCKUpQ1nKUZ4KVKQSlalCVapRnRrUpBa1qUNd6lGfBjSkEY1pQlOa0ZwWtKQVrWlDW9rRng50pBOd6UJXutGdHvSkF73pQ1/60Z8BDGQQgxnCUL4Bn7GfwQ== + + +AQAAAAACAAAAAgAA6gAAAA==eNoNwwFEGAEAAMCvlFJKKaWUpimllFJKs5SylFJKKaWUUkoppTSbjRERERERERERETEiIiIiIiIiIiIiou64sCAIIowyxjgTTDLFNDP84ldzzLPAIksss8JvVlljnfU22myr7Xbaba/9DjrsqONOOu2s8/70t3/956JLLrviqmuuu+GmW26746577nvgoUf+99gTTz3z3AsvvfLaG2+9894HH33y2RdfffPdD0NDgiDcSKONNd5Ek0013UyzzDbXfAstttRyK/1utbX+sMEmW2yzwy577HPAIUccc8IpZ5xzwV/+8RPNizXs + + +AQAAAIAAAACAAAAADAAAAA==eNpjZR1YAAChwAKB + + + + +AQAAAAAGAAAABgAAFwAAAA==eNpjYGBwYBjFo3gUj+JRPOIwALbRYAE= + +AQAAAAAGAAAABgAANwAAAA==eNpjYGA4wEA+Rgb01IvLHEoAqe6khfggAA32o3g4YwaHYYpx5V9caqglTgmmxEyquAcAbUjFiQ== + +AQAAAAAGAAAABgAAFAAAAA==eNpjYBgFo2AUjIJRMBIBAAYAAAE= + +AQAAAAAGAAAABgAAFwAAAA==eNpjYGiwZxjFo3gUj+JRPOIwAFnVHpA= + + + + + + + + + + + + +AQAAAKAXAACgFwAAnwIAAA==eNqNWMF1xSAMYxRPQjyKR/FojNZL2ycUCfJvX5Fkx3YCZIzt9wz9/6Frj+A/Gm/A2+Act02sfnQsx9/iCn6TZys+5jX1/w1/9ut4DflKw1yl3e5r0n1NgZM/+sh8KP+b9tWLXzwNjv5p+Ij3wV9pecY2jsDbxE2T5zj4Ky3nlFhPgXO/FB9xnv+8aLlfaWZJ+bOnypOfwbxoB9VfadM8y0l5psH70TOmtE18fCekwNk/DT9N/jft9pvm/zTvqEmaqfEWPk6L/os95hvH52VN8pkab+HjtJy/zG+ad90UMQT+fw8ftG1qMkz+nE+rHh3WkXHTwrwteu7WfOP4bC68R+IvsRasD9rt2ae4WH+535i7j+oX1/Oqpfy397zAX/Np+GPq+b9p29Rkmfw5nxb8dVj310XL68UfHgZH/zB8xPPg72KpHoXBsf5h+IjnwV9peU35y7kMjv5l+Ij3wV9puf6uF27fouqfpl/xQfva82POAm+qj+IX9cv6m1i498MaKrxNX8r0MQ/+Ssv7zG3eBJ5mbsPM+Tj5Cy3X3/XC7nun6ZG43/qg5RkqXIsVjjGm4QPe0/u7WMm1/uVInNYvyQe8p/dXWj4XFKy/Ckf/ZfiI8/6/Llquv+uFOxeU6ZHs1wctr19h9kIhzgJrav6ifjl/FwvPHVhDhWP9ueaqjz29v9LyfiPM3kzOp+Fv+PD+Ukv1d71w8xOmR2H2tzftoPVO9TrMGTZorsLg+eg9ktImrUcYNwTO61cYfohzaH3Qcv5q9sKchYPmvAzewsdp09QkTP5p8g/Suu8McdHi94Si7wkl8CR+GX6JbwX1QZtUT4xbAuf6l+GXqedNy/njN5AQOM9nGH6Y+b9p09SkTP5p8i/Suu9CddT+APxz8CQ= + + + + + +AQAAAOAHAADgBwAA4QIAAA==eNol08MSLAYAALB9tm3btm3btm3btm3btm3brtvM9JBPSCAQCAQhKMEITghCEorQhCEs4QhPBCISichEISrRiE4MYhKL2MQhLvGITwISkojEJCEpyUhOClKSitSkIS3pSE8GMpKJzGQhK9nITg5ykovc5CEv+chPAQpSiMIUoSjFKE4JSlKK0pShLOUoTwUqUonKVKEq1ahODWpSi9rUoS71qE8DGtKIxjShKc1oTgta0orWtKEt7WhPBzrSic50oSvd6E4PetKL3vShL/3ozwAGMojBDGEowxjOCEYyitGMYSzjGM8EJjKJyUxhKtOYzgxmMovZzGEu85jPAhayiMUsYSnLWM4KVrKK1axhLetYzwY2sonNbGEr29jODnayi93sYS/72M8BDnKIwxzhKMc4zglOcorTnOEs5zjPBS5yictc4SrXuM4NbnKL29zhLve4zwMe8ojHPOEpz3jOC17yite84S3veM8HPvKJz3zhK9/4zg9+8ovf+J0/+JO/+Jt/+Dfwf/4gBCUYwQlBSEIRmjCEJRzhiUBEIhGZKEQlGtGJQUxiEZs4xCUe8UlAQhKRmCQkJRnJSUFKUpGaNKQlHenJQEYykZksZCUb2clBTnKRmzzkJR/5KUBBClGYIhSlGMUpQUlKUZoylKUc5alARSpRmSpUpRrVqUFNalGbOtSlHvVpQEMa0ZgmNKUZzWlBS1rRmja0pR3t6UBHOtGZLnSlG93pQU960Zs+9KUf/RnAQAYxmCEMZRjDGcFIRjGaMYxlHOOZwEQmMZkpTGUa05nBTGYxmznMZR7zWcBCFrGYJSxlGctZwUpWsZo1rGUd69nARjaxmS1sZRvb2cFOdrGbPexlH/s5wEEOcZgjHOUYxznBSU5xmjOc5RznucBFLnGZK1zlGte5wU1ucZs73OUe93nAQx7xmCc85RnPecFLXvGaN7zlHe/5wEc+8ZkvfOUb3/nBT37xH/wj+B0= + + +AQAAAKACAACgAgAAMwEAAA==eNoNwwFoCAEAAMCfRUTWRERkTWRZW5a1RUS0ZdE0TVuTNW1NW1tbW1tbExGRRWSRtUWTtbW1RbRlbdFEWxbR1rRlbdFE1rQ1teKuLjQIgmWucJVhrnGdG9zkFiPc5g6jjDbWOONNdJ8HPOQRk03xuCc86SkzPW22Z83znIUWW2q5lVZ73ote9qrXrfWWd6zzvvU2+sjHNttqu50+84Xd9tjna9/4zkGH/OhnR/ziuBNO+d0f/nLGP87710X/uSQkCJa63JWuNty1rnejm91qpNvd6S5j3O0eE9zrfg962CSPesxU00w3wyzPmGOu+RZYZIllVlhljRe85BWvecOb3vau93xggw9t8oktttnhU5/b5Ut7fWW/bx3wvR/85LCjjvnVSb857U9/O+ucC/4HElhTsA== + + +AQAAAKgAAACoAAAADAAAAA==eNpjZR0aAAAV+wNJ + + + + +AQAAAOAHAADgBwAAHgAAAA==eNpjYKA1aLAfxQOJGRxG8SgexaN4FI88DAA1baeh + +AQAAAOAHAADgBwAAPQAAAA==eNpjYGjYzzCKhzFmOEABRgb01IvLHEoAqe6khfggAA32o3g4YwaHYYpx5V9caqglTgmmxEyquAcAseNbIA== + +AQAAAOAHAADgBwAAFwAAAA==eNpjYBgFo2AUjIJRMApGwXADAAfgAAE= + +AQAAAOAHAADgBwAAGgAAAA==eNpjYGiwZxjFo3gUj+JRPIpH8bDCAIIQeBg= + + + + + + + + + + + + + + +AQAAAAASAAAAEgAABgIAAA==eNqNltFtAzEMQz2KJnE0ikfRaDda0aJAGIYvuX6lDEnzKCG+tV7+9sr/Cz7bvt/AT5obWvW/3GO/4+th/A18wSf4kNbzx3yCq/8vfgE/PsMN7UAnC/J7nkkz2sE3+Eft45n/L+PjiV/7HZ/9yr925is+wYe06r/sXO1f90b56pPm5X1+1Vr+0d4C/rafwH/B17sPaQc6uSC/55nA9+eanf0H5pt2pgBX/wK+4v3Bn85KMyrAtf8CvuL9wT9pNX9L5gO4+h/gKz4f/JPW+6dZTMjT0H/DvOqGdqT/kQ4P4GP9JP6xeaE/nDVylnaY8IG5HJhjf/BPWs3fvm8Bb9jbgj1fn/yD1vunWdD+pP4b5nVuaH2Hjt7FCdczNvAFn83+dFZ71/+ciNv9FfmCz2b/pNX8I5kvwNX/Ar7if78n4J+03j/NokOe2bn/oXnd0Pr9VfAuVPJZ+0n8y+ZF/nRWy2ftMOHav3ee5jib/ZPW3zcK3s3ifgL/BV/sH7XWP82C9qdgRgXvt9+0y+67NOuyO1r5Bfy0b3VD23Yf6bkVcL+/CviK9yO/kySt50+7p3gb/wA/7X/d0DZ0UpC/IX+ZtsPzNnBUO5L/6G+pZFa8jX+Ar3gHH9K29annnoB7/wf4B/r8pvX8LXgF3PezgF+w/9+0DZ0cyN+Q/5i2w/M2cJ7aH7k+iCA= + + + + + +AQAAAAAGAAAABgAARwIAAA==eNol02O7HgQAANB3xp1tm3e272zbtm3VbNRWs70aa0bNZs22VeN5nn04P+EEAoFAKEIThrCEIzwRiEgkIhNEFKISjejEICaxiE0c4hKP+CQgIYlITBKSkozkpCAlqUhNGtKSjvRkICOZyEwWspKN7ASTg5zkIjd5yEs+8lOAghSiMEUoSjGKU4KSlCKE0pShLOUoTwUqUonKVKEq1ahODWpSi9rUoS71qE8DGtKIxjShKc1oTgta0orWtKEt7WhPBzrSic50oSvd6E4PetKL3vShL/3ozwAGMojBDGEowxjOCEYyitH8wI+MYSzjGM8EJjKJyUxhKtOYzgxmMovZ/MTPzGEuv/Ar85jPAhayiMUsYSnLWM4KVrKK1axhLetYzwY28hu/s4nNbGEr29jOH/zJDnayi93sYS/72M8BDvIXf3OIwxzhKMc4zglOcorTnOEs5zjPBS5yicv8w79c4SrXuM4NbnKL29zhLve4zwMe8ojHPOEpz3jOC17yite84S3veM8H/uN/PvKJz3zha+B7/lCEJgxhCUd4IhCRSEQmiChEJRrRiUFMYhGbOMQlHvFJQEISkZgkJCUZyUlBSlKRmjSkJR3pyUBGMpGZLGQlG9kJJgc5yUVu8pCXfOSnAAUpRGGKUJRiFKcEJSlFCKUpQ1nKUZ4KVKQSlalCVapRnRrUpBa1qUNd6lGfBjSkEY1pQlOa0ZwWtKQVrWlDW9rRng50pBOd6UJXutGdHvSkF73pQ1/60Z8BDGQQgxnCUL4Bn7GfwQ== + + +AQAAAAACAAAAAgAA6gAAAA==eNoNwwFEGAEAAMCvlFJKKaWUpimllFJKs5SylFJKKaWUUkoppTSbjRERERERERERETEiIiIiIiIiIiIiou64sCAIIowyxjgTTDLFNDP84ldzzLPAIksss8JvVlljnfU22myr7Xbaba/9DjrsqONOOu2s8/70t3/956JLLrviqmuuu+GmW26746577nvgoUf+99gTTz3z3AsvvfLaG2+9894HH33y2RdfffPdD0NDgiDcSKONNd5Ek0013UyzzDbXfAstttRyK/1utbX+sMEmW2yzwy577HPAIUccc8IpZ5xzwV/+8RPNizXs + + +AQAAAIAAAACAAAAADAAAAA==eNpjZR1YAAChwAKB + + + + +AQAAAAAGAAAABgAAFwAAAA==eNpjYGBwYBjFo3gUj+JRPOIwALbRYAE= + +AQAAAAAGAAAABgAAQQAAAA==eNpjYGA4wDAwGBlQyxxizCRGPSVuI1UvMW6ghXtINL/BHoGplQZoYSY9MbL7cWFqqafEDSjmOIziUQzDAEw3wJo= + +AQAAAAAGAAAABgAAFAAAAA==eNpjYBgFo2AUjIJRMBIBAAYAAAE= + +AQAAAAAGAAAABgAAFwAAAA==eNpjYGBwYBjFo3gUj+JRPOIwALbRYAE= + + + + + + + + + + + + +AQAAAKAXAACgFwAAnwIAAA==eNqNWMF1xSAMYxRPQjyKR/FojNZL2ycUCfJvX5Fkx3YCZIzt9wz9/6Frj+A/Gm/A2+Act02sfnQsx9/iCn6TZys+5jX1/w1/9ut4DflKw1yl3e5r0n1NgZM/+sh8KP+b9tWLXzwNjv5p+Ij3wV9pecY2jsDbxE2T5zj4Ky3nlFhPgXO/FB9xnv+8aLlfaWZJ+bOnypOfwbxoB9VfadM8y0l5psH70TOmtE18fCekwNk/DT9N/jft9pvm/zTvqEmaqfEWPk6L/os95hvH52VN8pkab+HjtJy/zG+ad90UMQT+fw8ftG1qMkz+nE+rHh3WkXHTwrwteu7WfOP4bC68R+IvsRasD9rt2ae4WH+535i7j+oX1/Oqpfy397zAX/Np+GPq+b9p29Rkmfw5nxb8dVj310XL68UfHgZH/zB8xPPg72KpHoXBsf5h+IjnwV9peU35y7kMjv5l+Ij3wV9puf6uF27fouqfpl/xQfva82POAm+qj+IX9cv6m1i498MaKrxNX8r0MQ/+Ssv7zG3eBJ5mbsPM+Tj5Cy3X3/XC7nun6ZG43/qg5RkqXIsVjjGm4QPe0/u7WMm1/uVInNYvyQe8p/dXWj4XFKy/Ckf/ZfiI8/6/Llquv+uFOxeU6ZHs1wctr19h9kIhzgJrav6ifjl/FwvPHVhDhWP9ueaqjz29v9LyfiPM3kzOp+Fv+PD+Ukv1d71w8xOmR2H2tzftoPVO9TrMGTZorsLg+eg9ktImrUcYNwTO61cYfohzaH3Qcv5q9sKchYPmvAzewsdp09QkTP5p8g/Suu8McdHi94Si7wkl8CR+GX6JbwX1QZtUT4xbAuf6l+GXqedNy/njN5AQOM9nGH6Y+b9p09SkTP5p8i/Suu9CddT+APxz8CQ= + + + + + +AQAAAOAHAADgBwAA4QIAAA==eNol08MSLAYAALB9tm3btm3btm3btm3btm3brtvM9JBPSCAQCAQhKMEITghCEorQhCEs4QhPBCISichEISrRiE4MYhKL2MQhLvGITwISkojEJCEpyUhOClKSitSkIS3pSE8GMpKJzGQhK9nITg5ykovc5CEv+chPAQpSiMIUoSjFKE4JSlKK0pShLOUoTwUqUonKVKEq1ahODWpSi9rUoS71qE8DGtKIxjShKc1oTgta0orWtKEt7WhPBzrSic50oSvd6E4PetKL3vShL/3ozwAGMojBDGEowxjOCEYyitGMYSzjGM8EJjKJyUxhKtOYzgxmMovZzGEu85jPAhayiMUsYSnLWM4KVrKK1axhLetYzwY2sonNbGEr29jODnayi93sYS/72M8BDnKIwxzhKMc4zglOcorTnOEs5zjPBS5yictc4SrXuM4NbnKL29zhLve4zwMe8ojHPOEpz3jOC17yite84S3veM8HPvKJz3zhK9/4zg9+8ovf+J0/+JO/+Jt/+Dfwf/4gBCUYwQlBSEIRmjCEJRzhiUBEIhGZKEQlGtGJQUxiEZs4xCUe8UlAQhKRmCQkJRnJSUFKUpGaNKQlHenJQEYykZksZCUb2clBTnKRmzzkJR/5KUBBClGYIhSlGMUpQUlKUZoylKUc5alARSpRmSpUpRrVqUFNalGbOtSlHvVpQEMa0ZgmNKUZzWlBS1rRmja0pR3t6UBHOtGZLnSlG93pQU960Zs+9KUf/RnAQAYxmCEMZRjDGcFIRjGaMYxlHOOZwEQmMZkpTGUa05nBTGYxmznMZR7zWcBCFrGYJSxlGctZwUpWsZo1rGUd69nARjaxmS1sZRvb2cFOdrGbPexlH/s5wEEOcZgjHOUYxznBSU5xmjOc5RznucBFLnGZK1zlGte5wU1ucZs73OUe93nAQx7xmCc85RnPecFLXvGaN7zlHe/5wEc+8ZkvfOUb3/nBT37xH/wj+B0= + + +AQAAAKACAACgAgAAMwEAAA==eNoNwwFoCAEAAMCfRUTWRERkTWRZW5a1RUS0ZdE0TVuTNW1NW1tbW1tbExGRRWSRtUWTtbW1RbRlbdFEWxbR1rRlbdFE1rQ1teKuLjQIgmWucJVhrnGdG9zkFiPc5g6jjDbWOONNdJ8HPOQRk03xuCc86SkzPW22Z83znIUWW2q5lVZ73ote9qrXrfWWd6zzvvU2+sjHNttqu50+84Xd9tjna9/4zkGH/OhnR/ziuBNO+d0f/nLGP87710X/uSQkCJa63JWuNty1rnejm91qpNvd6S5j3O0eE9zrfg962CSPesxU00w3wyzPmGOu+RZYZIllVlhljRe85BWvecOb3vau93xggw9t8oktttnhU5/b5Ut7fWW/bx3wvR/85LCjjvnVSb857U9/O+ucC/4HElhTsA== + + +AQAAAKgAAACoAAAADAAAAA==eNpjZR0aAAAV+wNJ + + + + +AQAAAOAHAADgBwAAHgAAAA==eNpjYKA1aLAfxQOJGRxG8SgexaN4FI88DAA1baeh + +AQAAAOAHAADgBwAARwAAAA==eNpjYGjYzzCKhzFmODBAGBlQyxxizCRGPSVuI1UvMW6ghXtINL/BHoGplQZoYSY9MbL7cWFqqafEDSjmOIziUQzDAJDSVjE= + +AQAAAOAHAADgBwAAFwAAAA==eNpjYBgFo2AUjIJRMApGwXADAAfgAAE= + +AQAAAOAHAADgBwAAGgAAAA==eNpjYGBwYBjFo3gUj+JRPIpH8bDCAMbhfgE= + + + + + + -- 2.39.5