Skip to content

Commit f37080a

Browse files
authored
Nurbs (#11)
* Add possibility for NURBS Coords * Test nurbs coords * fix error from rebase
1 parent 0c28372 commit f37080a

9 files changed

+410
-35
lines changed

src/IgAShell.jl

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ using SparseArrays
99
using StaticArrays
1010
using TimerOutputs
1111

12+
"""
13+
NurbsCoords and NurbsOrBSplineCoords
14+
15+
Used for dispatching on Nurbs (coords and weights) or Bsplines (only coords), depending on what is used.
16+
"""
17+
const NurbsCoords{dim_s,T} = Tuple{Vector{Vec{dim_s,T}}, Vector{T}}
18+
const NurbsOrBSplineCoords{dim_s,T} = Union{ Vector{Vec{dim_s,T}} , NurbsCoords{dim_s,T}}
19+
20+
1221
"""
1322
EdgeInterfaceIndex
1423
Specifiying interface on cell.

src/igashell_data.jl

+6-2
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ end
330330
"""
331331
332332
"""
333-
struct IGAShellData{dim_p,dim_s,T,LM<:Five.AbstractMaterial,IM<:Five.AbstractCohesiveMaterial}
333+
struct IGAShellData{dim_p,dim_s,T,LM<:Five.AbstractMaterial,IM<:Five.AbstractCohesiveMaterial,CT}
334334
layer_materials::Vector{LM}
335335
interface_material::IM
336336
orders::NTuple{dim_s,Int}
@@ -351,6 +351,7 @@ struct IGAShellData{dim_p,dim_s,T,LM<:Five.AbstractMaterial,IM<:Five.AbstractCoh
351351
nqp_ooplane_per_layer::Int
352352
nqp_interface_order::Int
353353
add_czcells_vtk::Bool
354+
coordstype::Type{CT}
354355
end
355356

356357
function IGAShellData(;
@@ -362,6 +363,7 @@ function IGAShellData(;
362363
initial_cellstates::Vector{CELLSTATE},
363364
nqp_inplane_order::Int,
364365
nqp_ooplane_per_layer::Int,
366+
nurbscoords::Bool = false,
365367
width::T = 1.0, #Only used in 2d,
366368
nlayers::Int = length(layer_materials),
367369
zcoords::Vector{T} = collect(-thickness/2:(thickness/nlayers):thickness/2),
@@ -384,14 +386,16 @@ function IGAShellData(;
384386
end
385387
end
386388

389+
coordstype = nurbscoords ? NurbsCoords{dim_s,T} : Vec{dim_s, T}
390+
387391
#-----
388392
ninterfaces = nlayers-1
389393
ncells = length(initial_cellstates)
390394
@assert(size(initial_interface_damages)[1] == ninterfaces)
391395
@assert(size(initial_interface_damages)[2] == ncells)
392396
dim_s == 3 && @assert(width == 1.0)
393397

394-
return IGAShellData(layer_materials, interface_material, orders, knot_vectors, thickness, width, nlayers, zcoords, initial_cellstates, initial_interface_damages, adaptable, limit_stress_criterion, limit_damage_criterion, search_radius, collect(locked_elements), small_deformations_theory, nqp_inplane_order, nqp_ooplane_per_layer, nqp_interface_order, add_czcells_vtk)
398+
return IGAShellData(layer_materials, interface_material, orders, knot_vectors, thickness, width, nlayers, zcoords, initial_cellstates, initial_interface_damages, adaptable, limit_stress_criterion, limit_damage_criterion, search_radius, collect(locked_elements), small_deformations_theory, nqp_inplane_order, nqp_ooplane_per_layer, nqp_interface_order, add_czcells_vtk, coordstype)
395399

396400
end
397401

src/igashell_main.jl

+15-12
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,10 @@ function _assemble_stiffnessmatrix_and_forcevector!( dh::Ferrite.AbstractDofHand
413413

414414
assembler = start_assemble(state.system_arrays.Kⁱ, state.system_arrays.fⁱ, fillzero=false)
415415

416-
X = igashell.cache.X
417-
Xᵇ = igashell.cache.Xᵇ
416+
417+
nnodes = Ferrite.nnodes_per_cell(igashell)
418+
X = zeros(igashell.layerdata.coordstype, nnodes) #X = igashell.cache.X
419+
Xᵇ = similar(X) # Xᵇ = igashell.cache.Xᵇ
418420
ue = igashell.cache.ue
419421
fe = igashell.cache.fe
420422
ife = igashell.cache.ife
@@ -423,28 +425,26 @@ function _assemble_stiffnessmatrix_and_forcevector!( dh::Ferrite.AbstractDofHand
423425
ue = igashell.cache.ue
424426
celldofs = igashell.cache.celldofs
425427

426-
nqp_oop_per_layer = getnquadpoints_ooplane_per_layer(igashell)
427-
428428
Δt = state.Δt
429429

430430
@timeit "Shell loop" for (ic, cellid) in enumerate(igashell.cellset)
431431
cellstate = getcellstate(adapdata(igashell), ic)
432432
cv = build_cellvalue!(igashell, cellstate)
433433
active_layer_dofs = build_active_layer_dofs(igashell, cellstate)
434434

435-
Ce = get_extraction_operator(intdata(igashell), ic)
436-
IGA.set_bezier_operator!(cv, Ce)
437-
438435
ndofs = Ferrite.ndofs_per_cell(dh, cellid)
439436
resize!(celldofs, ndofs)
440437
resize!(ue, ndofs)
441438

442439
Ferrite.cellcoords!(X, dh, cellid)
443440
Ferrite.celldofs!(celldofs, dh, cellid)
441+
442+
Ce = get_extraction_operator(intdata(igashell), ic)
444443

445444
disassemble!(ue, state.d, celldofs)
446445

447446
IGA.compute_bezier_points!(Xᵇ, Ce, X)
447+
IGA.set_bezier_operator!(cv, Ce, X)
448448
@timeit "reinit1" reinit!(cv, Xᵇ)
449449

450450
materialstates = state.partstates[ic].materialstates
@@ -626,9 +626,10 @@ function Five.post_part!(dh, igashell::IGAShell{dim_p,dim_s,T}, states) where {d
626626
ue = states.d[_celldofs]
627627

628628
nnodes = Ferrite.nnodes_per_cell(igashell)
629-
X = zeros(Vec{dim_s,T}, nnodes)
629+
X = zeros(igashell.layerdata.coordstype, nnodes)
630+
Xᵇ = similar(X)
630631
Ferrite.cellcoords!(X, dh, cellid)
631-
Xᵇ = IGA.compute_bezier_points(Ce, X)
632+
IGA.compute_bezier_points!(Xᵇ, Ce, X)
632633

633634
if is_lumped(cellstate)
634635
_post_lumped(igashell, Xᵇ, X, ue, Ce, cellstate, ic, cellid)
@@ -646,7 +647,7 @@ function _post_layered(igashell, Xᵇ, X, ue, Ce, cellstate, ic::Int, cellid::In
646647

647648
#Shape values for evaluating stresses at center of cell
648649
cv_mid_interface = igashell.integration_data.cell_value_mid_interfaces
649-
set_bezier_operator!(cv_mid_interface, Ce)
650+
set_bezier_operator!(cv_mid_interface, Ce, X)
650651

651652
#oop_values = _build_oop_basisvalue!(igashell, cellstate)
652653
#set_oop_basefunctions!(cv_mid_interface, oop_values)
@@ -678,18 +679,20 @@ function _post_lumped(igashell, Xᵇ, X, ue, Ce, cellstate, ic::Int, cellid::Int
678679

679680
#Build basis_values for cell
680681
cv = build_cellvalue!(igashell, cellstate)
681-
IGA.set_bezier_operator!(cv, Ce)
682+
IGA.set_bezier_operator!(cv, Ce, X)
682683
reinit!(cv, Xᵇ)
683684

684685
#Build basis_values for stress_recovory
685686
cv_sr = intdata(igashell).cell_values_sr
686687
oop_values = _build_oop_basisvalue!(igashell, cellstate)
687688
set_oop_basefunctions!(cv_sr, oop_values)
688-
IGA.set_bezier_operator!(cv_sr, Ce)
689+
IGA.set_bezier_operator!(cv_sr, Ce, X)
689690
reinit!(cv_sr, Xᵇ)
690691

691692
recover_cell_stresses(srdata(igashell), σ_states, celldata, cv_sr, cv)
692693

694+
695+
IGA.compute_bezier_points!(Xᵇ, Ce, X)
693696
end
694697

695698
function _get_layer_forcevector_and_stiffnessmatrix!(

src/igashell_output.jl

-1
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,5 @@ Five.outputname(o::IGAShellConfigStateOutput) = "ElementState"
307307
dir::Int = 1
308308
end
309309

310-
311310
Five.outputname(o::IGAShellMaterialStateOutput) = string(o.field)
312311

src/igashell_utils.jl

+36-1
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,39 @@ end
205205

206206
#
207207
_to3d(s::SymmetricTensor{2,2,T}) where T = SymmetricTensor{2,3,T,6}((s[1,1], T(0.0), s[1,2], T(0.0), T(0.0), s[2,2]))
208-
_to3d(s::SymmetricTensor{2,3}) = s
208+
_to3d(s::SymmetricTensor{2,3}) = s
209+
210+
"""
211+
Dispatch on Nurbscoords
212+
"""
213+
214+
function Ferrite.cellcoords!((x, w)::NurbsCoords, dh::Ferrite.AbstractDofHandler, i::Int)
215+
Ferrite.cellcoords!(x, dh, i)
216+
getweights!(w, dh.grid, i)
217+
end
218+
219+
function IGA.compute_bezier_points!((xb, wb)::NurbsCoords{dim_s,T2}, Ce::BezierExtractionOperator{T}, (x,w)::NurbsCoords{dim_s, T2}; dim::Int=1) where {dim_s,T,T2}
220+
IGA.compute_bezier_points!(xb, Ce, w.*x, dim=dim)
221+
IGA.compute_bezier_points!(wb, Ce, w)
222+
xb .*= inv.(wb)
223+
end
224+
225+
function IGA.set_bezier_operator!(cv::IGAShellValues, Ce::BezierExtractionOperator{T}, (x,w)::NurbsCoords{dim_s,T}) where {dim_s,T}
226+
IGA.set_bezier_operator!(cv, w.*Ce)
227+
end
228+
229+
function IGA.set_bezier_operator!(cv::IGAShellValues, Ce::BezierExtractionOperator{T}, x::Vector{Vec{dim_s,T}}) where {dim_s,T}
230+
IGA.set_bezier_operator!(cv, Ce)
231+
end
232+
233+
function Base.similar((x,w)::NurbsCoords{dim_s, T}) where {dim_s,T}
234+
return similar(x), similar(w)
235+
end
236+
237+
function Base.zeros(::Type{NurbsCoords{dim_s,T}}, n::Int...) where {dim_s,T}
238+
return (zeros(Vec{dim_s,T},n), zeros(T,n))
239+
end
240+
241+
function myzeros(::Type{NurbsCoords{dim_s,T}}, n::Int) where {dim_s,T}
242+
return (zeros(Vec{dim_s,T},n), zeros(T,n))
243+
end

src/igashell_values.jl

+135-10
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ function function_second_derivative(fe_v::BasisValues{dim_p}, q_point::Int, u::A
6565
return d²udξ²
6666
end
6767

68+
Base.copy(cv::BasisValues) = return BasisValues(copy(cv.N), copy(cv.dNdξ), copy(cv.d²Ndξ²))
6869

6970
"""
7071
@@ -243,22 +244,22 @@ function set_oop_basefunctions!(cv::IGAShellValues{dim_s,dim_p,T}, ooplane_basis
243244

244245
end
245246

246-
function _inplane_nurbs_bezier_extraction(cv::IGAShellValues{dim_s,dim_p,T}, C::IGA.BezierExtractionOperator{T}) where {dim_s,dim_p,T}
247-
dBdξ = cv.inplane_values_bezier.dNdξ
248-
B = cv.inplane_values_bezier.N
247+
function _inplane_nurbs_bezier_extraction(cv::IGAShellValues{dim_s,dim_p,T}, nurbs::BasisValues, bezier::BasisValues, C::IGA.BezierExtractionOperator{T}) where {dim_s,dim_p,T}
248+
dBdξ = bezier.dNdξ
249+
B = bezier.N
249250

250251
for iq in 1:getnquadpoints_inplane(cv)
251252
for ib in 1:getnbasefunctions_inplane(cv)
252253

253-
cv.inplane_values_nurbs.N[ib, iq] = zero(eltype(cv.inplane_values_nurbs.N))
254-
cv.inplane_values_nurbs.dNdξ[ib, iq] = zero(eltype(cv.inplane_values_nurbs.dNdξ))
254+
nurbs.N[ib, iq] = zero(eltype(nurbs.N))
255+
nurbs.dNdξ[ib, iq] = zero(eltype(nurbs.dNdξ))
255256

256257
C_ib = C[ib]
257258

258259
for (i, nz_ind) in enumerate(C_ib.nzind)
259260
val = C_ib.nzval[i]
260-
cv.inplane_values_nurbs.N[ib, iq] += val* B[nz_ind, iq]
261-
cv.inplane_values_nurbs.dNdξ[ib, iq] += val*dBdξ[nz_ind, iq]
261+
nurbs.N[ib, iq] += val* B[nz_ind, iq]
262+
nurbs.dNdξ[ib, iq] += val*dBdξ[nz_ind, iq]
262263
end
263264
end
264265
end
@@ -345,7 +346,7 @@ function _reinit_layer!(cv::IGAShellValues{dim_s,dim_p,T}, qp_indx) where {dim_s
345346
G[dim_s] = D
346347

347348
detJ = dim_s == 3 ? norm((cross(G[1], G[2]))) : norm(cross(G[1]))
348-
cv.detJdA[qp] = detJ*cv.qr.weights[qp]
349+
cv.detJdA[qp] = detJ*cv.qr.weights[qp] # TODO: Should be detJ*cv.iqr.weights[iqp] ?
349350
cv.detJdV[qp] = detJ*cv.iqr.weights[iqp]*cv.oqr.weights[oqp]*0.5*cv.thickness
350351

351352
Gⁱʲ = inv(SymmetricTensor{2,dim_s,T}((i,j)-> G[i]G[j]))
@@ -420,14 +421,19 @@ function _reinit_midsurface!(cv::IGAShellValues{dim_s,dim_p,T}, iqp::Int, coords
420421

421422
end
422423

423-
function Ferrite.reinit!(cv::IGAShellValues, coords::Vector{Vec{dim_s,T}}) where {dim_s,T}
424+
function Ferrite.reinit!(cv::IGAShellValues, coords::NurbsOrBSplineCoords{dim_s,T}) where {dim_s,T}
424425

425426
qp = 0
426427
for iqp in 1:getnquadpoints_inplane(cv)
427428
_reinit_midsurface!(cv, iqp, coords)
428429
end
429430

430-
_inplane_nurbs_bezier_extraction(cv, cv.current_bezier_operator[])
431+
if coords isa NurbsCoords
432+
_inplane_nurbs_preprocess(cv, coords[2])
433+
_inplane_nurbs_bezier_extraction(cv, cv.inplane_values_nurbs, copy(cv.inplane_values_nurbs), cv.current_bezier_operator[])
434+
else
435+
_inplane_nurbs_bezier_extraction(cv, cv.inplane_values_nurbs, cv.inplane_values_bezier, cv.current_bezier_operator[])
436+
end
431437

432438
for oqp in 1:getnquadpoints_ooplane(cv)
433439
for iqp in 1:getnquadpoints_inplane(cv)
@@ -600,4 +606,123 @@ end
600606

601607
function basis_value(cv::IGAShellValues{dim_s,dim_p,T}, qp::Int, i::Int) where {dim_s,dim_p,T}
602608
return cv.N[i,qp]
609+
end
610+
611+
function Ferrite.shape_value(cv::IGAShellValues{dim_s,dim_p,T}, qp::Int, (xᴮ, wᴮ)::NurbsCoords{dim_s,T}) where {dim_s,dim_p,T}
612+
val = zero(Vec{dim_s,T})
613+
nbasefuncs = getnbasefunctions(cv.inplane_values_bezier)
614+
@assert(length(xᴮ) == nbasefuncs)
615+
616+
W = 0.0
617+
@inbounds for i in 1:nbasefuncs
618+
W += cv.inplane_values_bezier.N[i,qp] * wᴮ[i]
619+
end
620+
621+
@inbounds for i in 1:nbasefuncs
622+
val += xᴮ[i] * wᴮ[i] *inv(W) * cv.inplane_values_bezier.N[i,qp]
623+
end
624+
return val
625+
end
626+
627+
function shape_parent_derivative(cv::IGAShellValues{dim_s,dim_p,T}, qp::Int, (xᴮ, wᴮ)::NurbsCoords{dim_s,T}, Θ::Int) where {dim_s,dim_p,T}
628+
629+
grad = zero(Vec{dim_s,T})
630+
nbasefuncs = getnbasefunctions(cv.inplane_values_bezier)
631+
@assert(length(xᴮ) == nbasefuncs)
632+
633+
W = 0.0
634+
dWdξ = 0.0
635+
@inbounds for i in 1:nbasefuncs
636+
N = cv.inplane_values_bezier.N[i,qp]
637+
dNdξ = cv.inplane_values_bezier.dNdξ[i,qp][Θ]
638+
639+
W += N * wᴮ[i]
640+
dWdξ += dNdξ * wᴮ[i]
641+
end
642+
643+
@inbounds for i in 1:nbasefuncs
644+
N = cv.inplane_values_bezier.N[i,qp]
645+
dNdξ = cv.inplane_values_bezier.dNdξ[i,qp][Θ]
646+
647+
grad += xᴮ[i] * wᴮ[i] * inv(W^2) * (dNdξ * W - dWdξ * N)
648+
end
649+
return grad
650+
end
651+
652+
function shape_parent_second_derivative(cv::IGAShellValues{dim_s,dim_p,T}, qp::Int, (xᴮ, wᴮ)::NurbsCoords{dim_s,T}, θ::Tuple{Int,Int}) where {dim_s,dim_p,T}
653+
hess = zero(Vec{dim_s,T})
654+
nbasefuncs = getnbasefunctions(cv.inplane_values_bezier)
655+
@assert(length(xᴮ) == nbasefuncs)
656+
657+
W = 0.0
658+
dWdξ₁ = 0.0
659+
dWdξ₂ = 0.0
660+
d²Wdξ² = 0.0
661+
@inbounds for i in 1:nbasefuncs
662+
N = cv.inplane_values_bezier.N[i,qp]
663+
dNdξ₁ = cv.inplane_values_bezier.dNdξ[i,qp][θ[1]]
664+
dNdξ₂ = cv.inplane_values_bezier.dNdξ[i,qp][θ[2]]
665+
d²Ndξ² = cv.inplane_values_bezier.d²Ndξ²[i,qp][θ[1],θ[2]]
666+
667+
W += N * wᴮ[i]
668+
dWdξ₁ += dNdξ₁ * wᴮ[i]
669+
dWdξ₂ += dNdξ₂ * wᴮ[i]
670+
d²Wdξ² += d²Ndξ² * wᴮ[i]
671+
end
672+
673+
@inbounds for i in 1:nbasefuncs
674+
N = cv.inplane_values_bezier.N[i,qp]
675+
dNdξ₁ = cv.inplane_values_bezier.dNdξ[i,qp][θ[1]]
676+
dNdξ₂ = cv.inplane_values_bezier.dNdξ[i,qp][θ[2]]
677+
d²Ndξ² = cv.inplane_values_bezier.d²Ndξ²[i,qp][θ[1],θ[2]]
678+
679+
hess += xᴮ[i] * wᴮ[i] * (
680+
-2*inv(W^3) * dWdξ₂ * (W*dNdξ₁ - dWdξ₁*N) +
681+
inv(W^2)*((dWdξ₂*dNdξ₁ + W*d²Ndξ²) - (d²Wdξ²*N + dWdξ₁*dNdξ₂))
682+
)
683+
end
684+
return hess
685+
end
686+
687+
function Ferrite.spatial_coordinate(cv::IGAShellValues{dim_s,dim_p,T}, qp::Int, x::NurbsCoords{dim_s,T}) where {dim_s,dim_p,T}
688+
i2s = CartesianIndices((getnquadpoints_inplane(cv), getnquadpoints_ooplane(cv)))
689+
iqp, oqp = Tuple(i2s[qp])
690+
D = cv.Eₐ[iqp][dim_s]
691+
692+
Xᴹ = shape_value(cv, iqp, x)
693+
return Xᴹ + cv.oqr.points[oqp][1]*D
694+
end
695+
696+
function spatial_midsurface_coordinate(cv::IGAShellValues{dim_s,dim_p,T}, iqp::Int, x::NurbsCoords{dim_s,T}) where {dim_s,dim_p,T}
697+
@assert(iqp <= getnquadpoints_inplane(cv))
698+
Xᴹ = shape_value(cv, iqp, x)
699+
return Xᴹ
700+
end
701+
702+
function _inplane_nurbs_preprocess(cv::IGAShellValues{dim_s,dim_p,T}, wᴮ::Vector{T}) where {dim_s,dim_p,T}
703+
704+
nbasefuncs = getnbasefunctions(cv.inplane_values_bezier)
705+
@assert(length(wᴮ) == nbasefuncs)
706+
707+
@inbounds for i in 1:getnquadpoints_inplane(cv)
708+
709+
W = zero(T)
710+
dWdξ = zero(Vec{dim_p,T})
711+
@inbounds for j in 1:nbasefuncs
712+
dNdξ = cv.inplane_values_bezier.dNdξ[j,i]
713+
N = cv.inplane_values_bezier.N[j, i]
714+
715+
W += wᴮ[j] * N
716+
dWdξ += wᴮ[j] * dNdξ
717+
end
718+
719+
@inbounds for j in 1:nbasefuncs
720+
dNdξ = cv.inplane_values_bezier.dNdξ[j,i]
721+
N = cv.inplane_values_bezier.N[j, i]
722+
723+
cv.inplane_values_nurbs.dNdξ[j, i] = inv(W)*dNdξ - inv(W^2) * N * dWdξ
724+
cv.inplane_values_nurbs.N[j, i] = N/W
725+
end
726+
end
727+
603728
end

0 commit comments

Comments
 (0)