Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# FlipSidesetGenerator

!syntax description /Mesh/FlipSidesetGenerator

## Overview

The `FlipSidesetGenerator` object flips the normal of a sideset by changing the element the sideset is attached to.
The sideset cannot be flipped if the original element it is attached to does not have a neighbor through the sideset.

!syntax parameters /Mesh/FlipSidesetGenerator

!syntax inputs /Mesh/FlipSidesetGenerator

!syntax children /Mesh/FlipSidesetGenerator
33 changes: 33 additions & 0 deletions framework/include/meshgenerators/FlipSidesetGenerator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//* 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 "MeshGenerator.h"

/**
* MeshGenerator for flipping a sideset
*/
class FlipSidesetGenerator : public MeshGenerator
{
public:
static InputParameters validParams();

FlipSidesetGenerator(const InputParameters & parameters);

protected:
std::unique_ptr<MeshBase> generate() override;

private:
/// Input mesh the operation will be applied to
std::unique_ptr<MeshBase> & _input;

/// Name of the sideset to flip
const BoundaryName _sideset_name;
Copy link
Owner

@aprilnovak aprilnovak Dec 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a const reference (const BoundaryName &)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason for this?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, one reason is related to MOOSE's Controls system. That system allows an input file to essentially modify input file parameters on-the-fly -- so using a reference will make sure that everything in an input file is deeply connected to the input parameter.

It's also convention in MOOSE to use whenever possible, so when you cannot do const references there's some extra context that the software developer can have.

};
72 changes: 72 additions & 0 deletions framework/src/meshgenerators/FlipSidesetGenerator.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//* 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 "FlipSidesetGenerator.h"

#include "CastUniquePointer.h"

registerMooseObject("MooseApp", FlipSidesetGenerator);

InputParameters
FlipSidesetGenerator::validParams()
{
InputParameters params = MeshGenerator::validParams();
params.addClassDescription("A Mesh Generator which flips a given sideset");
params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
params.addRequiredParam<BoundaryName>("boundary", "The sideset (boundary) that will be flipped");
return params;
}

FlipSidesetGenerator::FlipSidesetGenerator(const InputParameters & parameters)
: MeshGenerator(parameters),
_input(getMesh("input")),
_sideset_name(getParam<BoundaryName>("boundary"))
{
}

std::unique_ptr<MeshBase>
FlipSidesetGenerator::generate()
{
// get boundary info
BoundaryInfo & boundary_info = _input->get_boundary_info();
// get id of the input sideset
const auto sideset_id = boundary_info.get_id_by_name(_sideset_name);

// Throw an error if the sideset doesn't exist
if (sideset_id == libMesh::BoundaryInfo::invalid_id)
paramError("boundary", "The boundary '", _sideset_name, "' was not found");

// get a copy of sideset map to avoid changing the sideset map while looping on it
std::multimap<const Elem *, std::pair<unsigned short int, boundary_id_type>> sideset_map =
boundary_info.get_sideset_map();

// old_elem is the original element attached to the sideset before flipping
// new_elem is the element attached to the sideset after flipping
for (const auto & [old_elem, id_pair] : sideset_map)
{
boundary_id_type boundary_id = std::get<1>(id_pair);
if (boundary_id == sideset_id)
{
const auto old_side_id = std::get<0>(id_pair);
const auto old_elem_id = old_elem->id();
const auto new_elem = old_elem->neighbor_ptr(old_side_id);

// Throw an error if the old element doesn't have a neighbor on the old side
if (!new_elem)
mooseError("elem " + std::to_string(old_elem_id) +
" does not have a neighbor through side " + std::to_string(old_side_id) +
" therefore it cannot be flipped");

const auto new_side_id = new_elem->which_neighbor_am_i(old_elem);
boundary_info.remove_side(old_elem, old_side_id, sideset_id);
boundary_info.add_side(new_elem, new_side_id, sideset_id);
}
}
return dynamic_pointer_cast<MeshBase>(_input);
}
97 changes: 97 additions & 0 deletions test/tests/meshgenerators/flip_sideset_generator/flux_flip_2D.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 3
ny = 3
xmax = 3
ymax = 3
[]
[s1]
type = ParsedGenerateSideset
input = gmg
combinatorial_geometry = 'x > 0.9 & x < 1.1 & y > -0.1 & y < 1.1'
normal = '1 0 0'
new_sideset_name = s1
[]
[s2]
type = ParsedGenerateSideset
input = s1
combinatorial_geometry = 'x > 0.9 & x < 2.1 & y > 0.9 & y < 1.1'
normal = '0 1 0'
new_sideset_name = s2
[]
[s3]
type = ParsedGenerateSideset
input = s2
combinatorial_geometry = 'x > 1.9 & x < 2.1 & y > 0.9 & y < 2.1'
normal = '1 0 0'
new_sideset_name = s3
[]
[s4]
type = ParsedGenerateSideset
input = s3
combinatorial_geometry = 'x > 1.9 & x < 3.1 & y > 1.9 & y < 2.1'
normal = '0 1 0'
new_sideset_name = s4
[]
[sideset]
type = SideSetsFromBoundingBoxGenerator
input = s4
bottom_left = '0 0 0'
top_right = '3 3 3'
boundaries_old = 's1 s2 s3 s4'
boundary_new = 's_combined'
[]
[flip]
type = FlipSidesetGenerator
input = sideset
boundary = s_combined
[]
[]

[AuxVariables]
[u]
[]
[]

[AuxKernels]
[diffusion]
type = FunctionAux
variable = u
function = func
[]
[]

[Functions]
[func]
type = ParsedFunction
expression = x+y
[]
[]

[Problem]
type = FEProblem
solve = false
[]

[Postprocessors]
[flux]
type = SideDiffusiveFluxIntegral
variable = u
boundary = s_combined
diffusivity = 1
[]
[area]
type = AreaPostprocessor
boundary = s_combined
[]
[]

[Executioner]
type = Steady
[]

[Outputs]
csv = true
[]
76 changes: 76 additions & 0 deletions test/tests/meshgenerators/flip_sideset_generator/flux_flip_3D.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 3
nx = 3
ny = 3
nz = 3
xmax = 3
ymax = 3
zmax = 3
[]
[subdomains]
type = ParsedSubdomainMeshGenerator
input = gmg
combinatorial_geometry = 'x < 1 & y > 1 & y < 2'
block_id = 1
[]
[sideset]
type = ParsedGenerateSideset
input = subdomains
combinatorial_geometry = 'z < 1'
included_subdomains = '1'
normal = '1 0 0'
new_sideset_name = interior
[]
[flip]
type = FlipSidesetGenerator
input = sideset
boundary = interior
[]
[]
[AuxVariables]
[u]
[]
[]

[AuxKernels]
[diffusion]
type = FunctionAux
variable = u
function = func
[]
[]

[Functions]
[func]
type = ParsedFunction
expression = x+y+z
[]
[]

[Problem]
type = FEProblem
solve = false
[]

[Postprocessors]
[flux]
type = SideDiffusiveFluxIntegral
variable = u
boundary = interior
diffusivity = 1
[]
[area]
type = AreaPostprocessor
boundary = interior
[]
[]

[Executioner]
type = Steady
[]

[Outputs]
csv = true
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
time,area,flux
0,0,0
1,4,4
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
time,area,flux
0,0,0
1,1,1
16 changes: 16 additions & 0 deletions test/tests/meshgenerators/flip_sideset_generator/no_neighbor.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 1
ny = 1
[]
[flip]
type = FlipSidesetGenerator
input = gmg
boundary = 'right'
[]
[]
[Outputs]
exodus = true
[]
16 changes: 16 additions & 0 deletions test/tests/meshgenerators/flip_sideset_generator/no_sideset.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[Mesh]
[gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 1
ny = 1
[]
[flip]
type = FlipSidesetGenerator
input = gmg
boundary = 'bad_side'
[]
[]
[Outputs]
exodus = true
[]
39 changes: 39 additions & 0 deletions test/tests/meshgenerators/flip_sideset_generator/tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[Tests]
issues = '#25528'
design = 'FlipSidesetGenerator.md'
[flux_2D]
type = 'CSVDiff'
input = 'flux_flip_2D.i'
csvdiff = 'flux_flip_2D_out.csv'
recover = false
requirement = 'The system shall support switching the normal orientation of a sideset in a two-dimensional mesh'
mesh_mode = 'replicated'
[]

[flux_3D]
type = 'CSVDiff'
input = 'flux_flip_3D.i'
csvdiff = 'flux_flip_3D_out.csv'
recover = false
requirement = 'The system shall support switching the normal orientation of a sideset in a three-dimensional mesh'
mesh_mode = 'replicated'
[]

[no_sideset_exception]
type = 'RunException'
input = 'no_sideset.i'
cli_args = '--mesh-only'
expect_err = "The boundary 'bad_side' was not found"
requirement = "The system shall produce a reasonable error when switching the normal orientation of a sideset if the sideset does not exist"
mesh_mode = 'replicated'
[]

[no_neighbor_exception]
type = 'RunException'
input = 'no_neighbor.i'
cli_args = '--mesh-only'
expect_err = "elem 0 does not have a neighbor through side 1 therefore it cannot be flipped"
requirement = "The system shall produce a reasonable error when switching the normal orientation of a sideset if the sideset cannot be flipped"
mesh_mode = 'replicated'
[]
[]