1*6cf3b68dSWill Paznerfunction get_cartesian_mesh_size(dim, order, prob_size) 2*6cf3b68dSWill Pazner dims = zeros(CeedInt, dim) 3*6cf3b68dSWill Pazner # Use the approximate formula: 4*6cf3b68dSWill Pazner # prob_size ~ num_elem * order^dim 5*6cf3b68dSWill Pazner num_elem = div(prob_size, order^dim) 6*6cf3b68dSWill Pazner s = 0 # find s: num_elem/2 < 2^s <= num_elem 7*6cf3b68dSWill Pazner while num_elem > 1 8*6cf3b68dSWill Pazner num_elem = div(num_elem, 2) 9*6cf3b68dSWill Pazner s += 1 10*6cf3b68dSWill Pazner end 11*6cf3b68dSWill Pazner r = s%dim 12*6cf3b68dSWill Pazner for d = 1:dim 13*6cf3b68dSWill Pazner sd = div(s, dim) 14*6cf3b68dSWill Pazner if r > 0 15*6cf3b68dSWill Pazner sd += 1 16*6cf3b68dSWill Pazner r -= 1 17*6cf3b68dSWill Pazner end 18*6cf3b68dSWill Pazner dims[d] = 2^sd 19*6cf3b68dSWill Pazner end 20*6cf3b68dSWill Pazner dims 21*6cf3b68dSWill Paznerend 22*6cf3b68dSWill Pazner 23*6cf3b68dSWill Paznerstruct FormRestrictionMode{T} end 24*6cf3b68dSWill Paznerconst RestrictionOnly = FormRestrictionMode{:restr}() 25*6cf3b68dSWill Paznerconst StridedOnly = FormRestrictionMode{:restr_i}() 26*6cf3b68dSWill Paznerconst RestrictionAndStrided = FormRestrictionMode{:both}() 27*6cf3b68dSWill Pazner 28*6cf3b68dSWill Paznerfunction build_cartesian_restriction( 29*6cf3b68dSWill Pazner c::Ceed, 30*6cf3b68dSWill Pazner dim, 31*6cf3b68dSWill Pazner nxyz, 32*6cf3b68dSWill Pazner order, 33*6cf3b68dSWill Pazner ncomp, 34*6cf3b68dSWill Pazner num_qpts; 35*6cf3b68dSWill Pazner mode::Mode=RestrictionOnly, 36*6cf3b68dSWill Pazner) where {Mode} 37*6cf3b68dSWill Pazner p::CeedInt = order 38*6cf3b68dSWill Pazner pp1::CeedInt = p + 1 39*6cf3b68dSWill Pazner nnodes::CeedInt = pp1^dim # number of scal. nodes per element 40*6cf3b68dSWill Pazner elem_qpts::CeedInt = num_qpts^dim # number of qpts per element 41*6cf3b68dSWill Pazner 42*6cf3b68dSWill Pazner nd = CeedInt.(p*nxyz .+ 1) 43*6cf3b68dSWill Pazner num_elem::CeedInt = prod(nxyz) 44*6cf3b68dSWill Pazner scalar_size::CeedInt = prod(nd) 45*6cf3b68dSWill Pazner size::CeedInt = scalar_size*ncomp 46*6cf3b68dSWill Pazner 47*6cf3b68dSWill Pazner form_restr = (Mode() != StridedOnly) 48*6cf3b68dSWill Pazner form_strided = (Mode() != RestrictionOnly) 49*6cf3b68dSWill Pazner 50*6cf3b68dSWill Pazner # elem: 0 1 n-1 51*6cf3b68dSWill Pazner # |---*-...-*---|---*-...-*---|- ... -|--...--| 52*6cf3b68dSWill Pazner # nnodes: 0 1 p-1 p p+1 2*p n*p 53*6cf3b68dSWill Pazner 54*6cf3b68dSWill Pazner if form_restr 55*6cf3b68dSWill Pazner el_nodes = zeros(CeedInt, num_elem*nnodes) 56*6cf3b68dSWill Pazner exyz = zeros(CeedInt, dim) 57*6cf3b68dSWill Pazner @inbounds @simd for e = 0:(num_elem-1) 58*6cf3b68dSWill Pazner re::CeedInt = e 59*6cf3b68dSWill Pazner for d::CeedInt = 1:dim 60*6cf3b68dSWill Pazner exyz[d] = re%nxyz[d] 61*6cf3b68dSWill Pazner re ÷= nxyz[d] 62*6cf3b68dSWill Pazner end 63*6cf3b68dSWill Pazner for lnodes::CeedInt = 0:(nnodes-1) 64*6cf3b68dSWill Pazner gnodes::CeedInt = 0 65*6cf3b68dSWill Pazner gnodes_stride::CeedInt = 1 66*6cf3b68dSWill Pazner rnodes::CeedInt = lnodes 67*6cf3b68dSWill Pazner for d::CeedInt = 1:dim 68*6cf3b68dSWill Pazner q = rnodes÷pp1 69*6cf3b68dSWill Pazner r = rnodes - pp1*q 70*6cf3b68dSWill Pazner gnodes::CeedInt += (exyz[d]*p + r)*gnodes_stride 71*6cf3b68dSWill Pazner gnodes_stride::CeedInt *= nd[d] 72*6cf3b68dSWill Pazner rnodes = q 73*6cf3b68dSWill Pazner end 74*6cf3b68dSWill Pazner el_nodes[e*nnodes+lnodes+1] = gnodes 75*6cf3b68dSWill Pazner end 76*6cf3b68dSWill Pazner end 77*6cf3b68dSWill Pazner end 78*6cf3b68dSWill Pazner 79*6cf3b68dSWill Pazner restr = 80*6cf3b68dSWill Pazner form_restr ? 81*6cf3b68dSWill Pazner create_elem_restriction( 82*6cf3b68dSWill Pazner c, 83*6cf3b68dSWill Pazner num_elem, 84*6cf3b68dSWill Pazner nnodes, 85*6cf3b68dSWill Pazner ncomp, 86*6cf3b68dSWill Pazner scalar_size, 87*6cf3b68dSWill Pazner ncomp*scalar_size, 88*6cf3b68dSWill Pazner el_nodes, 89*6cf3b68dSWill Pazner ) : 90*6cf3b68dSWill Pazner nothing 91*6cf3b68dSWill Pazner restr_i = 92*6cf3b68dSWill Pazner form_strided ? 93*6cf3b68dSWill Pazner create_elem_restriction_strided( 94*6cf3b68dSWill Pazner c, 95*6cf3b68dSWill Pazner num_elem, 96*6cf3b68dSWill Pazner elem_qpts, 97*6cf3b68dSWill Pazner ncomp, 98*6cf3b68dSWill Pazner ncomp*elem_qpts*num_elem, 99*6cf3b68dSWill Pazner STRIDES_BACKEND, 100*6cf3b68dSWill Pazner ) : 101*6cf3b68dSWill Pazner nothing 102*6cf3b68dSWill Pazner 103*6cf3b68dSWill Pazner return size, restr, restr_i 104*6cf3b68dSWill Paznerend 105*6cf3b68dSWill Pazner 106*6cf3b68dSWill Paznerfunction set_cartesian_mesh_coords!(dim, nxyz, mesh_order, mesh_coords) 107*6cf3b68dSWill Pazner p = mesh_order 108*6cf3b68dSWill Pazner nd = p*nxyz .+ 1 109*6cf3b68dSWill Pazner num_elem::CeedInt = prod(nxyz) 110*6cf3b68dSWill Pazner scalar_size::CeedInt = prod(nd) 111*6cf3b68dSWill Pazner 112*6cf3b68dSWill Pazner # The H1 basis uses Lobatto quadrature points as nodes. 113*6cf3b68dSWill Pazner nodes::Vector{CeedScalar} = lobatto_quadrature(p + 1) # nodes are in [-1,1] 114*6cf3b68dSWill Pazner nodes = 0.5 .+ 0.5*nodes 115*6cf3b68dSWill Pazner 116*6cf3b68dSWill Pazner @witharray coords = mesh_coords begin 117*6cf3b68dSWill Pazner @inbounds @simd for gsnodes = 0:scalar_size-1 118*6cf3b68dSWill Pazner rnodes = gsnodes 119*6cf3b68dSWill Pazner for d = 1:dim 120*6cf3b68dSWill Pazner ndd = nd[d] 121*6cf3b68dSWill Pazner q = rnodes÷ndd 122*6cf3b68dSWill Pazner r = rnodes - ndd*q 123*6cf3b68dSWill Pazner 124*6cf3b68dSWill Pazner d1d = r 125*6cf3b68dSWill Pazner coords[gsnodes+scalar_size*(d-1)+1] = ((d1d÷p) + nodes[d1d%p+1])/nxyz[d] 126*6cf3b68dSWill Pazner rnodes = q 127*6cf3b68dSWill Pazner end 128*6cf3b68dSWill Pazner end 129*6cf3b68dSWill Pazner end 130*6cf3b68dSWill Paznerend 131