From a96ff790afc6a8fadfa25ef310199b41796af2cf Mon Sep 17 00:00:00 2001 From: Sebastian Schunert Date: Thu, 31 Oct 2019 17:44:10 -0600 Subject: [PATCH] Add SidesetInfoVectorPostprocessor (#14275) --- .../SidesetInfoVectorPostprocessor.md | 19 ++ .../SidesetInfoVectorPostprocessor.h | 68 +++++++ .../SidesetInfoVectorPostprocessor.C | 192 ++++++++++++++++++ .../sideset_info/gold/out_side_info_0001.csv | 4 + .../sideset_info/sideset_info.i | 63 ++++++ .../vectorpostprocessors/sideset_info/tests | 10 + 6 files changed, 356 insertions(+) create mode 100644 framework/doc/content/source/vectorpostprocessors/SidesetInfoVectorPostprocessor.md create mode 100644 framework/include/vectorpostprocessors/SidesetInfoVectorPostprocessor.h create mode 100644 framework/src/vectorpostprocessors/SidesetInfoVectorPostprocessor.C create mode 100644 test/tests/vectorpostprocessors/sideset_info/gold/out_side_info_0001.csv create mode 100644 test/tests/vectorpostprocessors/sideset_info/sideset_info.i create mode 100644 test/tests/vectorpostprocessors/sideset_info/tests diff --git a/framework/doc/content/source/vectorpostprocessors/SidesetInfoVectorPostprocessor.md b/framework/doc/content/source/vectorpostprocessors/SidesetInfoVectorPostprocessor.md new file mode 100644 index 000000000000..5c3fa2af3467 --- /dev/null +++ b/framework/doc/content/source/vectorpostprocessors/SidesetInfoVectorPostprocessor.md @@ -0,0 +1,19 @@ +# SidesetInfoVectorPostprocessor + +!syntax description /VectorPostprocessors/SidesetInfoVectorPostprocessor + +## Description + +SidesetInfoVectorPostprocessor assembles information from sidesets and prints them to +a csv file. Currently, it allows to obtain `area`, `centroid`, and the bounding box +via `min` and `max`. `min` contains the minimum x, y, z coordinates of the +sideset, while `max` contains the respective maximum values. Note that `centroid` +is not guaranteed to be a point contained in the sideset. + +!syntax parameters /VectorPostprocessors/SidesetInfoVectorPostprocessor + +!syntax inputs /VectorPostprocessors/SidesetInfoVectorPostprocessor + +!syntax children /VectorPostprocessors/SidesetInfoVectorPostprocessor + +!bibtex bibliography diff --git a/framework/include/vectorpostprocessors/SidesetInfoVectorPostprocessor.h b/framework/include/vectorpostprocessors/SidesetInfoVectorPostprocessor.h new file mode 100644 index 000000000000..3a27c408fe84 --- /dev/null +++ b/framework/include/vectorpostprocessors/SidesetInfoVectorPostprocessor.h @@ -0,0 +1,68 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "SideVectorPostprocessor.h" + +// Forward Declarations +class SidesetInfoVectorPostprocessor; + +template <> +InputParameters validParams(); + +class SidesetInfoVectorPostprocessor : public SideVectorPostprocessor +{ +public: + SidesetInfoVectorPostprocessor(const InputParameters & parameters); + + virtual void initialize() override; + virtual void execute() override; + virtual void finalize() override; + + virtual void threadJoin(const UserObject & y) override; + + struct BoundaryData + { + BoundaryData() + : area(0), + centroid(Point()), + min(Point(std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max())), + max(Point(std::numeric_limits::lowest(), + std::numeric_limits::lowest(), + std::numeric_limits::lowest())) + { + } + Real area; + Point centroid; + Point min; + Point max; + }; + +protected: + /// a helper function for retrieving data from _boundary_info + Real dataHelper(BoundaryID bid, std::string mdat_tpe) const; + + /// the type of meta data that is written to file + MultiMooseEnum _meta_data_types; + + /// the type of meta data that is written to file + std::vector _vpp_entry_names; + + /// the sideset id + VectorPostprocessorValue & _sideset_ids; + + /// the vpp data is stored here + std::vector _meta_data; + + /// all data available through the meta_data_types is always accumulated + std::map _boundary_data; +}; diff --git a/framework/src/vectorpostprocessors/SidesetInfoVectorPostprocessor.C b/framework/src/vectorpostprocessors/SidesetInfoVectorPostprocessor.C new file mode 100644 index 000000000000..b708d5566b44 --- /dev/null +++ b/framework/src/vectorpostprocessors/SidesetInfoVectorPostprocessor.C @@ -0,0 +1,192 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "SidesetInfoVectorPostprocessor.h" +#include + +#include "libmesh/quadrature.h" + +registerMooseObject("MooseApp", SidesetInfoVectorPostprocessor); + +template <> +InputParameters +validParams() +{ + InputParameters params = validParams(); + MultiMooseEnum meta_data_types("centroid=0 min=1 max=2 area=3"); + params.addParam( + "meta_data_types", meta_data_types, "Data types that are obtained and written to file."); + params.addClassDescription("This VectorPostprocessor collects meta data for provided sidesets."); + return params; +} + +SidesetInfoVectorPostprocessor::SidesetInfoVectorPostprocessor(const InputParameters & parameters) + : SideVectorPostprocessor(parameters), + _meta_data_types(getParam("meta_data_types")), + _sideset_ids(declareVector("Boundary IDs")) +{ + // this sets up the _vpp_entry_names vector + for (unsigned int j = 0; j < _meta_data_types.size(); ++j) + { + if (_meta_data_types[j] == "centroid" || _meta_data_types[j] == "min" || + _meta_data_types[j] == "max") + { + for (unsigned int d = 0; d < _mesh.dimension(); ++d) + { + std::stringstream ss; + ss << _meta_data_types[j] << "_"; + if (d == 0) + ss << "x"; + else if (d == 1) + ss << "y"; + else if (d == 2) + ss << "z"; + _vpp_entry_names.push_back(ss.str()); + } + } + else + _vpp_entry_names.push_back(_meta_data_types[j]); + } +} + +void +SidesetInfoVectorPostprocessor::initialize() +{ + for (auto & e : boundaryIDs()) + _boundary_data[e] = BoundaryData(); + + // resize the sideset id vector + _sideset_ids.resize(numBoundaryIDs()); + + // now we can initialize the _meta_data vector + _meta_data.resize(_vpp_entry_names.size()); + for (unsigned int j = 0; j < _vpp_entry_names.size(); ++j) + { + _meta_data[j] = &declareVector(_vpp_entry_names[j]); + _meta_data[j]->resize(numBoundaryIDs()); + } +} + +void +SidesetInfoVectorPostprocessor::execute() +{ + mooseAssert(_boundary_data.find(_current_boundary_id) != _boundary_data.end(), + "_current_boundary_id not found in _boundary_data."); + + auto & bd = _boundary_data.find(_current_boundary_id)->second; + bd.area += _current_side_elem->volume(); + bd.centroid += _current_side_elem->centroid() * _current_side_elem->volume(); + + BoundingBox box = _current_side_elem->loose_bounding_box(); + Point lmin = box.min(); + Point lmax = box.max(); + + for (unsigned int j = 0; j < 3; ++j) + { + if (lmin(j) < bd.min(j)) + bd.min(j) = lmin(j); + + if (lmax(j) > bd.max(j)) + bd.max(j) = lmax(j); + } +} + +void +SidesetInfoVectorPostprocessor::finalize() +{ + for (auto & e : _boundary_data) + { + auto & bd = e.second; + gatherSum(bd.area); + for (unsigned int j = 0; j < 3; ++j) + { + gatherMin(bd.min(j)); + gatherMax(bd.max(j)); + gatherSum(bd.centroid(j)); + } + } + + // centroid needs to be divided by area + for (auto & e : _boundary_data) + e.second.centroid /= e.second.area; + + // fill vectors + unsigned int j = 0; + for (auto & e : _boundary_data) + { + // store away the sideset id first + _sideset_ids[j] = e.first; + + // now work through the _vpp_entry_names vector + for (unsigned int i = 0; i < _vpp_entry_names.size(); ++i) + (*_meta_data[i])[j] = dataHelper(e.first, _vpp_entry_names[i]); + + // increment counter + ++j; + } +} + +void +SidesetInfoVectorPostprocessor::threadJoin(const UserObject & y) +{ + const SidesetInfoVectorPostprocessor & vpp = + static_cast(y); + + for (auto & e : _boundary_data) + { + mooseAssert(vpp._boundary_data.find(e.first) != vpp._boundary_data.end(), + "Boundary not found in threadJoin"); + auto & vpp_bd = vpp._boundary_data.find(e.first)->second; + auto & bd = e.second; + + bd.area += vpp_bd.area; + bd.centroid += vpp_bd.centroid; + + for (unsigned int j = 0; j < 3; ++j) + { + if (vpp_bd.min(j) < bd.min(j)) + bd.min(j) = vpp_bd.min(j); + + if (vpp_bd.max(j) > bd.max(j)) + bd.max(j) = vpp_bd.max(j); + } + } +} + +Real +SidesetInfoVectorPostprocessor::dataHelper(BoundaryID bid, std::string mdat_tpe) const +{ + mooseAssert(_boundary_data.find(bid) != _boundary_data.end(), + "boundary id not found in _boundary_data."); + + auto & bd = _boundary_data.find(bid)->second; + + if (mdat_tpe == "centroid_x") + return bd.centroid(0); + else if (mdat_tpe == "centroid_y") + return bd.centroid(1); + else if (mdat_tpe == "centroid_z") + return bd.centroid(2); + else if (mdat_tpe == "min_x") + return bd.min(0); + else if (mdat_tpe == "min_y") + return bd.min(1); + else if (mdat_tpe == "min_z") + return bd.min(2); + else if (mdat_tpe == "max_x") + return bd.max(0); + else if (mdat_tpe == "max_y") + return bd.max(1); + else if (mdat_tpe == "max_z") + return bd.max(2); + else if (mdat_tpe == "area") + return bd.area; + else + mooseError("meta_data_type not recognized. This should never happen."); +} diff --git a/test/tests/vectorpostprocessors/sideset_info/gold/out_side_info_0001.csv b/test/tests/vectorpostprocessors/sideset_info/gold/out_side_info_0001.csv new file mode 100644 index 000000000000..483cc32dbe76 --- /dev/null +++ b/test/tests/vectorpostprocessors/sideset_info/gold/out_side_info_0001.csv @@ -0,0 +1,4 @@ +Boundary IDs,centroid_x,centroid_y,min_x,min_y,max_x,max_y,area +0,0.5,-0.4,0,-0.4,1,-0.4,1 +1,1,5,1,-0.4,1,10.4,10.8 +3,0,5,0,-0.4,0,10.4,10.8 diff --git a/test/tests/vectorpostprocessors/sideset_info/sideset_info.i b/test/tests/vectorpostprocessors/sideset_info/sideset_info.i new file mode 100644 index 000000000000..f03fe2eb218c --- /dev/null +++ b/test/tests/vectorpostprocessors/sideset_info/sideset_info.i @@ -0,0 +1,63 @@ +[Mesh] + type = MeshGeneratorMesh + + [./uniform] + type = GeneratedMeshGenerator + dim = 2 + xmin = 0 + xmax = 1 + nx = 8 + ymin = -0.4 + ymax = 10.4 + ny = 5 + [../] +[] + +[Variables] + [./u] + order = FIRST + family = LAGRANGE + [../] +[] + +[Kernels] + [./diff] + type = Diffusion + variable = u + [../] +[] + +[BCs] + active = 'left right' + + [./left] + type = DirichletBC + variable = u + boundary = 1 + value = 0 + [../] + + [./right] + type = DirichletBC + variable = u + boundary = 2 + value = 1 + [../] +[] + +[VectorPostprocessors] + [./side_info] + type = SidesetInfoVectorPostprocessor + boundary = 'left right bottom' + meta_data_types = 'centroid min max area' + [../] +[] + +[Executioner] + type = Steady +[] + +[Outputs] + file_base = out + csv = true +[] diff --git a/test/tests/vectorpostprocessors/sideset_info/tests b/test/tests/vectorpostprocessors/sideset_info/tests new file mode 100644 index 000000000000..0228f32303e7 --- /dev/null +++ b/test/tests/vectorpostprocessors/sideset_info/tests @@ -0,0 +1,10 @@ +[Tests] + [./sideset_info] + type = 'CSVDiff' + input = 'sideset_info.i' + csvdiff = 'out_side_info_0001.csv' + issues = '#14275' + design = 'SidesetInfoVectorPostprocessor.md' + requirement = 'The system shall allow outputting relevant information about sidesets' + [../] +[]