Skip to content

Commit 810b451

Browse files
authored
Merge pull request #128 from sandialabs/pressure_bc
Adding Pressure NBC to Norma
2 parents 7f78872 + 220dc8f commit 810b451

File tree

8 files changed

+174
-1
lines changed

8 files changed

+174
-1
lines changed
10.2 KB
Binary file not shown.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
${side = 1.0}
2+
${h_size = 0.5}
3+
4+
create brick x {side} y {side} z {side}
5+
volume all size {h_size}
6+
mesh volume all
7+
block 1 volume 1
8+
block 1 name "cube"
9+
nodeset 1 surface with x_coord < 0
10+
nodeset 1 name "nsx-"
11+
nodeset 2 surface with x_coord > 0
12+
nodeset 2 name "nsx+"
13+
nodeset 3 surface with y_coord < 0
14+
nodeset 3 name "nsy-"
15+
nodeset 4 surface with y_coord > 0
16+
nodeset 4 name "nsy+"
17+
nodeset 5 surface with z_coord < 0
18+
nodeset 5 name "nsz-"
19+
nodeset 6 surface with z_coord > 0
20+
nodeset 6 name "nsz+"
21+
sideset 1 surface with x_coord < 0
22+
sideset 1 name "ssx-"
23+
sideset 2 surface with x_coord > 0
24+
sideset 2 name "ssx+"
25+
sideset 3 surface with y_coord < 0
26+
sideset 3 name "ssy-"
27+
sideset 4 surface with y_coord < 0
28+
sideset 4 name "ssy+"
29+
sideset 5 surface with z_coord < 0
30+
sideset 5 name "ssz-"
31+
sideset 6 surface with z_coord > 0
32+
sideset 6 name "ssz+"
33+
set large exodus file off
34+
export mesh "cube.g" overwrite
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
type: single
2+
input mesh file: cube.g
3+
output mesh file: cube.e
4+
Exodus output interval: 1
5+
CSV output interval: 0
6+
model:
7+
type: solid mechanics
8+
material:
9+
blocks:
10+
cube: elastic
11+
elastic:
12+
model: linear elastic
13+
elastic modulus: 1.0e+09
14+
Poisson's ratio: 0.25
15+
density: 1000.0
16+
time integrator:
17+
type: quasi static
18+
initial time: 0.0
19+
final time: 1.0
20+
time step: 0.1
21+
boundary conditions:
22+
Dirichlet:
23+
- node set: nsx-
24+
component: x
25+
function: "0.0"
26+
- node set: nsy-
27+
component: y
28+
function: "0.0"
29+
- node set: nsz-
30+
component: z
31+
function: "0.0"
32+
Neumann pressure:
33+
- side set: ssz+
34+
function: "1.0e+09 * t"
35+
solver:
36+
type: Hessian minimizer
37+
step: full Newton
38+
minimum iterations: 1
39+
maximum iterations: 16
40+
relative tolerance: 1.0e-14
41+
absolute tolerance: 1.0e-10

src/ics_bcs.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,24 @@ function SolidMechanicsNeumannBoundaryCondition(input_mesh::ExodusDatabase, bc_p
7777
)
7878
end
7979

80+
function SolidMechanicsNeumannPressureBoundaryCondition(input_mesh::ExodusDatabase, bc_params::Parameters)
81+
side_set_name = bc_params["side set"]
82+
expression = bc_params["function"]
83+
side_set_id = side_set_id_from_name(side_set_name, input_mesh)
84+
num_nodes_per_side, side_set_node_indices = Exodus.read_side_set_node_list(input_mesh, side_set_id)
85+
side_set_node_indices = Int64.(side_set_node_indices)
86+
87+
# Build symbolic expressions
88+
pressure_num = eval(Meta.parse(expression))
89+
90+
# Compile them into functions
91+
pressure_fun = eval(build_function(pressure_num, [t, x, y, z]; expression=Val(false)))
92+
93+
return SolidMechanicsNeumannPressureBoundaryCondition(
94+
side_set_name, side_set_id, num_nodes_per_side, side_set_node_indices, pressure_fun
95+
)
96+
end
97+
8098
function SolidMechanicsOverlapSchwarzBoundaryCondition(
8199
coupled_block_name::String,
82100
tol::Float64,
@@ -313,6 +331,22 @@ function apply_bc(model::SolidMechanics, bc::SolidMechanicsNeumannBoundaryCondit
313331
end
314332
end
315333

334+
function apply_bc(model::SolidMechanics, bc::SolidMechanicsNeumannPressureBoundaryCondition)
335+
ss_node_index = 1
336+
for side in bc.num_nodes_per_side
337+
side_nodes = bc.side_set_node_indices[ss_node_index:(ss_node_index + side - 1)]
338+
side_coordinates = model.reference[:, side_nodes]
339+
nodal_force_component = get_side_set_nodal_pressure(side_coordinates, bc.pressure_fun, model.time)
340+
ss_node_index += side
341+
side_node_index = 1
342+
for node_index in side_nodes
343+
dof_indices = [3 * node_index - 2, 3 * node_index - 1, 3 * node_index]
344+
model.boundary_force[dof_indices] += nodal_force_component[:, side_node_index]
345+
side_node_index += 1
346+
end
347+
end
348+
end
349+
316350
function compute_rotation_matrix(axis::SVector{3,Float64})::SMatrix{3,3,Float64}
317351
e1 = @SVector [1.0, 0.0, 0.0]
318352
angle_btwn = acos(dot(axis, e1))
@@ -846,6 +880,9 @@ function create_bcs(params::Parameters)
846880
elseif bc_type == "Neumann"
847881
boundary_condition = SolidMechanicsNeumannBoundaryCondition(input_mesh, bc_setting_params)
848882
push!(boundary_conditions, boundary_condition)
883+
elseif bc_type == "Neumann pressure"
884+
boundary_condition = SolidMechanicsNeumannPressureBoundaryCondition(input_mesh, bc_setting_params)
885+
push!(boundary_conditions, boundary_condition)
849886
elseif bc_type == "Schwarz contact"
850887
sim = params["parent_simulation"]
851888
sim.controller.schwarz_contact = true

src/ics_bcs_types.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ mutable struct SolidMechanicsNeumannBoundaryCondition <: SolidMechanicsRegularBo
4242
traction_fun::Function
4343
end
4444

45+
#IKT 6/9/2025 TODO: check with Alejandro if want to have separate NeumannPressure struct
46+
#or integrate it into the Neumann struct. The latter is possible and avoids some
47+
#code duplication.
48+
mutable struct SolidMechanicsNeumannPressureBoundaryCondition <: SolidMechanicsRegularBoundaryCondition
49+
name::String
50+
side_set_id::Int64
51+
num_nodes_per_side::Vector{Int64}
52+
side_set_node_indices::Vector{Int64}
53+
pressure_fun::Function
54+
end
55+
4556
mutable struct SolidMechanicsContactSchwarzBoundaryCondition <: SolidMechanicsSchwarzBoundaryCondition
4657
name::String
4758
side_set_id::Int64

src/interpolation.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,29 @@ function get_side_set_nodal_forces(nodal_coord::Matrix{Float64}, traction_fun::F
358358
return nodal_force_component
359359
end
360360

361+
function get_side_set_nodal_pressure(nodal_coord::Matrix{Float64}, pressure_fun::Function, time::Float64)
362+
_, num_side_nodes = size(nodal_coord)
363+
element_type = get_element_type(2, num_side_nodes)
364+
num_int_points = default_num_int_pts(element_type)
365+
N, dNdξ, w, _ = isoparametric(element_type, num_int_points)
366+
nodal_force_component = zeros(3, num_side_nodes)
367+
for point in 1:num_int_points
368+
Nₚ = N[:, point]
369+
dNdξₚ = dNdξ[:, :, point]
370+
dXdξ = dNdξₚ * nodal_coord'
371+
perp_vector = cross(dXdξ[1, :], dXdξ[2, :])
372+
normal = LinearAlgebra.normalize(perp_vector)
373+
j = norm(perp_vector)
374+
wₚ = w[point]
375+
point_coord = nodal_coord * Nₚ
376+
txzy = (time, point_coord[1], point_coord[2], point_coord[3])
377+
pressure_val = pressure_fun(txzy...)
378+
nodal_force_component_vector = LinearAlgebra.kron(pressure_val * Nₚ * j * wₚ, normal)
379+
nodal_force_component += reshape(nodal_force_component_vector, (3, num_side_nodes))
380+
end
381+
return nodal_force_component
382+
end
383+
361384
function map_to_parametric(element_type::ElementType, nodes::Matrix{Float64}, point::Vector{Float64})
362385
tol = 1.0e-08
363386
max_iters = 1024

test/runtests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ const indexed_test_files = [
5555
(39, "schwarz-ahead-nonoverlap-dynamic-torsion.jl"),
5656
(40, "schwarz-ahead-nonoverlap-dynamic-plate.jl"),
5757
(41, "schwarz-ahead-nonoverlap-dynamic-bracket.jl"),
58-
(42, "utils.jl"), # Must go last due to FPE traps
58+
(42, "single-static-solid-pressure-bc.jl"),
59+
(43, "utils.jl"), # Must go last due to FPE traps
5960
]
6061

6162
# Extract test file names
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Norma: Copyright 2025 National Technology & Engineering Solutions of
2+
# Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS,
3+
# the U.S. Government retains certain rights in this software. This software
4+
# is released under the BSD license detailed in the file license.txt in the
5+
# top-level Norma.jl directory.
6+
@testset "Single Static Solid Pressure Neumann Bc" begin
7+
cp("../examples/single/static-solid/pressure-bc/cube.yaml", "cube.yaml"; force=true)
8+
cp("../examples/single/static-solid/pressure-bc/cube.g", "cube.g"; force=true)
9+
simulation = Norma.run("cube.yaml")
10+
integrator = simulation.integrator
11+
model = simulation.model
12+
rm("cube.yaml")
13+
rm("cube.g")
14+
rm("cube.e")
15+
avg_disp = average_components(integrator.displacement)
16+
avg_stress = average_components(model.stress)
17+
@test avg_disp[1] -0.125 rtol = 1.0e-06
18+
@test avg_disp[2] -0.125 rtol = 1.0e-06
19+
@test avg_disp[3] 0.500 rtol = 1.0e-06
20+
@test avg_stress[1] 0.0 atol = 1.0e-06
21+
@test avg_stress[2] 0.0 atol = 1.0e-06
22+
@test avg_stress[3] 1.0e+09 rtol = 1.0e-06
23+
@test avg_stress[4] 0.0 atol = 1.0e-06
24+
@test avg_stress[5] 0.0 atol = 1.0e-06
25+
@test avg_stress[6] 0.0 atol = 1.0e-06
26+
end

0 commit comments

Comments
 (0)