From 28ff343201fea5bef07c3e3031400f6d10c175e5 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 12 Mar 2024 12:57:20 +1100 Subject: [PATCH 01/90] Added mem leak script --- scripts/_dev/mem_leak.jl | 114 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 scripts/_dev/mem_leak.jl diff --git a/scripts/_dev/mem_leak.jl b/scripts/_dev/mem_leak.jl new file mode 100644 index 00000000..f4fc3270 --- /dev/null +++ b/scripts/_dev/mem_leak.jl @@ -0,0 +1,114 @@ +using Gridap, LevelSetTopOpt + +# FE parameters +order = 1 # Finite element order +xmax=ymax=zmax=1.0 # Domain size +dom = (0,xmax,0,ymax,0,zmax) # Bounding domain +el_size = (40,40,40) # Mesh partition size +prop_Γ_N = 0.4 # Γ_N size parameter +prop_Γ_D = 0.2 # Γ_D size parameter +f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/4 + eps()) && + (zmax/2-zmax*prop_Γ_N/4 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/4 + eps()) +f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function + (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && + (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) +# FD parameters +γ = 0.1 # HJ equation time step coefficient +γ_reinit = 0.5 # Reinit. equation time step coefficient +max_steps = floor(Int,minimum(el_size)/3) # Max steps for advection +tol = 1/(2order^2)*prod(inv,minimum(el_size)) # Advection tolerance +# Problem parameters +κ = 1 # Diffusivity +g = 1 # Heat flow in +vf = 0.4 # Volume fraction constraint +lsf_func = initial_lsf(4,0.2) # Initial level set function +iter_mod = 10 # Output VTK files every 10th iteration + +# Model +model = CartesianDiscreteModel(dom,el_size); +update_labels!(1,model,f_Γ_D,"Gamma_D") +update_labels!(2,model,f_Γ_N,"Gamma_N") +# Triangulation and measures +Ω = Triangulation(model) +Γ_N = BoundaryTriangulation(model,tags="Gamma_N") +dΩ = Measure(Ω,2*order) +dΓ_N = Measure(Γ_N,2*order) +# Spaces +reffe = ReferenceFE(lagrangian,Float64,order) +V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) +U = TrialFESpace(V,0.0) +V_φ = TestFESpace(model,reffe) +V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) +U_reg = TrialFESpace(V_reg,0) +# Level set and interpolator +φh = interpolate(lsf_func,V_φ) +interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) +I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ +# Weak formulation +a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ +l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N +state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) +# Objective and constraints +J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ +dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ +vol_D = sum(∫(1)dΩ) +C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ +dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ +pcfs = PDEConstrainedFunctionals(J,[C],state_map,analytic_dJ=dJ,analytic_dC=[dC]) +# Velocity extension +α = 4*maximum(get_el_Δ(model)) +a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ +vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) +# Finite difference scheme +scheme = FirstOrderStencil(length(el_size),Float64) +stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +# Optimiser +optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +# Solve +for i = 1:10 + LevelSetTopOpt.rrule(state_map,φh) +end + +evaluate!(pcfs,φh); +uh = get_state(state_map) + +GC.gc() +Sys.free_memory() / 2^20 + +for i = 1:10 + begin + u = LevelSetTopOpt.forward_solve!(state_map,φh); + uh = FEFunction(LevelSetTopOpt.get_trial_space(state_map),u); + # LevelSetTopOpt.update_adjoint_caches!(state_map,uh,φh); + end; +end; + +Sys.free_memory() / 2^20 + +GC.gc() +Sys.free_memory() / 2^20 + +for i = 1:10 + begin + # u = LevelSetTopOpt.forward_solve!(state_map,φh); + # uh = FEFunction(LevelSetTopOpt.get_trial_space(state_map),u); + + LevelSetTopOpt.update_adjoint_caches!(state_map,uh,φh); + end; +end; + +Sys.free_memory() / 2^20 + +GC.gc() +Sys.free_memory() / 2^20 + +for i = 1:10 + begin + u = LevelSetTopOpt.forward_solve!(state_map,φh); + uh = FEFunction(LevelSetTopOpt.get_trial_space(state_map),u); + LevelSetTopOpt.update_adjoint_caches!(state_map,uh,φh); + end; +end; + +Sys.free_memory() / 2^20 From ab8127a05a5989eda2d29a4fa5a10b105b7cfdf8 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 12 Mar 2024 12:58:22 +1100 Subject: [PATCH 02/90] Minor --- scripts/_dev/mem_leak.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/_dev/mem_leak.jl b/scripts/_dev/mem_leak.jl index f4fc3270..af9a2b28 100644 --- a/scripts/_dev/mem_leak.jl +++ b/scripts/_dev/mem_leak.jl @@ -4,7 +4,7 @@ using Gridap, LevelSetTopOpt order = 1 # Finite element order xmax=ymax=zmax=1.0 # Domain size dom = (0,xmax,0,ymax,0,zmax) # Bounding domain -el_size = (40,40,40) # Mesh partition size +el_size = (10,10,10) # Mesh partition size prop_Γ_N = 0.4 # Γ_N size parameter prop_Γ_D = 0.2 # Γ_D size parameter f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function @@ -17,7 +17,7 @@ f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator func γ = 0.1 # HJ equation time step coefficient γ_reinit = 0.5 # Reinit. equation time step coefficient max_steps = floor(Int,minimum(el_size)/3) # Max steps for advection -tol = 1/(2order^2)*prod(inv,minimum(el_size)) # Advection tolerance +tol = 1/(2*order^2)*prod(inv,minimum(el_size)) # Advection tolerance # Problem parameters κ = 1 # Diffusivity g = 1 # Heat flow in From 7907edb9fb117f35d5f243cf62fe1368e72c056c Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 12 Mar 2024 13:03:09 +1100 Subject: [PATCH 03/90] Better gitignores --- .gitignore | 2 -- results/.gitignore | 2 ++ results/empty | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 results/.gitignore delete mode 100644 results/empty diff --git a/.gitignore b/.gitignore index b8aba4f7..d43b6663 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,6 @@ deps/src/ # Build artifacts for creating documentation generated by the Documenter package docs/build/ docs/site/ -Results/* -results/* # File generated by Pkg, the package manager, based on a corresponding Project.toml # It records a fixed state of all packages used by the project. As such, it should not be diff --git a/results/.gitignore b/results/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/results/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/results/empty b/results/empty deleted file mode 100644 index 0519ecba..00000000 --- a/results/empty +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 7f8003a238675ba42edb085e2aa15dda2fd9fe93 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Mar 2024 09:35:59 +1100 Subject: [PATCH 04/90] Bugfix: RepeatingAffineFEMap returned wrong U-assembler --- src/ChainRules.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 900d35db..a3ba34f6 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -705,10 +705,15 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap @check nblocks == length(l) spaces_0 = (U0,V0) + assem_U0 = assem_U + biform = IntegrandWithMeasure(a,dΩ) liforms = map(li -> IntegrandWithMeasure(li,dΩ),l) U, V = repeat_spaces(nblocks,U0,V0) spaces = (U,V,V_φ,U_reg) + assem_U = SparseMatrixAssembler( + get_matrix_type(assem_U0),get_vector_type(assem_V0),U,V,get_assembly_strategy(assem_U0) + ) ## Pullback cache uhd = zero(U0) @@ -802,9 +807,9 @@ function update_adjoint_caches!(φ_to_u::RepeatingAffineFEStateMap,uh,φh) return φ_to_u.adj_caches end -function adjoint_solve!(φ_to_u::RepeatingAffineFEStateMap,du::AbstractVector) +function adjoint_solve!(φ_to_u::RepeatingAffineFEStateMap,du::AbstractBlockVector) adjoint_ns, _, adjoint_x, _ = φ_to_u.adj_caches - map(blocks(adjoint_x),du) do xi, dui + map(blocks(adjoint_x),blocks(du)) do xi, dui solve!(xi,adjoint_ns,dui) end return adjoint_x From 30837bf457cd1e23d1c6079b3185c8044e12d454 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Mar 2024 09:47:37 +1100 Subject: [PATCH 05/90] Minor --- scripts/Serial/inverse_homenisation_ALM.jl | 2 +- src/ChainRules.jl | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index c480820d..f6b5ccbf 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -25,7 +25,7 @@ function main() α_coeff = 4 vf = 0.5 path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM" - mkdir(path) + !isdir(path) && mkdir(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index a3ba34f6..7a6b0c3f 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -712,7 +712,7 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap U, V = repeat_spaces(nblocks,U0,V0) spaces = (U,V,V_φ,U_reg) assem_U = SparseMatrixAssembler( - get_matrix_type(assem_U0),get_vector_type(assem_V0),U,V,get_assembly_strategy(assem_U0) + get_matrix_type(assem_U0),get_vector_type(assem_U0),U,V,FESpaces.get_assembly_strategy(assem_U0) ) ## Pullback cache @@ -725,12 +725,12 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap plb_caches = (dudφ_vec,assem_deriv) ## Forward cache - K = assemble_matrix((u,v) -> biform(u,v,φh),assem_U,U0,V0) + K = assemble_matrix((u,v) -> biform(u,v,φh),assem_U0,U0,V0) b = allocate_in_range(K); fill!(b,zero(eltype(b))) b0 = allocate_in_range(K); fill!(b0,zero(eltype(b0))) x = mortar(map(i -> allocate_in_domain(K), 1:nblocks)); fill!(x,zero(eltype(x))) ns = numerical_setup(symbolic_setup(ls,K),K) - fwd_caches = (ns,K,b,x,uhd,assem_U,b0) + fwd_caches = (ns,K,b,x,uhd,assem_U0,b0,assem_U) ## Adjoint cache adjoint_K = assemble_matrix((u,v)->biform(v,u,φh),assem_adjoint,V0,U0) @@ -764,26 +764,26 @@ end get_state(m::RepeatingAffineFEStateMap) = FEFunction(get_trial_space(m),m.fwd_caches[4]) get_measure(m::RepeatingAffineFEStateMap) = m.biform.dΩ get_spaces(m::RepeatingAffineFEStateMap) = m.spaces -get_assemblers(m::RepeatingAffineFEStateMap) = (m.fwd_caches[6],m.plb_caches[2],m.adj_caches[4]) +get_assemblers(m::RepeatingAffineFEStateMap) = (m.fwd_caches[8],m.plb_caches[2],m.adj_caches[4]) function forward_solve!(φ_to_u::RepeatingAffineFEStateMap,φh) biform, liforms = φ_to_u.biform, φ_to_u.liform U0, V0 = φ_to_u.spaces_0 - ns, K, b, x, uhd, assem_U, b0 = φ_to_u.fwd_caches + ns, K, b, x, uhd, assem_U0, b0, _ = φ_to_u.fwd_caches a_fwd(u,v) = biform(u,v,φh) - assemble_matrix!(a_fwd,K,assem_U,U0,V0) + assemble_matrix!(a_fwd,K,assem_U0,U0,V0) numerical_setup!(ns,K) l0_fwd(v) = a_fwd(uhd,v) - assemble_vector!(l0_fwd,b0,assem_U,V0) + assemble_vector!(l0_fwd,b0,assem_U0,V0) rmul!(b0,-1) v = get_fe_basis(V0) map(blocks(x),liforms) do xi, li copy!(b,b0) vecdata = collect_cell_vector(V0,li(v,φh)) - assemble_vector_add!(b,assem_U,vecdata) + assemble_vector_add!(b,assem_U0,vecdata) solve!(xi,ns,b) end return x From dac40c66a5a322e2b93236b6631b8ca5f4d7d1ae Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:19:59 +1000 Subject: [PATCH 06/90] clean up and fix --- scripts/MPI/3d_inverse_homenisation_ALM.jl | 18 +++++++----------- scripts/Serial/inverse_homenisation_ALM.jl | 14 ++++++-------- src/ChainRules.jl | 4 +++- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index af24bfba..b57d1785 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -67,16 +67,12 @@ function main(mesh_partition,distribute,el_size) l = [(v,φ,dΩ) -> ∫(-(I ∘ φ) * C ⊙ εᴹ[i] ⊙ ε(v))dΩ for i in 1:6] ## Optimisation functionals - _C(C,ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q; - - _K(C,u,εᴹ) = (_C(C,ε(u[1])+εᴹ[1],εᴹ[1]) + _C(C,ε(u[2])+εᴹ[2],εᴹ[2]) + _C(C,ε(u[3])+εᴹ[3],εᴹ[3]) + - 2(_C(C,ε(u[1])+εᴹ[1],εᴹ[2]) + _C(C,ε(u[1])+εᴹ[1],εᴹ[3]) + _C(C,ε(u[2])+εᴹ[2],εᴹ[3])))/9 - - _v_K(C,u,εᴹ) = (_C(C,ε(u[1])+εᴹ[1],ε(u[1])+εᴹ[1]) + _C(C,ε(u[2])+εᴹ[2],ε(u[2])+εᴹ[2]) + _C(C,ε(u[3])+εᴹ[3],ε(u[3])+εᴹ[3]) + - 2(_C(C,ε(u[1])+εᴹ[1],ε(u[2])+εᴹ[2]) + _C(C,ε(u[1])+εᴹ[1],ε(u[3])+εᴹ[3]) + _C(C,ε(u[2])+εᴹ[2],ε(u[3])+εᴹ[3])))/9 - - J(u,φ,dΩ) = ∫(-(I ∘ φ)*_K(C,u,εᴹ))dΩ - dJ(q,u,φ,dΩ) = ∫(_v_K(C,u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ + dCᴴ(r,s,q,u,φ,dΩ) = ∫(q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + κ(u,φ,dΩ) = -1/9*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+Cᴴ(3,3,u,φ,dΩ)+ + 2*(Cᴴ(1,2,u,φ,dΩ)+Cᴴ(1,3,u,φ,dΩ)+Cᴴ(2,3,u,φ,dΩ))) + dκ(q,u,φ,dΩ) = 1/9*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+dCᴴ(3,3,q,u,φ,dΩ)+ + 2*(dCᴴ(1,2,q,u,φ,dΩ)+dCᴴ(1,3,q,u,φ,dΩ)+dCᴴ(2,3,q,u,φ,dΩ))) Vol(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ @@ -95,7 +91,7 @@ function main(mesh_partition,distribute,el_size) assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), ls = solver, adjoint_ls = solver ) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) + pcfs = PDEConstrainedFunctionals(κ,[Vol],state_map;analytic_dJ=dκ,analytic_dC=[dVol]) ## Hilbertian extension-regularisation problems α = α_coeff*maximum(el_Δ) diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index c480820d..4dcf8b1f 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -24,7 +24,7 @@ function main() η_coeff = 2 α_coeff = 4 vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM" + path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_new" mkdir(path) ## FE Setup @@ -62,12 +62,10 @@ function main() l = [(v,φ,dΩ) -> ∫(-(I ∘ φ)* C ⊙ εᴹ[i] ⊙ ε(v))dΩ for i in 1:3] ## Optimisation functionals - _C(C,ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q - _K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],εᴹ[2]))/4 - _v_K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],ε(u1)+εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],ε(u2)+εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],ε(u2)+εᴹ[2]))/4 - - J(u,φ,dΩ) = ∫(-(I ∘ φ)*_K(C,u,εᴹ))dΩ - dJ(q,u,φ,dΩ) = ∫(_v_K(C,u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ + dCᴴ(r,s,q,u,φ,dΩ) = ∫(q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + κ(u,φ,dΩ) = -1/4*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+2*Cᴴ(1,2,u,φ,dΩ)) + dκ(q,u,φ,dΩ) = 1/4*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+2*dCᴴ(1,2,q,u,φ,dΩ)) Vol(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ @@ -76,7 +74,7 @@ function main() ## Setup solver and FE operators state_map = RepeatingAffineFEStateMap(3,a,l,U,V,V_φ,U_reg,φh,dΩ) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) + pcfs = PDEConstrainedFunctionals(κ,[Vol],state_map;analytic_dJ=dκ,analytic_dC=[dVol]) ## Hilbertian extension-regularisation problems α = α_coeff*maximum(el_Δ) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 900d35db..d9387dbe 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -49,7 +49,9 @@ function Gridap.gradient(F::IntegrandWithMeasure,uh::Vector,K::Int) local_fields = map(local_views,uh) |> to_parray_of_arrays local_measures = map(local_views,F.dΩ) |> to_parray_of_arrays contribs = map(local_measures,local_fields) do dΩ,lf - _f = u -> F.F(lf[1:K-1]...,u,lf[K+1:end]...,dΩ...) + # TODO: Remove second term below, this is a fix for the problem discussed in + # https://github.com/zjwegert/LSTO_Distributed/issues/46 + _f = u -> F.F(lf[1:K-1]...,u,lf[K+1:end]...,dΩ...) #+ ∑(∫(0)dΩ[i] for i = 1:length(dΩ)) return Gridap.Fields.gradient(_f,lf[K]) end return DistributedDomainContribution(contribs) From 274a03f814381d10c90d5755aa3b6ede091e6779 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:28:25 +1000 Subject: [PATCH 07/90] fix name --- scripts/Serial/inverse_homenisation_ALM.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index 4dcf8b1f..5090f339 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -24,7 +24,7 @@ function main() η_coeff = 2 α_coeff = 4 vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_new" + path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM" mkdir(path) ## FE Setup From f548e1e5d939ae7c4f7857d27689a769fbc9564f Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 14 Mar 2024 14:15:02 +1000 Subject: [PATCH 08/90] fix and add scripts for new issue --- scripts/MPI/3d_inverse_homenisation_ALM.jl | 4 +- scripts/Serial/inverse_homenisation_ALM.jl | 4 +- scripts/_dev/bug_issue_46/thermal_MPI.jl | 91 +++++++++++++++++++++ scripts/_dev/bug_issue_46/thermal_serial.jl | 87 ++++++++++++++++++++ 4 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 scripts/_dev/bug_issue_46/thermal_MPI.jl create mode 100644 scripts/_dev/bug_issue_46/thermal_serial.jl diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index b57d1785..488ca57e 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -68,10 +68,10 @@ function main(mesh_partition,distribute,el_size) ## Optimisation functionals Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ - dCᴴ(r,s,q,u,φ,dΩ) = ∫(q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + dCᴴ(r,s,q,u,φ,dΩ) = ∫(-q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ κ(u,φ,dΩ) = -1/9*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+Cᴴ(3,3,u,φ,dΩ)+ 2*(Cᴴ(1,2,u,φ,dΩ)+Cᴴ(1,3,u,φ,dΩ)+Cᴴ(2,3,u,φ,dΩ))) - dκ(q,u,φ,dΩ) = 1/9*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+dCᴴ(3,3,q,u,φ,dΩ)+ + dκ(q,u,φ,dΩ) = -1/9*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+dCᴴ(3,3,q,u,φ,dΩ)+ 2*(dCᴴ(1,2,q,u,φ,dΩ)+dCᴴ(1,3,q,u,φ,dΩ)+dCᴴ(2,3,q,u,φ,dΩ))) Vol(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index 5090f339..d4d60aa8 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -63,9 +63,9 @@ function main() ## Optimisation functionals Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ - dCᴴ(r,s,q,u,φ,dΩ) = ∫(q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + dCᴴ(r,s,q,u,φ,dΩ) = ∫(-q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ κ(u,φ,dΩ) = -1/4*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+2*Cᴴ(1,2,u,φ,dΩ)) - dκ(q,u,φ,dΩ) = 1/4*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+2*dCᴴ(1,2,q,u,φ,dΩ)) + dκ(q,u,φ,dΩ) = -1/4*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+2*dCᴴ(1,2,q,u,φ,dΩ)) Vol(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ diff --git a/scripts/_dev/bug_issue_46/thermal_MPI.jl b/scripts/_dev/bug_issue_46/thermal_MPI.jl new file mode 100644 index 00000000..2e4596ee --- /dev/null +++ b/scripts/_dev/bug_issue_46/thermal_MPI.jl @@ -0,0 +1,91 @@ +using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, + SparseMatricesCSR + +function main(mesh_partition,distribute,use_l::Bool) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + # FE parameters + order = 1 # Finite element order + xmax = ymax = 1.0 # Domain size + dom = (0,xmax,0,ymax) # Bounding domain + el_size = (200,200) # Mesh partition size + prop_Γ_N = 0.2 # Γ_N size parameter + prop_Γ_D = 0.2 # Γ_D size parameter + f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function + ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function + (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) # @$\lvert\lvert$@ + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Advection tolerance + # Problem parameters + κ = 1 # Diffusivity + g = 1 # Heat flow in + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + iter_mod = 10 # VTK Output modulo + path = "./results/AD_tut1_MPI_lobj_$use_l/" # Output path + i_am_main(ranks) && mkpath(path) # Create path + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + # Triangulation and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,0.0) + V_φ = TestFESpace(model,reffe) + V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N + state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = if use_l + ∫(g*u)dΓ_N #+ ∫(0)dΩ + else + ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ + end + dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + vol_D = sum(∫(1)dΩ) + C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C],state_map) + # Velocity extension + α = 4*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension(a_hilb, U_reg, V_reg) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) + # Solve + for (it,uh,φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|nabla(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) + write_history(path*"/history.txt",get_history(optimiser);ranks) + end + # Final structure + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, + "H(φ)"=>(H ∘ φh),"|nabla(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +end + +with_mpi() do distribute + mesh_partition = (2,2) + main(mesh_partition,distribute,false) + main(mesh_partition,distribute,true) # <- this should crash +end \ No newline at end of file diff --git a/scripts/_dev/bug_issue_46/thermal_serial.jl b/scripts/_dev/bug_issue_46/thermal_serial.jl new file mode 100644 index 00000000..e9c29a6c --- /dev/null +++ b/scripts/_dev/bug_issue_46/thermal_serial.jl @@ -0,0 +1,87 @@ +using LevelSetTopOpt, Gridap + +function main(use_l::Bool) + # FE parameters + order = 1 # Finite element order + xmax = ymax = 1.0 # Domain size + dom = (0,xmax,0,ymax) # Bounding domain + el_size = (200,200) # Mesh partition size + prop_Γ_N = 0.2 # Γ_N size parameter + prop_Γ_D = 0.2 # Γ_D size parameter + f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function + ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function + (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + κ = 1 # Diffusivity + g = 1 # Heat flow in + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + iter_mod = 10 # VTK Output modulo + path = "./results/tut1_lobj_$use_l/" # Output path + mkpath(path) # Create path + # Model + model = CartesianDiscreteModel(dom,el_size); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + # Triangulation and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,0.0) + V_φ = TestFESpace(model,reffe) + V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N + state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = if use_l + ∫(g*u)dΓ_N + else + ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ + end + dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + vol_D = sum(∫(1)dΩ) + C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C],state_map, + analytic_dJ=dJ,analytic_dC=[dC]) + # Velocity extension + α = 4*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + # Solve + for (it,uh,φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) + write_history(path*"/history.txt",get_history(optimiser)) + end + # Final structure + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, + "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +end + +main(false) +main(true) \ No newline at end of file From 67922d71f0319e5c673fee425357003f3d4ab88e Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 14 Mar 2024 14:33:31 +1000 Subject: [PATCH 09/90] Added new benchmark --- scripts/Benchmarks/benchmark.jl | 2 +- src/Benchmarks.jl | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index d91cbe6f..9abd59ee 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -439,7 +439,7 @@ with_mpi() do distribute bopt0 = i_am_main(ranks) && zeros(NREPS) end if occursin("bopt1",BMARK_TYPE) - bopt1 = benchmark_optimizer(optim, 1, ranks; nreps=NREPS) + bopt1 = benchmark_single_iteration(optim, ranks; nreps = NREPS) else bopt1 = i_am_main(ranks) && zeros(NREPS) end diff --git a/src/Benchmarks.jl b/src/Benchmarks.jl index d59ff5bd..87cc4a6e 100644 --- a/src/Benchmarks.jl +++ b/src/Benchmarks.jl @@ -79,6 +79,25 @@ function benchmark_optimizer(m::Optimiser, niter, ranks; nreps = 10) return benchmark(f, (m,), ranks; nreps, reset! = opt_reset!) end +""" + benchmark_single_iteration(m::Optimiser, ranks; nreps) + +Given an optimiser `m`, benchmark a single iteration after 0th iteration. +""" +function benchmark_single_iteration(m::Optimiser, ranks; nreps = 10) + _, state = iterate(m) + function f(m) + iterate(m, state) + end + + φ0 = copy(get_free_dof_values(m.φ0)) + function opt_reset!(m::Optimiser) + copy!(get_free_dof_values(m.φ0), φ0) + reset!(get_history(m)) + end + return benchmark(f, (m,), ranks; nreps, reset! = opt_reset!) +end + """ benchmark_forward_problem(m::AbstractFEStateMap, φh, ranks; nreps) From 9508a1c6da1d13bae1bc22a73590ee41c8f7bf1c Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 18 Mar 2024 14:36:13 +1000 Subject: [PATCH 10/90] Testing --- scripts/MPI/3d_thermal_compliance_ALM.jl | 12 ++++++------ scripts/MPI/inverse_homenisation_ALM.jl | 12 +++++------- scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index d2e4ad12..cae68f2d 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -73,7 +73,7 @@ function main(mesh_partition,distribute,el_size,coef,step) I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N + l(v,φ,dΩ,dΓ_N) = ∫(10v)dΓ_N ## Optimisation functionals J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ @@ -126,12 +126,12 @@ with_mpi() do distribute GridapPETSc.with(args=split(all_solver_options)) do main(mesh_partition,distribute,el_size,5,10) - main(mesh_partition,distribute,el_size,2,10) + # main(mesh_partition,distribute,el_size,2,10) - main(mesh_partition,distribute,el_size,5,5) - main(mesh_partition,distribute,el_size,2,5) + # main(mesh_partition,distribute,el_size,5,5) + # main(mesh_partition,distribute,el_size,2,5) - main(mesh_partition,distribute,el_size,5,3) - main(mesh_partition,distribute,el_size,2,3) + # main(mesh_partition,distribute,el_size,5,3) + # main(mesh_partition,distribute,el_size,2,3) end end; \ No newline at end of file diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index ed9c279f..e5399ae1 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -64,12 +64,10 @@ function main(mesh_partition,distribute,el_size) l = [(v,φ,dΩ) -> ∫(-(I ∘ φ) * C ⊙ εᴹ[i] ⊙ ε(v))dΩ for i in 1:3] ## Optimisation functionals - _C(C,ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q; - _K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],εᴹ[2]))/4 - _v_K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],ε(u1)+εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],ε(u2)+εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],ε(u2)+εᴹ[2]))/4 - - J(u,φ,dΩ) = ∫(-(I ∘ φ)*_K(C,u,εᴹ))dΩ - dJ(q,u,φ,dΩ) = ∫(_v_K(C,u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; + Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ + dCᴴ(r,s,q,u,φ,dΩ) = ∫(-q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + κ(u,φ,dΩ) = -1/4*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+2*Cᴴ(1,2,u,φ,dΩ)) + dκ(q,u,φ,dΩ) = -1/4*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+2*dCᴴ(1,2,q,u,φ,dΩ)) Vol(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ @@ -88,7 +86,7 @@ function main(mesh_partition,distribute,el_size) assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), ls = solver,adjoint_ls = solver ) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) + pcfs = PDEConstrainedFunctionals(κ,[Vol],state_map;analytic_dJ=dκ,analytic_dC=[dVol]) ## Hilbertian extension-regularisation problems α = α_coeff*maximum(el_Δ) diff --git a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs index ef1ff771..d71b2b8f 100644 --- a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs @@ -4,7 +4,7 @@ #PBS -N 3d_thermal_compliance_ALM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=200:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh From 45bd1d979c2f1900769170dac44aa4f24c1c4112 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:07:18 +1000 Subject: [PATCH 11/90] Add some more docs --- docs/make.jl | 36 +++++++++++++++------------ docs/src/getting-started.md | 39 ++++++++++++++++++++++++++++++ docs/src/index.md | 24 +++++++++++++++--- docs/src/reference/benchmarking.md | 1 + 4 files changed, 81 insertions(+), 19 deletions(-) create mode 100644 docs/src/getting-started.md diff --git a/docs/make.jl b/docs/make.jl index b9f14f4e..fc289362 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,3 +1,6 @@ +cd("./docs/") +using Pkg; Pkg.activate(".") + using Documenter using LevelSetTopOpt @@ -5,23 +8,24 @@ makedocs( sitename = "LevelSetTopOpt.jl", format = Documenter.HTML( prettyurls = false, - collapselevel = 1, + # collapselevel = 1, ), modules = [LevelSetTopOpt], pages = [ "Home" => "index.md", - "Usage" => [ - "usage/getting-started.md", - "usage/ad.md", - "usage/petsc.md", - "usage/mpi-mode.md", - ], - "Tutorials" => [ - "tutorials/minimum_thermal_compliance.md", - "tutorials/minimum_elastic_compliance.md", - "tutorials/inverter_mechanism.md", - "tutorials/inverse_homogenisation.md", - ], + "Getting Started" => "getting-started.md", + # "Usage" => [ + # "usage/getting-started.md", + # "usage/ad.md", + # "usage/petsc.md", + # "usage/mpi-mode.md", + # ], + # "Tutorials" => [ + # "tutorials/minimum_thermal_compliance.md", + # "tutorials/minimum_elastic_compliance.md", + # "tutorials/inverter_mechanism.md", + # "tutorials/inverse_homogenisation.md", + # ], "Reference" => [ "reference/optimisers.md", "reference/chainrules.md", @@ -31,9 +35,9 @@ makedocs( "reference/utilities.md", "reference/benchmarking.md" ], - "Developer Notes" => [ - "dev/shape_der.md", - ] + # "Developer Notes" => [ + # "dev/shape_der.md", + # ] ], ) diff --git a/docs/src/getting-started.md b/docs/src/getting-started.md new file mode 100644 index 00000000..5b9eed32 --- /dev/null +++ b/docs/src/getting-started.md @@ -0,0 +1,39 @@ +# Getting started + +## Installation + +`LevelSetTopOpt.jl` and additional dependencies can be installed in an existing Julia environment using the package manager. This can be accessed in the Julia REPL (read-eval–print loop) by pressing `]`. We then add the required packages via: +``` +pkg> add LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, SparseMatricesCSR +``` +Once installed, serial driver scripts can be run immediately, whereas parallel problems also require an MPI installation. + +### MPI +For basic users, [`MPI.jl`](https://github.com/JuliaParallel/MPI.jl) provides such an implementation and a Julia wrapper for `mpiexec` - the MPI executor. This is installed via: +``` +pkg> add MPI +julia> using MPI +julia> MPI.install_mpiexecjl() +``` +Once the `mpiexecjl` wrapper has been added to the system `PATH`, MPI scripts can be executed in a terminal via +``` +mpiexecjl -n P julia main.jl +``` +where `main` is a driver script, `P` denotes the number of processors. + +### PETSc +In `LevelSetTopOpt.jl` we rely on the [`GridapPETSc.jl`](https://github.com/gridap/GridapPETSc.jl) satellite package to interface with the linear and nonlinear solvers provided by the PETSc (Portable, Extensible Toolkit for Scientific Computation) library. For basic users these solvers are provided by `GridapPETSc.jl` with no additional work. + +### Advanced installation +For more advanced installations, such as use of a custom MPI/PETSc installation on a HPC cluster, we refer the reader to the [discussion](https://github.com/gridap/GridapPETSc.jl) for `GridapPETSc.jl` and the [configuration page](https://juliaparallel.org/MPI.jl/stable/configuration/) for `MPI.jl`. + +## Usage and tutorials +In order to get familiar with the library we recommend following the numerical examples described in: + +> Zachary J. Wegert, Jordi M. Fuertes, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. + +More general tutorials for familiarising ones self with Gridap are available via the [Gridap Tutorials](https://gridap.github.io/Tutorials/dev/). + +## Known issues +- PETSc's GAMG preconditioner breaks for split Dirichlet DoFs (e.g., x constrained while y free for a single node). There is no simple fix for this. We recommend instead using MUMPS or another preconditioner for this case. +- Currently, our implementation of automatic differentiation does not support multiplication and division of optimisation functionals. We plan to add this in a future release of `LevelSetTopOpt.jl`. \ No newline at end of file diff --git a/docs/src/index.md b/docs/src/index.md index c26e8171..2a9769a0 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,6 +1,24 @@ # LevelSetTopOpt.jl -Welcome to the documentation for LevelSetTopOpt.jl! +Welcome to the documentation for `LevelSetTopOpt.jl`! -# What +## Introduction +`LevelSetTopOpt.jl` is computational toolbox for level set-based topology optimisation implemented in Julia and the Gridap package ecosystem. The core design principle of `LevelSetTopOpt.jl` is to provide an extendable framework for solving optimisation problems in serial or parallel with a high-level programming interface and automatic differentiation. See the following publication for further details: -# Why +> Zachary J. Wegert, Jordi M. Fuertes, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. + +## How to use this documentation + +* The first step for new users is to visit the [Getting Started](getting-started.md) page. + +* A set of tutorials are available as part of the above paper. + +* The detailed documentation is in the Reference section. + +## Julia educational resources + +A basic knowledge of the Julia programming language is needed to use the `LevelSetTopOpt.jl` package. +Here, one can find a list of resources to get started with this programming language. + +* First steps to learn Julia form the [Gridap wiki](https://github.com/gridap/Gridap.jl/wiki/Start-learning-Julia) page. +* Official webpage [docs.julialang.org](https://docs.julialang.org/) +* Official list of learning resources [julialang.org/learning](https://julialang.org/learning/) \ No newline at end of file diff --git a/docs/src/reference/benchmarking.md b/docs/src/reference/benchmarking.md index e5e6d42e..617ee276 100644 --- a/docs/src/reference/benchmarking.md +++ b/docs/src/reference/benchmarking.md @@ -7,6 +7,7 @@ LevelSetTopOpt.benchmark ## Existing benchmark methods ```@docs LevelSetTopOpt.benchmark_optimizer +LevelSetTopOpt.benchmark_single_iteration LevelSetTopOpt.benchmark_forward_problem LevelSetTopOpt.benchmark_advection LevelSetTopOpt.benchmark_reinitialisation From e766580de3c598eb39b0c07b177214bfff8e40e1 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:13:58 +1000 Subject: [PATCH 12/90] Update readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 18d66ae5..4be459bc 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ -# LevelSetTopOpt.jl +# LevelSetTopOpt -... \ No newline at end of file +[comment]: badges + +LevelSetTopOpt is computational toolbox for level set-based topology optimisation implemented in Julia and the [Gridap](https://github.com/gridap/Gridap.jl) package ecosystem. See the documentation for further details. + +## Documentation + +- [**STABLE**](...) — **Documentation for the most recently tagged version.** +- [**LATEST**](...) — *Documentation for the in-development version.* \ No newline at end of file From 93f33fa935eb56ee884c7f798793ff1b89699acd Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:15:54 +1000 Subject: [PATCH 13/90] README update 2 --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4be459bc..1ce80170 100755 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # LevelSetTopOpt -[comment]: badges +| **badges** | -LevelSetTopOpt is computational toolbox for level set-based topology optimisation implemented in Julia and the [Gridap](https://github.com/gridap/Gridap.jl) package ecosystem. See the documentation for further details. +LevelSetTopOpt is computational toolbox for level set-based topology optimisation implemented in Julia and the [Gridap](https://github.com/gridap/Gridap.jl) package ecosystem. See the documentation and following publication for further details: + +> Zachary J. Wegert, Jordi M. Fuertes, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. ## Documentation From a18b6c94ea3f20a4d89ed2a7f81c8df9cc8c6940 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 4 Apr 2024 14:43:40 +1000 Subject: [PATCH 14/90] Add gc call and removed `write_vtk` --- docs/src/reference/io.md | 6 +---- scripts/MPI/3d_elastic_compliance_ALM.jl | 10 ++++--- scripts/MPI/3d_hyperelastic_compliance_ALM.jl | 10 ++++--- .../3d_hyperelastic_compliance_neohook_ALM.jl | 10 ++++--- scripts/MPI/3d_inverse_homenisation_ALM.jl | 10 ++++--- scripts/MPI/3d_inverter_ALM.jl | 8 +++--- scripts/MPI/3d_inverter_HPM.jl | 8 +++--- .../3d_nonlinear_thermal_compliance_ALM.jl | 8 +++--- scripts/MPI/3d_thermal_compliance_ALM.jl | 6 +++-- scripts/MPI/elastic_compliance_ALM.jl | 6 +++-- scripts/MPI/inverse_homenisation_ALM.jl | 6 +++-- scripts/MPI/thermal_compliance_ALM.jl | 6 +++-- scripts/MPI/thermal_compliance_ALM_PETSc.jl | 6 +++-- scripts/Serial/elastic_compliance_ALM.jl | 8 +++--- scripts/Serial/elastic_compliance_HPM.jl | 8 +++--- scripts/Serial/elastic_compliance_LM.jl | 8 +++--- scripts/Serial/hyperelastic_compliance_ALM.jl | 8 +++--- .../hyperelastic_compliance_neohook_ALM.jl | 8 +++--- scripts/Serial/inverse_homenisation_ALM.jl | 8 +++--- scripts/Serial/inverter_ALM.jl | 8 +++--- scripts/Serial/inverter_HPM.jl | 8 +++--- .../nonlinear_thermal_compliance_ALM.jl | 8 +++--- scripts/Serial/thermal_compliance_ALM.jl | 8 +++--- .../_dev/3d_hyperelastic_compliance_ALM.jl | 4 +-- .../inv_hom_block_assem_testing_3D_MPI.jl | 5 ++-- ...inv_hom_block_assem_testing_full_script.jl | 5 ++-- src/LevelSetTopOpt.jl | 1 - src/Optimisers/AugmentedLagrangian.jl | 4 +++ src/Optimisers/HilbertianProjection.jl | 4 +++ src/Utilities.jl | 27 +------------------ 30 files changed, 127 insertions(+), 103 deletions(-) diff --git a/docs/src/reference/io.md b/docs/src/reference/io.md index cc6fccc6..5adc2248 100644 --- a/docs/src/reference/io.md +++ b/docs/src/reference/io.md @@ -1,14 +1,10 @@ # IO -## Optimiser history and visualisation +## Optimiser history ```@docs LevelSetTopOpt.write_history ``` -```@docs -LevelSetTopOpt.write_vtk -``` - ## Object IO in serial ```@docs LevelSetTopOpt.save diff --git a/scripts/MPI/3d_elastic_compliance_ALM.jl b/scripts/MPI/3d_elastic_compliance_ALM.jl index 3e5f6f24..8ae4b8c3 100644 --- a/scripts/MPI/3d_elastic_compliance_ALM.jl +++ b/scripts/MPI/3d_elastic_compliance_ALM.jl @@ -28,7 +28,9 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4 vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_elastic_compliance_ALM" + path = dirname(dirname(@__DIR__))*"/results/3d_elastic_compliance_ALM/" + iter_mod = 10 + i_am_main(ranks) && mkdir(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -98,15 +100,15 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - i_am_main(ranks) && mkdir(path) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl index 7bb9a0b2..ad197331 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl @@ -24,7 +24,9 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4 vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_ALM" + path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_ALM/" + iter_mod = 10 + i_am_main(ranks) && mkdir(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) @@ -104,15 +106,15 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - i_am_main(ranks) && mkdir(path) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index c394a268..0ddd1da4 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -24,7 +24,9 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4 vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_neohook_ALM" + path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_neohook_ALM/" + iter_mod = 10 + i_am_main(ranks) && mkdir(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) @@ -118,15 +120,15 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - i_am_main(ranks) && mkdir(path) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index 488ca57e..2769375b 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -26,8 +26,9 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4 vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/3d_inverse_homenisation_ALM" - i_am_main(ranks) && mkdir(path) + path = dirname(dirname(@__DIR__))*"/results/3d_inverse_homenisation_ALM/" + iter_mod = 10 + i_am_main(ranks) && mkdir(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)) @@ -106,11 +107,12 @@ function main(mesh_partition,distribute,el_size) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))]) end with_mpi() do distribute diff --git a/scripts/MPI/3d_inverter_ALM.jl b/scripts/MPI/3d_inverter_ALM.jl index 4fff7765..1e34d67e 100644 --- a/scripts/MPI/3d_inverter_ALM.jl +++ b/scripts/MPI/3d_inverter_ALM.jl @@ -32,7 +32,8 @@ function main(mesh_partition,distribute,el_size) δₓ=0.5 ks = 0.01 g = VectorValue(1,0,0) - path = dirname(dirname(@__DIR__))*"/results/3d_inverter_ALM" + path = dirname(dirname(@__DIR__))*"/results/3d_inverter_ALM/" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -120,11 +121,12 @@ function main(mesh_partition,distribute,el_size) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol,:UΓ_out]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/3d_inverter_HPM.jl b/scripts/MPI/3d_inverter_HPM.jl index ad041a18..1e051812 100644 --- a/scripts/MPI/3d_inverter_HPM.jl +++ b/scripts/MPI/3d_inverter_HPM.jl @@ -32,7 +32,8 @@ function main(mesh_partition,distribute,el_size) δₓ=0.5 ks = 0.01 g = VectorValue(1,0,0) - path = dirname(dirname(@__DIR__))*"/results/3d_inverter_HPM" + path = dirname(dirname(@__DIR__))*"/results/3d_inverter_HPM/" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -121,11 +122,12 @@ function main(mesh_partition,distribute,el_size) optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh;γ,γ_reinit,ls_enabled,α_min=0.7, ls_γ_max=0.05,verbose=i_am_main(ranks),constraint_names=[:Vol,:UΓ_out]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl index 2fb8ce00..19598021 100644 --- a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl @@ -31,7 +31,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4 vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_nonlinear_thermal_compliance_ALM" + path = dirname(dirname(@__DIR__))*"/results/3d_nonlinear_thermal_compliance_ALM/" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -108,11 +109,12 @@ function main(mesh_partition,distribute,el_size) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index cae68f2d..d9da92ff 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -38,6 +38,7 @@ function main(mesh_partition,distribute,el_size,coef,step) α_coeff = 4 vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/3d_thermal_compliance_ALM_Nx$(el_size[1])_Coef$(coef)_Step$(step)" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -111,11 +112,12 @@ function main(mesh_partition,distribute,el_size,coef,step) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index 5be16714..49f97724 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -29,6 +29,7 @@ function main(mesh_partition,distribute,el_size) α_coeff = 4 vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM_MPI" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -100,11 +101,12 @@ function main(mesh_partition,distribute,el_size) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index e5399ae1..4b866b5f 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -27,6 +27,7 @@ function main(mesh_partition,distribute,el_size) α_coeff = 4 vf = 0.5 path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_MPI" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -101,11 +102,12 @@ function main(mesh_partition,distribute,el_size) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))]) end with_mpi() do distribute diff --git a/scripts/MPI/thermal_compliance_ALM.jl b/scripts/MPI/thermal_compliance_ALM.jl index f4208c11..b4f316e2 100644 --- a/scripts/MPI/thermal_compliance_ALM.jl +++ b/scripts/MPI/thermal_compliance_ALM.jl @@ -29,6 +29,7 @@ function main(mesh_partition,distribute) α_coeff = 4 vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -86,11 +87,12 @@ function main(mesh_partition,distribute) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/MPI/thermal_compliance_ALM_PETSc.jl b/scripts/MPI/thermal_compliance_ALM_PETSc.jl index a39f1a6a..8c032c04 100644 --- a/scripts/MPI/thermal_compliance_ALM_PETSc.jl +++ b/scripts/MPI/thermal_compliance_ALM_PETSc.jl @@ -29,6 +29,7 @@ function main(mesh_partition,distribute,el_size) α_coeff = 4 vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI+PETSc" + iter_mod = 10 i_am_main(ranks) && mkdir(path) ## FE Setup @@ -100,11 +101,12 @@ function main(mesh_partition,distribute,el_size) optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history;ranks=ranks) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/Serial/elastic_compliance_ALM.jl b/scripts/Serial/elastic_compliance_ALM.jl index a193d39b..c1f780db 100644 --- a/scripts/Serial/elastic_compliance_ALM.jl +++ b/scripts/Serial/elastic_compliance_ALM.jl @@ -26,7 +26,8 @@ function main() α_coeff = 4 vf = 0.4 g = VectorValue(0,-1) - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM" + path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -85,11 +86,12 @@ function main() optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main() \ No newline at end of file diff --git a/scripts/Serial/elastic_compliance_HPM.jl b/scripts/Serial/elastic_compliance_HPM.jl index 825e92f9..4e620db2 100644 --- a/scripts/Serial/elastic_compliance_HPM.jl +++ b/scripts/Serial/elastic_compliance_HPM.jl @@ -26,7 +26,8 @@ function main() α_coeff = 4 vf = 0.4 g = VectorValue(0,-1) - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_HPM" + path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_HPM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -86,11 +87,12 @@ function main() optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main(); \ No newline at end of file diff --git a/scripts/Serial/elastic_compliance_LM.jl b/scripts/Serial/elastic_compliance_LM.jl index 64b04677..b1be54a6 100644 --- a/scripts/Serial/elastic_compliance_LM.jl +++ b/scripts/Serial/elastic_compliance_LM.jl @@ -24,7 +24,8 @@ function main() η_coeff = 2 α_coeff = 4 g = VectorValue(0,-1) - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_LM" + path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_LM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -81,11 +82,12 @@ function main() ## Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main(); \ No newline at end of file diff --git a/scripts/Serial/hyperelastic_compliance_ALM.jl b/scripts/Serial/hyperelastic_compliance_ALM.jl index f2117446..e6b801dc 100644 --- a/scripts/Serial/hyperelastic_compliance_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_ALM.jl @@ -17,7 +17,8 @@ function main() η_coeff = 2 α_coeff = 4 vf = 0.6 - path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_ALM" + path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_ALM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -85,11 +86,12 @@ function main() optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main() \ No newline at end of file diff --git a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl index 0ebae329..1a10577c 100644 --- a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl @@ -17,7 +17,8 @@ function main() η_coeff = 2 α_coeff = 4 vf = 0.6 - path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_neohook_ALM" + path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_neohook_ALM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -99,11 +100,12 @@ function main() optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main() \ No newline at end of file diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index d4d60aa8..7ac70885 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -24,7 +24,8 @@ function main() η_coeff = 2 α_coeff = 4 vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM" + path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -85,11 +86,12 @@ function main() optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))]) end main() \ No newline at end of file diff --git a/scripts/Serial/inverter_ALM.jl b/scripts/Serial/inverter_ALM.jl index 85b28d89..9b1e4879 100644 --- a/scripts/Serial/inverter_ALM.jl +++ b/scripts/Serial/inverter_ALM.jl @@ -30,7 +30,8 @@ function main() δₓ = 0.2 ks = 0.1 g = VectorValue(0.5,0) - path = dirname(dirname(@__DIR__))*"/results/inverter_ALM" + path = dirname(dirname(@__DIR__))*"/results/inverter_ALM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -100,11 +101,12 @@ function main() optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol,:UΓ_out]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main() \ No newline at end of file diff --git a/scripts/Serial/inverter_HPM.jl b/scripts/Serial/inverter_HPM.jl index f79ca7e9..4f22c0f3 100644 --- a/scripts/Serial/inverter_HPM.jl +++ b/scripts/Serial/inverter_HPM.jl @@ -30,7 +30,8 @@ function main() δₓ = 0.2 ks = 0.1 g = VectorValue(0.5,0) - path = dirname(dirname(@__DIR__))*"/results/inverter_HPM_osc" + path = dirname(dirname(@__DIR__))*"/results/inverter_HPM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -102,11 +103,12 @@ function main() optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh; γ,γ_reinit,α_min=0.4,ls_enabled,verbose=true,constraint_names=[:Vol,:UΓ_out]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main() \ No newline at end of file diff --git a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl index 270eedcf..ba3f8d74 100644 --- a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl @@ -27,7 +27,8 @@ function main() η_coeff = 2 α_coeff = 4 vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/nonlinear_thermal_compliance_ALM" + path = dirname(dirname(@__DIR__))*"/results/nonlinear_thermal_compliance_ALM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -88,11 +89,12 @@ function main() optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it, uh, φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main() \ No newline at end of file diff --git a/scripts/Serial/thermal_compliance_ALM.jl b/scripts/Serial/thermal_compliance_ALM.jl index 171d8d49..425a63d5 100644 --- a/scripts/Serial/thermal_compliance_ALM.jl +++ b/scripts/Serial/thermal_compliance_ALM.jl @@ -26,7 +26,8 @@ function main() vf = 0.4 η_coeff = 2 α_coeff = 4 - path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM" + path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM/" + iter_mod = 10 mkdir(path) ## FE Setup @@ -86,11 +87,12 @@ function main() optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",optimiser.history) end it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end main() \ No newline at end of file diff --git a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl b/scripts/_dev/3d_hyperelastic_compliance_ALM.jl index 8066e3e6..2565536b 100644 --- a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/_dev/3d_hyperelastic_compliance_ALM.jl @@ -73,7 +73,7 @@ function main(mesh_partition,distribute,el_size,δₓ) ## Optimiser u = LevelSetTopOpt.forward_solve!(state_map,φh) uh = FEFunction(U,u) - write_vtk(Ω,path*"/struc_$δₓ",0,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"/struc_$δₓ",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end function main_alt(mesh_partition,distribute,el_size,gz) @@ -173,7 +173,7 @@ function main_alt(mesh_partition,distribute,el_size,gz) ## Optimiser u = LevelSetTopOpt.forward_solve!(state_map,φh) uh = FEFunction(U,u) - write_vtk(Ω,path*"/struc_neohook_$gz",0,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + writevtk(Ω,path*"/struc_neohook_$gz",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end with_mpi() do distribute diff --git a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl b/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl index aa2d019e..4ab969a6 100644 --- a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl +++ b/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl @@ -136,13 +136,14 @@ function main(mesh_partition,distribute,el_size,diag_assem::Bool) λi = optimiser.λ; Λi = optimiser.Λ print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi];ranks=ranks) write_history(history,path*"/history.csv";ranks=ranks) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] + iszero(it % 10) && writevtk(Ω,path*"out$it",cellfields=data) end it,Ji,Ci,Li = last(optimiser.history) λi = optimiser.λ; Λi = optimiser.Λ print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi];ranks=ranks) write_history(optimiser.history,path*"/history.csv";ranks=ranks) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))];iter_mod=1) + writevtk(Ω,path*"/out$it",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) end # RUN: mpiexecjl --project=. -n 8 julia ./scripts/inv_hom_block_assem_testing_3D_MPI.jl diff --git a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl b/scripts/_dev/inv_hom_block_assem_testing_full_script.jl index 75018ee6..f3c31fc2 100644 --- a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl +++ b/scripts/_dev/inv_hom_block_assem_testing_full_script.jl @@ -115,13 +115,14 @@ function main(diag_block) λi = optimiser.λ; Λi = optimiser.Λ print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi]) write_history(history,path*"/history.csv") - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] + iszero(it % 10) && writevtk(Ω,path*"out$it",cellfields=data) end it,Ji,Ci,Li = last(optimiser.history) λi = optimiser.λ; Λi = optimiser.Λ print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi]) write_history(optimiser.history,path*"/history.csv") - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))];iter_mod=1) + writevtk(Ω,path*"/out$it",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) end using LinearAlgebra diff --git a/src/LevelSetTopOpt.jl b/src/LevelSetTopOpt.jl index 39917e95..7b6ebc4d 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/LevelSetTopOpt.jl @@ -51,7 +51,6 @@ export update_labels! export initial_lsf export get_el_Δ export isotropic_elast_tensor -export write_vtk include("Advection.jl") export AdvectionStencil diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index fb9d74fe..b2380686 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -178,6 +178,10 @@ function Base.iterate(m::AugmentedLagrangian,state) update_mod, reinit_mod, ζ, Λ_max, γ_reinit, os_γ_mult = params.update_mod, params.reinit_mod, params.ζ, params.Λ_max, params.γ_reinit, params.os_γ_mult + ## Periodicially call GC + iszero(it % 50) && GC.gc(); + + ## Check stopping criteria if finished(m) return nothing end diff --git a/src/Optimisers/HilbertianProjection.jl b/src/Optimisers/HilbertianProjection.jl index c64a9d7f..9cb75952 100644 --- a/src/Optimisers/HilbertianProjection.jl +++ b/src/Optimisers/HilbertianProjection.jl @@ -321,6 +321,10 @@ function Base.iterate(m::HilbertianProjection,state) it, J, C, θ, dJ, dC, uh, φh, vel, φ_tmp, γ, os_it = state history, params = m.history, m.params + ## Periodicially call GC + iszero(it % 50) && GC.gc(); + + ## Check stopping criteria if finished(m) return nothing end diff --git a/src/Utilities.jl b/src/Utilities.jl index 82ba9f0f..aede0bd2 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -212,29 +212,4 @@ function isotropic_elast_tensor(D::Int,E::Number,v::Number) else @notimplemented end -end - -""" - write_vtk(Ω,path,it,entries::Vector{<:Pair};iter_mod=10) - -Write a VTK file to `path`. This functions in a similar way to -Gridap's `writevtk` function except we - -!!! note - This may be removed in future and replaced by - - ```(isone(it) || iszero(it % iter_mod)) && writevtk(Ω,path,cellfields=entries)``` - - or - - ```iszero(it-1 % iter_mod) && writevtk(Ω,path,cellfields=entries)``` -""" -function write_vtk(Ω,path,it,entries::Vector{<:Pair};iter_mod=10) # TODO: Rename to writevtk? - if isone(it) || iszero(it % iter_mod) - writevtk(Ω,path,cellfields=entries) - end - - if iszero(it % 10*iter_mod) - GC.gc() # TODO: Test in Julia 1.10.0 and check if fixed. - end -end +end \ No newline at end of file From d1633a91bc4ccc7d2d71202c6abd8c9508101480 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:32:49 +1000 Subject: [PATCH 15/90] Added paper scripts to later go in supplementary --- .../3d_hyperelastic_compliance_neohook_ALM.jl | 4 +- ...relastic_compliance_neohook_ALM_COMPARE.jl | 193 ----------------- scripts/_dev/Added_for_paper/thermal_MPI.jl | 88 -------- .../elast_comp_MPI_3D.jl} | 201 +++++++++--------- .../Paper_scripts/hyperelast_comp_MPI_3D.jl | 118 ++++++++++ .../_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 108 ++++++++++ scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 114 ++++++++++ .../Paper_scripts/jobs/elast_comp_MPI_3D.pbs | 16 ++ .../jobs/hyperelast_comp_MPI_3D.pbs | 16 ++ .../Paper_scripts/jobs/inverse_hom_MPI_3D.pbs | 16 ++ .../Paper_scripts/jobs/inverter_MPI_3D.pbs | 16 ++ .../Paper_scripts/jobs/therm_comp_MPI_3D.pbs | 17 ++ .../therm_comp_MPI.jl} | 17 +- .../therm_comp_MPI_3D.jl} | 20 +- .../therm_comp_serial.jl} | 6 +- 15 files changed, 547 insertions(+), 403 deletions(-) delete mode 100644 scripts/_dev/Added_for_paper/hyperelastic_compliance_neohook_ALM_COMPARE.jl delete mode 100644 scripts/_dev/Added_for_paper/thermal_MPI.jl rename scripts/_dev/{Added_for_paper/thermal_PETSc.jl => Paper_scripts/elast_comp_MPI_3D.jl} (50%) create mode 100644 scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl create mode 100644 scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl create mode 100644 scripts/_dev/Paper_scripts/inverter_MPI_3D.jl create mode 100644 scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs rename scripts/_dev/{Added_for_paper/thermal_MPI_PETSc.jl => Paper_scripts/therm_comp_MPI.jl} (86%) rename scripts/_dev/{Added_for_paper/thermal_MPI_PETSc_3D.jl => Paper_scripts/therm_comp_MPI_3D.jl} (87%) rename scripts/_dev/{Added_for_paper/thermal_serial.jl => Paper_scripts/therm_comp_serial.jl} (93%) diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index 0ddd1da4..cc428534 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -61,9 +61,9 @@ function main(mesh_partition,distribute,el_size) I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ ## Material properties - _E = 1000 + E = 1000 ν = 0.3 - μ, λ = _E/(2*(1 + ν)), _E*ν/((1 + ν)*(1 - 2*ν)) + μ, λ = E/(2*(1 + ν)), E*ν/((1 + ν)*(1 - 2*ν)) g = VectorValue(0,0,-100) ## Neohookean hyperelastic material diff --git a/scripts/_dev/Added_for_paper/hyperelastic_compliance_neohook_ALM_COMPARE.jl b/scripts/_dev/Added_for_paper/hyperelastic_compliance_neohook_ALM_COMPARE.jl deleted file mode 100644 index 673ae38c..00000000 --- a/scripts/_dev/Added_for_paper/hyperelastic_compliance_neohook_ALM_COMPARE.jl +++ /dev/null @@ -1,193 +0,0 @@ -using Gridap, LevelSetTopOpt - -""" - (Serial) Minimum hyperelastic (neohookean) compliance with augmented Lagrangian method in 2D. -""" -function main() - ## Parameters - order = 1 - xmax,ymax=2.0,1.0 - prop_Γ_N = 0.2 - dom = (0,xmax,0,ymax) - el_size = (400,200) - γ = 0.1 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(5order^2)/minimum(el_size) - η_coeff = 2 - α_coeff = 4 - vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/highres_hyperelastic_compliance_neohook_ALM" - mkdir(path) - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - vol_D = sum(∫(1)dΩ) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - ## Material properties - _E = 1000 - ν = 0.3 - μ, λ = _E/(2*(1 + ν)), _E*ν/((1 + ν)*(1 - 2*ν)) - g = VectorValue(0,-10) - - ## Neohookean hyperelastic material - # Deformation gradient - F(∇u) = one(∇u) + ∇u' - J(F) = sqrt(det(C(F))) - - # Derivative of green Strain - dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) - - # Right Caughy-green deformation tensor - C(F) = (F')⋅F - - # Constitutive law (Neo hookean) - function S(∇u) - Cinv = inv(C(F(∇u))) - μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv - end - - # Cauchy stress tensor and residual - σ(∇u) = (1.0/J(F(∇u)))*F(∇u)⋅S(∇u)⋅(F(∇u))' - res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE∘(∇(v),∇(u))) ⊙ (S∘∇(u))) )*dΩ - ∫(g⋅v)dΓ_N - - ## Optimisation functionals - Obj(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((dE∘(∇(u),∇(u))) ⊙ (S∘∇(u))))dΩ - Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; - dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) - - ## Setup solver and FE operators - state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - pcfs = PDEConstrainedFunctionals(Obj,[Vol],state_map,analytic_dC=[dVol]) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; - γ,γ_reinit,verbose=true,constraint_names=[:Vol]) - for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) - write_history(path*"/history.txt",optimiser.history) - end - it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) -end - -main() - -function main_LE_comparison() - ## Parameters - order = 1 - xmax,ymax=(2.0,1.0) - prop_Γ_N = 0.2 - dom = (0,xmax,0,ymax) - el_size = (400,200) - γ = 0.1 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(5order^2)/minimum(el_size) - C = isotropic_elast_tensor(2,1000,0.3) - η_coeff = 2 - α_coeff = 4 - vf = 0.4 - g = VectorValue(0,-10) - path = dirname(dirname(@__DIR__))*"/results/highres_LE_comparison" - mkdir(path) - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size) - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - vol_D = sum(∫(1)dΩ) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v⋅g)dΓ_N - - ## Optimisation functionals - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(u)))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; - Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; - dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) - - ## Setup solver and FE operators - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dJ=dJ,analytic_dC=[dVol]) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; - γ,γ_reinit,verbose=true,constraint_names=[:Vol]) - for (it,uh,φh) in optimiser - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) - write_history(path*"/history.txt",optimiser.history) - end - it = get_history(optimiser).niter; uh = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) -end - -main_LE_comparison() \ No newline at end of file diff --git a/scripts/_dev/Added_for_paper/thermal_MPI.jl b/scripts/_dev/Added_for_paper/thermal_MPI.jl deleted file mode 100644 index 446c0a54..00000000 --- a/scripts/_dev/Added_for_paper/thermal_MPI.jl +++ /dev/null @@ -1,88 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax = ymax = 1.0 # Domain size - dom = (0,xmax,0,ymax) # Bounding domain - el_size = (200,200) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) # @$\lvert\lvert$@ - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Advection tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "./results/tut1_MPI_FIXEDSign/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - solver = PETScLinearSolver() - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map, - analytic_dJ=dJ,analytic_dC=[dC]) - # Velocity extension - α = 4*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension(a_hilb, U_reg, V_reg) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; - γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|nabla(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|nabla(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (2,2) - main(mesh_partition,distribute) -end \ No newline at end of file diff --git a/scripts/_dev/Added_for_paper/thermal_PETSc.jl b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl similarity index 50% rename from scripts/_dev/Added_for_paper/thermal_PETSc.jl rename to scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl index 9b1383cf..b3bd339d 100644 --- a/scripts/_dev/Added_for_paper/thermal_PETSc.jl +++ b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl @@ -1,99 +1,104 @@ -using LevelSetTopOpt, Gridap, GridapPETSc, SparseMatricesCSR - -function main() - # FE parameters - order = 1 # Finite element order - xmax = ymax = 1.0 # Domain size - dom = (0,xmax,0,ymax) # Bounding domain - el_size = (200,200) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "./results/tut1_PETSc/" # Output path - mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = PETScLinearSolver() - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map, - analytic_dJ=dJ,analytic_dC=[dC]) - # Velocity extension - α = 4*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = solver - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; - γ,γ_reinit,verbose=true,constraint_names=[:Vol]) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser)) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" -GridapPETSc.with(args=split(solver_options)) do - main() +using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, + SparseMatricesCSR + +function main(mesh_partition,distribute) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + # FE parameters + order = 1 # Finite element order + xmax,ymax,zmax = (2.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + el_size = (160,80,80) # Mesh partition size + prop_Γ_N = 0.2 # Γ_N size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + iter_mod = 10 # VTK Output modulo + path = "./results/elast_comp_MPI_3D/" # Output path + i_am_main(ranks) && mkpath(path) # Create path + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + # Triangulation and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(v⋅g)dΓ_N + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + solver = ElasticitySolver(V) + state_map = AffineFEStateMap( + a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + ls = solver,adjoint_ls = solver + ) + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(u)))dΩ + dJ(q,u,φ,dΩ,dΓ_N) = ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) + # Velocity extension + α = 4*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension( + a_hilb, U_reg, V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() + ) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + verbose=i_am_main(ranks)) + # Solve + for (it,uh,φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) + write_history(path*"/history.txt",get_history(optimiser);ranks) + end + # Final structure + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, + "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +end + +with_mpi() do distribute + mesh_partition = (5,5,5) + solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + GridapPETSc.with(args=split(solver_options)) do + main(mesh_partition,distribute) + end end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl new file mode 100644 index 00000000..919e046e --- /dev/null +++ b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl @@ -0,0 +1,118 @@ +using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, + SparseMatricesCSR + +function main(mesh_partition,distribute) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + # FE parameters + order = 1 # Finite element order + xmax,ymax,zmax = (2.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + el_size = (160,80,80) # Mesh partition size + prop_Γ_N = 0.2 # Γ_N size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + E = 1000 # Young's modulus + ν = 0.3 # Poisson's ratio + μ, λ = E/(2*(1 + ν)), E*ν/((1 + ν)*(1 - 2*ν)) # Lame constants + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + iter_mod = 10 # VTK Output modulo + path = "./results/hyperelast_comp_MPI_3D/" # Output path + i_am_main(ranks) && mkpath(path) # Create path + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + # Triangulation and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + ## Piola-Kirchhoff tensor + function S(∇u) + Cinv = inv(C(F(∇u))) + μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv + end + ## Derivative of Green strain + dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) + ## Right Cauchy-Green deformation tensor + C(F) = (F')⋅F + ## Deformation gradient tensor + F(∇u) = one(∇u) + ∇u' + ## Volume change + J(F) = sqrt(det(C(F))) + ## Residual + res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE ∘ (∇(v),∇(u))) ⊙ (S ∘ ∇(u))) )*dΩ - ∫(g⋅v)dΓ_N + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + lin_solver = ElasticitySolver(V) + nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose=i_am_main(ranks)) + state_map = NonlinearFEStateMap( + res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + nls = nl_solver, adjoint_ls = lin_solver + ) + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((dE ∘ (∇(u),∇(u))) ⊙ (S ∘ ∇(u))))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map,analytic_dC=[dC1]) + # Velocity extension + α = 4*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension( + a_hilb, U_reg, V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() + ) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + verbose=i_am_main(ranks)) + # Solve + for (it,uh,φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) + write_history(path*"/history.txt",get_history(optimiser);ranks) + end + # Final structure + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, + "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +end + +with_mpi() do distribute + mesh_partition = (5,5,5) + solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + GridapPETSc.with(args=split(solver_options)) do + main(mesh_partition,distribute) + end +end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl new file mode 100644 index 00000000..eab453d0 --- /dev/null +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -0,0 +1,108 @@ +using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, + SparseMatricesCSR + +function main(mesh_partition,distribute) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + # FE parameters + order = 1 # Finite element order + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + el_size = (100,100,100) # Mesh partition size + f_Γ_D(x) = iszero(x) # Γ_D indicator function + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + lsf_func(x) = cos(2π*x[1]) + cos(2π*x[2]) + # Initial level set function + cos(2π*x[3]) + iter_mod = 10 # VTK Output modulo + path = "./results/inverse_hom_MPI_3D/" # Output path + i_am_main(ranks) && mkpath(path) # Create path + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)); + update_labels!(1,model,f_Γ_D,"origin") + # Triangulation and measures + Ω = Triangulation(model) + dΩ = Measure(Ω,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["origin"]) + U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar) + U_reg = TrialFESpace(V_reg) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + εᴹ = (TensorValue(1.,0.,0.,0.,0.,0.,0.,0.,0.), + TensorValue(0.,0.,0.,0.,1.,0.,0.,0.,0.), + TensorValue(0.,0.,0.,0.,0.,0.,0.,0.,1.), + TensorValue(0.,0.,0.,0.,0.,1/2,0.,1/2,0.), + TensorValue(0.,0.,1/2,0.,0.,0.,1/2,0.,0.), + TensorValue(0.,1/2,0.,1/2,0.,0.,0.,0.,0.)) + a(u,v,φ,dΩ) = ∫((I ∘ φ) * C ⊙ ε(u) ⊙ ε(v))dΩ + l = [(v,φ,dΩ) -> ∫(-(I ∘ φ) * C ⊙ εᴹ[i] ⊙ ε(v))dΩ for i in 1:6] + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + solver = ElasticitySolver(V) + state_map = RepeatingAffineFEStateMap( + 6,a,l,U,V,V_φ,U_reg,φh,dΩ; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + ls = solver, adjoint_ls = solver + ) + # Objective and constraints + Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ + dCᴴ(r,s,q,u,φ,dΩ) = ∫(-q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + κ(u,φ,dΩ) = -1/9*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+Cᴴ(3,3,u,φ,dΩ)+ + 2*(Cᴴ(1,2,u,φ,dΩ)+Cᴴ(1,3,u,φ,dΩ)+Cᴴ(2,3,u,φ,dΩ))) + dκ(q,u,φ,dΩ) = -1/9*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+dCᴴ(3,3,q,u,φ,dΩ)+ + 2*(dCᴴ(1,2,q,u,φ,dΩ)+dCᴴ(1,3,q,u,φ,dΩ)+dCᴴ(2,3,q,u,φ,dΩ))) + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(κ,[C1],state_map, + analytic_dJ=dκ,analytic_dC=[dC1]) + # Velocity extension + α = 4*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension( + a_hilb, U_reg, V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() + ) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + verbose=i_am_main(ranks)) + # Solve + for (it,uh,φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) + write_history(path*"/history.txt",get_history(optimiser);ranks) + end + # Final structure + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, + "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))]) +end + +with_mpi() do distribute + mesh_partition = (5,5,5) + solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + GridapPETSc.with(args=split(solver_options)) do + main(mesh_partition,distribute) + end +end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl new file mode 100644 index 00000000..0dbac675 --- /dev/null +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -0,0 +1,114 @@ +using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, + SparseMatricesCSR + +function main(mesh_partition,distribute) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + # FE parameters + order = 1 # Finite element order + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + el_size = (100,100,100) # Mesh partition size + f_Γ_in(x) = (x[1] ≈ 0.0) && # Γ_in indicator function + (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) + f_Γ_out(x) = (x[1] ≈ 1.0) && # Γ_out indicator function + (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function + (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + sphere(x,(xc,yc,zc)) = -sqrt((x[1]-xc)^2+(x[2]-yc)^2+(x[3]-zc)^2) + 0.2 + lsf_func(x) = max(initial_lsf(4,0.2)(x), # Initial level set function + sphere(x,(1,0,0)),sphere(x,(1,0,1)),sphere(x,(1,1,0)),sphere(x,(1,1,1))) + lsf_func = initial_lsf(4,0.2) # Initial level set function + iter_mod = 10 # VTK Output modulo + path = "./results/inverter_MPI_3D/" # Output path + i_am_main(ranks) && mkpath(path) # Create path + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + update_labels!(1,model,f_Γ_in,"Gamma_in") + update_labels!(2,model,f_Γ_out,"Gamma_out") + update_labels!(4,model,f_Γ_D,"Gamma_D") + # Triangulation and measures + Ω = Triangulation(model) + Γ_in = BoundaryTriangulation(model,tags="Gamma_in") + Γ_out = BoundaryTriangulation(model,tags="Gamma_out") + dΩ = Measure(Ω,2*order) + dΓ_in = Measure(Γ_in,2*order) + dΓ_out = Measure(Γ_out,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_in","Gamma_out"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ); + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + a(u,v,φ,dΩ,dΓ_in,dΓ_out) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + ∫(ks*(u⋅v))dΓ_out + l(v,φ,dΩ,dΓ_in,dΓ_out) = ∫(v⋅g)dΓ_in + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + solver = ElasticitySolver(V) + state_map = AffineFEStateMap( + a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + ls = solver,adjoint_ls = solver + ) + # Objective and constraints + e₁ = VectorValue(1,0,0) + vol_Γ_in = sum(∫(1)dΓ_in) + vol_Γ_out = sum(∫(1)dΓ_out) + vol_D = sum(∫(1)dΩ) + J(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅e₁)/vol_Γ_in)dΓ_in + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + C2(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out + pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map, + analytic_dJ=dJ,analytic_dC=[dC1,nothing]) + # Velocity extension + α = 4*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension( + a_hilb, U_reg, V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() + ) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + verbose=i_am_main(ranks)) + # Solve + for (it,uh,φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) + write_history(path*"/history.txt",get_history(optimiser);ranks) + end + # Final structure + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, + "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +end + +with_mpi() do distribute + mesh_partition = (5,5,5) + solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + GridapPETSc.with(args=split(solver_options)) do + main(mesh_partition,distribute) + end +end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs new file mode 100644 index 00000000..38e3aaa8 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs @@ -0,0 +1,16 @@ +#!/bin/bash -l +#PBS -P LSTO +#PBS -N elast_comp_MPI_3D + +#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 +#PBS -l walltime=50:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-ompi.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" + +mpirun --hostfile $PBS_NODEFILE \ + julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs new file mode 100644 index 00000000..a9c89845 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs @@ -0,0 +1,16 @@ +#!/bin/bash -l +#PBS -P LSTO +#PBS -N hyperelast_comp_MPI_3D + +#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 +#PBS -l walltime=50:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-ompi.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" + +mpirun --hostfile $PBS_NODEFILE \ + julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs new file mode 100644 index 00000000..d1a72278 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs @@ -0,0 +1,16 @@ +#!/bin/bash -l +#PBS -P LSTO +#PBS -N inverse_hom_MPI_3D + +#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 +#PBS -l walltime=50:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-ompi.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" + +mpirun --hostfile $PBS_NODEFILE \ + julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs new file mode 100644 index 00000000..aeeada29 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs @@ -0,0 +1,16 @@ +#!/bin/bash -l +#PBS -P LSTO +#PBS -N inverter_MPI_3D + +#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 +#PBS -l walltime=50:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-ompi.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" + +mpirun --hostfile $PBS_NODEFILE \ + julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs new file mode 100644 index 00000000..795dc33d --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs @@ -0,0 +1,17 @@ +#!/bin/bash -l + +#PBS -P LSTO +#PBS -N therm_comp_MPI_3D + +#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 +#PBS -l walltime=23:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-ompi.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" + +mpirun --hostfile $PBS_NODEFILE \ + julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl \ No newline at end of file diff --git a/scripts/_dev/Added_for_paper/thermal_MPI_PETSc.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl similarity index 86% rename from scripts/_dev/Added_for_paper/thermal_MPI_PETSc.jl rename to scripts/_dev/Paper_scripts/therm_comp_MPI.jl index ef08aa72..a0b1afeb 100644 --- a/scripts/_dev/Added_for_paper/thermal_MPI_PETSc.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl @@ -5,7 +5,7 @@ function main(mesh_partition,distribute) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order - xmax = ymax = 1.0 # Domain size + xmax,ymax = (1.0,1.0) # Domain size dom = (0,xmax,0,ymax) # Bounding domain el_size = (200,200) # Mesh partition size prop_Γ_N = 0.2 # Γ_N size parameter @@ -25,7 +25,7 @@ function main(mesh_partition,distribute) vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/tut1_MPI_PETSc/" # Output path + path = "./results/therm_comp_MPI/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -64,10 +64,10 @@ function main(mesh_partition,distribute) J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map, - analytic_dJ=dJ,analytic_dC=[dC]) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) # Velocity extension α = 4*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ @@ -80,12 +80,11 @@ function main(mesh_partition,distribute) scheme = FirstOrderStencil(length(el_size),Float64) stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; - γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",get_history(optimiser);ranks) end # Final structure diff --git a/scripts/_dev/Added_for_paper/thermal_MPI_PETSc_3D.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl similarity index 87% rename from scripts/_dev/Added_for_paper/thermal_MPI_PETSc_3D.jl rename to scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl index 90addf1d..0fb2889c 100644 --- a/scripts/_dev/Added_for_paper/thermal_MPI_PETSc_3D.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl @@ -5,8 +5,8 @@ function main(mesh_partition,distribute) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order - xmax = ymax = 1.0 # Domain size - dom = (0,xmax,0,ymax) # Bounding domain + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain el_size = (150,150,150) # Mesh partition size prop_Γ_N = 0.2 # Γ_N size parameter prop_Γ_D = 0.2 # Γ_D size parameter @@ -27,7 +27,7 @@ function main(mesh_partition,distribute) vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/tut1_MPI_PETSc_3D/" # Output path + path = "./results/therm_comp_MPI_3D/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -66,10 +66,10 @@ function main(mesh_partition,distribute) J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map, - analytic_dJ=dJ,analytic_dC=[dC]) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) # Velocity extension α = 4*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ @@ -82,12 +82,12 @@ function main(mesh_partition,distribute) scheme = FirstOrderStencil(length(el_size),Float64) stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; - γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",get_history(optimiser);ranks) end # Final structure diff --git a/scripts/_dev/Added_for_paper/thermal_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl similarity index 93% rename from scripts/_dev/Added_for_paper/thermal_serial.jl rename to scripts/_dev/Paper_scripts/therm_comp_serial.jl index 115e1b5e..055f5ad9 100644 --- a/scripts/_dev/Added_for_paper/thermal_serial.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_serial.jl @@ -23,7 +23,7 @@ function main() vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/tut1/" # Output path + path = "./results/therm_comp_serial/" # Output path mkpath(path) # Create path # Model model = CartesianDiscreteModel(dom,el_size); @@ -65,8 +65,8 @@ function main() scheme = FirstOrderStencil(length(el_size),Float64) stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; - γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + verbose=true) # Solve for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] From dbb13b0f62dd298b1f5ba4d61ef3dff15f85c165 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:39:26 +1000 Subject: [PATCH 16/90] Consistency --- scripts/_dev/Paper_scripts/therm_comp_serial.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/_dev/Paper_scripts/therm_comp_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl index 055f5ad9..6c657510 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_serial.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_serial.jl @@ -53,10 +53,10 @@ function main() J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map, - analytic_dJ=dJ,analytic_dC=[dC]) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) # Velocity extension α = 4*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ From 7253fc4ec1916758b3b814e4b592633fde42ac81 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 6 Apr 2024 10:32:23 +1000 Subject: [PATCH 17/90] typo fix --- src/Advection.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Advection.jl b/src/Advection.jl index ebd31306..241af032 100644 --- a/src/Advection.jl +++ b/src/Advection.jl @@ -74,7 +74,7 @@ function reinit!(::FirstOrderStencil{2,T},φ_new,φ,vel,Δt,Δx,isperiodic,cache # Sign approximation ∇⁺ .= @. (D⁺ʸ - D⁻ʸ)/(2Δy); ~yperiodic ? ∇⁺[:,[1,end]] .= zero(T) : 0; ∇⁻ .= @. (D⁺ˣ - D⁻ˣ)/(2Δx); ~xperiodic ? ∇⁻[[1,end],:] .= zero(T) : 0; - ϵₛ = maximum((Δx,Δy)) + ϵₛ = minimum((Δx,Δy)) vel .= @. φ/sqrt(φ^2 + ϵₛ^2*(∇⁺^2+∇⁻^2)) # Forward (+) & Backward (-) D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end] .= zero(T) : 0; @@ -129,7 +129,7 @@ function reinit!(::FirstOrderStencil{3,T},φ_new,φ,vel,Δt,Δx,isperiodic,cache ∇⁻ .= @. (D⁺ˣ - D⁻ˣ)/(2Δx); ~xperiodic ? ∇⁻[[1,end],:,:] .= zero(T) : 0; ∇⁺ .= @. ∇⁺^2+∇⁻^2 # |∇φ|² (partially computed) ∇⁻ .= @. (D⁺ᶻ - D⁻ᶻ)/(2Δz); ~xperiodic ? ∇⁻[:,:,[1,end]] .= zero(T) : 0; - ϵₛ = maximum((Δx,Δy)) + ϵₛ = minimum((Δx,Δy,Δz)) vel .= @. φ/sqrt(φ^2 + ϵₛ^2*(∇⁺+∇⁻^2)) # Forward (+) & Backward (-) D⁺ʸ .= (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end,:] .= zero(T) : 0; From 2d613e52a04204009972ca741dd2b5baf667a2d3 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 7 Apr 2024 10:10:24 +1000 Subject: [PATCH 18/90] Several script tuning changes --- scripts/MPI/3d_elastic_compliance_ALM.jl | 15 ++- scripts/MPI/3d_hyperelastic_compliance_ALM.jl | 18 +-- .../3d_hyperelastic_compliance_neohook_ALM.jl | 18 +-- scripts/MPI/3d_inverse_homenisation_ALM.jl | 15 ++- scripts/MPI/3d_inverter_ALM.jl | 15 ++- scripts/MPI/3d_inverter_HPM.jl | 15 ++- .../3d_nonlinear_thermal_compliance_ALM.jl | 15 ++- scripts/MPI/3d_thermal_compliance_ALM.jl | 22 ++-- scripts/MPI/elastic_compliance_ALM.jl | 4 +- scripts/MPI/inverse_homenisation_ALM.jl | 4 +- .../MPI/jobs/3d_elastic_compliance_ALM.pbs | 13 ++- .../jobs/3d_hyperelastic_compliance_ALM.pbs | 13 ++- ...3d_hyperelastic_compliance_neohook_ALM.pbs | 13 ++- .../MPI/jobs/3d_inverse_homenisation_ALM.pbs | 13 ++- scripts/MPI/jobs/3d_inverter_ALM.pbs | 14 ++- scripts/MPI/jobs/3d_inverter_HPM.pbs | 14 ++- .../3d_nonlinear_thermal_compliance_ALM.pbs | 14 ++- .../MPI/jobs/3d_thermal_compliance_ALM.pbs | 20 ++-- scripts/MPI/thermal_compliance_ALM.jl | 4 +- scripts/MPI/thermal_compliance_ALM_PETSc.jl | 4 +- scripts/Serial/elastic_compliance_ALM.jl | 4 +- scripts/Serial/elastic_compliance_HPM.jl | 4 +- scripts/Serial/elastic_compliance_LM.jl | 4 +- scripts/Serial/hyperelastic_compliance_ALM.jl | 4 +- .../hyperelastic_compliance_neohook_ALM.jl | 4 +- scripts/Serial/inverse_homenisation_ALM.jl | 4 +- scripts/Serial/inverter_ALM.jl | 4 +- scripts/Serial/inverter_HPM.jl | 4 +- .../nonlinear_thermal_compliance_ALM.jl | 4 +- scripts/Serial/thermal_compliance_ALM.jl | 6 +- .../thermal_compliance_ALM_higherorderlsf.jl | 104 ++++++++++++++++++ .../_dev/Paper_scripts/elast_comp_MPI_3D.jl | 4 +- .../Paper_scripts/hyperelast_comp_MPI_3D.jl | 4 +- .../_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 4 +- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 4 +- .../Paper_scripts/jobs/elast_comp_MPI_3D.pbs | 3 +- .../jobs/hyperelast_comp_MPI_3D.pbs | 3 +- .../Paper_scripts/jobs/inverse_hom_MPI_3D.pbs | 3 +- .../Paper_scripts/jobs/inverter_MPI_3D.pbs | 3 +- scripts/_dev/Paper_scripts/therm_comp_MPI.jl | 4 +- .../_dev/Paper_scripts/therm_comp_MPI_3D.jl | 4 +- .../_dev/Paper_scripts/therm_comp_serial.jl | 6 +- src/Optimisers/AugmentedLagrangian.jl | 6 +- 43 files changed, 320 insertions(+), 137 deletions(-) create mode 100644 scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl diff --git a/scripts/MPI/3d_elastic_compliance_ALM.jl b/scripts/MPI/3d_elastic_compliance_ALM.jl index 8ae4b8c3..8bf651f1 100644 --- a/scripts/MPI/3d_elastic_compliance_ALM.jl +++ b/scripts/MPI/3d_elastic_compliance_ALM.jl @@ -1,6 +1,13 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) + """ (MPI) Minimum elastic compliance with augmented Lagrangian method in 3D. @@ -21,12 +28,12 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax,0,zmax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/5) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(3,1.,0.3) g = VectorValue(0,0,-1) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/3d_elastic_compliance_ALM/" iter_mod = 10 @@ -112,8 +119,8 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - mesh_partition = (5,5,5) - el_size = (160,80,80) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" diff --git a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl index ad197331..8c24bbcb 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl @@ -3,11 +3,15 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, using GridapSolvers: NewtonSolver +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) + """ (MPI) Minimum hyperelastic compliance with augmented Lagrangian method in 3D. - - Optimisation problem: - ... """ function main(mesh_partition,distribute,el_size) ranks = distribute(LinearIndices((prod(mesh_partition),))) @@ -19,10 +23,10 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax,0,zmax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_ALM/" iter_mod = 10 @@ -118,8 +122,8 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - mesh_partition = (5,5,5) - el_size = (160,80,80) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index cc428534..662071b7 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -3,11 +3,15 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, using GridapSolvers: NewtonSolver +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) + """ (MPI) Minimum hyperelastic compliance with augmented Lagrangian method in 3D. - - Optimisation problem: - ... """ function main(mesh_partition,distribute,el_size) ranks = distribute(LinearIndices((prod(mesh_partition),))) @@ -19,10 +23,10 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax,0,zmax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_neohook_ALM/" iter_mod = 10 @@ -132,8 +136,8 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - mesh_partition = (5,5,5) - el_size = (160,80,80) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index 2769375b..a0df9c4b 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -1,6 +1,13 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) + """ (MPI) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 3D. @@ -20,11 +27,11 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax,0,zmax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(3,1.,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.5 path = dirname(dirname(@__DIR__))*"/results/3d_inverse_homenisation_ALM/" iter_mod = 10 @@ -116,8 +123,8 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - mesh_partition = (5,5,5) - el_size = (100,100,100) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" diff --git a/scripts/MPI/3d_inverter_ALM.jl b/scripts/MPI/3d_inverter_ALM.jl index 1e34d67e..fde12b40 100644 --- a/scripts/MPI/3d_inverter_ALM.jl +++ b/scripts/MPI/3d_inverter_ALM.jl @@ -1,6 +1,13 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) + """ (MPI) Inverter mechanism with Hilbertian projection method in 3D. @@ -23,11 +30,11 @@ function main(mesh_partition,distribute,el_size) dom = (0,1,0,1,0,1) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(3,1.0,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf=0.4 δₓ=0.5 ks = 0.01 @@ -130,8 +137,8 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - mesh_partition = (5,5,5) - el_size = (100,100,100) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" diff --git a/scripts/MPI/3d_inverter_HPM.jl b/scripts/MPI/3d_inverter_HPM.jl index 1e051812..b645ab9c 100644 --- a/scripts/MPI/3d_inverter_HPM.jl +++ b/scripts/MPI/3d_inverter_HPM.jl @@ -1,6 +1,13 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) + """ (MPI) Inverter mechanism with Hilbertian projection method in 3D. @@ -23,11 +30,11 @@ function main(mesh_partition,distribute,el_size) dom = (0,1,0,1,0,1) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(3,1.0,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf=0.4 δₓ=0.5 ks = 0.01 @@ -131,8 +138,8 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - mesh_partition = (5,5,5) - el_size = (100,100,100) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" diff --git a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl index 19598021..8aab7ed2 100644 --- a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl @@ -3,6 +3,13 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, using GridapSolvers: NewtonSolver +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) + """ (MPI) Minimum thermal compliance with augmented Lagrangian method in 3D with nonlinear diffusivity. @@ -26,10 +33,10 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax,0,zmax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/3d_nonlinear_thermal_compliance_ALM/" iter_mod = 10 @@ -118,8 +125,8 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - mesh_partition = (5,5,5) - el_size = (150,150,150) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index d9da92ff..eded269d 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -1,14 +1,12 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -using GridapSolvers: NewtonSolver - -# global elx = parse(Int,ARGS[1]) -# global ely = parse(Int,ARGS[2]) -# global elz = parse(Int,ARGS[3]) -# global Px = parse(Int,ARGS[4]) -# global Py = parse(Int,ARGS[5]) -# global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) """ (MPI) Minimum thermal compliance with augmented Lagrangian method in 3D. @@ -31,11 +29,11 @@ function main(mesh_partition,distribute,el_size,coef,step) dom = (0,xmax,0,ymax,0,zmax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/step) + max_steps = floor(Int,order*minimum(el_size)/step) tol = 1/(coef*order^2)/minimum(el_size) κ = 1 η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/3d_thermal_compliance_ALM_Nx$(el_size[1])_Coef$(coef)_Step$(step)" iter_mod = 10 @@ -121,8 +119,8 @@ function main(mesh_partition,distribute,el_size,coef,step) end with_mpi() do distribute - mesh_partition = (5,5,5)#(Px,Py,Pz) - el_size = (150,150,150)#(elx,ely,elz) + mesh_partition = (Px,Py,Pz) + el_size = (elx,ely,elz) all_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index 49f97724..21f8ce9a 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -21,12 +21,12 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.,0.3) g = VectorValue(0,-1) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM_MPI" iter_mod = 10 diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index 4b866b5f..e9a736db 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -20,11 +20,11 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax) γ = 0.05 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.5 path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_MPI" iter_mod = 10 diff --git a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs index 3d6df3ef..81d10175 100644 --- a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs @@ -3,7 +3,7 @@ #PBS -N 3d_elastic_compliance_ALM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh @@ -11,6 +11,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_elastic_compliance_ALM.jl +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_elastic_compliance_ALM.jl \ + 160 \ + 80 \ + 80 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs index 19e1bde9..9a9d94c6 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs @@ -3,7 +3,7 @@ #PBS -N 3d_hyperelastic_compliance_ALM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh @@ -11,6 +11,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_ALM.jl \ + 160 \ + 80 \ + 80 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs index e100e2e4..5b7ef3f7 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs @@ -3,7 +3,7 @@ #PBS -N 3d_hyperelastic_compliance_neohook_ALM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh @@ -11,6 +11,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl \ + 160 \ + 80 \ + 80 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs index 111cb9a1..bf1e09f4 100644 --- a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs @@ -3,7 +3,7 @@ #PBS -N 3d_inverse_homenisation_ALM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh @@ -11,6 +11,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_inverse_homenisation_ALM.jl +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_inverse_homenisation_ALM.jl \ + 100 \ + 100 \ + 100 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_inverter_ALM.pbs b/scripts/MPI/jobs/3d_inverter_ALM.pbs index 7499fd5a..5e80b93d 100644 --- a/scripts/MPI/jobs/3d_inverter_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverter_ALM.pbs @@ -1,9 +1,10 @@ #!/bin/bash -l + #PBS -P LSTO #PBS -N 3d_inverter_ALM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh @@ -11,6 +12,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_inverter_ALM.jl +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_inverter_ALM.jl \ + 100 \ + 100 \ + 100 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_inverter_HPM.pbs b/scripts/MPI/jobs/3d_inverter_HPM.pbs index b4092519..c95b0423 100644 --- a/scripts/MPI/jobs/3d_inverter_HPM.pbs +++ b/scripts/MPI/jobs/3d_inverter_HPM.pbs @@ -1,9 +1,10 @@ #!/bin/bash -l + #PBS -P LSTO #PBS -N 3d_inverter_HPM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh @@ -11,6 +12,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_inverter_HPM.jl +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_inverter_HPM.jl \ + 100 \ + 100 \ + 100 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs index acbc4a6c..3b8774a6 100644 --- a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs @@ -1,9 +1,10 @@ #!/bin/bash -l + #PBS -P LSTO #PBS -N 3d_nonlinear_thermal_compliance_ALM #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh @@ -11,6 +12,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl \ + 100 \ + 100 \ + 100 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs index d71b2b8f..5451c039 100644 --- a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs @@ -12,15 +12,11 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_thermal_compliance_ALM.jl - -# mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ -# $PROJECT_DIR/scripts/MPI/3d_thermal_compliance_ALM.jl \ -# 150 \ -# 150 \ -# 150 \ -# 5 \ -# 5 \ -# 5 \ No newline at end of file +mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ + $PROJECT_DIR/scripts/MPI/3d_thermal_compliance_ALM.jl \ + 150 \ + 150 \ + 150 \ + 5 \ + 5 \ + 5 \ No newline at end of file diff --git a/scripts/MPI/thermal_compliance_ALM.jl b/scripts/MPI/thermal_compliance_ALM.jl index b4f316e2..9b807c90 100644 --- a/scripts/MPI/thermal_compliance_ALM.jl +++ b/scripts/MPI/thermal_compliance_ALM.jl @@ -22,11 +22,11 @@ function main(mesh_partition,distribute) el_size = (200,200) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) κ = 1 η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI" iter_mod = 10 diff --git a/scripts/MPI/thermal_compliance_ALM_PETSc.jl b/scripts/MPI/thermal_compliance_ALM_PETSc.jl index 8c032c04..8a3ce6d5 100644 --- a/scripts/MPI/thermal_compliance_ALM_PETSc.jl +++ b/scripts/MPI/thermal_compliance_ALM_PETSc.jl @@ -22,11 +22,11 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) κ = 1 η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI+PETSc" iter_mod = 10 diff --git a/scripts/Serial/elastic_compliance_ALM.jl b/scripts/Serial/elastic_compliance_ALM.jl index c1f780db..c313ef68 100644 --- a/scripts/Serial/elastic_compliance_ALM.jl +++ b/scripts/Serial/elastic_compliance_ALM.jl @@ -19,11 +19,11 @@ function main() el_size = (200,100) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 g = VectorValue(0,-1) path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM/" diff --git a/scripts/Serial/elastic_compliance_HPM.jl b/scripts/Serial/elastic_compliance_HPM.jl index 4e620db2..e7fe84c8 100644 --- a/scripts/Serial/elastic_compliance_HPM.jl +++ b/scripts/Serial/elastic_compliance_HPM.jl @@ -19,11 +19,11 @@ function main() el_size = (200,100) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 g = VectorValue(0,-1) path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_HPM/" diff --git a/scripts/Serial/elastic_compliance_LM.jl b/scripts/Serial/elastic_compliance_LM.jl index b1be54a6..004e2119 100644 --- a/scripts/Serial/elastic_compliance_LM.jl +++ b/scripts/Serial/elastic_compliance_LM.jl @@ -18,11 +18,11 @@ function main() el_size = (200,100) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ g = VectorValue(0,-1) path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_LM/" iter_mod = 10 diff --git a/scripts/Serial/hyperelastic_compliance_ALM.jl b/scripts/Serial/hyperelastic_compliance_ALM.jl index e6b801dc..fe45ee8e 100644 --- a/scripts/Serial/hyperelastic_compliance_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_ALM.jl @@ -12,10 +12,10 @@ function main() el_size = (200,200) γ = 0.05 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.6 path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_ALM/" iter_mod = 10 diff --git a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl index 1a10577c..c212f0ef 100644 --- a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl @@ -12,10 +12,10 @@ function main() el_size = (200,200) γ = 0.05 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.6 path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_neohook_ALM/" iter_mod = 10 diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index 7ac70885..7779b851 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -18,11 +18,11 @@ function main() el_size = (200,200) γ = 0.05 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.5 path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM/" iter_mod = 10 diff --git a/scripts/Serial/inverter_ALM.jl b/scripts/Serial/inverter_ALM.jl index 9b1e4879..d1144e2f 100644 --- a/scripts/Serial/inverter_ALM.jl +++ b/scripts/Serial/inverter_ALM.jl @@ -21,11 +21,11 @@ function main() el_size = (200,100) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.0,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 δₓ = 0.2 ks = 0.1 diff --git a/scripts/Serial/inverter_HPM.jl b/scripts/Serial/inverter_HPM.jl index 4f22c0f3..ae21a683 100644 --- a/scripts/Serial/inverter_HPM.jl +++ b/scripts/Serial/inverter_HPM.jl @@ -21,11 +21,11 @@ function main() el_size = (200,100) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.0,0.3) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 δₓ = 0.2 ks = 0.1 diff --git a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl index ba3f8d74..edbc0b1b 100644 --- a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl @@ -22,10 +22,10 @@ function main() el_size = (200,200) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5order^2)/minimum(el_size) η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ vf = 0.4 path = dirname(dirname(@__DIR__))*"/results/nonlinear_thermal_compliance_ALM/" iter_mod = 10 diff --git a/scripts/Serial/thermal_compliance_ALM.jl b/scripts/Serial/thermal_compliance_ALM.jl index 425a63d5..44903c27 100644 --- a/scripts/Serial/thermal_compliance_ALM.jl +++ b/scripts/Serial/thermal_compliance_ALM.jl @@ -11,7 +11,7 @@ using Gridap, LevelSetTopOpt ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. """ function main() - ## Parameters| + ## Parameters order = 1 xmax=ymax=1.0 prop_Γ_N = 0.2 @@ -20,12 +20,12 @@ function main() el_size = (200,200) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5*order^2)/minimum(el_size) κ = 1 vf = 0.4 η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM/" iter_mod = 10 mkdir(path) diff --git a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl new file mode 100644 index 00000000..9123a832 --- /dev/null +++ b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl @@ -0,0 +1,104 @@ +using Gridap, LevelSetTopOpt + +""" + (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D. + + This problem uses a higher order level set function than the FE solution for + the state equation. In future, second order upwind schemes will require a + higher order FE function. + + Optimisation problem: + Min J(Ω) = ∫ κ*∇(u)⋅∇(u) dΩ + Ω + s.t., Vol(Ω) = vf, + ⎡u∈V=H¹(Ω;u(Γ_D)=0), + ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. +""" +function main() + ## Parameters + fe_order = 1 + order = 2 + xmax=ymax=1.0 + prop_Γ_N = 0.2 + prop_Γ_D = 0.2 + dom = (0,xmax,0,ymax) + el_size = (200,200) + γ = 0.1 + γ_reinit = 0.5 + max_steps = floor(Int,order*minimum(el_size)/10) + tol = 1/(5*order^2)/minimum(el_size) + κ = 1 + vf = 0.4 + η_coeff = 2 + α_coeff = 4max_steps*γ + path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_higherorderlsf/" + iter_mod = 10 + mkdir(path) + + ## FE Setup + model = CartesianDiscreteModel(dom,el_size); + el_Δ = get_el_Δ(model) + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + x[2] >= ymax-ymax*prop_Γ_D - eps())) + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + ymax/2+ymax*prop_Γ_N/2 + eps()) + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + + ## Triangulations and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + vol_D = sum(∫(1)dΩ) + + ## Spaces + reffe = ReferenceFE(lagrangian,Float64,fe_order) + lsf_reffe = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,0.0) + V_φ = TestFESpace(model,lsf_reffe) + V_reg = TestFESpace(model,lsf_reffe;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + + ## Create FE functions + φh = interpolate(initial_lsf(4,0.2),V_φ) + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N + + ## Optimisation functionals + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ + dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; + Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; + dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + + ## Finite difference solver and level set function + stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + + ## Setup solver and FE operators + state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) + pcfs = PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dJ=dJ,analytic_dC=[dVol]) + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + + ## Optimiser + optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + for (it,uh,φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) + write_history(path*"/history.txt",optimiser.history) + end + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +end + +main() \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl index b3bd339d..52871792 100644 --- a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl @@ -16,7 +16,7 @@ function main(mesh_partition,distribute) # FD parameters γ = 0.1 # HJ eqn time step coeff γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor @@ -69,7 +69,7 @@ function main(mesh_partition,distribute) pcfs = PDEConstrainedFunctionals(J,[C1],state_map, analytic_dJ=dJ,analytic_dC=[dC1]) # Velocity extension - α = 4*maximum(get_el_Δ(model)) + α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( a_hilb, U_reg, V_reg; diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl index 919e046e..5b4730c5 100644 --- a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl @@ -16,7 +16,7 @@ function main(mesh_partition,distribute) # FD parameters γ = 0.1 # HJ eqn time step coeff γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters E = 1000 # Young's modulus @@ -83,7 +83,7 @@ function main(mesh_partition,distribute) dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ pcfs = PDEConstrainedFunctionals(J,[C1],state_map,analytic_dC=[dC1]) # Velocity extension - α = 4*maximum(get_el_Δ(model)) + α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( a_hilb, U_reg, V_reg; diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl index eab453d0..d15c424c 100644 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -12,7 +12,7 @@ function main(mesh_partition,distribute) # FD parameters γ = 0.1 # HJ eqn time step coeff γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor @@ -73,7 +73,7 @@ function main(mesh_partition,distribute) pcfs = PDEConstrainedFunctionals(κ,[C1],state_map, analytic_dJ=dκ,analytic_dC=[dC1]) # Velocity extension - α = 4*maximum(get_el_Δ(model)) + α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( a_hilb, U_reg, V_reg; diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index 0dbac675..b9f3269c 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -17,7 +17,7 @@ function main(mesh_partition,distribute) # FD parameters γ = 0.1 # HJ eqn time step coeff γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor @@ -79,7 +79,7 @@ function main(mesh_partition,distribute) pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map, analytic_dJ=dJ,analytic_dC=[dC1,nothing]) # Velocity extension - α = 4*maximum(get_el_Δ(model)) + α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( a_hilb, U_reg, V_reg; diff --git a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs index 38e3aaa8..f0e6a8e1 100644 --- a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs @@ -1,9 +1,10 @@ #!/bin/bash -l + #PBS -P LSTO #PBS -N elast_comp_MPI_3D #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh diff --git a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs index a9c89845..2e765a8a 100644 --- a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs @@ -1,9 +1,10 @@ #!/bin/bash -l + #PBS -P LSTO #PBS -N hyperelast_comp_MPI_3D #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh diff --git a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs index d1a72278..6b5f5c2c 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs @@ -1,9 +1,10 @@ #!/bin/bash -l + #PBS -P LSTO #PBS -N inverse_hom_MPI_3D #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh diff --git a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs index aeeada29..29179f69 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs @@ -1,9 +1,10 @@ #!/bin/bash -l + #PBS -P LSTO #PBS -N inverter_MPI_3D #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=50:00:00 +#PBS -l walltime=23:00:00 #PBS -j oe source $HOME/hpc-environments-main/lyra/load-ompi.sh diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl index a0b1afeb..9b76c455 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl @@ -17,7 +17,7 @@ function main(mesh_partition,distribute) # FD parameters γ = 0.1 # HJ eqn time step coeff γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + max_steps = floor(Int,order*minimum(el_size)/10)# Max steps for advection tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters κ = 1 # Diffusivity @@ -69,7 +69,7 @@ function main(mesh_partition,distribute) pcfs = PDEConstrainedFunctionals(J,[C1],state_map, analytic_dJ=dJ,analytic_dC=[dC1]) # Velocity extension - α = 4*maximum(get_el_Δ(model)) + α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( a_hilb, U_reg, V_reg; diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl index 0fb2889c..99be6ec8 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl @@ -19,7 +19,7 @@ function main(mesh_partition,distribute) # FD parameters γ = 0.1 # HJ eqn time step coeff γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters κ = 1 # Diffusivity @@ -71,7 +71,7 @@ function main(mesh_partition,distribute) pcfs = PDEConstrainedFunctionals(J,[C1],state_map, analytic_dJ=dJ,analytic_dC=[dC1]) # Velocity extension - α = 4*maximum(get_el_Δ(model)) + α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( a_hilb, U_reg, V_reg; diff --git a/scripts/_dev/Paper_scripts/therm_comp_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl index 6c657510..78cd651c 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_serial.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_serial.jl @@ -15,7 +15,7 @@ function main() # FD parameters γ = 0.1 # HJ eqn time step coeff γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection + max_steps = floor(Int,order*minimum(el_size)/10)# Max steps for advection tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters κ = 1 # Diffusivity @@ -58,7 +58,7 @@ function main() pcfs = PDEConstrainedFunctionals(J,[C1],state_map, analytic_dJ=dJ,analytic_dC=[dC1]) # Velocity extension - α = 4*maximum(get_el_Δ(model)) + α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme @@ -70,7 +70,7 @@ function main() # Solve for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) write_history(path*"/history.txt",get_history(optimiser)) end # Final structure diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index b2380686..ec9823f5 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -124,8 +124,8 @@ end function default_al_converged( m::AugmentedLagrangian; - L_tol = 0.05*maximum(m.stencil.params.Δ), - C_tol = 0.001 + L_tol = 0.01*maximum(m.stencil.params.Δ), + C_tol = 0.01 ) h = m.history it = get_last_iteration(h) @@ -134,7 +134,7 @@ function default_al_converged( end Li, Ci = h[:L,it], h[:C,it] - L_prev = h[:L,it-10:it-1] + L_prev = h[:L,it-5:it-1] A = all(L -> abs(Li - L)/abs(Li) < L_tol, L_prev) B = all(C -> abs(C) < C_tol,Ci) return A && B From 8e5695ed222c98edccf2460f47de17a642d9dbd1 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 7 Apr 2024 10:11:52 +1000 Subject: [PATCH 19/90] Adjust ALM Lambda update --- src/Optimisers/AugmentedLagrangian.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index b2380686..f462c6ff 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -79,7 +79,7 @@ struct AugmentedLagrangian{N,O} <: Optimiser stencil :: AdvectionStencil{O}, vel_ext :: VelocityExtension, φ0; - Λ_max = 5.0, ζ = 1.1, update_mod = 5, reinit_mod = 1, γ = 0.1, γ_reinit = 0.5, + Λ_max = 10^10, ζ = 1.1, update_mod = 5, reinit_mod = 1, γ = 0.1, γ_reinit = 0.5, os_γ_mult = 0.75, maxiter = 1000, verbose=false, constraint_names = map(i -> Symbol("C_$i"),1:N), converged::Function = default_al_converged, debug = false, has_oscillations::Function = default_has_oscillations, @@ -209,8 +209,12 @@ function Base.iterate(m::AugmentedLagrangian,state) ## Augmented Lagrangian method λ .= λ .- Λ .* C - if iszero(it % update_mod) - Λ .= @.(min(Λ*ζ,Λ_max)) + if iszero(it % update_mod) + for i = 1:length(C) + if abs(C[i])>0.01 + Λ[i] = min(Λ[i]*ζ,Λ_max) + end + end end ## Compute dL and it's projection From 4c759189a073114a5783c1ef0e31c4e4be457c7d Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 8 Apr 2024 08:37:09 +1000 Subject: [PATCH 20/90] start iteration option in default_has_oscillations --- src/Optimisers/AugmentedLagrangian.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index 9b903b05..3a44ea75 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -100,10 +100,11 @@ end get_history(m::AugmentedLagrangian) = m.history -function default_has_oscillations(m::AugmentedLagrangian,os_it;itlength=25,algo=:zerocrossing) +function default_has_oscillations(m::AugmentedLagrangian,os_it;itlength=25, + itstart=2itlength,algo=:zerocrossing) h = m.history it = get_last_iteration(h) - if it < 2itlength || it < os_it + itlength + 1 + if it < itstart || it < os_it + itlength + 1 return false end From 3f8ea5315665d3cf56fd6bdfe18e72ab33f94475 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 8 Apr 2024 09:36:42 +1000 Subject: [PATCH 21/90] update benchmarks --- scripts/Benchmarks/benchmark.jl | 346 ++++++++---------- .../Benchmarks/generate_benchmark_scripts.jl | 18 +- 2 files changed, 165 insertions(+), 199 deletions(-) diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index 9abd59ee..3c0fe455 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -18,35 +18,36 @@ global VERBOSE = parse(Int,ARGS[8]) global NREPS = parse(Int,ARGS[9]) function nl_elast(mesh_partition,ranks,el_size,order,verbose) - ## Parameters - xmax=ymax=zmax=1.0 - prop_Γ_N = 0.2 - dom = (0,xmax,0,ymax,0,zmax) - γ = 0.05 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(2order^2)/minimum(el_size) - vf = 0.5 - η_coeff = 2 - α_coeff = 4 - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) - f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + # FE parameters + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + prop_Γ_N = 0.2 # Γ_N size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + E = 1000 # Young's modulus + ν = 0.3 # Poisson's ratio + μ, λ = E/(2*(1 + ν)), E*ν/((1 + ν)*(1 - 2*ν)) # Lame constants + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures + # Triangulation and measures Ω = Triangulation(model) Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - vol_D = sum(∫(1)dΩ) - - ## Spaces + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) reffe_scalar = ReferenceFE(lagrangian,Float64,order) V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) @@ -54,55 +55,30 @@ function nl_elast(mesh_partition,ranks,el_size,order,verbose) V_φ = TestFESpace(model,reffe_scalar) V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - ## Material properties - _E = 1000 - nu = 0.3 - μ, λ = _E/(2*(1 + nu)), _E*nu/((1 + nu)*(1 - 2*nu)) - g = VectorValue(0,0,-100) - - ## Neohookean hyperelastic material - # Deformation gradient - F(∇u) = one(∇u) + ∇u' - J(F) = sqrt(det(C(F))) - - # Derivative of green Strain - dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) - - # Right Caughy-green deformation tensor - C(F) = (F')⋅F - - # Constitutive law (Neo hookean) + # Weak formulation + ## Piola-Kirchhoff tensor function S(∇u) Cinv = inv(C(F(∇u))) μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv end - - # Cauchy stress tensor and residual - σ(∇u) = (1.0/J(F(∇u)))*F(∇u)⋅S(∇u)⋅(F(∇u))' - res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE∘(∇(v),∇(u))) ⊙ (S∘∇(u))) )*dΩ - ∫(g⋅v)dΓ_N - - ## Optimisation functionals - Obj(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((dE∘(∇(u),∇(u))) ⊙ (S∘∇(u))))dΩ - Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) - - ## Setup solver and FE operators + ## Derivative of Green strain + dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) + ## Right Cauchy-Green deformation tensor + C(F) = (F')⋅F + ## Deformation gradient tensor + F(∇u) = one(∇u) + ∇u' + ## Volume change + J(F) = sqrt(det(C(F))) + ## Residual + res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE ∘ (∇(v),∇(u))) ⊙ (S ∘ ∇(u))) )*dΩ - ∫(g⋅v)dΓ_N Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} lin_solver = ElasticitySolver(V) - nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose=verbose) - + nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose) state_map = NonlinearFEStateMap( res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -110,82 +86,75 @@ function nl_elast(mesh_partition,ranks,el_size,order,verbose) assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), nls = nl_solver, adjoint_ls = lin_solver ) - pcfs = PDEConstrainedFunctionals(Obj,[Vol],state_map,analytic_dC=[dVol]) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((dE ∘ (∇(u),∇(u))) ⊙ (S ∘ ∇(u))))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map,analytic_dC=[dC1]) + # Velocity extension + α = 4max_steps*γ*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( - a_hilb,U_reg,V_reg; + a_hilb, U_reg, V_reg; assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - - ## Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=verbose) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) end function therm(mesh_partition,ranks,el_size,order,verbose) - ## Parameters - xmax=ymax=zmax=1.0 - prop_Γ_N = 0.2 - prop_Γ_D = 0.2 - dom = (0,xmax,0,ymax,0,zmax) - γ = 0.05 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(2order^2)/minimum(el_size) - D = 1 - η_coeff = 2 - α_coeff = 4 - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) - f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && + # FE parameters + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + prop_Γ_N = 0.2 # Γ_N size parameter + prop_Γ_D = 0.2 # Γ_D size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function + (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && + (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + κ = 1 # Diffusivity + g = 1 # Heat flow in + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures + # Triangulation and measures Ω = Triangulation(model) Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - - ## Spaces - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + V_φ = TestFESpace(model,reffe) + V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ); - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N - - ## Optimisation functionals - ξ = 0.1 - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(u) + ξ*(ρ ∘ φ))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((-ξ+D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) - - ## Setup solver and FE operators + # Weak formulation + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = PETScLinearSolver() - state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -193,53 +162,58 @@ function therm(mesh_partition,ranks,el_size,order,verbose) assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), ls = solver,adjoint_ls = solver ) - pcfs = PDEConstrainedFunctionals(J,state_map,analytic_dJ=dJ) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ + dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) + # Velocity extension + α = 4max_steps*γ*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( a_hilb, U_reg, V_reg; assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = solver ) - - ## Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=verbose) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) end function elast(mesh_partition,ranks,el_size,order,verbose) - ## Parameters - xmax=ymax=zmax=1.0 - prop_Γ_N = 0.2 - dom = (0,xmax,0,ymax,0,zmax) - γ = 0.05 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(2order^2)/minimum(el_size) - C = isotropic_elast_tensor(3,1.,0.3) - g = VectorValue(0,0,-1) - η_coeff = 2 - α_coeff = 4 - vf = 0.5 - - ## FE Setup + # FE parameters + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + prop_Γ_N = 0.2 # Γ_N size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) - f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures + # Triangulation and measures Ω = Triangulation(model) Γ_N = BoundaryTriangulation(model,tags="Gamma_N") dΩ = Measure(Ω,2*order) dΓ_N = Measure(Γ_N,2*order) - vol_D = sum(∫(1)dΩ) - - ## Spaces + # Spaces reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) reffe_scalar = ReferenceFE(lagrangian,Float64,order) V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) @@ -247,51 +221,44 @@ function elast(mesh_partition,ranks,el_size,order,verbose) V_φ = TestFESpace(model,reffe_scalar) V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - + # Weak formulation a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ l(v,φ,dΩ,dΓ_N) = ∫(v⋅g)dΓ_N - - ## Optimisation functionals - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(u)))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) - - ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = ElasticitySolver(V) - state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver, adjoint_ls = solver + ls = solver,adjoint_ls = solver ) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(u)))dΩ + dJ(q,u,φ,dΩ,dΓ_N) = ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) + # Velocity extension + α = 4max_steps*γ*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension( - a_hilb,U_reg,V_reg; + a_hilb, U_reg, V_reg; assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - - ## Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=verbose) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + # Optimiser + return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) end function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) @@ -399,8 +366,7 @@ with_mpi() do distribute verbose = Bool(VERBOSE) ? i_am_main(ranks) : false; if PROB_TYPE == "NLELAST" options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" opt = nl_elast elseif PROB_TYPE == "THERM" options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true @@ -408,13 +374,11 @@ with_mpi() do distribute opt = therm elseif PROB_TYPE == "ELAST" options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" opt = elast elseif PROB_TYPE == "INVERTER_HPM" options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" opt = inverter_HPM else error("Problem not defined") diff --git a/scripts/Benchmarks/generate_benchmark_scripts.jl b/scripts/Benchmarks/generate_benchmark_scripts.jl index 257fdf4c..4214f36e 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts.jl @@ -19,7 +19,7 @@ function generate( ) ncpus = n_mesh_partition^3 - wallhr = occursin("STRONG",name) && n_mesh_partition <= 3 ? 50 : wallhr + wallhr = occursin("STRONG",name) && n_mesh_partition <= 3 ? 100 : wallhr mem = occursin("STRONG",name) && n_mesh_partition == 1 ? 256 : occursin("STRONG",name) && n_mesh_partition == 2 ? 32 : gb_per_cpu; @@ -29,14 +29,16 @@ function generate( end function generate_jobs(template,phys_type,ndof_per_node,bmark_types) - strong = (N).^3; - weak_el_x = @. floor(Int,(dofs_per_proc*strong/ndof_per_node)^(1/3)-1); - dof_sanity_check = @.(floor(Int,ndof_per_node*(weak_el_x+1)^3/strong)), - maximum(abs,@. ndof_per_node*(weak_el_x+1)^3/strong/dofs_per_proc - 1) + npart = (N).^3; + weak_el_x = @. floor(Int,(dofs_per_proc*npart/ndof_per_node)^(1/3)-1); + dof_sanity_check = @.(floor(Int,ndof_per_node*(weak_el_x+1)^3/npart)), + maximum(abs,@. ndof_per_node*(weak_el_x+1)^3/npart/dofs_per_proc - 1) sname(phys_type,ndof_per_node,n,elx) = "STRONG_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" wname(phys_type,ndof_per_node,n,elx) = "WEAK_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" + strong_el_x = ceil(Int,(strong_dof/ndof_per_node)^(1/3)); + strong_jobs = map(n->(sname(phys_type,ndof_per_node,n,strong_el_x), generate(template,sname(phys_type,ndof_per_node,n,strong_el_x),phys_type,bmark_types, cputype,wallhr,n,strong_el_x,fe_order,verbose,dir_name,write_dir,nreps)),N) @@ -63,14 +65,14 @@ dir_name= "LevelSetTopOpt"; write_dir = "\$HOME/$dir_name/results/benchmarks/" N = 1:10; # Number of partitions in x-axis -strong_el_x=100; # Number of elements in x-axis (strong scaling) +strong_dof=(150+1)^3*3; # Number of dofs for strong scaling # Phys type and number of dofs per node, and what to benchmark phys_types = [ ("THERM",1,"bopt0,bopt1,bfwd,badv,breinit,bvelext"), - ("ELAST",3,"bopt0,bopt1,bfwd"), + ("ELAST",3,"bopt0,bopt1,bfwd,badv,breinit,bvelext"), ("NLELAST",3,"bopt0,bopt1,bfwd"), - ("INVERTER_HPM",3,"bhpm"), + # ("INVERTER_HPM",3,"bhpm"), ]; # Template From b23c411dc49b00400094aa8e5f4b5d20e242ea5a Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 8 Apr 2024 14:16:45 +1000 Subject: [PATCH 22/90] Cleanup --- docs/make.jl | 5 +++-- scripts/MPI/3d_elastic_compliance_ALM.jl | 5 ++--- scripts/MPI/3d_hyperelastic_compliance_ALM.jl | 5 ++--- .../MPI/3d_hyperelastic_compliance_neohook_ALM.jl | 5 ++--- scripts/MPI/3d_inverse_homenisation_ALM.jl | 5 ++--- scripts/MPI/3d_inverter_ALM.jl | 5 ++--- scripts/MPI/3d_inverter_HPM.jl | 5 ++--- scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl | 2 +- scripts/MPI/3d_thermal_compliance_ALM.jl | 13 +++---------- 9 files changed, 19 insertions(+), 31 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index fc289362..67bba876 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,5 +1,6 @@ -cd("./docs/") -using Pkg; Pkg.activate(".") +## Local generate +# cd("./docs/") +# using Pkg; Pkg.activate(".") using Documenter using LevelSetTopOpt diff --git a/scripts/MPI/3d_elastic_compliance_ALM.jl b/scripts/MPI/3d_elastic_compliance_ALM.jl index 8bf651f1..58836523 100644 --- a/scripts/MPI/3d_elastic_compliance_ALM.jl +++ b/scripts/MPI/3d_elastic_compliance_ALM.jl @@ -35,7 +35,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_elastic_compliance_ALM/" + path = dirname(dirname(@__DIR__))*"/results/3d_elastic_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) @@ -122,8 +122,7 @@ with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl index 8c24bbcb..6064ae61 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl @@ -28,7 +28,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_ALM/" + path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) @@ -125,8 +125,7 @@ with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index 662071b7..7b02dd0c 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -28,7 +28,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_neohook_ALM/" + path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_neohook_ALM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) @@ -139,8 +139,7 @@ with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index a0df9c4b..ec6f7872 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -33,7 +33,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/3d_inverse_homenisation_ALM/" + path = dirname(dirname(@__DIR__))*"/results/3d_inverse_homenisation_ALM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) @@ -126,8 +126,7 @@ with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/scripts/MPI/3d_inverter_ALM.jl b/scripts/MPI/3d_inverter_ALM.jl index fde12b40..0b600003 100644 --- a/scripts/MPI/3d_inverter_ALM.jl +++ b/scripts/MPI/3d_inverter_ALM.jl @@ -39,7 +39,7 @@ function main(mesh_partition,distribute,el_size) δₓ=0.5 ks = 0.01 g = VectorValue(1,0,0) - path = dirname(dirname(@__DIR__))*"/results/3d_inverter_ALM/" + path = dirname(dirname(@__DIR__))*"/results/3d_inverter_ALM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) @@ -140,8 +140,7 @@ with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/scripts/MPI/3d_inverter_HPM.jl b/scripts/MPI/3d_inverter_HPM.jl index b645ab9c..bd6d16e9 100644 --- a/scripts/MPI/3d_inverter_HPM.jl +++ b/scripts/MPI/3d_inverter_HPM.jl @@ -39,7 +39,7 @@ function main(mesh_partition,distribute,el_size) δₓ=0.5 ks = 0.01 g = VectorValue(1,0,0) - path = dirname(dirname(@__DIR__))*"/results/3d_inverter_HPM/" + path = dirname(dirname(@__DIR__))*"/results/3d_inverter_HPM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) @@ -141,8 +141,7 @@ with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl index 8aab7ed2..f4f110d6 100644 --- a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl @@ -38,7 +38,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_nonlinear_thermal_compliance_ALM/" + path = dirname(dirname(@__DIR__))*"/results/3d_nonlinear_thermal_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index eded269d..9d0366f6 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -18,7 +18,7 @@ global Pz = parse(Int,ARGS[6]) ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. """ -function main(mesh_partition,distribute,el_size,coef,step) +function main(mesh_partition,distribute,el_size) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -35,7 +35,7 @@ function main(mesh_partition,distribute,el_size,coef,step) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_thermal_compliance_ALM_Nx$(el_size[1])_Coef$(coef)_Step$(step)" + path = dirname(dirname(@__DIR__))*"/results/3d_thermal_compliance_ALM_Nx$(el_size[1])" iter_mod = 10 i_am_main(ranks) && mkdir(path) @@ -125,13 +125,6 @@ with_mpi() do distribute -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(all_solver_options)) do - main(mesh_partition,distribute,el_size,5,10) - # main(mesh_partition,distribute,el_size,2,10) - - # main(mesh_partition,distribute,el_size,5,5) - # main(mesh_partition,distribute,el_size,2,5) - - # main(mesh_partition,distribute,el_size,5,3) - # main(mesh_partition,distribute,el_size,2,3) + main(mesh_partition,distribute,el_size) end end; \ No newline at end of file From 6e1d718c4d01a57fa328069576520b7c40ab714b Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 09:30:20 +1000 Subject: [PATCH 23/90] fix paths --- scripts/MPI/3d_thermal_compliance_ALM.jl | 2 +- scripts/MPI/elastic_compliance_ALM.jl | 2 +- scripts/MPI/inverse_homenisation_ALM.jl | 2 +- scripts/MPI/thermal_compliance_ALM.jl | 2 +- scripts/MPI/thermal_compliance_ALM_PETSc.jl | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index 9d0366f6..0fa01deb 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -35,7 +35,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_thermal_compliance_ALM_Nx$(el_size[1])" + path = dirname(dirname(@__DIR__))*"/results/3d_thermal_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 i_am_main(ranks) && mkdir(path) diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index 21f8ce9a..fcfb451f 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -28,7 +28,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM_MPI" + path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM_MPI/" iter_mod = 10 i_am_main(ranks) && mkdir(path) diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index e9a736db..7a068021 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -26,7 +26,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_MPI" + path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_MPI/" iter_mod = 10 i_am_main(ranks) && mkdir(path) diff --git a/scripts/MPI/thermal_compliance_ALM.jl b/scripts/MPI/thermal_compliance_ALM.jl index 9b807c90..8bb1e9aa 100644 --- a/scripts/MPI/thermal_compliance_ALM.jl +++ b/scripts/MPI/thermal_compliance_ALM.jl @@ -28,7 +28,7 @@ function main(mesh_partition,distribute) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI" + path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI/" iter_mod = 10 i_am_main(ranks) && mkdir(path) diff --git a/scripts/MPI/thermal_compliance_ALM_PETSc.jl b/scripts/MPI/thermal_compliance_ALM_PETSc.jl index 8a3ce6d5..39bd0271 100644 --- a/scripts/MPI/thermal_compliance_ALM_PETSc.jl +++ b/scripts/MPI/thermal_compliance_ALM_PETSc.jl @@ -28,7 +28,7 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI+PETSc" + path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI+PETSc/" iter_mod = 10 i_am_main(ranks) && mkdir(path) From 4b94785e030ac2bc69ac58700b517ed5ea938ec6 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 10:43:19 +1000 Subject: [PATCH 24/90] Create LevelSetEvolution abstract type --- .../HamiltonJacobiEvolution.jl | 351 ++++++++++++++++++ src/LevelSetEvolution/LevelSetEvolution.jl | 39 ++ src/LevelSetEvolution/SpatialStencil.jl | 175 +++++++++ 3 files changed, 565 insertions(+) create mode 100644 src/LevelSetEvolution/HamiltonJacobiEvolution.jl create mode 100644 src/LevelSetEvolution/LevelSetEvolution.jl create mode 100644 src/LevelSetEvolution/SpatialStencil.jl diff --git a/src/LevelSetEvolution/HamiltonJacobiEvolution.jl b/src/LevelSetEvolution/HamiltonJacobiEvolution.jl new file mode 100644 index 00000000..8e86f07a --- /dev/null +++ b/src/LevelSetEvolution/HamiltonJacobiEvolution.jl @@ -0,0 +1,351 @@ +""" + struct HamiltonJacobiEvolution{O} + +A standard forward Euler in time finite difference method for solving the +Hamilton-Jacobi evolution equation and reinitialisation equation +on order `O` finite elements in serial or parallel. + +Based on the scheme by Osher and Fedkiw ([link](https://doi.org/10.1007/b98879)). + +# Parameters + +- `stencil::SpatialStencil`: Spatial finite difference stencil for a single step HJ + equation and reinitialisation equation. +- `model`: A `CartesianDiscreteModel`. +- `space`: FE space for level-set function +- `perm`: A permutation vector +- `params`: Tuple of additional params +- `cache`: SpatialStencil cache +""" +struct HamiltonJacobiEvolution{O} <: LevelSetEvolution + stencil :: SpatialStencil + model + space + perm + params + cache +end + +""" + HamiltonJacobiEvolution(stencil::SpatialStencil,model,space,tol,max_steps,max_steps_reinit) + +Create an instance of `HamiltonJacobiEvolution` given a stencil, model, FE space, and +additional optional arguments. This automatically creates the DoF permutation +to handle high-order finite elements. +""" +function HamiltonJacobiEvolution( + stencil::SpatialStencil, + model, + space, + tol=1.e-3, + max_steps=100, + max_steps_reinit=2000 +) + # Parameters + order, isperiodic, Δ, ndof = get_stencil_params(model,space) + params = (;isperiodic,Δ,ndof,max_steps,max_steps_reinit,tol) + + # Check that we have sufficient order + check_order(stencil,order) + + # Dof permutation + perm = create_dof_permutation(model,space,order) + + # Caches + φ, vel = zero_free_values(space), zero_free_values(space) + cache = allocate_caches(stencil,φ,vel,perm,order,ndof) + + return HamiltonJacobiEvolution{order}(stencil,model,space,perm,params,cache) +end + +""" + get_dof_Δ(::HamiltonJacobiEvolution) + +Return the distance betweem degree of freedom +""" +function get_dof_Δ(m::HamiltonJacobiEvolution) + return m.params.Δ +end + +""" + compute_Δt(::HamiltonJacobiEvolution,φ,vel) + +Compute the time step for the `HamiltonJacobiEvolution`. +""" +function compute_Δt(::HamiltonJacobiEvolution,Δ,γ,φ,vel) + T = eltype(γ) + v_norm = maximum(abs,vel) + return γ * min(Δ...) / (eps(T)^2 + v_norm) +end + +""" + evolve!(s::HamiltonJacobiEvolution{O},φ,vel,γ) where O + +Solve the Hamilton-Jacobi evolution equation using the `HamiltonJacobiEvolution`. + +# Hamilton-Jacobi evolution equation +``\\frac{\\partial\\phi}{\\partial t} + V(\\boldsymbol{x})\\lVert\\boldsymbol{\\nabla}\\phi\\rVert = 0,`` + +with ``\\phi(0,\\boldsymbol{x})=\\phi_0(\\boldsymbol{x})`` and ``\\boldsymbol{x}\\in D,~t\\in(0,T)``. + +# Arguments + +- `s::HamiltonJacobiEvolution{O}`: Method +- `φ`: level set function as a vector of degrees of freedom +- `vel`: the normal velocity as a vector of degrees of freedom +- `γ`: coeffient on the time step size. +""" +function evolve!(s::HamiltonJacobiEvolution{O},φ::PVector,vel::PVector,γ) where O + _, _, perm_caches, stencil_cache = s.cache + Δ, isperiodic, = s.params.Δ, s.params.isperiodic + ndof, max_steps = s.params.ndof, s.params.max_steps + + _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ + _vel = (O >= 2) ? permute!(perm_caches[2],vel,s.perm) : vel + + ## CFL Condition (requires γ≤1.0) + Δt = compute_Δt(s,Δ,γ,φ,vel) + for _ in 1:max_steps + # Apply operations across partitions + map(local_views(_φ),local_views(_vel),stencil_cache,ndof) do _φ,_vel,stencil_cache,S + φ_mat = reshape(_φ,S) + vel_mat = reshape(_vel,S) + evolve!(s.stencil,φ_mat,vel_mat,Δt,Δ,isperiodic,stencil_cache) + end + # Update ghost nodes + consistent!(_φ) |> fetch + end + φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ + return φ +end + +function evolve!(s::HamiltonJacobiEvolution{O},φ::Vector,vel::Vector,γ) where O + _, _, perm_caches, stencil_cache = s.cache + Δ, isperiodic, = s.params.Δ, s.params.isperiodic + ndof, max_steps = s.params.ndof, s.params.max_steps + + _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ + _vel = (O >= 2) ? permute!(perm_caches[2],vel,s.perm) : vel + + ## CFL Condition (requires γ≤1.0) + Δt = compute_Δt(s,Δ,γ,φ,vel) + for _ in 1:max_steps + φ_mat = reshape(_φ,ndof) + vel_mat = reshape(_vel,ndof) + evolve!(s.stencil,φ_mat,vel_mat,Δt,Δ,isperiodic,stencil_cache) + end + φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ + return φ +end + +function evolve!(s::HamiltonJacobiEvolution,φh,args...) + evolve!(s,get_free_dof_values(φh),args...) +end + +""" + reinit!(s::HamiltonJacobiEvolution{O},φ,γ) where O + +Solve the reinitialisation equation using the `HamiltonJacobiEvolution`. + +# Reinitialisation equation +``\\frac{\\partial\\phi}{\\partial t} + \\mathrm{sign}(\\phi_0)(\\lVert\\boldsymbol{\\nabla}\\phi\\rVert-1) = 0,`` + +with ``\\phi(0,\\boldsymbol{x})=\\phi_0(\\boldsymbol{x})`` and ``\\boldsymbol{x}\\in D,~t\\in(0,T)``. + +# Arguments + +- `s::HamiltonJacobiEvolution{O}`: Method +- `φ`: level set function as a vector of degrees of freedom +- `γ`: coeffient on the time step size. +""" +function reinit!(s::HamiltonJacobiEvolution{O},φ::PVector,γ) where O + φ_tmp, vel_tmp, perm_caches, stencil_cache = s.cache + Δ, isperiodic, ndof = s.params.Δ, s.params.isperiodic, s.params.ndof + tol, max_steps = s.params.tol, s.params.max_steps_reinit + + _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ + + ## CFL Condition (requires γ≤0.5). Note infnorm(S) = 1.0 + Δt = compute_Δt(s,Δ,γ,_φ,1.0) + + # Apply operations across partitions + step = 1; err = maximum(abs,φ); fill!(φ_tmp,0.0) + while (err > tol) && (step <= max_steps) + # Step of 1st order upwind reinitialisation equation + map(local_views(φ_tmp),local_views(_φ),local_views(vel_tmp),stencil_cache,ndof) do φ_tmp,_φ,vel_tmp,stencil_cache,S + φ_tmp_mat = reshape(φ_tmp,S) + φ_mat = reshape(_φ,S) + vel_tmp_mat = reshape(vel_tmp,S) + reinit!(s.stencil,φ_tmp_mat,φ_mat,vel_tmp_mat,Δt,Δ,isperiodic,stencil_cache) + end + + # Compute error + _φ .-= φ_tmp # φ - φ_tmp + err = maximum(abs,_φ) + step += 1 + + # Update φ + copy!(_φ,φ_tmp) + consistent!(_φ) |> fetch # We exchange ghosts here! + end + φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ + return φ +end + +function reinit!(s::HamiltonJacobiEvolution{O},φ::Vector,γ) where O + φ_tmp, vel_tmp, perm_caches, stencil_cache = s.cache + Δ, isperiodic, ndof = s.params.Δ, s.params.isperiodic, s.params.ndof + tol, max_steps = s.params.tol, s.params.max_steps_reinit + + _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ + + ## CFL Condition (requires γ≤0.5) + Δt = compute_Δt(s,Δ,γ,_φ,1.0) + + # Apply operations across partitions + step = 1; err = maximum(abs,φ); fill!(φ_tmp,0.0) + while (err > tol) && (step <= max_steps) + # Step of 1st order upwind reinitialisation equation + φ_tmp_mat = reshape(φ_tmp,ndof) + φ_mat = reshape(_φ,ndof) + vel_tmp_mat = reshape(vel_tmp,ndof) + reinit!(s.stencil,φ_tmp_mat,φ_mat,vel_tmp_mat,Δt,Δ,isperiodic,stencil_cache) + + # Compute error + _φ .-= φ_tmp + err = maximum(abs,_φ) + step += 1 + + # Update φ + copy!(_φ,φ_tmp) + end + φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ + return φ +end + +function reinit!(s::HamiltonJacobiEvolution,φh,args...) + reinit!(s,get_free_dof_values(φh),args...) +end + +## Utilities +function get_stencil_params(model::CartesianDiscreteModel,space::FESpace) + order = get_order(first(Gridap.CellData.get_data(get_fe_basis(space)))) + desc = get_cartesian_descriptor(model) + isperiodic = desc.isperiodic + ndof = order .* desc.partition .+ 1 .- isperiodic + Δ = desc.sizes ./ order + return order, isperiodic, Δ, ndof +end + +function get_stencil_params(model::DistributedDiscreteModel,space::DistributedFESpace) + order, isperiodic, Δ, ndof = map(local_views(model),local_views(space)) do model, space + get_stencil_params(model,space) + end |> PartitionedArrays.tuple_of_arrays + + isperiodic = getany(isperiodic) + order = getany(order) + Δ = getany(Δ) + return order, isperiodic, Δ, ndof +end + +Gridap.ReferenceFEs.get_order(f::Gridap.Fields.LinearCombinationFieldVector) = get_order(f.fields) + +# Create dof permutation vector to enable finite differences on +# higher order Lagrangian finite elements on a Cartesian mesh. +function create_dof_permutation(model::CartesianDiscreteModel{Dc}, + space::UnconstrainedFESpace, + order::Integer) where Dc + function get_terms(poly::Polytope, orders) + _nodes, facenodes = Gridap.ReferenceFEs._compute_nodes(poly, orders) + terms = Gridap.ReferenceFEs._coords_to_terms(_nodes, orders) + return terms + end + desc = get_cartesian_descriptor(model) + + periodic = desc.isperiodic + ncells = desc.partition + ndofs = order .* ncells .+ 1 .- periodic + @check prod(ndofs) == num_free_dofs(space) + + new_dof_ids = CircularArray(LinearIndices(ndofs)) + n2o_dof_map = fill(-1,num_free_dofs(space)) + + terms = get_terms(first(get_polytopes(model)), fill(order,Dc)) + cell_dof_ids = get_cell_dof_ids(space) + cache_cell_dof_ids = array_cache(cell_dof_ids) + for (iC,cell) in enumerate(CartesianIndices(ncells)) + first_new_dof = order .* (Tuple(cell) .- 1) .+ 1 + new_dofs_range = map(i -> i:i+order,first_new_dof) + new_dofs = view(new_dof_ids,new_dofs_range...) + + cell_dofs = getindex!(cache_cell_dof_ids,cell_dof_ids,iC) + for (iDof, dof) in enumerate(cell_dofs) + t = terms[iDof] + #o2n_dof_map[dof] = new_dofs[t] + n2o_dof_map[new_dofs[t]] = dof + end + end + + return n2o_dof_map +end + +function create_dof_permutation(model::GridapDistributed.DistributedDiscreteModel, + space::GridapDistributed.DistributedFESpace, + order::Integer) + local_perms = map(local_views(model),local_views(space)) do model, space + create_dof_permutation(model,space,order) + end + return local_perms +end + +function PartitionedArrays.permute_indices(indices::LocalIndices,perm) + id = part_id(indices) + n_glob = global_length(indices) + l2g = view(local_to_global(indices),perm) + l2o = view(local_to_owner(indices),perm) + return LocalIndices(n_glob,id,l2g,l2o) +end + +function allocate_caches(s::SpatialStencil,φ::Vector,vel::Vector,perm,order,ndofs) + stencil_caches = allocate_caches(s,reshape(φ,ndofs),reshape(vel,ndofs)) + φ_tmp = similar(φ) + vel_tmp = similar(vel) + perm_caches = (order >= 2) ? (similar(φ), similar(vel)) : nothing + return φ_tmp, vel_tmp, perm_caches, stencil_caches +end + +function allocate_caches(s::SpatialStencil,φ::PVector,vel::PVector,perm,order,local_ndofs) + local_stencil_caches = map(local_views(φ),local_views(vel),local_views(local_ndofs)) do φ,vel,ndofs + allocate_caches(s,reshape(φ,ndofs),reshape(vel,ndofs)) + end + + perm_indices = map(permute_indices,partition(axes(φ,1)),perm) + perm_caches = (order >= 2) ? (pfill(0.0,perm_indices),pfill(0.0,perm_indices)) : nothing + + φ_tmp = (order >= 2) ? pfill(0.0,perm_indices) : similar(φ) + vel_tmp = (order >= 2) ? pfill(0.0,perm_indices) : similar(vel) + return φ_tmp, vel_tmp, perm_caches, local_stencil_caches +end + +function permute!(x_out,x_in,perm) + for (i_new,i_old) in enumerate(perm) + x_out[i_new] = x_in[i_old] + end + return x_out +end + +function permute!(x_out::PVector,x_in::PVector,perm) + map(permute!,partition(x_out),partition(x_in),perm) + return x_out +end + +function permute_inv!(x_out,x_in,perm) + for (i_new,i_old) in enumerate(perm) + x_out[i_old] = x_in[i_new] + end + return x_out +end +function permute_inv!(x_out::PVector,x_in::PVector,perm) + map(permute_inv!,partition(x_out),partition(x_in),perm) + return x_out +end \ No newline at end of file diff --git a/src/LevelSetEvolution/LevelSetEvolution.jl b/src/LevelSetEvolution/LevelSetEvolution.jl new file mode 100644 index 00000000..d6a743f4 --- /dev/null +++ b/src/LevelSetEvolution/LevelSetEvolution.jl @@ -0,0 +1,39 @@ +""" + abstract type LevelSetEvolution + +Your own evolution method can be implemented by implementing +concrete functionality of the below. +""" +abstract type LevelSetEvolution end + +""" + evolve!(::LevelSetEvolution,φ,args...) + +Evolve the level set function φ according to an evolution +method LevelSetEvolution. +""" +function evolve!(::LevelSetEvolution,φ,args...) + @abstractmethod +end + +""" + reinit!(::LevelSetEvolution,φ,args...) + +Reinitialise the level set function φ according to an +evolution method LevelSetEvolution. +""" +function reinit!(::LevelSetEvolution,φ,args...) + @abstractmethod +end + +""" + get_dof_Δ(::LevelSetEvolution) + +Return the distance betweem degree of freedom +""" +function get_dof_Δ(::LevelSetEvolution) + @abstractmethod +end + +include("SpatialStencil.jl") +include("HamiltonJacobiEvolution.jl") \ No newline at end of file diff --git a/src/LevelSetEvolution/SpatialStencil.jl b/src/LevelSetEvolution/SpatialStencil.jl new file mode 100644 index 00000000..12dd6469 --- /dev/null +++ b/src/LevelSetEvolution/SpatialStencil.jl @@ -0,0 +1,175 @@ +""" + abstract type SpatialStencil + +Finite difference stencil for a single step of the Hamilton-Jacobi +evolution equation and reinitialisation equation. + +Your own stencil can be implemented by extending the methods below. +""" +abstract type SpatialStencil end + +""" + allocate_caches(::SpatialStencil,φ,vel) + +Allocate caches for a given `SpatialStencil`. +""" +function allocate_caches(::SpatialStencil,φ,vel) + nothing # By default, no caches are required. +end + +""" + check_order(::SpatialStencil,order) + +Throw error if insufficient reference element order +to implement stencil in parallel. +""" +function check_order(::SpatialStencil,order) + @abstractmethod +end + +""" + reinit!(::SpatialStencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) -> φ + +Single finite difference step of the reinitialisation equation for a given `SpatialStencil`. +""" +function reinit!(::SpatialStencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) + @abstractmethod +end + +""" + evolve!(::SpatialStencil,φ,vel,Δt,Δx,isperiodic,caches) -> φ + +Single finite difference step of the Hamilton-Jacobi evoluation equation for a given +`SpatialStencil`. +""" +function evolve!(::SpatialStencil,φ,vel,Δt,Δx,isperiodic,caches) + @abstractmethod +end + +""" + struct FirstOrderStencil{D,T} <: SpatialStencil end + +A first order Godunov upwind difference scheme based on Osher and Fedkiw +([link](https://doi.org/10.1007/b98879)). +""" +struct FirstOrderStencil{D,T} <: SpatialStencil + function FirstOrderStencil(D::Integer,::Type{T}) where T<:Real + new{D,T}() + end +end + +function check_order(::FirstOrderStencil,order) + @check order >= 1 "FirstOrderStencil requires reference element to have order >= 1" +end + +function allocate_caches(::FirstOrderStencil{2},φ,vel) + D⁺ʸ = similar(φ); D⁺ˣ = similar(φ) + D⁻ʸ = similar(φ); D⁻ˣ = similar(φ) + ∇⁺ = similar(φ); ∇⁻ = similar(φ) + return D⁺ʸ, D⁺ˣ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ +end + +function reinit!(::FirstOrderStencil{2,T},φ_new,φ,vel,Δt,Δx,isperiodic,caches) where T + D⁺ʸ, D⁺ˣ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ = caches + Δx, Δy = Δx + xperiodic,yperiodic = isperiodic + # Prepare shifted lsf + circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)) + circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)) + # Sign approximation + ∇⁺ .= @. (D⁺ʸ - D⁻ʸ)/(2Δy); ~yperiodic ? ∇⁺[:,[1,end]] .= zero(T) : 0; + ∇⁻ .= @. (D⁺ˣ - D⁻ˣ)/(2Δx); ~xperiodic ? ∇⁻[[1,end],:] .= zero(T) : 0; + ϵₛ = minimum((Δx,Δy)) + vel .= @. φ/sqrt(φ^2 + ϵₛ^2*(∇⁺^2+∇⁻^2)) + # Forward (+) & Backward (-) + D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end] .= zero(T) : 0; + D⁺ˣ .= @. (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:] .= zero(T) : 0; + D⁻ʸ .= @. (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1] .= zero(T) : 0; + D⁻ˣ .= @. (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:] .= zero(T) : 0; + # Operators + ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2); + ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2); + # Update + φ_new .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻ - vel) + return φ_new +end + +function evolve!(::FirstOrderStencil{2,T},φ,vel,Δt,Δx,isperiodic,caches) where T + D⁺ʸ, D⁺ˣ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ = caches + Δx, Δy = Δx + xperiodic,yperiodic = isperiodic + # Prepare shifted lsf + circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)) + circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)) + # Forward (+) & Backward (-) + D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end] .= zero(T) : 0; + D⁺ˣ .= @. (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:] .= zero(T) : 0; + D⁻ʸ .= @. (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1] .= zero(T) : 0; + D⁻ˣ .= @. (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:] .= zero(T) : 0; + # Operators + ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2) + ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2) + # Update + φ .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻) + return φ +end + +function allocate_caches(::FirstOrderStencil{3},φ,vel) + D⁺ᶻ = similar(φ); D⁺ʸ = similar(φ); D⁺ˣ = similar(φ) + D⁻ᶻ = similar(φ); D⁻ʸ = similar(φ); D⁻ˣ = similar(φ) + ∇⁺ = similar(φ); ∇⁻ = similar(φ) + return D⁺ᶻ, D⁺ʸ, D⁺ˣ, D⁻ᶻ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ +end + +function reinit!(::FirstOrderStencil{3,T},φ_new,φ,vel,Δt,Δx,isperiodic,caches) where T + D⁺ᶻ, D⁺ʸ, D⁺ˣ, D⁻ᶻ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻=caches + Δx, Δy, Δz = Δx + xperiodic,yperiodic,zperiodic = isperiodic + # Prepare shifted lsf + circshift!(D⁺ʸ,φ,(0,-1,0)); circshift!(D⁻ʸ,φ,(0,1,0)) + circshift!(D⁺ˣ,φ,(-1,0,0)); circshift!(D⁻ˣ,φ,(1,0,0)) + circshift!(D⁺ᶻ,φ,(0,0,-1)); circshift!(D⁻ᶻ,φ,(0,0,1)) + # Sign approximation + ∇⁺ .= @. (D⁺ʸ - D⁻ʸ)/(2Δy); ~yperiodic ? ∇⁺[:,[1,end],:] .= zero(T) : 0; + ∇⁻ .= @. (D⁺ˣ - D⁻ˣ)/(2Δx); ~xperiodic ? ∇⁻[[1,end],:,:] .= zero(T) : 0; + ∇⁺ .= @. ∇⁺^2+∇⁻^2 # |∇φ|² (partially computed) + ∇⁻ .= @. (D⁺ᶻ - D⁻ᶻ)/(2Δz); ~xperiodic ? ∇⁻[:,:,[1,end]] .= zero(T) : 0; + ϵₛ = minimum((Δx,Δy,Δz)) + vel .= @. φ/sqrt(φ^2 + ϵₛ^2*(∇⁺+∇⁻^2)) + # Forward (+) & Backward (-) + D⁺ʸ .= (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end,:] .= zero(T) : 0; + D⁺ˣ .= (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:,:] .= zero(T) : 0; + D⁺ᶻ .= (D⁺ᶻ - φ)/Δz; ~zperiodic ? D⁺ᶻ[:,:,end] .= zero(T) : 0; + D⁻ʸ .= (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1,:] .= zero(T) : 0; + D⁻ˣ .= (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:,:] .= zero(T) : 0; + D⁻ᶻ .= (φ - D⁻ᶻ)/Δz; ~zperiodic ? D⁻ᶻ[:,:,1] .= zero(T) : 0; + # Operators + ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2) + ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2) + # Update + φ_new .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻ - vel) + return φ_new +end + +function evolve!(::FirstOrderStencil{3,T},φ,vel,Δt,Δx,isperiodic,caches) where T + D⁺ᶻ, D⁺ʸ, D⁺ˣ, D⁻ᶻ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻=caches + Δx, Δy, Δz = Δx + xperiodic,yperiodic,zperiodic = isperiodic + # Prepare shifted lsf + circshift!(D⁺ʸ,φ,(0,-1,0)); circshift!(D⁻ʸ,φ,(0,1,0)) + circshift!(D⁺ˣ,φ,(-1,0,0)); circshift!(D⁻ˣ,φ,(1,0,0)) + circshift!(D⁺ᶻ,φ,(0,0,-1)); circshift!(D⁻ᶻ,φ,(0,0,1)) + # Forward (+) & Backward (-) + D⁺ʸ .= (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end,:] .= zero(T) : 0; + D⁺ˣ .= (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:,:] .= zero(T) : 0; + D⁺ᶻ .= (D⁺ᶻ - φ)/Δz; ~zperiodic ? D⁺ᶻ[:,:,end] .= zero(T) : 0; + D⁻ʸ .= (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1,:] .= zero(T) : 0; + D⁻ˣ .= (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:,:] .= zero(T) : 0; + D⁻ᶻ .= (φ - D⁻ᶻ)/Δz; ~zperiodic ? D⁻ᶻ[:,:,1] .= zero(T) : 0; + # Operators + ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2) + ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2) + # Update + φ .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻) + return φ +end \ No newline at end of file From 3d0539e083f46e4f4f56263cc896688d0669c962 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 10:43:45 +1000 Subject: [PATCH 25/90] Update includes and exports --- src/LevelSetTopOpt.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LevelSetTopOpt.jl b/src/LevelSetTopOpt.jl index 7b6ebc4d..cc30a752 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/LevelSetTopOpt.jl @@ -52,8 +52,8 @@ export initial_lsf export get_el_Δ export isotropic_elast_tensor -include("Advection.jl") -export AdvectionStencil +include("LevelSetEvolution/LevelSetEvolution.jl") +export HamiltonJacobiEvolution export FirstOrderStencil export advect! export reinit! From 8850dfa052c64bdf4178f469203b44873c7b8444 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 10:46:14 +1000 Subject: [PATCH 26/90] Update Benchmark.jl --- src/Benchmarks.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Benchmarks.jl b/src/Benchmarks.jl index 87cc4a6e..afffef2d 100644 --- a/src/Benchmarks.jl +++ b/src/Benchmarks.jl @@ -116,13 +116,13 @@ function benchmark_forward_problem(m::AbstractFEStateMap, φh, ranks; nreps = 10 end """ - benchmark_advection(stencil::AdvectionStencil, φ0, v0, γ, ranks; nreps) + benchmark_advection(stencil::LevelSetEvolution, φ0, v0, γ, ranks; nreps) Benchmark solving the Hamilton-Jacobi evolution equation given a `stencil`, level-set function `φ0`, velocity function `v0`, and time step coefficient `γ`. See [`advect!`](@ref) for input types. """ -function benchmark_advection(stencil::AdvectionStencil, φ0, v0, γ, ranks; nreps = 10) +function benchmark_advection(stencil::LevelSetEvolution, φ0, v0, γ, ranks; nreps = 10) function f(stencil,φ,v,γ) advect!(stencil,φ,v,γ) end @@ -136,12 +136,12 @@ function benchmark_advection(stencil::AdvectionStencil, φ0, v0, γ, ranks; nrep end """ - benchmark_reinitialisation(stencil::AdvectionStencil, φ0, γ_reinit, ranks; nreps) + benchmark_reinitialisation(stencil::LevelSetEvolution, φ0, γ_reinit, ranks; nreps) Benchmark solving the reinitialisation equation given a `stencil`, level-set function `φ0`, and time step coefficient `γ`. See [`reinit!`](@ref) for input types. """ -function benchmark_reinitialisation(stencil::AdvectionStencil, φ0, γ_reinit, ranks; nreps = 10) +function benchmark_reinitialisation(stencil::LevelSetEvolution, φ0, γ_reinit, ranks; nreps = 10) function f(stencil,φ,γ_reinit) reinit!(stencil,φ,γ_reinit) end From 8b60442857aa7e78aeddd64f47ba0ff2d14b4609 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 11:08:07 +1000 Subject: [PATCH 27/90] Rename advect! --- src/Benchmarks.jl | 4 ++-- src/LevelSetTopOpt.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Benchmarks.jl b/src/Benchmarks.jl index afffef2d..0c052a44 100644 --- a/src/Benchmarks.jl +++ b/src/Benchmarks.jl @@ -120,11 +120,11 @@ end Benchmark solving the Hamilton-Jacobi evolution equation given a `stencil`, level-set function `φ0`, velocity function `v0`, and time step coefficient `γ`. -See [`advect!`](@ref) for input types. +See [`evolve!`](@ref) for input types. """ function benchmark_advection(stencil::LevelSetEvolution, φ0, v0, γ, ranks; nreps = 10) function f(stencil,φ,v,γ) - advect!(stencil,φ,v,γ) + evolve!(stencil,φ,v,γ) end function reset!(stencil,φ,v,γ) copy!(φ,φ0) diff --git a/src/LevelSetTopOpt.jl b/src/LevelSetTopOpt.jl index cc30a752..5de30155 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/LevelSetTopOpt.jl @@ -55,7 +55,7 @@ export isotropic_elast_tensor include("LevelSetEvolution/LevelSetEvolution.jl") export HamiltonJacobiEvolution export FirstOrderStencil -export advect! +export evolve! export reinit! include("Solvers.jl") From 489f886c96d485e9070e6221bbc7ecab97a7751a Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 11:22:10 +1000 Subject: [PATCH 28/90] Update src/Optimisers/.. --- src/Optimisers/AugmentedLagrangian.jl | 45 ++++++++++++-------------- src/Optimisers/HilbertianProjection.jl | 37 +++++++++++---------- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index 3a44ea75..1c879508 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -1,5 +1,5 @@ """ - struct AugmentedLagrangian{N,O} <: Optimiser + struct AugmentedLagrangian <: Optimiser An augmented Lagrangian method based on Nocedal and Wright, 2006 ([link](https://doi.org/10.1007/978-0-387-40065-5)). Note that @@ -8,9 +8,8 @@ are defined in `problem::PDEConstrainedFunctionals`. # Parameters -- `problem::PDEConstrainedFunctionals{N}`: The objective and constraint setup. -- `stencil::AdvectionStencil{O}`: The finite difference stencil for - solving the evolution and reinitisation equations. +- `problem::PDEConstrainedFunctionals`: The objective and constraint setup. +- `ls_evolver::LevelSetEvolution`: Solver for the evolution and reinitisation equations. - `vel_ext::VelocityExtension`: The velocity-extension method for extending shape sensitivities onto the computational domain. - `history::OptimiserHistory{Float64}`: Historical information for optimisation problem. @@ -22,9 +21,9 @@ The `has_oscillations` function has been added to avoid oscillations in the iteration history. By default this uses a mean zero crossing algorithm as implemented in ChaosTools. Oscillations checking can be disabled by taking `has_oscillations = (args...) -> false`. """ -struct AugmentedLagrangian{N,O} <: Optimiser - problem :: PDEConstrainedFunctionals{N} - stencil :: AdvectionStencil{O} +struct AugmentedLagrangian <: Optimiser + problem :: PDEConstrainedFunctionals + ls_evolver :: LevelSetEvolution vel_ext :: VelocityExtension history :: OptimiserHistory{Float64} converged :: Function @@ -34,9 +33,9 @@ struct AugmentedLagrangian{N,O} <: Optimiser @doc """ AugmentedLagrangian( - problem :: PDEConstrainedFunctionals{N}, - stencil :: AdvectionStencil{O}, - vel_ext :: VelocityExtension, + problem :: PDEConstrainedFunctionals{N}, + ls_evolver :: LevelSetEvolution, + vel_ext :: VelocityExtension, φ0; Λ_max = 5.0, ζ = 1.1, update_mod = 5, γ = 0.1, γ_reinit = 0.5, os_γ_mult = 0.75, maxiter = 1000, verbose=false, constraint_names = map(i -> Symbol("C_\$i"),1:N), @@ -48,9 +47,8 @@ struct AugmentedLagrangian{N,O} <: Optimiser # Required - - `problem::PDEConstrainedFunctionals{N}`: The objective and constraint setup. - - `stencil::AdvectionStencil{O}`: The finite difference stencil for - solving the evolution and reinitisation equations. + - `problem::PDEConstrainedFunctionals`: The objective and constraint setup. + - `ls_evolver::LevelSetEvolution`: Solver for the evolution and reinitisation equations. - `vel_ext::VelocityExtension`: The velocity-extension method for extending shape sensitivities onto the computational domain. - `φ0`: An initial level-set function defined as a FEFunction or GridapDistributed equivilent. @@ -75,16 +73,16 @@ struct AugmentedLagrangian{N,O} <: Optimiser - `debug = false`: Debug flag. """ function AugmentedLagrangian( - problem :: PDEConstrainedFunctionals{N}, - stencil :: AdvectionStencil{O}, - vel_ext :: VelocityExtension, + problem :: PDEConstrainedFunctionals{N}, + ls_evolver :: LevelSetEvolution, + vel_ext :: VelocityExtension, φ0; Λ_max = 10^10, ζ = 1.1, update_mod = 5, reinit_mod = 1, γ = 0.1, γ_reinit = 0.5, os_γ_mult = 0.75, maxiter = 1000, verbose=false, constraint_names = map(i -> Symbol("C_$i"),1:N), converged::Function = default_al_converged, debug = false, has_oscillations::Function = default_has_oscillations, initial_parameters::Function = default_al_init_params - ) where {N,O} + ) where N constraint_names = map(Symbol,constraint_names) λ_names = map(i -> Symbol("λ$i"),1:N) @@ -94,7 +92,7 @@ struct AugmentedLagrangian{N,O} <: Optimiser history = OptimiserHistory(Float64,al_keys,al_bundles,maxiter,verbose) params = (;Λ_max,ζ,update_mod,reinit_mod,γ,γ_reinit,os_γ_mult,debug,initial_parameters) - new{N,O}(problem,stencil,vel_ext,history,converged,has_oscillations,params,φ0) + new(problem,ls_evolver,vel_ext,history,converged,has_oscillations,params,φ0) end end @@ -125,7 +123,7 @@ end function default_al_converged( m::AugmentedLagrangian; - L_tol = 0.01*maximum(m.stencil.params.Δ), + L_tol = 0.01*maximum(get_dof_Δ(m.ls_evolver)), C_tol = 0.01 ) h = m.history @@ -145,7 +143,7 @@ function Base.iterate(m::AugmentedLagrangian) φh, history, params = m.φ0, m.history, m.params ## Reinitialise as SDF - reinit!(m.stencil,φh,params.γ_reinit) + reinit!(m.ls_evolver,φh,params.γ_reinit) ## Compute FE problem and shape derivatives J, C, dJ, dC = evaluate!(m.problem,φh) @@ -176,8 +174,7 @@ end function Base.iterate(m::AugmentedLagrangian,state) it, L, J, C, dL, dJ, dC, uh, φh, vel, λ, Λ, γ, os_it = state params, history = m.params, m.history - update_mod, reinit_mod, ζ, Λ_max, γ_reinit, os_γ_mult = params.update_mod, - params.reinit_mod, params.ζ, params.Λ_max, params.γ_reinit, params.os_γ_mult + Λ_max,ζ,update_mod,reinit_mod,_,γ_reinit,os_γ_mult,_,_ = params ## Periodicially call GC iszero(it % 50) && GC.gc(); @@ -197,8 +194,8 @@ function Base.iterate(m::AugmentedLagrangian,state) U_reg = get_deriv_space(m.problem.state_map) V_φ = get_aux_space(m.problem.state_map) interpolate!(FEFunction(U_reg,dL),vel,V_φ) - advect!(m.stencil,φh,vel,γ) - iszero(it % reinit_mod) && reinit!(m.stencil,φh,γ_reinit) + evolve!(m.ls_evolver,φh,vel,γ) + iszero(it % reinit_mod) && reinit!(m.ls_evolver,φh,γ_reinit) ## Calculate objective, constraints, and shape derivatives J, C, dJ, dC = evaluate!(m.problem,φh) diff --git a/src/Optimisers/HilbertianProjection.jl b/src/Optimisers/HilbertianProjection.jl index 9cb75952..b4f18628 100644 --- a/src/Optimisers/HilbertianProjection.jl +++ b/src/Optimisers/HilbertianProjection.jl @@ -124,7 +124,7 @@ function compute_α(C,dC_orthog,dC,normsq,K,P,λ,α_min,α_max) end """ - struct HilbertianProjection{T,N} <: Optimiser + struct HilbertianProjection <: Optimiser A Hilbertian projection method as described by Wegert et al., 2023 ([link](https://doi.org/10.1007/s00158-023-03663-0)). @@ -132,8 +132,7 @@ A Hilbertian projection method as described by Wegert et al., 2023 # Parameters - `problem::PDEConstrainedFunctionals{N}`: The objective and constraint setup. -- `stencil::AdvectionStencil{O}`: The finite difference stencil for - solving the evolution and reinitisation equations. +- `ls_evolver::LevelSetEvolution`: Solver for the evolution and reinitisation equations. - `vel_ext::VelocityExtension`: The velocity-extension method for extending shape sensitivities onto the computational domain. - `projector::HilbertianProjectionMap`: Sensitivity information projector @@ -142,9 +141,9 @@ A Hilbertian projection method as described by Wegert et al., 2023 - `has_oscillations::Function`: A function to check for oscillations. - `params::NamedTuple`: Optimisation parameters. """ -struct HilbertianProjection{T,N} <: Optimiser - problem :: PDEConstrainedFunctionals{N} - stencil :: AdvectionStencil +struct HilbertianProjection <: Optimiser + problem :: PDEConstrainedFunctionals + ls_evolver :: LevelSetEvolution vel_ext :: VelocityExtension projector :: HilbertianProjectionMap history :: OptimiserHistory{Float64} @@ -156,7 +155,7 @@ struct HilbertianProjection{T,N} <: Optimiser @doc """ HilbertianProjection( problem :: PDEConstrainedFunctionals{N}, - stencil :: AdvectionStencil, + ls_evolver :: LevelSetEvolution, vel_ext :: VelocityExtension, φ0; orthog = HPModifiedGramSchmidt(), @@ -174,8 +173,7 @@ struct HilbertianProjection{T,N} <: Optimiser # Required - `problem::PDEConstrainedFunctionals{N}`: The objective and constraint setup. - - `stencil::AdvectionStencil{O}`: The finite difference stencil for - solving the evolution and reinitisation equations. + - `ls_evolver::LevelSetEvolution`: Solver for the evolution and reinitisation equations. - `vel_ext::VelocityExtension`: The velocity-extension method for extending shape sensitivities onto the computational domain. - `φ0`: An initial level-set function defined as a FEFunction or GridapDistributed equivilent. @@ -221,9 +219,9 @@ struct HilbertianProjection{T,N} <: Optimiser disabling the line search via `ls_enabled = false` will enable oscillation detection. """ function HilbertianProjection( - problem :: PDEConstrainedFunctionals{N}, - stencil :: AdvectionStencil, - vel_ext :: VelocityExtension, + problem :: PDEConstrainedFunctionals{N}, + ls_evolver :: LevelSetEvolution, + vel_ext :: VelocityExtension, φ0; orthog = HPModifiedGramSchmidt(), λ=0.5, α_min=0.1, α_max=1.0, γ=0.1, γ_reinit=0.5, reinit_mod = 1, @@ -234,7 +232,9 @@ struct HilbertianProjection{T,N} <: Optimiser converged::Function = default_hp_converged, debug = false, has_oscillations::Function = (ls_enabled ? (args...)->false : default_has_oscillations), os_γ_mult = 0.5 - ) where {N} + ) where N + + @assert α_min <= α_max "We require α_min <= α_max" constraint_names = map(Symbol,constraint_names) al_keys = [:J,constraint_names...,:γ] @@ -244,8 +244,7 @@ struct HilbertianProjection{T,N} <: Optimiser projector = HilbertianProjectionMap(N,orthog,vel_ext;λ,α_min,α_max,debug) params = (;debug,γ,γ_reinit,reinit_mod,ls_enabled,ls_max_iters,ls_δ_inc,ls_δ_dec,ls_ξ, ls_ξ_reduce_coef,ls_ξ_reduce_abs_tol,ls_γ_min,ls_γ_max,os_γ_mult) - T = typeof(orthog) - new{T,N}(problem,stencil,vel_ext,projector,history,converged, + new(problem,ls_evolver,vel_ext,projector,history,converged, has_oscillations,params,φ0) end end @@ -258,7 +257,7 @@ end function default_hp_converged( m::HilbertianProjection; - J_tol = 0.2*maximum(m.stencil.params.Δ), + J_tol = 0.2*maximum(get_dof_Δ(m.ls_evolver)), C_tol = 0.001 ) h = m.history @@ -296,7 +295,7 @@ function Base.iterate(m::HilbertianProjection) φh = m.φ0 ## Reinitialise as SDF - reinit!(m.stencil,φh,params.γ_reinit) + reinit!(m.ls_evolver,φh,params.γ_reinit) ## Compute FE problem and shape derivatives J, C, dJ, dC = Gridap.evaluate!(m.problem,φh) @@ -351,8 +350,8 @@ function Base.iterate(m::HilbertianProjection,state) φ = get_free_dof_values(φh); copy!(φ_tmp,φ) while !done && (ls_it <= ls_max_iters) # Advect & Reinitialise - advect!(m.stencil,φ,vel,γ) - iszero(it % reinit_mod) && reinit!(m.stencil,φ,params.γ_reinit) + evolve!(m.ls_evolver,φ,vel,γ) + iszero(it % reinit_mod) && reinit!(m.ls_evolver,φ,params.γ_reinit) ~ls_enabled && break From bea8cf2be9c0e989b4d711e1f674668912f45982 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 11:25:22 +1000 Subject: [PATCH 29/90] Update scripts --- scripts/Benchmarks/benchmark.jl | 8 ++++---- scripts/MPI/3d_elastic_compliance_ALM.jl | 2 +- scripts/MPI/3d_hyperelastic_compliance_ALM.jl | 2 +- scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl | 2 +- scripts/MPI/3d_inverse_homenisation_ALM.jl | 2 +- scripts/MPI/3d_inverter_ALM.jl | 2 +- scripts/MPI/3d_inverter_HPM.jl | 2 +- scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl | 2 +- scripts/MPI/3d_thermal_compliance_ALM.jl | 2 +- scripts/MPI/elastic_compliance_ALM.jl | 2 +- scripts/MPI/inverse_homenisation_ALM.jl | 2 +- scripts/MPI/thermal_compliance_ALM.jl | 2 +- scripts/MPI/thermal_compliance_ALM_PETSc.jl | 2 +- scripts/Serial/elastic_compliance_ALM.jl | 2 +- scripts/Serial/elastic_compliance_HPM.jl | 2 +- scripts/Serial/elastic_compliance_LM.jl | 2 +- scripts/Serial/hyperelastic_compliance_ALM.jl | 2 +- scripts/Serial/hyperelastic_compliance_neohook_ALM.jl | 2 +- scripts/Serial/inverse_homenisation_ALM.jl | 2 +- scripts/Serial/inverter_ALM.jl | 2 +- scripts/Serial/inverter_HPM.jl | 2 +- scripts/Serial/nonlinear_thermal_compliance_ALM.jl | 2 +- scripts/Serial/thermal_compliance_ALM.jl | 2 +- scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl | 2 +- scripts/_dev/3d_hyperelastic_compliance_ALM.jl | 2 +- scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl | 2 +- scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl | 2 +- scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 2 +- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 2 +- scripts/_dev/Paper_scripts/therm_comp_MPI.jl | 2 +- scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl | 2 +- scripts/_dev/Paper_scripts/therm_comp_serial.jl | 2 +- .../_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl | 2 +- .../_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl | 2 +- scripts/_dev/benchmark_tests/serial_benchmark_test.jl | 2 +- scripts/_dev/bug_issue_46/thermal_MPI.jl | 2 +- scripts/_dev/bug_issue_46/thermal_serial.jl | 2 +- scripts/_dev/full_piezo_script.jl | 2 +- scripts/_dev/inv_hom_block_assem_testing.jl | 2 +- scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl | 2 +- scripts/_dev/inv_hom_block_assem_testing_full_script.jl | 2 +- scripts/_dev/mem_leak.jl | 2 +- scripts/_dev/nonlinear_adjoint_MWE.jl | 2 +- .../minimum_thermal_compliance_implementation.jl | 2 +- .../minimum_thermal_compliance_implementation_3d.jl | 2 +- .../minimum_thermal_compliance_implementation_3d_petsc.jl | 2 +- ...imum_thermal_compliance_implementation_3d_petsc_mpi.jl | 2 +- ...minimum_thermal_compliance_implementation_nonlinear.jl | 2 +- 48 files changed, 51 insertions(+), 51 deletions(-) diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index 3c0fe455..759bf6e0 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -102,7 +102,7 @@ function nl_elast(mesh_partition,ranks,el_size,order,verbose) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) end @@ -180,7 +180,7 @@ function therm(mesh_partition,ranks,el_size,order,verbose) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) end @@ -256,7 +256,7 @@ function elast(mesh_partition,ranks,el_size,order,verbose) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) end @@ -329,7 +329,7 @@ function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_elastic_compliance_ALM.jl b/scripts/MPI/3d_elastic_compliance_ALM.jl index 58836523..d44fdff3 100644 --- a/scripts/MPI/3d_elastic_compliance_ALM.jl +++ b/scripts/MPI/3d_elastic_compliance_ALM.jl @@ -81,7 +81,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl index 6064ae61..c103beab 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl @@ -83,7 +83,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index 7b02dd0c..1a9fe02e 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -97,7 +97,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index ec6f7872..2fed57d8 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -85,7 +85,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_inverter_ALM.jl b/scripts/MPI/3d_inverter_ALM.jl index 0b600003..5d270952 100644 --- a/scripts/MPI/3d_inverter_ALM.jl +++ b/scripts/MPI/3d_inverter_ALM.jl @@ -99,7 +99,7 @@ function main(mesh_partition,distribute,el_size) UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_inverter_HPM.jl b/scripts/MPI/3d_inverter_HPM.jl index bd6d16e9..f1684cf0 100644 --- a/scripts/MPI/3d_inverter_HPM.jl +++ b/scripts/MPI/3d_inverter_HPM.jl @@ -99,7 +99,7 @@ function main(mesh_partition,distribute,el_size) UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl index f4f110d6..126309d5 100644 --- a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl @@ -85,7 +85,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index 0fa01deb..e0cea609 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -81,7 +81,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index fcfb451f..6fa7a17c 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -74,7 +74,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index 7a068021..ec4d8886 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -73,7 +73,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/MPI/thermal_compliance_ALM.jl b/scripts/MPI/thermal_compliance_ALM.jl index 8bb1e9aa..bce212f1 100644 --- a/scripts/MPI/thermal_compliance_ALM.jl +++ b/scripts/MPI/thermal_compliance_ALM.jl @@ -72,7 +72,7 @@ function main(mesh_partition,distribute) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/MPI/thermal_compliance_ALM_PETSc.jl b/scripts/MPI/thermal_compliance_ALM_PETSc.jl index 39bd0271..cfe2acd6 100644 --- a/scripts/MPI/thermal_compliance_ALM_PETSc.jl +++ b/scripts/MPI/thermal_compliance_ALM_PETSc.jl @@ -72,7 +72,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} diff --git a/scripts/Serial/elastic_compliance_ALM.jl b/scripts/Serial/elastic_compliance_ALM.jl index c313ef68..7cd20e1a 100644 --- a/scripts/Serial/elastic_compliance_ALM.jl +++ b/scripts/Serial/elastic_compliance_ALM.jl @@ -71,7 +71,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/Serial/elastic_compliance_HPM.jl b/scripts/Serial/elastic_compliance_HPM.jl index e7fe84c8..50964928 100644 --- a/scripts/Serial/elastic_compliance_HPM.jl +++ b/scripts/Serial/elastic_compliance_HPM.jl @@ -72,7 +72,7 @@ function main() dVol = (q,u,φ,dΩ,dΓ_N) -> ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/Serial/elastic_compliance_LM.jl b/scripts/Serial/elastic_compliance_LM.jl index 004e2119..0517ef1b 100644 --- a/scripts/Serial/elastic_compliance_LM.jl +++ b/scripts/Serial/elastic_compliance_LM.jl @@ -68,7 +68,7 @@ function main() dJ = (q,u,φ,dΩ,dΓ_N) -> ∫((- ξ + C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/Serial/hyperelastic_compliance_ALM.jl b/scripts/Serial/hyperelastic_compliance_ALM.jl index fe45ee8e..c455de7b 100644 --- a/scripts/Serial/hyperelastic_compliance_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_ALM.jl @@ -71,7 +71,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl index c212f0ef..03ea9f55 100644 --- a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl @@ -85,7 +85,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index 7779b851..c079c08c 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -71,7 +71,7 @@ function main() dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = RepeatingAffineFEStateMap(3,a,l,U,V,V_φ,U_reg,φh,dΩ) diff --git a/scripts/Serial/inverter_ALM.jl b/scripts/Serial/inverter_ALM.jl index d1144e2f..2774a9ea 100644 --- a/scripts/Serial/inverter_ALM.jl +++ b/scripts/Serial/inverter_ALM.jl @@ -86,7 +86,7 @@ function main() UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out) diff --git a/scripts/Serial/inverter_HPM.jl b/scripts/Serial/inverter_HPM.jl index ae21a683..f2587eec 100644 --- a/scripts/Serial/inverter_HPM.jl +++ b/scripts/Serial/inverter_HPM.jl @@ -87,7 +87,7 @@ function main() UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out) diff --git a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl index edbc0b1b..51597244 100644 --- a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl @@ -74,7 +74,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/Serial/thermal_compliance_ALM.jl b/scripts/Serial/thermal_compliance_ALM.jl index 44903c27..6ddf66cc 100644 --- a/scripts/Serial/thermal_compliance_ALM.jl +++ b/scripts/Serial/thermal_compliance_ALM.jl @@ -72,7 +72,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl index 9123a832..0b076760 100644 --- a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl +++ b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl @@ -78,7 +78,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) diff --git a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl b/scripts/_dev/3d_hyperelastic_compliance_ALM.jl index 2565536b..de79e6fc 100644 --- a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/_dev/3d_hyperelastic_compliance_ALM.jl @@ -153,7 +153,7 @@ function main_alt(mesh_partition,distribute,el_size,gz) res(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((T ∘ ∇(u)) ⊙ ∇(v)))dΩ - ∫(g⋅v)dΓ_N ## Finite difference solver and level set function - # stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + # stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) # reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl index 52871792..c903951a 100644 --- a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl @@ -78,7 +78,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl index 5b4730c5..6f463318 100644 --- a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl @@ -92,7 +92,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl index d15c424c..657b35c4 100644 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -82,7 +82,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index b9f3269c..75163cb0 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -88,7 +88,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl index 9b76c455..8320ff76 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl @@ -78,7 +78,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) # Solve diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl index 99be6ec8..3cb4f8ba 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl @@ -80,7 +80,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) diff --git a/scripts/_dev/Paper_scripts/therm_comp_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl index 78cd651c..9e7e2342 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_serial.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_serial.jl @@ -63,7 +63,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, verbose=true) diff --git a/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl b/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl index e4a309ad..2d09b546 100644 --- a/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl +++ b/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl @@ -62,7 +62,7 @@ function main(mesh_partition,el_size,ranks) dJ(q,u,φ,dΩ,dΓ_N) = ∫((-ξ+D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl b/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl index 37b149c8..5842ead6 100644 --- a/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl +++ b/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl @@ -68,7 +68,7 @@ function main(mesh_partition,distribute,el_size) dJ(q,u,φ,dΩ,dΓ_N) = ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl b/scripts/_dev/benchmark_tests/serial_benchmark_test.jl index 8de90168..0f8a784a 100644 --- a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl +++ b/scripts/_dev/benchmark_tests/serial_benchmark_test.jl @@ -56,7 +56,7 @@ function main() dJ(q,u,φ,dΩ,dΓ_N) = ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/bug_issue_46/thermal_MPI.jl b/scripts/_dev/bug_issue_46/thermal_MPI.jl index 2e4596ee..176e7b05 100644 --- a/scripts/_dev/bug_issue_46/thermal_MPI.jl +++ b/scripts/_dev/bug_issue_46/thermal_MPI.jl @@ -68,7 +68,7 @@ function main(mesh_partition,distribute,use_l::Bool) vel_ext = VelocityExtension(a_hilb, U_reg, V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) diff --git a/scripts/_dev/bug_issue_46/thermal_serial.jl b/scripts/_dev/bug_issue_46/thermal_serial.jl index e9c29a6c..b94a4d09 100644 --- a/scripts/_dev/bug_issue_46/thermal_serial.jl +++ b/scripts/_dev/bug_issue_46/thermal_serial.jl @@ -67,7 +67,7 @@ function main(use_l::Bool) vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/_dev/full_piezo_script.jl b/scripts/_dev/full_piezo_script.jl index 7cb7c149..49dc507a 100644 --- a/scripts/_dev/full_piezo_script.jl +++ b/scripts/_dev/full_piezo_script.jl @@ -92,7 +92,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ) = ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/inv_hom_block_assem_testing.jl b/scripts/_dev/inv_hom_block_assem_testing.jl index acd4c897..d8623a05 100644 --- a/scripts/_dev/inv_hom_block_assem_testing.jl +++ b/scripts/_dev/inv_hom_block_assem_testing.jl @@ -74,7 +74,7 @@ Vol = (u,φ,dΩ) -> ∫(((ρ ∘ φ) - 0.5)/vol_D)dΩ; dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function -stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol); +stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol); reinit!(stencil,φ,γ_reinit) ## Initialise op diff --git a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl b/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl index 4ab969a6..d0317914 100644 --- a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl +++ b/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl @@ -86,7 +86,7 @@ function main(mesh_partition,distribute,el_size,diag_assem::Bool) dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(3,Float64),model,V_φ,el_size./order,max_steps,tol) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,el_size./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl b/scripts/_dev/inv_hom_block_assem_testing_full_script.jl index f3c31fc2..13da1a00 100644 --- a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl +++ b/scripts/_dev/inv_hom_block_assem_testing_full_script.jl @@ -77,7 +77,7 @@ function main(diag_block) dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/mem_leak.jl b/scripts/_dev/mem_leak.jl index af9a2b28..2865affb 100644 --- a/scripts/_dev/mem_leak.jl +++ b/scripts/_dev/mem_leak.jl @@ -62,7 +62,7 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve diff --git a/scripts/_dev/nonlinear_adjoint_MWE.jl b/scripts/_dev/nonlinear_adjoint_MWE.jl index a84705a2..082e78e0 100644 --- a/scripts/_dev/nonlinear_adjoint_MWE.jl +++ b/scripts/_dev/nonlinear_adjoint_MWE.jl @@ -70,7 +70,7 @@ function main() J = (u,φ,dΩ,dΓ_N) -> ∫((I ∘ φ)*(D ∘ u)*∇(u)⋅∇(u) + ξ*(ρ ∘ φ))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl index 6867340e..c9f05eca 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl @@ -61,7 +61,7 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl index 0f167337..f6db4233 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl @@ -63,7 +63,7 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl index a8db1de4..b41760df 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl @@ -77,7 +77,7 @@ function main() ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl index d9fde797..7ea63770 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl @@ -78,7 +78,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl index 058f1f4f..69c03024 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl @@ -59,7 +59,7 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve From a8d2e265f673d33db34ead5aaa07a8e71f50e2dd Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 11:27:40 +1000 Subject: [PATCH 30/90] Update warmup script --- compile/warmup.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compile/warmup.jl b/compile/warmup.jl index c79ecbd1..70adbc03 100644 --- a/compile/warmup.jl +++ b/compile/warmup.jl @@ -70,7 +70,7 @@ function main(mesh_partition,distribute) dJ = (q,u,φ,dΩ,dΓ_N) -> ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators From 6358a6febfb2ff65730a388640b5e8ca45dacd61 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 11:34:29 +1000 Subject: [PATCH 31/90] Started updating docs --- docs/make.jl | 2 +- .../{advection.md => levelsetevolution.md} | 8 ++++---- docs/src/tutorials/minimum_thermal_compliance.md | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) rename docs/src/reference/{advection.md => levelsetevolution.md} (64%) diff --git a/docs/make.jl b/docs/make.jl index 67bba876..6edb2324 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,7 +30,7 @@ makedocs( "Reference" => [ "reference/optimisers.md", "reference/chainrules.md", - "reference/advection.md", + "reference/levelsetevolution.md", "reference/velext.md", "reference/io.md", "reference/utilities.md", diff --git a/docs/src/reference/advection.md b/docs/src/reference/levelsetevolution.md similarity index 64% rename from docs/src/reference/advection.md rename to docs/src/reference/levelsetevolution.md index 46166d58..a9ba77e4 100644 --- a/docs/src/reference/advection.md +++ b/docs/src/reference/levelsetevolution.md @@ -1,9 +1,9 @@ -# Advection +# LevelSetEvolution (NEED TO UPDATE THIS) -## `AdvectionStencil` +## `HamiltonJacobiEvolution` ```@docs -LevelSetTopOpt.AdvectionStencil -LevelSetTopOpt.AdvectionStencil(stencil::LevelSetTopOpt.Stencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) +LevelSetTopOpt.HamiltonJacobiEvolution +LevelSetTopOpt.HamiltonJacobiEvolution(stencil::LevelSetTopOpt.Stencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) LevelSetTopOpt.advect! LevelSetTopOpt.reinit! ``` diff --git a/docs/src/tutorials/minimum_thermal_compliance.md b/docs/src/tutorials/minimum_thermal_compliance.md index ddbb4337..5d1f4452 100644 --- a/docs/src/tutorials/minimum_thermal_compliance.md +++ b/docs/src/tutorials/minimum_thermal_compliance.md @@ -346,10 +346,10 @@ Both of these equations can be solved numerically on a Cartesian mesh using a fi ```julia # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) ``` -In the above we first build an object [`FirstOrderStencil`](@ref) that represents a finite difference stencil for a single step of the Hamilton-Jacobi evolution equation and reinitialisation equation. We use `length(el_size)` to indicate the dimension of the problem. We then create an [`AdvectionStencil`](@ref) which enables finite differencing on order `O` finite elements in serial or parallel. The [`AdvectionStencil`](@ref) object provides two important methods [`advect!`](@ref) and [`reinit!`](@ref) that correspond to solving the Hamilton-Jacobi evolution equation and reinitialisation equation, respectively. +In the above we first build an object [`FirstOrderStencil`](@ref) that represents a finite difference stencil for a single step of the Hamilton-Jacobi evolution equation and reinitialisation equation. We use `length(el_size)` to indicate the dimension of the problem. We then create an [`HamiltonJacobiEvolution`](@ref) which enables finite differencing on order `O` finite elements in serial or parallel. The [`HamiltonJacobiEvolution`](@ref) object provides two important methods [`advect!`](@ref) and [`reinit!`](@ref) that correspond to solving the Hamilton-Jacobi evolution equation and reinitialisation equation, respectively. ### Optimiser, visualisation and IO @@ -461,7 +461,7 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve @@ -604,7 +604,7 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve @@ -754,7 +754,7 @@ function main() ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve @@ -918,7 +918,7 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) + stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) @@ -1070,7 +1070,7 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = AdvectionStencil(scheme,model,V_φ,tol,max_steps) +stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve From 29e628029cbd79d5b34152bfd6a000f56adac3d8 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 11:50:08 +1000 Subject: [PATCH 32/90] Remove src/Advection.jl and ALM converge change --- src/Advection.jl | 501 -------------------------- src/Optimisers/AugmentedLagrangian.jl | 4 +- 2 files changed, 2 insertions(+), 503 deletions(-) delete mode 100644 src/Advection.jl diff --git a/src/Advection.jl b/src/Advection.jl deleted file mode 100644 index 241af032..00000000 --- a/src/Advection.jl +++ /dev/null @@ -1,501 +0,0 @@ -""" - abstract type Stencil - -Finite difference stencil for a single step of the Hamilton-Jacobi -evolution equation and reinitialisation equation. - -Your own stencil can be implemented by extending the methods below. -""" -abstract type Stencil end - -""" - allocate_caches(::Stencil,φ,vel) - -Allocate caches for a given `Stencil`. -""" -function allocate_caches(::Stencil,φ,vel) - nothing # By default, no caches are required. -end - -""" - reinit!(::Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) -> φ - -Single finite difference step of the reinitialisation equation for a given `Stencil`. -""" -function reinit!(::Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) - @abstractmethod -end - -""" - advect!(::Stencil,φ,vel,Δt,Δx,isperiodic,caches) -> φ - -Single finite difference step of the Hamilton-Jacobi evoluation equation for a given -`Stencil`. -""" -function advect!(::Stencil,φ,vel,Δt,Δx,isperiodic,caches) - @abstractmethod -end - -""" - compute_Δt(::Stencil,φ,vel) - -Compute the time step for the `Stencil`. -""" -function compute_Δt(::Stencil,φ,vel) - @abstractmethod -end - -""" - struct FirstOrderStencil{D,T} <: Stencil end - -A first order Godunov upwind difference scheme based on Osher and Fedkiw -([link](https://doi.org/10.1007/b98879)). -""" -struct FirstOrderStencil{D,T} <: Stencil - function FirstOrderStencil(D::Integer,::Type{T}) where T<:Real - new{D,T}() - end -end - -function allocate_caches(::FirstOrderStencil{2},φ,vel) - D⁺ʸ = similar(φ); D⁺ˣ = similar(φ) - D⁻ʸ = similar(φ); D⁻ˣ = similar(φ) - ∇⁺ = similar(φ); ∇⁻ = similar(φ) - return D⁺ʸ, D⁺ˣ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ -end - -function reinit!(::FirstOrderStencil{2,T},φ_new,φ,vel,Δt,Δx,isperiodic,caches) where T - D⁺ʸ, D⁺ˣ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ = caches - Δx, Δy = Δx - xperiodic,yperiodic = isperiodic - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)) - circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)) - # Sign approximation - ∇⁺ .= @. (D⁺ʸ - D⁻ʸ)/(2Δy); ~yperiodic ? ∇⁺[:,[1,end]] .= zero(T) : 0; - ∇⁻ .= @. (D⁺ˣ - D⁻ˣ)/(2Δx); ~xperiodic ? ∇⁻[[1,end],:] .= zero(T) : 0; - ϵₛ = minimum((Δx,Δy)) - vel .= @. φ/sqrt(φ^2 + ϵₛ^2*(∇⁺^2+∇⁻^2)) - # Forward (+) & Backward (-) - D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end] .= zero(T) : 0; - D⁺ˣ .= @. (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:] .= zero(T) : 0; - D⁻ʸ .= @. (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1] .= zero(T) : 0; - D⁻ˣ .= @. (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:] .= zero(T) : 0; - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2); - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2); - # Update - φ_new .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻ - vel) - return φ_new -end - -function advect!(::FirstOrderStencil{2,T},φ,vel,Δt,Δx,isperiodic,caches) where T - D⁺ʸ, D⁺ˣ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ = caches - Δx, Δy = Δx - xperiodic,yperiodic = isperiodic - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)) - circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)) - # Forward (+) & Backward (-) - D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end] .= zero(T) : 0; - D⁺ˣ .= @. (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:] .= zero(T) : 0; - D⁻ʸ .= @. (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1] .= zero(T) : 0; - D⁻ˣ .= @. (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:] .= zero(T) : 0; - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2) - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2) - # Update - φ .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻) - return φ -end - -function allocate_caches(::FirstOrderStencil{3},φ,vel) - D⁺ᶻ = similar(φ); D⁺ʸ = similar(φ); D⁺ˣ = similar(φ) - D⁻ᶻ = similar(φ); D⁻ʸ = similar(φ); D⁻ˣ = similar(φ) - ∇⁺ = similar(φ); ∇⁻ = similar(φ) - return D⁺ᶻ, D⁺ʸ, D⁺ˣ, D⁻ᶻ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻ -end - -function reinit!(::FirstOrderStencil{3,T},φ_new,φ,vel,Δt,Δx,isperiodic,caches) where T - D⁺ᶻ, D⁺ʸ, D⁺ˣ, D⁻ᶻ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻=caches - Δx, Δy, Δz = Δx - xperiodic,yperiodic,zperiodic = isperiodic - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1,0)); circshift!(D⁻ʸ,φ,(0,1,0)) - circshift!(D⁺ˣ,φ,(-1,0,0)); circshift!(D⁻ˣ,φ,(1,0,0)) - circshift!(D⁺ᶻ,φ,(0,0,-1)); circshift!(D⁻ᶻ,φ,(0,0,1)) - # Sign approximation - ∇⁺ .= @. (D⁺ʸ - D⁻ʸ)/(2Δy); ~yperiodic ? ∇⁺[:,[1,end],:] .= zero(T) : 0; - ∇⁻ .= @. (D⁺ˣ - D⁻ˣ)/(2Δx); ~xperiodic ? ∇⁻[[1,end],:,:] .= zero(T) : 0; - ∇⁺ .= @. ∇⁺^2+∇⁻^2 # |∇φ|² (partially computed) - ∇⁻ .= @. (D⁺ᶻ - D⁻ᶻ)/(2Δz); ~xperiodic ? ∇⁻[:,:,[1,end]] .= zero(T) : 0; - ϵₛ = minimum((Δx,Δy,Δz)) - vel .= @. φ/sqrt(φ^2 + ϵₛ^2*(∇⁺+∇⁻^2)) - # Forward (+) & Backward (-) - D⁺ʸ .= (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end,:] .= zero(T) : 0; - D⁺ˣ .= (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:,:] .= zero(T) : 0; - D⁺ᶻ .= (D⁺ᶻ - φ)/Δz; ~zperiodic ? D⁺ᶻ[:,:,end] .= zero(T) : 0; - D⁻ʸ .= (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1,:] .= zero(T) : 0; - D⁻ˣ .= (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:,:] .= zero(T) : 0; - D⁻ᶻ .= (φ - D⁻ᶻ)/Δz; ~zperiodic ? D⁻ᶻ[:,:,1] .= zero(T) : 0; - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2) - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2) - # Update - φ_new .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻ - vel) - return φ_new -end - -function advect!(::FirstOrderStencil{3,T},φ,vel,Δt,Δx,isperiodic,caches) where T - D⁺ᶻ, D⁺ʸ, D⁺ˣ, D⁻ᶻ, D⁻ʸ, D⁻ˣ, ∇⁺, ∇⁻=caches - Δx, Δy, Δz = Δx - xperiodic,yperiodic,zperiodic = isperiodic - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1,0)); circshift!(D⁻ʸ,φ,(0,1,0)) - circshift!(D⁺ˣ,φ,(-1,0,0)); circshift!(D⁻ˣ,φ,(1,0,0)) - circshift!(D⁺ᶻ,φ,(0,0,-1)); circshift!(D⁻ᶻ,φ,(0,0,1)) - # Forward (+) & Backward (-) - D⁺ʸ .= (D⁺ʸ - φ)/Δy; ~yperiodic ? D⁺ʸ[:,end,:] .= zero(T) : 0; - D⁺ˣ .= (D⁺ˣ - φ)/Δx; ~xperiodic ? D⁺ˣ[end,:,:] .= zero(T) : 0; - D⁺ᶻ .= (D⁺ᶻ - φ)/Δz; ~zperiodic ? D⁺ᶻ[:,:,end] .= zero(T) : 0; - D⁻ʸ .= (φ - D⁻ʸ)/Δy; ~yperiodic ? D⁻ʸ[:,1,:] .= zero(T) : 0; - D⁻ˣ .= (φ - D⁻ˣ)/Δx; ~xperiodic ? D⁻ˣ[1,:,:] .= zero(T) : 0; - D⁻ᶻ .= (φ - D⁻ᶻ)/Δz; ~zperiodic ? D⁻ᶻ[:,:,1] .= zero(T) : 0; - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2) - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2) - # Update - φ .= @. φ - Δt*(max(vel,0)*∇⁺ + min(vel,0)*∇⁻) - return φ -end - -function compute_Δt(::FirstOrderStencil{D,T},Δ,γ,φ,vel) where {D,T} - v_norm = maximum(abs,vel) - return γ * min(Δ...) / (eps(T)^2 + v_norm) -end - -""" - struct AdvectionStencil{O} - -Wrapper to enable finite differencing to solve the -Hamilton-Jacobi evolution equation and reinitialisation equation -on order `O` finite elements in serial or parallel. - -# Parameters - -- `stencil::Stencil`: Finite difference stencil for a single step HJ - equation and reinitialisation equation. -- `model`: A `CartesianDiscreteModel`. -- `space`: FE space for level-set function -- `perm`: A permutation vector -- `params`: Tuple of additional params -- `cache`: Stencil cache -""" -struct AdvectionStencil{O} - stencil :: Stencil - model - space - perm - params - cache -end - -""" - AdvectionStencil(stencil::Stencil,model,space,tol,max_steps,max_steps_reinit) - -Create an instance of `AdvectionStencil` given a stencil, model, FE space, and -additional optional arguments. This automatically creates the DoF permutation -to handle high-order finite elements. -""" -function AdvectionStencil( - stencil::Stencil, - model, - space, - tol=1.e-3, - max_steps=100, - max_steps_reinit=2000 -) - # Parameters - order, isperiodic, Δ, ndof = get_stencil_params(model,space) - params = (;isperiodic,Δ,ndof,max_steps,max_steps_reinit,tol) - - # Dof permutation - perm = create_dof_permutation(model,space,order) - - # Caches - φ, vel = zero_free_values(space), zero_free_values(space) - cache = allocate_caches(stencil,φ,vel,perm,order,ndof) - - return AdvectionStencil{order}(stencil,model,space,perm,params,cache) -end - -function get_stencil_params(model::CartesianDiscreteModel,space::FESpace) - order = get_order(first(Gridap.CellData.get_data(get_fe_basis(space)))) - desc = get_cartesian_descriptor(model) - isperiodic = desc.isperiodic - ndof = order .* desc.partition .+ 1 .- isperiodic - Δ = desc.sizes ./ order - return order, isperiodic, Δ, ndof -end - -function get_stencil_params(model::DistributedDiscreteModel,space::DistributedFESpace) - order, isperiodic, Δ, ndof = map(local_views(model),local_views(space)) do model, space - get_stencil_params(model,space) - end |> PartitionedArrays.tuple_of_arrays - - isperiodic = getany(isperiodic) - order = getany(order) - Δ = getany(Δ) - return order, isperiodic, Δ, ndof -end - -Gridap.ReferenceFEs.get_order(f::Gridap.Fields.LinearCombinationFieldVector) = get_order(f.fields) - -# Create dof permutation vector to enable finite differences on -# higher order Lagrangian finite elements on a Cartesian mesh. -function create_dof_permutation(model::CartesianDiscreteModel{Dc}, - space::UnconstrainedFESpace, - order::Integer) where Dc - function get_terms(poly::Polytope, orders) - _nodes, facenodes = Gridap.ReferenceFEs._compute_nodes(poly, orders) - terms = Gridap.ReferenceFEs._coords_to_terms(_nodes, orders) - return terms - end - desc = get_cartesian_descriptor(model) - - periodic = desc.isperiodic - ncells = desc.partition - ndofs = order .* ncells .+ 1 .- periodic - @check prod(ndofs) == num_free_dofs(space) - - new_dof_ids = CircularArray(LinearIndices(ndofs)) - n2o_dof_map = fill(-1,num_free_dofs(space)) - - terms = get_terms(first(get_polytopes(model)), fill(order,Dc)) - cell_dof_ids = get_cell_dof_ids(space) - cache_cell_dof_ids = array_cache(cell_dof_ids) - for (iC,cell) in enumerate(CartesianIndices(ncells)) - first_new_dof = order .* (Tuple(cell) .- 1) .+ 1 - new_dofs_range = map(i -> i:i+order,first_new_dof) - new_dofs = view(new_dof_ids,new_dofs_range...) - - cell_dofs = getindex!(cache_cell_dof_ids,cell_dof_ids,iC) - for (iDof, dof) in enumerate(cell_dofs) - t = terms[iDof] - #o2n_dof_map[dof] = new_dofs[t] - n2o_dof_map[new_dofs[t]] = dof - end - end - - return n2o_dof_map -end - -function create_dof_permutation(model::GridapDistributed.DistributedDiscreteModel, - space::GridapDistributed.DistributedFESpace, - order::Integer) - local_perms = map(local_views(model),local_views(space)) do model, space - create_dof_permutation(model,space,order) - end - return local_perms -end - -function PartitionedArrays.permute_indices(indices::LocalIndices,perm) - id = part_id(indices) - n_glob = global_length(indices) - l2g = view(local_to_global(indices),perm) - l2o = view(local_to_owner(indices),perm) - return LocalIndices(n_glob,id,l2g,l2o) -end - -function allocate_caches(s::Stencil,φ::Vector,vel::Vector,perm,order,ndofs) - stencil_caches = allocate_caches(s,reshape(φ,ndofs),reshape(vel,ndofs)) - φ_tmp = similar(φ) - vel_tmp = similar(vel) - perm_caches = (order >= 2) ? (similar(φ), similar(vel)) : nothing - return φ_tmp, vel_tmp, perm_caches, stencil_caches -end - -function allocate_caches(s::Stencil,φ::PVector,vel::PVector,perm,order,local_ndofs) - local_stencil_caches = map(local_views(φ),local_views(vel),local_views(local_ndofs)) do φ,vel,ndofs - allocate_caches(s,reshape(φ,ndofs),reshape(vel,ndofs)) - end - - perm_indices = map(permute_indices,partition(axes(φ,1)),perm) - perm_caches = (order >= 2) ? (pfill(0.0,perm_indices),pfill(0.0,perm_indices)) : nothing - - φ_tmp = (order >= 2) ? pfill(0.0,perm_indices) : similar(φ) - vel_tmp = (order >= 2) ? pfill(0.0,perm_indices) : similar(vel) - return φ_tmp, vel_tmp, perm_caches, local_stencil_caches -end - -function permute!(x_out,x_in,perm) - for (i_new,i_old) in enumerate(perm) - x_out[i_new] = x_in[i_old] - end - return x_out -end - -function permute!(x_out::PVector,x_in::PVector,perm) - map(permute!,partition(x_out),partition(x_in),perm) - return x_out -end - -function permute_inv!(x_out,x_in,perm) - for (i_new,i_old) in enumerate(perm) - x_out[i_old] = x_in[i_new] - end - return x_out -end -function permute_inv!(x_out::PVector,x_in::PVector,perm) - map(permute_inv!,partition(x_out),partition(x_in),perm) - return x_out -end - -function advect!(s::AdvectionStencil,φh,args...) - advect!(s,get_free_dof_values(φh),args...) -end - -""" - advect!(s::AdvectionStencil{O},φ,vel,γ) where O - -Solve the Hamilton-Jacobi evolution equation using the `AdvectionStencil`. - -# Hamilton-Jacobi evolution equation -``\\frac{\\partial\\phi}{\\partial t} + V(\\boldsymbol{x})\\lVert\\boldsymbol{\\nabla}\\phi\\rVert = 0,`` - -with ``\\phi(0,\\boldsymbol{x})=\\phi_0(\\boldsymbol{x})`` and ``\\boldsymbol{x}\\in D,~t\\in(0,T)``. - -# Arguments - -- `s::AdvectionStencil{O}`: Stencil for computation -- `φ`: level set function as a vector of degrees of freedom -- `vel`: the normal velocity as a vector of degrees of freedom -- `γ`: coeffient on the time step size. -""" -function advect!(s::AdvectionStencil{O},φ::PVector,vel::PVector,γ) where O - _, _, perm_caches, stencil_cache = s.cache - Δ, isperiodic, = s.params.Δ, s.params.isperiodic - ndof, max_steps = s.params.ndof, s.params.max_steps - - _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ - _vel = (O >= 2) ? permute!(perm_caches[2],vel,s.perm) : vel - - ## CFL Condition (requires γ≤1.0) - Δt = compute_Δt(s.stencil,Δ,γ,φ,vel) - for _ in 1:max_steps - # Apply operations across partitions - map(local_views(_φ),local_views(_vel),stencil_cache,ndof) do _φ,_vel,stencil_cache,S - φ_mat = reshape(_φ,S) - vel_mat = reshape(_vel,S) - advect!(s.stencil,φ_mat,vel_mat,Δt,Δ,isperiodic,stencil_cache) - end - # Update ghost nodes - consistent!(_φ) |> fetch - end - φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ - return φ -end - -function advect!(s::AdvectionStencil{O},φ::Vector,vel::Vector,γ) where O - _, _, perm_caches, stencil_cache = s.cache - Δ, isperiodic, = s.params.Δ, s.params.isperiodic - ndof, max_steps = s.params.ndof, s.params.max_steps - - _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ - _vel = (O >= 2) ? permute!(perm_caches[2],vel,s.perm) : vel - - ## CFL Condition (requires γ≤1.0) - Δt = compute_Δt(s.stencil,Δ,γ,φ,vel) - for _ in 1:max_steps - φ_mat = reshape(_φ,ndof) - vel_mat = reshape(_vel,ndof) - advect!(s.stencil,φ_mat,vel_mat,Δt,Δ,isperiodic,stencil_cache) - end - φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ - return φ -end - -function reinit!(s::AdvectionStencil,φh,args...) - reinit!(s,get_free_dof_values(φh),args...) -end - -""" - reinit!(s::AdvectionStencil{O},φ,γ) where O - -Solve the reinitialisation equation using the `AdvectionStencil`. - -# Reinitialisation equation -``\\frac{\\partial\\phi}{\\partial t} + \\mathrm{sign}(\\phi_0)(\\lVert\\boldsymbol{\\nabla}\\phi\\rVert-1) = 0,`` - -with ``\\phi(0,\\boldsymbol{x})=\\phi_0(\\boldsymbol{x})`` and ``\\boldsymbol{x}\\in D,~t\\in(0,T)``. - -# Arguments - -- `s::AdvectionStencil{O}`: Stencil for computation -- `φ`: level set function as a vector of degrees of freedom -- `γ`: coeffient on the time step size. -""" -function reinit!(s::AdvectionStencil{O},φ::PVector,γ) where O - φ_tmp, vel_tmp, perm_caches, stencil_cache = s.cache - Δ, isperiodic, ndof = s.params.Δ, s.params.isperiodic, s.params.ndof - tol, max_steps = s.params.tol, s.params.max_steps_reinit - - _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ - - ## CFL Condition (requires γ≤0.5). Note inform(vel_tmp) = 1.0 - Δt = compute_Δt(s.stencil,Δ,γ,_φ,1.0) - - # Apply operations across partitions - step = 1; err = maximum(abs,φ); fill!(φ_tmp,0.0) - while (err > tol) && (step <= max_steps) - # Step of 1st order upwind reinitialisation equation - map(local_views(φ_tmp),local_views(_φ),local_views(vel_tmp),stencil_cache,ndof) do φ_tmp,_φ,vel_tmp,stencil_cache,S - φ_tmp_mat = reshape(φ_tmp,S) - φ_mat = reshape(_φ,S) - vel_tmp_mat = reshape(vel_tmp,S) - reinit!(s.stencil,φ_tmp_mat,φ_mat,vel_tmp_mat,Δt,Δ,isperiodic,stencil_cache) - end - - # Compute error - _φ .-= φ_tmp # φ - φ_tmp - err = maximum(abs,_φ) - step += 1 - - # Update φ - copy!(_φ,φ_tmp) - consistent!(_φ) |> fetch # We exchange ghosts here! - end - φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ - return φ -end - -function reinit!(s::AdvectionStencil{O},φ::Vector,γ) where O - φ_tmp, vel_tmp, perm_caches, stencil_cache = s.cache - Δ, isperiodic, ndof = s.params.Δ, s.params.isperiodic, s.params.ndof - tol, max_steps = s.params.tol, s.params.max_steps_reinit - - _φ = (O >= 2) ? permute!(perm_caches[1],φ,s.perm) : φ - - ## CFL Condition (requires γ≤0.5) - Δt = compute_Δt(s.stencil,Δ,γ,_φ,1.0) - - # Apply operations across partitions - step = 1; err = maximum(abs,φ); fill!(φ_tmp,0.0) - while (err > tol) && (step <= max_steps) - # Step of 1st order upwind reinitialisation equation - φ_tmp_mat = reshape(φ_tmp,ndof) - φ_mat = reshape(_φ,ndof) - vel_tmp_mat = reshape(vel_tmp,ndof) - reinit!(s.stencil,φ_tmp_mat,φ_mat,vel_tmp_mat,Δt,Δ,isperiodic,stencil_cache) - - # Compute error - _φ .-= φ_tmp - err = maximum(abs,_φ) - step += 1 - - # Update φ - copy!(_φ,φ_tmp) - end - φ = (O >= 2) ? permute_inv!(φ,_φ,s.perm) : _φ - return φ -end diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index 1c879508..6c2d48b5 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -37,7 +37,7 @@ struct AugmentedLagrangian <: Optimiser ls_evolver :: LevelSetEvolution, vel_ext :: VelocityExtension, φ0; - Λ_max = 5.0, ζ = 1.1, update_mod = 5, γ = 0.1, γ_reinit = 0.5, os_γ_mult = 0.75, + Λ_max = 10^10, ζ = 1.1, update_mod = 5, γ = 0.1, γ_reinit = 0.5, os_γ_mult = 0.75, maxiter = 1000, verbose=false, constraint_names = map(i -> Symbol("C_\$i"),1:N), converged::Function = default_al_converged, debug = false, has_oscillations::Function = default_has_oscillations @@ -123,7 +123,7 @@ end function default_al_converged( m::AugmentedLagrangian; - L_tol = 0.01*maximum(get_dof_Δ(m.ls_evolver)), + L_tol = 0.01*maximum(get_dof_Δ(m.ls_evolver))/(length(get_dof_Δ(m.ls_evolver))-1), C_tol = 0.01 ) h = m.history From f142cd5e5b9b4b8d506ababf381815b5229018c9 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 14:29:56 +1000 Subject: [PATCH 33/90] Update docs --- docs/src/reference/levelsetevolution.md | 34 +++++++++++++------ docs/src/reference/optimisers.md | 2 +- .../tutorials/minimum_thermal_compliance.md | 2 +- .../HamiltonJacobiEvolution.jl | 8 ++--- src/LevelSetEvolution/SpatialStencil.jl | 6 ++-- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/docs/src/reference/levelsetevolution.md b/docs/src/reference/levelsetevolution.md index a9ba77e4..3fd8ebf4 100644 --- a/docs/src/reference/levelsetevolution.md +++ b/docs/src/reference/levelsetevolution.md @@ -1,25 +1,39 @@ -# LevelSetEvolution (NEED TO UPDATE THIS) +# LevelSetEvolution +In LevelSetTopOpt, the level set is evolved and reinitialised using a `LevelSetEvolution` method. The most standard of these is the Hamilton-Jacobi evolution equation solved using a first order upwind finite difference scheme. A forward Euler in time method is provided below via `HamiltonJacobiEvolution <: LevelSetEvolution` along with an upwind finite difference stencil for the spatial discretisation via `FirstOrderStencil`. + +This can be extended in several ways. For example, higher order spatial stencils can be implemented by extending the `SpatialStencil` interface below. In addition, more advanced ODE solvers could be implemented (e.g., Runge–Kutta methods) or entirely different level set evolution methods by extending the `LevelSetEvolution` interface below. ## `HamiltonJacobiEvolution` ```@docs LevelSetTopOpt.HamiltonJacobiEvolution -LevelSetTopOpt.HamiltonJacobiEvolution(stencil::LevelSetTopOpt.Stencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) -LevelSetTopOpt.advect! +LevelSetTopOpt.HamiltonJacobiEvolution(stencil::LevelSetTopOpt.SpatialStencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) +LevelSetTopOpt.evolve! LevelSetTopOpt.reinit! +LevelSetTopOpt.get_dof_Δ(m::HamiltonJacobiEvolution) ``` -## Stencils +## Spatial stencils for `HamiltonJacobiEvolution` ```@docs LevelSetTopOpt.FirstOrderStencil ``` -## Custom `Stencil` +## Custom `SpatialStencil` + +```@docs +LevelSetTopOpt.SpatialStencil +LevelSetTopOpt.evolve!(::LevelSetTopOpt.SpatialStencil,φ,vel,Δt,Δx,isperiodic,caches) +LevelSetTopOpt.reinit!(::LevelSetTopOpt.SpatialStencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) +LevelSetTopOpt.allocate_caches(::LevelSetTopOpt.SpatialStencil,φ,vel) +LevelSetTopOpt.check_order +``` + +## Custom `LevelSetEvolution` +To implement a custom level set evolution method, we can extend the methods below. For example, one could consider Reaction-Diffusion-based evolution of the level set function. This can be solved with a finite element method and so we can implement a new type that inherits from `LevelSetEvolution` independently of the `SpatialStencil` types. ```@docs -LevelSetTopOpt.Stencil -LevelSetTopOpt.advect!(::LevelSetTopOpt.Stencil,φ,vel,Δt,Δx,isperiodic,caches) -LevelSetTopOpt.reinit!(::LevelSetTopOpt.Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) -LevelSetTopOpt.compute_Δt(::LevelSetTopOpt.Stencil,φ,vel) -LevelSetTopOpt.allocate_caches(::LevelSetTopOpt.Stencil,φ,vel) +LevelSetTopOpt.LevelSetEvolution +LevelSetTopOpt.evolve!(::LevelSetTopOpt.LevelSetEvolution,φ,args...) +LevelSetTopOpt.reinit!(::LevelSetTopOpt.LevelSetEvolution,φ,args...) +LevelSetTopOpt.get_dof_Δ(::LevelSetTopOpt.LevelSetEvolution) ``` \ No newline at end of file diff --git a/docs/src/reference/optimisers.md b/docs/src/reference/optimisers.md index f886ccf2..502759d3 100644 --- a/docs/src/reference/optimisers.md +++ b/docs/src/reference/optimisers.md @@ -23,7 +23,7 @@ LevelSetTopOpt.OptimiserHistory LevelSetTopOpt.OptimiserHistorySlice ``` -## Custom optimiser +## Custom `Optimiser` ```@docs LevelSetTopOpt.Optimiser LevelSetTopOpt.iterate(::LevelSetTopOpt.Optimiser) diff --git a/docs/src/tutorials/minimum_thermal_compliance.md b/docs/src/tutorials/minimum_thermal_compliance.md index 5d1f4452..0839f6e7 100644 --- a/docs/src/tutorials/minimum_thermal_compliance.md +++ b/docs/src/tutorials/minimum_thermal_compliance.md @@ -349,7 +349,7 @@ scheme = FirstOrderStencil(length(el_size),Float64) stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) ``` -In the above we first build an object [`FirstOrderStencil`](@ref) that represents a finite difference stencil for a single step of the Hamilton-Jacobi evolution equation and reinitialisation equation. We use `length(el_size)` to indicate the dimension of the problem. We then create an [`HamiltonJacobiEvolution`](@ref) which enables finite differencing on order `O` finite elements in serial or parallel. The [`HamiltonJacobiEvolution`](@ref) object provides two important methods [`advect!`](@ref) and [`reinit!`](@ref) that correspond to solving the Hamilton-Jacobi evolution equation and reinitialisation equation, respectively. +In the above we first build an object [`FirstOrderStencil`](@ref) that represents a finite difference stencil for a single step of the Hamilton-Jacobi evolution equation and reinitialisation equation. We use `length(el_size)` to indicate the dimension of the problem. We then create an [`HamiltonJacobiEvolution`](@ref) which enables finite differencing on order `O` finite elements in serial or parallel. The [`HamiltonJacobiEvolution`](@ref) object provides two important methods [`evolve!`](@ref) and [`reinit!`](@ref) that correspond to solving the Hamilton-Jacobi evolution equation and reinitialisation equation, respectively. ### Optimiser, visualisation and IO diff --git a/src/LevelSetEvolution/HamiltonJacobiEvolution.jl b/src/LevelSetEvolution/HamiltonJacobiEvolution.jl index 8e86f07a..f8052495 100644 --- a/src/LevelSetEvolution/HamiltonJacobiEvolution.jl +++ b/src/LevelSetEvolution/HamiltonJacobiEvolution.jl @@ -59,7 +59,7 @@ function HamiltonJacobiEvolution( end """ - get_dof_Δ(::HamiltonJacobiEvolution) + get_dof_Δ(m::HamiltonJacobiEvolution) Return the distance betweem degree of freedom """ @@ -67,11 +67,7 @@ function get_dof_Δ(m::HamiltonJacobiEvolution) return m.params.Δ end -""" - compute_Δt(::HamiltonJacobiEvolution,φ,vel) - -Compute the time step for the `HamiltonJacobiEvolution`. -""" +# Compute the time step for the `HamiltonJacobiEvolution`. function compute_Δt(::HamiltonJacobiEvolution,Δ,γ,φ,vel) T = eltype(γ) v_norm = maximum(abs,vel) diff --git a/src/LevelSetEvolution/SpatialStencil.jl b/src/LevelSetEvolution/SpatialStencil.jl index 12dd6469..f306442f 100644 --- a/src/LevelSetEvolution/SpatialStencil.jl +++ b/src/LevelSetEvolution/SpatialStencil.jl @@ -1,10 +1,10 @@ """ abstract type SpatialStencil -Finite difference stencil for a single step of the Hamilton-Jacobi +Spatial finite difference stencil for a single step of the Hamilton-Jacobi evolution equation and reinitialisation equation. -Your own stencil can be implemented by extending the methods below. +Your own spatial stencil can be implemented by extending the methods below. """ abstract type SpatialStencil end @@ -49,7 +49,7 @@ end """ struct FirstOrderStencil{D,T} <: SpatialStencil end -A first order Godunov upwind difference scheme based on Osher and Fedkiw +A first order upwind difference scheme based on Osher and Fedkiw ([link](https://doi.org/10.1007/b98879)). """ struct FirstOrderStencil{D,T} <: SpatialStencil From 02321bc923529c2f75707d283ee2ff26db5ef52c Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 14:31:18 +1000 Subject: [PATCH 34/90] Fix precompile bug for SmoothErsatzMaterialInterpolation --- src/Utilities.jl | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Utilities.jl b/src/Utilities.jl index aede0bd2..25f6ab57 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -22,17 +22,24 @@ function ``\\varphi`` and ``I`` is an indicator function. - To update η and/or ϵ in an instance `m`, take `m.η .= `. - A conviencence constructor is provided to create an instance given `η<:Number` and `ϵ<:Number`. """ -Base.@kwdef struct SmoothErsatzMaterialInterpolation{M<:Vector{<:Number},N<:Vector{<:Number}} +struct SmoothErsatzMaterialInterpolation{M<:Vector{<:Number},N<:Vector{<:Number}} η::M ϵ::N - H = x -> H_η(x,first(η)) - DH = x -> DH_η(x,first(η)) - I = φ -> (1 - H(φ)) + first(ϵ)*H(φ) - ρ = φ -> 1 - H(φ) -end - -function SmoothErsatzMaterialInterpolation(;η::M,ϵ::N=10^-3) where {M<:Number,N<:Number} - return SmoothErsatzMaterialInterpolation{Vector{M},Vector{N}}(η=[η],ϵ=[ϵ]) + H + DH + I + ρ + function SmoothErsatzMaterialInterpolation(; + η::M, + ϵ::N = 10^-3, + H = x -> H_η(x,first(η)), + DH = x -> DH_η(x,first(η)), + I = φ -> (1 - H(φ)) + first(ϵ)*H(φ), + ρ = φ -> 1 - H(φ) + ) where {M<:Number,N<:Number} + + new{Vector{M},Vector{N}}([η],[ϵ],H,DH,I,ρ) + end end function H_η(t,η) From 51b6cd15d85315fea102020b1365344911f48330 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Wed, 10 Apr 2024 14:35:35 +1000 Subject: [PATCH 35/90] Update stop --- src/Optimisers/AugmentedLagrangian.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index 3a44ea75..20bcfd19 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -38,7 +38,7 @@ struct AugmentedLagrangian{N,O} <: Optimiser stencil :: AdvectionStencil{O}, vel_ext :: VelocityExtension, φ0; - Λ_max = 5.0, ζ = 1.1, update_mod = 5, γ = 0.1, γ_reinit = 0.5, os_γ_mult = 0.75, + Λ_max = 10^10, ζ = 1.1, update_mod = 5, γ = 0.1, γ_reinit = 0.5, os_γ_mult = 0.75, maxiter = 1000, verbose=false, constraint_names = map(i -> Symbol("C_\$i"),1:N), converged::Function = default_al_converged, debug = false, has_oscillations::Function = default_has_oscillations @@ -125,7 +125,7 @@ end function default_al_converged( m::AugmentedLagrangian; - L_tol = 0.01*maximum(m.stencil.params.Δ), + L_tol = 0.01*maximum(m.stencil.params.Δ)/(length(m.stencil.params.Δ)-1), C_tol = 0.01 ) h = m.history From ae39c6cb382b8fd7b067cd2fb503411f2fdf3cb1 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 10 Apr 2024 16:51:56 +1000 Subject: [PATCH 36/90] Rename stencil in scripts --- compile/warmup.jl | 4 +-- .../tutorials/minimum_thermal_compliance.md | 26 +++++++++---------- scripts/Benchmarks/benchmark.jl | 16 ++++++------ scripts/MPI/3d_elastic_compliance_ALM.jl | 4 +-- scripts/MPI/3d_hyperelastic_compliance_ALM.jl | 4 +-- .../3d_hyperelastic_compliance_neohook_ALM.jl | 4 +-- scripts/MPI/3d_inverse_homenisation_ALM.jl | 4 +-- scripts/MPI/3d_inverter_ALM.jl | 4 +-- scripts/MPI/3d_inverter_HPM.jl | 4 +-- .../3d_nonlinear_thermal_compliance_ALM.jl | 4 +-- scripts/MPI/3d_thermal_compliance_ALM.jl | 4 +-- scripts/MPI/elastic_compliance_ALM.jl | 4 +-- scripts/MPI/inverse_homenisation_ALM.jl | 4 +-- scripts/MPI/thermal_compliance_ALM.jl | 4 +-- scripts/MPI/thermal_compliance_ALM_PETSc.jl | 4 +-- scripts/Serial/elastic_compliance_ALM.jl | 4 +-- scripts/Serial/elastic_compliance_HPM.jl | 4 +-- scripts/Serial/elastic_compliance_LM.jl | 4 +-- scripts/Serial/hyperelastic_compliance_ALM.jl | 4 +-- .../hyperelastic_compliance_neohook_ALM.jl | 4 +-- scripts/Serial/inverse_homenisation_ALM.jl | 4 +-- scripts/Serial/inverter_ALM.jl | 4 +-- scripts/Serial/inverter_HPM.jl | 4 +-- .../nonlinear_thermal_compliance_ALM.jl | 4 +-- scripts/Serial/thermal_compliance_ALM.jl | 4 +-- .../thermal_compliance_ALM_higherorderlsf.jl | 4 +-- .../_dev/3d_hyperelastic_compliance_ALM.jl | 2 +- .../_dev/Paper_scripts/elast_comp_MPI_3D.jl | 4 +-- .../Paper_scripts/hyperelast_comp_MPI_3D.jl | 4 +-- .../_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 4 +-- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 4 +-- scripts/_dev/Paper_scripts/therm_comp_MPI.jl | 4 +-- .../_dev/Paper_scripts/therm_comp_MPI_3D.jl | 4 +-- .../_dev/Paper_scripts/therm_comp_serial.jl | 4 +-- .../MPI_benchmark_test_2D_themal.jl | 4 +-- .../MPI_benchmark_test_3D_themal.jl | 4 +-- .../benchmark_tests/serial_benchmark_test.jl | 4 +-- scripts/_dev/bug_issue_46/thermal_MPI.jl | 4 +-- scripts/_dev/bug_issue_46/thermal_serial.jl | 4 +-- scripts/_dev/full_piezo_script.jl | 4 +-- scripts/_dev/inv_hom_block_assem_testing.jl | 2 +- .../inv_hom_block_assem_testing_3D_MPI.jl | 4 +-- ...inv_hom_block_assem_testing_full_script.jl | 4 +-- scripts/_dev/mem_leak.jl | 4 +-- scripts/_dev/nonlinear_adjoint_MWE.jl | 2 +- ...nimum_thermal_compliance_implementation.jl | 4 +-- ...um_thermal_compliance_implementation_3d.jl | 4 +-- ...rmal_compliance_implementation_3d_petsc.jl | 4 +-- ..._compliance_implementation_3d_petsc_mpi.jl | 4 +-- ...mal_compliance_implementation_nonlinear.jl | 4 +-- test/seq/ThermalComplianceALMTests.jl | 4 +-- 51 files changed, 116 insertions(+), 116 deletions(-) diff --git a/compile/warmup.jl b/compile/warmup.jl index 70adbc03..c2b6e5e3 100644 --- a/compile/warmup.jl +++ b/compile/warmup.jl @@ -70,7 +70,7 @@ function main(mesh_partition,distribute) dJ = (q,u,φ,dΩ,dΓ_N) -> ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators @@ -84,7 +84,7 @@ function main(mesh_partition,distribute) ## Optimiser _conv_cond = t->LevelSetTopOpt.conv_cond(t;coef=1/50); - optimiser = AugmentedLagrangian(φ,pcfs,stencil,vel_ext,interp,el_size,γ,γ_reinit,conv_criterion=_conv_cond); + optimiser = AugmentedLagrangian(φ,pcfs,ls_evo,vel_ext,interp,el_size,γ,γ_reinit,conv_criterion=_conv_cond); for history in optimiser it,Ji,_,_ = last(history) print_history(it,["J"=>Ji];ranks=ranks) diff --git a/docs/src/tutorials/minimum_thermal_compliance.md b/docs/src/tutorials/minimum_thermal_compliance.md index 0839f6e7..3d52db3c 100644 --- a/docs/src/tutorials/minimum_thermal_compliance.md +++ b/docs/src/tutorials/minimum_thermal_compliance.md @@ -346,7 +346,7 @@ Both of these equations can be solved numerically on a Cartesian mesh using a fi ```julia # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) ``` In the above we first build an object [`FirstOrderStencil`](@ref) that represents a finite difference stencil for a single step of the Hamilton-Jacobi evolution equation and reinitialisation equation. We use `length(el_size)` to indicate the dimension of the problem. We then create an [`HamiltonJacobiEvolution`](@ref) which enables finite differencing on order `O` finite elements in serial or parallel. The [`HamiltonJacobiEvolution`](@ref) object provides two important methods [`evolve!`](@ref) and [`reinit!`](@ref) that correspond to solving the Hamilton-Jacobi evolution equation and reinitialisation equation, respectively. @@ -357,7 +357,7 @@ We may now create the optimiser object. This structure holds all information reg ```julia # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) ``` As optimisers inheriting from [`LevelSetTopOpt.Optimiser`](@ref) implement Julia's iterator functionality, we can solve the optimisation problem to convergence by iterating over the optimiser: @@ -461,9 +461,9 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] @@ -604,9 +604,9 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] @@ -754,9 +754,9 @@ function main() ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] @@ -827,7 +827,7 @@ We then adjust lines 28-31 as follows: The function `i_am_main` returns true only on the first processor. This function is useful for ensuring certain operations only happen once instead of several times across each executable. In addition, we now create a partitioned Cartesian model using `CartesianDiscreteModel(ranks,mesh_partition,dom,el_size)`. Finally, we adjust line 82 to ensure that verbosity only happens on the first processors: ```julia -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) ``` @@ -918,9 +918,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser @@ -1070,9 +1070,9 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index 759bf6e0..862262d7 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -102,9 +102,9 @@ function nl_elast(mesh_partition,ranks,el_size,order,verbose) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) end function therm(mesh_partition,ranks,el_size,order,verbose) @@ -180,9 +180,9 @@ function therm(mesh_partition,ranks,el_size,order,verbose) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) end function elast(mesh_partition,ranks,el_size,order,verbose) @@ -256,9 +256,9 @@ function elast(mesh_partition,ranks,el_size,order,verbose) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose) + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) end function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) @@ -329,7 +329,7 @@ function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -355,7 +355,7 @@ function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) ) ## Optimiser - return HilbertianProjection(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=verbose) + return HilbertianProjection(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=verbose) end with_mpi() do distribute diff --git a/scripts/MPI/3d_elastic_compliance_ALM.jl b/scripts/MPI/3d_elastic_compliance_ALM.jl index d44fdff3..558d05d8 100644 --- a/scripts/MPI/3d_elastic_compliance_ALM.jl +++ b/scripts/MPI/3d_elastic_compliance_ALM.jl @@ -81,7 +81,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -107,7 +107,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl index c103beab..6cd67d04 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl @@ -83,7 +83,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -110,7 +110,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index 1a9fe02e..8ad44dc4 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -97,7 +97,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -124,7 +124,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index 2fed57d8..1746a942 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -85,7 +85,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -111,7 +111,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] diff --git a/scripts/MPI/3d_inverter_ALM.jl b/scripts/MPI/3d_inverter_ALM.jl index 5d270952..4fa6ee26 100644 --- a/scripts/MPI/3d_inverter_ALM.jl +++ b/scripts/MPI/3d_inverter_ALM.jl @@ -99,7 +99,7 @@ function main(mesh_partition,distribute,el_size) UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -125,7 +125,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol,:UΓ_out]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/3d_inverter_HPM.jl b/scripts/MPI/3d_inverter_HPM.jl index f1684cf0..3aacbfe1 100644 --- a/scripts/MPI/3d_inverter_HPM.jl +++ b/scripts/MPI/3d_inverter_HPM.jl @@ -99,7 +99,7 @@ function main(mesh_partition,distribute,el_size) UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -126,7 +126,7 @@ function main(mesh_partition,distribute,el_size) ## Optimiser ls_enabled=false # Setting to true will use a line search instead of oscillation detection - optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh;γ,γ_reinit,ls_enabled,α_min=0.7, + optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,ls_enabled,α_min=0.7, ls_γ_max=0.05,verbose=i_am_main(ranks),constraint_names=[:Vol,:UΓ_out]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl index 126309d5..e3bbfde2 100644 --- a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl @@ -85,7 +85,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -113,7 +113,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index e0cea609..2c63d3e0 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -81,7 +81,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -107,7 +107,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index 6fa7a17c..76a48e2b 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -74,7 +74,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -98,7 +98,7 @@ function main(mesh_partition,distribute,el_size) ls=PETScLinearSolver()) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index ec4d8886..55fe3af0 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -73,7 +73,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -99,7 +99,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] diff --git a/scripts/MPI/thermal_compliance_ALM.jl b/scripts/MPI/thermal_compliance_ALM.jl index bce212f1..db881e3e 100644 --- a/scripts/MPI/thermal_compliance_ALM.jl +++ b/scripts/MPI/thermal_compliance_ALM.jl @@ -72,7 +72,7 @@ function main(mesh_partition,distribute) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -84,7 +84,7 @@ function main(mesh_partition,distribute) vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/MPI/thermal_compliance_ALM_PETSc.jl b/scripts/MPI/thermal_compliance_ALM_PETSc.jl index cfe2acd6..366f13ef 100644 --- a/scripts/MPI/thermal_compliance_ALM_PETSc.jl +++ b/scripts/MPI/thermal_compliance_ALM_PETSc.jl @@ -72,7 +72,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} @@ -98,7 +98,7 @@ function main(mesh_partition,distribute,el_size) ) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks),constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/elastic_compliance_ALM.jl b/scripts/Serial/elastic_compliance_ALM.jl index 7cd20e1a..6b8e4d17 100644 --- a/scripts/Serial/elastic_compliance_ALM.jl +++ b/scripts/Serial/elastic_compliance_ALM.jl @@ -71,7 +71,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -83,7 +83,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/elastic_compliance_HPM.jl b/scripts/Serial/elastic_compliance_HPM.jl index 50964928..d13be2c1 100644 --- a/scripts/Serial/elastic_compliance_HPM.jl +++ b/scripts/Serial/elastic_compliance_HPM.jl @@ -72,7 +72,7 @@ function main() dVol = (q,u,φ,dΩ,dΓ_N) -> ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -84,7 +84,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh; + optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/elastic_compliance_LM.jl b/scripts/Serial/elastic_compliance_LM.jl index 0517ef1b..3accdfac 100644 --- a/scripts/Serial/elastic_compliance_LM.jl +++ b/scripts/Serial/elastic_compliance_LM.jl @@ -68,7 +68,7 @@ function main() dJ = (q,u,φ,dΩ,dΓ_N) -> ∫((- ξ + C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -80,7 +80,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true) + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) diff --git a/scripts/Serial/hyperelastic_compliance_ALM.jl b/scripts/Serial/hyperelastic_compliance_ALM.jl index c455de7b..63b9e1bf 100644 --- a/scripts/Serial/hyperelastic_compliance_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_ALM.jl @@ -71,7 +71,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -83,7 +83,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl index 03ea9f55..72738c4e 100644 --- a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl @@ -85,7 +85,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -97,7 +97,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index c079c08c..0ffdd411 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -71,7 +71,7 @@ function main() dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = RepeatingAffineFEStateMap(3,a,l,U,V,V_φ,U_reg,φh,dΩ) @@ -83,7 +83,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] diff --git a/scripts/Serial/inverter_ALM.jl b/scripts/Serial/inverter_ALM.jl index 2774a9ea..132a32e3 100644 --- a/scripts/Serial/inverter_ALM.jl +++ b/scripts/Serial/inverter_ALM.jl @@ -86,7 +86,7 @@ function main() UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out) @@ -98,7 +98,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol,:UΓ_out]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/inverter_HPM.jl b/scripts/Serial/inverter_HPM.jl index f2587eec..39ed22a0 100644 --- a/scripts/Serial/inverter_HPM.jl +++ b/scripts/Serial/inverter_HPM.jl @@ -87,7 +87,7 @@ function main() UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out) @@ -100,7 +100,7 @@ function main() ## Optimiser ls_enabled=false # Setting to true will use a line search instead of oscillation detection - optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh; + optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,α_min=0.4,ls_enabled,verbose=true,constraint_names=[:Vol,:UΓ_out]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl index 51597244..621060a2 100644 --- a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl @@ -74,7 +74,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -86,7 +86,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it, uh, φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/thermal_compliance_ALM.jl b/scripts/Serial/thermal_compliance_ALM.jl index 6ddf66cc..9cd0883e 100644 --- a/scripts/Serial/thermal_compliance_ALM.jl +++ b/scripts/Serial/thermal_compliance_ALM.jl @@ -72,7 +72,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -84,7 +84,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl index 0b076760..1cbc6344 100644 --- a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl +++ b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl @@ -78,7 +78,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -90,7 +90,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl b/scripts/_dev/3d_hyperelastic_compliance_ALM.jl index de79e6fc..ddc16243 100644 --- a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/_dev/3d_hyperelastic_compliance_ALM.jl @@ -153,7 +153,7 @@ function main_alt(mesh_partition,distribute,el_size,gz) res(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((T ∘ ∇(u)) ⊙ ∇(v)))dΩ - ∫(g⋅v)dΓ_N ## Finite difference solver and level set function - # stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + # ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) # reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl index c903951a..d177d1da 100644 --- a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl @@ -78,9 +78,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl index 6f463318..bef8a90d 100644 --- a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl @@ -92,9 +92,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl index 657b35c4..af7c2735 100644 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -82,9 +82,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index 75163cb0..d2e25582 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -88,9 +88,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl index 8320ff76..902742bf 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl @@ -78,9 +78,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl index 3cb4f8ba..5104e0d6 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl @@ -80,9 +80,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=i_am_main(ranks)) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/Paper_scripts/therm_comp_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl index 9e7e2342..0b53164f 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_serial.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_serial.jl @@ -63,9 +63,9 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit, + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, verbose=true) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl b/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl index 2d09b546..9a0c3e3f 100644 --- a/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl +++ b/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl @@ -62,7 +62,7 @@ function main(mesh_partition,el_size,ranks) dJ(q,u,φ,dΩ,dΓ_N) = ∫((-ξ+D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators @@ -75,7 +75,7 @@ function main(mesh_partition,el_size,ranks) vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit) + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit) end with_debug() do distribute diff --git a/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl b/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl index 5842ead6..b04bbac8 100644 --- a/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl +++ b/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl @@ -68,7 +68,7 @@ function main(mesh_partition,distribute,el_size) dJ(q,u,φ,dΩ,dΓ_N) = ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators @@ -96,7 +96,7 @@ function main(mesh_partition,distribute,el_size) ## Optimiser make_dir(path;ranks=ranks) - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit) + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit) end with_mpi() do distribute diff --git a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl b/scripts/_dev/benchmark_tests/serial_benchmark_test.jl index 0f8a784a..17eb71cf 100644 --- a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl +++ b/scripts/_dev/benchmark_tests/serial_benchmark_test.jl @@ -56,7 +56,7 @@ function main() dJ(q,u,φ,dΩ,dΓ_N) = ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators @@ -69,7 +69,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - return AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit) + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit) end function main_benchmark() diff --git a/scripts/_dev/bug_issue_46/thermal_MPI.jl b/scripts/_dev/bug_issue_46/thermal_MPI.jl index 176e7b05..f318893d 100644 --- a/scripts/_dev/bug_issue_46/thermal_MPI.jl +++ b/scripts/_dev/bug_issue_46/thermal_MPI.jl @@ -68,9 +68,9 @@ function main(mesh_partition,distribute,use_l::Bool) vel_ext = VelocityExtension(a_hilb, U_reg, V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/bug_issue_46/thermal_serial.jl b/scripts/_dev/bug_issue_46/thermal_serial.jl index b94a4d09..2d0e2017 100644 --- a/scripts/_dev/bug_issue_46/thermal_serial.jl +++ b/scripts/_dev/bug_issue_46/thermal_serial.jl @@ -67,9 +67,9 @@ function main(use_l::Bool) vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/full_piezo_script.jl b/scripts/_dev/full_piezo_script.jl index 49dc507a..7ed4c1ab 100644 --- a/scripts/_dev/full_piezo_script.jl +++ b/scripts/_dev/full_piezo_script.jl @@ -92,7 +92,7 @@ function main(mesh_partition,distribute,el_size) dVol(q,u,φ,dΩ) = ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators @@ -126,7 +126,7 @@ function main(mesh_partition,distribute,el_size) # ## Optimiser # make_dir(path;ranks=ranks) - # optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) + # optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) # for (it, uh, φh) in optimiser # write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) # write_history(path*"/history.txt",optimiser.history;ranks=ranks) diff --git a/scripts/_dev/inv_hom_block_assem_testing.jl b/scripts/_dev/inv_hom_block_assem_testing.jl index d8623a05..14d2b24a 100644 --- a/scripts/_dev/inv_hom_block_assem_testing.jl +++ b/scripts/_dev/inv_hom_block_assem_testing.jl @@ -74,7 +74,7 @@ Vol = (u,φ,dΩ) -> ∫(((ρ ∘ φ) - 0.5)/vol_D)dΩ; dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function -stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol); +ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol); reinit!(stencil,φ,γ_reinit) ## Initialise op diff --git a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl b/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl index d0317914..3c7e57a6 100644 --- a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl +++ b/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl @@ -86,7 +86,7 @@ function main(mesh_partition,distribute,el_size,diag_assem::Bool) dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,el_size./order,max_steps,tol) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,el_size./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators @@ -130,7 +130,7 @@ function main(mesh_partition,distribute,el_size,diag_assem::Bool) ## Optimiser make_dir(path;ranks=ranks) - optimiser = AugmentedLagrangian(φ,pcfs,stencil,vel_ext,interp,el_size,γ,γ_reinit); + optimiser = AugmentedLagrangian(φ,pcfs,ls_evo,vel_ext,interp,el_size,γ,γ_reinit); for history in optimiser it,Ji,Ci,Li = last(history) λi = optimiser.λ; Λi = optimiser.Λ diff --git a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl b/scripts/_dev/inv_hom_block_assem_testing_full_script.jl index 13da1a00..46d9baf3 100644 --- a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl +++ b/scripts/_dev/inv_hom_block_assem_testing_full_script.jl @@ -77,7 +77,7 @@ function main(diag_block) dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators @@ -109,7 +109,7 @@ function main(diag_block) ## Optimiser make_dir(path) - optimiser = AugmentedLagrangian(φ,pcfs,stencil,vel_ext,interp,el_size,γ,γ_reinit); + optimiser = AugmentedLagrangian(φ,pcfs,ls_evo,vel_ext,interp,el_size,γ,γ_reinit); for history in optimiser it,Ji,Ci,Li = last(history) λi = optimiser.λ; Λi = optimiser.Λ diff --git a/scripts/_dev/mem_leak.jl b/scripts/_dev/mem_leak.jl index 2865affb..278ec667 100644 --- a/scripts/_dev/mem_leak.jl +++ b/scripts/_dev/mem_leak.jl @@ -62,9 +62,9 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for i = 1:10 LevelSetTopOpt.rrule(state_map,φh) diff --git a/scripts/_dev/nonlinear_adjoint_MWE.jl b/scripts/_dev/nonlinear_adjoint_MWE.jl index 082e78e0..df5fe18a 100644 --- a/scripts/_dev/nonlinear_adjoint_MWE.jl +++ b/scripts/_dev/nonlinear_adjoint_MWE.jl @@ -70,7 +70,7 @@ function main() J = (u,φ,dΩ,dΓ_N) -> ∫((I ∘ φ)*(D ∘ u)*∇(u)⋅∇(u) + ξ*(ρ ∘ φ))dΩ ## Finite difference solver and level set function - stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) reinit!(stencil,φ,γ_reinit) ## Setup solver and FE operators diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl index c9f05eca..91dbabaa 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl @@ -61,9 +61,9 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl index f6db4233..8218dabf 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl @@ -63,9 +63,9 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl index b41760df..10c1dacf 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl @@ -77,9 +77,9 @@ function main() ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl index 7ea63770..1b88fd91 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl @@ -78,9 +78,9 @@ function main(mesh_partition,distribute) ) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) - stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl index 69c03024..3642fb95 100644 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl +++ b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl @@ -59,9 +59,9 @@ a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) # Finite difference scheme scheme = FirstOrderStencil(length(el_size),Float64) -stencil = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) +ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) # Optimiser -optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) +optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Solve for (it,uh,φh) in optimiser data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] diff --git a/test/seq/ThermalComplianceALMTests.jl b/test/seq/ThermalComplianceALMTests.jl index 1d227f11..a5891838 100644 --- a/test/seq/ThermalComplianceALMTests.jl +++ b/test/seq/ThermalComplianceALMTests.jl @@ -71,7 +71,7 @@ function main() dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -83,7 +83,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh; + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) # Do a few iterations From 7603a8934548635565f36748b90e7f0a9d064564 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:08:32 +1000 Subject: [PATCH 37/90] Undo Stencil naming --- docs/src/reference/levelsetevolution.md | 16 +++++----- .../HamiltonJacobiEvolution.jl | 14 ++++---- src/LevelSetEvolution/LevelSetEvolution.jl | 2 +- .../{SpatialStencil.jl => Stencil.jl} | 32 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) rename src/LevelSetEvolution/{SpatialStencil.jl => Stencil.jl} (89%) diff --git a/docs/src/reference/levelsetevolution.md b/docs/src/reference/levelsetevolution.md index 3fd8ebf4..3f41a926 100644 --- a/docs/src/reference/levelsetevolution.md +++ b/docs/src/reference/levelsetevolution.md @@ -1,12 +1,12 @@ # LevelSetEvolution In LevelSetTopOpt, the level set is evolved and reinitialised using a `LevelSetEvolution` method. The most standard of these is the Hamilton-Jacobi evolution equation solved using a first order upwind finite difference scheme. A forward Euler in time method is provided below via `HamiltonJacobiEvolution <: LevelSetEvolution` along with an upwind finite difference stencil for the spatial discretisation via `FirstOrderStencil`. -This can be extended in several ways. For example, higher order spatial stencils can be implemented by extending the `SpatialStencil` interface below. In addition, more advanced ODE solvers could be implemented (e.g., Runge–Kutta methods) or entirely different level set evolution methods by extending the `LevelSetEvolution` interface below. +This can be extended in several ways. For example, higher order spatial stencils can be implemented by extending the `Stencil` interface below. In addition, more advanced ODE solvers could be implemented (e.g., Runge–Kutta methods) or entirely different level set evolution methods by extending the `LevelSetEvolution` interface below. ## `HamiltonJacobiEvolution` ```@docs LevelSetTopOpt.HamiltonJacobiEvolution -LevelSetTopOpt.HamiltonJacobiEvolution(stencil::LevelSetTopOpt.SpatialStencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) +LevelSetTopOpt.HamiltonJacobiEvolution(stencil::LevelSetTopOpt.Stencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) LevelSetTopOpt.evolve! LevelSetTopOpt.reinit! LevelSetTopOpt.get_dof_Δ(m::HamiltonJacobiEvolution) @@ -18,18 +18,18 @@ LevelSetTopOpt.get_dof_Δ(m::HamiltonJacobiEvolution) LevelSetTopOpt.FirstOrderStencil ``` -## Custom `SpatialStencil` +## Custom `Stencil` ```@docs -LevelSetTopOpt.SpatialStencil -LevelSetTopOpt.evolve!(::LevelSetTopOpt.SpatialStencil,φ,vel,Δt,Δx,isperiodic,caches) -LevelSetTopOpt.reinit!(::LevelSetTopOpt.SpatialStencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) -LevelSetTopOpt.allocate_caches(::LevelSetTopOpt.SpatialStencil,φ,vel) +LevelSetTopOpt.Stencil +LevelSetTopOpt.evolve!(::LevelSetTopOpt.Stencil,φ,vel,Δt,Δx,isperiodic,caches) +LevelSetTopOpt.reinit!(::LevelSetTopOpt.Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) +LevelSetTopOpt.allocate_caches(::LevelSetTopOpt.Stencil,φ,vel) LevelSetTopOpt.check_order ``` ## Custom `LevelSetEvolution` -To implement a custom level set evolution method, we can extend the methods below. For example, one could consider Reaction-Diffusion-based evolution of the level set function. This can be solved with a finite element method and so we can implement a new type that inherits from `LevelSetEvolution` independently of the `SpatialStencil` types. +To implement a custom level set evolution method, we can extend the methods below. For example, one could consider Reaction-Diffusion-based evolution of the level set function. This can be solved with a finite element method and so we can implement a new type that inherits from `LevelSetEvolution` independently of the `Stencil` types. ```@docs LevelSetTopOpt.LevelSetEvolution diff --git a/src/LevelSetEvolution/HamiltonJacobiEvolution.jl b/src/LevelSetEvolution/HamiltonJacobiEvolution.jl index f8052495..06dba88b 100644 --- a/src/LevelSetEvolution/HamiltonJacobiEvolution.jl +++ b/src/LevelSetEvolution/HamiltonJacobiEvolution.jl @@ -9,16 +9,16 @@ Based on the scheme by Osher and Fedkiw ([link](https://doi.org/10.1007/b98879)) # Parameters -- `stencil::SpatialStencil`: Spatial finite difference stencil for a single step HJ +- `stencil::Stencil`: Spatial finite difference stencil for a single step HJ equation and reinitialisation equation. - `model`: A `CartesianDiscreteModel`. - `space`: FE space for level-set function - `perm`: A permutation vector - `params`: Tuple of additional params -- `cache`: SpatialStencil cache +- `cache`: Stencil cache """ struct HamiltonJacobiEvolution{O} <: LevelSetEvolution - stencil :: SpatialStencil + stencil :: Stencil model space perm @@ -27,14 +27,14 @@ struct HamiltonJacobiEvolution{O} <: LevelSetEvolution end """ - HamiltonJacobiEvolution(stencil::SpatialStencil,model,space,tol,max_steps,max_steps_reinit) + HamiltonJacobiEvolution(stencil::Stencil,model,space,tol,max_steps,max_steps_reinit) Create an instance of `HamiltonJacobiEvolution` given a stencil, model, FE space, and additional optional arguments. This automatically creates the DoF permutation to handle high-order finite elements. """ function HamiltonJacobiEvolution( - stencil::SpatialStencil, + stencil::Stencil, model, space, tol=1.e-3, @@ -302,7 +302,7 @@ function PartitionedArrays.permute_indices(indices::LocalIndices,perm) return LocalIndices(n_glob,id,l2g,l2o) end -function allocate_caches(s::SpatialStencil,φ::Vector,vel::Vector,perm,order,ndofs) +function allocate_caches(s::Stencil,φ::Vector,vel::Vector,perm,order,ndofs) stencil_caches = allocate_caches(s,reshape(φ,ndofs),reshape(vel,ndofs)) φ_tmp = similar(φ) vel_tmp = similar(vel) @@ -310,7 +310,7 @@ function allocate_caches(s::SpatialStencil,φ::Vector,vel::Vector,perm,order,ndo return φ_tmp, vel_tmp, perm_caches, stencil_caches end -function allocate_caches(s::SpatialStencil,φ::PVector,vel::PVector,perm,order,local_ndofs) +function allocate_caches(s::Stencil,φ::PVector,vel::PVector,perm,order,local_ndofs) local_stencil_caches = map(local_views(φ),local_views(vel),local_views(local_ndofs)) do φ,vel,ndofs allocate_caches(s,reshape(φ,ndofs),reshape(vel,ndofs)) end diff --git a/src/LevelSetEvolution/LevelSetEvolution.jl b/src/LevelSetEvolution/LevelSetEvolution.jl index d6a743f4..6f9c4f32 100644 --- a/src/LevelSetEvolution/LevelSetEvolution.jl +++ b/src/LevelSetEvolution/LevelSetEvolution.jl @@ -35,5 +35,5 @@ function get_dof_Δ(::LevelSetEvolution) @abstractmethod end -include("SpatialStencil.jl") +include("Stencil.jl") include("HamiltonJacobiEvolution.jl") \ No newline at end of file diff --git a/src/LevelSetEvolution/SpatialStencil.jl b/src/LevelSetEvolution/Stencil.jl similarity index 89% rename from src/LevelSetEvolution/SpatialStencil.jl rename to src/LevelSetEvolution/Stencil.jl index f306442f..4b15e82e 100644 --- a/src/LevelSetEvolution/SpatialStencil.jl +++ b/src/LevelSetEvolution/Stencil.jl @@ -1,58 +1,58 @@ """ - abstract type SpatialStencil + abstract type Stencil -Spatial finite difference stencil for a single step of the Hamilton-Jacobi +Finite difference stencil for a single step of the Hamilton-Jacobi evolution equation and reinitialisation equation. Your own spatial stencil can be implemented by extending the methods below. """ -abstract type SpatialStencil end +abstract type Stencil end """ - allocate_caches(::SpatialStencil,φ,vel) + allocate_caches(::Stencil,φ,vel) -Allocate caches for a given `SpatialStencil`. +Allocate caches for a given `Stencil`. """ -function allocate_caches(::SpatialStencil,φ,vel) +function allocate_caches(::Stencil,φ,vel) nothing # By default, no caches are required. end """ - check_order(::SpatialStencil,order) + check_order(::Stencil,order) Throw error if insufficient reference element order to implement stencil in parallel. """ -function check_order(::SpatialStencil,order) +function check_order(::Stencil,order) @abstractmethod end """ - reinit!(::SpatialStencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) -> φ + reinit!(::Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) -> φ -Single finite difference step of the reinitialisation equation for a given `SpatialStencil`. +Single finite difference step of the reinitialisation equation for a given `Stencil`. """ -function reinit!(::SpatialStencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) +function reinit!(::Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) @abstractmethod end """ - evolve!(::SpatialStencil,φ,vel,Δt,Δx,isperiodic,caches) -> φ + evolve!(::Stencil,φ,vel,Δt,Δx,isperiodic,caches) -> φ Single finite difference step of the Hamilton-Jacobi evoluation equation for a given -`SpatialStencil`. +`Stencil`. """ -function evolve!(::SpatialStencil,φ,vel,Δt,Δx,isperiodic,caches) +function evolve!(::Stencil,φ,vel,Δt,Δx,isperiodic,caches) @abstractmethod end """ - struct FirstOrderStencil{D,T} <: SpatialStencil end + struct FirstOrderStencil{D,T} <: Stencil end A first order upwind difference scheme based on Osher and Fedkiw ([link](https://doi.org/10.1007/b98879)). """ -struct FirstOrderStencil{D,T} <: SpatialStencil +struct FirstOrderStencil{D,T} <: Stencil function FirstOrderStencil(D::Integer,::Type{T}) where T<:Real new{D,T}() end From 32f70e63a01b475935828fe4b5fb6e1db58aafa0 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 11 Apr 2024 08:55:16 +1000 Subject: [PATCH 38/90] Improvements to docs --- docs/src/getting-started.md | 5 ++++- docs/src/reference/io.md | 1 + docs/src/reference/optimisers.md | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/src/getting-started.md b/docs/src/getting-started.md index 5b9eed32..485fb54f 100644 --- a/docs/src/getting-started.md +++ b/docs/src/getting-started.md @@ -32,8 +32,11 @@ In order to get familiar with the library we recommend following the numerical e > Zachary J. Wegert, Jordi M. Fuertes, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. +In addition, there are several driver scripts available in `/scripts/..` + More general tutorials for familiarising ones self with Gridap are available via the [Gridap Tutorials](https://gridap.github.io/Tutorials/dev/). ## Known issues - PETSc's GAMG preconditioner breaks for split Dirichlet DoFs (e.g., x constrained while y free for a single node). There is no simple fix for this. We recommend instead using MUMPS or another preconditioner for this case. -- Currently, our implementation of automatic differentiation does not support multiplication and division of optimisation functionals. We plan to add this in a future release of `LevelSetTopOpt.jl`. \ No newline at end of file +- Currently, our implementation of automatic differentiation does not support multiplication and division of optimisation functionals. We plan to add this in a future release of `LevelSetTopOpt.jl` -- Issue [#38](https://github.com/zjwegert/LSTO_Distributed/issues/38). +- Analytic gradient breaks in parallel for integrals of certain measures -- Issue [#46](https://github.com/zjwegert/LSTO_Distributed/issues/46) \ No newline at end of file diff --git a/docs/src/reference/io.md b/docs/src/reference/io.md index 5adc2248..e4c4ff89 100644 --- a/docs/src/reference/io.md +++ b/docs/src/reference/io.md @@ -1,4 +1,5 @@ # IO +In LevelSetTopOpt, the usual IO from [Gridap](https://github.com/gridap/Gridap.jl/) is available. In addition, we also implement the below IO for convenience. ## Optimiser history ```@docs diff --git a/docs/src/reference/optimisers.md b/docs/src/reference/optimisers.md index f886ccf2..647dea10 100644 --- a/docs/src/reference/optimisers.md +++ b/docs/src/reference/optimisers.md @@ -1,5 +1,9 @@ # Optimisers +In LevelSetTopOpt we implement optimisation algorithms as [iterators](https://docs.julialang.org/en/v1/manual/interfaces/) that inherit from an abstract type `Optimiser`. A concrete `Optimiser` implementation, say `OptEg`, then implements `iterate(m::OptEg) ↦ (var,state)` and `iterate(m::OptEg,state) ↦ (var,state)`, where `var` and `state` are the available items in the outer loop and internal state of the iterator, respectively. As a result we can iterate over the object `m=OptEg(...)` using `for var in m`. The benefit of this implementation is that the internals of the optimisation method can be hidden in the source code while the explicit `for` loop is still visible to the user. The body of the loop can then be used for auxiliary operations such as writing the optimiser history and other files. + +The below describes the implemented optimisers along with the `OptimiserHistory` type. Custom optimisers can be implemented by creating types that inherit from `Optimiser` and extending the interfaces in [Custom optimiser](@ref). + ## Lagrangian & Augmented Lagrangian method ```@autodocs Modules = [LevelSetTopOpt] From dd2ca0e58dca545eb2158bcf4a10a5c2da412571 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:02:27 +1000 Subject: [PATCH 39/90] Adjust for consistency --- scripts/_dev/Paper_scripts/therm_comp_serial.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/_dev/Paper_scripts/therm_comp_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl index 78cd651c..b80a31c4 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_serial.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_serial.jl @@ -3,7 +3,7 @@ using LevelSetTopOpt, Gridap function main() # FE parameters order = 1 # Finite element order - xmax = ymax = 1.0 # Domain size + xmax,ymax = (1.0,1.0) # Domain size dom = (0,xmax,0,ymax) # Bounding domain el_size = (200,200) # Mesh partition size prop_Γ_N = 0.2 # Γ_N size parameter From 5e84e209125846baee32e79cfcf8fc72485fb716 Mon Sep 17 00:00:00 2001 From: Z J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:10:59 +1000 Subject: [PATCH 40/90] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..9772d89f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 [Zachary Wegert](mailto:zach.wegert@hdr.qut.edu.au), [Jordi Fuertes](mailto:jordi.manyer@monash.edu), [Connor Mallon](mailto:connor.mallon@monash.edu), [Santiago Badia](mailto:santiago.badia@monash.edu) and [Vivien Challis](mailto:vivien.challis@qut.edu.au) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 8c79b884ff0e846f307f7819dbc4e1ae84b5f081 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:12:06 +1000 Subject: [PATCH 41/90] Missing .md --- LICENSE => LICENSE.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENSE => LICENSE.md (100%) diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md From 7e4a0e87d93e2401839abeb5832c48a48f92023d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 11 Apr 2024 17:33:08 +1000 Subject: [PATCH 42/90] Bugfix: Distributed RepeatingAffineFEStateMaps --- Project.toml | 1 + scripts/MPI/inverse_homenisation_ALM.jl | 6 +++--- src/ChainRules.jl | 3 ++- src/GridapExtensions.jl | 17 +++++++++++++++-- src/LevelSetTopOpt.jl | 1 + 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Project.toml b/Project.toml index 5bb5edb6..8e0627a6 100755 --- a/Project.toml +++ b/Project.toml @@ -13,6 +13,7 @@ DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" Gridap = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" GridapDistributed = "f9701e48-63b3-45aa-9a63-9bc6c271f355" +GridapP4est = "c2c8e14b-f5fd-423d-9666-1dd9ad120af9" GridapPETSc = "bcdc36c2-0c3e-11ea-095a-c9dadae499f1" GridapSolvers = "6d3209ee-5e3c-4db7-a716-942eb12ed534" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index 7a068021..b5f52841 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -21,14 +21,14 @@ function main(mesh_partition,distribute,el_size) γ = 0.05 γ_reinit = 0.5 max_steps = floor(Int,order*minimum(el_size)/10) - tol = 1/(5order^2)/minimum(el_size) + tol = 1/(5*order^2)/minimum(el_size) C = isotropic_elast_tensor(2,1.,0.3) η_coeff = 2 - α_coeff = 4max_steps*γ + α_coeff = 4*max_steps*γ vf = 0.5 path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_MPI/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + #i_am_main(ranks) && mkdir(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true)); diff --git a/src/ChainRules.jl b/src/ChainRules.jl index f201a9c5..5ecc930d 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -714,7 +714,8 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap U, V = repeat_spaces(nblocks,U0,V0) spaces = (U,V,V_φ,U_reg) assem_U = SparseMatrixAssembler( - get_matrix_type(assem_U0),get_vector_type(assem_U0),U,V,FESpaces.get_assembly_strategy(assem_U0) + get_local_matrix_type(assem_U0), get_local_vector_type(assem_U0), + U, V, get_assembly_strategy(assem_U0) ) ## Pullback cache diff --git a/src/GridapExtensions.jl b/src/GridapExtensions.jl index f209d0f7..51b5d1e8 100644 --- a/src/GridapExtensions.jl +++ b/src/GridapExtensions.jl @@ -59,7 +59,7 @@ function assemble_adjoint_matrix!(f::Function,A::AbstractMatrix,a::Assembler,U:: end # Assembly addons - +""" function Gridap.FESpaces.allocate_matrix(a::Function,assem::Assembler,U::FESpace,V::FESpace) v = get_fe_basis(V) u = get_trial_fe_basis(U) @@ -77,6 +77,18 @@ function Gridap.FESpaces.assemble_matrix_and_vector!( u = get_trial_fe_basis(U) assemble_matrix_and_vector!(A,b,assem,collect_cell_matrix_and_vector(U,V,a(u,v),l(v),uhd)) end +""" + +get_local_matrix_type(a::Assembler) = get_matrix_type(a) +get_local_vector_type(a::Assembler) = get_vector_type(a) + +function get_local_matrix_type(a::GridapDistributed.DistributedSparseMatrixAssembler) + return getany(map(get_matrix_type,a.assems)) +end + +function get_local_vector_type(a::GridapDistributed.DistributedSparseMatrixAssembler) + return getany(map(get_vector_type,a.assems)) +end # PETScNonlinearSolver override @@ -88,8 +100,9 @@ function Gridap.Algebra.solve!(x::T,nls::PETScNonlinearSolver,op::Gridap.Algebra end # Stuff from ODE refactor - +""" function (+)(a::Gridap.CellData.DomainContribution,b::GridapDistributed.DistributedDomainContribution) @assert iszero(Gridap.CellData.num_domains(a)) return b end +""" \ No newline at end of file diff --git a/src/LevelSetTopOpt.jl b/src/LevelSetTopOpt.jl index 7b6ebc4d..51292647 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/LevelSetTopOpt.jl @@ -15,6 +15,7 @@ using Gridap.Helpers, Gridap.Algebra, Gridap.TensorValues using Gridap.Geometry, Gridap.CellData, Gridap.Fields using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.MultiField using Gridap.Geometry: get_faces +using Gridap.FESpaces: get_assembly_strategy using Gridap: writevtk using GridapDistributed From 681bea89a81bc2704319729872856a21b85a18d8 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Fri, 12 Apr 2024 10:15:33 +1000 Subject: [PATCH 43/90] Typo in inverter script for paper --- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index b9f3269c..8f965df8 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -61,7 +61,7 @@ function main(mesh_partition,distribute) Tv = Vector{PetscScalar} solver = ElasticitySolver(V) state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; + a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), @@ -73,8 +73,8 @@ function main(mesh_partition,distribute) vol_Γ_out = sum(∫(1)dΓ_out) vol_D = sum(∫(1)dΩ) J(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅e₁)/vol_Γ_in)dΓ_in - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + C1(u,φ,dΩ,dΓ_in,dΓ_out) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_in,dΓ_out) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ C2(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map, analytic_dJ=dJ,analytic_dC=[dC1,nothing]) From 11ebdc23607f0725f0439b5a9ca8b543eabaaed3 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Fri, 12 Apr 2024 10:31:52 +1000 Subject: [PATCH 44/90] Missing NewtonSolver import --- scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl index 5b4730c5..fe74df74 100644 --- a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl @@ -1,6 +1,8 @@ using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, SparseMatricesCSR +using GridapSolvers: NewtonSolver + function main(mesh_partition,distribute) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters From 537301909b24306a9f0eda5cfbb483f610f89709 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Fri, 12 Apr 2024 10:53:54 +1000 Subject: [PATCH 45/90] Missing --- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index 8f965df8..a04b319f 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -22,6 +22,7 @@ function main(mesh_partition,distribute) # Problem parameters C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor g = VectorValue(0,0,-1) # Applied load on Γ_N + ks = 0.01 # Artificial spring stiffness vf = 0.4 # Volume fraction constraint sphere(x,(xc,yc,zc)) = -sqrt((x[1]-xc)^2+(x[2]-yc)^2+(x[3]-zc)^2) + 0.2 lsf_func(x) = max(initial_lsf(4,0.2)(x), # Initial level set function From c5838c9e80e8f9bc8b7e56a3808b344d26841f44 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 15 Apr 2024 14:56:16 +1000 Subject: [PATCH 46/90] Name corrections + remove TODO + 2d pz dev script --- LICENSE.md | 2 +- README.md | 2 +- docs/src/getting-started.md | 2 +- docs/src/index.md | 2 +- scripts/_dev/full_piezo_script_2d.jl | 246 +++++++++++++++++++++++++++ src/ChainRules.jl | 2 +- 6 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 scripts/_dev/full_piezo_script_2d.jl diff --git a/LICENSE.md b/LICENSE.md index 9772d89f..1dbccfec 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 [Zachary Wegert](mailto:zach.wegert@hdr.qut.edu.au), [Jordi Fuertes](mailto:jordi.manyer@monash.edu), [Connor Mallon](mailto:connor.mallon@monash.edu), [Santiago Badia](mailto:santiago.badia@monash.edu) and [Vivien Challis](mailto:vivien.challis@qut.edu.au) +Copyright (c) 2024 [Zachary Wegert](mailto:zach.wegert@hdr.qut.edu.au), [Jordi Manyer](mailto:jordi.manyer@monash.edu), [Connor Mallon](mailto:connor.mallon@monash.edu), [Santiago Badia](mailto:santiago.badia@monash.edu) and [Vivien Challis](mailto:vivien.challis@qut.edu.au) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1ce80170..8fa50d55 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ LevelSetTopOpt is computational toolbox for level set-based topology optimisation implemented in Julia and the [Gridap](https://github.com/gridap/Gridap.jl) package ecosystem. See the documentation and following publication for further details: -> Zachary J. Wegert, Jordi M. Fuertes, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. +> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. ## Documentation diff --git a/docs/src/getting-started.md b/docs/src/getting-started.md index 485fb54f..80775cda 100644 --- a/docs/src/getting-started.md +++ b/docs/src/getting-started.md @@ -30,7 +30,7 @@ For more advanced installations, such as use of a custom MPI/PETSc installation ## Usage and tutorials In order to get familiar with the library we recommend following the numerical examples described in: -> Zachary J. Wegert, Jordi M. Fuertes, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. +> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. In addition, there are several driver scripts available in `/scripts/..` diff --git a/docs/src/index.md b/docs/src/index.md index 2a9769a0..e3b8ed44 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -4,7 +4,7 @@ Welcome to the documentation for `LevelSetTopOpt.jl`! ## Introduction `LevelSetTopOpt.jl` is computational toolbox for level set-based topology optimisation implemented in Julia and the Gridap package ecosystem. The core design principle of `LevelSetTopOpt.jl` is to provide an extendable framework for solving optimisation problems in serial or parallel with a high-level programming interface and automatic differentiation. See the following publication for further details: -> Zachary J. Wegert, Jordi M. Fuertes, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. +> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. ## How to use this documentation diff --git a/scripts/_dev/full_piezo_script_2d.jl b/scripts/_dev/full_piezo_script_2d.jl new file mode 100644 index 00000000..f56e65fa --- /dev/null +++ b/scripts/_dev/full_piezo_script_2d.jl @@ -0,0 +1,246 @@ +using LevelSetTopOpt, Gridap + +using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.FESpaces, Gridap.Helpers, Gridap.Algebra +using GridapDistributed +using GridapPETSc +using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code +using PartitionedArrays +using SparseMatricesCSR +using ChainRulesCore + +using GridapSolvers +using Gridap.MultiField + +## Piezo helpers +function PZT5A(D::Int) + ε_0 = 8.854e-12; + if D == 3 + C_Voigt = [12.0400e10 7.52000e10 7.51000e10 0.0 0.0 0.0 + 7.52000e10 12.0400e10 7.51000e10 0.0 0.0 0.0 + 7.51000e10 7.51000e10 11.0900e10 0.0 0.0 0.0 + 0.0 0.0 0.0 2.1000e10 0.0 0.0 + 0.0 0.0 0.0 0.0 2.1000e10 0.0 + 0.0 0.0 0.0 0.0 0.0 2.30e10] + e_Voigt = [0.0 0.0 0.0 0.0 12.30000 0.0 + 0.0 0.0 0.0 12.30000 0.0 0.0 + -5.40000 -5.40000 15.80000 0.0 0.0 0.0] + K_Voigt = [540*ε_0 0 0 + 0 540*ε_0 0 + 0 0 830*ε_0] + elseif D == 2 + C_Voigt = [12.0400e10 7.51000e10 0.0 + 7.51000e10 11.0900e10 0.0 + 0.0 0.0 2.1000e10] + e_Voigt = [0.0 0.0 12.30000 + -5.40000 15.80000 0.0] + K_Voigt = [540*ε_0 0 + 0 830*ε_0] + else + @notimplemented + end + C = voigt2tensor4(C_Voigt) + e = voigt2tensor3(e_Voigt) + κ = voigt2tensor2(K_Voigt) + C,e,κ +end + +""" + Given a material constant given in Voigt notation, + return a SymFourthOrderTensorValue using ordering from Gridap +""" +function voigt2tensor4(A::Array{M,2}) where M + if isequal(size(A),(3,3)) + return SymFourthOrderTensorValue(A[1,1], A[3,1], A[2,1], + A[1,3], A[3,3], A[2,3], + A[1,2], A[3,2], A[2,2]) + elseif isequal(size(A),(6,6)) + return SymFourthOrderTensorValue(A[1,1], A[6,1], A[5,1], A[2,1], A[4,1], A[3,1], + A[1,6], A[6,6], A[5,6], A[2,6], A[4,6], A[3,6], + A[1,5], A[6,5], A[5,5], A[2,5], A[4,5], A[3,5], + A[1,2], A[6,2], A[5,2], A[2,2], A[4,2], A[3,2], + A[1,4], A[6,4], A[5,4], A[2,4], A[4,4], A[3,4], + A[1,3], A[6,3], A[5,3], A[2,3], A[4,3], A[3,3]) + else + @notimplemented + end +end + +""" + Given a material constant given in Voigt notation, + return a ThirdOrderTensorValue using ordering from Gridap +""" +function voigt2tensor3(A::Array{M,2}) where M + if isequal(size(A),(2,3)) + return ThirdOrderTensorValue(A[1,1], A[2,1], A[1,3], A[2,3], A[1,3], A[2,3], A[1,2], A[2,2]) + elseif isequal(size(A),(3,6)) + return ThirdOrderTensorValue( + A[1,1], A[2,1], A[3,1], A[1,6], A[2,6], A[3,6], A[1,5], A[2,5], A[3,5], + A[1,6], A[2,6], A[3,6], A[1,2], A[2,2], A[3,2], A[1,4], A[2,4], A[3,4], + A[1,5], A[2,5], A[3,5], A[1,4], A[2,4], A[3,4], A[1,3], A[2,3], A[3,3]) + else + @notimplemented + end +end + +""" + Given a material constant given in Voigt notation, + return a SymTensorValue using ordering from Gridap +""" +function voigt2tensor2(A::Array{M,2}) where M + return TensorValue(A) +end + +## Parameters +el_size = (100,100) +order = 1 +xmax,ymax=(1.0,1.0) +dom = (0,xmax,0,ymax) +γ = 0.1 +γ_reinit = 0.5 +max_steps = floor(Int,order*minimum(el_size)/10) +tol = 1/(5order^2)/minimum(el_size) +η_coeff = 2 +α_coeff = 4*max_steps*γ +vf = 0.5 +path = dirname(dirname(@__DIR__))*"/results/2d_PZ_inverse_homenisation_ALM" + +## FE Setup +model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)) +el_Δ = get_el_Δ(model) +f_Γ_D(x) = iszero(x) +update_labels!(1,model,f_Γ_D,"origin") + +## Triangulations and measures +Ω = Triangulation(model) +dΩ = Measure(Ω,2*order) +vol_D = sum(∫(1)dΩ) + +## Spaces +reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_scalar = ReferenceFE(lagrangian,Float64,order) +V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) +U = TrialFESpace(V,VectorValue(0.0,0.0)) +Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) +P = TrialFESpace(Q,0) +# mfs = BlockMultiFieldStyle() +UP = MultiFieldFESpace([U,P])#;style=mfs) +VQ = MultiFieldFESpace([V,Q])#;style=mfs) + +V_φ = TestFESpace(model,reffe_scalar) +V_reg = TestFESpace(model,reffe_scalar) +U_reg = TrialFESpace(V_reg) + +## Create FE functions +φh = interpolate(initial_lsf(4,0.2),V_φ) + +## Interpolation and weak form +interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ))#,ϵ=10^-9) +I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + +## Material tensors +C, e, κ = PZT5A(2); +k0 = norm(C.data,Inf); +α0 = norm(e.data,Inf); +β0 = norm(κ.data,Inf); +γ = β0*k0/α0^2; + +## Weak forms +εᴹ = (SymTensorValue(1.0,0.0,0.0), + SymTensorValue(0.0,0.0,1.0), + SymTensorValue(0.0,1/2,0)) +Eⁱ = (VectorValue(1.0,0.0,), + VectorValue(0.0,1.0)) + +a((u,ϕ),(v,q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - + 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + + -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + + -γ/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q))) )dΩ; + +l_ε = [((v,q),φ,dΩ) -> ∫(((I ∘ φ) * (-C ⊙ εᴹ[i] ⊙ ε(v) + k0/α0*(e ⋅² εᴹ[i]) ⋅ -∇(q))))dΩ for i = 1:3]; +l_E = [((v,q),φ,dΩ) -> ∫((I ∘ φ) * ((Eⁱ[i] ⋅ e ⊙ ε(v) + k0/α0*(κ ⋅ Eⁱ[i]) ⋅ -∇(q))))dΩ for i = 1:2]; +l = [l_ε; l_E] + +state_map = RepeatingAffineFEStateMap(5,a,l,UP,VQ,V_φ,U_reg,φh,dΩ) + +x = state_map(φh) +U = LevelSetTopOpt.get_trial_space(state_map) +xh = FEFunction(U,x) +# u1,ϕ1,u2,ϕ2,u3,ϕ3,u4,ϕ4,u5,ϕ5 = xh + + +function Cᴴ(r,s,uϕ,φ,dΩ) # (normalised by 1/k0) + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(1/k0 * (I ∘ φ) * (((C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ εᴹ[r]) + ((1/α0*∇(ϕ_s) ⋅ e) ⊙ εᴹ[r])))dΩ; +end + +function eᴴ(i,s,uϕ,φ,dΩ) # (normalised by 1/α0) + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(1/α0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ Eⁱ[i])))dΩ; +end + +function κᴴ(i,j,uϕ,φ,dΩ) # (normalised by 1/β0) + u_j = uϕ[6+2j-1]; ϕ_j = uϕ[6+2j] + ∫(1/β0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_j)) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_j) + Eⁱ[j])) ⋅ Eⁱ[i]))))dΩ; +end + +function dᴴ(uϕ,φ,dΩ) + _Cᴴ(r,s) = sum(Cᴴ(r,s,uϕ,φ,dΩ)) + _eᴴ(i,s) = sum(eᴴ(i,s,uϕ,φ,dΩ)) + (_Cᴴ(2,2)*_eᴴ(2,1) + _Cᴴ(1,1)*_eᴴ(2,2) - _Cᴴ(2,1)*(_eᴴ(2,1) + _eᴴ(2,2)))/ + (_Cᴴ(1,1)*_Cᴴ(2,2) - _Cᴴ(2,1)^2) +end + +# map(rs->sum(Cᴴ(rs[1],rs[2],xh,φh,dΩ)), CartesianIndices((1:3, 1:3))) +# map(is->sum(eᴴ(is[1],is[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:3))) +# map(ij->sum(κᴴ(ij[1],ij[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:2))) +dᴴ(xh,φh,dΩ)#*α0/k0 + +C_mat = map(rs->sum(Cᴴ(rs[1],rs[2],xh,φh,dΩ)), CartesianIndices((1:3, 1:3))) +e_mat = map(is->sum(eᴴ(is[1],is[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:3))) +d_mat = e_mat*inv(C_mat); +dh = d_mat[2,1] + d_mat[2,2] + +nothing +# ## Optimisation functionals +# J((u, p),φ,dΩ) = ∫(0)dΩ +# dJ(q,(u, p),φ,dΩ) = ∫(0q)dΩ +# Vol((u, p),φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; +# dVol(q,(u, p),φ,dΩ) = ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + +# ## Finite difference solver and level set function +# stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + +# ## Setup solver and FE operators +# state_map = RepeatingAffineFEStateMap(5,a,l,UP,VQ,V_φ,U_reg,φh,dΩ) +# pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) + +# evaluate!(pcfs,φh) + +# ## Hilbertian extension-regularisation problems +# α = α_coeff*maximum(el_Δ) +# a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; +# vel_ext = VelocityExtension( +# a_hilb,U_reg,V_reg, +# assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), +# ls = PETScLinearSolver() +# ) + +# ## Optimiser +# make_dir(path;ranks=ranks) +# optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) +# for (it, uh, φh) in optimiser +# write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +# write_history(path*"/history.txt",optimiser.history;ranks=ranks) +# end +# it = optimiser.history.niter; uh = get_state(optimiser.problem) +# write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) + + +function dh(stuff) + C(M,N) = @notimplemented + e(i,M) = @notimplemented + dh = (C23^2*e31 - C22*C33*e31 + C13^2*e32 + C11*C23*e32 - C11*C33*e32 + + C12*C33*(e31 + e32) + C12^2*e33 + C11*(-C22 + C23)*e33 - C12*C23*(e31 + e33) + + C13*(-(C23*(e31 + e32)) + C22*(e31 + e33) - C12*(e32 + e33)))/( + C13^2*C22 - 2*C12*C13*C23 + C12^2*C33 + C11*(C23^2 - C22*C33)) +end diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 5ecc930d..4112b5ae 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -521,7 +521,7 @@ end function update_adjoint_caches!(φ_to_u::AffineFEStateMap,uh,φh) adjoint_ns, adjoint_K, _, assem_adjoint = φ_to_u.adj_caches U, V, _, _ = φ_to_u.spaces - assemble_matrix!((u,v) -> φ_to_u.biform(v,u,φh),adjoint_K,assem_adjoint,V,U) # TODO: @Jordi, should this be `assemble_adjoint_matrix!`? + assemble_matrix!((u,v) -> φ_to_u.biform(v,u,φh),adjoint_K,assem_adjoint,V,U) numerical_setup!(adjoint_ns,adjoint_K) return φ_to_u.adj_caches end From b7f69b10527a3f4c62ac21dc8bef3bf1a5c07bd0 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Fri, 19 Apr 2024 10:49:17 +1000 Subject: [PATCH 47/90] Remove unnecessary packages from Project.toml --- Project.toml | 4 ---- scripts/MPI/elastic_compliance_ALM.jl | 3 +-- scripts/MPI/inverse_homenisation_ALM.jl | 3 +-- src/LevelSetTopOpt.jl | 6 +++--- src/Optimisers/AugmentedLagrangian.jl | 4 ++-- src/Optimisers/HilbertianProjection.jl | 6 +++--- src/Utilities.jl | 12 ++++++++++++ 7 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Project.toml b/Project.toml index 8e0627a6..8f014570 100755 --- a/Project.toml +++ b/Project.toml @@ -7,23 +7,19 @@ version = "0.1.0" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -ChaosTools = "608a59af-f2a3-5ad4-90b4-758bdf3122a7" CircularArrays = "7a955b69-7140-5f4e-a0ed-f168c5e2e749" DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" Gridap = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" GridapDistributed = "f9701e48-63b3-45aa-9a63-9bc6c271f355" -GridapP4est = "c2c8e14b-f5fd-423d-9666-1dd9ad120af9" GridapPETSc = "bcdc36c2-0c3e-11ea-095a-c9dadae499f1" GridapSolvers = "6d3209ee-5e3c-4db7-a716-942eb12ed534" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" MPIPreferences = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267" PartitionedArrays = "5a9dfac6-5c52-46f7-8278-5e2210713be9" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" SparseMatricesCSR = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index 76a48e2b..48bacf32 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -113,8 +113,7 @@ with_mpi() do distribute mesh_partition = (2,2) el_size = (200,100) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index e2ec347b..6cbe688b 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -114,8 +114,7 @@ with_mpi() do distribute mesh_partition = (2,2) el_size = (200,200) hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" + -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(hilb_solver_options)) do main(mesh_partition,distribute,el_size) diff --git a/src/LevelSetTopOpt.jl b/src/LevelSetTopOpt.jl index 9df3865b..52d28514 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/LevelSetTopOpt.jl @@ -4,11 +4,11 @@ using GridapPETSc, GridapPETSc.PETSC using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code using MPI -using BlockArrays, SparseArrays, CircularArrays -using LinearAlgebra, SparseMatricesCSR +using BlockArrays +using CircularArrays +using LinearAlgebra using ChainRulesCore using DelimitedFiles, Printf -using ChaosTools: estimate_period using Gridap using Gridap.Helpers, Gridap.Algebra, Gridap.TensorValues diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index 6c2d48b5..843d7a3a 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -99,7 +99,7 @@ end get_history(m::AugmentedLagrangian) = m.history function default_has_oscillations(m::AugmentedLagrangian,os_it;itlength=25, - itstart=2itlength,algo=:zerocrossing) + itstart=2itlength) h = m.history it = get_last_iteration(h) if it < itstart || it < os_it + itlength + 1 @@ -107,7 +107,7 @@ function default_has_oscillations(m::AugmentedLagrangian,os_it;itlength=25, end L = h[:L] - return ~isnan(estimate_period(L[it-itlength+1:it+1],algo)) + return ~isnan(_zerocrossing_period(L[it-itlength+1:it+1])) end function default_al_init_params(J,C) diff --git a/src/Optimisers/HilbertianProjection.jl b/src/Optimisers/HilbertianProjection.jl index b4f18628..875466fe 100644 --- a/src/Optimisers/HilbertianProjection.jl +++ b/src/Optimisers/HilbertianProjection.jl @@ -274,7 +274,7 @@ function default_hp_converged( end function default_has_oscillations(m::HilbertianProjection,os_it; - itlength=50,itstart=2itlength,algo=:zerocrossing) + itlength=50,itstart=2itlength) h = m.history it = get_last_iteration(h) if it < itstart || it < os_it + itlength + 1 @@ -282,9 +282,9 @@ function default_has_oscillations(m::HilbertianProjection,os_it; end J = h[:J] - J_osc = ~isnan(estimate_period(J[it-itlength+1:it+1],algo)); + J_osc = ~isnan(_zerocrossing_period(J[it-itlength+1:it+1])); C = h[:C,it-itlength+1:it+1] - C_osc = all(x->~isnan(estimate_period(x,algo)),C); + C_osc = all(x->~isnan(_zerocrossing_period(x)),C); return J_osc && C_osc end diff --git a/src/Utilities.jl b/src/Utilities.jl index 25f6ab57..d3bed832 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -219,4 +219,16 @@ function isotropic_elast_tensor(D::Int,E::Number,v::Number) else @notimplemented end +end + +# function zerocrossing_period +# +# Find the period of oscillations based on a zero crossing algorithm. +# +# This is based on the zero crossing method from ChaosTools.jl +# See (https://github.com/JuliaDynamics/ChaosTools.jl) +function _zerocrossing_period(v;t=0:length(v)-1,line=sum(v)/length(v)) + inds = findall(@. ≥(line, $@view(v[2:end])) & <(line, $@view(v[1:end-1]))) + difft = diff(t[inds]) + sum(difft)/length(difft) end \ No newline at end of file From 6e02104e44d08c6dbb07136d8151e2035846a7a5 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 19 Apr 2024 20:40:35 +1000 Subject: [PATCH 48/90] fix benchmark single iter --- scripts/Benchmarks/benchmark.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index 862262d7..1e630f8e 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -3,7 +3,7 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, using LevelSetTopOpt: get_deriv_space, get_aux_space,benchmark_optimizer, benchmark_forward_problem,benchmark_advection,benchmark_reinitialisation, - benchmark_velocity_extension,benchmark_hilbertian_projection_map + benchmark_velocity_extension,benchmark_hilbertian_projection_map,benchmark_single_iteration using GridapSolvers: NewtonSolver From 5d53eebe7fa27b6ff76afc5861f7f6b75716c6a9 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 20 Apr 2024 06:25:04 +1000 Subject: [PATCH 49/90] bug fix --- scripts/Benchmarks/benchmark.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index 1e630f8e..02446951 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -409,12 +409,12 @@ with_mpi() do distribute end ## Benchmark reinitialisation if occursin("breinit",BMARK_TYPE) - breinit = benchmark_reinitialisation(optim.stencil, get_free_dof_values(optim.φ0), 0.1, ranks; nreps=NREPS) + breinit = benchmark_reinitialisation(optim.ls_evolver, get_free_dof_values(optim.φ0), 0.1, ranks; nreps=NREPS) else breinit = i_am_main(ranks) && zeros(NREPS) end ## Benchmark forward problem - reinit!(optim.stencil,optim.φ0,optim.params.γ_reinit) + reinit!(optim.ls_evolver,optim.φ0,optim.params.γ_reinit) if occursin("bfwd",BMARK_TYPE) bfwd = benchmark_forward_problem(optim.problem.state_map, optim.φ0, ranks; nreps=NREPS) else @@ -425,7 +425,7 @@ with_mpi() do distribute vh = interpolate(FEFunction(get_deriv_space(optim.problem.state_map),optim.problem.dJ), get_aux_space(optim.problem.state_map)) v = get_free_dof_values(vh) - badv = benchmark_advection(optim.stencil, get_free_dof_values(optim.φ0), v, 0.1, ranks; nreps=NREPS) + badv = benchmark_advection(optim.ls_evolver, get_free_dof_values(optim.φ0), v, 0.1, ranks; nreps=NREPS) else badv = i_am_main(ranks) && zeros(NREPS) end From fadee3a7d8c4251bec4dc33cd79dc2292b499506 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:46:45 +1000 Subject: [PATCH 50/90] Bug fix for for nonlinear problems in MPI with Gridap update --- src/ChainRules.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 4112b5ae..4d54eb9c 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -65,7 +65,7 @@ Gridap.gradient(F::IntegrandWithMeasure,uh) = Gridap.gradient(F,[uh],1) Given an an `IntegrandWithMeasure` `F` and a vector of `FEFunctions` or `CellField` `uh` (excluding measures) evaluate the Jacobian `F.F` with respect to `uh[K]`. """ -function Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector{<:Union{FEFunction,CellField}},K::Int) +function Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector{<:FEFunction},K::Int) @check 0 < K <= length(uh) _f(uk) = F.F(uh[1:K-1]...,uk,uh[K+1:end]...,F.dΩ...) return Gridap.jacobian(_f,uh[K]) From 0a7d20f45c80a0f136c7f045eee8d36eaa04018b Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:53:45 +1000 Subject: [PATCH 51/90] Added script for 2d nonlinear prob with MPI --- .../MPI/nonlinear_thermal_compliance_ALM.jl | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 scripts/MPI/nonlinear_thermal_compliance_ALM.jl diff --git a/scripts/MPI/nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/nonlinear_thermal_compliance_ALM.jl new file mode 100644 index 00000000..a4a835e5 --- /dev/null +++ b/scripts/MPI/nonlinear_thermal_compliance_ALM.jl @@ -0,0 +1,103 @@ +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, + PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + +""" + (MPI) Minimum thermal compliance with augmented Lagrangian method in 2D with nonlinear diffusivity. + + Optimisation problem: + Min J(Ω) = ∫ κ(u)*∇(u)⋅∇(u) dΩ + Ω + s.t., Vol(Ω) = vf, + ⎡u∈V=H¹(Ω;u(Γ_D)=0), + ⎣∫ κ(u)*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. + + In this example κ(u) = κ0*(exp(ξ*u)) +""" +function main(mesh_partition,distribute,el_size) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + ## Parameters + order = 1 + xmax=ymax=1.0 + prop_Γ_N = 0.2 + prop_Γ_D = 0.2 + dom = (0,xmax,0,ymax) + γ = 0.1 + γ_reinit = 0.5 + max_steps = floor(Int,order*minimum(el_size)/10) + tol = 1/(5order^2)/minimum(el_size) + η_coeff = 2 + α_coeff = 4max_steps*γ + vf = 0.4 + path = dirname(dirname(@__DIR__))*"/results/nonlinear_thermal_compliance_ALM_MPI/" + iter_mod = 10 + mkdir(path) + + ## FE Setup + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + el_Δ = get_el_Δ(model) + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + x[2] >= ymax-ymax*prop_Γ_D - eps())); + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + ymax/2+ymax*prop_Γ_N/2 + eps()); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + + ## Triangulations and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + vol_D = sum(∫(1)dΩ) + + ## Spaces + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,0.0) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + + ## Create FE functions + φh = interpolate(initial_lsf(4,0.2),V_φ) + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + κ0 = 1 + ξ = -1 + κ(u) = κ0*(exp(ξ*u)) + res(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(v))dΩ - ∫(v)dΓ_N + + ## Optimisation functionals + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(u))dΩ + Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; + dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + + ## Finite difference solver and level set function + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + + ## Setup solver and FE operators + state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) + pcfs = PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dC=[dVol]) + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + + ## Optimiser + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; + γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) + for (it, uh, φh) in optimiser + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] + iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) + write_history(path*"/history.txt",optimiser.history;ranks=ranks) + end + it = get_history(optimiser).niter; uh = get_state(pcfs) + writevtk(Ω,path*"out$it",cellfields=["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) +end + +with_mpi() do distribute + main((2,2),distribute,(200,200)) +end \ No newline at end of file From c07eeb9194446ee2e32ccfda1b1eab9943ea91e7 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 21 Apr 2024 19:57:30 +1000 Subject: [PATCH 52/90] fix single iter benchmark --- src/Benchmarks.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Benchmarks.jl b/src/Benchmarks.jl index 0c052a44..0a9c1428 100644 --- a/src/Benchmarks.jl +++ b/src/Benchmarks.jl @@ -86,8 +86,10 @@ Given an optimiser `m`, benchmark a single iteration after 0th iteration. """ function benchmark_single_iteration(m::Optimiser, ranks; nreps = 10) _, state = iterate(m) + _, L, J, C, dL, dJ, dC, uh, φh, vel, λ, Λ, γ, os_it = state; function f(m) - iterate(m, state) + _state = (;it=1,L,J,C,dL,dJ,dC,uh,φh,vel,λ,Λ,γ,os_it) + iterate(m, _state) end φ0 = copy(get_free_dof_values(m.φ0)) From ed2fc735bbfcff4749b61b27750004864730404e Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 21 Apr 2024 21:34:46 +1000 Subject: [PATCH 53/90] Ensure benchmark fairness by filling dofs with zero at reset --- scripts/_dev/benchmark_tests/serial_benchmark_test.jl | 10 +++++++--- src/Benchmarks.jl | 9 ++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl b/scripts/_dev/benchmark_tests/serial_benchmark_test.jl index 17eb71cf..6ad4eec8 100644 --- a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl +++ b/scripts/_dev/benchmark_tests/serial_benchmark_test.jl @@ -57,7 +57,6 @@ function main() ## Finite difference solver and level set function ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) - reinit!(stencil,φh,γ_reinit) ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) @@ -69,7 +68,7 @@ function main() vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit) + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true) end function main_benchmark() @@ -94,4 +93,9 @@ bopt bfwd badv brinit -bvelext \ No newline at end of file +bvelext + +opt = main() + ## Benchmark optimiser +bopt0 = LevelSetTopOpt.benchmark_optimizer(opt,0, nothing; nreps = 10) +bopt = LevelSetTopOpt.benchmark_single_iteration(opt, nothing; nreps = 10) \ No newline at end of file diff --git a/src/Benchmarks.jl b/src/Benchmarks.jl index 0a9c1428..5796eb95 100644 --- a/src/Benchmarks.jl +++ b/src/Benchmarks.jl @@ -73,6 +73,8 @@ function benchmark_optimizer(m::Optimiser, niter, ranks; nreps = 10) φ0 = copy(get_free_dof_values(m.φ0)) function opt_reset!(m::Optimiser) + u = get_free_dof_values(get_state(m.problem)); + fill!(u,zero(eltype(u))) copy!(get_free_dof_values(m.φ0), φ0) reset!(get_history(m)) end @@ -86,16 +88,17 @@ Given an optimiser `m`, benchmark a single iteration after 0th iteration. """ function benchmark_single_iteration(m::Optimiser, ranks; nreps = 10) _, state = iterate(m) - _, L, J, C, dL, dJ, dC, uh, φh, vel, λ, Λ, γ, os_it = state; function f(m) - _state = (;it=1,L,J,C,dL,dJ,dC,uh,φh,vel,λ,Λ,γ,os_it) - iterate(m, _state) + iterate(m, state) end φ0 = copy(get_free_dof_values(m.φ0)) function opt_reset!(m::Optimiser) + u = get_free_dof_values(get_state(m.problem)); + fill!(u,zero(eltype(u))) copy!(get_free_dof_values(m.φ0), φ0) reset!(get_history(m)) + iterate(m) end return benchmark(f, (m,), ranks; nreps, reset! = opt_reset!) end From 73add204e1ce102c3bfdae9c13dead58d7ea469f Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 21 Apr 2024 21:40:33 +1000 Subject: [PATCH 54/90] Type consistency --- src/Optimisers/AugmentedLagrangian.jl | 2 +- src/Optimisers/HilbertianProjection.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Optimisers/AugmentedLagrangian.jl b/src/Optimisers/AugmentedLagrangian.jl index 843d7a3a..bf33e91d 100644 --- a/src/Optimisers/AugmentedLagrangian.jl +++ b/src/Optimisers/AugmentedLagrangian.jl @@ -224,7 +224,7 @@ function Base.iterate(m::AugmentedLagrangian,state) ## Update history and build state push!(history,(L,J,C...,γ,λ...,Λ...)) - state = (it+1,L,J,C,dL,dJ,dC,uh,φh,vel,λ,Λ,γ,os_it) + state = (;it=it+1,L,J,C,dL,dJ,dC,uh,φh,vel,λ,Λ,γ,os_it) vars = params.debug ? (it,uh,φh,state) : (it,uh,φh) return vars, state end diff --git a/src/Optimisers/HilbertianProjection.jl b/src/Optimisers/HilbertianProjection.jl index 875466fe..73b41ef2 100644 --- a/src/Optimisers/HilbertianProjection.jl +++ b/src/Optimisers/HilbertianProjection.jl @@ -384,7 +384,7 @@ function Base.iterate(m::HilbertianProjection,state) ## Update history and build state push!(history,(J,C...,γ)) - state = (it+1, J, C, θ, dJ, dC, uh, φh, vel, φ_tmp, γ, os_it) + state = (;it=it+1, J, C, θ, dJ, dC, uh, φh, vel, φ_tmp, γ, os_it) vars = params.debug ? (it,uh,φh,state) : (it,uh,φh) return vars, state end From 79effb8566093302c0b2d2f6580444e591fa1ee4 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Mon, 22 Apr 2024 06:33:30 +1000 Subject: [PATCH 55/90] adjust bmarks --- scripts/Benchmarks/benchmark.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index 02446951..cd4126b4 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -414,13 +414,13 @@ with_mpi() do distribute breinit = i_am_main(ranks) && zeros(NREPS) end ## Benchmark forward problem - reinit!(optim.ls_evolver,optim.φ0,optim.params.γ_reinit) if occursin("bfwd",BMARK_TYPE) bfwd = benchmark_forward_problem(optim.problem.state_map, optim.φ0, ranks; nreps=NREPS) else bfwd = i_am_main(ranks) && zeros(NREPS) end ## Benchmark advection + reinit!(optim.ls_evolver,optim.φ0,optim.params.γ_reinit) if occursin("badv",BMARK_TYPE) vh = interpolate(FEFunction(get_deriv_space(optim.problem.state_map),optim.problem.dJ), get_aux_space(optim.problem.state_map)) From b948a7923252f2a62b9e3ce671ed8016d2a50b55 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 22 Apr 2024 08:38:18 +1000 Subject: [PATCH 56/90] fix job scripts --- scripts/Benchmarks/jobtemplate.sh | 2 +- scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs | 2 +- scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs | 2 +- scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs | 2 +- scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs | 2 +- scripts/MPI/jobs/3d_inverter_ALM.pbs | 2 +- scripts/MPI/jobs/3d_inverter_HPM.pbs | 2 +- scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs | 2 +- scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs | 2 +- scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs | 3 +-- scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs | 3 +-- scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs | 3 +-- scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs | 3 +-- scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs | 3 +-- 14 files changed, 14 insertions(+), 19 deletions(-) diff --git a/scripts/Benchmarks/jobtemplate.sh b/scripts/Benchmarks/jobtemplate.sh index 7adbe538..4c5962e4 100644 --- a/scripts/Benchmarks/jobtemplate.sh +++ b/scripts/Benchmarks/jobtemplate.sh @@ -11,7 +11,7 @@ PROJECT_DIR=$HOME/{{:dir_name}}/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/Benchmarks/benchmark.jl \ {{:name}} \ {{{:write_dir}}} \ diff --git a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs index 81d10175..665cdea4 100644 --- a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs @@ -11,7 +11,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_elastic_compliance_ALM.jl \ 160 \ 80 \ diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs index 9a9d94c6..9e2ae8b9 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs @@ -11,7 +11,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_ALM.jl \ 160 \ 80 \ diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs index 5b7ef3f7..a6825fe2 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs @@ -11,7 +11,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl \ 160 \ 80 \ diff --git a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs index bf1e09f4..d16b2016 100644 --- a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs @@ -11,7 +11,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_inverse_homenisation_ALM.jl \ 100 \ 100 \ diff --git a/scripts/MPI/jobs/3d_inverter_ALM.pbs b/scripts/MPI/jobs/3d_inverter_ALM.pbs index 5e80b93d..35713c7e 100644 --- a/scripts/MPI/jobs/3d_inverter_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverter_ALM.pbs @@ -12,7 +12,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_inverter_ALM.jl \ 100 \ 100 \ diff --git a/scripts/MPI/jobs/3d_inverter_HPM.pbs b/scripts/MPI/jobs/3d_inverter_HPM.pbs index c95b0423..78737ee8 100644 --- a/scripts/MPI/jobs/3d_inverter_HPM.pbs +++ b/scripts/MPI/jobs/3d_inverter_HPM.pbs @@ -12,7 +12,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_inverter_HPM.jl \ 100 \ 100 \ diff --git a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs index 3b8774a6..b8921872 100644 --- a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs @@ -12,7 +12,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl \ 100 \ 100 \ diff --git a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs index 5451c039..de99436c 100644 --- a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs @@ -12,7 +12,7 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/MPI/3d_thermal_compliance_ALM.jl \ 150 \ 150 \ diff --git a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs index f0e6a8e1..421c9cf6 100644 --- a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs @@ -12,6 +12,5 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs index 2e765a8a..2a00f636 100644 --- a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs @@ -12,6 +12,5 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs index 6b5f5c2c..e59a519b 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs @@ -12,6 +12,5 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs index 29179f69..26d806c3 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs @@ -12,6 +12,5 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs index 795dc33d..36e63880 100644 --- a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs @@ -12,6 +12,5 @@ PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" -mpirun --hostfile $PBS_NODEFILE \ - julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ +mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl \ No newline at end of file From 56455421c277c319f49e4ae4dc03bd4614422d50 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 22 Apr 2024 09:00:54 +1000 Subject: [PATCH 57/90] Another fix for lyra runs --- scripts/Benchmarks/jobtemplate.sh | 2 +- scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs | 2 +- scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs | 2 +- scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs | 2 +- scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs | 2 +- scripts/MPI/jobs/3d_inverter_ALM.pbs | 2 +- scripts/MPI/jobs/3d_inverter_HPM.pbs | 2 +- scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs | 2 +- scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs | 2 +- scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs | 2 +- scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs | 2 +- scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs | 2 +- scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs | 2 +- scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/Benchmarks/jobtemplate.sh b/scripts/Benchmarks/jobtemplate.sh index 4c5962e4..09e204c3 100644 --- a/scripts/Benchmarks/jobtemplate.sh +++ b/scripts/Benchmarks/jobtemplate.sh @@ -6,7 +6,7 @@ #PBS -l walltime={{:wallhr}}:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/{{:dir_name}}/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs index 665cdea4..20e7f3c6 100644 --- a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs @@ -6,7 +6,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs index 9e2ae8b9..b0f29779 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs @@ -6,7 +6,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs index a6825fe2..7fd9279a 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs @@ -6,7 +6,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs index d16b2016..ffa8d005 100644 --- a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs @@ -6,7 +6,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_inverter_ALM.pbs b/scripts/MPI/jobs/3d_inverter_ALM.pbs index 35713c7e..54b6311b 100644 --- a/scripts/MPI/jobs/3d_inverter_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverter_ALM.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_inverter_HPM.pbs b/scripts/MPI/jobs/3d_inverter_HPM.pbs index 78737ee8..c0390d54 100644 --- a/scripts/MPI/jobs/3d_inverter_HPM.pbs +++ b/scripts/MPI/jobs/3d_inverter_HPM.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs index b8921872..de3e8b48 100644 --- a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs index de99436c..f456d8a7 100644 --- a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs index 421c9cf6..94a34cfa 100644 --- a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs index 2a00f636..5a8b0387 100644 --- a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs index e59a519b..9da69050 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs index 26d806c3..6cfc5060 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" diff --git a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs index 36e63880..d24b04a1 100644 --- a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs @@ -7,7 +7,7 @@ #PBS -l walltime=23:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-ompi.sh +source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" From 97a31470b1aaebe838c5b2f7ba15b7b3b6bbf08f Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 22 Apr 2024 10:34:49 +1000 Subject: [PATCH 58/90] another fix --- scripts/Benchmarks/generate_benchmark_scripts.jl | 2 +- src/Benchmarks.jl | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts/Benchmarks/generate_benchmark_scripts.jl b/scripts/Benchmarks/generate_benchmark_scripts.jl index 4214f36e..4ad06b06 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts.jl @@ -65,7 +65,7 @@ dir_name= "LevelSetTopOpt"; write_dir = "\$HOME/$dir_name/results/benchmarks/" N = 1:10; # Number of partitions in x-axis -strong_dof=(150+1)^3*3; # Number of dofs for strong scaling +strong_dof=(100+1)^3*3; # Number of dofs for strong scaling # Phys type and number of dofs per node, and what to benchmark phys_types = [ diff --git a/src/Benchmarks.jl b/src/Benchmarks.jl index 5796eb95..342dcfed 100644 --- a/src/Benchmarks.jl +++ b/src/Benchmarks.jl @@ -86,19 +86,25 @@ end Given an optimiser `m`, benchmark a single iteration after 0th iteration. """ -function benchmark_single_iteration(m::Optimiser, ranks; nreps = 10) - _, state = iterate(m) +function benchmark_single_iteration(m::Optimiser,ranks; nreps = 10) + _,state = iterate(m) function f(m) - iterate(m, state) + iterate(m,state) end φ0 = copy(get_free_dof_values(m.φ0)) + λ0 = copy(state.λ); Λ0 = copy(state.Λ) + dL0 = copy(state.dL) function opt_reset!(m::Optimiser) u = get_free_dof_values(get_state(m.problem)); fill!(u,zero(eltype(u))) copy!(get_free_dof_values(m.φ0), φ0) + copy!(get_free_dof_values(state.φh), φ0) + copy!(state.λ,λ0) + copy!(state.Λ,Λ0) + copy!(state.dL,dL0) reset!(get_history(m)) - iterate(m) + get_history(m).niter = state.it - 1 # <- due to compilation end return benchmark(f, (m,), ranks; nreps, reset! = opt_reset!) end From fd8e2b7c80e5574c157aa18cfe2145d389ead33a Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 22 Apr 2024 14:42:06 +1000 Subject: [PATCH 59/90] Cleanup GridapExtensions --- src/GridapExtensions.jl | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/GridapExtensions.jl b/src/GridapExtensions.jl index 51b5d1e8..6b6b9991 100644 --- a/src/GridapExtensions.jl +++ b/src/GridapExtensions.jl @@ -59,25 +59,6 @@ function assemble_adjoint_matrix!(f::Function,A::AbstractMatrix,a::Assembler,U:: end # Assembly addons -""" -function Gridap.FESpaces.allocate_matrix(a::Function,assem::Assembler,U::FESpace,V::FESpace) - v = get_fe_basis(V) - u = get_trial_fe_basis(U) - allocate_matrix(assem,collect_cell_matrix(U,V,a(u,v))) -end - -function Gridap.FESpaces.allocate_vector(l::Function,assem::Assembler,V::FESpace) - v = get_fe_basis(V) - allocate_vector(assem,collect_cell_vector(V,l(v))) -end - -function Gridap.FESpaces.assemble_matrix_and_vector!( - a::Function,l::Function,A::AbstractMatrix,b::AbstractVector,assem::Assembler,U::FESpace,V::FESpace,uhd) - v = get_fe_basis(V) - u = get_trial_fe_basis(U) - assemble_matrix_and_vector!(A,b,assem,collect_cell_matrix_and_vector(U,V,a(u,v),l(v),uhd)) -end -""" get_local_matrix_type(a::Assembler) = get_matrix_type(a) get_local_vector_type(a::Assembler) = get_vector_type(a) @@ -89,20 +70,3 @@ end function get_local_vector_type(a::GridapDistributed.DistributedSparseMatrixAssembler) return getany(map(get_vector_type,a.assems)) end - -# PETScNonlinearSolver override - -function Gridap.Algebra.solve!(x::T,nls::PETScNonlinearSolver,op::Gridap.Algebra.NonlinearOperator, - cache::GridapPETSc.PETScNonlinearSolverCache{<:T}) where T <: AbstractVector - @check_error_code GridapPETSc.PETSC.SNESSolve(cache.snes[],C_NULL,cache.x_petsc.vec[]) - copy!(x,cache.x_petsc) - cache -end - -# Stuff from ODE refactor -""" -function (+)(a::Gridap.CellData.DomainContribution,b::GridapDistributed.DistributedDomainContribution) - @assert iszero(Gridap.CellData.num_domains(a)) - return b -end -""" \ No newline at end of file From 3dfec9b6004dc99e49169fb82bd34ed3b17442ac Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 22 Apr 2024 15:03:20 +1000 Subject: [PATCH 60/90] RepeatedFEStateMaps support for BlockMultiFieldStyle --- src/ChainRules.jl | 63 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 4d54eb9c..7d6d52ca 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -747,23 +747,68 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap end end +const MultiFieldSpaceTypes = Union{<:MultiField.MultiFieldFESpace,<:GridapDistributed.DistributedMultiFieldFESpace} + function repeat_spaces(nblocks::Integer,U0::FESpace,V0::FESpace) U = MultiFieldFESpace([U0 for i in 1:nblocks];style=BlockMultiFieldStyle()) V = MultiFieldFESpace([V0 for i in 1:nblocks];style=BlockMultiFieldStyle()) return U,V end -function repeat_spaces( - nblocks::Integer,U0::T,V0::T -) where T <: Union{MultiField.MultiFieldFESpace,GridapDistributed.DistributedMultiFieldFESpace} +function repeat_spaces(nblocks::Integer,U0::MultiFieldSpaceTypes,V0::MultiFieldSpaceTypes) nfields = num_fields(U0) @assert nfields == num_fields(V0) - mfs = BlockMultiFieldStyle(nblocks,Tuple(fill(nfields,nblocks))) + @assert MultiFieldStyle(U0) === MultiFieldStyle(V0) + + mfs = repeat_mfs(nblocks,nfields,MultiFieldStyle(U0)) U = MultiFieldFESpace(repeat([U0...],nblocks);style=mfs) V = MultiFieldFESpace(repeat([V0...],nblocks);style=mfs) return U,V end +function repeat_mfs(nblocks::Integer,nfields::Integer,::ConsecutiveMultiFieldStyle) + return BlockMultiFieldStyle(nblocks,Tuple(fill(nfields,nblocks))) +end + +function repeat_mfs(nblocks::Integer,nfields::Integer,::BlockMultiFieldStyle{NB,SB,P}) where {NB,SB,P} + @assert length(P) == nfields + P_new = [P...] + for iB in 2:nblocks + P_new = vcat(P_new,(P .+ (iB-1)*nfields)...) + end + return BlockMultiFieldStyle(NB*nblocks, Tuple(repeat([SB...],nblocks)), Tuple(P_new)) +end + +repeated_blocks(V0::FESpace,x::AbstractBlockVector) = blocks(x) +repeated_blocks(V0::FESpace,xh) = xh + +repeated_blocks(V0::MultiFieldSpaceTypes,x) = repeated_blocks(MultiFieldStyle(V0),V0,x) +repeated_blocks(::ConsecutiveMultiFieldStyle,V0,x::AbstractBlockVector) = blocks(x) +repeated_blocks(::ConsecutiveMultiFieldStyle,V0,xh) = xh + +function repeated_blocks(::BlockMultiFieldStyle{NB},V0::MultiFieldSpaceTypes,x::AbstractBlockVector) where NB + xb = blocks(x) + @assert length(xb) % NB == 0 + + nblocks = length(xb) ÷ NB + rep_blocks = map(1:nblocks) do iB + mortar(xb[(iB-1)*NB+1:iB*NB]) + end + return rep_blocks +end + +function repeated_blocks(::BlockMultiFieldStyle,V0::MultiFieldSpaceTypes,xh) + xb = blocks(x) + nfields = num_fields(V0) + @assert length(xb) % nfields == 0 + + nblocks = length(xb) ÷ nfields + rep_blocks = map(1:nblocks) do iB + FEFunction(V0,xh[(iB-1)*nfields+1:iB*nfields]) + end + return rep_blocks +end + get_state(m::RepeatingAffineFEStateMap) = FEFunction(get_trial_space(m),m.fwd_caches[4]) get_measure(m::RepeatingAffineFEStateMap) = m.biform.dΩ get_spaces(m::RepeatingAffineFEStateMap) = m.spaces @@ -783,7 +828,7 @@ function forward_solve!(φ_to_u::RepeatingAffineFEStateMap,φh) rmul!(b0,-1) v = get_fe_basis(V0) - map(blocks(x),liforms) do xi, li + map(repeated_blocks(U0,x),liforms) do xi, li copy!(b,b0) vecdata = collect_cell_vector(V0,li(v,φh)) assemble_vector_add!(b,assem_U0,vecdata) @@ -794,9 +839,12 @@ end function dRdφ(φ_to_u::RepeatingAffineFEStateMap,uh,vh,φh) biform, liforms = φ_to_u.biform, φ_to_u.liform + U0, V0 = φ_to_u.spaces_0 + uh_blocks = repeated_blocks(U0,uh) + vh_blocks = repeated_blocks(V0,vh) res = DomainContribution() - for (liform,uhi,vhi) in zip(liforms,uh,vh) + for (liform,uhi,vhi) in zip(liforms,uh_blocks,vh_blocks) res = res + ∇(biform,[uhi,vhi,φh],3) - ∇(liform,[vhi,φh],2) end return res @@ -812,7 +860,8 @@ end function adjoint_solve!(φ_to_u::RepeatingAffineFEStateMap,du::AbstractBlockVector) adjoint_ns, _, adjoint_x, _ = φ_to_u.adj_caches - map(blocks(adjoint_x),blocks(du)) do xi, dui + U0, V0 = φ_to_u.spaces_0 + map(repeated_blocks(U0,adjoint_x),repeated_blocks(U0,du)) do xi, dui solve!(xi,adjoint_ns,dui) end return adjoint_x From a345da0accec3e876daa1e3e4791055b7c42c824 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 22 Apr 2024 15:13:40 +1000 Subject: [PATCH 61/90] Bugfix --- src/ChainRules.jl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 7d6d52ca..8f57722c 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -798,13 +798,9 @@ function repeated_blocks(::BlockMultiFieldStyle{NB},V0::MultiFieldSpaceTypes,x:: end function repeated_blocks(::BlockMultiFieldStyle,V0::MultiFieldSpaceTypes,xh) - xb = blocks(x) - nfields = num_fields(V0) - @assert length(xb) % nfields == 0 - - nblocks = length(xb) ÷ nfields - rep_blocks = map(1:nblocks) do iB - FEFunction(V0,xh[(iB-1)*nfields+1:iB*nfields]) + x_blocks = repeated_blocks(MultiFieldStyle(V0),V0,get_free_values(xh)) + rep_blocks = map(x_blocks) do xb + FEFunction(V0,xb) end return rep_blocks end From e0399141c4f42213d32d925e0ed54f06ae7cc991 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 22 Apr 2024 22:46:32 +1000 Subject: [PATCH 62/90] More bugfixes --- scripts/_dev/piezo_repeating.jl | 354 ++++++++++++++++++++++++++++++++ src/ChainRules.jl | 19 +- src/GridapExtensions.jl | 15 +- 3 files changed, 382 insertions(+), 6 deletions(-) create mode 100644 scripts/_dev/piezo_repeating.jl diff --git a/scripts/_dev/piezo_repeating.jl b/scripts/_dev/piezo_repeating.jl new file mode 100644 index 00000000..4c069651 --- /dev/null +++ b/scripts/_dev/piezo_repeating.jl @@ -0,0 +1,354 @@ +using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, + PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +using Gridap.TensorValues, Gridap.Helpers, Gridap.MultiField +using GridapSolvers.BlockSolvers + +function PZT5A(D::Int) + ε_0 = 8.854e-12; + if D == 3 + C_Voigt = [12.0400e10 7.52000e10 7.51000e10 0.0 0.0 0.0 + 7.52000e10 12.0400e10 7.51000e10 0.0 0.0 0.0 + 7.51000e10 7.51000e10 11.0900e10 0.0 0.0 0.0 + 0.0 0.0 0.0 2.1000e10 0.0 0.0 + 0.0 0.0 0.0 0.0 2.1000e10 0.0 + 0.0 0.0 0.0 0.0 0.0 2.30e10] + e_Voigt = [0.0 0.0 0.0 0.0 12.30000 0.0 + 0.0 0.0 0.0 12.30000 0.0 0.0 + -5.40000 -5.40000 15.80000 0.0 0.0 0.0] + K_Voigt = [540*ε_0 0 0 + 0 540*ε_0 0 + 0 0 830*ε_0] + elseif D == 2 + C_Voigt = [12.0400e10 7.51000e10 0.0 + 7.51000e10 11.0900e10 0.0 + 0.0 0.0 2.1000e10] + e_Voigt = [0.0 0.0 12.30000 + -5.40000 15.80000 0.0] + K_Voigt = [540*ε_0 0 + 0 830*ε_0] + else + @notimplemented + end + C = voigt2tensor4(C_Voigt) + e = voigt2tensor3(e_Voigt) + κ = voigt2tensor2(K_Voigt) + C,e,κ +end + +""" + Given a material constant given in Voigt notation, + return a SymFourthOrderTensorValue using ordering from Gridap +""" +function voigt2tensor4(A::Array{M,2}) where M + if isequal(size(A),(3,3)) + return SymFourthOrderTensorValue(A[1,1], A[3,1], A[2,1], + A[1,3], A[3,3], A[2,3], + A[1,2], A[3,2], A[2,2]) + elseif isequal(size(A),(6,6)) + return SymFourthOrderTensorValue(A[1,1], A[6,1], A[5,1], A[2,1], A[4,1], A[3,1], + A[1,6], A[6,6], A[5,6], A[2,6], A[4,6], A[3,6], + A[1,5], A[6,5], A[5,5], A[2,5], A[4,5], A[3,5], + A[1,2], A[6,2], A[5,2], A[2,2], A[4,2], A[3,2], + A[1,4], A[6,4], A[5,4], A[2,4], A[4,4], A[3,4], + A[1,3], A[6,3], A[5,3], A[2,3], A[4,3], A[3,3]) + else + @notimplemented + end +end + +""" + Given a material constant given in Voigt notation, + return a ThirdOrderTensorValue using ordering from Gridap +""" +function voigt2tensor3(A::Array{M,2}) where M + if isequal(size(A),(2,3)) + return ThirdOrderTensorValue(A[1,1], A[2,1], A[1,3], A[2,3], A[1,3], A[2,3], A[1,2], A[2,2]) + elseif isequal(size(A),(3,6)) + return ThirdOrderTensorValue( + A[1,1], A[2,1], A[3,1], A[1,6], A[2,6], A[3,6], A[1,5], A[2,5], A[3,5], + A[1,6], A[2,6], A[3,6], A[1,2], A[2,2], A[3,2], A[1,4], A[2,4], A[3,4], + A[1,5], A[2,5], A[3,5], A[1,4], A[2,4], A[3,4], A[1,3], A[2,3], A[3,3]) + else + @notimplemented + end +end + +""" + Given a material constant given in Voigt notation, + return a SymTensorValue using ordering from Gridap +""" +function voigt2tensor2(A::Array{M,2}) where M + return TensorValue(A) +end + +## Parameters +#function main(mesh_partition,distribute) + #ranks = distribute(LinearIndices((prod(mesh_partition),))) + +mesh_partition = (1,1) +ranks = with_mpi() do distribute + distribute(LinearIndices((prod(mesh_partition),))) +end + +el_size = (100,100) +order = 1 +xmax,ymax=(1.0,1.0) +dom = (0,xmax,0,ymax) +γ = 0.1 +γ_reinit = 0.5 +max_steps = floor(Int,order*minimum(el_size)/10) +tol = 1/(5order^2)/minimum(el_size) +η_coeff = 2 +α_coeff = 4*max_steps*γ +vf = 0.5 +path = dirname(@__DIR__)*"/results/2d_PZ_inverse_homenisation_MPI_Nx$(mesh_partition[1])Ny$(mesh_partition[2])/" +#i_am_main(ranks) && mkpath(path) + +## FE Setup +model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true)) +el_Δ = get_el_Δ(model) +f_Γ_D(x) = iszero(x) +update_labels!(1,model,f_Γ_D,"origin") + +## Triangulations and measures +Ω = Triangulation(model) +dΩ = Measure(Ω,2*order) +vol_D = sum(∫(1)dΩ) + +## Spaces +reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_scalar = ReferenceFE(lagrangian,Float64,order) +V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) +U = TrialFESpace(V,VectorValue(0.0,0.0)) +Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) +P = TrialFESpace(Q,0) +mfs = BlockMultiFieldStyle() +UP = MultiFieldFESpace([U,P];style=mfs) +VQ = MultiFieldFESpace([V,Q];style=mfs) + +V_φ = TestFESpace(model,reffe_scalar) +V_reg = TestFESpace(model,reffe_scalar) +U_reg = TrialFESpace(V_reg) + +## Create FE functions +lsf_fn = initial_lsf(2,0.2) +φh = interpolate(lsf_fn,V_φ) + +## Interpolation and weak form +interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ),ϵ=10^-9) +I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + +## Material tensors +C, e, κ = PZT5A(2); +k0 = norm(C.data,Inf); +α0 = norm(e.data,Inf); +β0 = norm(κ.data,Inf); +γ0 = β0*k0/α0^2; + +## Weak forms +εᴹ = (SymTensorValue(1.0,0.0,0.0), + SymTensorValue(0.0,0.0,1.0), + SymTensorValue(0.0,1/2,0)) +Eⁱ = (VectorValue(1.0,0.0,), + VectorValue(0.0,1.0)) + +a((u,ϕ),(v,q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - + 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + + -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + + -γ0/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q))) )dΩ; + +l_ε = [((v,q),φ,dΩ) -> ∫(((I ∘ φ) * (-C ⊙ εᴹ[i] ⊙ ε(v) + k0/α0*(e ⋅² εᴹ[i]) ⋅ -∇(q))))dΩ for i = 1:3]; +l_E = [((v,q),φ,dΩ) -> ∫((I ∘ φ) * ((Eⁱ[i] ⋅ e ⊙ ε(v) + k0/α0*(κ ⋅ Eⁱ[i]) ⋅ -∇(q))))dΩ for i = 1:2]; +l = [l_ε; l_E] + +## Optimisation functionals +# Note, uϕ unpacks as -> uϕ = u1,ϕ1,u2,ϕ2,u3,ϕ3,u4,ϕ4,u5,ϕ5 +# where entries 1,2,3 correspond to εᴹ[1],εᴹ[2],εᴹ[3] and +# 4,5 correspond to Eⁱ[1],Eⁱ[2]. + +function Cᴴ(r,s,uϕ,φ,dΩ) # (normalised by 1/k0) + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(1/k0 * (I ∘ φ) * (((C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ εᴹ[r]) - ((-1/α0*∇(ϕ_s) ⋅ e) ⊙ εᴹ[r])))dΩ; +end + +function DCᴴ(r,s,q,uϕ,φ,dΩ) # (normalised by 1/k0) + u_r = uϕ[2r-1]; ϕ_r = uϕ[2r] + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(- 1/k0 * q * ( + (C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - + (-1/α0*∇(ϕ_s) ⋅ e) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - + (e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ (-1/α0*∇(ϕ_r)) - + (κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ (-1/α0*∇(ϕ_r)) + ) * (DH ∘ φ) * (norm ∘ ∇(φ)) + )dΩ; +end + +function eᴴ(i,s,uϕ,φ,dΩ) # (normalised by 1/α0) + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(1/α0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ Eⁱ[i])))dΩ; +end + +function Deᴴ(i,s,q,uϕ,φ,dΩ) # (normalised by 1/α0) + u_i = uϕ[6+2i-1]; ϕ_i = uϕ[6+2i] + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(- 1/α0 * q * ( + - (C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ (1/k0*ε(u_i)) + + (-1/α0*∇(ϕ_s) ⋅ e) ⊙ (1/k0*ε(u_i)) + + (e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) + + (κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) + ) * (DH ∘ φ) * (norm ∘ ∇(φ)) + )dΩ; +end + +function κᴴ(i,j,uϕ,φ,dΩ) # (normalised by 1/β0) + u_j = uϕ[6+2j-1]; ϕ_j = uϕ[6+2j] + ∫(1/β0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_j)) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_j) + Eⁱ[j])) ⋅ Eⁱ[i]))))dΩ; +end + +function Dκᴴ(i,j,q,uϕ,φ,dΩ) # (normalised by 1/β0) + u_i = uϕ[6+2i-1]; ϕ_i = uϕ[6+2i] + u_j = uϕ[6+2j-1]; ϕ_j = uϕ[6+2j] + ∫(- 1/β0 * q * ( + - (C ⊙ (1/k0*ε(u_j))) ⊙ (1/k0*ε(u_i)) + + ((-1/α0*∇(ϕ_j) + Eⁱ[j]) ⋅ e) ⊙ (1/k0*ε(u_i)) + + (e ⋅² (1/k0*ε(u_j))) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) + + (κ ⋅ (-1/α0*∇(ϕ_j) + Eⁱ[j])) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) + ) * (DH ∘ φ) * (norm ∘ ∇(φ)) + )dΩ; +end + +# Equiv to +# C_mat = map(rs->sum(Cᴴ(rs[1],rs[2],xh,φh,dΩ)), CartesianIndices((1:3, 1:3))) +# e_mat = map(is->sum(eᴴ(is[1],is[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:3))) +# d_mat = e_mat*inv(C_mat); +# dh = d_mat[2,1] + d_mat[2,2] +function dᴴ(uϕ,φ,dΩ) + # We leave eᴴ_21 and eᴴ_22 as DomainContribution so that result is a DomainContribution. + # Note that this means AD applied to this functional would be incorrect. + Cᴴ_11 = sum(Cᴴ(1,1,uϕ,φ,dΩ)); + Cᴴ_22 = sum(Cᴴ(2,2,uϕ,φ,dΩ)); + Cᴴ_21 = sum(Cᴴ(2,1,uϕ,φ,dΩ)); + eᴴ_21 = eᴴ(2,1,uϕ,φ,dΩ); + eᴴ_22 = eᴴ(2,2,uϕ,φ,dΩ); + (Cᴴ_22*eᴴ_21 + Cᴴ_11*eᴴ_22 - Cᴴ_21*(eᴴ_21 + eᴴ_22))*(1/(Cᴴ_11*Cᴴ_22 - Cᴴ_21^2)) +end + +function Ddᴴ(q,uϕ,φ,dΩ) + Cᴴ_11 = sum(Cᴴ(1,1,uϕ,φ,dΩ)); DCᴴ_11 = DCᴴ(1,1,q,uϕ,φ,dΩ) + Cᴴ_22 = sum(Cᴴ(2,2,uϕ,φ,dΩ)); DCᴴ_22 = DCᴴ(2,2,q,uϕ,φ,dΩ) + Cᴴ_21 = sum(Cᴴ(2,1,uϕ,φ,dΩ)); DCᴴ_21 = DCᴴ(2,1,q,uϕ,φ,dΩ) + eᴴ_21 = sum(eᴴ(2,1,uϕ,φ,dΩ)); Deᴴ_21 = DCᴴ(2,1,q,uϕ,φ,dΩ) + eᴴ_22 = sum(eᴴ(2,2,uϕ,φ,dΩ)); Deᴴ_22 = DCᴴ(2,2,q,uϕ,φ,dΩ) + (-1*Cᴴ_11^2*eᴴ_22*(DCᴴ_22)+Cᴴ_22^2*(-eᴴ_21*(DCᴴ_11)+Cᴴ_11*(Deᴴ_21))+ + Cᴴ_21^3*((Deᴴ_21)+(Deᴴ_22))+Cᴴ_11*Cᴴ_22*(-1*((eᴴ_21+eᴴ_22)*(DCᴴ_21))+ + Cᴴ_11*(Deᴴ_22))-Cᴴ_21^2*(eᴴ_22*((DCᴴ_11)+(DCᴴ_21))+eᴴ_21*((DCᴴ_21)+(DCᴴ_22))+ + Cᴴ_22*(Deᴴ_21)+Cᴴ_11*(Deᴴ_22))+Cᴴ_21*(Cᴴ_11*(2*eᴴ_22*(DCᴴ_21)+(eᴴ_21+eᴴ_22)*(DCᴴ_22))+ + Cᴴ_22*((eᴴ_21+eᴴ_22)*(DCᴴ_11)+2*eᴴ_21*(DCᴴ_21)-Cᴴ_11*((Deᴴ_21)+(Deᴴ_22)))))*(1/(Cᴴ_21^2-Cᴴ_11*Cᴴ_22)^2) +end + +Bᴴ(uϕ,φ,dΩ) = 1/4*(Cᴴ(1,1,uϕ,φ,dΩ)+Cᴴ(2,2,uϕ,φ,dΩ)+2*Cᴴ(1,2,uϕ,φ,dΩ)) +DBᴴ(q,uϕ,φ,dΩ) = 1/4*(DCᴴ(1,1,q,uϕ,φ,dΩ)+DCᴴ(2,2,q,uϕ,φ,dΩ)+2*DCᴴ(1,2,q,uϕ,φ,dΩ)) + + +J(uϕ,φ,dΩ) = -1*dᴴ(uϕ,φ,dΩ) +DJ(q,uϕ,φ,dΩ) = -1*Ddᴴ(q,uϕ,φ,dΩ) +C1(uϕ,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; +DC1(q,uϕ,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ +C2(uϕ,φ,dΩ) = Cᴴ(2,2,uϕ,φ,dΩ) - ∫(0.05/vol_D)dΩ +DC2(q,uϕ,φ,dΩ) = DCᴴ(2,2,q,uϕ,φ,dΩ) + +# ## Finite difference solver and level set function +stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + +# ## Setup solver and FE operators +Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} +Tv = Vector{PetscScalar} +solver_u = LUSolver() #ElasticitySolver(V) #GridapSolvers.LinearSolvers.ElasticitySolver(V) +solver_ϕ = LUSolver() #PETScLinearSolver() + +# P = GridapSolvers.BlockDiagonalSolver([solver_u,solver_ϕ]) +# solver = GridapSolvers.LinearSolvers.GMRESSolver(100;Pr=P,rtol=1.e-8,verbose=i_am_main(ranks)) +solver = BlockTriangularSolver([solver_u,solver_ϕ]) + +state_map = RepeatingAffineFEStateMap(5,a,l,UP,VQ,V_φ,U_reg,φh,dΩ; + assem_U = SparseMatrixAssembler(Tm,Tv,UP,VQ), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,VQ,UP), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + ls = solver,adjoint_ls = solver +) +pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map;analytic_dJ=DJ,analytic_dC=[DC1,DC2]) + +# ## Hilbertian extension-regularisation problems +α = α_coeff*maximum(el_Δ) +a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; +vel_ext = VelocityExtension( + a_hilb,U_reg,V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() +) + +# ## Optimiser +has_oscillations(m,os_it) = LevelSetTopOpt.default_has_oscillations(m,os_it;itlength=25) +optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh;γ,γ_reinit,has_oscillations, + verbose=i_am_main(ranks),ls_enabled=true) +for (it, uh, φh) in optimiser + u1,ϕ1,u2,ϕ2,u3,ϕ3,u4,ϕ4,u5,ϕ5 = uh + data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)), + "u1"=>1/k0*u1,"ϕ1"=>1/α0*ϕ1,"u2"=>1/k0*u2,"ϕ2"=>1/α0*ϕ2,"u3"=>1/k0*u3,"ϕ3"=>1/α0*ϕ3, + "u4"=>1/k0*u4,"ϕ4"=>1/α0*ϕ4,"u5"=>1/k0*u5,"ϕ5"=>1/α0*ϕ5] + writevtk(Ω,path*"out$it",cellfields=data) + write_history(path*"/history.txt",optimiser.history) +end +#end + +#with_debug() do distribute +# mesh_partition = (2,2) +# solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true +# -ksp_converged_reason -ksp_rtol 1.0e-12" +# GridapPETSc.with(args=split(solver_options)) do +# main(mesh_partition,distribute) +# end +#end + +# mesh_partition = (2,2) +# ranks = with_debug() do distribute +# distribute(LinearIndices((prod(mesh_partition),))) +# end + +# el_size = (200,200) +# order = 1 +# xmax,ymax=(1.0,1.0) +# dom = (0,xmax,0,ymax) +# γ = 0.1 +# γ_reinit = 0.5 +# max_steps = floor(Int,order*minimum(el_size)/10) +# tol = 1/(5order^2)/minimum(el_size) +# η_coeff = 2 +# α_coeff = 4*max_steps*γ +# vf = 0.5 + +# ## FE Setup +# model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true)) +# el_Δ = get_el_Δ(model) +# f_Γ_D(x) = iszero(x) +# update_labels!(1,model,f_Γ_D,"origin") + +# ## Triangulations and measures +# Ω = Triangulation(model) +# dΩ = Measure(Ω,2*order) +# vol_D = sum(∫(1)dΩ) + +# ## Spaces +# reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +# reffe_scalar = ReferenceFE(lagrangian,Float64,order) +# V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) +# U = TrialFESpace(V,VectorValue(0.0,0.0)) +# Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) +# P = TrialFESpace(Q,0) +# mfs = BlockMultiFieldStyle() +# UP = MultiFieldFESpace([U,P];style=mfs) +# VQ = MultiFieldFESpace([V,Q];style=mfs) + +# Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} +# Tv = Vector{PetscScalar} +# assem = SparseMatrixAssembler(Tm,Tv,UP,VQ) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 8f57722c..398f74db 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -695,7 +695,7 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap - The resulting `FEFunction` will be a `MultiFieldFEFunction` (or GridapDistributed equivalent) where each field corresponds to an entry in the vector of linear forms """ - function RepeatingAffineFEStateMap( + function RepeatingAffineFEStateMap( nblocks::Int,a::Function,l::Vector{<:Function}, U0,V0,V_φ,U_reg,φh,dΩ...; assem_U = SparseMatrixAssembler(U0,V0), @@ -715,7 +715,7 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap spaces = (U,V,V_φ,U_reg) assem_U = SparseMatrixAssembler( get_local_matrix_type(assem_U0), get_local_vector_type(assem_U0), - U, V, get_assembly_strategy(assem_U0) + U, V, get_local_assembly_strategy(assem_U0) ) ## Pullback cache @@ -731,13 +731,13 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap K = assemble_matrix((u,v) -> biform(u,v,φh),assem_U0,U0,V0) b = allocate_in_range(K); fill!(b,zero(eltype(b))) b0 = allocate_in_range(K); fill!(b0,zero(eltype(b0))) - x = mortar(map(i -> allocate_in_domain(K), 1:nblocks)); fill!(x,zero(eltype(x))) + x = repeated_allocate_in_domain(nblocks,K); fill!(x,zero(eltype(x))) ns = numerical_setup(symbolic_setup(ls,K),K) fwd_caches = (ns,K,b,x,uhd,assem_U0,b0,assem_U) ## Adjoint cache adjoint_K = assemble_matrix((u,v)->biform(v,u,φh),assem_adjoint,V0,U0) - adjoint_x = mortar(map(i -> allocate_in_domain(adjoint_K), 1:nblocks)); fill!(adjoint_x,zero(eltype(adjoint_x))) + adjoint_x = repeated_allocate_in_domain(nblocks,adjoint_K); fill!(adjoint_x,zero(eltype(adjoint_x))) adjoint_ns = numerical_setup(symbolic_setup(adjoint_ls,adjoint_K),adjoint_K) adj_caches = (adjoint_ns,adjoint_K,adjoint_x,assem_adjoint) @@ -782,6 +782,7 @@ end repeated_blocks(V0::FESpace,x::AbstractBlockVector) = blocks(x) repeated_blocks(V0::FESpace,xh) = xh +repeated_blocks(V0::MultiFieldSpaceTypes,x::AbstractBlockVector) = repeated_blocks(MultiFieldStyle(V0),V0,x) repeated_blocks(V0::MultiFieldSpaceTypes,x) = repeated_blocks(MultiFieldStyle(V0),V0,x) repeated_blocks(::ConsecutiveMultiFieldStyle,V0,x::AbstractBlockVector) = blocks(x) repeated_blocks(::ConsecutiveMultiFieldStyle,V0,xh) = xh @@ -798,13 +799,21 @@ function repeated_blocks(::BlockMultiFieldStyle{NB},V0::MultiFieldSpaceTypes,x:: end function repeated_blocks(::BlockMultiFieldStyle,V0::MultiFieldSpaceTypes,xh) - x_blocks = repeated_blocks(MultiFieldStyle(V0),V0,get_free_values(xh)) + x_blocks = repeated_blocks(MultiFieldStyle(V0),V0,get_free_dof_values(xh)) rep_blocks = map(x_blocks) do xb FEFunction(V0,xb) end return rep_blocks end +function repeated_allocate_in_domain(nblocks::Integer,M::AbstractMatrix) + mortar(map(i -> allocate_in_domain(M), 1:nblocks)) +end + +function repeated_allocate_in_domain(nblocks::Integer,M::AbstractBlockMatrix) + mortar(vcat(map(i -> blocks(allocate_in_domain(M)), 1:nblocks)...)) +end + get_state(m::RepeatingAffineFEStateMap) = FEFunction(get_trial_space(m),m.fwd_caches[4]) get_measure(m::RepeatingAffineFEStateMap) = m.biform.dΩ get_spaces(m::RepeatingAffineFEStateMap) = m.spaces diff --git a/src/GridapExtensions.jl b/src/GridapExtensions.jl index 6b6b9991..3e8b6e4b 100644 --- a/src/GridapExtensions.jl +++ b/src/GridapExtensions.jl @@ -62,11 +62,24 @@ end get_local_matrix_type(a::Assembler) = get_matrix_type(a) get_local_vector_type(a::Assembler) = get_vector_type(a) +get_local_assembly_strategy(a::Assembler) = get_assembly_strategy(a) function get_local_matrix_type(a::GridapDistributed.DistributedSparseMatrixAssembler) return getany(map(get_matrix_type,a.assems)) end - function get_local_vector_type(a::GridapDistributed.DistributedSparseMatrixAssembler) return getany(map(get_vector_type,a.assems)) end +function get_local_assembly_strategy(a::GridapDistributed.DistributedSparseMatrixAssembler) + return get_assembly_strategy(a) +end + +function get_local_matrix_type(a::MultiField.BlockSparseMatrixAssembler) + return get_local_matrix_type(first(a.block_assemblers)) +end +function get_local_vector_type(a::MultiField.BlockSparseMatrixAssembler) + return get_local_vector_type(first(a.block_assemblers)) +end +function get_local_assembly_strategy(a::MultiField.BlockSparseMatrixAssembler) + return get_local_assembly_strategy(first(a.block_assemblers)) +end From 249b60b3c856177db1a8b07e4b870826c8c9fc9a Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:44:58 +1000 Subject: [PATCH 63/90] More fixes for Lyra jobs --- scripts/Benchmarks/jobtemplate.sh | 4 ++++ scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs | 4 ++++ scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs | 4 ++++ scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs | 4 ++++ scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs | 4 ++++ scripts/MPI/jobs/3d_inverter_ALM.pbs | 4 ++++ scripts/MPI/jobs/3d_inverter_HPM.pbs | 4 ++++ scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs | 4 ++++ scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs | 4 ++++ scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs | 4 ++++ scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs | 4 ++++ scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs | 4 ++++ scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs | 4 ++++ scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs | 4 ++++ 14 files changed, 56 insertions(+) diff --git a/scripts/Benchmarks/jobtemplate.sh b/scripts/Benchmarks/jobtemplate.sh index 09e204c3..049acb79 100644 --- a/scripts/Benchmarks/jobtemplate.sh +++ b/scripts/Benchmarks/jobtemplate.sh @@ -5,6 +5,10 @@ #PBS -l select={{:ncpus}}:ncpus=1:mpiprocs=1:ompthreads=1:mem={{:mem}}GB:cputype={{:cputype}} #PBS -l walltime={{:wallhr}}:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/{{:dir_name}}/ diff --git a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs index 20e7f3c6..9ab66596 100644 --- a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs @@ -5,6 +5,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs index b0f29779..58b91b3a 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs @@ -5,6 +5,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs index 7fd9279a..67935f3b 100644 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs +++ b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs @@ -5,6 +5,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs index ffa8d005..5a1e636d 100644 --- a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs @@ -5,6 +5,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/MPI/jobs/3d_inverter_ALM.pbs b/scripts/MPI/jobs/3d_inverter_ALM.pbs index 54b6311b..1eb0f7f2 100644 --- a/scripts/MPI/jobs/3d_inverter_ALM.pbs +++ b/scripts/MPI/jobs/3d_inverter_ALM.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/MPI/jobs/3d_inverter_HPM.pbs b/scripts/MPI/jobs/3d_inverter_HPM.pbs index c0390d54..66365043 100644 --- a/scripts/MPI/jobs/3d_inverter_HPM.pbs +++ b/scripts/MPI/jobs/3d_inverter_HPM.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs index de3e8b48..985235f3 100644 --- a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs index f456d8a7..5d69d821 100644 --- a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs +++ b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs index 94a34cfa..b257f199 100644 --- a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs index 5a8b0387..c2fd001a 100644 --- a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs index 9da69050..e56cd3d1 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs index 6cfc5060..a2c4e55c 100644 --- a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ diff --git a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs index d24b04a1..775f4a00 100644 --- a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs @@ -6,6 +6,10 @@ #PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 #PBS -l walltime=23:00:00 #PBS -j oe +#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh +#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh +#PBS -v I_MPI_HYDRA_IFACE=ib0 +#PBS -v OMP_NUM_THREADS=1 source $HOME/hpc-environments-main/lyra/load-intel.sh PROJECT_DIR=$HOME/LevelSetTopOpt/ From 5c1ba52cc8f8946595bd145d5762ee7c590fc6ef Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 26 Apr 2024 06:27:02 +1000 Subject: [PATCH 64/90] script fix --- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index ff76c4a0..d1b3c677 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -77,8 +77,7 @@ function main(mesh_partition,distribute) C1(u,φ,dΩ,dΓ_in,dΓ_out) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ dC1(q,u,φ,dΩ,dΓ_in,dΓ_out) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ C2(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out - pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map, - analytic_dJ=dJ,analytic_dC=[dC1,nothing]) + pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map,analytic_dC=[dC1,nothing]) # Velocity extension α = 4max_steps*γ*maximum(get_el_Δ(model)) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ From ad05548ba08b7730eb750b83cad8aecd3d0a9243 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 26 Apr 2024 16:34:40 +1000 Subject: [PATCH 65/90] added bmarks for gadi --- .../generate_benchmark_scripts_gadi.jl | 95 +++++++++++++++++++ scripts/Benchmarks/jobtemplate_gadi.sh | 26 +++++ 2 files changed, 121 insertions(+) create mode 100644 scripts/Benchmarks/generate_benchmark_scripts_gadi.jl create mode 100644 scripts/Benchmarks/jobtemplate_gadi.sh diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl new file mode 100644 index 00000000..8f2eb50f --- /dev/null +++ b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl @@ -0,0 +1,95 @@ +using Pkg +Pkg.activate() +using Mustache + +function generate( + template, + name, + type, + bmark_type, + cputype, + wallhr, + n_mesh_partition, + n_el_size, + fe_order, + verbose, + dir_name, + write_dir, + nreps + ) + + ncpus = n_mesh_partition^3 + wallhr = occursin("STRONG",name) && n_mesh_partition <= 3 ? 100 : wallhr + mem = occursin("STRONG",name) && n_mesh_partition == 1 ? 256 : + occursin("STRONG",name) && n_mesh_partition == 2 ? 32 : gb_per_cpu; + + settings = (;name,type,bmark_type,cputype,wallhr,ncpus,mem, + n_mesh_partition,n_el_size,fe_order,verbose,dir_name,write_dir,nreps) + Mustache.render(template, settings) +end + +function generate_jobs(template,phys_type,ndof_per_node,bmark_types) + npart = (N).^3; + weak_el_x = @. floor(Int,(dofs_per_proc*npart/ndof_per_node)^(1/3)-1); + dof_sanity_check = @.(floor(Int,ndof_per_node*(weak_el_x+1)^3/npart)), + maximum(abs,@. ndof_per_node*(weak_el_x+1)^3/npart/dofs_per_proc - 1) + + sname(phys_type,ndof_per_node,n,elx) = "STRONG_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" + wname(phys_type,ndof_per_node,n,elx) = "WEAK_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" + + strong_el_x = ceil(Int,(strong_dof/ndof_per_node)^(1/3)); + + strong_jobs = map(n->(sname(phys_type,ndof_per_node,n,strong_el_x), + generate(template,sname(phys_type,ndof_per_node,n,strong_el_x),phys_type,bmark_types, + cputype,wallhr,n,strong_el_x,fe_order,verbose,dir_name,write_dir,nreps)),N) + weak_jobs = map((n,elx)->(wname(phys_type,ndof_per_node,n,elx), + generate(template,wname(phys_type,ndof_per_node,n,elx),phys_type,bmark_types, + cputype,wallhr,n,elx,fe_order,verbose,dir_name,write_dir,nreps)),N,weak_el_x) + + strong_jobs,weak_jobs,dof_sanity_check +end + +dir_name= "LevelSetTopOpt"; +job_output_path = "\$SCRATCH/$dir_name/scripts/Benchmarks/jobs-gadi/"; +mkpath(job_output_path); + +# SETUP PARAMETERS +cputype=""; # Not needed here +gb_per_cpu = 8 # GB +wallhr = 3 ; # Hours (Note may want to manually change some afterwards) + +nreps = 10; # Number of benchmark repetitions +dofs_per_proc = 32000; +fe_order= 1; +verbose= 1; +write_dir = "\$SCRATCH/$dir_name/results/benchmarks/" + +N = 1:10; # Number of partitions in x-axis +strong_dof=(100+1)^3*3; # Number of dofs for strong scaling + +# Phys type and number of dofs per node, and what to benchmark +phys_types = [ + ("THERM",1,"bopt0,bopt1,bfwd,badv,breinit,bvelext"), + ("ELAST",3,"bopt0,bopt1,bfwd,badv,breinit,bvelext"), + ("NLELAST",3,"bopt0,bopt1,bfwd"), + # ("INVERTER_HPM",3,"bhpm"), +]; + +# Template +template = read("\$SCRATCH/$dir_name/scripts/Benchmarks/jobtemplate_gadi.sh",String) + +## Generate Jobs +jobs_by_phys = map(x->(x[1],generate_jobs(template,x[1],x[2],x[3])),phys_types); + +for jobs in jobs_by_phys + strong_jobs,weak_jobs,dof_sanity_check = jobs[2] + + println("$(jobs[1]): Weak dofs = $(dof_sanity_check[1])\n Error = $(dof_sanity_check[2])\n") + for job in vcat(strong_jobs,weak_jobs) + name = job[1] + content = job[2] + open(job_output_path*"$name.pbs","w") do f + write(f,content) + end + end +end \ No newline at end of file diff --git a/scripts/Benchmarks/jobtemplate_gadi.sh b/scripts/Benchmarks/jobtemplate_gadi.sh new file mode 100644 index 00000000..63dfe4d8 --- /dev/null +++ b/scripts/Benchmarks/jobtemplate_gadi.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#PBS -P np01 +#PBS -q normal +#PBS -N "{{:name}}" +#PBS -l ncpus={{:ncpus}} +#PBS -l mem={{:mem}}GB +#PBS -l walltime={{:wallhr}}:00:00 +#PBS -j oe + +source $HOME/hpc-environments/gadi/load-intel.sh +PROJECT_DIR=$SCRATCH/{{:dir_name}}/ + +julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" + +mpirun -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 \ + $PROJECT_DIR/scripts/Benchmarks/benchmark.jl \ + {{:name}} \ + {{{:write_dir}}} \ + {{:type}} \ + {{:bmark_type}} \ + {{:n_mesh_partition}} \ + {{:n_el_size}} \ + {{:fe_order}} \ + {{:verbose}} \ + {{:nreps}} \ No newline at end of file From 9601445d3668c0a54ba276d6eb5099d9970a8955 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:07:38 +1000 Subject: [PATCH 66/90] fix --- scripts/Benchmarks/generate_benchmark_scripts_gadi.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl index 8f2eb50f..d1988f80 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl @@ -50,7 +50,7 @@ function generate_jobs(template,phys_type,ndof_per_node,bmark_types) end dir_name= "LevelSetTopOpt"; -job_output_path = "\$SCRATCH/$dir_name/scripts/Benchmarks/jobs-gadi/"; +job_output_path = "./$dir_name/scripts/Benchmarks/jobs-gadi/"; mkpath(job_output_path); # SETUP PARAMETERS @@ -76,7 +76,7 @@ phys_types = [ ]; # Template -template = read("\$SCRATCH/$dir_name/scripts/Benchmarks/jobtemplate_gadi.sh",String) +template = read("./$dir_name/scripts/Benchmarks/jobtemplate_gadi.sh",String) ## Generate Jobs jobs_by_phys = map(x->(x[1],generate_jobs(template,x[1],x[2],x[3])),phys_types); From df1718fbf8d142a6e2425b1c8327f3637522651a Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:08:48 +1000 Subject: [PATCH 67/90] another fix --- scripts/Benchmarks/generate_benchmark_scripts_gadi.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl index d1988f80..bf288c4b 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl @@ -50,7 +50,7 @@ function generate_jobs(template,phys_type,ndof_per_node,bmark_types) end dir_name= "LevelSetTopOpt"; -job_output_path = "./$dir_name/scripts/Benchmarks/jobs-gadi/"; +job_output_path = "$(ENV["SCRATCH"])/$dir_name/scripts/Benchmarks/jobs-gadi/"; mkpath(job_output_path); # SETUP PARAMETERS @@ -76,7 +76,7 @@ phys_types = [ ]; # Template -template = read("./$dir_name/scripts/Benchmarks/jobtemplate_gadi.sh",String) +template = read("$(ENV["SCRATCH"])/$dir_name/scripts/Benchmarks/jobtemplate_gadi.sh",String) ## Generate Jobs jobs_by_phys = map(x->(x[1],generate_jobs(template,x[1],x[2],x[3])),phys_types); From 16b8293a74b614a3eda1be6dc9b8f017440cefec Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:58:24 +1000 Subject: [PATCH 68/90] Fixed bmarks for gadi --- scripts/Benchmarks/benchmark_gadi.jl | 460 ++++++++++++++++++ .../generate_benchmark_scripts_gadi.jl | 50 +- scripts/Benchmarks/jobtemplate_gadi.sh | 6 +- 3 files changed, 499 insertions(+), 17 deletions(-) create mode 100644 scripts/Benchmarks/benchmark_gadi.jl diff --git a/scripts/Benchmarks/benchmark_gadi.jl b/scripts/Benchmarks/benchmark_gadi.jl new file mode 100644 index 00000000..c3dc701c --- /dev/null +++ b/scripts/Benchmarks/benchmark_gadi.jl @@ -0,0 +1,460 @@ +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, + PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + +using LevelSetTopOpt: get_deriv_space, get_aux_space,benchmark_optimizer, + benchmark_forward_problem,benchmark_advection,benchmark_reinitialisation, + benchmark_velocity_extension,benchmark_hilbertian_projection_map,benchmark_single_iteration + +using GridapSolvers: NewtonSolver + +global NAME = ARGS[1] +global WRITE_DIR = ARGS[2] +global PROB_TYPE = ARGS[3] +global BMARK_TYPE = ARGS[4] +global Nx = parse(Int,ARGS[5]) +global Ny = parse(Int,ARGS[6]) +global Nz = parse(Int,ARGS[7]) +global N_EL = parse(Int,ARGS[8]) +global ORDER = parse(Int,ARGS[9]) +global VERBOSE = parse(Int,ARGS[10]) +global NREPS = parse(Int,ARGS[11]) + +function nl_elast(mesh_partition,ranks,el_size,order,verbose) + # FE parameters + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + prop_Γ_N = 0.2 # Γ_N size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + E = 1000 # Young's modulus + ν = 0.3 # Poisson's ratio + μ, λ = E/(2*(1 + ν)), E*ν/((1 + ν)*(1 - 2*ν)) # Lame constants + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + # Triangulation and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + ## Piola-Kirchhoff tensor + function S(∇u) + Cinv = inv(C(F(∇u))) + μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv + end + ## Derivative of Green strain + dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) + ## Right Cauchy-Green deformation tensor + C(F) = (F')⋅F + ## Deformation gradient tensor + F(∇u) = one(∇u) + ∇u' + ## Volume change + J(F) = sqrt(det(C(F))) + ## Residual + res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE ∘ (∇(v),∇(u))) ⊙ (S ∘ ∇(u))) )*dΩ - ∫(g⋅v)dΓ_N + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + lin_solver = ElasticitySolver(V) + nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose) + state_map = NonlinearFEStateMap( + res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + nls = nl_solver, adjoint_ls = lin_solver + ) + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((dE ∘ (∇(u),∇(u))) ⊙ (S ∘ ∇(u))))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map,analytic_dC=[dC1]) + # Velocity extension + α = 4max_steps*γ*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension( + a_hilb, U_reg, V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() + ) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + # Optimiser + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) +end + +function therm(mesh_partition,ranks,el_size,order,verbose) + # FE parameters + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + prop_Γ_N = 0.2 # Γ_N size parameter + prop_Γ_D = 0.2 # Γ_D size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function + (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && + (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + κ = 1 # Diffusivity + g = 1 # Heat flow in + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + # Triangulation and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,0.0) + V_φ = TestFESpace(model,reffe) + V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + solver = PETScLinearSolver() + state_map = AffineFEStateMap( + a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + ls = solver,adjoint_ls = solver + ) + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ + dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) + # Velocity extension + α = 4max_steps*γ*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension( + a_hilb, U_reg, V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = solver + ) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + # Optimiser + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) +end + +function elast(mesh_partition,ranks,el_size,order,verbose) + # FE parameters + xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size + dom = (0,xmax,0,ymax,0,zmax) # Bounding domain + prop_Γ_N = 0.2 # Γ_N size parameter + f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function + (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function + # FD parameters + γ = 0.1 # HJ eqn time step coeff + γ_reinit = 0.5 # Reinit. eqn time step coeff + max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection + tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance + # Problem parameters + C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor + g = VectorValue(0,0,-1) # Applied load on Γ_N + vf = 0.4 # Volume fraction constraint + lsf_func = initial_lsf(4,0.2) # Initial level set function + # Model + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + # Triangulation and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + # Spaces + reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + # Level set and interpolator + φh = interpolate(lsf_func,V_φ) + interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + # Weak formulation + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(v⋅g)dΓ_N + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + solver = ElasticitySolver(V) + state_map = AffineFEStateMap( + a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + ls = solver,adjoint_ls = solver + ) + # Objective and constraints + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(u)))dΩ + dJ(q,u,φ,dΩ,dΓ_N) = ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + vol_D = sum(∫(1)dΩ) + C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + pcfs = PDEConstrainedFunctionals(J,[C1],state_map, + analytic_dJ=dJ,analytic_dC=[dC1]) + # Velocity extension + α = 4max_steps*γ*maximum(get_el_Δ(model)) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension( + a_hilb, U_reg, V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() + ) + # Finite difference scheme + scheme = FirstOrderStencil(length(el_size),Float64) + ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) + # Optimiser + return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) +end + +function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) + ## Parameters + dom = (0,1,0,1,0,1) + γ = 0.05 + γ_reinit = 0.5 + max_steps = floor(Int,minimum(el_size)/3) + tol = 1/(2order^2)/minimum(el_size) + C = isotropic_elast_tensor(3,1.0,0.3) + η_coeff = 2 + α_coeff = 4 + vf=0.4 + δₓ=0.5 + ks = 0.01 + g = VectorValue(1,0,0) + + ## FE Setup + model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); + el_Δ = get_el_Δ(model) + f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + (0.4 - eps() <= x[3] <= 0.6 + eps()) + f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + (0.4 - eps() <= x[3] <= 0.6 + eps()) + f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && + (0.3 - eps() <= x[3] <= 0.7 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) + update_labels!(1,model,f_Γ_in,"Gamma_in") + update_labels!(2,model,f_Γ_out,"Gamma_out") + update_labels!(3,model,f_Γ_out_ext,"Gamma_out_ext") + update_labels!(4,model,f_Γ_D,"Gamma_D") + + ## Triangulations and measures + Ω = Triangulation(model) + Γ_in = BoundaryTriangulation(model,tags="Gamma_in") + Γ_out = BoundaryTriangulation(model,tags="Gamma_out") + dΩ = Measure(Ω,2*order) + dΓ_in = Measure(Γ_in,2*order) + dΓ_out = Measure(Γ_out,2*order) + vol_D = sum(∫(1)dΩ) + vol_Γ_in = sum(∫(1)dΓ_in) + vol_Γ_out = sum(∫(1)dΓ_out) + + ## Spaces + reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_in","Gamma_out","Gamma_out_ext"]) + U_reg = TrialFESpace(V_reg,[0,0,0]) + + ## Create FE functions + φh = interpolate(initial_lsf(4,0.1),V_φ); + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + a(u,v,φ,dΩ,dΓ_in,dΓ_out) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + ∫(ks*(u⋅v))dΓ_out + l(v,φ,dΩ,dΓ_in,dΓ_out) = ∫(v⋅g)dΓ_in + + ## Optimisation functionals + e₁ = VectorValue(1,0,0) + J(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅e₁)/vol_Γ_in)dΓ_in + Vol(u,φ,dΩ,dΓ_in,dΓ_out) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; + dVol(q,u,φ,dΩ,dΓ_in,dΓ_out) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out + + ## Finite difference solver + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + + ## Setup solver and FE operators + Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} + Tv = Vector{PetscScalar} + solver = ElasticitySolver(V) + + state_map = AffineFEStateMap( + a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out; + assem_U = SparseMatrixAssembler(Tm,Tv,U,V), + assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), + assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), + ls = solver, adjoint_ls = solver + ) + pcfs = PDEConstrainedFunctionals(J,[Vol,UΓ_out],state_map,analytic_dC=[dVol,nothing]) + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + vel_ext = VelocityExtension( + a_hilb,U_reg,V_reg; + assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), + ls = PETScLinearSolver() + ) + + ## Optimiser + return HilbertianProjection(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=verbose) +end + +with_mpi() do distribute + # Setup + mesh_partition = (Nx,Ny,Nz) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + el_size = (N_EL,N_EL,N_EL) + verbose = Bool(VERBOSE) ? i_am_main(ranks) : false; + if PROB_TYPE == "NLELAST" + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + opt = nl_elast + elseif PROB_TYPE == "THERM" + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + opt = therm + elseif PROB_TYPE == "ELAST" + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + opt = elast + elseif PROB_TYPE == "INVERTER_HPM" + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + -ksp_converged_reason -ksp_rtol 1.0e-12" + opt = inverter_HPM + else + error("Problem not defined") + end + + # Output + i_am_main(ranks) && ~isdir(WRITE_DIR) && mkpath(WRITE_DIR) + # Run + t_start = PTimer(ranks); + GridapPETSc.with(args=split(options)) do + tic!(t_start;barrier=true) + optim = opt(mesh_partition,ranks,el_size,ORDER,verbose) + toc!(t_start,"startup") + startup_time = map_main(t_start.data) do data + map(x -> x.max,values(data)) + end |> PartitionedArrays.getany + bstart = i_am_main(ranks) && [startup_time; zeros(NREPS-1)] + ## Benchmark optimiser + if occursin("bopt0",BMARK_TYPE) + bopt0 = benchmark_optimizer(optim, 0, ranks; nreps=NREPS) + else + bopt0 = i_am_main(ranks) && zeros(NREPS) + end + if occursin("bopt1",BMARK_TYPE) + bopt1 = benchmark_single_iteration(optim, ranks; nreps = NREPS) + else + bopt1 = i_am_main(ranks) && zeros(NREPS) + end + ## Benchmark reinitialisation + if occursin("breinit",BMARK_TYPE) + breinit = benchmark_reinitialisation(optim.ls_evolver, get_free_dof_values(optim.φ0), 0.1, ranks; nreps=NREPS) + else + breinit = i_am_main(ranks) && zeros(NREPS) + end + ## Benchmark forward problem + if occursin("bfwd",BMARK_TYPE) + bfwd = benchmark_forward_problem(optim.problem.state_map, optim.φ0, ranks; nreps=NREPS) + else + bfwd = i_am_main(ranks) && zeros(NREPS) + end + ## Benchmark advection + reinit!(optim.ls_evolver,optim.φ0,optim.params.γ_reinit) + if occursin("badv",BMARK_TYPE) + vh = interpolate(FEFunction(get_deriv_space(optim.problem.state_map),optim.problem.dJ), + get_aux_space(optim.problem.state_map)) + v = get_free_dof_values(vh) + badv = benchmark_advection(optim.ls_evolver, get_free_dof_values(optim.φ0), v, 0.1, ranks; nreps=NREPS) + else + badv = i_am_main(ranks) && zeros(NREPS) + end + ## Benchmark velocity extension + if occursin("bvelext",BMARK_TYPE) + bvelext = benchmark_velocity_extension(optim.vel_ext, optim.problem.dJ, ranks; nreps=NREPS) + else + bvelext = i_am_main(ranks) && zeros(NREPS) + end + ## HPM + if occursin("bhpm",BMARK_TYPE) + @assert typeof(optim) <: HilbertianProjection + J, C, dJ, dC = Gridap.evaluate!(optim.problem,optim.φ0) + optim.projector,dJ,C,dC,optim.vel_ext.K + bhpm = benchmark_hilbertian_projection_map(optim.projector,dJ,C,dC,optim.vel_ext.K,ranks) + else + bhpm = i_am_main(ranks) && zeros(NREPS) + end + ## Write results + if i_am_main(ranks) + open(WRITE_DIR*NAME*".txt","w") do f + bcontent = "startup,bopt(0),bopt(1),bfwd,badv,breinit,bvelext,bhpm\n" + for i = 1:NREPS + bcontent *= "$(bstart[i]),$(bopt0[i]),$(bopt1[i]),$(bfwd[i]),$(badv[i]),$(breinit[i]),$(bvelext[i]),$(bhpm[i])\n" + end + write(f,bcontent) + end + end + end +end \ No newline at end of file diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl index bf288c4b..453ff8c0 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl @@ -2,6 +2,21 @@ using Pkg Pkg.activate() using Mustache +# These are generated by solving +# Minimise X + Y + Z s.t. X*Y*Z=i*48 for X,Y,Z∈ℤ⁺ (See bottom) +mesh_partitions = [(4, 4, 3),(4, 4, 6),(4, 6, 6),(4, 6, 8),(5, 6, 8),(6, 6, 8),(7, 6, 8),(6, 8, 8),(6, 9, 8),(10, 6, 8), + (11, 6, 8),(9, 8, 8),(13, 6, 8),(12, 7, 8),(10, 9, 8),(12, 8, 8),(6, 8, 17),(12, 9, 8),(6, 8, 19), + (10, 12, 8),(14, 9, 8),(11, 12, 8),(6, 8, 23),(12, 12, 8),(10, 10, 12),(13, 12, 8),(12, 12, 9),(12, 14, 8), + (6, 8, 29),(10, 12, 12),(6, 8, 31),(8, 12, 16),(11, 12, 12),(8, 12, 17),(10, 12, 14),(12, 12, 12),(6, 8, 37), + (8, 12, 19),(13, 12, 12),(10, 12, 16),(6, 8, 41),(12, 12, 14),(6, 8, 43),(11, 12, 16),(12, 12, 15),(8, 12, 23), + (6, 8, 47),(12, 12, 16),(12, 14, 14),(10, 15, 16),(12, 12, 17),(12, 13, 16),(6, 8, 53),(12, 12, 18),(11, 15, 16), + (12, 14, 16),(12, 12, 19),(8, 12, 29),(6, 8, 59),(12, 15, 16),(6, 8, 61),(8, 12, 31),(12, 14, 18),(12, 16, 16), + (13, 15, 16),(11, 16, 18),(6, 8, 67),(12, 16, 17),(12, 12, 23),(14, 15, 16),(6, 8, 71),(12, 16, 18),(6, 8, 73), + (8, 12, 37),(15, 15, 16),(12, 16, 19),(11, 16, 21),(13, 16, 18),(6, 8, 79),(15, 16, 16),(12, 18, 18),(8, 12, 41), + (6, 8, 83),(14, 16, 18),(15, 16, 17),(8, 12, 43),(12, 12, 29),(12, 16, 22),(6, 8, 89),(15, 16, 18)] + +@assert Int.(prod.(mesh_partitions)/48) == collect(1:length(mesh_partitions)) + function generate( template, name, @@ -9,7 +24,7 @@ function generate( bmark_type, cputype, wallhr, - n_mesh_partition, + mesh_partition, n_el_size, fe_order, verbose, @@ -18,33 +33,34 @@ function generate( nreps ) - ncpus = n_mesh_partition^3 - wallhr = occursin("STRONG",name) && n_mesh_partition <= 3 ? 100 : wallhr - mem = occursin("STRONG",name) && n_mesh_partition == 1 ? 256 : - occursin("STRONG",name) && n_mesh_partition == 2 ? 32 : gb_per_cpu; + ncpus = prod(mesh_partition) + wallhr = occursin("STRONG",name) && ncpus <= 8 ? 100 : wallhr + mem = occursin("STRONG",name) && ncpus == 1 ? 100 : + occursin("STRONG",name) && ncpus == 8 ? 32 : Int(gb_per_node*ncpus/cps_per_node); + Nx_partition, Ny_partition, Nz_partition = mesh_partition settings = (;name,type,bmark_type,cputype,wallhr,ncpus,mem, - n_mesh_partition,n_el_size,fe_order,verbose,dir_name,write_dir,nreps) + Nx_partition,Ny_partition,Nz_partition,n_el_size,fe_order,verbose,dir_name,write_dir,nreps) Mustache.render(template, settings) end function generate_jobs(template,phys_type,ndof_per_node,bmark_types) - npart = (N).^3; + npart = prod.(parts) weak_el_x = @. floor(Int,(dofs_per_proc*npart/ndof_per_node)^(1/3)-1); dof_sanity_check = @.(floor(Int,ndof_per_node*(weak_el_x+1)^3/npart)), maximum(abs,@. ndof_per_node*(weak_el_x+1)^3/npart/dofs_per_proc - 1) - sname(phys_type,ndof_per_node,n,elx) = "STRONG_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" - wname(phys_type,ndof_per_node,n,elx) = "WEAK_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" + sname(phys_type,ndof_per_node,n,elx) = "STRONG_$(phys_type)_dof$(ndof_per_node)_N$(prod(n))_elx$(elx)" + wname(phys_type,ndof_per_node,n,elx) = "WEAK_$(phys_type)_dof$(ndof_per_node)_N$(prod(n))_elx$(elx)" strong_el_x = ceil(Int,(strong_dof/ndof_per_node)^(1/3)); strong_jobs = map(n->(sname(phys_type,ndof_per_node,n,strong_el_x), generate(template,sname(phys_type,ndof_per_node,n,strong_el_x),phys_type,bmark_types, - cputype,wallhr,n,strong_el_x,fe_order,verbose,dir_name,write_dir,nreps)),N) + cputype,wallhr,n,strong_el_x,fe_order,verbose,dir_name,write_dir,nreps)),parts) weak_jobs = map((n,elx)->(wname(phys_type,ndof_per_node,n,elx), generate(template,wname(phys_type,ndof_per_node,n,elx),phys_type,bmark_types, - cputype,wallhr,n,elx,fe_order,verbose,dir_name,write_dir,nreps)),N,weak_el_x) + cputype,wallhr,n,elx,fe_order,verbose,dir_name,write_dir,nreps)),parts,weak_el_x) strong_jobs,weak_jobs,dof_sanity_check end @@ -55,7 +71,8 @@ mkpath(job_output_path); # SETUP PARAMETERS cputype=""; # Not needed here -gb_per_cpu = 8 # GB +gb_per_node = 192 # GB +cps_per_node = 48 wallhr = 3 ; # Hours (Note may want to manually change some afterwards) nreps = 10; # Number of benchmark repetitions @@ -64,7 +81,7 @@ fe_order= 1; verbose= 1; write_dir = "\$SCRATCH/$dir_name/results/benchmarks/" -N = 1:10; # Number of partitions in x-axis +parts = [(1,1,1);(2,2,2);(3,3,3);mesh_partitions[1:3:22]] # Mesh partitions strong_dof=(100+1)^3*3; # Number of dofs for strong scaling # Phys type and number of dofs per node, and what to benchmark @@ -92,4 +109,9 @@ for jobs in jobs_by_phys write(f,content) end end -end \ No newline at end of file +end + +# Mathematica code: +# F[N_]:=Minimize[{X+Y+Z,X*Y*Z==N*48, X>0, Y>0, Z>0,X\[Element] Integers,Y\[Element] Integers,Z\[Element] Integers},{X,Y,Z}] +# For[i=1,i<=50,i++,X[i]=F[i]]; +# For[i=1,i<=90,i++,Print[{X[i][[2]][[1]][[2]],X[i][[2]][[2]][[2]],X[i][[2]][[3]][[2]]}]] \ No newline at end of file diff --git a/scripts/Benchmarks/jobtemplate_gadi.sh b/scripts/Benchmarks/jobtemplate_gadi.sh index 63dfe4d8..63ef1507 100644 --- a/scripts/Benchmarks/jobtemplate_gadi.sh +++ b/scripts/Benchmarks/jobtemplate_gadi.sh @@ -11,15 +11,15 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/{{:dir_name}}/ -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - mpirun -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 \ $PROJECT_DIR/scripts/Benchmarks/benchmark.jl \ {{:name}} \ {{{:write_dir}}} \ {{:type}} \ {{:bmark_type}} \ - {{:n_mesh_partition}} \ + {{:Nx_partition}} \ + {{:Ny_partition}} \ + {{:Nz_partition}} \ {{:n_el_size}} \ {{:fe_order}} \ {{:verbose}} \ From 4de04fc1f6ba8b55771d5ecbe8625448b0609f4a Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:21:21 +1000 Subject: [PATCH 69/90] Missing gadi --- scripts/Benchmarks/jobtemplate_gadi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Benchmarks/jobtemplate_gadi.sh b/scripts/Benchmarks/jobtemplate_gadi.sh index 63ef1507..5d41e56a 100644 --- a/scripts/Benchmarks/jobtemplate_gadi.sh +++ b/scripts/Benchmarks/jobtemplate_gadi.sh @@ -12,7 +12,7 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/{{:dir_name}}/ mpirun -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/Benchmarks/benchmark.jl \ + $PROJECT_DIR/scripts/Benchmarks/benchmark_gadi.jl \ {{:name}} \ {{{:write_dir}}} \ {{:type}} \ From c02c65692d5030cfdf6f798fc4fbd77e92f77456 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 26 Apr 2024 23:15:13 +1000 Subject: [PATCH 70/90] adjust script for gadi --- scripts/Benchmarks/generate_benchmark_scripts_gadi.jl | 5 ++++- scripts/Benchmarks/jobtemplate_gadi.sh | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl index 453ff8c0..a313cb83 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl @@ -81,7 +81,10 @@ fe_order= 1; verbose= 1; write_dir = "\$SCRATCH/$dir_name/results/benchmarks/" -parts = [(1,1,1);(2,2,2);(3,3,3);mesh_partitions[1:3:22]] # Mesh partitions +# parts = [(1,1,1);(2,2,2);(3,3,3);mesh_partitions[1:3:22]] # Mesh partitions +# parts = [(1,1,1);mesh_partitions[1:2:20]] +# parts = [(1,1,1);mesh_partitions[[1,2,3,4,5]];mesh_partitions[8:4:20]] +parts = [(1,1,1);mesh_partitions[[1,2,3,5]];mesh_partitions[8:5:23]] strong_dof=(100+1)^3*3; # Number of dofs for strong scaling # Phys type and number of dofs per node, and what to benchmark diff --git a/scripts/Benchmarks/jobtemplate_gadi.sh b/scripts/Benchmarks/jobtemplate_gadi.sh index 5d41e56a..4bee92f9 100644 --- a/scripts/Benchmarks/jobtemplate_gadi.sh +++ b/scripts/Benchmarks/jobtemplate_gadi.sh @@ -11,7 +11,7 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/{{:dir_name}}/ -mpirun -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 \ +mpiexec -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 \ $PROJECT_DIR/scripts/Benchmarks/benchmark_gadi.jl \ {{:name}} \ {{{:write_dir}}} \ From fce7613a53c3946b283629fc04e5b1ff208a3fff Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 27 Apr 2024 08:32:55 +1000 Subject: [PATCH 71/90] adjust for first two runs --- scripts/Benchmarks/generate_benchmark_scripts_gadi.jl | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl index a313cb83..469e1220 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl @@ -34,9 +34,9 @@ function generate( ) ncpus = prod(mesh_partition) - wallhr = occursin("STRONG",name) && ncpus <= 8 ? 100 : wallhr - mem = occursin("STRONG",name) && ncpus == 1 ? 100 : - occursin("STRONG",name) && ncpus == 8 ? 32 : Int(gb_per_node*ncpus/cps_per_node); + wallhr = occursin("STRONG",name) && ncpus == 1 ? 100 : + occursin("STRONG",name) && ncpus == 8 ? 24 : wallhr + mem = occursin("STRONG",name) && ncpus == 1 ? 100 : Int(gb_per_node*ncpus/cps_per_node); Nx_partition, Ny_partition, Nz_partition = mesh_partition settings = (;name,type,bmark_type,cputype,wallhr,ncpus,mem, @@ -81,10 +81,7 @@ fe_order= 1; verbose= 1; write_dir = "\$SCRATCH/$dir_name/results/benchmarks/" -# parts = [(1,1,1);(2,2,2);(3,3,3);mesh_partitions[1:3:22]] # Mesh partitions -# parts = [(1,1,1);mesh_partitions[1:2:20]] -# parts = [(1,1,1);mesh_partitions[[1,2,3,4,5]];mesh_partitions[8:4:20]] -parts = [(1,1,1);mesh_partitions[[1,2,3,5]];mesh_partitions[8:5:23]] +parts = [(2,2,2);(3,3,3);mesh_partitions[[1,2,3,5]];mesh_partitions[8:5:23]] strong_dof=(100+1)^3*3; # Number of dofs for strong scaling # Phys type and number of dofs per node, and what to benchmark From ba203403df533fd84d9f7bb9b5c1b07e06b6c160 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:14:09 +1000 Subject: [PATCH 72/90] add full TO scripts for gadi --- .../Benchmarks/generate_benchmark_scripts_gadi.jl | 7 +++++-- scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl | 2 +- .../_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl | 2 +- scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 2 +- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 2 +- .../Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs | 14 ++++++++++++++ .../jobs-gadi/hyperelast_comp_MPI_3D.pbs | 14 ++++++++++++++ .../Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs | 14 ++++++++++++++ .../Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs | 14 ++++++++++++++ .../Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs | 14 ++++++++++++++ scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl | 2 +- 11 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs create mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl index 469e1220..f142b86b 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl @@ -35,8 +35,11 @@ function generate( ncpus = prod(mesh_partition) wallhr = occursin("STRONG",name) && ncpus == 1 ? 100 : - occursin("STRONG",name) && ncpus == 8 ? 24 : wallhr - mem = occursin("STRONG",name) && ncpus == 1 ? 100 : Int(gb_per_node*ncpus/cps_per_node); + occursin("STRONG",name) && ncpus == 8 ? 24 : + occursin("STRONG",name) && ncpus == 27 ? 10 : wallhr + mem = occursin("STRONG",name) && ncpus == 1 ? 100 : + occursin("STRONG",name) && ncpus == 8 ? 128 : + occursin("STRONG",name) && ncpus == 27 ? 192 : Int(gb_per_node*ncpus/cps_per_node); Nx_partition, Ny_partition, Nz_partition = mesh_partition settings = (;name,type,bmark_type,cputype,wallhr,ncpus,mem, diff --git a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl index d177d1da..ec1cea4d 100644 --- a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl @@ -95,7 +95,7 @@ function main(mesh_partition,distribute) end with_mpi() do distribute - mesh_partition = (5,5,5) + mesh_partition = (4,6,6) solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl index 7e532243..45efaaaa 100644 --- a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl @@ -111,7 +111,7 @@ function main(mesh_partition,distribute) end with_mpi() do distribute - mesh_partition = (5,5,5) + mesh_partition = (4,6,6) solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl index af7c2735..efb3f3f9 100644 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -99,7 +99,7 @@ function main(mesh_partition,distribute) end with_mpi() do distribute - mesh_partition = (5,5,5) + mesh_partition = (4,6,6) solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index d1b3c677..a9e382e4 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -105,7 +105,7 @@ function main(mesh_partition,distribute) end with_mpi() do distribute - mesh_partition = (5,5,5) + mesh_partition = (4,6,6) solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs new file mode 100644 index 00000000..fda46ec2 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs @@ -0,0 +1,14 @@ +#!/bin/bash -l +#PBS -P np01 +#PBS -q normal +#PBS -N elast_comp_MPI_3D +#PBS -l ncpus=144 +#PBS -l mem=576GB +#PBS -l walltime=10:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-intel.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs new file mode 100644 index 00000000..73943486 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs @@ -0,0 +1,14 @@ +#!/bin/bash -l +#PBS -P np01 +#PBS -q normal +#PBS -N hyperelast_comp_MPI_3D +#PBS -l ncpus=144 +#PBS -l mem=576GB +#PBS -l walltime=10:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-intel.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs new file mode 100644 index 00000000..dd590bea --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs @@ -0,0 +1,14 @@ +#!/bin/bash -l +#PBS -P np01 +#PBS -q normal +#PBS -N inverse_hom_MPI_3D +#PBS -l ncpus=144 +#PBS -l mem=576GB +#PBS -l walltime=24:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-intel.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs new file mode 100644 index 00000000..1e04d719 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs @@ -0,0 +1,14 @@ +#!/bin/bash -l +#PBS -P np01 +#PBS -q normal +#PBS -N inverter_MPI_3D +#PBS -l ncpus=144 +#PBS -l mem=576GB +#PBS -l walltime=16:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-intel.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs new file mode 100644 index 00000000..72a28429 --- /dev/null +++ b/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs @@ -0,0 +1,14 @@ +#!/bin/bash -l +#PBS -P np01 +#PBS -q normal +#PBS -N therm_comp_MPI_3D +#PBS -l ncpus=144 +#PBS -l mem=576GB +#PBS -l walltime=16:00:00 +#PBS -j oe + +source $HOME/hpc-environments-main/lyra/load-intel.sh +PROJECT_DIR=$HOME/LevelSetTopOpt/ + +mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ + $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl index 5104e0d6..a9014711 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl @@ -97,7 +97,7 @@ function main(mesh_partition,distribute) end with_mpi() do distribute - mesh_partition = (5,5,5) + mesh_partition = (4,6,6) solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do From d69663108996805fa3cd9142338f18e1f7488147 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:17:06 +1000 Subject: [PATCH 73/90] oops --- scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs | 4 ++-- .../_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs | 4 ++-- scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs | 4 ++-- scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs | 4 ++-- scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs index fda46ec2..0d2dbc39 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs @@ -7,8 +7,8 @@ #PBS -l walltime=10:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ +source $HOME/hpc-environments/gadi/load-intel.sh +PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs index 73943486..978321a3 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs @@ -7,8 +7,8 @@ #PBS -l walltime=10:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ +source $HOME/hpc-environments/gadi/load-intel.sh +PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs index dd590bea..1ee191c2 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs @@ -7,8 +7,8 @@ #PBS -l walltime=24:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ +source $HOME/hpc-environments/gadi/load-intel.sh +PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs index 1e04d719..5db3bed6 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs @@ -7,8 +7,8 @@ #PBS -l walltime=16:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ +source $HOME/hpc-environments/gadi/load-intel.sh +PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs index 72a28429..7597a0a8 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs @@ -4,11 +4,11 @@ #PBS -N therm_comp_MPI_3D #PBS -l ncpus=144 #PBS -l mem=576GB -#PBS -l walltime=16:00:00 +#PBS -l walltime=3:00:00 #PBS -j oe -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ +source $HOME/hpc-environments/gadi/load-intel.sh +PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl From f49b9ee18c925ea8ceb3abc778deba3a43027402 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:54:21 +1000 Subject: [PATCH 74/90] Fix writing to scratch --- scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl | 7 ++++--- scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl | 7 ++++--- scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 7 ++++--- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 7 ++++--- scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs | 3 ++- .../Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs | 3 ++- .../_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs | 3 ++- scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs | 3 ++- scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs | 3 ++- scripts/_dev/Paper_scripts/therm_comp_MPI.jl | 7 ++++--- scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl | 7 ++++--- 11 files changed, 34 insertions(+), 23 deletions(-) diff --git a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl index ec1cea4d..f3e23201 100644 --- a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl @@ -1,7 +1,7 @@ using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, SparseMatricesCSR -function main(mesh_partition,distribute) +function main(mesh_partition,distribute,write_dir) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order @@ -24,7 +24,7 @@ function main(mesh_partition,distribute) vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/elast_comp_MPI_3D/" # Output path + path = "$write_dir/elast_comp_MPI_3D/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -96,9 +96,10 @@ end with_mpi() do distribute mesh_partition = (4,6,6) + write_dir = ARGS[1] solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute) + main(mesh_partition,distribute,write_dir) end end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl index 45efaaaa..d164c73d 100644 --- a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl @@ -3,7 +3,7 @@ using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, using GridapSolvers: NewtonSolver -function main(mesh_partition,distribute) +function main(mesh_partition,distribute,write_dir) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order @@ -28,7 +28,7 @@ function main(mesh_partition,distribute) vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/hyperelast_comp_MPI_3D/" # Output path + path = "$write_dir/hyperelast_comp_MPI_3D/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -112,9 +112,10 @@ end with_mpi() do distribute mesh_partition = (4,6,6) + write_dir = ARGS[1] solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute) + main(mesh_partition,distribute,write_dir) end end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl index efb3f3f9..0bab1470 100644 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -1,7 +1,7 @@ using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, SparseMatricesCSR -function main(mesh_partition,distribute) +function main(mesh_partition,distribute,write_dir) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order @@ -21,7 +21,7 @@ function main(mesh_partition,distribute) lsf_func(x) = cos(2π*x[1]) + cos(2π*x[2]) + # Initial level set function cos(2π*x[3]) iter_mod = 10 # VTK Output modulo - path = "./results/inverse_hom_MPI_3D/" # Output path + path = "$write_dir/inverse_hom_MPI_3D/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)); @@ -100,9 +100,10 @@ end with_mpi() do distribute mesh_partition = (4,6,6) + write_dir = ARGS[1] solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute) + main(mesh_partition,distribute,write_dir) end end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index a9e382e4..e22b4874 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -1,7 +1,7 @@ using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, SparseMatricesCSR -function main(mesh_partition,distribute) +function main(mesh_partition,distribute,write_dir) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order @@ -29,7 +29,7 @@ function main(mesh_partition,distribute) sphere(x,(1,0,0)),sphere(x,(1,0,1)),sphere(x,(1,1,0)),sphere(x,(1,1,1))) lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/inverter_MPI_3D/" # Output path + path = "$write_dir/inverter_MPI_3D/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -106,9 +106,10 @@ end with_mpi() do distribute mesh_partition = (4,6,6) + write_dir = ARGS[1] solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute) + main(mesh_partition,distribute,write_dir) end end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs index 0d2dbc39..9fb3b55b 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs @@ -11,4 +11,5 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl + $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl \ + $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs index 978321a3..f9b7897f 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs @@ -11,4 +11,5 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl + $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl \ + $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs index 1ee191c2..9cbe2ad9 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs @@ -11,4 +11,5 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl + $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl \ + $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs index 5db3bed6..d16868d7 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs @@ -11,4 +11,5 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl + $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl \ + $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs index 7597a0a8..d859dc27 100644 --- a/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs +++ b/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs @@ -11,4 +11,5 @@ source $HOME/hpc-environments/gadi/load-intel.sh PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl + $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl \ + $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl index 902742bf..a5476e50 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl @@ -1,7 +1,7 @@ using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, SparseMatricesCSR -function main(mesh_partition,distribute) +function main(mesh_partition,distribute,write_dir) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order @@ -25,7 +25,7 @@ function main(mesh_partition,distribute) vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/therm_comp_MPI/" # Output path + path = "$write_dir/results/therm_comp_MPI/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -95,9 +95,10 @@ end with_mpi() do distribute mesh_partition = (2,2) + write_dir = ARGS[1] solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute) + main(mesh_partition,distribute,write_dir) end end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl index a9014711..be63b8db 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl @@ -1,7 +1,7 @@ using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, SparseMatricesCSR -function main(mesh_partition,distribute) +function main(mesh_partition,distribute,write_dir) ranks = distribute(LinearIndices((prod(mesh_partition),))) # FE parameters order = 1 # Finite element order @@ -27,7 +27,7 @@ function main(mesh_partition,distribute) vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/therm_comp_MPI_3D/" # Output path + path = "$write_dir/therm_comp_MPI_3D/" # Output path i_am_main(ranks) && mkpath(path) # Create path # Model model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -98,9 +98,10 @@ end with_mpi() do distribute mesh_partition = (4,6,6) + write_dir = ARGS[1] solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute) + main(mesh_partition,distribute,write_dir) end end \ No newline at end of file From e80369c39f78dabce1e4ba0fb30eddffd7450877 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:06:41 +1000 Subject: [PATCH 75/90] bug fixes --- scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 4 ++-- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl index 0bab1470..1d7c2425 100644 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -68,8 +68,8 @@ function main(mesh_partition,distribute,write_dir) dκ(q,u,φ,dΩ) = -1/9*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+dCᴴ(3,3,q,u,φ,dΩ)+ 2*(dCᴴ(1,2,q,u,φ,dΩ)+dCᴴ(1,3,q,u,φ,dΩ)+dCᴴ(2,3,q,u,φ,dΩ))) vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + C1(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dC1(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ pcfs = PDEConstrainedFunctionals(κ,[C1],state_map, analytic_dJ=dκ,analytic_dC=[dC1]) # Velocity extension diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index e22b4874..dd8117bd 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -23,6 +23,7 @@ function main(mesh_partition,distribute,write_dir) C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor g = VectorValue(0,0,-1) # Applied load on Γ_N ks = 0.01 # Artificial spring stiffness + δₓ = 0.5 # Required displacement vf = 0.4 # Volume fraction constraint sphere(x,(xc,yc,zc)) = -sqrt((x[1]-xc)^2+(x[2]-yc)^2+(x[3]-zc)^2) + 0.2 lsf_func(x) = max(initial_lsf(4,0.2)(x), # Initial level set function From d6b06514885190390d37d44c152ac10b849a8715 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 27 Apr 2024 16:14:58 +1000 Subject: [PATCH 76/90] loaded messed up --- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index dd8117bd..c52e206c 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -21,7 +21,7 @@ function main(mesh_partition,distribute,write_dir) tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor - g = VectorValue(0,0,-1) # Applied load on Γ_N + g = VectorValue(1,0,0) # Applied load on Γ_N ks = 0.01 # Artificial spring stiffness δₓ = 0.5 # Required displacement vf = 0.4 # Volume fraction constraint From b3b3781a5b56caad82ea56e36fb9be9c8ba67ef0 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 27 Apr 2024 22:23:46 +1000 Subject: [PATCH 77/90] Inverter now includes Gamma_out_ext --- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index c52e206c..ab2e1faa 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -12,6 +12,9 @@ function main(mesh_partition,distribute,write_dir) (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) f_Γ_out(x) = (x[1] ≈ 1.0) && # Γ_out indicator function (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) + f_Γ_out_ext(x) = ~f_Γ_out(x) && # Γ_out_ext indicator function + (0.95 <= x[1] <= 1.0) && (0.35 - eps() <= x[2] <= 0.65 + eps()) && + (0.35 - eps() <= x[3] <= 0.65 + eps()) f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) # FD parameters @@ -21,9 +24,9 @@ function main(mesh_partition,distribute,write_dir) tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor - g = VectorValue(1,0,0) # Applied load on Γ_N + g = VectorValue(1,0,0) # Applied load on Γ_N ks = 0.01 # Artificial spring stiffness - δₓ = 0.5 # Required displacement + δₓ = 0.25 # Required displacement vf = 0.4 # Volume fraction constraint sphere(x,(xc,yc,zc)) = -sqrt((x[1]-xc)^2+(x[2]-yc)^2+(x[3]-zc)^2) + 0.2 lsf_func(x) = max(initial_lsf(4,0.2)(x), # Initial level set function @@ -36,6 +39,7 @@ function main(mesh_partition,distribute,write_dir) model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); update_labels!(1,model,f_Γ_in,"Gamma_in") update_labels!(2,model,f_Γ_out,"Gamma_out") + update_labels!(3,model,f_Γ_out_ext,"Gamma_out_ext") update_labels!(4,model,f_Γ_D,"Gamma_D") # Triangulation and measures Ω = Triangulation(model) @@ -50,7 +54,8 @@ function main(mesh_partition,distribute,write_dir) V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_in","Gamma_out"]) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=[ + "Gamma_in","Gamma_out","Gamma_out_ext"]) U_reg = TrialFESpace(V_reg,0) # Level set and interpolator φh = interpolate(lsf_func,V_φ); From 103465bc436fb499b3406ce5142598901edaf9e9 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sun, 28 Apr 2024 15:28:02 +1000 Subject: [PATCH 78/90] inverter results done --- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl index ab2e1faa..5ecde638 100644 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl @@ -13,7 +13,7 @@ function main(mesh_partition,distribute,write_dir) f_Γ_out(x) = (x[1] ≈ 1.0) && # Γ_out indicator function (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) f_Γ_out_ext(x) = ~f_Γ_out(x) && # Γ_out_ext indicator function - (0.95 <= x[1] <= 1.0) && (0.35 - eps() <= x[2] <= 0.65 + eps()) && + (0.9 <= x[1] <= 1.0) && (0.35 - eps() <= x[2] <= 0.65 + eps()) && (0.35 - eps() <= x[3] <= 0.65 + eps()) f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) @@ -26,12 +26,11 @@ function main(mesh_partition,distribute,write_dir) C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor g = VectorValue(1,0,0) # Applied load on Γ_N ks = 0.01 # Artificial spring stiffness - δₓ = 0.25 # Required displacement + δₓ = 0.4 # Required displacement vf = 0.4 # Volume fraction constraint sphere(x,(xc,yc,zc)) = -sqrt((x[1]-xc)^2+(x[2]-yc)^2+(x[3]-zc)^2) + 0.2 lsf_func(x) = max(initial_lsf(4,0.2)(x), # Initial level set function sphere(x,(1,0,0)),sphere(x,(1,0,1)),sphere(x,(1,1,0)),sphere(x,(1,1,1))) - lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo path = "$write_dir/inverter_MPI_3D/" # Output path i_am_main(ranks) && mkpath(path) # Create path From 710e1260220b36bc85d32a83775cb7774572ad19 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 29 Apr 2024 14:45:56 +1000 Subject: [PATCH 79/90] minor script change for paper --- scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl index 1d7c2425..83175010 100644 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl @@ -16,7 +16,6 @@ function main(mesh_partition,distribute,write_dir) tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance # Problem parameters C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor - g = VectorValue(0,0,-1) # Applied load on Γ_N vf = 0.4 # Volume fraction constraint lsf_func(x) = cos(2π*x[1]) + cos(2π*x[2]) + # Initial level set function cos(2π*x[3]) From 637c22852d4504b6f16ddcb71b03adb7248a23f6 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 29 Apr 2024 16:15:23 +1000 Subject: [PATCH 80/90] minor update to serial script for paper --- scripts/_dev/Paper_scripts/therm_comp_serial.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/_dev/Paper_scripts/therm_comp_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl index efd90e5f..69fc7d73 100644 --- a/scripts/_dev/Paper_scripts/therm_comp_serial.jl +++ b/scripts/_dev/Paper_scripts/therm_comp_serial.jl @@ -1,6 +1,6 @@ using LevelSetTopOpt, Gridap -function main() +function main(write_dir) # FE parameters order = 1 # Finite element order xmax,ymax = (1.0,1.0) # Domain size @@ -23,7 +23,7 @@ function main() vf = 0.4 # Volume fraction constraint lsf_func = initial_lsf(4,0.2) # Initial level set function iter_mod = 10 # VTK Output modulo - path = "./results/therm_comp_serial/" # Output path + path = "$write_dir/therm_comp_serial/" # Output path mkpath(path) # Create path # Model model = CartesianDiscreteModel(dom,el_size); @@ -79,4 +79,4 @@ function main() "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end -main() \ No newline at end of file +main("results/") \ No newline at end of file From 357e02280a18f7c63ee14cbba5cf28f5c3c377b6 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Tue, 30 Apr 2024 08:12:09 +1000 Subject: [PATCH 81/90] Added some serial tests + bug fix in ChainRules --- scripts/MPI/3d_thermal_compliance_ALM.jl | 2 +- src/ChainRules.jl | 6 +- src/LevelSetTopOpt.jl | 4 +- test/seq/InverseHomogenisationALMTests.jl | 103 ++++++++++++++++ test/seq/InverterHPMTests.jl | 114 ++++++++++++++++++ .../seq/NonlinearThermalComplianceALMTests.jl | 101 ++++++++++++++++ test/seq/ThermalComplianceALMTests.jl | 112 +++++++++++++++-- test/seq/runtests.jl | 3 + 8 files changed, 433 insertions(+), 12 deletions(-) create mode 100644 test/seq/InverseHomogenisationALMTests.jl create mode 100644 test/seq/InverterHPMTests.jl create mode 100644 test/seq/NonlinearThermalComplianceALMTests.jl diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index 2c63d3e0..ce4849db 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -29,7 +29,7 @@ function main(mesh_partition,distribute,el_size) dom = (0,xmax,0,ymax,0,zmax) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,order*minimum(el_size)/step) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(coef*order^2)/minimum(el_size) κ = 1 η_coeff = 2 diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 398f74db..1a2a5f49 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -65,13 +65,15 @@ Gridap.gradient(F::IntegrandWithMeasure,uh) = Gridap.gradient(F,[uh],1) Given an an `IntegrandWithMeasure` `F` and a vector of `FEFunctions` or `CellField` `uh` (excluding measures) evaluate the Jacobian `F.F` with respect to `uh[K]`. """ -function Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector{<:FEFunction},K::Int) +function Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector{<:Union{FEFunction,CellField}},K::Int) @check 0 < K <= length(uh) _f(uk) = F.F(uh[1:K-1]...,uk,uh[K+1:end]...,F.dΩ...) return Gridap.jacobian(_f,uh[K]) end -function Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector,K::Int) +DistributedFields = Union{DistributedCellField,DistributedMultiFieldCellField} + +function Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector{<:DistributedFields},K::Int) @check 0 < K <= length(uh) local_fields = map(local_views,uh) |> to_parray_of_arrays local_measures = map(local_views,F.dΩ) |> to_parray_of_arrays diff --git a/src/LevelSetTopOpt.jl b/src/LevelSetTopOpt.jl index 52d28514..43f948f7 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/LevelSetTopOpt.jl @@ -21,8 +21,8 @@ using Gridap: writevtk using GridapDistributed using GridapDistributed: DistributedDiscreteModel, DistributedTriangulation, DistributedFESpace, DistributedDomainContribution, to_parray_of_arrays, - allocate_in_domain, DistributedCellField, DistributedMultiFieldFEBasis, - BlockPMatrix, BlockPVector, change_ghost + allocate_in_domain, DistributedCellField, DistributedMultiFieldCellField, + DistributedMultiFieldFEBasis, BlockPMatrix, BlockPVector, change_ghost using PartitionedArrays using PartitionedArrays: getany, tuple_of_arrays, matching_ghost_indices diff --git a/test/seq/InverseHomogenisationALMTests.jl b/test/seq/InverseHomogenisationALMTests.jl new file mode 100644 index 00000000..82929b7d --- /dev/null +++ b/test/seq/InverseHomogenisationALMTests.jl @@ -0,0 +1,103 @@ +module InverseHomogenisationALMTests +using Test + +using Gridap, LevelSetTopOpt + +""" + (Serial) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 2D. + + Optimisation problem: + Min J(Ω) = -κ(Ω) + Ω + s.t., Vol(Ω) = vf, + ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, + ⎣∫ ∑ᵢ C ⊙ ε(uᵢ) ⊙ ε(vᵢ) dΩ = ∫ -∑ᵢ C ⊙ ε⁰ᵢ ⊙ ε(vᵢ) dΩ, ∀v∈V. +""" +function main(;AD) + ## Parameters + order = 1 + xmax,ymax=(1.0,1.0) + dom = (0,xmax,0,ymax) + el_size = (20,20) + γ = 0.05 + γ_reinit = 0.5 + max_steps = floor(Int,order*minimum(el_size)/10) + tol = 1/(5order^2)/minimum(el_size) + C = isotropic_elast_tensor(2,1.,0.3) + η_coeff = 2 + α_coeff = 4max_steps*γ + vf = 0.5 + + ## FE Setup + model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)) + el_Δ = get_el_Δ(model) + f_Γ_D(x) = iszero(x) + update_labels!(1,model,f_Γ_D,"origin") + + ## Triangulations and measures + Ω = Triangulation(model) + dΩ = Measure(Ω,2*order) + vol_D = sum(∫(1)dΩ) + + ## Spaces + reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["origin"]) + U = TrialFESpace(V,VectorValue(0.0,0.0)) + V_reg = V_φ = TestFESpace(model,reffe_scalar) + U_reg = TrialFESpace(V_reg) + + ## Create FE functions + lsf_fn = x->max(initial_lsf(2,0.4)(x),initial_lsf(2,0.4;b=VectorValue(0,0.5))(x)) + φh = interpolate(lsf_fn,V_φ) + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + εᴹ = (TensorValue(1.,0.,0.,0.), # ϵᵢⱼ⁽¹¹⁾≡ϵᵢⱼ⁽¹⁾ + TensorValue(0.,0.,0.,1.), # ϵᵢⱼ⁽²²⁾≡ϵᵢⱼ⁽²⁾ + TensorValue(0.,1/2,1/2,0.)) # ϵᵢⱼ⁽¹²⁾≡ϵᵢⱼ⁽³⁾ + + a(u,v,φ,dΩ) = ∫((I ∘ φ) * C ⊙ ε(u) ⊙ ε(v) )dΩ + l = [(v,φ,dΩ) -> ∫(-(I ∘ φ)* C ⊙ εᴹ[i] ⊙ ε(v))dΩ for i in 1:3] + + ## Optimisation functionals + Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ + dCᴴ(r,s,q,u,φ,dΩ) = ∫(-q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + κ(u,φ,dΩ) = -1/4*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+2*Cᴴ(1,2,u,φ,dΩ)) + dκ(q,u,φ,dΩ) = -1/4*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+2*dCᴴ(1,2,q,u,φ,dΩ)) + Vol(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dVol(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + + ## Finite difference solver and level set function + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + + ## Setup solver and FE operators + state_map = RepeatingAffineFEStateMap(3,a,l,U,V,V_φ,U_reg,φh,dΩ) + pcfs = if AD + PDEConstrainedFunctionals(κ,[Vol],state_map;analytic_dJ=dκ,analytic_dC=[dVol]) + else + PDEConstrainedFunctionals(κ,[Vol],state_map) + end + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + + ## Optimiser + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; + γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + + # Do a few iterations + vars, state = iterate(optimiser) + vars, state = iterate(optimiser,state) + true +end + +# Test that these run successfully +@test main(;AD=true) +@test main(;AD=false) + +end # module \ No newline at end of file diff --git a/test/seq/InverterHPMTests.jl b/test/seq/InverterHPMTests.jl new file mode 100644 index 00000000..ce94a389 --- /dev/null +++ b/test/seq/InverterHPMTests.jl @@ -0,0 +1,114 @@ +module InverterHPMTests +using Test + +using Gridap, LevelSetTopOpt + +""" + (Serial) Inverter mechanism with Hilbertian projection method in 2D. + + Optimisation problem: + Min J(Ω) = ηᵢₙ*∫ u⋅e₁ dΓᵢₙ/Vol(Γᵢₙ) + Ω + s.t., Vol(Ω) = vf, + C(Ω) = 0, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. + + where C(Ω) = ∫ -u⋅e₁-δₓ dΓₒᵤₜ/Vol(Γₒᵤₜ). We assume symmetry in the problem to aid + convergence. +""" +function main() + ## Parameters + order = 1 + dom = (0,1,0,0.5) + el_size = (20,20) + γ = 0.1 + γ_reinit = 0.5 + max_steps = floor(Int,order*minimum(el_size)/10) + tol = 1/(5order^2)/minimum(el_size) + C = isotropic_elast_tensor(2,1.0,0.3) + η_coeff = 2 + α_coeff = 4max_steps*γ + vf = 0.4 + δₓ = 0.2 + ks = 0.1 + g = VectorValue(0.5,0) + + ## FE Setup + model = CartesianDiscreteModel(dom,el_size) + el_Δ = get_el_Δ(model) + f_Γ_in(x) = (x[1] ≈ 0.0) && (x[2] <= 0.03 + eps()) + f_Γ_out(x) = (x[1] ≈ 1.0) && (x[2] <= 0.07 + eps()) + f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] >= 0.4) + f_Γ_D2(x) = (x[2] ≈ 0.0) + update_labels!(1,model,f_Γ_in,"Gamma_in") + update_labels!(2,model,f_Γ_out,"Gamma_out") + update_labels!(3,model,f_Γ_D,"Gamma_D") + update_labels!(4,model,f_Γ_D2,"SymLine") + + ## Triangulations and measures + Ω = Triangulation(model) + Γ_in = BoundaryTriangulation(model,tags="Gamma_in") + Γ_out = BoundaryTriangulation(model,tags="Gamma_out") + dΩ = Measure(Ω,2order) + dΓ_in = Measure(Γ_in,2order) + dΓ_out = Measure(Γ_out,2order) + vol_D = sum(∫(1)dΩ) + vol_Γ_in = sum(∫(1)dΓ_in) + vol_Γ_out = sum(∫(1)dΓ_out) + + ## Spaces + reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D","SymLine"], + dirichlet_masks=[(true,true),(false,true)]) + U = TrialFESpace(V,[VectorValue(0.0,0.0),VectorValue(0.0,0.0)]) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_in","Gamma_out"]) + U_reg = TrialFESpace(V_reg,[0,0]) + + ## Create FE functions + lsf_fn(x) = min(max(initial_lsf(6,0.2)(x),-sqrt((x[1]-1)^2+(x[2]-0.5)^2)+0.2), + sqrt((x[1])^2+(x[2]-0.5)^2)-0.1) + φh = interpolate(lsf_fn,V_φ) + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + a(u,v,φ,dΩ,dΓ_in,dΓ_out) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + ∫(ks*(u⋅v))dΓ_out + l(v,φ,dΩ,dΓ_in,dΓ_out) = ∫(v⋅g)dΓ_in + + ## Optimisation functionals + e₁ = VectorValue(1,0) + J(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅e₁)/vol_Γ_in)dΓ_in + Vol(u,φ,dΩ,dΓ_in,dΓ_out) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ + dVol(q,u,φ,dΩ,dΓ_in,dΓ_out) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out + + ## Finite difference solver and level set function + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + + ## Setup solver and FE operators + state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out) + pcfs = PDEConstrainedFunctionals(J,[Vol,UΓ_out],state_map,analytic_dC=[dVol,nothing]) + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + + ## Optimiser + optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh; + γ,γ_reinit,verbose=true,debug=true,constraint_names=[:Vol,:UΓ_out]) + + # Do a few iterations + vars, state = iterate(optimiser) + vars, state = iterate(optimiser,state) + true +end + +# Test that these run successfully +@test main() + +end # module \ No newline at end of file diff --git a/test/seq/NonlinearThermalComplianceALMTests.jl b/test/seq/NonlinearThermalComplianceALMTests.jl new file mode 100644 index 00000000..c624d997 --- /dev/null +++ b/test/seq/NonlinearThermalComplianceALMTests.jl @@ -0,0 +1,101 @@ +module NonlinearThermalComplianceALMTests +using Test + +using Gridap, LevelSetTopOpt + +""" + (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D with nonlinear diffusivity. + + Optimisation problem: + Min J(Ω) = ∫ κ(u)*∇(u)⋅∇(u) dΩ + Ω + s.t., Vol(Ω) = vf, + ⎡u∈V=H¹(Ω;u(Γ_D)=0), + ⎣∫ κ(u)*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. + + In this example κ(u) = κ0*(exp(ξ*u)) +""" +function main() + ## Parameters + order = 1 + xmax=ymax=1.0 + prop_Γ_N = 0.2 + prop_Γ_D = 0.2 + dom = (0,xmax,0,ymax) + el_size = (20,20) + γ = 0.1 + γ_reinit = 0.5 + max_steps = floor(Int,order*minimum(el_size)/10) + tol = 1/(5order^2)/minimum(el_size) + η_coeff = 2 + α_coeff = 4max_steps*γ + vf = 0.4 + + ## FE Setup + model = CartesianDiscreteModel(dom,el_size); + el_Δ = get_el_Δ(model) + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + x[2] >= ymax-ymax*prop_Γ_D - eps())); + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + ymax/2+ymax*prop_Γ_N/2 + eps()); + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + + ## Triangulations and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + vol_D = sum(∫(1)dΩ) + + ## Spaces + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,0.0) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + + ## Create FE functions + φh = interpolate(initial_lsf(4,0.2),V_φ) + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + κ0 = 1 + ξ = -1 + κ(u) = κ0*(exp(ξ*u)) + res(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(v))dΩ - ∫(v)dΓ_N + + ## Optimisation functionals + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(u))dΩ + Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; + dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + + ## Finite difference solver and level set function + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + + ## Setup solver and FE operators + state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) + pcfs = PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dC=[dVol]) + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + + ## Optimiser + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; + γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + + # Do a few iterations + vars, state = iterate(optimiser) + vars, state = iterate(optimiser,state) + true +end + +# Test that these run successfully +@test main() + +end # module \ No newline at end of file diff --git a/test/seq/ThermalComplianceALMTests.jl b/test/seq/ThermalComplianceALMTests.jl index a5891838..c96225f8 100644 --- a/test/seq/ThermalComplianceALMTests.jl +++ b/test/seq/ThermalComplianceALMTests.jl @@ -1,4 +1,5 @@ module ThermalComplianceALMTests +using Test using Gridap, LevelSetTopOpt @@ -12,22 +13,21 @@ using Gridap, LevelSetTopOpt ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. """ -function main() - ## Parameters| - order = 1 - xmax=ymax=1.0 +function main(;order,AD) + ## Parameters + xmax = ymax = 1.0 prop_Γ_N = 0.2 prop_Γ_D = 0.2 dom = (0,xmax,0,ymax) el_size = (20,20) γ = 0.1 γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) + max_steps = floor(Int,order*minimum(el_size)/10) tol = 1/(5*order^2)/minimum(el_size) κ = 1 vf = 0.4 η_coeff = 2 - α_coeff = 4 + α_coeff = 4max_steps*γ ## FE Setup model = CartesianDiscreteModel(dom,el_size); @@ -73,6 +73,99 @@ function main() ## Finite difference solver and level set function ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + ## Setup solver and FE operators + state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) + pcfs = if AD + PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dJ=dJ,analytic_dC=[dVol]) + else + PDEConstrainedFunctionals(J,[Vol],state_map) + end + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + + ## Optimiser + optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; + γ,γ_reinit,verbose=true,constraint_names=[:Vol]) + + # Do a few iterations + vars, state = iterate(optimiser) + vars, state = iterate(optimiser,state) + true +end + +""" + (Serial) Minimum thermal compliance with augmented Lagrangian method in 3D. + + Optimisation problem: + Min J(Ω) = ∫ κ*∇(u)⋅∇(u) dΩ + Ω + s.t., Vol(Ω) = vf, + ⎡u∈V=H¹(Ω;u(Γ_D)=0), + ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. +""" +function main_3d(;order) + ## Parameters + xmax = ymax = zmax = 1.0 + prop_Γ_N = 0.2 + prop_Γ_D = 0.2 + dom = (0,xmax,0,ymax,0,zmax) + el_size = (20,20,20) + γ = 0.1 + γ_reinit = 0.5 + max_steps = floor(Int,order*minimum(el_size)/10) + tol = 1/(5*order^2)/minimum(el_size) + κ = 1 + vf = 0.4 + η_coeff = 2 + α_coeff = 4max_steps*γ + + ## FE Setup + model = CartesianDiscreteModel(dom,el_size); + el_Δ = get_el_Δ(model) + f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && + (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) + f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && + (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) + update_labels!(1,model,f_Γ_D,"Gamma_D") + update_labels!(2,model,f_Γ_N,"Gamma_N") + + ## Triangulations and measures + Ω = Triangulation(model) + Γ_N = BoundaryTriangulation(model,tags="Gamma_N") + dΩ = Measure(Ω,2*order) + dΓ_N = Measure(Γ_N,2*order) + vol_D = sum(∫(1)dΩ) + + ## Spaces + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) + U = TrialFESpace(V,0.0) + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) + U_reg = TrialFESpace(V_reg,0) + + ## Create FE functions + φh = interpolate(initial_lsf(4,0.2),V_φ) + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ + l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N + + ## Optimisation functionals + J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ + dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; + Vol(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; + dVol(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + + ## Finite difference solver and level set function + ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) + ## Setup solver and FE operators state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) pcfs = PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dJ=dJ,analytic_dC=[dVol]) @@ -89,8 +182,13 @@ function main() # Do a few iterations vars, state = iterate(optimiser) vars, state = iterate(optimiser,state) + true end -main() +# Test that these run successfully +@test main(;order=1,AD=true) +@test main(;order=2,AD=true) +@test main(;order=1,AD=false) +@test main_3d(;order=1) end # module \ No newline at end of file diff --git a/test/seq/runtests.jl b/test/seq/runtests.jl index 92ccacfa..20fd54e7 100644 --- a/test/seq/runtests.jl +++ b/test/seq/runtests.jl @@ -3,5 +3,8 @@ module LSTOSequentialTests using Test @time @testset "Thermal Compliance - ALM" begin include("ThermalComplianceALMTests.jl") end +@time @testset "Nonlinear Thermal Compliance - ALM" begin include("NonLinearThermalComplianceALMTests.jl") end +@time @testset "Inverse Homogenisation - ALM" begin include("InverseHomogenisationALMTests.jl") end +@time @testset "Inverter - HPM" begin include("InverterHPMTests.jl") end end # module \ No newline at end of file From e93e121eb23e773fb019bf4c3b08d4ec788024db Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Tue, 30 Apr 2024 08:33:00 +1000 Subject: [PATCH 82/90] Add PZMultiFieldRepeatingState Tests --- test/seq/PZMultiFieldRepeatingStateTests.jl | 191 ++++++++++++++++++++ test/seq/runtests.jl | 1 + 2 files changed, 192 insertions(+) create mode 100644 test/seq/PZMultiFieldRepeatingStateTests.jl diff --git a/test/seq/PZMultiFieldRepeatingStateTests.jl b/test/seq/PZMultiFieldRepeatingStateTests.jl new file mode 100644 index 00000000..827f9c91 --- /dev/null +++ b/test/seq/PZMultiFieldRepeatingStateTests.jl @@ -0,0 +1,191 @@ +module PZMultiFieldRepeatingStateTests +using Test + +using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, + PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + +using Gridap.TensorValues, Gridap.Helpers + +## Parameters +function main(;AD) + el_size = (20,20) + order = 1 + xmax,ymax=(1.0,1.0) + dom = (0,xmax,0,ymax) + γ = 0.1 + γ_reinit = 0.5 + max_steps = floor(Int,order*minimum(el_size)/10) + tol = 1/(5order^2)/minimum(el_size) + η_coeff = 2 + α_coeff = 4*max_steps*γ + vf = 0.5 + + ## FE Setup + model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)) + el_Δ = get_el_Δ(model) + f_Γ_D(x) = iszero(x) + update_labels!(1,model,f_Γ_D,"origin") + + ## Triangulations and measures + Ω = Triangulation(model) + dΩ = Measure(Ω,2*order) + vol_D = sum(∫(1)dΩ) + + ## Spaces + reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) + reffe_scalar = ReferenceFE(lagrangian,Float64,order) + V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) + U = TrialFESpace(V,VectorValue(0.0,0.0)) + Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) + P = TrialFESpace(Q,0) + UP = MultiFieldFESpace([U,P]) + VQ = MultiFieldFESpace([V,Q]) + + V_φ = TestFESpace(model,reffe_scalar) + V_reg = TestFESpace(model,reffe_scalar) + U_reg = TrialFESpace(V_reg) + + ## Create FE functions + φh = interpolate(initial_lsf(2,0.2),V_φ) + + ## Interpolation and weak form + interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ),ϵ=10^-9) + I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ + + ## Material tensors + C, e, κ = PZT5A_2D(); + k0 = norm(C.data,Inf); + α0 = norm(e.data,Inf); + β0 = norm(κ.data,Inf); + γ0 = β0*k0/α0^2; + + ## Weak forms + εᴹ = (SymTensorValue(1.0,0.0,0.0), + SymTensorValue(0.0,0.0,1.0), + SymTensorValue(0.0,1/2,0)) + Eⁱ = (VectorValue(1.0,0.0,), + VectorValue(0.0,1.0)) + + a((u,ϕ),(v,q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - + 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + + -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + + -γ0/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q))) )dΩ; + + l_ε = [((v,q),φ,dΩ) -> ∫(((I ∘ φ) * (-C ⊙ εᴹ[i] ⊙ ε(v) + k0/α0*(e ⋅² εᴹ[i]) ⋅ -∇(q))))dΩ for i = 1:3]; + l_E = [((v,q),φ,dΩ) -> ∫((I ∘ φ) * ((Eⁱ[i] ⋅ e ⊙ ε(v) + k0/α0*(κ ⋅ Eⁱ[i]) ⋅ -∇(q))))dΩ for i = 1:2]; + l = [l_ε; l_E] + + function Cᴴ(r,s,uϕ,φ,dΩ) + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(1/k0 * (I ∘ φ) * (((C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ εᴹ[r]) - ((-1/α0*∇(ϕ_s) ⋅ e) ⊙ εᴹ[r])))dΩ; + end + + function DCᴴ(r,s,q,uϕ,φ,dΩ) + u_r = uϕ[2r-1]; ϕ_r = uϕ[2r] + u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] + ∫(- 1/k0 * q * ( + (C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - + (-1/α0*∇(ϕ_s) ⋅ e) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - + (e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ (-1/α0*∇(ϕ_r)) - + (κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ (-1/α0*∇(ϕ_r)) + ) * (DH ∘ φ) * (norm ∘ ∇(φ)) + )dΩ; + end + + Bᴴ(uϕ,φ,dΩ) = 1/4*(Cᴴ(1,1,uϕ,φ,dΩ)+Cᴴ(2,2,uϕ,φ,dΩ)+2*Cᴴ(1,2,uϕ,φ,dΩ)) + DBᴴ(q,uϕ,φ,dΩ) = 1/4*(DCᴴ(1,1,q,uϕ,φ,dΩ)+DCᴴ(2,2,q,uϕ,φ,dΩ)+2*DCᴴ(1,2,q,uϕ,φ,dΩ)) + + J(uϕ,φ,dΩ) = -1*Bᴴ(uϕ,φ,dΩ) + DJ(q,uϕ,φ,dΩ) = -1*DBᴴ(q,uϕ,φ,dΩ) + C1(uϕ,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; + DC1(q,uϕ,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ + + ## Finite difference solver and level set function + stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) + + ## Setup solver and FE operators + state_map = RepeatingAffineFEStateMap(5,a,l,UP,VQ,V_φ,U_reg,φh,dΩ) + pcfs = if AD + PDEConstrainedFunctionals(J,[C1],state_map;analytic_dJ=DJ,analytic_dC=[DC1]) + else + PDEConstrainedFunctionals(J,[C1],state_map) + end + + ## Hilbertian extension-regularisation problems + α = α_coeff*maximum(el_Δ) + a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; + vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) + + # ## Optimiser + optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=true) + vars, state = iterate(optimiser) + vars, state = iterate(optimiser,state) + true +end + +function PZT5A_2D() + ε_0 = 8.854e-12; + C_Voigt = [12.0400e10 7.51000e10 0.0 + 7.51000e10 11.0900e10 0.0 + 0.0 0.0 2.1000e10] + e_Voigt = [0.0 0.0 12.30000 + -5.40000 15.80000 0.0] + K_Voigt = [540*ε_0 0 + 0 830*ε_0] + C = voigt2tensor4(C_Voigt) + e = voigt2tensor3(e_Voigt) + κ = voigt2tensor2(K_Voigt) + C,e,κ +end + +""" + Given a material constant given in Voigt notation, + return a SymFourthOrderTensorValue using ordering from Gridap +""" +function voigt2tensor4(A::Array{M,2}) where M + if isequal(size(A),(3,3)) + return SymFourthOrderTensorValue(A[1,1], A[3,1], A[2,1], + A[1,3], A[3,3], A[2,3], + A[1,2], A[3,2], A[2,2]) + elseif isequal(size(A),(6,6)) + return SymFourthOrderTensorValue(A[1,1], A[6,1], A[5,1], A[2,1], A[4,1], A[3,1], + A[1,6], A[6,6], A[5,6], A[2,6], A[4,6], A[3,6], + A[1,5], A[6,5], A[5,5], A[2,5], A[4,5], A[3,5], + A[1,2], A[6,2], A[5,2], A[2,2], A[4,2], A[3,2], + A[1,4], A[6,4], A[5,4], A[2,4], A[4,4], A[3,4], + A[1,3], A[6,3], A[5,3], A[2,3], A[4,3], A[3,3]) + else + @notimplemented + end +end + +""" + Given a material constant given in Voigt notation, + return a ThirdOrderTensorValue using ordering from Gridap +""" +function voigt2tensor3(A::Array{M,2}) where M + if isequal(size(A),(2,3)) + return ThirdOrderTensorValue(A[1,1], A[2,1], A[1,3], A[2,3], A[1,3], A[2,3], A[1,2], A[2,2]) + elseif isequal(size(A),(3,6)) + return ThirdOrderTensorValue( + A[1,1], A[2,1], A[3,1], A[1,6], A[2,6], A[3,6], A[1,5], A[2,5], A[3,5], + A[1,6], A[2,6], A[3,6], A[1,2], A[2,2], A[3,2], A[1,4], A[2,4], A[3,4], + A[1,5], A[2,5], A[3,5], A[1,4], A[2,4], A[3,4], A[1,3], A[2,3], A[3,3]) + else + @notimplemented + end +end + +""" + Given a material constant given in Voigt notation, + return a SymTensorValue using ordering from Gridap +""" +function voigt2tensor2(A::Array{M,2}) where M + return TensorValue(A) +end + +# Test that these run successfully +@test main(;AD=true) +@test main(;AD=false) + +end # module \ No newline at end of file diff --git a/test/seq/runtests.jl b/test/seq/runtests.jl index 20fd54e7..6338d22d 100644 --- a/test/seq/runtests.jl +++ b/test/seq/runtests.jl @@ -6,5 +6,6 @@ using Test @time @testset "Nonlinear Thermal Compliance - ALM" begin include("NonLinearThermalComplianceALMTests.jl") end @time @testset "Inverse Homogenisation - ALM" begin include("InverseHomogenisationALMTests.jl") end @time @testset "Inverter - HPM" begin include("InverterHPMTests.jl") end +@time @testset "PZMultiFieldRepeatingState - ALM" begin include("PZMultiFieldRepeatingStateTests.jl") end end # module \ No newline at end of file From 38ad633a06dd128d65c60b4625a7062d84bf915d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 1 May 2024 10:28:42 +1000 Subject: [PATCH 83/90] Bugfix: repeated_blocks --- src/ChainRules.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 1a2a5f49..501c4f7b 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -785,9 +785,7 @@ repeated_blocks(V0::FESpace,x::AbstractBlockVector) = blocks(x) repeated_blocks(V0::FESpace,xh) = xh repeated_blocks(V0::MultiFieldSpaceTypes,x::AbstractBlockVector) = repeated_blocks(MultiFieldStyle(V0),V0,x) -repeated_blocks(V0::MultiFieldSpaceTypes,x) = repeated_blocks(MultiFieldStyle(V0),V0,x) repeated_blocks(::ConsecutiveMultiFieldStyle,V0,x::AbstractBlockVector) = blocks(x) -repeated_blocks(::ConsecutiveMultiFieldStyle,V0,xh) = xh function repeated_blocks(::BlockMultiFieldStyle{NB},V0::MultiFieldSpaceTypes,x::AbstractBlockVector) where NB xb = blocks(x) @@ -800,7 +798,7 @@ function repeated_blocks(::BlockMultiFieldStyle{NB},V0::MultiFieldSpaceTypes,x:: return rep_blocks end -function repeated_blocks(::BlockMultiFieldStyle,V0::MultiFieldSpaceTypes,xh) +function repeated_blocks(V0::MultiFieldSpaceTypes,xh) x_blocks = repeated_blocks(MultiFieldStyle(V0),V0,get_free_dof_values(xh)) rep_blocks = map(x_blocks) do xb FEFunction(V0,xb) From 6e1bcc1b2a86b70019cc3aa3f60e12cc437ccc35 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Tue, 7 May 2024 11:11:51 +1000 Subject: [PATCH 84/90] clean up repo --- .../Deprecated_root_files/ChainRules.jl | 594 ------------------ Deprecated/Deprecated_root_files/LevelSet.jl | 205 ------ Deprecated/Deprecated_root_files/MainMPI.jl | 59 -- .../Deprecated_root_files/OptimiseALM.jl | 68 -- .../Deprecated_root_files/OptimiseHPM.jl | 89 --- .../Deprecated_root_files/ProjectionMethod.jl | 144 ----- Deprecated/Deprecated_root_files/Setup.jl | 444 ------------- Deprecated/Deprecated_root_files/Utilities.jl | 136 ---- .../auto_diff_elastic_compliance_parallel.jl | 216 ------- .../inverse_homogenisation_parallel.jl | 234 ------- .../Deprecated_root_files/test_iterate.jl | 37 -- .../Deprecated_scripts/AD_AM_testing.jl | 139 ---- Deprecated/Deprecated_scripts/advection.jl | 30 - .../Deprecated_scripts/inverter_AD_testing.jl | 114 ---- .../main_inverter_(Based on Laurain).jl | 112 ---- Deprecated/Images/Algorithm.png | Bin 1482410 -> 0 bytes Deprecated/assembler_bug.jl | 43 -- .../auto_diff_elastic_compliance_serial.jl | 214 ------- Deprecated/dg_upwinding_tests.jl | 63 -- Deprecated/elastic_compliance_for_jordi.jl | 128 ---- Deprecated/get_dof_coords.jl | 72 --- Deprecated/permutation_tests.jl | 72 --- Deprecated/test_periodic_finitediff.jl | 160 ----- Deprecated/tests.jl | 173 ----- Deprecated/tests2.jl | 42 -- Deprecated/tests3.jl | 43 -- Deprecated/tests4.jl | 203 ------ Deprecated/tests_solver.jl | 128 ---- Deprecated/tests_solver2_mpi.jl | 96 --- Deprecated/tests_solvers2.jl | 150 ----- README.md | 7 +- results/.gitignore | 2 - scripts/Benchmarks/benchmark.jl | 14 +- scripts/Benchmarks/benchmark_gadi.jl | 460 -------------- .../Benchmarks/generate_benchmark_scripts.jl | 63 +- .../generate_benchmark_scripts_gadi.jl | 120 ---- scripts/Benchmarks/jobtemplate.sh | 32 +- scripts/Benchmarks/jobtemplate_gadi.sh | 26 - scripts/MPI/3d_elastic_compliance_ALM.jl | 30 +- scripts/MPI/3d_hyperelastic_compliance_ALM.jl | 30 +- .../3d_hyperelastic_compliance_neohook_ALM.jl | 30 +- scripts/MPI/3d_inverse_homenisation_ALM.jl | 34 +- scripts/MPI/3d_inverter_ALM.jl | 44 +- scripts/MPI/3d_inverter_HPM.jl | 44 +- .../3d_nonlinear_thermal_compliance_ALM.jl | 34 +- scripts/MPI/3d_thermal_compliance_ALM.jl | 28 +- scripts/MPI/elastic_compliance_ALM.jl | 19 +- scripts/MPI/inverse_homenisation_ALM.jl | 23 +- .../MPI/jobs/3d_elastic_compliance_ALM.pbs | 25 - .../jobs/3d_hyperelastic_compliance_ALM.pbs | 25 - ...3d_hyperelastic_compliance_neohook_ALM.pbs | 25 - .../MPI/jobs/3d_inverse_homenisation_ALM.pbs | 25 - scripts/MPI/jobs/3d_inverter_ALM.pbs | 26 - scripts/MPI/jobs/3d_inverter_HPM.pbs | 26 - .../3d_nonlinear_thermal_compliance_ALM.pbs | 26 - .../MPI/jobs/3d_thermal_compliance_ALM.pbs | 26 - .../MPI/nonlinear_thermal_compliance_ALM.jl | 21 +- scripts/MPI/thermal_compliance_ALM.jl | 9 +- scripts/MPI/thermal_compliance_ALM_PETSc.jl | 17 +- scripts/Serial/elastic_compliance_ALM.jl | 11 +- scripts/Serial/elastic_compliance_HPM.jl | 13 +- scripts/Serial/elastic_compliance_LM.jl | 13 +- scripts/Serial/hyperelastic_compliance_ALM.jl | 9 +- .../hyperelastic_compliance_neohook_ALM.jl | 9 +- scripts/Serial/inverse_homenisation_ALM.jl | 11 +- scripts/Serial/inverter_ALM.jl | 17 +- scripts/Serial/inverter_HPM.jl | 17 +- .../nonlinear_thermal_compliance_ALM.jl | 15 +- scripts/Serial/thermal_compliance_ALM.jl | 13 +- .../thermal_compliance_ALM_higherorderlsf.jl | 17 +- .../_dev/3d_hyperelastic_compliance_ALM.jl | 203 ------ scripts/_dev/OptimiserHistoryTests.jl | 8 - .../_dev/Paper_scripts/elast_comp_MPI_3D.jl | 105 ---- .../Paper_scripts/hyperelast_comp_MPI_3D.jl | 121 ---- .../_dev/Paper_scripts/inverse_hom_MPI_3D.jl | 108 ---- scripts/_dev/Paper_scripts/inverter_MPI_3D.jl | 120 ---- .../jobs-gadi/elast_comp_MPI_3D.pbs | 15 - .../jobs-gadi/hyperelast_comp_MPI_3D.pbs | 15 - .../jobs-gadi/inverse_hom_MPI_3D.pbs | 15 - .../jobs-gadi/inverter_MPI_3D.pbs | 15 - .../jobs-gadi/therm_comp_MPI_3D.pbs | 15 - .../Paper_scripts/jobs/elast_comp_MPI_3D.pbs | 20 - .../jobs/hyperelast_comp_MPI_3D.pbs | 20 - .../Paper_scripts/jobs/inverse_hom_MPI_3D.pbs | 20 - .../Paper_scripts/jobs/inverter_MPI_3D.pbs | 20 - .../Paper_scripts/jobs/therm_comp_MPI_3D.pbs | 20 - scripts/_dev/Paper_scripts/therm_comp_MPI.jl | 104 --- .../_dev/Paper_scripts/therm_comp_MPI_3D.jl | 107 ---- .../_dev/Paper_scripts/therm_comp_serial.jl | 82 --- .../MPI_benchmark_test_2D_themal.jl | 108 ---- .../MPI_benchmark_test_3D_themal.jl | 134 ---- .../benchmark_tests/serial_benchmark_test.jl | 101 --- scripts/_dev/bug_issue_46/thermal_MPI.jl | 91 --- scripts/_dev/bug_issue_46/thermal_serial.jl | 87 --- scripts/_dev/fileio_testing.jl | 52 -- scripts/_dev/full_piezo_script.jl | 236 ------- scripts/_dev/full_piezo_script_2d.jl | 246 -------- scripts/_dev/inv_hom_block_assem_testing.jl | 132 ---- .../inv_hom_block_assem_testing_3D_MPI.jl | 172 ----- ...inv_hom_block_assem_testing_full_script.jl | 151 ----- scripts/_dev/mem_leak.jl | 114 ---- scripts/_dev/nonlinear_adjoint_MWE.jl | 83 --- scripts/_dev/nonlinear_adjoint_testing.jl | 41 -- scripts/_dev/operations/ops_testing.jl | 85 --- .../_dev/operations/ops_testing_fn_version.jl | 96 --- scripts/_dev/operations/ops_testing_iwm.jl | 72 --- scripts/_dev/piezo_repeating.jl | 354 ----------- scripts/_dev/piezo_script.jl | 154 ----- ...nimum_thermal_compliance_implementation.jl | 76 --- ...um_thermal_compliance_implementation_3d.jl | 78 --- ...rmal_compliance_implementation_3d_petsc.jl | 99 --- ..._compliance_implementation_3d_petsc_mpi.jl | 104 --- ...mal_compliance_implementation_nonlinear.jl | 74 --- 113 files changed, 321 insertions(+), 9396 deletions(-) delete mode 100644 Deprecated/Deprecated_root_files/ChainRules.jl delete mode 100755 Deprecated/Deprecated_root_files/LevelSet.jl delete mode 100755 Deprecated/Deprecated_root_files/MainMPI.jl delete mode 100755 Deprecated/Deprecated_root_files/OptimiseALM.jl delete mode 100755 Deprecated/Deprecated_root_files/OptimiseHPM.jl delete mode 100755 Deprecated/Deprecated_root_files/ProjectionMethod.jl delete mode 100755 Deprecated/Deprecated_root_files/Setup.jl delete mode 100755 Deprecated/Deprecated_root_files/Utilities.jl delete mode 100644 Deprecated/Deprecated_root_files/auto_diff_elastic_compliance_parallel.jl delete mode 100644 Deprecated/Deprecated_root_files/inverse_homogenisation_parallel.jl delete mode 100644 Deprecated/Deprecated_root_files/test_iterate.jl delete mode 100644 Deprecated/Deprecated_scripts/AD_AM_testing.jl delete mode 100644 Deprecated/Deprecated_scripts/advection.jl delete mode 100644 Deprecated/Deprecated_scripts/inverter_AD_testing.jl delete mode 100644 Deprecated/Deprecated_scripts/main_inverter_(Based on Laurain).jl delete mode 100644 Deprecated/Images/Algorithm.png delete mode 100644 Deprecated/assembler_bug.jl delete mode 100644 Deprecated/auto_diff_elastic_compliance_serial.jl delete mode 100644 Deprecated/dg_upwinding_tests.jl delete mode 100644 Deprecated/elastic_compliance_for_jordi.jl delete mode 100644 Deprecated/get_dof_coords.jl delete mode 100644 Deprecated/permutation_tests.jl delete mode 100644 Deprecated/test_periodic_finitediff.jl delete mode 100644 Deprecated/tests.jl delete mode 100644 Deprecated/tests2.jl delete mode 100644 Deprecated/tests3.jl delete mode 100644 Deprecated/tests4.jl delete mode 100644 Deprecated/tests_solver.jl delete mode 100644 Deprecated/tests_solver2_mpi.jl delete mode 100644 Deprecated/tests_solvers2.jl delete mode 100644 results/.gitignore delete mode 100644 scripts/Benchmarks/benchmark_gadi.jl delete mode 100644 scripts/Benchmarks/generate_benchmark_scripts_gadi.jl delete mode 100644 scripts/Benchmarks/jobtemplate_gadi.sh delete mode 100644 scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs delete mode 100644 scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs delete mode 100644 scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs delete mode 100644 scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs delete mode 100644 scripts/MPI/jobs/3d_inverter_ALM.pbs delete mode 100644 scripts/MPI/jobs/3d_inverter_HPM.pbs delete mode 100644 scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs delete mode 100644 scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs delete mode 100644 scripts/_dev/3d_hyperelastic_compliance_ALM.jl delete mode 100644 scripts/_dev/OptimiserHistoryTests.jl delete mode 100644 scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl delete mode 100644 scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl delete mode 100644 scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl delete mode 100644 scripts/_dev/Paper_scripts/inverter_MPI_3D.jl delete mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs delete mode 100644 scripts/_dev/Paper_scripts/therm_comp_MPI.jl delete mode 100644 scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl delete mode 100644 scripts/_dev/Paper_scripts/therm_comp_serial.jl delete mode 100644 scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl delete mode 100644 scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl delete mode 100644 scripts/_dev/benchmark_tests/serial_benchmark_test.jl delete mode 100644 scripts/_dev/bug_issue_46/thermal_MPI.jl delete mode 100644 scripts/_dev/bug_issue_46/thermal_serial.jl delete mode 100644 scripts/_dev/fileio_testing.jl delete mode 100644 scripts/_dev/full_piezo_script.jl delete mode 100644 scripts/_dev/full_piezo_script_2d.jl delete mode 100644 scripts/_dev/inv_hom_block_assem_testing.jl delete mode 100644 scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl delete mode 100644 scripts/_dev/inv_hom_block_assem_testing_full_script.jl delete mode 100644 scripts/_dev/mem_leak.jl delete mode 100644 scripts/_dev/nonlinear_adjoint_MWE.jl delete mode 100644 scripts/_dev/nonlinear_adjoint_testing.jl delete mode 100644 scripts/_dev/operations/ops_testing.jl delete mode 100644 scripts/_dev/operations/ops_testing_fn_version.jl delete mode 100644 scripts/_dev/operations/ops_testing_iwm.jl delete mode 100644 scripts/_dev/piezo_repeating.jl delete mode 100644 scripts/_dev/piezo_script.jl delete mode 100644 scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl delete mode 100644 scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl delete mode 100644 scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl delete mode 100644 scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl delete mode 100644 scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl diff --git a/Deprecated/Deprecated_root_files/ChainRules.jl b/Deprecated/Deprecated_root_files/ChainRules.jl deleted file mode 100644 index 0d428fb6..00000000 --- a/Deprecated/Deprecated_root_files/ChainRules.jl +++ /dev/null @@ -1,594 +0,0 @@ -# ========================================================== -# ========================================================== -# HELPER FUNCTIONS -# ========================================================== -# ========================================================== - -function Adjoint(ϕ,u,du,op,res,Q)#,solver) - A = Gridap.jacobian(op,u) # = dr/du - Aᵀ = adjoint(A) - V = op.test - λₕ = FEFunction(V,Aᵀ\du)#,solver) - ϕh = FEFunction(Q,ϕ) - dϕ() = Gridap.FESpaces.gradient(ϕh -> res(u,λₕ,ϕh),ϕh) - dϕ = -assemble_vector(dϕ(),Q) -end - -function AdjointAffine(ϕ,u,du,op,a,Q)#,solver) - A = Gridap.jacobian(op,u) # = dr/du - Aᵀ = adjoint(A) - V = op.test - λₕ = FEFunction(V,Aᵀ\du)#,solver) - ϕh = FEFunction(Q,ϕ) - dϕ() = Gridap.FESpaces.gradient(ϕh -> res(u,λₕ,ϕh,Q),ϕh) - dϕ = -assemble_vector(dϕ(),Q) -end - -# ================ -# ================ -# CHAIN RULES MAIN -# ================ -# ================ - -# ============================================================ -# u -> J : Struct representing the scalar objective evaluation -# ============================================================ - -struct LossFunction{P,U} - loss::Function - param_sp::P - state_sp::U - # assem::Assembler -end - -function (u_to_j::LossFunction)(u,ϕ) - loss=u_to_j.loss - U=u_to_j.state_sp - Q=u_to_j.param_sp - uₕ=FEFunction(U,u) - ϕₕ=FEFunction(Q,ϕ) - sum(loss(uₕ,ϕₕ)) -end - -function ChainRulesCore.rrule(u_to_j::LossFunction,u,ϕ) - loss=u_to_j.loss - U=u_to_j.state_sp - Q=u_to_j.param_sp - uₕ=FEFunction(U,u) - ϕₕ=FEFunction(Q,ϕ) - jp=sum(loss(uₕ,ϕₕ)) - function u_to_j_pullback(dj) - djdu = ∇(uₕ->loss(uₕ,ϕₕ))(uₕ) - djdu_vec = assemble_vector(djdu,U) - djdϕ = ∇(ϕₕ->loss(uₕ,ϕₕ))(ϕₕ) - djdϕ_vec = assemble_vector(djdϕ,Q) - ( NoTangent(), dj*djdu_vec, dj*djdϕ_vec ) - end - jp, u_to_j_pullback -end -# ================================================================================================================================== -# ϕ -> u : Struct that represents the FE solution of a parameterised Affine PDE. It is a map from the parameter space P to a FESpace -# ================================================================================================================================== - -struct _AffineFEStateMap{P,U <: FESpace, V <: FESpace} - a::Function - ℓ::Function - res::Function - param_sp::P # params (CellData) - trial::U - test::V - # assem::Assembler -end - -function (ϕ_to_u::_AffineFEStateMap)(ϕ) - a=ϕ_to_u.a - l=ϕ_to_u.ℓ - res=ϕ_to_u.res - Q=ϕ_to_u.param_sp - U=ϕ_to_u.trial - V=ϕ_to_u.test - op = AffineFEOperator(a(ϕ),l(ϕ),U,V) - get_free_dof_values(Gridap.solve(op)) -end - -function ChainRulesCore.rrule(ϕ_to_u::_AffineFEStateMap,ϕ) - a=ϕ_to_u.a - l=ϕ_to_u.ℓ - res=ϕ_to_u.res - Q=ϕ_to_u.param_sp - U=ϕ_to_u.trial - V=ϕ_to_u.test - op = AffineFEOperator(a(ϕ),l(ϕ),U,V) - uₕ = Gridap.solve(op) - function ϕ_to_u_pullback(du) - dϕ = Adjoint(ϕ,uₕ,du,op,res,Q) - ( NoTangent(),dϕ) - end - get_free_dof_values(uₕ), ϕ_to_u_pullback -end - -# ========================================================= -# ϕn1 -> ϕb4 : Adding the volume constraint enforcing bias -# ========================================================= - -struct VolumeConstraintMap{P} - ϕ_b_to_ϕc::Function - b::Function - ϕ_b_to_Vol::Function - param_sp::P - Vₘₐₓ::Float64 - problem#::ProblemType -end - -function (ϕₛ₃_to_ϕ::VolumeConstraintMap)(ϕₛ₃) - ϕ_b_to_ϕc=ϕₛ₃_to_ϕ.ϕ_b_to_ϕc - b = ϕₛ₃_to_ϕ.b - Vbg = ϕₛ₃_to_ϕ.param_sp - Vₘₐₓ = ϕₛ₃_to_ϕ.Vₘₐₓ - problem = ϕₛ₃_to_ϕ.problem - - bp = b(ϕₛ₃,Vbg,Vₘₐₓ,problem) - ϕp = ϕ_b_to_ϕc(ϕₛ₃,bp,problem) -end - -function ChainRulesCore.rrule(ϕₛ₃_to_ϕ::VolumeConstraintMap,ϕₛ₃) - ϕ_b_to_ϕc=ϕₛ₃_to_ϕ.ϕ_b_to_ϕc - b = ϕₛ₃_to_ϕ.b - ϕ_b_to_Vol = ϕₛ₃_to_ϕ.ϕ_b_to_Vol - Vbg = ϕₛ₃_to_ϕ.param_sp - Vₘₐₓ = ϕₛ₃_to_ϕ.Vₘₐₓ - problem = ϕₛ₃_to_ϕ.problem - - bp = b(ϕₛ₃,Vbg,Vₘₐₓ,problem) - ϕp = ϕ_b_to_ϕc(ϕₛ₃,bp,problem) - - ab_r = AD.ReverseDiffBackend() - pb_ϕₛ₃ = AD.pullback_function(ab_r, ϕₛ₃ -> ϕ_b_to_ϕc(ϕₛ₃,bp,problem) , ϕₛ₃) - pb_b = AD.pullback_function(ab_r, bp -> ϕ_b_to_ϕc(ϕₛ₃,bp,problem) , bp) - - function ϕᵤ_to_ϕ_pullback(dϕ) - dVoldϕₛ₃ = ReverseDiff.gradient( ϕ -> ϕ_b_to_Vol(ϕ,bp,Vbg,problem), reshape(ϕₛ₃,(length(ϕₛ₃),1))) # N X 1 - dVoldb = ForwardDiff.derivative( b -> ϕ_b_to_Vol(ϕₛ₃,b,Vbg,problem), bp) # N X 1 - dϕdb_dϕ = pb_b(dϕ)[1][1] #sum(dϕ) # 1 X 1 = ( 1 X N ) * ( N X 1 ) - dϕₛ₃₍ₘ₎ = pb_ϕₛ₃(dϕ)[1] - dVoldϕₛ₃*(dVoldb)^-1 * dϕdb_dϕ # N X Q X Q X 1 + (N X 1) X (1 X 1) X [(1 X 1)] where the last 1X1 is from the above loop - dϕₛ₃ = collect1d(dϕₛ₃₍ₘ₎) - (NoTangent(), dϕₛ₃) - end - ϕp,ϕᵤ_to_ϕ_pullback -end - -#= - -function (ϕₛ₃_to_ϕ::VolumeConstraintMap)(ϕₛ₃,method::MethodType{:constrained}) - ϕₛ₃ -end - -function ChainRulesCore.rrule(ϕₛ₃_to_ϕ::VolumeConstraintMap,ϕₛ₃,method::MethodType{:constrained}) - function ϕᵤ_to_ϕ_pullback(dϕ) - (NoTangent(), dϕ, NoTangent()) - end - ϕₛ₃,ϕᵤ_to_ϕ_pullback -end - -function (ϕₛ₃_to_ϕ::VolumeConstraintMap)(ϕₛ₃,method::MethodType{:unconstrained}) - ϕₛ₃_to_ϕ(ϕₛ₃) -end - -function ChainRulesCore.rrule(ϕₛ₃_to_ϕ::VolumeConstraintMap,ϕₛ₃,method::MethodType{:unconstrained}) - ϕₛ₃,ϕᵤ_to_ϕ_pullback =rrule(ϕₛ₃_to_ϕ,ϕₛ₃) - function ϕᵤ_to_ϕ_pullback_with_extra_NoTangent(dϕ) - (ϕᵤ_to_ϕ_pullback(dϕ)...,NoTangent()) - end - ϕₛ₃, ϕᵤ_to_ϕ_pullback_with_extra_NoTangent -end - -=# - -# ============================================================================================================================================================================================= -# ϕᵧ₂ -> ϕₛ₃ : Applying the signed distance reinitialisation. This is another FEStateMap which, as apposed to the Affine version, solves the nonlinear residual using a specified initial point -# ============================================================================================================================================================================================= - -struct InitialisableFEStateMap{P,U <: FESpace, V <: FESpace} - res::Function - jac::Function - get_geo_params::Function - param_sp::P # params (CellData) - trial::U - test::V - # assem::Assembler -end - -function (ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap)(ϕ) - res=ϕᵧ₂_to_ϕₛ₃.res - jac=ϕᵧ₂_to_ϕₛ₃.jac - #get_geo_params_=ϕᵧ₂_to_ϕₛ₃.get_geo_params - Q=ϕᵧ₂_to_ϕₛ₃.param_sp - U=ϕᵧ₂_to_ϕₛ₃.trial - V=ϕᵧ₂_to_ϕₛ₃.test - #fϕ,_=get_geo_params(ϕ,Q) - op = FEOperator(res(ϕ),jac(ϕ),U,V) - ls = LUSolver() - nls = NLSolver( - show_trace=true, method=:newton, linesearch=BackTracking(), ftol=1e-12, iterations= 50 ) - solver = FESolver(nls) - ϕh = FEFunction(V,copy(ϕ)) - ϕₛ₃,_ = Gridap.solve!(ϕh,nls,op) - ϕₛ₃.free_values -end - -function ChainRulesCore.rrule(ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap,ϕ) - res=ϕᵧ₂_to_ϕₛ₃.res - jac=ϕᵧ₂_to_ϕₛ₃.jac - #get_geo_params_=ϕᵧ₂_to_ϕₛ₃.get_geo_params - Q=ϕᵧ₂_to_ϕₛ₃.param_sp - U=ϕᵧ₂_to_ϕₛ₃.trial - V=ϕᵧ₂_to_ϕₛ₃.test - #fϕ,_=get_geo_params(ϕ,Q) - op = FEOperator(res(ϕ),jac(ϕ),U,V) - ls = LUSolver() - nls = NLSolver( - show_trace=true, method=:newton, linesearch=BackTracking(), ftol=1e-12, iterations= 50 ) - solver = FESolver(nls) - ϕh = FEFunction(V,copy(ϕ)) - ϕₛ₃,_ = Gridap.solve!(ϕh,nls,op) - function ϕᵧ₂_to_ϕₛ₃_pullback(dϕₛ₃) - dϕᵧ₂ = Adjoint(ϕ,ϕₛ₃,dϕₛ₃,op,res,Q) - (NoTangent(),dϕᵧ₂) - end - ϕₛ₃.free_values, ϕᵧ₂_to_ϕₛ₃_pullback -end - -#= - -function (ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap)(ϕᵧ₂,method::MethodType{:unconstrained},problem::ProblemType{:heat_simp}) - ϕᵧ₂ -end - -function ChainRulesCore.rrule(ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap,ϕᵧ₂,method::MethodType{:unconstrained},problem::ProblemType{:heat_simp}) - function ϕᵧ₂_to_ϕₛ₃_pullback(dϕₛ₃) - ( NoTangent(),dϕₛ₃, NoTangent(), NoTangent()) - end - ϕᵧ₂, ϕᵧ₂_to_ϕₛ₃_pullback -end - -function (ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap)(ϕᵧ₂,method::MethodType{:constrained},problem::ProblemType{:heat_simp}) - ϕᵧ₂ -end - -function ChainRulesCore.rrule(ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap,ϕᵧ₂,method::MethodType{:constrained},problem::ProblemType{:heat_simp}) - function ϕᵧ₂_to_ϕₛ₃_pullback(dϕₛ₃) - ( NoTangent(),dϕₛ₃, NoTangent(), NoTangent()) - end - ϕᵧ₂, ϕᵧ₂_to_ϕₛ₃_pullback -end - -function (ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap)(ϕᵧ₂,method::MethodType{:constrained},problem) - ϕᵧ₂ -end - -function ChainRulesCore.rrule(ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap,ϕᵧ₂,method::MethodType{:constrained},problem) - function ϕᵧ₂_to_ϕₛ₃_pullback(dϕₛ₃) - ( NoTangent(),dϕₛ₃, NoTangent(), NoTangent()) - end - ϕᵧ₂, ϕᵧ₂_to_ϕₛ₃_pullback -end - -function (ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap)(ϕᵧ₂,method::MethodType{:unconstrained},problem) - ϕᵧ₂_to_ϕₛ₃(ϕᵧ₂) -end - -function ChainRulesCore.rrule(ϕᵧ₂_to_ϕₛ₃::InitialisableFEStateMap,ϕᵧ₂,method::MethodType{:unconstrained},problem) - ϕₛ₃,ϕᵧ₂_to_ϕₛ₃_pullback = rrule(ϕᵧ₂_to_ϕₛ₃,ϕᵧ₂) - function ϕᵧ₂_to_ϕₛ₃_pullback_with_extra_NoTangent(dϕₛ₃) - (ϕᵧ₂_to_ϕₛ₃_pullback(dϕₛ₃)...,NoTangent(), NoTangent()) - end - ϕₛ₃, ϕᵧ₂_to_ϕₛ₃_pullback_with_extra_NoTangent -end - -=# - - -# ============================================================================================================================================================================================= -# An extra Affine InitialisableAffineFEStateMap -# ============================================================================================================================================================================================= - -struct InitialisableAffineFEStateMap{P,U <: FESpace, V <: FESpace} - a::Function - l::Function - res::Function - param_sp::P # params (CellData) - trial::U - test::V - # assem::Assembler -end - -function (ϕᵧ₂_to_ϕₛ₃::InitialisableAffineFEStateMap)(ϕ) - a = ϕᵧ₂_to_ϕₛ₃.a - l = ϕᵧ₂_to_ϕₛ₃.l - res=ϕᵧ₂_to_ϕₛ₃.res - Q=ϕᵧ₂_to_ϕₛ₃.param_sp - U=ϕᵧ₂_to_ϕₛ₃.trial - V=ϕᵧ₂_to_ϕₛ₃.test - op = AffineFEOperator(a(ϕ),l(ϕ),U,V) - ls = LUSolver() - solver = FESolver(nls) - ϕh = FEFunction(V,copy(ϕ)) - ϕₛ₃,_ = Gridap.solve!(ϕh,ls,op) - ϕₛ₃.free_values -end - -function ChainRulesCore.rrule(ϕᵧ₂_to_ϕₛ₃::InitialisableAffineFEStateMap,ϕ) - res=ϕᵧ₂_to_ϕₛ₃.res - jac=ϕᵧ₂_to_ϕₛ₃.jac - #get_geo_params_=ϕᵧ₂_to_ϕₛ₃.get_geo_params - Q=ϕᵧ₂_to_ϕₛ₃.param_sp - U=ϕᵧ₂_to_ϕₛ₃.trial - V=ϕᵧ₂_to_ϕₛ₃.test - #fϕ,_=get_geo_params(ϕ,Q) - op = AffineFEOperator(a(ϕ),l(ϕ),U,V) - ls = LUSolver() - solver = FESolver(nls) - ϕh = FEFunction(V,copy(ϕ)) - ϕₛ₃,_ = Gridap.solve!(ϕh,ls,op) - function ϕᵧ₂_to_ϕₛ₃_pullback(dϕₛ₃) - dϕᵧ₂ = Adjoint(ϕ,ϕₛ₃,dϕₛ₃,op,res,Q) - (NoTangent(),dϕᵧ₂) - end - ϕₛ₃.free_values, ϕᵧ₂_to_ϕₛ₃_pullback -end - - -# ============================================================================================================================================================================================= -# An extra Affine InitialisableFEStateMap that can utilise autodiff but has to use a hack for the part of res not dep on u for the moment -# ============================================================================================================================================================================================= - -struct InitialisableAutoFEStateMap{P,U <: FESpace, V <: FESpace} - res::Function - res_ϕ::Function - param_sp::P # params (CellData) - trial::U - test::V - u0::Array{Float64} - # assem::Assembler -end - -function (ϕᵧ₂_to_ϕₛ₃::InitialisableAutoFEStateMap)(ϕ) - res=ϕᵧ₂_to_ϕₛ₃.res - res_ϕ=ϕᵧ₂_to_ϕₛ₃.res_ϕ - Q=ϕᵧ₂_to_ϕₛ₃.param_sp - U=ϕᵧ₂_to_ϕₛ₃.trial - V=ϕᵧ₂_to_ϕₛ₃.test - u0 = ϕᵧ₂_to_ϕₛ₃.u0 - op = FEOperator(res(ϕ),U,V) - #ls = LUSolver() - nls = NLSolver( - show_trace=true, method=:newton, linesearch=BackTracking(), ftol=1e-9, iterations= 50 ) - solver = FESolver(nls) - ϕₛ₃0h = FEFunction(V,copy(u0)) - ϕₛ₃,_ = Gridap.solve!(ϕₛ₃0h,nls,op) - ϕₛ₃.free_values -end - -function ChainRulesCore.rrule(ϕᵧ₂_to_ϕₛ₃::InitialisableAutoFEStateMap,ϕ) - res=ϕᵧ₂_to_ϕₛ₃.res - res_ϕ=ϕᵧ₂_to_ϕₛ₃.res_ϕ - Q=ϕᵧ₂_to_ϕₛ₃.param_sp - U=ϕᵧ₂_to_ϕₛ₃.trial - V=ϕᵧ₂_to_ϕₛ₃.test - u0 = ϕᵧ₂_to_ϕₛ₃.u0 - op = FEOperator(res(ϕ),U,V) - #ls = LUSolver() - nls = NLSolver( - show_trace=true, method=:newton, linesearch=BackTracking(), ftol=1e-9, iterations= 50 ) - solver = FESolver(nls) - ϕh = FEFunction(V,copy(u0)) - ϕₛ₃,_ = Gridap.solve!(ϕh,nls,op) - function ϕᵧ₂_to_ϕₛ₃_pullback(dϕₛ₃) - dϕᵧ₂ = Adjoint(ϕ,ϕₛ₃,dϕₛ₃,op,res_ϕ,Q) - (NoTangent(),dϕᵧ₂) - end - ϕₛ₃.free_values, ϕᵧ₂_to_ϕₛ₃_pullback -end - -# ========================================================= -# ϕₙ₁ -> ϕᵧ₂ : Smoothing the level set with a linear filter -# ========================================================= - -struct LinearFilter - bgmodel::CartesianDiscreteModel - filter_weights::Matrix{Float64} - pullback_jacobian::Function # This is a constant matrix : we keep it as a pullback to avoid assembling -end - -function (ϕₙ₁_to_ϕᵧ₂::LinearFilter)(ϕₙ₁) - bgmodel=ϕₙ₁_to_ϕᵧ₂.bgmodel - filter_weights = ϕₙ₁_to_ϕᵧ₂.filter_weights - ϕᵧ₂ = apply_filter(filter_weights,bgmodel,ϕₙ₁) -end - -function ChainRulesCore.rrule(ϕₙ₁_to_ϕᵧ₂::LinearFilter,ϕₙ₁) - bgmodel=ϕₙ₁_to_ϕᵧ₂.bgmodel - filter_weights = ϕₙ₁_to_ϕᵧ₂.filter_weights - pb_f = ϕₙ₁_to_ϕᵧ₂.pullback_jacobian - ϕᵧ₂ = apply_filter(filter_weights,bgmodel,ϕₙ₁) - function ϕₙ₁_to_ϕᵧ₂_pullback(dϕᵧ₂) - dϕₙ₁M = pb_f(dϕᵧ₂)[1] - cd = Gridap.Geometry.get_cartesian_descriptor(bgmodel) - cells = cd.partition - dϕₙ₁ = collect(reshape(dϕₙ₁M,(cells[1]+1)*(cells[2]+1))) - (NoTangent(),dϕₙ₁) - end - ϕᵧ₂,ϕₙ₁_to_ϕᵧ₂_pullback -end - -function apply_filter(filter_weights,bgmodel,ϕₙ₁) - cd = Gridap.Geometry.get_cartesian_descriptor(bgmodel) - cells = cd.partition - ϕₙ₁M=reshape(ϕₙ₁,(cells[1]+1,cells[2]+1)) - w = centered(filter_weights) - ϕᵧ₂M = imfilter(ϕₙ₁M,w,"replicate") - ϕᵧ₂ = reshape(ϕᵧ₂M,(cells[1]+1)*(cells[2]+1)) -end - -# =============================================================================================================================================================================================== -# p -> ϕn1 : A map from the initial parameterisation to level set values. The initial parameterisation may be a neural network or simply pixel based (in which case this map is the identity). -# =============================================================================================================================================================================================== - -# We also include here a tape for mapping p to L where L is the sub-objective for matching a level set to a desired level set. This is used to train a neural network to provide a specified initial guess (defined by a set of level set values). -struct NeuralObjective - N0::Vector{Float64} -end - -function (ϕₙ₁_to_L::NeuralObjective)(ϕₙ₁) - N0 = ϕₙ₁_to_L.N0 - sum( (N0.-ϕₙ₁).^2 ) / length(N0) -end - -function ChainRulesCore.rrule(ϕₙ₁_to_L::NeuralObjective,ϕₙ₁) - function ϕₙ₁_to_L_pullback(dL) - dϕₙ₁ = ForwardDiff.gradient(ϕₙ₁_to_L,ϕₙ₁) * dL - ( NoTangent(), dϕₙ₁) - end - ϕₙ₁_to_L(ϕₙ₁), ϕₙ₁_to_L_pullback -end - -struct NeuralGeometry - N::Function - pP::Vector{Float64} -end - -function (p_to_ϕₙ₁::NeuralGeometry)(p) - N = p_to_ϕₙ₁.N - pP = p_to_ϕₙ₁.pP - Nh = N(p) # nucleation_promotion(N(p),pP) # - Np = collect(Iterators.flatten(Nh)) -end - -function ChainRulesCore.rrule(p_to_ϕₙ₁::NeuralGeometry,p) - N = p_to_ϕₙ₁.N - pP = p_to_ϕₙ₁.pP - Nh, dNdp_vjp = Zygote.pullback(N,p) # Zygote.pullback(p->nucleation_promotion(N(p),pP),p) # - Np = collect(Iterators.flatten(Nh)) - function p_to_ϕₙ₁_pullback(ds) - dp = dNdp_vjp(Float32.(ds))[1] - ( NoTangent(),dp ) - end - Np, p_to_ϕₙ₁_pullback -end - -#= - -function (p_to_ϕₙ₁::NeuralGeometry)(p,prior::PriorType{:pixel}) - p -end - -function ChainRulesCore.rrule(p_to_ϕₙ₁::NeuralGeometry,p,prior::PriorType{:pixel}) - function p_to_ϕₙ₁_pullback(dϕₙ₁) - dp=dϕₙ₁ - ( NoTangent(),dp, NoTangent()) - end - p_to_ϕₙ₁(p,prior), p_to_ϕₙ₁_pullback -end - -function (p_to_ϕₙ₁::NeuralGeometry)(p,prior::PriorType{:neural}) - p_to_ϕₙ₁(p) -end - -function ChainRulesCore.rrule(p_to_ϕₙ₁::NeuralGeometry,p,prior::PriorType{:neural}) - ϕₙ₁, p_to_ϕₙ₁_pullback = rrule(p_to_ϕₙ₁,p) - function p_to_ϕₙ₁_pullbackrrule_with_extra_NoTangent(dϕₙ₁) - (p_to_ϕₙ₁_pullback(dϕₙ₁)..., NoTangent()) - end - ϕₙ₁, p_to_ϕₙ₁_pullbackrrule_with_extra_NoTangent -end - -function p_to_L(p,bg_params) #prior) - ϕₙ₁ = p_to_ϕₙ₁(p,bg_params) #prior) - L = ϕₙ₁_to_L(ϕₙ₁,bg_params) # unfiltered unconstrained nodal values (s) to filtered unconstrained values (ϕᵤ) - L -end - -p_to_L(prior) = p -> p_to_L(p,prior) - -=# - -# ========================================================== -# ========================================================== -# CHAIN RULES CONSTRAINTS ( FOR USE WITH MMA ) -# ========================================================== -# ========================================================== - -struct VolumeMap{V<:FESpace} - ϕc_to_Vol::Function - param_space::V - problem#::ProblemType -end - -function (ϕ_to_Vol::VolumeMap)(ϕ) - ϕc_to_Vol=ϕ_to_Vol.ϕc_to_Vol - Vbg=ϕ_to_Vol.param_space - problem = ϕ_to_Vol.problem - - ϕc_to_Vol(ϕ,Vbg,problem) -end - -function ChainRulesCore.rrule(ϕ_to_Vol::VolumeMap,ϕ) - ϕc_to_Vol=ϕ_to_Vol.ϕc_to_Vol - Vbg=ϕ_to_Vol.param_space - problem = ϕ_to_Vol.problem - - Vol0=ϕc_to_Vol(ϕ,Vbg,problem) - - function ϕ_to_Vol_pullback(dVol) - dVoldϕ = ReverseDiff.gradient(ϕ -> ϕc_to_Vol(ϕ,Vbg,problem),reshape(ϕ,(length(ϕ),1))) - dϕₘ = dVol*dVoldϕ - dϕ = collect1d(dϕₘ) - ( NoTangent(),dϕ ) - end - Vol0, ϕ_to_Vol_pullback -end - -struct UnstructuredVolumeMap{V<:FESpace} - unstructured_ϕc_to_Vol::Function - param_space::V -end - -function (ϕ_to_Vol::UnstructuredVolumeMap)(ϕ) - unstructured_ϕc_to_Vol=ϕ_to_Vol.unstructured_ϕc_to_Vol - Qf=ϕ_to_Vol.param_space - - ϕh = FEFunction(Qf,ϕ) - - sum(unstructured_ϕc_to_Vol(ϕh)) -end - -function ChainRulesCore.rrule(ϕ_to_Vol::UnstructuredVolumeMap,ϕ) - unstructured_ϕc_to_Vol=ϕ_to_Vol.unstructured_ϕc_to_Vol - Qf=ϕ_to_Vol.param_space - - ϕh = FEFunction(Qf,ϕ) - - Vol0=sum(unstructured_ϕc_to_Vol(ϕh)) - - function ϕ_to_Vol_pullback(dVol) - dVoldϕ() = Gridap.FESpaces.gradient(ϕh -> unstructured_ϕc_to_Vol(ϕh),ϕh) #ReverseDiff.gradient(ϕ -> ϕc_to_Vol(ϕ,Vbg,problem),reshape(ϕ,(length(ϕ),1))) - dVoldϕ = assemble_vector(dVoldϕ(),Qf) - dϕ = dVol*dVoldϕ - ( NoTangent(),dϕ ) - end - Vol0, ϕ_to_Vol_pullback -end - -## Helpers -function φ_to_φₕ(φ::AbstractArray,Q) - φ = FEFunction(Q,φ) -end -function φ_to_φₕ(φ::FEFunction,Q) - φ -end -function φ_to_φₕ(φ::CellField,Q) - φ -end -function φ_to_φₕ(φ::GridapDistributed.DistributedCellField,Q) - φ -end \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/LevelSet.jl b/Deprecated/Deprecated_root_files/LevelSet.jl deleted file mode 100755 index b8ac90da..00000000 --- a/Deprecated/Deprecated_root_files/LevelSet.jl +++ /dev/null @@ -1,205 +0,0 @@ -# Generate initial LSF -gen_lsf(ξ,a) = x::VectorValue -> -1/4*prod(cos.(get_array(ξ*pi*x))) - a/4 - -# struct LevelSetUpdate{N,M} -# model -# fe_space -# γ -# max_steps -# cache - -# function LevelSetUpdate{M,N}() where {M,N} -# new{M,N}() -# end - -# end - -# struct VelocityExtension -# U -# V -# assem -# dΩ -# K -# cache -# end - -# struct LevelSetCache{N,M} - -# φ_tmp - -# end - -## H-J and reinit -""" - Single step for first order upwind method for H-J equation (2D) -""" -function advect!(φ::T,V::T,Δ::NTuple{2,M},Δt::M,caches) where {M,T<:Array{M,2}} - D⁺ʸ,D⁺ˣ,D⁻ʸ,D⁻ˣ,∇⁺,∇⁻=caches - Δx,Δy = Δ - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)); - circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)); - # Forward (+) & Backward (-) - D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; - D⁺ˣ .= @. (D⁺ˣ - φ)/Δx; - D⁻ʸ .= @. (φ - D⁻ʸ)/Δy; - D⁻ˣ .= @. (φ - D⁻ˣ)/Δx; - # Check for boundaries with ghost nodes - D⁺ʸ[:,end] .= zero(M); - D⁺ˣ[end,:] .= zero(M); - D⁻ʸ[:,1] .= zero(M); - D⁻ˣ[1,:] .= zero(M); - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2); - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2); - # Update - φ .= @. φ - Δt*(max(V,0)*∇⁺ + min(V,0)*∇⁻); - return nothing -end - -""" - Single step for first order upwind method for reinitialisation equation (2D) -""" -function reinit!(φ::T,φ_tmp::T,S::T,Δ::NTuple{2,M},Δt::M,caches) where {M,T<:Array{M,2}} - D⁺ʸ,D⁺ˣ,D⁻ʸ,D⁻ˣ,∇⁺,∇⁻=caches - Δx,Δy = Δ - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)); - circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)); - # Forward (+) & Backward (-) - D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; - D⁺ˣ .= @. (D⁺ˣ - φ)/Δx; - D⁻ʸ .= @. (φ - D⁻ʸ)/Δy; - D⁻ˣ .= @. (φ - D⁻ˣ)/Δx; - # Check for boundaries with ghost nodes - D⁺ʸ[:,end] .= zero(M); - D⁺ˣ[end,:] .= zero(M); - D⁻ʸ[:,1] .= zero(M); - D⁻ˣ[1,:] .= zero(M); - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2); - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2); - # Update - φ_tmp .= @. φ - Δt*(max(S,0)*∇⁺ + min(S,0)*∇⁻ - S); - return nothing -end - -""" - Single step for first order upwind method for H-J equation (3D) -""" -function advect!(φ::T,V::T,Δ::NTuple{3,M},Δt::M,caches) where {M,T<:Array{M,3}} - D⁺ʸ,D⁺ˣ,D⁻ʸ,D⁻ˣ,∇⁺,∇⁻=caches - Δx,Δy,Δz = Δ - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1,0)); circshift!(D⁻ʸ,φ,(0,1,0)); - circshift!(D⁺ˣ,φ,(-1,0,0)); circshift!(D⁻ˣ,φ,(1,0,0)); - circshift!(D⁺ᶻ,φ,(0,0,-1)); circshift!(D⁻ᶻ,φ,(0,0,1)); - # Forward (+) & Backward (-) - D⁺ʸ .= (D⁺ʸ - φ)/Δy; - D⁺ˣ .= (D⁺ˣ - φ)/Δx; - D⁺ᶻ .= (D⁺ᶻ - φ)/Δz; - D⁻ʸ .= (φ - D⁻ʸ)/Δy; - D⁻ˣ .= (φ - D⁻ˣ)/Δx; - D⁻ᶻ .= (φ - D⁻ᶻ)/Δz; - # Check for boundaries with ghost nodes - D⁺ʸ[:,end,:] .= zero(M); - D⁺ˣ[end,:,:] .= zero(M); - D⁺ᶻ[:,:,end] .= zero(M); - D⁻ʸ[:,1,:] .= zero(M); - D⁻ˣ[1,:,:] .= zero(M); - D⁻ᶻ[:,:,1] .= zero(M); - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2); - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2); - # Update - φ .= @. φ - Δt*(max(V,0)*∇⁺ + min(V,0)*∇⁻); - return nothing -end - -""" - Single step for first order upwind method for reinitialisation equation (3D) -""" -function reinit!(φ::T,φ_tmp::T,S::T,Δ::NTuple{3,M},Δt::M) where {M,T<:Array{M,3}} - D⁺ʸ,D⁺ˣ,D⁻ʸ,D⁻ˣ,∇⁺,∇⁻=caches - Δx,Δy,Δz = Δ - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1,0)); circshift!(D⁻ʸ,φ,(0,1,0)); - circshift!(D⁺ˣ,φ,(-1,0,0)); circshift!(D⁻ˣ,φ,(1,0,0)); - circshift!(D⁺ᶻ,φ,(0,0,-1)); circshift!(D⁻ᶻ,φ,(0,0,1)); - # Forward (+) & Backward (-) - D⁺ʸ .= (D⁺ʸ - φ)/Δy; - D⁺ˣ .= (D⁺ˣ - φ)/Δx; - D⁺ᶻ .= (D⁺ᶻ - φ)/Δz; - D⁻ʸ .= (φ - D⁻ʸ)/Δy; - D⁻ˣ .= (φ - D⁻ˣ)/Δx; - D⁻ᶻ .= (φ - D⁻ᶻ)/Δz; - # Check for boundaries with ghost nodes - D⁺ʸ[:,end,:] .= zero(M); - D⁺ˣ[end,:,:] .= zero(M); - D⁺ᶻ[:,:,end] .= zero(M); - D⁻ʸ[:,1,:] .= zero(M); - D⁻ˣ[1,:,:] .= zero(M); - D⁻ᶻ[:,:,1] .= zero(M); - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2); - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2); - # Update - φ_tmp .= @. φ - Δt*(max(S,0)*∇⁺ + min(S,0)*∇⁻ - S); - return nothing -end - -function advect!(φ::T,V::T,model::D,Δ::NTuple{N,M},γ::M,max_steps::Int) where {N,M, - T<:PVector{Vector{M}},D<:DistributedDiscreteModel} - ## CFL Condition (requires γ≤1.0) - Δt = γ*min(Δ...)/(eps(M)^2+infnorm(V)) - # Find part size and location of boundaries with ghost nodes - part_size,g_loc = map(ghost_values(φ),local_views(model)) do φ_ghost,model - part_size = size(model.grid.node_coords) - g_loc = find_part_ghost_boundaries(φ_ghost,part_size) - part_size,g_loc - end |> tuple_of_arrays - for _ ∈ Base.OneTo(max_steps) - # Apply operations across partitions - map(local_views(φ),local_views(V),part_size,g_loc) do φ,V,part_size,g_loc - # Step of 1st order upwind H-J evolution equation - advect_step!(reshape(φ,part_size),reshape(V,part_size),g_loc,Δ,Δt) - end - # Update ghost nodes - consistent!(φ) |> fetch - end -end - -function reinit!(φ::T,model::D,Δ::NTuple{N,M},γ::M,max_steps::Int,tol::M,caches) where {N,M, - T<:PVector{Vector{M}},D<:DistributedDiscreteModel} - # Initalise φ_tmp - φ_tmp = zero(φ) # <- cache me - # Compute approx sign function S - ∏Δ = prod(Δ); - S = zero(φ) # <- cache me - map(local_views(S),local_views(φ)) do S,φ - S .= @. φ/sqrt(φ^2 + ∏Δ) - end - ## CFL Condition (requires γ≤0.5) - Δt = γ*min(Δ...) - part_size = map(local_views(model)) do model # <- in setup - get_cartesian_descriptor(model).partition .+ 1 - end - # Apply operations across partitions - for _ ∈ Base.OneTo(max_steps) - # Step of 1st order upwind reinitialisation equation - map(local_views(φ),local_views(φ_tmp),local_views(S),part_size) do φ,φ_tmp,S,part_size - reinit_step!(reshape(φ,part_size),reshape(φ_tmp,part_size),reshape(S,part_size),Δ,Δt,caches) - end - # Update ghost nodes - consistent!(φ_tmp) |> fetch - # Check convergence |φ-φ_tmp|<ε - if infnorm(φ-φ_tmp) fetch - end -end \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/MainMPI.jl b/Deprecated/Deprecated_root_files/MainMPI.jl deleted file mode 100755 index 650b3b68..00000000 --- a/Deprecated/Deprecated_root_files/MainMPI.jl +++ /dev/null @@ -1,59 +0,0 @@ -using SparseMatricesCSR -using SparseArrays -using Gridap, Gridap.TensorValues, Gridap.Geometry -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using DelimitedFiles -using LinearAlgebra -using Printf - -import GridapDistributed.DistributedCellField -import GridapDistributed.DistributedFESpace -import GridapDistributed.DistributedDiscreteModel -import GridapDistributed.DistributedMeasure - -include("Utilities.jl"); -include("LevelSet.jl"); -include("Setup.jl"); -include("ProjectionMethod.jl"); -# Currently, to switch between augmented Lagrangian method and -# Hilbertian projection method for constrained optimisation -# replace "OptimiseALM.jl" with "OptimiseHPM.jl". This will -# change later. -include("OptimiseALM.jl"); - -const mesh_partition = length(ARGS) == 3 ? parse.(Int,(ARGS[2],ARGS[3])) : - length(ARGS) == 4 ? parse.(Int,(ARGS[2],ARGS[3],ARGS[4])) : - error("mesh_partition should be of length 2 or 3"); - -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # Set PETSc options - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - # Get setup function and check exists - setup = getfield(Main, Symbol(ARGS[1])) - @assert @isdefined(setup) && isa(setup,Function) "Setup not defined" - # Create results path - ptn_str = replace(string(mesh_partition),"("=>"",")"=>"",", "=>"x") - path = "$(pwd())/Results_p$(ptn_str)_$setup" - if i_am_main(ranks) - !isdir(path) ? mkdir(path) : rm(path,recursive=true); - !isdir(path) ? mkdir(path) : 0; - end - # Run and time - t = PTimer(ranks) - tic!(t) - GridapPETSc.with(args=split(options)) do - optimise(ranks,mesh_partition,setup,path) - end - toc!(t,"Run time") - t -end - -t = with_mpi() do distribute - main(mesh_partition,distribute) -end -display(t) diff --git a/Deprecated/Deprecated_root_files/OptimiseALM.jl b/Deprecated/Deprecated_root_files/OptimiseALM.jl deleted file mode 100755 index a1830a0d..00000000 --- a/Deprecated/Deprecated_root_files/OptimiseALM.jl +++ /dev/null @@ -1,68 +0,0 @@ -function optimise(ranks,mesh_partition,setup::Function,path::String) - ### Get parameters - prob,obj,lsf,vf,mat,g,fe_order,coord_max,el,η_coeff, - α_coeff,_,_,_,γ,steps,reinit_tol = setup() - vol_D = prod(coord_max); - Δ = coord_max./el # Element size - η = η_coeff*maximum(Δ); α = α_coeff*maximum(Δ) # Smoothing parameters - interp = SmoothErsatzMaterialInterpolation(η=η) # Material interpolation - λ = -0.01; Λ = 100; ζ = 0.9; # Augmented Lagrangian parameters - ### Setup FE data - model,Ω,V_φ,solve_data,hilb_data = prob(ranks,mesh_partition,fe_order,coord_max,el,α) - ### Setup level set - φh = interpolate(lsf,V_φ) - φ = get_free_dof_values(φh) - reinit!(φ,model,Δ,0.5,2000,reinit_tol) - ### Main loop - history = NaN*zeros(1000,3); - for it in 1:1000 - ## Calculate objective and constraints - J_new,v_J,uh = obj(φh,g,mat,solve_data,interp) - C_new,v_C = vol(φh,interp,solve_data.dΩ,solve_data.V_L2,vol_D) - L_new = J_new - λ*(C_new - vf) + 1/(2Λ)*(C_new - vf)^2 - ## Log - history[it,:] = [J_new,C_new,L_new] - if i_am_main(ranks) - println("it: ",it," | J: ",round(J_new;digits=5)," | ","Vol: ",round(C_new;digits=5)) - println("λ = ",λ," Λ = ",Λ) - writedlm("$path/history.csv",history[1:it,:]) - end - isone(it) || iszero(it % 30) ? write_vtk(Ω,"$path/struc_$it",φh,uh,interp.H) : 0 - # write_vtk(Ω,"$path/struc_$it",φh,uh,interp.H) - ## Check stopping criteria - if it > 10 && all(@.(abs(L_new-history[it-5:it-1,3])) .< 1/5/maximum(el)*L_new) && - abs(C_new-vf) < 0.0001 - write_vtk(Ω,"$path/struc_$it",φh,uh,interp.H) - break - end - ## Extend shape sensitivities - ext_v_J = hilbertian_ext(v_J,φh,hilb_data,interp) |> get_free_dof_values - ext_v_C = hilbertian_ext(v_C,φh,hilb_data,interp) |> get_free_dof_values - # Augmented Lagrangian method - λ -= 1/Λ*(C_new - vf); - iszero(it % 5) ? Λ *= ζ : 0; - v_Lh = FEFunction(hilb_data.U_reg,ext_v_J - λ*ext_v_C + 1/Λ*(C_new - vf)*ext_v_C) - v_Lh_full = interpolate(v_Lh,V_φ) - g_Ω = get_free_dof_values(v_Lh_full); - ## Advect & Reinitialise - advect!(φ,g_Ω,model,Δ,γ,steps) - reinit!(φ,model,Δ,0.5,2000,reinit_tol) - end -end - -# Hilbertian extension-regulariation -function hilbertian_ext(vh::DistributedCellField,φh::DistributedCellField,hilb_data::NT, - interp::T) where {T<:SmoothErsatzMaterialInterpolation,NT<:NamedTuple} - ## Unpack - dΩ=hilb_data.dΩ; K=hilb_data.K; DH = interp.DH - ## Linear Form - J′(v) = ∫(-vh*v*(DH ∘ φh)*(norm ∘ ∇(φh)))dΩ; - ## Assembly - b = assemble_vector(J′,hilb_data.assem,hilb_data.V_reg) - op = AffineFEOperator(hilb_data.U_reg,hilb_data.V_reg,K,b) - ## Solve - ls = PETScLinearSolver() - xh = solve(ls,op) - x = correct_ghost_layout(xh,K.col_partition) - return FEFunction(hilb_data.U_reg,x) -end \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/OptimiseHPM.jl b/Deprecated/Deprecated_root_files/OptimiseHPM.jl deleted file mode 100755 index 70f177d6..00000000 --- a/Deprecated/Deprecated_root_files/OptimiseHPM.jl +++ /dev/null @@ -1,89 +0,0 @@ -function optimise(ranks,mesh_partition,setup::Function,path::String) - ### Get parameters - prob,obj,lsf,vf,mat,g,fe_order,coord_max,el,η_coeff, - α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol = setup() - vol_D = prod(coord_max); - Δ = coord_max./el # Element size - η,α = [η_coeff*maximum(Δ),α_coeff*maximum(Δ)] # Smoothing parameters - interp = SmoothErsatzMaterialInterpolation(η=η) # Material interpolation - HPM = HilbertianProjectionMethod{Float64}() # Projection method - ### Setup FE data - model,Ω,V_φ,solve_data,hilb_data = prob(ranks,mesh_partition,fe_order,coord_max,el,α) - ### Setup level set - φh = interpolate(lsf,V_φ) - φ = get_free_dof_values(φh) - reinit!(φ,model,Δ,0.1,2000,reinit_tol) - φ0 = zero(φ); φ0 .= φ; - ### Main loop - J_new,_,uh = obj(φh,g,mat,solve_data,interp) - C_new,_ = vol(φh,interp,solve_data.dΩ,solve_data.V_L2,vol_D) - history = NaN*zeros(1000,2); - history[1,:] = [J_new,C_new] - i_am_main(ranks) ? println("it: ",0," | J: ", - round(J_new;digits=5)," | ","Vol: ",round(C_new;digits=5)) : 0 - write_vtk(Ω,"$path/struc_0",φh,uh,interp.H) - for it in 1:1000 - ## Create temp level set structure and other objects - φ0 .= φ; - consistent!(φ0) |> fetch - J,C = [copy(J_new),copy(C_new)]; - ## Calculate shape sensitivities and apply constraint method - _,v_J,uh = obj(φh,g,mat,solve_data,interp) - _,v_C = vol(φh,interp,solve_data.dΩ,solve_data.V_L2,vol_D) - ext_v_J = hilbertian_ext(v_J,φh,hilb_data,interp) - ext_v_C = hilbertian_ext(v_C,φh,hilb_data,interp) - θn_h = project(get_free_dof_values(ext_v_J),[C-vf],[get_free_dof_values(ext_v_C)], - hilb_data.K,hilb_data.U_reg,HPM) - θn_h_full = interpolate(θn_h,V_φ) - g_Ω = get_free_dof_values(θn_h_full); - ## Line search - for k ∈ 1:10 - ## Advect & Reinitialise - advect!(φ,g_Ω,model,Δ,γ,steps) - reinit!(φ,model,Δ,0.1,2000,reinit_tol) - ## Calcuate new objective and constraints - J_new,_,uh = obj(φh,g,mat,solve_data,interp) - C_new,_ = vol(φh,interp,solve_data.dΩ,solve_data.V_L2,vol_D) - ## Reduce line search parameter if constraints close to saturation - _μ = abs(C_new-vf) < 0.01 ? μ/10 : μ - if J_new < J + _μ*abs(J) || γ <= γ_min ## Accept - γ = min(1.1*γ,γ_max) - break - else ## Reject - γ = max(0.7*γ,γ_min) - φ .= φ0 - consistent!(φ) |> fetch - end - end - ## Log - history[it,:] = [J_new,C_new] - if i_am_main(ranks) - println("it: ",it," | J: ",round(J_new;digits=5)," | ","Vol: ",round(C_new;digits=5)) - writedlm("$path/history.csv",history[1:it,:]) - end - isone(it) || iszero(it % 30) ? write_vtk(Ω,"$path/struc_$it",φh,uh,interp.H) : 0 - ## Check stopping criteria - if it > 10 && all(@.(abs(J_new-history[it-5:it-1,1])) .< 1/5/maximum(el)*J_new) && - abs(C_new-vf) < 0.0001 - write_vtk(Ω,"$path/struc_$it",φh,uh,interp.H) - break - end - end -end - -# Hilbertian extension-regulariation -function hilbertian_ext(vh::DistributedCellField,φh::DistributedCellField,hilb_data::NT, - interp::T) where {T<:SmoothErsatzMaterialInterpolation,NT<:NamedTuple} - ## Unpack - dΩ=hilb_data.dΩ; K=hilb_data.K; DH = interp.DH - ## Linear Form - J′(v) = ∫(-vh*v*(DH ∘ φh)*(norm ∘ ∇(φh)))dΩ; - ## Assembly - b = assemble_vector(J′,hilb_data.assem,hilb_data.V_reg) - op = AffineFEOperator(hilb_data.U_reg,hilb_data.V_reg,K,b) - ## Solve - ls = PETScLinearSolver() - xh = solve(ls,op) - x = correct_ghost_layout(xh,K.col_partition) - return FEFunction(hilb_data.U_reg,x) -end \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/ProjectionMethod.jl b/Deprecated/Deprecated_root_files/ProjectionMethod.jl deleted file mode 100755 index 4283d972..00000000 --- a/Deprecated/Deprecated_root_files/ProjectionMethod.jl +++ /dev/null @@ -1,144 +0,0 @@ -Base.@kwdef struct HilbertianProjectionMethod{M<:AbstractFloat} - λ::M = M(0.5) - α_min::M = M(0.1) - α_max::M = M(1.0) -end - -ip(u::T1,K::T2,v::T3) where {T1<:AbstractArray,T2<:AbstractMatrix,T3<:AbstractArray} = dot(u,K*v) - -function project(V::VT,Cᵥ::Vector{M},C::P,B::T,VSpace::VS,m::HilbertianProjectionMethod{M}) where - {M<:AbstractFloat,VT<:PVector{Vector{M}},P<:Vector{<:PVector{Vector{M}}},T<:PSparseMatrix,VS<:DistributedFESpace} - # Get Data - λ = m.λ; α_min = m.α_min; α_max = m.α_max; - # Orthogonalisation - C_orthog,nullity,len_sq=gram_schmidt_orthog(C,B) - C_len = sqrt.(len_sq); - # Check norm and nullity - k = length(C_orthog) - orth_norm = zeros(k,k); - for i = Base.OneTo(k), j = Base.OneTo(k) - orth_norm[i,j] = ip(C_orthog[i],B,C_orthog[j]) - end - orth_norm[diagind(orth_norm)].=0; - # Project V - V,norm_PCperp_V = project_V(V,C_orthog,len_sq,B) - p_norm = ip.([V],[B],C_orthog) - # Calculate αᵢ - α = copy(Cᵥ); - compute_α!(α,C_orthog,C,len_sq,C_len,B) - ∑α² =λ^2*dot(α,α); - # Printing and check ∑α² and update λ if required - # i_am_main(ranks) - # print("\n ↱----------------------------------------------------------↰\n") - # printstyled(" Orthogonalisation method: gram_schmidt_orthog ",color=:yellow); - # @printf("\n --> Orthogonality inf-norm: %e\n",norm(orth_norm,Inf)) - # @printf(" --> Projection inf-norm: %e\n",(norm(p_norm,Inf))) - # println(" --> Basis nullity: ",nullity) - # end - if ∑α² ≈ zero(M) - # i_am_main(ranks) ? println(" --> Constraints satisfied: ∑α² ≈ 0.") : 0; - elseif ∑α² > α_max - λ *= sqrt(α_max/∑α²) - ∑α² = α_max - # i_am_main(ranks) ? @printf(" --> ∑α² > α_max, scaling λ: %e\n",λ) : 0; - elseif ∑α² < α_min - λ *= sqrt(α_min/∑α²) - ∑α² = α_min - # i_am_main(ranks) ? @printf(" --> ∑α² < α_max, scaling λ: %e\n",λ) : 0; - end - # i_am_main(ranks) ? print(" ↳----------------------------------------------------------↲\n") : 0; - α .*= λ - # Calculate direction - idx_non_zero = (Base.OneTo(k))[.~iszero.(C_len)] - θₙ = sqrt(1-∑α²)*V/norm_PCperp_V + sum(α[i] * C_orthog[i] / C_len[i] for i ∈ idx_non_zero) - consistent!(θₙ) |> fetch - return FEFunction(VSpace,θₙ) -end - -# Compute α ignoring λ for now -function compute_α!(α::Vector{M},C_orthog::P,C::P,len_sq::Vector{M},C_len::Vector{M},B::T) where { - M<:AbstractFloat,P<:Vector{<:PVector{Vector{M}}},T<:PSparseMatrix} - k = length(C_orthog); - for i ∈ Base.OneTo(k) - if iszero(len_sq[i]) - α[i] = zero(M) - else - for j = 1:i-1 - if ~iszero(len_sq[j]) - # αᵢ|̄vᵢ| = λCᵢ - ∑ⱼ₌₁ⁱ⁻¹[ αⱼ(̄vⱼ⋅vᵢ)/|̄vⱼ| ] - α[i] -= α[j]*ip(C_orthog[j],B,C[i])/C_len[j] - end - end - α[i] /= C_len[i] # |̄vᵢ| - end - end - return nothing -end - -# Form projection operator for C⟂ of V: P_C⟂_V = V - ∑[(̄vᵢ ⋅ m)/|̄vᵢ|² ̄vᵢ] where ̄vᵢ spans C and ̄vᵢ ⋅ ̄vⱼ = δᵢⱼ -# Return norm of projected V -function project_V(V::VT,C_orthog::P,len_sq::Vector{M},B::T) where {M<:AbstractFloat,VT<:PVector{Vector{M}}, - P<:Vector{<:PVector{Vector{M}}},T<:PSparseMatrix} - k = length(C_orthog); - for i ∈ Base.OneTo(k) - if ~iszero(len_sq[i]) - V -= ip(C_orthog[i],B,V)/len_sq[i]*C_orthog[i] # [(̄vᵢ ⋅ m)/|̄vᵢ|² ̄vᵢ] - end - end - # Check if projected V is zero vector - consistent!(V) |> fetch - if sqrt(ip(V,B,V)) ≈ 0 - return V,one(M) - else - return V,sqrt(ip(V,B,V)) - end -end - -function gram_schmidt_orthog(C::P,B::T) where {M<:AbstractFloat,P<:Vector{<:PVector{Vector{M}}},T<:PSparseMatrix} - k = length(C); - nullity = 0; - len_sq= zeros(M,k); - tmp = zeros(M,k); - C_orthog = zero.(C) - for i ∈ Base.OneTo(k) - C_orthog[i] .= C[i] - consistent!(C_orthog[i]) |> fetch - end - # Loop - len_sq[1] = ip(C_orthog[1],B,C_orthog[1]); # |̄v₁|² - for i = 2:k - len_sq[i] = ip(C_orthog[i],B,C_orthog[i]); # |̄vᵢ|² - for j = 1:i-1 - if iszero(len_sq[j]) - # V: The j_th vector in the sum is linearly dependent with previous vectors so ignore it - continue - end - tmp[j] = ip(C_orthog[j],B,C_orthog[i]); # vᵢ ⋅ ̄vⱼ - end - for j = 1:i-1 - if iszero(len_sq[j]) - # V: The j_th vector in the sum is linearly dependent with previous vectors so ignore it - continue - end - # ̄vᵢ = vᵢ - ∑ⱼ₌₁ⁱ⁻¹ [(vᵢ ⋅ ̄vⱼ)/|̄vⱼ|² ̄vⱼ] - C_orthog[i] = C_orthog[i] - tmp[j]*C_orthog[j]/len_sq[j] - end - - # Check for a linear dependency - if len_sq[i] < 10^-14 - nullity += 1 - len_sq[i] = zero(M) - C_orthog[i] = zero(C_orthog[i]) - elseif ip(C_orthog[i],B,C_orthog[i])/len_sq[i] < 10^-14 - nullity += 1 - len_sq[i] = zero(M) - C_orthog[i] = zero(C_orthog[i]) - else - len_sq[i] = ip(C_orthog[i],B,C_orthog[i]) - end - end - for i ∈ Base.OneTo(k) - consistent!(C_orthog[i]) |> fetch - end - C_orthog,nullity,len_sq -end \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/Setup.jl b/Deprecated/Deprecated_root_files/Setup.jl deleted file mode 100755 index 7f0d5217..00000000 --- a/Deprecated/Deprecated_root_files/Setup.jl +++ /dev/null @@ -1,444 +0,0 @@ -## User defined setups - -########################## -# Thermal Compliance # -########################## -## Objective and shape sensitivity -function li2019_mumps_setup(ksp) - pc = Ref{GridapPETSc.PETSC.PC}() - mumpsmat = Ref{GridapPETSc.PETSC.Mat}() - @check_error_code GridapPETSc.PETSC.KSPView(ksp[],C_NULL) - @check_error_code GridapPETSc.PETSC.KSPSetType(ksp[],GridapPETSc.PETSC.KSPPREONLY) - @check_error_code GridapPETSc.PETSC.KSPGetPC(ksp[],pc) - @check_error_code GridapPETSc.PETSC.PCSetType(pc[],GridapPETSc.PETSC.PCLU) - @check_error_code GridapPETSc.PETSC.PCFactorSetMatSolverType(pc[],GridapPETSc.PETSC.MATSOLVERMUMPS) - @check_error_code GridapPETSc.PETSC.PCFactorSetUpMatSolverType(pc[]) - @check_error_code GridapPETSc.PETSC.PCFactorGetMatrix(pc[],mumpsmat) - @check_error_code GridapPETSc.PETSC.MatMumpsSetIcntl(mumpsmat[], 4, 1) - @check_error_code GridapPETSc.PETSC.MatMumpsSetIcntl(mumpsmat[], 7, 0) - # @check_error_code GridapPETSc.PETSC.MatMumpsSetIcntl(mumpsmat[], 14, 1000) - @check_error_code GridapPETSc.PETSC.MatMumpsSetIcntl(mumpsmat[], 28, 2) - @check_error_code GridapPETSc.PETSC.MatMumpsSetIcntl(mumpsmat[], 29, 2) - @check_error_code GridapPETSc.PETSC.MatMumpsSetCntl(mumpsmat[], 3, 1.0e-6) -end - -function thermal_compliance(φh::DistributedCellField,g,D::M,solve_data::NT,interp::T) where { - M<:AbstractFloat,T<:SmoothErsatzMaterialInterpolation,NT<:NamedTuple} - I = interp.I; dΩ=solve_data.dΩ; dΓ_N=solve_data.dΓ_N; - ## Weak form - a(u,v) = ∫((I ∘ φh)*D*∇(u)⋅∇(v))dΩ - l(v) = ∫(v*g)dΓ_N - ## Assembly - op = AffineFEOperator(a,l,solve_data.U,solve_data.V,solve_data.assem) - K = op.op.matrix; - ## Solve - ls = PETScLinearSolver(li2019_mumps_setup) - uh = solve(ls,op) - u = correct_ghost_layout(uh,K.col_partition) - ## Compute J and v_J - J = dot(u,(K*u)) - v_J = interpolate(-D*∇(uh)⋅∇(uh),solve_data.V_L2) - return J,v_J,uh -end - -## Problem setups -function pipe_setup_2d() - ## FE setup name and objective - prob = pipe_2d - obj = thermal_compliance - vf = 0.5; # Required volume fraction - ## Material and loading - D = 1.0 # Thermal coefficient - g = 1.0; # Heat flow - ## FE Parameters - fe_order = 1; - coord_max=(1.0,1.0); - el=(800,800); # Elements in axial directions - ## LS Paramters - lsf = gen_lsf(4,0.2); # Initial LSF - η_coeff = 2 # Interpolation radius coefficent - α_coeff = 4 # Hilbertian smoothing coefficent - μ=0.005 # Line search parameter - γ,γ_min,γ_max = [0.05,0.001,0.1] # CFL Coefficent - steps = Int(floor(minimum(el)/10)) # Finite diff. steps - reinit_tol = min(4*prod(inv,el),10^-4) # Reinit tol. - - return prob,obj,lsf,vf,D,g,fe_order,coord_max,el, - η_coeff,α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol -end - -function pipe_setup_3d() - ## FE setup name - prob = pipe_3d - obj = thermal_compliance - vf = 0.5; # Required volume fraction - ## Material and loading - D = 1.0 # Thermal coefficient - g = 3.0 # Heat flow - ## FE Parameters - fe_order = 1; - coord_max=(1.0,1.0,1.0); - el=(100,100,100); # Elements in axial directions - ## LS Paramters - lsf = gen_lsf(4,0.2); # Initial LSF - η_coeff = 2 # Interpolation radius coefficent - α_coeff = 4 # Hilbertian smoothing coefficent - μ=0.005 # Line search parameter - γ,γ_min,γ_max = [0.1,0.001,0.1] # CFL Coefficent - steps = Int(floor(minimum(el)/3)); # Finite diff. steps - reinit_tol = min(1000*prod(inv,el),10^-3) # Reinit tol. - - return prob,obj,lsf,vf,D,g,fe_order,coord_max,el, - η_coeff,α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol -end - -function pipe_2d(ranks,mesh_partition,order::T,coord_max::NTuple{2,M}, - el_size::NTuple{2,T},α::M) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - xmax,ymax = coord_max - prop_Γ_N,prop_Γ_D = [0.4,0.2] - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || - x[2] >= ymax-ymax*prop_Γ_D - eps())) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,coord_max,"Gamma_D") - update_labels!(2,model,f_Γ_N,coord_max,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;conformity=:H1, - dirichlet_tags=["Gamma_D"],dirichlet_masks=[true]) - U = TrialFESpace(V,[0.0]) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - V_L2 = TestFESpace(model,reffe;conformity=:L2) - # Space in Hilb. ext.-reg. endowed with H-regularity - V_reg = TestFESpace(model,reffe;conformity=:H1, - dirichlet_tags=["Gamma_N"],dirichlet_masks=[true]) - U_reg = TrialFESpace(V_reg,[0.0]) - # FE space for LSF - V_φ = TestFESpace(model,reffe;conformity=:H1) - ## Build stiffness matrix for Hilbertian ext-reg - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=dΓ_N) - hilb_data = (U_reg=U_reg,V_reg=V_reg,assem=Hilb_assem,dΩ=dΩ,K=K) - return model,Ω,V_φ,solve_data,hilb_data -end - -function pipe_3d(ranks,mesh_partition,order::T,coord_max::NTuple{3,M}, - el_size::NTuple{3,T},α::M) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2],0,coord_max[3]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - xmax,ymax,zmax = coord_max - prop_Γ_N = 0.4 - prop_Γ_D = 0.2 - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || - x[2] >= ymax-ymax*prop_Γ_D - eps()) && (x[3] <= zmax*prop_Γ_D + eps() || - x[3] >= zmax-zmax*prop_Γ_D - eps())) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps() && zmax/2-zmax*prop_Γ_N/4 - eps() <= x[3] - <= zmax/2+zmax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,coord_max,"Gamma_D") - update_labels!(2,model,f_Γ_N,coord_max,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;conformity=:H1, - dirichlet_tags=["Gamma_D"],dirichlet_masks=[true]) - U = TrialFESpace(V,[0.0]) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - V_L2 = TestFESpace(model,reffe;conformity=:L2) - # Space in Hilb. ext.-reg. endowed with H-regularity - V_reg = TestFESpace(model,reffe;conformity=:H1, - dirichlet_tags=["Gamma_N"],dirichlet_masks=[true]) - U_reg = TrialFESpace(V_reg,[0.0]) - # FE space for LSF - V_φ = TestFESpace(model,reffe;conformity=:H1) - ## Build stiffness matrix for Hilbertian ext-reg - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=dΓ_N) - hilb_data = (U_reg=U_reg,V_reg=V_reg,assem=Hilb_assem,dΩ=dΩ,K=K) - return model,Ω,V_φ,solve_data,hilb_data -end - -function pipe2_setup_3d() - ## FE setup name - prob = pipe2_3d - obj = thermal_compliance - vf = 0.3; # Required volume fraction - ## Material and loading - D = 1.0 # Thermal coefficient - g = 5.0 # Heat flow - ## FE Parameters - fe_order = 1; - coord_max=(1.0,1.0,1.0); - el=(100,100,100); # Elements in axial directions - ## LS Paramters - lsf = gen_lsf(2,0.4); # Initial LSF - η_coeff = 2 # Interpolation radius coefficent - α_coeff = 4 # Hilbertian smoothing coefficent - μ=0.005 # Line search parameter - γ,γ_min,γ_max = [0.1,0.001,0.1] # CFL Coefficent - steps = Int(floor(minimum(el)/3)); # Finite diff. steps - reinit_tol = min(1000*prod(inv,el),10^-3) # Reinit tol. - - return prob,obj,lsf,vf,D,g,fe_order,coord_max,el, - η_coeff,α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol -end - -function pipe2_3d(ranks,mesh_partition,order::T,coord_max::NTuple{3,M}, - el_size::NTuple{3,T},α::M) where {T<:Integer,M<:AbstractFloat} - ## Model - @assert isone(coord_max[1]) && isone(coord_max[2]) && isone(coord_max[3]) - dom = (0,coord_max[1],0,coord_max[2],0,coord_max[3]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - f_Γ_D(x) = (max(abs(x[1]-0.2),abs(x[2]-0.5),abs(x[3]-0.5)) <= 0.05+eps() || - max(abs(x[1]-0.8),abs(x[2]-0.5),abs(x[3]-0.5)) <= 0.05+eps() || - max(abs(x[1]-0.5),abs(x[2]-0.2),abs(x[3]-0.5)) <= 0.05+eps() || - max(abs(x[1]-0.5),abs(x[2]-0.8),abs(x[3]-0.5)) <= 0.05+eps()) ? true : false; - f_Γ_N(x) = (max(abs(x[1]),abs(x[2]),abs(x[3])) <= 0.05+eps() && (iszero(x[1]) || iszero(x[2]) || iszero(x[3])))|| - (max(abs(x[1]-1),abs(x[2]),abs(x[3])) <= 0.05+eps() && (isone(x[1]) || iszero(x[2]) || iszero(x[3])))|| - (max(abs(x[1]),abs(x[2]-1),abs(x[3])) <= 0.05+eps() && (iszero(x[1]) || isone(x[2]) || iszero(x[3])))|| - (max(abs(x[1]-1),abs(x[2]-1),abs(x[3])) <= 0.05+eps() && (isone(x[1]) || isone(x[2]) || iszero(x[3])))|| - (max(abs(x[1]),abs(x[2]),abs(x[3]-1)) <= 0.05+eps() && (iszero(x[1]) || iszero(x[2]) || isone(x[3])))|| - (max(abs(x[1]-1),abs(x[2]),abs(x[3]-1)) <= 0.05+eps() && (isone(x[1]) || iszero(x[2]) || isone(x[3])))|| - (max(abs(x[1]),abs(x[2]-1),abs(x[3]-1)) <= 0.05+eps() && (iszero(x[1]) || isone(x[2]) || isone(x[3])))|| - (max(abs(x[1]-1),abs(x[2]-1),abs(x[3]-1)) <= 0.05+eps() && (isone(x[1]) || isone(x[2]) || isone(x[3]))) ? true : false; - update_labels!(1,model,f_Γ_D,coord_max,"Gamma_D") - update_labels!(2,model,f_Γ_N,coord_max,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;conformity=:H1, - dirichlet_tags=["Gamma_N","Gamma_D"],dirichlet_masks=[true,true]) - U = TrialFESpace(V,[0.0,0.0]) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - V_L2 = TestFESpace(model,reffe;conformity=:L2) - # Space in Hilb. ext.-reg. endowed with H-regularity - V_reg = TestFESpace(model,reffe;conformity=:H1, - dirichlet_tags=["Gamma_N","Gamma_D"],dirichlet_masks=[true,true]) - U_reg = TrialFESpace(V_reg,[0.0,0.0]) - # FE space for LSF - V_φ = TestFESpace(model,reffe;conformity=:H1) - ## Build stiffness matrix for Hilbertian ext-reg - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=dΓ_N) - hilb_data = (U_reg=U_reg,V_reg=V_reg,assem=Hilb_assem,dΩ=dΩ,K=K) - return model,Ω,V_φ,solve_data,hilb_data -end - -########################## -# Elastic Compliance # -########################## -## Objective and shape sensitivity -function elastic_compliance(φh::DistributedCellField,g,C::S,solve_data::NT,interp::T) where { - S<:SymFourthOrderTensorValue,T<:SmoothErsatzMaterialInterpolation,NT<:NamedTuple} - I = interp.I; dΩ=solve_data.dΩ; dΓ_N=solve_data.dΓ_N; - ## Weak form - a(u,v) = ∫((I ∘ φh)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v) = ∫(v ⋅ g)dΓ_N - ## Solve finite element problem - op = AffineFEOperator(a,l,solve_data.U,solve_data.V,solve_data.assem) - K = op.op.matrix; - ## Solve - ls = PETScLinearSolver() - uh = solve(ls,op) - u = correct_ghost_layout(uh,K.col_partition) - ## Compute J and v_J - J = dot(u,(K*u)) - v_J = interpolate(-C ⊙ ε(uh) ⊙ ε(uh),solve_data.V_L2) - return J,v_J,uh -end - -function cantilever_setup_2d() - ## FE setup name - prob = cantilever_2d - obj = elastic_compliance - vf = 0.5; # Required volume fraction - ## Material and loading - C = isotropic_2d(1.0,0.3) # Stiffness tensor - g = VectorValue(0,-0.1); # Loading - ## FE Parameters - fe_order = 1; - coord_max=(2.0,1.0); - el=(800,400); # Elements in axial directions - ## LS Paramters - lsf = gen_lsf(4,0.2); # Initial LSF - η_coeff = 2 # Interpolation radius coefficent - α_coeff = 4 # Hilbertian smoothing coefficent - μ=0.005 # Line search parameter - γ,γ_min,γ_max = [0.1,0.001,0.1] # CFL Coefficent - steps = Int(floor(minimum(el)/10)) # Finite diff. steps - reinit_tol = min(4*prod(inv,el),10^-4) # Reinit tol. - - return prob,obj,lsf,vf,C,g,fe_order,coord_max,el, - η_coeff,α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol -end - -function cantilever_setup_3d() - ## FE setup name - prob = cantilever_3d - obj = elastic_compliance - vf = 0.5; # Required volume fraction - ## Material and loading - C = isotropic_3d(1.0,0.3) # Stiffness tensor - g = VectorValue(0,0,-0.1); # Loading - ## FE Parameters - fe_order = 1; - coord_max=(2.0,1.0,1.0); - el=(100,50,50); # Elements in axial directions - ## LS Paramters - lsf = gen_lsf(4,0.2); # Initial LSF - η_coeff = 2 # Interpolation radius coefficent - α_coeff = 4 # Hilbertian smoothing coefficent - μ=0.005 # Line search parameter - γ,γ_min,γ_max = [0.1,0.001,0.1] # CFL Coefficent - steps = Int(floor(minimum(el)/3)); # Finite diff. steps - reinit_tol = min(1000*prod(inv,el),10^-3) # Reinit tol. - - return prob,obj,lsf,vf,C,g,fe_order,coord_max,el, - η_coeff,α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol -end - -function cantilever_2d(ranks,mesh_partition,order::T,coord_max::NTuple{2,M}, - el_size::NTuple{2,T},α::M) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - xmax,ymax = coord_max - prop_Γ_N = 0.4 - f_Γ_D(x) = (x[1] ≈ 0.0) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,coord_max,"Gamma_D") - update_labels!(2,model,f_Γ_N,coord_max,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["Gamma_D"], - dirichlet_masks=[(true,true)],vector_type=Vector{PetscScalar}) - U = TrialFESpace(V,[VectorValue(0.0,0.0)]) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V_L2 = TestFESpace(model,reffe_scalar;conformity=:L2) - # Space in Hilb. ext.-reg. endowed with H-regularity - V_reg = TestFESpace(model,reffe_scalar;conformity=:H1, - dirichlet_tags=["Gamma_N"],dirichlet_masks=[true]) - U_reg = TrialFESpace(V_reg,[0.0]) - # FE space for LSF - V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) - ## Build stiffness matrix for Hilbertian ext-reg - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=dΓ_N) - hilb_data = (U_reg=U_reg,V_reg=V_reg,assem=Hilb_assem,dΩ=dΩ,K=K) - return model,Ω,V_φ,solve_data,hilb_data -end - -function cantilever_3d(ranks,mesh_partition,order::T,coord_max::NTuple{3,M}, - el_size::NTuple{3,T},α::M) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2],0,coord_max[3]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - xmax,ymax,zmax = coord_max - prop_Γ_N = 0.4 - f_Γ_D(x) = (x[1] ≈ 0.0) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps() && zmax/2-zmax*prop_Γ_N/4 - eps() <= x[3] - <= zmax/2+zmax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,coord_max,"Gamma_D") - update_labels!(2,model,f_Γ_N,coord_max,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["Gamma_D"], - dirichlet_masks=[(true,true,true)]) - U = TrialFESpace(V,[VectorValue(0.0,0.0,0.0)]) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V_L2 = TestFESpace(model,reffe_scalar;conformity=:L2) - # Space in Hilb. ext.-reg. endowed with H-regularity - V_reg = TestFESpace(model,reffe_scalar;conformity=:H1, - dirichlet_tags=["Gamma_N"],dirichlet_masks=[true]) - U_reg = TrialFESpace(V_reg,[0.0]) - # FE space for LSF - V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) - ## Build stiffness matrix for Hilbertian ext-reg - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=dΓ_N) - hilb_data = (U_reg=U_reg,V_reg=V_reg,assem=Hilb_assem,dΩ=dΩ,K=K) - return model,Ω,V_φ,solve_data,hilb_data -end - -########################## -# Volume # -########################## -function vol(φh::DistributedCellField,interp::T,dΩ::ME,V_L2::V,vol_D::M) where { - M<:AbstractFloat,T<:SmoothErsatzMaterialInterpolation, - V<:DistributedFESpace,ME<:DistributedMeasure} - ρ = interp.ρ; - vol = sum(∫(ρ ∘ φh)dΩ)/vol_D; - v_vol = interpolate(x->one(M)/vol_D,V_L2) - return vol,v_vol -end \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/Utilities.jl b/Deprecated/Deprecated_root_files/Utilities.jl deleted file mode 100755 index af5f0792..00000000 --- a/Deprecated/Deprecated_root_files/Utilities.jl +++ /dev/null @@ -1,136 +0,0 @@ -# Heaviside function -function H_η(t::M;η::M) where M<:AbstractFloat - if t<-η - return zero(M) - elseif abs(t)<=η - return M(1/2*(1+t/η+1/pi*sin(pi*t/η))) - elseif t>η - return one(M) - end -end - -function DH_η(t::M;η::M) where M<:AbstractFloat - if t<-η - return zero(M) - elseif abs(t)<=η - return M(1/2/η*(1+cos(pi*t/η))) - elseif t>η - return zero(M) - end -end - -# Material interpolation -Base.@kwdef struct SmoothErsatzMaterialInterpolation{M<:AbstractFloat} - η::M # Smoothing radius - ϵₘ::M = 10^-3 # Void material multiplier - H = x -> H_η(x,η=η) - DH = x -> DH_η(x,η=η) - I = φ -> (1 - H(φ)) + ϵₘ*H(φ) - ρ = φ -> 1 - H(φ) -end - -write_vtk(Ω,path,φh,uh,H) = writevtk(Ω,path,cellfields=["phi"=>φh, - "H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) - -# Update layout of ghost nodes to match columns of stiffness matrix -function correct_ghost_layout(xh::DistributedCellField,cols) - x_tmp = get_free_dof_values(xh) - x = pfill(0.0, cols) - map(local_views(own_values(x)),local_views(own_values(x_tmp))) do x,x_tmp - x .= x_tmp - end - consistent!(x) |> fetch - return x -end - -# Inf norm -function infnorm(a::PVector) - contibs = map(own_values(a)) do oid_to_value - norm(oid_to_value,Inf) - end - reduce(max,contibs;init=zero(eltype(contibs))) -end - -# Update label given function f_Γ. e should be the count of added tags. -function update_labels!(e::Int,model::D,f_Γ::F,::T,name::String) where { - M<:AbstractFloat,F<:Function,T<:NTuple{2,M},D<:DistributedDiscreteModel} - cell_to_entity = map(local_views(model)) do model - labels = get_face_labeling(model) - cell_to_entity = labels.d_to_dface_to_entity[end] - entity = maximum(cell_to_entity) + e - # Vertices - vtx_coords = model.grid_topology.vertex_coordinates - vtxs_Γ = findall(isone,f_Γ.(vtx_coords)) - vtx_edge_connectivity = Array(Geometry.get_faces(model.grid_topology,0,1)[vtxs_Γ]) - # Edges - edge_entries = [findall(x->any(x .∈ vtx_edge_connectivity[1:end.!=j]), - vtx_edge_connectivity[j]) for j = 1:length(vtx_edge_connectivity)] - edge_Γ = unique(reduce(vcat,getindex.(vtx_edge_connectivity,edge_entries),init=[])) - labels.d_to_dface_to_entity[1][vtxs_Γ] .= entity - labels.d_to_dface_to_entity[2][edge_Γ] .= entity - add_tag!(labels,name,[entity]) - cell_to_entity - end - cell_gids=get_cell_gids(model) - cache=GridapDistributed.fetch_vector_ghost_values_cache(cell_to_entity,partition(cell_gids)) - GridapDistributed.fetch_vector_ghost_values!(cell_to_entity,cache) -end - -function update_labels!(e::Int,model::D,f_Γ::F,::T,name::String) where { - M<:AbstractFloat,F<:Function,T<:NTuple{3,M},D<:DistributedDiscreteModel} - cell_to_entity = map(local_views(model)) do model - labels = get_face_labeling(model) - cell_to_entity = labels.d_to_dface_to_entity[end] - entity = maximum(cell_to_entity) + e - # Vertices - vtx_coords = model.grid_topology.vertex_coordinates - vtxs_Γ = findall(isone,f_Γ.(vtx_coords)) - vtx_edge_connectivity = Array(Geometry.get_faces(model.grid_topology,0,1)[vtxs_Γ]) - vtx_face_connectivity = Array(Geometry.get_faces(model.grid_topology,0,2)[vtxs_Γ]) - # Edges - edge_entries = [findall(x->any(x .∈ vtx_edge_connectivity[1:end.!=j]), - vtx_edge_connectivity[j]) for j = 1:length(vtx_edge_connectivity)] - edge_Γ = unique(reduce(vcat,getindex.(vtx_edge_connectivity,edge_entries),init=[])) - # Faces - face_entries = [findall(x->count(x .∈ vtx_face_connectivity[1:end.!=j])>2, - vtx_face_connectivity[j]) for j = 1:length(vtx_face_connectivity)] - face_Γ = unique(reduce(vcat,getindex.(vtx_face_connectivity,face_entries),init=[])) - labels.d_to_dface_to_entity[1][vtxs_Γ] .= entity - labels.d_to_dface_to_entity[2][edge_Γ] .= entity - labels.d_to_dface_to_entity[3][face_Γ] .= entity - add_tag!(labels,name,[entity]) - cell_to_entity - end - cell_gids=get_cell_gids(model) - cache=GridapDistributed.fetch_vector_ghost_values_cache(cell_to_entity,partition(cell_gids)) - GridapDistributed.fetch_vector_ghost_values!(cell_to_entity,cache) -end - -# Isotropic elasticity tensors -function isotropic_2d(E::M,ν::M) where M<:AbstractFloat - λ = E*ν/((1+ν)*(1-ν)); μ = E/(2*(1+ν)) - C = [λ+2μ λ 0 - λ λ+2μ 0 - 0 0 μ]; - SymFourthOrderTensorValue( - C[1,1], C[3,1], C[2,1], - C[1,3], C[3,3], C[2,3], - C[1,2], C[3,2], C[2,2]) -end - -function isotropic_3d(E::M,ν::M) where M<:AbstractFloat - λ = E*ν/((1+ν)*(1-2ν)); μ = E/(2*(1+ν)) - C =[λ+2μ λ λ 0 0 0 - λ λ+2μ λ 0 0 0 - λ λ λ+2μ 0 0 0 - 0 0 0 μ 0 0 - 0 0 0 0 μ 0 - 0 0 0 0 0 μ]; - return SymFourthOrderTensorValue( - C[1,1], C[6,1], C[5,1], C[2,1], C[4,1], C[3,1], - C[1,6], C[6,6], C[5,6], C[2,6], C[4,6], C[3,6], - C[1,5], C[6,5], C[5,5], C[2,5], C[4,5], C[3,5], - C[1,2], C[6,2], C[5,2], C[2,2], C[4,2], C[3,2], - C[1,4], C[6,4], C[5,4], C[2,4], C[4,4], C[3,4], - C[1,3], C[6,3], C[5,3], C[2,3], C[4,3], C[3,3]) -end \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/auto_diff_elastic_compliance_parallel.jl b/Deprecated/Deprecated_root_files/auto_diff_elastic_compliance_parallel.jl deleted file mode 100644 index 5816ae01..00000000 --- a/Deprecated/Deprecated_root_files/auto_diff_elastic_compliance_parallel.jl +++ /dev/null @@ -1,216 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.FESpaces, Gridap.Helpers -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR -using ChainRulesCore - -include("src/ChainRules.jl") -include("src/Utilities.jl") -include("src/MaterialInterpolation.jl") - -###################################################### -## FE Setup -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - order = 1; - el_size = (200,200); - dom = (0.,1.,0.,1.); - coord_max = dom[2],dom[4] - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - xmax,ymax = coord_max - prop_Γ_N = 0.4 - f_Γ_D(x) = (x[1] ≈ 0.0) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["Gamma_D"], - dirichlet_masks=[(true,true)],vector_type=Vector{PetscScalar}) - U = TrialFESpace(V,[VectorValue(0.0,0.0)]) - # Space for shape sensitivities - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - # FE space for LSF - V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) - # FE Space for shape derivatives - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0.0) - ###################################################### - eΔ = (xmax,ymax)./el_size; - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(eΔ)) - C = isotropic_2d(1.,0.3) - g = VectorValue(0.,-1.0) - φh = interpolate(x->-sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)+0.25,V_φ) - - ## Weak form - I = interp.I; - DH = interp.DH - - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v,φh,dΩ,dΓ_N) = ∫(v ⋅ g)dΓ_N - res(u,v,φ,dΩ,dΓ_N) = a(u,v,φ,dΩ,dΓ_N) - l(v,φ,dΩ,dΓ_N) - - ## Functionals J and DJ - J = (u,φ,dΩ,dΓ_N) -> a(u,u,φ,dΩ,dΓ_N) - DJ = (q,u,φ,dΩ,dΓ_N) -> ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; - state_map = AffineFEStateMap(a,l,res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - pcfs = PDEConstrainedFunctionals(J,Function[J],state_map,analytic_dC=[DJ]) - - φ = get_free_dof_values(φh) - j,c,dJ,dC = Gridap.evaluate!(pcfs,φ) - uh = get_state(pcfs) - - println("J = $j | C = $c") - - ## Shape derivative - # Autodiff - dF = dJ - # Analytic - dF_analytic = first(dC) - - abs_error = maximum(abs,dF-dF_analytic) - rel_error = (abs_error)/maximum(abs,dF_analytic) - - ## Hilb ext reg - α = 4*maximum(eΔ) - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - hilb_K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Autodiff result - op = AffineFEOperator(U_reg,V_reg,hilb_K,-dF) - dF_Ω = get_free_dof_values(solve(op)) - ## Analytic result - op = AffineFEOperator(U_reg,V_reg,hilb_K,-dF_analytic) - dF_analytic_Ω = get_free_dof_values(solve(op)) - - hilb_abs_error = maximum(abs,dF_Ω-dF_analytic_Ω) - hilb_rel_error = (hilb_abs_error)/maximum(abs,dF_analytic_Ω) - # path = dirname(dirname(@__DIR__))*"/results/AutoDiffTesting_Parallel"; - # writevtk(Ω,path,cellfields=["phi"=>φh, - # "H(phi)"=>(interp.H ∘ φh), - # "|nabla(phi)|"=>(norm ∘ ∇(φh)), - # "uh"=>uh, - # "J′_analytic"=>FEFunction(U_reg,dF_analytic), - # "J′_autodiff"=>FEFunction(U_reg,dF), - # "v_J_Ω"=>FEFunction(U_reg,dF_analytic_Ω), - # "dJφh_Ω"=>FEFunction(U_reg,dF_Ω) - # ]) - abs_error,rel_error,hilb_abs_error,hilb_rel_error -end - -out = with_debug() do distribute - main((3,3),distribute) -end - -#################### -# Debug Testing # -#################### -using BenchmarkTools -include("ChainRules.jl"); -function test(;run_as_serial::Bool=true) - ranks = with_debug() do distribute - distribute(LinearIndices((1,))) - end - - model = if run_as_serial - CartesianDiscreteModel((0,1,0,1),(2,2)) - else - CartesianDiscreteModel(ranks,(1,1),(0,1,0,1),(2,2)) - end - - Ω = Triangulation(model) - dΩ = Measure(Ω,2) - V_φ = FESpace(model,ReferenceFE(lagrangian,Float64,1)) - V_reg = FESpace(model,ReferenceFE(lagrangian,Float64,1),dirichlet_tags=["tag_1"]) - U_reg = TrialFESpace(V_reg,1) - φh = interpolate(x->1,V_φ); - φ = get_free_dof_values(φh) - - # FE Problem - V = FESpace(model,ReferenceFE(lagrangian,Float64,1),dirichlet_tags=["boundary"]) - U = TrialFESpace(V,2) - a(u,v,φ,dΩ) = ∫( φ*∇(v)⋅∇(u) )*dΩ - l(v,φ,dΩ) = ∫(v)*dΩ - res(u,v,φ,dΩ) = a(u,v,φ,dΩ) - l(v,φ,dΩ) - - J = (u,φ,dΩ) -> ∫(1+(u⋅u)*(u⋅u)+sqrt ∘ φ)dΩ - state_map = AffineFEStateMap(a,l,res,U,V,V_φ,U_reg,φh,dΩ) - pcfs = PDEConstrainedFunctionals(J,state_map) - - - j,c,dJ,dC = Gridap.evaluate!(pcfs,φ) - - println("J = $j | C = $c") - - ### Connor's implementation: - if run_as_serial - function _a(u,v,φ) - __φh = φ_to_φₕ(φ,V_φ) - a(u,v,__φh,dΩ) - end - function _l(v,φ) - __φh = φ_to_φₕ(φ,V_φ) - l(v,__φh,dΩ) - end - _a(φ) = (u,v) -> _a(u,v,φ) - _l(φ) = v -> _l(v,φ) - _res(u,v,φ) = _a(u,v,φ) - _l(v,φ) - - _φ_to_u = _AffineFEStateMap(_a,_l,_res,V_φ,U,V) - _u_to_j = LossFunction((u,φ) -> J(u,φ,dΩ),V_φ,U) - - _u, _u_pullback = rrule(_φ_to_u,φ) - _j, _j_pullback = rrule(_u_to_j,_u,φ) - _, _du, _dφ₍ⱼ₎ = _j_pullback(1) # dj = 1 - _, _dφ₍ᵤ₎ = _u_pullback(_du) - dφ_connor = _dφ₍ᵤ₎ + _dφ₍ⱼ₎ - if ~(V_φ === U_reg) - dφ_connor = get_free_dof_values(interpolate(FEFunction(V_φ,dφ_connor),U_reg)) - end - - return dJ,dJ-dφ_connor - else - return dJ,nothing - end -end - -_out_serial,_diff = test(run_as_serial=true); - -_out,_ = test(run_as_serial=false); - -@show norm(_out_serial-_out.vector_partition.items[1],Inf) - -""" -assemble_matrix_and_vector!: - - Line 310 Assemblers.jl: assemble_matrix_and_vector!(f::Function,b::Function,M::AbstractMatrix,r::AbstractVector,a::Assembler,U::FESpace,V::FESpace) - - -> Calls Line 453 Assemblers.jl: data = collect_cell_matrix_and_vector(trial::FESpace,test::FESpace,biform::DomainContribution,liform::DomainContribution) - - -> Line 85 SparseMatrixAssembler.jl: assemble_matrix_and_vector!(A,b,a::SparseMatrixAssembler, data) -> assemble_matrix_and_vector_add!... - -AffineFEOperator: - - Line 23 AffineFEOperator.jl: AffineFEOperator(weakform::Function,trial::FESpace,test::FESpace,assem::Assembler) - - -> Line 464 Assemblers.jl: data = collect_cell_matrix_and_vector(trial::FESpace,test::FESpace,biform::DomainContribution,liform::DomainContribution,uhd::FEFunction) - - -> Line 244 Assemblers.jl: assemble_matrix_and_vector(a::Assembler,data) - - ->-> Line 73 SparseMatrixAssembler.jl: A,b = allocate_matrix_and_vector(a,data) - - ->-> Line 85 SparseMatrixAssembler.jl: assemble_matrix_and_vector!(A,b,a::SparseMatrixAssembler, data) -> assemble_matrix_and_vector_add!... - -Why does assemble_matrix_and_vector! at the top not take uhd??? -""" \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/inverse_homogenisation_parallel.jl b/Deprecated/Deprecated_root_files/inverse_homogenisation_parallel.jl deleted file mode 100644 index 7ffb6e68..00000000 --- a/Deprecated/Deprecated_root_files/inverse_homogenisation_parallel.jl +++ /dev/null @@ -1,234 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.FESpaces, Gridap.Helpers -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR -using ChainRulesCore - -include("src/ChainRules.jl") -include("src/Utilities.jl") -include("src/MaterialInterpolation.jl") - -###################################################### -## FE Setup -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - order = 1; - el_size = (100,100); - dom = (0.,1.,0.,1.); - coord_max = dom[2],dom[4] - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true)); - ## Define Γ_N and Γ_D - xmax,ymax = coord_max - f_Γ_D(x) = iszero(x) - update_labels!(1,model,f_Γ_D,"origin") - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - _V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) - _U = TrialFESpace(_V,[VectorValue(0.0,0.0)]) - V = MultiFieldFESpace([_V,_V,_V]) - U = MultiFieldFESpace([_U,_U,_U]) - # Space for shape sensitivities - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - # FE space for LSF - V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) - # FE Space for shape derivatives - V_reg = TestFESpace(model,reffe_scalar;conformity=:H1) - U_reg = TrialFESpace(V_reg) - ###################################################### - eΔ = (xmax,ymax)./el_size; - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(eΔ)) - C = isotropic_2d(1.,0.3) - φh = interpolate(x->-sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)+0.25,V_φ) - - ## Weak form - I = interp.I; - DH = interp.DH - - εᴹ = (TensorValue(1.,0.,0.,0.), # ϵᵢⱼ⁽¹¹⁾≡ϵᵢⱼ⁽¹⁾ - TensorValue(0.,0.,0.,1.), # ϵᵢⱼ⁽²²⁾≡ϵᵢⱼ⁽²⁾ - TensorValue(0.,1/2,1/2,0.)) # ϵᵢⱼ⁽¹²⁾≡ϵᵢⱼ⁽³⁾ - - a((u1,u2,u3),(v1,v2,v3),φ,dΩ) = ∫((I ∘ φ)*(C ⊙ ε(u1) ⊙ ε(v1)) + - (I ∘ φ)*(C ⊙ ε(u2) ⊙ ε(v2)) + - (I ∘ φ)*(C ⊙ ε(u3) ⊙ ε(v3)))dΩ - l((v1,v2,v3),φ,dΩ) = ∫(-(I ∘ φ)*(C ⊙ εᴹ[1] ⊙ ε(v1)) - - (I ∘ φ)*(C ⊙ εᴹ[2] ⊙ ε(v2)) - - (I ∘ φ)*(C ⊙ εᴹ[3] ⊙ ε(v3)))dΩ; - - res(u,v,φ,dΩ) = a(u,v,φ,dΩ) - l(v,φ,dΩ) - - _C(ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q; - _K((u1,u2,u3),εᴹ) = (_C(ε(u1)+εᴹ[1],εᴹ[1]) + _C(ε(u2)+εᴹ[2],εᴹ[2]) + 2*_C(ε(u1)+εᴹ[1],εᴹ[2]))/4 - _v_K((u1,u2,u3),εᴹ) = (_C(ε(u1)+εᴹ[1],ε(u1)+εᴹ[1]) + _C(ε(u2)+εᴹ[2],ε(u2)+εᴹ[2]) + 2*_C(ε(u1)+εᴹ[1],ε(u2)+εᴹ[2]))/4 - - K_mod = (u,φ,dΩ) -> ∫((I ∘ φ)*_K(u,εᴹ))dΩ; - DK_mod = (q,u,φ,dΩ) -> ∫(-_v_K(u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; - - state_map = AffineFEStateMap(a,l,res,U,V,V_φ,U_reg,φh,dΩ) - pcfs = PDEConstrainedFunctionals(K_mod,[K_mod],state_map,analytic_dC=[DK_mod]) - - φ = get_free_dof_values(φh) - j,c,dJ,dC = Gridap.evaluate!(pcfs,φ) - uh = get_state(pcfs) - - dFh = interpolate(FEFunction(V_φ,dJ),U_reg) - dF = get_free_dof_values(dFh) - - dFh_analytic = interpolate(FEFunction(V_φ,first(dC)),U_reg) - dF_analytic = get_free_dof_values(dFh_analytic) - - pre_hilb_abs_error = maximum(abs,dF-dF_analytic) - pre_hilb_rel_error = maximum(abs,dF-dF_analytic)/maximum(abs,dF_analytic) - - abs_error = abs(dFh-dFh_analytic) - rel_error = (abs(dFh-dFh_analytic))/abs(dFh_analytic) - - ## Hilb ext reg - α = 4*maximum(eΔ) - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - hilb_K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Autodiff result - op = AffineFEOperator(U_reg,V_reg,hilb_K,-get_free_dof_values(dFh)) - dFh_Ω = solve(op) - dF_Ω = get_free_dof_values(dFh_Ω) - ## Analytic result - op = AffineFEOperator(U_reg,V_reg,hilb_K,-get_free_dof_values(dFh_analytic)) - dFh_analytic_Ω = solve(op) - dF_analytic_Ω = get_free_dof_values(dFh_analytic_Ω) - - hilb_abs_error = abs(dFh_Ω-dFh_analytic_Ω) - hilb_rel_error = (abs(dFh_Ω-dFh_analytic_Ω))/abs(dFh_analytic_Ω) - - post_hilb_abs_error = maximum(abs,dF_Ω-dF_analytic_Ω) - post_hilb_rel_error = maximum(abs,dF_Ω-dF_analytic_Ω)/maximum(abs,dF_analytic_Ω) - - path = dirname(dirname(@__DIR__))*"/results/InvHomLE_AutoDiffTesting_Parallel"; - writevtk(Ω,path,cellfields=["phi"=>φh, - "H(phi)"=>(interp.H ∘ φh), - "|nabla(phi)|"=>(norm ∘ ∇(φh)), - "uh1"=>uh[1], - "uh2"=>uh[2], - "uh3"=>uh[3], - "J′_abs_error"=>abs_error, - "J′_rel_error"=>rel_error, - "J′_analytic"=>dFh_analytic, - "J′_autodiff"=>dFh, - "hilb_abs_error"=>hilb_abs_error, - "hilb_rel_error"=>hilb_rel_error, - "v_J_Ω"=>dFh_analytic_Ω, - "dJφh_Ω"=>dFh_Ω - ]) - - return pre_hilb_abs_error,pre_hilb_rel_error,post_hilb_abs_error,post_hilb_rel_error -end - -out = with_debug() do distribute - main((3,3),distribute) -end - -#################### -# Serial Testing # -#################### -# function update_labels!(e::Int,model::CartesianDiscreteModel,f_Γ::F,::T,name::String) where { -# M<:AbstractFloat,F<:Function,T<:NTuple{2,M}} -# labels = get_face_labeling(model) -# cell_to_entity = labels.d_to_dface_to_entity[end] -# entity = maximum(cell_to_entity) + e -# # Vertices -# vtx_coords = model.grid_topology.vertex_coordinates -# vtxs_Γ = findall(isone,f_Γ.(vtx_coords)) -# vtx_edge_connectivity = Array(Geometry.get_faces(model.grid_topology,0,1)[vtxs_Γ]) -# # Edges -# edge_entries = [findall(x->any(x .∈ vtx_edge_connectivity[1:end.!=j]), -# vtx_edge_connectivity[j]) for j = 1:length(vtx_edge_connectivity)] -# edge_Γ = unique(reduce(vcat,getindex.(vtx_edge_connectivity,edge_entries),init=[])) -# labels.d_to_dface_to_entity[1][vtxs_Γ] .= entity -# labels.d_to_dface_to_entity[2][edge_Γ] .= entity -# add_tag!(labels,name,[entity]) -# end - -# order = 1; -# el_size = (100,100); -# dom = (0.,1.,0.,1.); -# coord_max = dom[2],dom[4] -# model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)); -# ## Define Γ_N and Γ_D -# xmax,ymax = coord_max -# # f_Γ_D(x) = iszero(x) ? true : false; -# # update_labels!(1,model,f_Γ_D,coord_max,"origin") -# ## Triangulations and measures -# Ω = Triangulation(model) -# dΩ = Measure(Ω,2order) -# ## Spaces -# reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) -# V = TestFESpace(model,reffe;conformity=:H1,constraint = :zeromean) -# U = TrialFESpace(V,[VectorValue(0.0,0.0)]) - -# all_V = MultiFieldFESpace([V,V,V]) -# all_U = MultiFieldFESpace([U,U,U]) - -# # Space for shape sensitivities -# reffe_scalar = ReferenceFE(lagrangian,Float64,order) -# # FE space for LSF -# V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) -# # FE Space for shape derivatives -# V_reg = TestFESpace(model,reffe_scalar;conformity=:H1) -# U_reg = TrialFESpace(V_reg) -# ###################################################### -# eΔ = (xmax,ymax)./el_size; -# interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(eΔ)) -# C = isotropic_2d(1.,0.3) -# g = VectorValue(0.,-1.0) -# φh = interpolate(x->-sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)+0.25,V_φ) -# uh = zero(all_U) - -# ## Weak form -# I = interp.I; -# DH = interp.DH - -# εᴹ = (TensorValue(1.,0.,0.,0.), # ϵᵢⱼ⁽¹¹⁾≡ϵᵢⱼ⁽¹⁾ -# TensorValue(0.,0.,0.,1.), # ϵᵢⱼ⁽²²⁾≡ϵᵢⱼ⁽²⁾ -# TensorValue(0.,1/2,1/2,0.)) # ϵᵢⱼ⁽¹²⁾≡ϵᵢⱼ⁽³⁾ - -# a((u1,u2,u3),(v1,v2,v3),φ,dΩ) = ∫((I ∘ φ)*(C ⊙ ε(u1) ⊙ ε(v1)) + -# (I ∘ φ)*(C ⊙ ε(u2) ⊙ ε(v2)) + -# (I ∘ φ)*(C ⊙ ε(u3) ⊙ ε(v3)))dΩ -# l((v1,v2,v3),φ,dΩ) = ∫(-(I ∘ φ)*(C ⊙ εᴹ[1] ⊙ ε(v1)) - -# (I ∘ φ)*(C ⊙ εᴹ[2] ⊙ ε(v2)) - -# (I ∘ φ)*(C ⊙ εᴹ[2] ⊙ ε(v3)))dΩ; - -# a(φ,dΩ) = (u,v) -> a(u,v,φ,dΩ) -# l(φ,dΩ) = (v) -> l(v,φ,dΩ) -# res(u,v,φ,dΩ) = a(u,v,φ,dΩ) - l(v,φ,dΩ) - -# _C(ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q; -# _K((u1,u2,u3),εᴹ) = (_C(ε(u1)+εᴹ[1],εᴹ[1]) + _C(ε(u2)+εᴹ[2],εᴹ[2]) + 2*_C(ε(u1)+εᴹ[1],εᴹ[2]))/4 -# _v_K((u1,u2,u3),εᴹ) = (_C(ε(u1)+εᴹ[1],ε(u1)+εᴹ[1]) + _C(ε(u2)+εᴹ[2],ε(u2)+εᴹ[2]) + 2*_C(ε(u1)+εᴹ[1],ε(u2)+εᴹ[2]))/4 - -# K_mod = (u,φ,dΩ) -> ∫((I ∘ φ)*_K(u,εᴹ))dΩ; -# DK_mod = (q,u,φ,dΩ) -> ∫(-_v_K(u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; - -# K_mod_func = Functional(K_mod,dΩ,uh,φh); -# K_mod_func_analytic = Functional(K_mod,dΩ,uh,φh;DF=DK_mod); -# K_mod_smap, C_smaps = AffineFEStateMap(K_mod_func,[K_mod_func_analytic],all_U,all_V,V_φ,a,l,res;ls = LUSolver()); - -# K_mod_smap(φh) -# K_mod_smap.F.F() -# C_smaps[1].F.F() - -# dFh = compute_shape_derivative!(φh,K_mod_smap) -# dF = get_free_dof_values(dFh) - -# dFh_analytic = compute_shape_derivative!(φh,C_smaps[1]) -# dF_analytic = get_free_dof_values(dFh_analytic) - -# norm(dF-dF_analytic,Inf) -# norm(dF-dF_analytic,Inf)/norm(dF_analytic,Inf) \ No newline at end of file diff --git a/Deprecated/Deprecated_root_files/test_iterate.jl b/Deprecated/Deprecated_root_files/test_iterate.jl deleted file mode 100644 index 60519f0e..00000000 --- a/Deprecated/Deprecated_root_files/test_iterate.jl +++ /dev/null @@ -1,37 +0,0 @@ -struct MyIterator{A,B,C} - cache :: Tuple{A,B,C} -end - -function conv_criterion(m::MyIterator,item,state) - it,J,C = item - _,φ,dL = state - return it>10 -end - -function Base.iterate(m::MyIterator) - _,_,_ = m.cache - J = 1; C = [1,1] - return (0,J,C),(0,[],[]) -end - -function Base.iterate(m::MyIterator,state) - (it,φ,dL) = state; - a,b,c = m.cache - - J_new = a + rand() - C_new = @. b + rand() - - new_item = (it+1,J_new,C_new) - new_state = (it+1,φ,dL) - - if conv_criterion(m,new_item,new_state) - return nothing - else - return new_item,new_state - end -end - -m = MyIterator((-1,-2,-3)) -for (it,J_new,C_new) in m - println("$it: $J_new | $C_new") -end \ No newline at end of file diff --git a/Deprecated/Deprecated_scripts/AD_AM_testing.jl b/Deprecated/Deprecated_scripts/AD_AM_testing.jl deleted file mode 100644 index c944b317..00000000 --- a/Deprecated/Deprecated_scripts/AD_AM_testing.jl +++ /dev/null @@ -1,139 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt - -""" - ... -""" -function main() - ## Parameters - order = 2; - xmax,ymax=(1.0,1.0) - prop_Γ_N = 0.4; - dom = (0,xmax,0,ymax); - el_size = (500,500); - γ = 0.1; - γ_reinit = 0.5; - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(order^2*10)*prod(inv,minimum(el_size)) - C = isotropic_2d(1.,0.3); - η_coeff = 2; - α_coeff = 4; - g = VectorValue(0,-1); - path = dirname(dirname(@__DIR__))*"/results/minimum_length_scale" - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size); - Δ = get_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(gen_lsf(4,0.2),V_φ); - φ = get_free_dof_values(φh) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(Δ),ϵₘ=0.0) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v⋅g)dΓ_N - res(u,v,φ,dΩ,dΓ_N) = a(u,v,φ,dΩ,dΓ_N) - l(v,φ,dΩ,dΓ_N) - - ## Optimisation functionals - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) - reinit!(stencil,φ,γ_reinit) - - uh = interpolate(x->x[1],V_φ) - # f = φ->∫((DH ∘ φ)*(norm ∘ φ)*uh)dΩ; - f = φ->∫((I ∘ φ)*uh)dΩ; # <- this corresponds to J_1Ω - df = gradient(f,φh) - dfh = FEFunction(V_φ, assemble_vector(df,V_φ)) - - # df_analytic = q->∫(q*(∇(uh)⋅∇(φh)+laplacian(φh)*uh)*(DH ∘ φh)*(norm ∘ φh))dΩ - df_analytic = q->∫(uh*q*(DH ∘ φh))dΩ#*(norm ∘ ∇(φh)))dΩ # <- assume |∇φ| = 1 - df_analytic_h = FEFunction(V_φ, assemble_vector(df_analytic,V_φ)) - - make_dir(path) - writevtk(Ω,"$path/TestVariational",cellfields=["dfh_analytic"=>df_analytic_h,"dfh"=>dfh]) - - ## When it doesn't work: - """ - Take - J(Ω) = ∫ j(φ) dD - where D is the whole bounding domain and φ is a signed distance function. Then, - J'(Ω)(θ) = ... a very complicated expression. -""" - - return nothing - - - - P_minT = (u,φ,dΩ,dΓ_N) -> ∫(φ*φ*(_max ∘ φ)*(_max ∘ φ))dΩ # ∫(H ∘ φ)dΩ - - function dP_minT(q,uu,_φ,dΩ,dΓ_N) - jp = 2_φ*(_max ∘ _φ)*(_max ∘ _φ)-_φ*_φ*(_max ∘ _φ) #DH ∘ _φ - - ω(_φ,_Δφ) = 1/(1 + 100*abs(_φ)^3.5*abs(_Δφ)^3.5) - - bi_form(u,v) = ∫(u*v*(DH ∘ _φ)*(norm ∘ ∇(_φ)) + (ω ∘ (_φ,laplacian(_φ)))*(∇(_φ) ⋅ ∇(u))*(∇(_φ) ⋅ ∇(v)) )dΩ; - li_form(v) = ∫(-jp*v)dΩ - - op = AffineFEOperator(bi_form,li_form,V_φ,V_φ) - xh = solve(op) - ∫(xh*q*(DH ∘ _φ)*(norm ∘ ∇(_φ)))dΩ - end - - ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) - reinit!(stencil,φ,γ_reinit) - - ## Setup solver and FE operators - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - # pcfs = PDEConstrainedFunctionals(P_minT,state_map) - pcfs = PDEConstrainedFunctionals(P_minT,[P_minT],state_map,analytic_dC=[dP_minT]) - J_val,C_val,dJ,dC = Gridap.evaluate!(pcfs,φ) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - make_dir(path) - # optimiser = AugmentedLagrangian(φ,pcfs,stencil,vel_ext,interp,el_size,γ,γ_reinit); - # for history in optimiser - # it,Ji,_,_= last(history) - # print_history(it,["J"=>Ji]) - # write_history(history,path*"/history.csv") - # uhi = get_state(pcfs) - # write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))];iter_mod=1) - # end - # it,Ji,_,_ = last(optimiser.history) - # print_history(it,["J"=>Ji]) - # write_history(optimiser.history,path*"/history.csv") - # uhi = get_state(pcfs) - # write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))];iter_mod=1) - - @show J_val - - writevtk(Ω,"$path/TestVariational",cellfields=["φh"=>φh,"dJ"=>FEFunction(U_reg,dJ),"dJ_analytic"=>FEFunction(U_reg,dC[1])]) - maximum(abs,dJ-dC[1]),maximum(abs,dJ-dC[1])/maximum(abs,dC[1]) -end - -main() \ No newline at end of file diff --git a/Deprecated/Deprecated_scripts/advection.jl b/Deprecated/Deprecated_scripts/advection.jl deleted file mode 100644 index bed8fe88..00000000 --- a/Deprecated/Deprecated_scripts/advection.jl +++ /dev/null @@ -1,30 +0,0 @@ - -# This file shows how to modify the advection scheme - -using GridapTopOp - -struct MyStencil <: GridapTopOp.AdvectionStencil end - -function GridapTopOp.allocate_caches(::MyStencil,φ,vel) - # Do stuff here... -end - -function GridapTopOp.reinit!(::MyStencil,φ_new,φ_old,vel,Δt,Δx,caches) - # Do stuff here... -end - -function GridapTopOp.advect!(::MyStencil,φ,vel,Δt,Δx,caches) - # Do stuff here... -end - -function GridapTopOp.compute_Δt(s::MyStencil{D,T},φ,vel) where {D,T} - # Do stuff here... -end - -######################################## - -# Basically same code as the standard one, but using our new stencil -function main() - -end - diff --git a/Deprecated/Deprecated_scripts/inverter_AD_testing.jl b/Deprecated/Deprecated_scripts/inverter_AD_testing.jl deleted file mode 100644 index 79425c83..00000000 --- a/Deprecated/Deprecated_scripts/inverter_AD_testing.jl +++ /dev/null @@ -1,114 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt - -""" - (Serial) Inverter mechanism with augmented Lagrangian method in 2D. - - Ref: http://doi.org/10.1007/s00158-018-1950-2 - - Optimisation problem: - Min J(Ω) = ∫ ηᵢₙ * uₓ dΓᵢₙ + ∫ ηₒᵤₜ * uₓ dΓₒᵤₜ - Ω - s.t., Vol(Ω) = Vf, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, - ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. -""" -function main() - ## Parameters - order = 1; - dom = (0,1,0,1); - el_size = (200,200); - γ = 0.1; - γ_reinit = 0.5; - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(10order^2)*prod(inv,minimum(el_size)) - C = isotropic_2d(1.0,0.3); - η_coeff = 2; - α_coeff = 4; - path = dirname(dirname(@__DIR__))*"/results/testing_inverter_AD" - - η_in = 2; - η_out = 1; - ks = 0.01; - g = VectorValue(1,0); - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size); - Δ = get_Δ(model) - f_Γ_in(x) = (x[1] ≈ 0.0) && 0.47 - eps() <= x[2] <= 0.53 + eps() ? true : false; - f_Γ_out(x) = (x[1] ≈ 1.0) && 0.43 - eps() <= x[2] <= 0.57 + eps() ? true : false; - f_Γ_D(x) = x[1] ≈ 0.0 && (x[2] <= 0.1 || x[2] >= 0.9) ? true : false; - update_labels!(1,model,f_Γ_in,"Gamma_in") - update_labels!(2,model,f_Γ_out,"Gamma_out") - update_labels!(3,model,f_Γ_D,"Gamma_D") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_in = BoundaryTriangulation(model,tags="Gamma_in") - Γ_out = BoundaryTriangulation(model,tags="Gamma_out") - dΩ = Measure(Ω,2order) - dΓ_in = Measure(Γ_in,2order) - dΓ_out = Measure(Γ_out,2order) - vol_D = sum(∫(1)dΩ) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_in","Gamma_out"]) - U_reg = TrialFESpace(V_reg,[0,0]) - - ## Create FE functions - φh = interpolate(gen_lsf(4,0.2),V_φ); - φ = get_free_dof_values(φh) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(Δ),ϵₘ=10^-8) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_in,dΓ_out) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + ∫(ks*(u⋅v))dΓ_out - l(v,φ,dΩ,dΓ_in,dΓ_out) = ∫(v⋅g)dΓ_in - res(u,v,φ,dΩ,dΓ_in,dΓ_out) = a(u,v,φ,dΩ,dΓ_in,dΓ_out) - l(v,φ,dΩ,dΓ_in,dΓ_out) - - ## Optimisation functionals - J = (u,φ,dΩ,dΓ_in,dΓ_out) -> ∫(η_in*u⋅VectorValue(1,0))dΓ_in + - ∫(η_out*u⋅VectorValue(1,0))dΓ_out - - function dJ(q,u,φ,dΩ,dΓ_in,dΓ_out) - a_adjoint(λ,v) = ∫((I ∘ φ)*(C ⊙ ε(λ) ⊙ ε(v)))dΩ + ∫(ks*(λ⋅v))dΓ_out - l_adjoint(v) = ∫(-η_in*v⋅VectorValue(1,0))dΓ_in + ∫(-η_out*v⋅VectorValue(1,0))dΓ_out - - op = AffineFEOperator(a_adjoint,l_adjoint,U,V) - λh = solve(op) - - ∫(q*(C ⊙ ε(u) ⊙ ε(λh))*(DH ∘ φh))dΩ - end - - Vol = (u,φ,dΩ,dΓ_in,dΓ_out) -> ∫(((ρ ∘ φ) - 0.5)/vol_D)dΩ; - dVol = (q,u,φ,dΩ,dΓ_in,dΓ_out) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) - reinit!(stencil,φ,γ_reinit) - - ## Setup solver and FE operators - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out) - pcfs = PDEConstrainedFunctionals(J,[Vol,J],state_map,analytic_dC=[dVol,dJ]) - - J_val,C_val,dJ,dC = Gridap.evaluate!(pcfs,φ) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - ## Optimiser - make_dir(path) - - writevtk(Ω,"$path/TestVariational",cellfields=["φh"=>φh,"dJ"=>FEFunction(U_reg,dJ),"dJ_analytic"=>FEFunction(U_reg,dC[2])]) - - maximum(abs,dJ-dC[2]),maximum(abs,dJ-dC[2])/maximum(abs,dC[2]) -end - -main(); \ No newline at end of file diff --git a/Deprecated/Deprecated_scripts/main_inverter_(Based on Laurain).jl b/Deprecated/Deprecated_scripts/main_inverter_(Based on Laurain).jl deleted file mode 100644 index 11a8e574..00000000 --- a/Deprecated/Deprecated_scripts/main_inverter_(Based on Laurain).jl +++ /dev/null @@ -1,112 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt - -""" - (Serial) Inverter mechanism with augmented Lagrangian method in 2D. - - Ref: http://doi.org/10.1007/s00158-018-1950-2 - - Optimisation problem: - Min J(Ω) = ∫ ηᵢₙ * uₓ dΓᵢₙ + ∫ ηₒᵤₜ * uₓ dΓₒᵤₜ - Ω - s.t., Vol(Ω) = Vf, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, - ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. -""" -function main() - ## Parameters - order = 1; - dom = (0,1,0,1); - el_size = (200,200); - γ = 0.1; - γ_reinit = 0.5; - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(order^2*10)*prod(inv,minimum(el_size)) - C = isotropic_2d(1.0,0.3); - η_coeff = 2; - α_coeff = 4; - path = dirname(dirname(@__DIR__))*"/results/main_inverter_mechanism" - - η_in = 2; - η_out = 1; - ks = 0.01; - g = VectorValue(1,0); - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size); - Δ = get_Δ(model) - f_Γ_in(x) = (x[1] ≈ 0.0) && 0.47 - eps() <= x[2] <= 0.53 + eps() ? true : false; - f_Γ_out(x) = (x[1] ≈ 1.0) && 0.43 - eps() <= x[2] <= 0.57 + eps() ? true : false; - f_Γ_D(x) = x[1] ≈ 0.0 && (x[2] <= 0.1 || x[2] >= 0.9) ? true : false; - update_labels!(1,model,f_Γ_in,"Gamma_in") - update_labels!(2,model,f_Γ_out,"Gamma_out") - update_labels!(3,model,f_Γ_D,"Gamma_D") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_in = BoundaryTriangulation(model,tags="Gamma_in") - Γ_out = BoundaryTriangulation(model,tags="Gamma_out") - dΩ = Measure(Ω,2order) - dΓ_in = Measure(Γ_in,2order) - dΓ_out = Measure(Γ_out,2order) - vol_D = sum(∫(1)dΩ) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_in","Gamma_out"]) - U_reg = TrialFESpace(V_reg,[0,0]) - - ## Create FE functions - φh = interpolate(gen_lsf(4,0.2),V_φ); - φ = get_free_dof_values(φh) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_in,dΓ_out) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + ∫(ks*(u⋅v))dΓ_out - l(v,φ,dΩ,dΓ_in,dΓ_out) = ∫(v⋅g)dΓ_in - res(u,v,φ,dΩ,dΓ_in,dΓ_out) = a(u,v,φ,dΩ,dΓ_in,dΓ_out) - l(v,φ,dΩ,dΓ_in,dΓ_out) - - ## Optimisation functionals - J = (u,φ,dΩ,dΓ_in,dΓ_out) -> ∫(η_in*u⋅VectorValue(1,0))dΓ_in + - ∫(η_out*u⋅VectorValue(1,0))dΓ_out - Vol = (u,φ,dΩ,dΓ_in,dΓ_out) -> ∫(((ρ ∘ φ) - 0.5)/vol_D)dΩ; - dVol = (q,u,φ,dΩ,dΓ_in,dΓ_out) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,Δ./order,max_steps,tol) - reinit!(stencil,φ,γ_reinit) - - ## Setup solver and FE operators - state_map = AffineFEStateMap(a,l,res,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dC=[dVol]) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - ## Optimiser - make_dir(path) - optimiser = AugmentedLagrangian(φ,pcfs,stencil,vel_ext,interp,el_size,γ,γ_reinit); - for history in optimiser - it,Ji,Ci,Li = last(history) - λi = optimiser.λ; Λi = optimiser.Λ - print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi]) - write_history(history,path*"/history.csv") - # uhi = get_state(pcfs) - # write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uhi];iter_mod=1) - end - it,Ji,Ci,Li = last(optimiser.history) - λi = optimiser.λ; Λi = optimiser.Λ - print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi]) - write_history(optimiser.history,path*"/history.csv") - uhi = get_state(pcfs) - write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uhi];iter_mod=1) -end - -main(); \ No newline at end of file diff --git a/Deprecated/Images/Algorithm.png b/Deprecated/Images/Algorithm.png deleted file mode 100644 index aa6a2f64c9c9176c8804d419fc3bfe46a62a6487..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1482410 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\TA zSpPITkn667hc|BxMaS>%(qTPwHUE(@9Q@taDs&*S-ZslKX*H1?{H|^bylo#I%nbg z*R22x4cQCH+p@*uAcZ8ufqQOzmsChNhQ2*o>^wi_OrRL_z#(nm#UJ3eBk(Ww$|#UX z$V_%mi{SpU7@OtBF>v4EP+}p`2oyaY#UG=n9i4BOjNFhm9`f~A**)f1p1QbcK7JO? z1B`Y5r}F*Q+397=YNdp!ol+g4(2T#xC@7F*L;Bd$eJmjd$F`&-P9E@NO>KAu?yS#IXPw zP;m0v$lr}8r1WQpO(K##FQZ|TaaV3?H|G^1yLNTXPvuW*AH-vMZnC0VVk8O``0Nw^ zoOVtscUP?mwVq~3E4|Bcz;d7JA6|qigVN3`Yl`d#D#1l|_$r*$>Vk}eOm9KxS%lD=e6!ZM&r{?jnvLk`()R~6pX70!mWua~TE!Qcw& zJZoRymjkm1foiJ_m@%9;=^eLtNWUHe4{vn?Xf7Ywi)>Iy)S4pM!CYIlv(L_WeOewB zZ7k8L1B%Uw8*7t^DB_QAGO}jVo!MoHaMe$s6Xj1Cp?big>*1`7|1-ru(97Lse&FCV z4U=C0n`Mixmr}Z^Xl8&}|0D6Mzv}E1yfl>YPnqcH&2-BpC66%rN(OvLJ?`(8JXr3Y z3xZ;@u$jqtBZxMLI_`L8(SB9YwG+Qc8IjQwb);D5o13zUHl0L`^1HHG4Eb}5 zZ&l<5jXsTk+e%M7+{9-4XRZ=!c_PfSn$?b8BT zeh`6}XNWY*Hg()nl*?=4`6IE@XSiV4K=e|+X@78^k1tu+aLR^2ZnqZW;6TCT>82du zJk+#U7aZ&~|MnkYj8Z`a6GNkaIOOK!WE~+Ccyccgg!U&zI&?)pa2o4SFM1`jyeRd9 zXR$5qb+VC9@_0{$HJ?&WP|W1!;d@gSfJTb9KqawZq)T;t~cRt6`6 zUr1r$=B&`J37xn2cRH+eP=agjssuX6=dgH}f*Kl;9 zk1SWy4r0VSr;O9v-%;>4t5E$U*J|@Kk(O4uYKF)UYfUn$2gmg48r%%CGMo9lXDkJr z92~krMEtXIyHiSMcFpmTCw@??Y%;{OQwz{4-M6Hi)A8*Kol z`L5{9LNuH0&}uXyk#E4RBPBO(K4wRqxhmbu=Be7$*?G@*+fZ|HOoh+sy=mZeDk=^{ zb7HgHAyQ`3?avM49>DoT%=y>qTsxb|w%83$6S+>swey|vK6@nlm!l>Bodw9%1PJG{ zu@{_BDtlQql3u|$hVA)Z>l$H38VN48>75_?&pS`8r{ouIMYud1ak4fy^)~LFdUq(G zAb+EXW8_G)t;4CGKUYcjV)s?rtIuH$q}+8#!#`_}(bnn#XphMF@$MqnUP{u}JXG8F zvtyIJGLmX{U9!p!mJDm~2@9b{PxgKUo#5M62}t>L96R7bsQ;j?5CK%Kysw%gv7$Xu zWcOG?J5B1$t%La%CwY}^X_{Z*LaJEkIxR(Fi@ZX7Z9o=V2%~p)44Dm7{PgJiRIbL9T1c@Q zP+KD}HwT=Fy!=J*0z`F*DNfvr}b2UjUKd*(_(bRK7m6sJ1TW{v1T{rp;@6xPKdG+M_=wt8I#umvnw8yx6rMF2fSXLhj40O^fP|aY&{vNOBBhZqnqmEoVkkwjFxLB=oR@ z-mPgA8mXGeV#o4`v8LuYN7d+$18xzHdpjF^k(!=LB9k~1u%|noX^Ht*B!Mc&Ilp;1 zI%*PAnsFP{1W?c31e!mEb&NeyHt#=v3gj;RRDZuEp#SE%*VME#SkNqphraJ9XKi)Z2}^ZIZ>S#~eiQ9y$4?s)4ixoo~_( z-Zxdte5m1Ui+WP@)^&Q6@ykU$3^Gih_Oi2ka`SS%i7ZK|u0A~R{rn~S#Zl=I5{=dl zZNMDUg96#j>!^o-YkQnPc+6FFGEsep<I^-p6-92&J4VteDlM;pgV&R<3dS*Af2P=;;j)4$gK3TpX`-8IelY>+XV(m+`kp z_WGRkk{=j2!p8PMRafV=-BXq?`+{Ke-0fUWYHITG5>0qX3I5{6Bt&J8i13M~n*trc z2=%J7xfO+mKvt`Bnj2un9{28=NLAQ%$1Ics4((tp*BbC+1zI$7?uzO{Z z)FjLo9qUIxWmW)mJU%za2l{+;)Oc>iEfw}JmB8;c)gPBS6`zTYJ8!;X@E*!t%4@pl zLCx~+bpRG!5yl6Y%Ts%@U}zAS&4m*Xl9yXNU8wjxBxdRJ-U%A#ha=R!0taT$mULO1 zU0l%kj(uwC8D8U&j>v+U-DYwXr<|y0lf3e4xMB&CV0<*hJ7C1WpOF4_yl?aVUD3g0 zW6F3AF>#?xFeI&!*<~nWaIjj)r-xVA*!)XZEbeD^BltpWs3d%7=U=E(IdX-$xCLbm z)i-Ibn32vO#s?-VJ~>IqZ||^-=mrabQZ4ATigi<_EIkP!5erC#MPwjMyc@+7HE;TH zJP^?_te@3JMkd@3tLdI3=Yydt?IVu(zHD68W7n15?xupW?$^vfubKV+xJ1VlK;6{w@1NTqc*xoZy}BNiTRH@WW>Ld0KzMYRpc+`<;KuS#vKh%GqsyzkI1Z zzPuF)NKROFmnA5bq}hG^*sd|fmyYOJY?hl};~-H{JA%P}i9;au`il)Aho4%m$&D~i*amp@3SMATAuWte zK;QsO(IC;%GIV39XvTq{)JFu^NG{^2Z>vi#Rqfm z2G13?pQx>sgAxG8OK@k2hE7*l7F>1+dZKOn-7wl|hFX8#@#298Ixeo!N<^xn9IP57 z@+I6tF`y4|sT&DOU}km&gym~J;ABEMx^aFzAo~lzr2W4T8_Hw*TBB%#L`+xLpBhzG z!jur@@Z32n(mY7DA;$>^if{pvOlO`OF2uPfYIxwR zSfNocnlALRs);2R8%Maz(DSP$_9-$+{GK-Azmsy2$xzVZtI!Qb+m*#)@|_5m&dhf8#8)NqZ7Ig+ODNlZ7o5p|bj)** z0k{>5J3i~z+|D6(CYks2X}1RviG~t_P#lP!sZ{v>l7?D%%7cg(VTqo~^tVzfsLqAZ zGK%dU6VH~>f@sm--Za1f8)17hvqZM00lb^>VT8qj#}D*WcP*yXsow4M51v9xpfMnE z7u%n!Zzxvb?yyn%53%To7(65}Qf%PaA-qsiH`PL%TDS2ao7^QZ+R-VLz-m zp0ejZ$84RaL~8RbSkK>(gMM)B`P;QpqEkfpnRhTo(=>t_^DQtzg0 z&<%5_ldCmhbgTHr4@L<&g~+$>H4tzCSte0@1;)_AA0D-Iq%fK06JsMIpA1PQ?6dp> zsD*?9P;2Wioyh{%gdLTe8`zUMaBJsS@nz^tDD_8=&;gUcc@R%*Z-3xs*-OgAXf&TU zGrLb`IT2stkV*KiiMnZztq@S|L|5Fma2TzC8Nz7jH_fch-N zdBUb~D1AAekE==J-o46;7ZYbCNicnF&)@@X>9O}-!d!jU$F=<1WRM24F>Y6=)yo6% zXy&6%MnoY-%zxhD;B9|(=BG-3xt+5Zg8ZOqBU>4%z}Fw84o)-VH1kM6k14mOYcQox zI=i#!k`HYv_zbdS)0-zdNSM|k2V+uy1b|jk=M5Js9u&KzZowM2wCIheuwDUzziNe| z(AJR{-0Tz!vm`d>cv&n6>>$3&T-C6wnd&{g_8g4B@PF~56fOW9>L1-|)8Z(wjLb!Jb1dm1WHM^E=g@mU=Z`?^ zD0@xHM<(Du3l~Jk$U5*W)NZ&hR1 zhj;$%=XI~u#4CWpQOJh@F!xIe9l=kzOKyzR_E+x7LBb629T_jPcPxXQit9f-DcKp^ zo_pu*B&;(t0Oeo)?*LrdJXNo#S~q#n^|jC59d^`+zqkSjB(7rn9nT0}`!jz1Fc!$O z4#CEdKhAJCIyk69)LY2C?XIaQGp4)fY_KjyyEctqs-{njX%p10cZy>PpMs)viD9a)0{|cJ>7{6fAh=4f_0js5!(q9f!KrxKrchDiI(le> zKr&`dKToRDx7Cgh3UZo%Wt30&!`T&~Kk5Ui%vE~}Dbdgo5`_J@Q6SozlUHD~TFqEK zlkvG9YGckwek|_1qfn>p$*lL6C*s*&-<@cqJ+_$-;LR2oi*rBZ4v6V(#a885r6%LR%h4 z=Yb6d5fdIsT(N3q#jTCkQwk7)gv^G~*h*|hVq!+~O6G21n>8in3~~OgY;^mMVjW^7 z0lDeu*X3T@JOqiR4Xf?Foz0^>)!jeEj74zKF>X3sC~t62Tp!(YQlHpThvbNf5tOLw z>Rl%&6!(Ous=la5uPA0EfP_(bh=t zDJl9AD&A>-Y%M;$49u0Nb9EZPOXZceR{FV`q~|@Ws=RU`K7#YYMj`S{Q1F0Lvyh=d zqREgHc&MhPU*L23(ji0X+q?v2P*AZgkJ}5@hQzdVHtE*_` zH|wlCn0Couzdx{kG*HxwCHg|^zZCF6296ABRi4to0-+5&N_1_(*@>L@*Sohppvqwd zN+fU!xIu=Pk(T2iAS)VwtJ4Jx{#S3U}i!4}=g8dlM1koA#+xPhhRcgr1RxT#?yqkLjvqA(xiqNdK-8f-mwUjIH;) zXKool-b5%A8xp_J4bmSyN6m;-0vr3Bx}MkTYi7>4v3>4{(w=R5I-=v-wU&pBSHLiG z#aFGsYu^9;YgF-MOuSU9R}6VjR$ftJZ;8BrnI><C9zBo;g+ik<0C#sKZR~qB_@40hF=&ac zeX>^xbGz%p4L!)+I=L;Wdg_LQ*XJr>ngTX?iCe#miwh9~N;4l74miM3LsZBVpX+0< ztxtl9Z&y>Yeaab$t#3>j>S3ldSdjQoejg@}X=O-c!*V{a+&ZxZM8Njii~RhBM6J** z=r^#Oqpsf*G71LeLu=`4AUzvM3Wz^|sD_Z)n+z}qh`jFCavT%CJnlSGGQce@jYY4l z&q*pFfr$uY9!uU+vDdvu@OP*aL(-!luNQ7CX*IPg5Dp}X`%za+_2I2VYKC546ogLY zXTmL9ThM1fS4vlRJ4o(s-cP`iRGU!vwL$+K`3OkCV9!IK}}$JCd-c z$jt@)s!dVe?TLeYX)4MMbx8ZtcT`0}ZWq+{{OUxy%w5k@w>s~&S-2q1+w6~)lvsF1 z*B6Z5xer&5zP4VS7Sh^~dSBZA8qxU^oEZy$X8HC$lw9v2S~c!&uS7z+<~idOOzUeS zQ>R)+r1P5vkSWmm%5c70GAL8zTB=xWaWf#DGh-Wt;cTtG<#(4H{inxHndzK3fb1qD z5j1o*J(pKbMFs|@fMZ8bZ_2|ZpjRaKF3P(rR%COtteZx}_Z@r|X;Z@5Y4z*<)`QW0 zjW$`x%e&49qXCVL&z!%M9*|DGd=n5$+W5F66r@xCTE}IZmk^b$6f^ajYCQq@(1>Hw zfsr(T;6UWhYHMVA^{U63KcvhuCh~bH8N+cps}e=v}f`Y4MR|$r3;9_Te==sR5ST z@U)W_nT;<1qaxKEl-GS&sb1TrW9lux6X8Pgt;=;ExjAA@p)YopqczEU(zo(_M6g0+ z!>_iGV0|A+{)ELduQkyTz0^wk_AW7c3o(2}i}WQ$;QPc|#D~}6?Lg!us_r-@c z*yIp4%VZ?;2Hhds%*|Gs;#D=CAdsp7l9+@bBo(-7>t+T?(GaEmEkUgz;$YdiK9DR8G z+^j>bW`Wkg;nvjDx=B~}4K2VSKt>A)MgH2b@Ip#u_EX;%P+8`qlh2xzh%#MF?8#CR zNoeJOB(jr)ndwij+@{yN(R_YkiB`t^Zp8fj{c~#)PAzqsD^= zhWAqX4S&>v>8fSpqoSa0L1+-B66E(&F}4~VozfD@&z;=8F4Kg{cAZ?6Qi%QWk?f)# zjFuI0*-Q{l8es2pDOg^^BA`@3CqMsr-_P@^qNUFglMJI{V>Radpf9q!ojQqCU!Foa z*2SL4BU!MDxbqWoI>E47$kQkcHu5knjM?3KLEM#;)zxh{EnS|u>%8SUw9sAup?#od ztK+QetWh?Dv2+gZz$Ys+cv#&^K0hMj9nQ4-6np5}>Pc0MFl$e4i(#IA`~L67(Rm>) zf~l6*&(Wz@x}<1H)xyF;YS6kK#}S+b^b3snh}k1!)HJp^DQ01$%FmHOqR#bBZ9K0( zjAmrDQh}XaPG>geNr-Wd4ztgxt`4xNjeA*RgC+cZ7Rsa{)0v~Nmnnlt2=k6w924fs z(o*g<`^ASCc?v2a3k zc=!`i5ubzmModYGb#6m{bIeo=+RiT7$&qU(=GIk>f_=U9TDQebB}enH9JpL7qE+Fu zfD~;VkChwJ!xNks+W0Pd9~E(YQ)|uU8yB@<&-5DQyS7?79?p^*U3}+HzPM3Pkox-d z_-TAc%&cTm9CsvFd9SaHZ-J9@3C_CFXMSiUTbX$zDnS^z;0~Msj9OdvP$>6upAl%F1TpOyTnwE=_o z724g*8vI%A?H)dMj+Af#A>{}eh;)Ixt2Hl{q*?B#jk6H?HaQ||i44>7Pd$je-IWW= z*M>!@$aqIaa-BLQy|t~SW)Xcq4_y<@C^(m^=PK6p<;#3=Xk1c~opa!FMAYP-yFf{w z%e{}&vCai8EiIi3Nk}8V!xYw^H=fZguOiI>kHFS8T1^Ko#iB=nci^?^!-pY<$CR=L z@7TvbQcWfxH{>S`l0qce+(r1cFr9iwj!9zTaoj|fWK)8SMwL??tGT&$ zCEnY3UBcU)zvp!rc*Rv~9;zmG364;EWvKzb=57qcf3rBa8LeTzKTh)ou~7_>C}!JqSRF#Y;m^!B>|X26!m@# z{>t74CMn$vEzLKq28f~&89%Lfe>4Bb1EzjC^|=+d{^((!+yi>xHge zy?O^(iZ(uWVRqE2Svg)nhKdy}9|3RCVdLOnpwd1{@pO;RM_D1F(3qYI?PLmpmh>Ap z)!CqPE4w%d{X4j%pcu8fcl%7vrIW`vhOW=iqtplcSjAkV#*a{t;tjvHdH>s3&yPDEtf5827n4gT<-M{51e;xN79-U~?rt}!4YV`NI2 zKa#8c1O1`;34w&x{xZ|ht95-St|kG<8ZbH!ob>dh6sr;hSKD%q2 zs8`VLkv!3gJRTGBBn!Q-Q!J808Za~#ue$i}R|bpxqn#aH;PrdRuUt7*NXU&8he(?^ zU<6UQ*rOC^Ww}MI&-)Y2tu1^`DT9fM>{pXJ(vI*%zxkb=t4`x*2QR99X(i1^`Ubdb3B=VHJ5)Ttiq)aEj0$>8~rrFfBz2PIdEg(-5#SCvXy#3$SZep(WQ8})YmA&EydSW zARr@ygT*p}I1ABLYAs3%3O370hVtppOSWzy@DA_pmkGo8Eca3&0UE}7I)vdA zCno8J;#vr;vcpoBsSAmBloAXA++F+VY8Do` z%xZpED<8gsvo+pdqlne3npWDAI`9;-8I(JVH}y!&MgB^BthMMbm;SV6bbR_S1)V+IDZz&wC1M^ApPRK;sT?dR z{{5);UK750$Jpn_9e8}bJbtKujQi!+DN+?HZ&guHuwM|{Rf3HEbl8ZIs;Vk4bOSA< zl;DeAPu}Tumj89tVX0`L{cvf3B+1ZZfBhKJxx?}GT94~f&9$=a%$Y(A7N?=OVCRUB zEngp~H@3OwjMSrGTNXE$Ur(Q6l=1HEGZjHS_PrWw7uH=|{-(dG-=Cu`GcLTSnVr7z z>v8IZzBP415&REd2DVTG|HJnwdS5;Lb@uqLA9|W}(yXL!Zu-i_Tq~NH!OB0$0f*UD z3YQE2YikTr!JG}3aM@4WrlknH_ZIQj8_X%mAjdFj;pzFjQ02k5gMVzN@vlQTaB;{n z{71IR566-eT_V!!K%w9wSeqZ2=I~j zy)R6YYhPZ&yBFq7sHyX`Xz9}>m_)1Zx5QRs0;tfO92}pDhY1APB>W)u5$muz`zd28 z^lucIk!Fe=`El-6iwn{d^Gx||hKp(dr0+2srJrXRN|li{>KRQdyj7*BNfCFR>jvZ4 z6Tt?a*0*mC_<3a-Ru00>3F+D`7-`RKUe!qM>f#f#v)bJnYvgG?$1h!XeQjZ*mtI`z z|J2RD{uD)jIKIM+?K4YvV&56qg5@zv-QfWf&RY8Z70O()1!d zixt6`CC75*1EX(?T+Agiv-?4l`xFqK<9#W!$RTi4Sxegz({`%0ND!;P0`1SS@ zo~jfme?-PQlf72TzDf=ZmKalwT#CPh!NKm{t1GOenWgOg%NfT5n_F7cx+*oOf6M3N z$PQXlOG--OGqFlMeAv3fwBj%d5Q^pEhMJAyUmrgv%!D__v;g^GgB3MYS|w=j)`Xpk zctNI|ephkv3cXuh>saSCg1HC-zP;nS{Z}PzzEshbVEs~G^5B(n5v#%2r&pg+r(ZFS z{Z-1MXdD}OUUBsz+$_MwTyS(BA8zaMRt-YIr?*#Reeau8qpx`z`xkDiE>;uKrzEOx zyOLcAEGPD}fg(;ANK%)$bn5G^Hnudkw#KCRzg?)>@CL4k(R9wtWVh<~uA%d_Du=K~ zPSdRTC<+B6A7fuvWr#v`Mr2G!;!9mR6Bvb;=ZifrJxvlWIJocZ?{QaG_r9mcHaTWM zS|h`R|mttk8?(FqgVCYai zGr3d3dA^PMLGu;UP|Z;2T`T;HG36>RrQ*9(6!v{&5AwGwF7n8!K}u4suH9c57)?fsImAc3ezGd@0UUPiu7Jlz(R(cS4yf5ExKO7ZUJpq3nF&YE;N;>?cy zf)+YPEg~vBIRhC?bLB;62h*-uEf(vo2zTB`1)CM=+q+}mWAwh?vfkgn+jvC;$*C}9 zzG+^go`dx!J;iGd^FugQPfyVa!z>BBGN0lt+9VF^^5ITr~I_+5Ml9%6agc z#gDw0L>E1z_C-bG@-&;|##pvwWj^3+nOQEXYpY0<7{S1i0g^gAVBn%FwQWf}Ook_L z=4+b&T(b3Ef1!(@Qw>{FU!NAMomaaRJ}}$=nSj*rWj7Wo&JzP=ZP9%;#d@&`30Pn6 zv*J1L{OQ+g73G77uX3=oImZ|fVuzdaZE@ zqFb+Fwaftry!9b=L# zUT|t|E=+s5k*UCCE!%g?)hRZjEvfjLc5Z*hSKlK6)~E=={?o|FV1#0pzIZ5ZS8&MS zIFy)|M`9$RT&63?P^yo+#+@MjqbrUY9~E>Y1ckinm<$;~!J6YlLJdhaGnuDUUY3S& zSzR~!MT?6e$s1W#PNWR%Q3E18AI|}_0~9r#7&2iIJ?-Z{cvC?|q6R(2ysgDwLAxoyh+JVaDAo90bC1smG)hj!1l(*GfTt==M(tc>@u@;kOl&%!VbYxxJ%_V?P zoUMI3e8M+f!aafwP0_kLjK*Wl?dw9(HA&79EWK zbWszi{l9mfOkH7BtYH+A#K7Pt&)d(}uk@wtPN9f#1MElh%W9IWe_^D0`ImqgX>V<_~*Q(^0%-fEnkli~?@Y&AfYWc>Fl zqoBySZE(?$LRAlfab>%6EDl>~Vo<-Za9%l>q1LU>`TH`Cd>sv^P?InEI@b~1!p!U! zE5xGuR)fPmdd4S&af498zrYz;*<4iys+MLs^QoAb#0rV?Gfn6g(6z5@NS-TF2e}29 z^Rj#_V2Q`gDy|gTYfzs3i@*pQi9?Uwb<%=$e9r9L>6XkdBUuDQdid! z-NM)AvMt*u{s-<$Cp+ED=Ot_?-y!X{3HWS+lbM-(+D=@n8Kkkp<8c+w+Kee2j!W_X zV}4TAgW80cK$GVEhC0Jfr%%6Yelq-XmKS2H7{$rM4)Zq?T7z!A|JZ3t$1OTj+Lk!H zIDNz6IowlyUXIUl^i?CnLnmCtyb8TGl5}Xb4%HLbA0HUQS^VQNw7CEmaK|ZmqFb_6 z=GEk#6yv@bVwAIQ#8K7b_#YqKU{4aCn7%=cbKDbwuuLf55$(6x+NlI5pTW+C97{Jmg?|Gj4gc(f+{M<^1y-Sq+w7mbu_?6RA!XM=%r98hGltl2OuB)LV}`A|Y{T zBhy3mS|4nL$s5Kg@EiZQtcoC{Q}I;moxn`cw+xfwx_9`zhx>8ju$zg*E}u6a1*zc6 z3FGdi9NtjAbPC8BEY{U%TQ(e(i~ZB-cfHIsf>TeY61pYu3VH_M&}>$MwCY3E*5zw7 z6x`Lw2Y#2uFc}{E$59I&^MP#2i9JT+%{AL=*5ahBoFx?}{NP~YGxc-L0_|B(ve0ze zl<_dE&lfXQ%lc$$mc>0Y$d#Fu99>d^fv_R{IZX{PUQGS+d!lsU+geu5y0EqE*T(E( znEsmqT@e^Zbt{9JSFRveWbg^XDtC=-{wWfLLEu8gFnh6k| z&5*?JJGgMU2_z`VD~Trf(+V^+4T$R?&dVB2^oRNywxF>ohO7LGmlQ6ET)r%ino@3( zPK}3(TV0zn=_%W5ttuGsr7fU~{q&?+!)jJHldX}Hmsh41J^;)WmJwCCSo9-+7V@Z9 zYVuv@O`ou}z~>LwMo&y>6FM^uodL$2{t*VNAJopDZvw0m3;ONzzj{ilj(r35eP+4_ zdZBA>sL729Za|;_k(!(3BVkJ-pSC&%d6Q37ae6<=H!~Se7=#WEUi*^#N)@0BD5-G8 z;r_RUwDQKsrn`Q<6Suj3hue>FCV7|o%;0Y%w8pr;dd0EYMxGb686T)BAlEp#x#7Hx zASdzur`bI_6)|`DK-zt5Y3b3-^Jf5VryNKtTQ=;v@>dsYL)sxm0Fi0Sc%5CYIR!*S zw!_OXIN`!6j}cWP&5jU?*M8ohIr+pa%j#2qVX4W01jt1EC4EnDL#?gw;>b00V;k%_ zGLXQ>bK7%vTp0p;3iz^i?K^igpUp#`Li&rCYo!7RcE)oC1LgbI(gl!73@f^1&M+J1=RHz7!DM}7Vz%Q$9hUedNzw-ABViR>T-;5~G?My=AMS#f(rJkW5+`gSm&F<*|l)aqElv@4mf`Iy~^{ zV?wU($_H3jdN4l4Vn!OITIbccvs<)F3KuvKiZWAF%|nLZ){q}b5ny#o@j>_}>(Ygk zc2~IEuI@;>iw62M7dEu&o<&mcMeKrJ4v1R6ztY#}nXS1AE!U5F<9o!(@87fIas3Qc zwj;w| zf5$7e=2P8sgHr9w$)$;l>SIw}`-vN?EBfPP?aZ&0!Dl?5U}4Fu4BmY=Ykd4BW!cVF zU@kPm*^U`uLauj`l5>1(*2+}GN};Ps^@Q(3MM<7?0i!XNecA5>eZ2;-u&hBO@2^=A zK{zQq%La)<<1_TB;F|$?=|-a)qWQ|LZ#kQhtF$_QQMq4nU@QWC!Nc%MMp3xb3_J)5ZT?xzAP**Q?a=HN_51>a?dD?Xe zVlGwKUb`|lCM>%ugvCSL>cq8u`coWSiN#Q%6CVa3zoq9iuvY%u}YvydD81T@5%W%TG)P9 z8Sl=g3cmNVd96?J0G85b3GVNdrryCshqGB4=r5b#z|^s_aY^wN_qIEMk4z}&&aK~0 zOnkk&F|)Oz;idO(!v6V*6d6fx>3onf&Wdgf5BYO*arHaVyorfPEiJv<(vGuo?_t{T z(I4N0of2>cH;pUS@jpc^1RF4mPqSembU@5rNUkGnY0H3=)vM!bFhlUb8Nw-gG&6guf1SH%Uj0m zfrVXpc&3ZU0&$9!{Z%t^SmO;`=)D4MJG(N18#sW3+yPyr5@Q#}V5}`kyT3O5ddHKK z3U$%jEE@l2OYlm_1yGNJZDKJHBl_G9fzB&vSwgCe3cfgj?NzN@;SutAN>@@Kcb)jioD;Plb57jodXFRx(oqQ=iLiC3wao18*5 zAN=sxNFEdN=;c{nEj_4IzIoMRJ%0yzj)m+6?qUZ*)#s~{U=IXt$X$RHp23^o*O6D3 z#l^uPi_pBGMMoOu?FjYhA!tIQ6dsA^$1-fR@OI{sTi>?tl-H~pNP^UNR&@PYAVbc* zmbB+~J9d*p{gq>+JD&>5X8U&j7!q9nbeP-?v^rNV_>^IdsA&JfC0j6px7VgPaB%v_ zeCXM7d3JCDwl)w!U`b|HqL$5^3^GHDm+j{#CMx2rZmP4|#pkDv_J3(h0%9!J$iR}} zv;7dtq_wytyojY$kBBl*|`%M(f*_y>?l?a(K48uv} z>j@~;?XKESXQN7<0W1M4@~(;`{zE}~bX`ns_Ew#QDQRi(!a=ZJ`FTsyId30f-?wgy z+mHuo)f-G*3fsM0(wDDv!EC17_$uHj864RKt>bYMg5}(ozgN)S&sV+g6~Wd7Xz@j; zhX%-whL2;3V0V*ORPNJN)_`&pzv|<6U2O8(A>Z8(w@pp6b3wQP4xfg;mhf(~;sLUT zzSgv=YQrbzbE6N?hsjn?MQGd+!NGV?QgTC+7FDD3l*Y&Ob;0!&b2h6JF4(z`cl!ns z4rV>ct~-QvxNK*S6BRi!mjMO5Zz$!@q!4{k7?}_p?3tw$rJR%K?j^uv%<&xx0>cNH4Ep^8VU1iO9(94iP56t3?&-zIiIb z#PEhqtFZI_-Z81n7a`kUyLoQEI^GD08+*iF1%0s@)_#eEdTB!*mB*zPhmr37NXgGF zv}Tjb;*F$t4we@VlOx-bx>h2CPVLfOSc=&;Hg;)jo8r*Y?y9`Ae_gWBlzc&GA#LlP zoxjbWvCx@=2c>2wbCEd+5>lle->vnEe1f3O=NbhpP#@3b0EX1t8vq_`rec->N*(-Y zA**kK1k4Dww-HUOeJh|2%QdZ5_BW)i%h~pa@VN|xjYy_KB+O`TvxA#v?T7UrF%t)p zh8lpwg9iOSrUw%;`fewXgF(L^X{*)%(3WR1B@Q#ZDxwC!f-D5fI{G9K3--UAW?cW5 zb*=&CzOB@;0;zv9jtAUWe)St~Q{JXhG9cW4?PrXjO0Vt8!vn7yJZyD#aKibmix^}LNNz(ZX;9-#iUFcf+K8c7n+&%-bWTxz`|m73 z|5{9_JG4fkt-G(Gg$4Bb0x6U1!KIQy}75^V+P+c)wKifB2SCQ!vF>BCo&-cmcw>8e^pewvn#+Px~h_9 z?6R?PN&~tuoq>(&x6}ejW>v^q1ciy~J+y|hf|9KI8X6RfuxfA_-WJ~ofpp&O#!x#> z!QCpKCj7SVzB9-G*~wmZkyeC-hqxgdVe9sS5#&^X(9bMJvsjX2Qd|x;J>7hDrGe{d zaBQfe&GN2FZI#aoO&dK-dH-{gQTPY1>zq#@LY$8uSJPXbB8xHObT>j1ObF3soJsg$ zOhxY}(8M%*Iz#UHRr)P`B!Tl_qrltOH{-Qc=@p}_hs@!{?28r<7i2@FrO~(=#(L*Z z_SV_wDklwE>e}^Igjo@7w4c}>lDQZ78NcRnd&yBQI^GKnsw2cutcMdg`UJrwAs>d-2OP~~!>a$*4c)mSbk`SGg zWHjw5A946F1~z1^Via1y>>o*yV(EFC4L+31NI)H(cc=>>^^rp=TsK*fUK%7(T-Fh4 z9RXUfO8nYd63_@YnhRTHAPQj1Hkf`!)$UB%A?OvF3pqV^Z>`5UA!xpM?zfNx9cdOo z?%}c8smY}`6S+`;`c$V1Hl}-CC5d@H_D)*={*X;yr(b}dC?=fpYA3Qyl?lS(9abjYEuD9LdHAzlmJJ;`1a@9m= zJFL*nC19k={wi!WEAdO(`K!P5g5lf}!k)@=oZ{E~ml~W0i@~07j>hH%}r`gqcXZ5>QWZouy9QNgy z9TE}eZhf1YG%&@*(~@&MjE`?);ROg#O5Sy0;3^1i$IQ%jTHi_AftfM)(b(>VOV_r? zwDz`k6x^7mbjFXhZcZOVrh^@$5SuMpcj7O3cmCI%By85;1&Vdw{ z@<#G0E`gw&ICpI617e_Ay`ofLhg ziD_$NaCUUmhUTML>EsI`8O?D6L^-jUyUZlD>Hf^Npnw@#tp79eh@E63kHGf|b@j*e zMgEBQnCW*7SlDc&WdPmTVS@v2SN}AT_==w!y5OR%wZ@j~-RS@<)&b!#zNP#B2-4IS zO{b!$S~0^Pj_|B5m6A`;D9|-FifAe&&}fp&L~<=x$O?O3NRb?F(@CU(*&pTVFih4H z#t;ns+ETUuf*~kL9Q0QykHXkYg*4zcb~P&sNc(CP0vD!r_XpZ`U^$YFi!&!C*~856 zm0_u0+{#<@Ui8Qo7ijR3J3m4X8+X-e0+Nhh`c4zWr_8HAlH=Xb3i~1G7mbBp+?H#J zRVIR%s|C63{f*iE$93aLZ+_3zHnxBjS=U;seu!C|o$OL}FtI<#|5_mb97zCr+Z&n_ zEa3pGk}Dt433xP8mfKWEt{GEr0Js-l*g}WIua;DX7CXQLtK>@(ql-Hb+q?bAK0bfg zmxV`oJp8SL0n(j8SU_!ksKGBJV9~Zg3*7ESDpD8o_q-X%>-ajg1UHfBO)+uMA{VPW zhr8&DL0$41Uz$KaN{D!?SQ#(n`V>HEX}&k)vns35T^ua5M0mC2`=j%rOhY*v!^N~u z1g*MM!X(P_zi#;hL?q_#_Y_N5eWRKsOsOT1dE}wL8f_V~f(E8Xq$kOgT!#Z0al9+j zi%IeDvW;``dkp}>zJ}O8>tn7$)fz&s>zuP+M9?S*dtN`{*1&wr{_Hq2Gli&sbS&CrBsZ4#q?l1B6UBC6(B_Nb8TKSNEs}*)g4*` z-HHsp>P+{H?D)b$I)3rsgOk*r%eE@$4uOQtS1JYS;6|ND@}5}EMd-{E;e@}r(e`Kg z%Br&?f1sP|Vmx-%%H&a@;TTNdg73r7`0|U7yT`(*-8!m407Y6Oyg1VwBGvhymtdoX zF87;@uvd5t^3$~kR5%;o^w!3@MB4bq^fC*`?!{amOufu+`LiQ7m?_d_A!^tQhXYsz zsmTGe95Ck472YYYk893mQHEV?;xhhxt< z4b{39)b9Jdp3uV_thMXdo%_@J1kR_tKe zPtPP{46ok+;IORf0(y6Mq`D3%*oMq z|HvRrFvHQj*6{QmVfi{z_gLlX3Z?d#`HPNd!yG&$?U&5X2^s#}LTQ%tudLPz66-V5 zlKti8;or=HF(R2$47QA;V_;i@70O&(F&fkB(K@MDO zu>AUygsr-C>?oT5rxDhmvevMXhX-W*JdN_7p)sLn0cwC*9BnlRY2f(1dEXmxPC(r< zy;f^Q>b4%<^=9*s$%$v~Eb$YgQYg=6K*i<|tf?TJ3` zO}EBhF`+9E?C$kp8-*bp}+Uc`gmEI z!*&cPcvMa#xi_wR#yDify1xP7)R^Uv73I(C*uEzXm;jv27f4yXQ&}jsw0T4<+>?jj z|Azbw%PwqRCxH6q$G&RD8!Q}SeF^!lw zcJzzoklB-GuEBo(y3nz}>&AVy?u4XI(XNef0&a3q1p+ti{l#1V4}0(Z&}7=J3)>wF zFry-hlu;=H0*dsiA|fEYM7m1vQbH$K22c=?F1-_aq=XWhihzK0LV!R}kxoE*36Qfg zd%x#wXV3Q^eEdRyBs_WU`(EX`uC>-tILB3k@CMk1tg^}B5XVy*Y{324v^OtuDv>3_ z_#ZjhiJkQ6$Z<@aI;B2a(B)Kdh~KcBS?{s9c3T5iU6s@%U~jzTFU-B5a;K14gc$2x z8xoReP+q#*d@>-^sXq&Y#{mM;N~jEG^Rm}3`F5X&Y9s>FSNn698eHdxubaw!;T^mA zF4|v43^Lloj=kS(DF==n3{J#zexnxxec6h6q>~kTn@1!=a;rp#AaiLX)+UZ0(`Lz|!(KC#Cv(zM>e} zfP9?R^{d?l_L3yh1#Rs5W71r?jp36d?wM1gKr(a_E$mNyLaU;H zlK*>=P$HIjOWrgx(`dUU|K5(uQvH2k&u+-E^Feii*4|j)wV~;q9 z%~wjN_)hEvj6D6CQ^IZ#P^{8R-L}%n)RSso9vYNSK-M43;unyqEZnin-(K~<4Lq9O z9EI+!dG*j!0ITkjq!plku zIe~?#-1f#t-g(QAbdc#ie28L#o=_})TQjPlmp9HIC(crw7O}HoJ~OI}!F_d8p6yom zEiLn*z{=#6nSe}Ol9Y#5fu3(JxanH}d2)tfP_5NJ-tSFpJHUu132)_y52GPol)tY0 z`EyJy6M|71^8aeQt&OxIX849foq_Vv8EAl9+XqXFngF$c2{b#V$9(cg;(MJ~e5swj}79B0w*s6+iYf@sN@FKOW7cZ37E#&@fqWss-6F zJ^2S9YkYC){P?9`wE{P{{!DvicNd(2_iC%|c0&tQYpx>m$0I8QV-yd923+yQ);VpI zfY3v){ov6CjmJ}8RFI1zA9!oy;AGWSt4E7FeyFtqbj=`E3f9=T#lg8JF4@&ZC}du% z%4^&nSW_qcVvv^14$Rs1T^IPPRKWe>sy2(ERFJU}4N2~w5GX(b#q@~4LfPPt0b&Se za_ab1C#E1)&YA6tg2VkCvyc6bO4~4YtAL7dY>J89rM*q~>;u>Y?>?D9)!7xO#Iul) z70^Ows?e{Se3^(ObT=b!;IoOlKuin1TZG!n>CrrA@3o>#@9hBoIM%`{7RGN_(`c1c zZNnYW#q&VQW3PHFxTxoajbbSc$u&@UR{pb+IwZW%JLO6lsGjxTy&;;479_{MbrTrQ zah|XsgpCP1b&el4DFdyF-lyM)Z|{2z!;;WaXW${0&P3UTXLf zZ$0xBN-O8-6-}Nj`EbC;RAFk+&G#CvXc$_!4&=maA9ZXl7O?#es)bfwm{SP&*}scf z!}FD)m^FEoG+pPBwUM9uXYd&XbFu{^5r@Og8ldKi9msXh7?~6l{y1?-`9$4D!p&2+ zZ{Kr@l8oQljj;IIc|S6qgX56wVuMR(lFvfa7k+LG!EYhcSnBK$@sEfiI{aS#sZ+zB zG>SaOab3{m0x=^RMu-GbN~4Q(x)?5*AFF7KsxyD=tO+^BI7CKqwJa-~b{ptcVJnnUWl4vp)0&!}{ z+Eh(FUIl}m>*21P&OeWteO`~iCBLhF^5HV9;S_Vzx6Pa7Qnht{B5mJ3j3*Nt5L(|m zk5|5uIa4(F7QbH6YOb}B66ak$)@j^wF7ojD!XDn{HQpd+4CU3?J*6b{;Y~W>!tmbS z#o0cmU`6Kvw5FNmdA3MWxpT_#6Rsn}qJo0DHSSlpO|{a-;*XaY|W`eidF_%`Huu zig$TPW#2Ymzi%w`?a`>$;_XH&ANO6L6;$ylK5O|5(QfwW;+mz#GD({%NrI3PZ7in& zcE)a+GSPyTQG3qA+ooN)Fn;Fu-)EOyqgqu$6W!eMi@mf)zO6wR_^NKSTpxjM8(Ekg zK^E4XdZ%M@z9yfyrTDJ^5zN3IWj)o>8oDgTgmEtx4H)TetxZ|cfx4pDKWjNZlN1;mH=BRb_Pwm!Z{|7y^y8X0%RV;lK!CXy*8sk|kV zd_ipHN>ppX$2(L`*m4Odw8T)WqatBtPhi4&zU ziE~@ne-y*@(+O!j>0Dl3)+4$fL@s6f_Ze^O=Ej+*6U@{d@c0`h+8EMlW4-REHuehY za)>^(q%0nPnSDzhbAuyr$X>L_Xh|(#9NH^m(nqV5xB~)wVs*YPvOo45l(>j0(-uj1 zL5Y*#yoH?pvGd+p;jXD?rDKh2ePC#nzL`L+A_LW|E+b>u`;3*J?LciJR7P4k#hpn6 zA(&BRg>l2=Y5gJ#W{KwNQUiIB!HW_ETda*adF|_C}jrx!6r*7Eh}!* z;$JfVvT30NG<`=k72n`l_GEfg=#FyBF;5meM?0ETNpmo*)Efw zit^Ng?yr{jJS7PyS=}?!{jNF(JvPgbNkMb@XM%1^xSUvVL5Ey@;J|G<#zQK~$6*MJ zB0i-{J3`Z;AGVhd^ar+`Sgy45lk@V*gWAo!^sdoQ)IJHWX|^!q@grwPr4l zr;5#_he_A>)J(zp6e(+k`5UoBLc zV?^4kmB6^T%HeX>H0L8-kL?dES&D6q5&cDm|bnlz$S~$2&vm$_dMmkEh!@?-8i|yN|%1Y zbkdEXxYLX5>7=GE^}T1ED++-vNFFxJ{kE1{SXh3S==1$~ebgE7YNXCqiDJyuXh93R zV|JHZy{4h4Uv_!_;BkWD#dK8|-D4h?$~s65(l*7`YX><<@2Y(>fW{tlbOo#G z=#fSTQ|as&eqHac%*PVMoem%RYc}#2!`v%>vSv_NW0I`tX&GW(q`9#*(J?JOIT?AM zTZ>*iw7peL@9y2&bPP`E>7z%@`H7aUf$4tJ?_K1jILhQc_y)`lcu5v=Yk9J_0eUpQxcdns~YF9c2nWXDpK~F zBbIBmr@qc)WZ1@T9_q@HSX$a=<|YljE~Qg> zdDp$CLXUy!rkAeL_wl`T>%NMHZH6SrbJXz-ss^}f;z|pPL3YQ5y@I?x)BHYVv$b^H zIaxKl4g)OPk~Cg5|NhId!spMg%A1Cs-eVa!u;hF}SLdx^ri4sSmJ+wT)Q!ux^0?{o zv$A2IijlJgon!o03**xrI=gZoX4yS^_Dz>W$k*zd(=_IC*xEiaJ3L2nR=&n}b_Wq5x3h_%Je_#}M&(f&ZvV znhjLYpSRez_x0@m1-J=5TT{ z4Q25QI!j#@^ckDgT`aKM2;m*!@}8jB4i^^SkPTG=w+pqQL43HjdL)ms@^K)1B%9cR z^=|J>F5jtneTZ^!8uq+--UP?Y%F$W z;awu(j=Os#$;$zRtXggxrYM*An-b&%1hiwoKnJckj`)sv5a<0d>N$tj?KIWX%cmW) zu;jb8gD(wjrFP1~!owSGHzu54aE(8IjIB$1)GoyAK$*^osh9rm(jBm|JU3RXlXWrf zx)&vGT>g-E+f((&4{^*hlKuiSeUGAG5@G}ZnnZ#|XnW9i{TXZq3e8B@# zYuiSr^grM*vagwMs3eM^Y@D17c;i~7CDT8K=ThwlU&9$I7J{Plc4VLFyD^%RUG|Mo(Ot&^PB@Cu#K zE!V|`CYW%X1&-BD8u9R9m1F(xiMrJhjm8%XC2Mce&Yzo38hjI%INLv!&ul=OU0z8o zw_PN*w;O6|I)L)%p-(E_fU8WR@7jW|s>=n5?Jk4mcGqDD7;eiOBNr;bPI=-`}wL*b*hY$S$1MuHDv`j7hT* zwfbz!zmhAIfk~bFl$M_q;rdA-Qp;rFSYFsEVb;@kIC&~#yLxtfr$oA|mi!B@-D+oj z_Uw@@0rdobFui1a0nlc@H9S*Uw2QBQ%($7E-dqtvaA5kx;(*AFvFOT5*GS)#M%(~= zpmA#(RBh zL1X@3eF2hV7BrODe%%g9$@jYNyf7EFnysrW?oM^wyqVeDnI9uT1ZQ8ri?)S91nc$S zi45Y2r)BH+)ciQJ0~{TQgNT{y zVselLa=o9F)FncVPsQdxuwrbM*qB#L5&>;cjSrw$l_9 zPcmWMO>aNc@!!GNvlmuZu3RYiAq%>80Q!Gv>>;_4FPyUY5DxIgJc-N1?onIv2w}KDS5LcX#Kg`CSy)R#rJ~E5jz& z@F$uh<^a?66hTNX+Ph7_gY%sK@R+9uC&F&`^-cWR_O;FUAG6{}V+ZzA!&!G-MGrww+VaQr#pRWT*crna zPeDN^V~;)-`D`3`f{s*=@b)F3lU(KM6h3^=#C>n`A5i{6r|?Xoy_^2G--^m?Yc3+) z!^9V-?(^`7LLy_((tqb|$ek~dH{Kn&J#n8a%6pX=Gef8^R!kYpLXg^ecl{~yai&}9 z$Z6pbi_!%g9&{j+TWY&uEiXGP3kZj9o?|?N+oW<7x_8;BpJYWveUtR#a4*_Dd<0Fz zZP_uNowV+MJM5JnjL9af^|lbEM#2x%hucItd0v) zGb`av(PaM^21qR3h{-E>m_vDkd3cZi-9Yr?_6;dHI7>6yE7Q9%L?)2FV2E zsTkMgSZ*WT2{&x2>njO4`S#fQ$I~YmoHQrgiwrh;e%N%`e0#1q??($N!757By?NNg z?!-I!Rk;J_6tT1O!jAjrk&O3AHr50S#=D4PYQ?8mWWMDaSSk>vZlqTYR`XgrP*sgP ztVFHyHOJ|(ICgQ!vOws+E11>b{}Q)W^t=Yx{cA z4;3UMp&cnuH@`S#?2^O5sydi&_DX72>SP=}>x1;ytCz8|P9b`A$)~(ZOT+NiYAs|x z-yM901%??c1+iky5S{u z5fW^Ruyd_xwB_&X+2jwbFCG<$Of`MezEtO}E?nNHWoChm#d{mod7D~V6YU2K)WaO^ z0nDIKUyqK=q+g)QL&P7MHQq`&;|lPyspo=T*HwOgH*bvwE6gzgK3o2+E&ayE<@9t_ z5$9fNbseVfw3M+#!aH44zw7N57To;}U%y^K&fDL|wcZcM^dyB5b_7NRq8t40g-%Kn zvuo~Yxrix|%$IvRDm!$or}LQT&zv>412+WojWn8?wzj8V*qu2$U_|)hTQKn0@yd6j zk#<10ypqWcaAMSsHOHfM3ybMnT(hhe+j$E;J-L#^oj-RM+p}sLkNSkgL3-`nz;o0N z$^IlZE-@cIi1eP}(IbI#kk@K^-cj*M9Y1lx+vHl0bJ-DU^1y2C4JLCvncOgOuKtAk zCTdhrgs-y(LMPh2b@yAhVxdgBnFI#k5ViLK27v}jhJ$Eoc1odn%@H7vTy!H5vTT?EvzWQQ7!o5#X_I(5IYA)50;UJ`|x=K>z~P6 z>WQPe-^iUGhM$#R5_QPCi5>CYRI(CGst{V;Sh%4CXjNeSELBZ$ttj{kOY%45Hs z?E4u}IZO;AU~^P!#C6#)Gafj%)({xQGOFC->1|puRH(Kw80_go@fNPkgdmLB!PKx2 zKnK!VSvtn9@&r`J)TUgLwCF!)#@Hd!Gr`EG65KId>zs0gE+y~%`=65GeDImk`Sk!K zeeYojI2?m{#?VrXhx6&p{EzZj@q@HLaHGXZ5V5tdpysie9?_rvWUxk%+GXDJ#wESI z8Me@tyF)S1JtS5}#B+L$F>DbM25ru>Ek|=@N<_V3fTGFOMEqM?&5qIKmJyq2VyO)( z22aOVYClsj{BFI>_O6%vIgxb%d7nmHS9EGzPUzf}?dE4gI!4hhJ-mz>p;(j+4TFb3 zN2ZJM&3Tg z__Bj&fwIbpt_O^55t)k`Iy#2(SMjQ|QY>Z78WC8VvSOHAki*>KS#jco-DH29uYH`N z>*}nGW?xQ&`82T#RSZ%>Wki>!Dr9HqZ{gX3nUo!sEWS~c&2o;4C$PHO=qx9+Yx z_cr0J@Wfc)4;&l^sO-jke`sS9fil?4(q2=qsvwv12BcWyapAjDU%%c}OI1&?z5hn$ z-QtFA>X@Z#4$Su)Q)9GXl^_WkbAC!Kt{S{b-M6tY5w@YLZmRZ#!#!DXyg+NTVWM6} zB{~`Tg(Mn(ALlacie=ObJ<05yd_avN`yCoV!{8(6c!veB9~z7mDp$z5vha1NXw8Z4 zj*#lB#2ebo{!tH}BtzR22uNQQz)HkaSJ+GH2K>kfS&R!0H^ojWsgcH)M3r7i!KCur zK16dNo8i?s5N{gKxC3VE^wL#zH3*;2^#HPNT|ScTqHNTe^Z4eOm1C!=kM0>rM7Z3f ztnbV&p^l#@#d`I{L60`(t*xUzwYx(Z@-2^OxnG?FWG0ym#V}FMu}s0cIH72Zt`xrsfqOC7LlA~i{Lf53{nv|4M zgl18f`91frV}3EZhF^dt>acY6A`y<5j_p&epY{4La7Baw;qirGZ49cUnX!%e`2gD3 zPEFG7Np{PMk@VihP*#uB^e*6QG{@KR!F)V6l^M*~f`JNbYf@_QNYa_`O3E&QiSAf~ zX6UfZ2q(jUrM2TRh-@aJ_PV+&MRDF!pSSVo&Od;h=qq;i^D9;cpbP}Jx05!H-M0|o>d$V9nYHCgoy`bq+yOQfYk`XT5<772V{b+vZ%83iK z)NesX5L?+Xc^@?DHrU5THQr%YV^0APqnJIOv=FB|+FlmMBh*{x<26^&{Fk))z!Xo* z1{eoXc~hk6YZon-Ww!9CcSD5+JADl&{SF@K&;ZoW_Kb?dvEP0}Djxv!&k#bg0`M=i zOt_!ZSqPS7o7lcQ@G0Bc$B@PnrQAqS9BgZQJ#`Do*Ox5pK4J>w~SIUD4zu;(^@)OIMpvaW7^1LR|m7{Bc7xb2ot^U$4l zH;aieXT@}c5zcyuo5;%~H#$?cAC?WRwuh_x)EYm&y(PkTDML5lm22gmSIWgDpQSFU zo?54K_e-%hQqD7A7WlPFiHO!1>~3-aO%{KjYxKz+`uOqSLiejASrm=IL?5-`TP7nm_!fS8`}lnQYA0gT z*1$XT5%N$ex?|a(bg;Q+p5F!*dv&g>%l3N~H>8VG$6MAQZbGQ}4UlA0Y7x}k9rsHA zu3euv+o4_ra>gP&AFv(Wu&&Sdua&#H$`rhboq1P>ZWYiyFa1Lj{ptO6dZk1wXzY+f zBN0Rs@kJ%Hw}2@(6&s=FkTnAFKR1rkA`fkFu_ygtI_)>T+oo+xyW3#2kbMrR7xtRb zi>8siYM*F2hXV(U5S(pauCX1ou?Z>|sjL~UxR8~bTe0pwpKdKLQr}1OCIG_q7i`?A zoOFLp?3;b+x2<}eLwk`(F$^%Pblfw53{-QRD>z|*wOpMAbyr0tWOXTsfJ^=} z35Wz!U+;q52jo7F(j1fB3_~I=SfU{E5DP+xr9$w^6S>wL(ar56)@|ie$=ggQibrMV zSQKEK({+^skU=C}+@D`weh-9%v=M?u=60Ej4So-}qLkznM}Dk}S}6mRS>a@ywq_^m zZ0BoYk}vD)kuP(-lSo8}jfoO87^`{1TJCt$Vff)SVx;XnNq06LCElxFdbrE1aLJqT zKt*8c#dUX`r++32qcW_N3TTPEE`TI#MP^#+EWKz~HQh26anBsZxwl_lX9mK+$w))u z7A44fpf2PL8|k*zmbYUkrEj!Y=YfGiRyF$=M@aSqgz<`U%y^kls56Wu@LA0Wj*L72 zP0i15kL((&yBJ+yd|M_xTwh^NT*kUD?zEDZ4jpq2wCHa%}IXma|2ni z^6T!v@r@$KE`{^n8VDG0*gkJ^U(>)K_vup&I%aQUPD8KeKCF72Ba@^q*Vw!D8NeIsjGr;w?BLyJ8*n6){CC!svl(0ri!6dowo+t0txCb*8rYPMDxDUf2JN{u z9tE;ILTB&yB_bvqq2}(AO$7CQsAYqgs*I1Ro=tBc-d59n;JSm69HO=5b*m@eo~OK0 zi@R>TX9NVa2Pr5*Ct2>?wpdYW0o?5?V%*su??|d|ZXLCo{;A!n1WJ}slr`15e)j9rsXLrHt3q8|Lbm)$ba z^H&j#*@8+5HE>dQ4+ecH_pfjsHS)=DK%t;9&7Q&TQ6v7SR`a)+@BTD|mA4yZ9&aQE z(HC|@m#Zr`R&t5Qq#2<;Ize(*C-Nasgt62;TwfK0F3`!ho%#Cgx^fgVfMh_Ylmh`5 z$m#6*Q&fr1^Pt7nC}fF6|Z!Pzz!Y;T-U6b80q-Ofu>Glk?c z=dxR|8K6w%g5>c8lXM2S;NG_(3%Y$d#Iamd1NkQ34{c#n~lI{KF4 zJQvo>F{Y*@Z}KT0h4H1+?0rQZUtH~2wYBW^w7#nqZI08)`@_tmB2!9UsnF?y9UoE0 zUd?dnlGc=miAm+eB0Ck!yU$5pX3rl#&OlNMoq%i3Y7;j$9*?_yVwQZ_VRvyu}$*{7p%f#Br_QHM>sYgT45fwJLxh4~X0Ab7SJq%o4=|kQc z;}dcD0@1b;J_ob6w|RuJ#wluv+^T+K>?Je@(jf2gm=iGxE*k#zKF^4Z&S+Kt);(8R z-edZG=fFO|3LE%g!dj3C8jx$p4n7!*yw`{l$U(FAfLr8c^%q8kOxF5i;i#K*7_JKY z#zrLsdQyKG;Sh4sE05%};sVHr zqDRbv>q@iW+E|xk-8w%u>yp(#(aPRhAzD?-;clpfGn5hdIHsu#t$Nyf^^JG`zmjn#SqCC0_K zfg{hM<{7hVPaRE3bt!YW4PYW5R>)(NM4D>kG|y3FPm@2se@1ZlG;-t**C*Nad&?%Q z>Ll*G+F<;k^M=j)wDYz-rD#y4#U#gMK^1`wARUrb{_%m~I8}nlMlr+(Ns}Sr#H_ef z_Sv4rZ9-5ijT7dG;XXd%ABQo-pI2XAUylJGImPRG`Y?ktyE+MNMIBO!bZh$IKeNn7 z#Tcyg2f%OI_xzN4<@TIvz&w%s%rbx&v<3AF6rs9N8h^lvhXUd>Q-3c#$VfS9abe%z z3a1kS9zG4Ax=NtT@CUYO)=`Yom9$f?>lCV}OBKenlLmmLwp$I@n4Ue40qG1Ra_Lrk zL+vTQGoI>wkX#d{dwYkAM&YL`5(ZD(rTE~&wPQNk-rhGke)1&2k6|yzom}A2Lv{Xk z+F;wxODhqQ(&D!}<#)rXwLg3aJ>y|sSHJx@HaK{Bbuh}%m}}p}L`t_Do8vc4-NFk_ zyE=f)XwAIs?Y-nD|c#{%7xwagG?>}2_y~n?k~k3#!;ObYNV+f3nqmd zB-}@G701jgv`3yr!3kd0GC*UuzfoFXLfBO~>O*Kh#|>m>RDviu128ULP{!Tfv2*|` z87g(6z>D3v!>5|OmvMxluD-XLKlZWA6ZJQWF`TMgQ6`=fRd8>WB29c9--R_hIs5p~ z<^r&Hc|NZIWo4Y}V*fTam3do`WrNB1`h=-kOsclFS-BnMQjxKYBB&zrl=?csq^aZc zR<2OqzJ0;B)?`)51ELKQp?LS9YSL=7_eQ+=z2%Tl{UY`Tf1@BXLayP4Gj8J)PQq;frf1I=sTJ(Xbz3Gm_1aZ-)M3{W>HBVEbOhUPX~o z2Hj}(Xm?l)VEq>5jY@D{+dq?eV#1t%Ofh9G$O!ZlQqFpnC+nc(3;}K2t(~Sur=}J^ zeSeL1o8UH>s3y2+-LpQ;c-EW`ju%us=nyM>`9Or!tSUJRn?piZz`dmv`K5eDa1O*V zD!g){vdON=2M#nQ4P1|mj;_*%9N7-GKY*9I<6Nvrya*=OiE5*}uoyMu-wOejOz=|u zQ4|biALrYt%^ECZXOd0F7m(tbv@X$>?7X+%7B*WS5%8C&CNR!TEWuE=7Xouo5W&H= z1&NLnBUVW|4~Z#|kF4Zgs@6%F_gD^K;)|>Mn`F!+Q$Q@|F=CwZNjDj*30$nqhE|3m zv1*QpSs=7cIJI}lJ@6RYh!S7W^+5z~5*ZPUG~2Am0YU)I=JIZS!~1G;l= zp^jA(ry-E7!pecEhQaT5zz=d2VDE#v1sI955b-4^2$Kr|Ik&Ll<^ej1Oxh}=McZeK zyk}yG4Y|v*Kc*|2y5_(uMs`@nwEoCG7Dtsg6Tl%JJ?elQP2bedInKo;Y_5d6@(RS8 zimrmxUF7c1(M;MM1TU+ax`YD-VB4FU2{G}xFwlH@gHv$k`x1lAa{1IryD!1gtJBQ# zF`a$T3a=hKbqk5@`m8%`$S)KgU4RB1;kcjQDI(tU#xw)y_XT{CLCHKnj3!M78{+G` zBjP^dmjJ*VD20}%H;PrVvje<$zUi&sS!zicp48O+(Pv@B+7}gGv1V=TzCt#&{`~Gj z()Rec=uBC7F~Y#MFl!k(6~HuxQQ?xdr&9YZ%XnoSqhRptEz0^{&IQMRlpssfjrqxO|0n6IxV*0}@JVVXt#MZu{$e#P5Q2TRC%GF1?)o{)E(D9ZIJxhjnDy z(4WcoyHC>D<)HWK)B#&w@1lt&)a9gYay3q~^}zJd4n~&Vd$O{qwpQ8V@m3%6lIVMp z36<07G#-_$j!TD+^`u?+f3yH>h+_$0+cY61LK$uT1?ABg=$Xd&M~^a425tAkwZTo_ z=Muy&Uc2)GhNXd0xV5DPli>fy|2KAFHWDbh}E%9eWV$IAwKJ}Eakbe~%SycwOGoJBJ@NKv7;!u zk_YbP%M&`09h0N6b2UzTTuy@QUX;z&F^qIP$Dh}XOiWC8uY8WR7lrOKpC9w+>Fejw z|X3ISso8PlRlG zTEuRmP|r%E&k_s#&Yp>FaVj}8w-*#URFKhuTI7YHqA_l>2H(kKKI+ro8?jkcRXa62 zWd_3J**IQRHoz4t1-d=Pc2xD_(UI@q1NT>q{(1PYBCnjFs=j{9d`xI#qoFmVzQT`J zQ;ky^&Z@l9!+4vjpip{STQlo>KYyOJg%}jL5eQ8RV2vQIrepU?v^3fXYd5FhG&G;* z=$NQ32Q9K|LwF9ST`RMh3{?c^`9coR{({^wAG!eGo{X6GSI?cRT(1P=o_}ZI57=|j zrs@aUG2B4WLSUr<$3j`9tssFh?yau7ivvVHj`a?XSpP1N;L+l7$QFxeDYHbg`Lb5c z`U?^BK{{rM$xd6$Wy=N+=rN$R1_988$BPE~ndS{eW6Os6Le^gq7o7D4WNo7N)`oHt7-8Em9L?+96sY_Ig!nuNrq7P;B ziQ}-@O;9hlZIS{F&yVqOr-s1f+Q1YeVp6?;&Df*d;<`O!rDkjdoZ;y7a3q@ zz&f|XCA_ zzSLV@TG9r75|R}Q*iZH2*Ng#Er--H~s|^>)p?nlT?SB=iv+q~_Eg%#KIjFk6ZGtg z07)d|?oB9$moM#$>UVRdzaL{L(9B%NZzsz#iAFyLH&5G-|E$ z!fCjHi_5jHSb;?GnY`mseIX$$SjUbQP-zkC>BZvjgBwRfzyUr5?m~t4dO{kgPu(P& z*XOtO$9%V#d^ne2E8`xwH3<9uaB$Q;-7*w%=g=s}hHPg_K&8z&&!il-}h#VU8c zEu_8wP2o-j%r3c{oR3RZfpaIb>uH5`kh|w!KS$iAM{6;1TBqm$Zv=D~;L3NhvlWg* zJG1V0mcSppyM3FPV8EgfP%Rl-B@fV|uErZqyLbfv_3;&>H?h|GUfH=(tp`;T+=X;p zqzr#dW?i}NTvMk-W2*Y|Rz8+M@G5xU6wHcZ74_=?_f`>+8XLvWRzPI-_nYfbZZcjBSIf{T;YWk2_L_(oQHaOAg43)k7byn$uX#|m1rCS=>*}wZ9 zX0PMe=^PIU0l4SfyC8?$eOS47)+!N5Z)G)7=E(dwAc{NS7LQYxQ6yZW$x49IXb;W=0f?Kp zdy$K)wmA>Kp2m}`OP34_{3sWJQ`h06R2uLD7hm}LwI`$*Zy@4=vq00NCx|SX@KN5h z5jtNTBSyneU+}gtFY2Z-F0?4dry9a~$n>FiUlvH7W1`RUa%7c&Gq-*ar8FU!H3XFM z^A{H&*NmWjgTKKFUNBM9j0ip@tS;#l#=%O=uH6ydq8#Rv&d6pKo5=;u4m0l+u|u>R z7I4cWCu{G*^3F-I(BeHl(2IZqRrg_MWL#zVrOSo|W>A(@>;aX)LcQU+g>53%=}Zr&I`j>vj`f} zyWnq43$zep-*ocx;ULk`BJDB>d4O*j_3o@icUbCzx&ahWWX6MCM;17&54_(hraf`( ze;>Qeevf@OkzSF|9tU3uApKp_oV z9^mP82o4b9juWL~6LU;ij~bnd8>j!Tb@+b|lIZSrA9~v7yU{ULzOzB#R5F1Y2IS&x z;1^nLi~uWynE|(frcZyL_7X?`zpioLzMC>D`HOI^FFMjK3Ldg_TEa2t;UkHZBLw`3 z6N6A)@}{+2CC+%y(>MTOCYo5(E4okkw=jZ0vBkcxpO&b9?8*Ha$LlAmm)Ab0};n$GX&I#pA>XWz{=@@U;)w*WtXKXekE<6+(>PI+*(No}t7(_cjp zFXf|O{=d8Y_oGf@E}~b8!a#M9+x%Ns>KZ}m;8B8~v^b@S)dVx)Ut4^@HI}yPCpKl{ zTHk)S7)nd!kN@_YE?k=ML_X8(MFUS;LYP9rE=f2bP^2$;vYeh|Gccid z+V;a6{HZkCi+p|OIoH#b&tVQ@1zA~Xz1IPm1`fjB$rLrw7yMGXFXA5?Gl`g+rgT`< zGZ#|wk&)ApS%CdQ1PP$eXM&hUBt+S|58i6aR%G3b?R~tpxlJQ3>zYn>L9k#A#4zV4 z2Q9e80G~mrODnVZCX~o0?^cr)6ujEHRH8TzAC8mrTAaH86<7OU)PO-wMuw5nL`yl? zBGZPO0YR0ysZaN(9jKPz0dw{S0zClpIF$D9e*~#XEJsZ2**p-LMe2aH)G=w2ymqY? zb>PTT?>7-_+|UaEWWI1k?dHouMn^+}m(8&T=KN*3xmVO9&-^iD0O{ZwqtFwR%;&$3 z`AU+y*UbTT0(fBnFG4wfmY45V0V0|jw| zr-eEuPeMlB_||Z5$Mj!U(DU^n)wKPv_qzek$g8Vi;)7xgT9x9#qo#&qkCKtJyiTIF zxW4gU{@oLL*m%}YWw*aF)9f~B54d+4pa9~(wR8BPmM*~uU3Jm9A3qvROl8})tOpoW z&lhde|Myt8|M`aRC7!}{JX2B|HoMm;ZG#W?Q0jJj2+2E~qdy`d`?Za6#<^K$HD{oT zO-Auo{_^klNlT}B%qNqeHJl|A1n>hLrUZ{Gxrc$f6`(+c?wojJAgwlIjrCs+#8cOO zP?+-!^b@o~KOv#-b5dvepNl$BU}8qKwttt&>Dh}3f!xC7Hhw|>^Q!;*@mH3c&nLb9 zloKqfm%qusyur}p;L(Wyk+hE~Q2lOOKl}&Gbm*WoG=K5;e|dS*LEl-aeMw%R3L<#? zmTO^*3&Y=_zS4H-WjlOSObfuwIVp~Rd7U`sO_~>*c*48vdinR~zXIRoPCiQT_(!9Y zzhC&oWclyA!y2ZqJ$CV5-fQ0zwTrh_SmILLA3(x5Cw21Qp3}+0VVyD_yR)2RFKXx) z^bbS+_bc8@1RUyc9o(x^fti+8YpnmWQv3Ezv78d_(gdOa2xK`;nSV1~Pj9?O*B`t| z2DGUhMdse#BL>kb0J$mml}GX%44I}ug4Wh1nNvG*8c=I(YwOb@PD9#t0#!!4N7WDz z11e9I0J)Z$D&T5@1L_CnW%IhC?s}P`a1f0bL#@ya`_sUvtdsRK=I6mnDC8p(QOwso z19x`ilO{!{tUlX!Laie0wKSx9r`9dL<2-F?LD4VKM8i)Z%%Oph!N*;J*~)qOSr4+S zm$;4EI}qT;?5P11Z!<<3i;k>ShdoFOhMqjRjCByZ32k5DdbP!E+bwnJ`JZ*aDQjw;@xc^Kw;8yT?R*>t72Z8o@IE@Dd&^t!7)QTw@0@wc z#=-W_*LZFy{rQ|a=KN!DWWzPi&NA}Jd{CbXCucxgyDG(Wlv*GsM(&?$Q`OcPJqtaR z(_J>0m?n6{1dXdD@+w^SeEs|IX_{8X17!Ca83-|J+y%5g?%~^{z3!Yrq=zYf|(dp}M+e!TR@w{MwGpZ=ymaLSA=!st-K2s+z0 z{>|`Do!H+I@~M-&vPK+sDz_p$p7@a!U2WMMjTSa*)1FBA<1|rIeRqlhy?9?~2+boG z+5@w}IF#0AD|J&*W;$rc6Z%&blqJh=!7$%E=(}jw+>aLd*@lL3xDQ}%N~{;Dv}w_9 zSkSD!ZZT5Dsr;~TSy|Xz$Wmsx|Jd=SPwqPAI@(3lT_1kK;nrrE7>()o?8i8^vQFD_k5{M^wY|LWMB+x#@WQY5r3DP~@e z^j`J7$raVQQ2Y8d$L{K={BVgw*vF3-_#|;LwSF($zHhQ|vOVByeAhNQsxsmUO-XPN2cn&gbyA_2z+Ecnt&0u8!l^W zSAm|2aXiApdaxc9jw$JdUos=JB$0;JKXRRINu~bTYjK?XYfn)-3m3_xY7M#zNKK-< zJg9*0LGOPEnEUHx+SiCUC#>Hbiz?Nk(0kqM!HXkud`_wFc}M?Ix$*Y_772Jdsc;FJ zQ}b}I^KuB^y_gQ#{;2b6ASeFsF|Ps8guJ9*bqJBC3Njw*zDa(9l&5fv)68m zjrQ^YREp$N0Q1Ki*XB!!wO5@(79<%lU1*fx#Bpb51+&*LUtM zpAGdvV`lqp(z#O%GVg{8mJ$6qyh3EX{oj=eh1(8&-$23&%j^vL#&?O5woXZt1sn|2P~DzYbJ#WuK4P>L?Y-uAr@sDT#gv|1o~0_a z@@%J%aZ5P4w`Gx`hjwMe^+uz7D{6hr_I%?b$geaeDI7}4lHt8+1$#w;En~U66g}IX z9WhuY`_YZ=lQsJU{>1<%IdL^!dp#_WA=-p}LmwA`yx zh{f2wPxIHMjAS>|!#R=@XuS4gW~RVjdar<4WX51&8{|%YKRfra4mK$F=Bd2}y@OwX z#~G;7+K%?OnJ87acSUdbUEjOQc*cCTJ}8IyJOxwNe=8_TjF`MMYp4h_j0oT6zh_8y zq%0+!74&WqMF{33r+7J*L9=HqIW_N_m831KB(gqzWZM$v%AA;LcywWm@>Li{JQ*p5 z+Y_oPDZn_^2)lhMpidT22c}-gITX`M zc6S$))W}_6@iE+_44Im<#7XZpuRE8Wd`+Y3aoW&1rC&b0L))!R)M7#Gq&&2lG(L88 z;GQI2b#;iTB4!H}$GP(3QQh`qDTO=DFqP0Bn!?@;nB$MVRJWn$M4VgOU?2=y`6C{9 zUPdoS^^NEY+ID_nvL7cdret**->vbb|9d@jou|`;9gT*%N_#m3Tc|mVzpT<%!8W6< zQ(x6#3t|JH1gAMsuIL&-7Hn*?xNkWO4v(7X8mMWZ7f{7d!Ye(V1{&?wHtsajMPZ#5 zg+|?{#N3U=Wu$A#1M&AQw>*!=dR3s~QUg!=^jwsVcX^CK?S1?_ig<^nmID5=4FCGWt)9Jh@9fF;j}w=c5f!dB@aj_h6FgG(P@Bs1 zO2-47NA080G0?H?`aI}zmb|?G)c8@M`+7Ty{7pBvAM#pMpvzy3CU@~nC^A|;^t2TX zmDbg6j7@OZNK21R@Ok>s@X-1Ehr1Vp|6)P<)ob^hM?)Sr*hBmW6DCz7wxH~825+>9 z=Jy(6Gqhq4Hn>=4(>ss2H!}<(%w#J7Q(Z;`>s{KizRO^NxE0Ik68nZW61E z(5h2cU&h*xkWGm+PENJK*Y>`lRG|3bTy+}#_X!I9d&E1=6T+FxOCCuQlyPm)DYSWZ ze5e#CggLffRswt-9s-h|@!(pj+j#bkD8!zdjiP1l1ANEbmlws7NakQ@VV}QGYeXo2 zh&5enmbUNp374U{(uWTzn1B|?wZB9FERGVrgUF_vmL0z> zJv>LGX^s4K0{g#iO%mLxlijB#!E@yj0XZ{OY;J8@R%Y4Y)@T*KVw=UI+tz2)+S60n zKEXVqpQq9U>+QAUJ7co|!zf3}UEjX_rPi#BpYsj7XNi?lmSYSV+t8z3mGHL+uQe{M zB5!Y6%=0ev>3&!&fWu|WrR6h98qJOGXR6bb3HC^7MNhjBJ=#AcnU^)srtQluFr800 z(CBaiuy%KWTi(nq4jfTQ1lyDu*_{g)b`^1Gq##~{S{E=SXIxV|BKHPqt{+3~-teBWACa>a zNi6##aor}{ALw|E4h>1f|B`r!aNt+NA5$~Wa0`Xwf!OG8%^po{ZI&}L76jSM-q1JD zD_RAK@92_mW3hmUNMm59DP<|}A2xBG+D-|b{Af-!R*&##DRQ{WtjAhG%whUeb5oO# z)~sYgJ4^udT+_0JoXg0uK~<6_M+{gnpP$RKU_=1`f(cOZUBANh1+Uu@IrHi9VZT@i zU4T8sCMEGU78}z2|LJ$`WB$&eWc_fNM$s5_Q1@8r-4mYrP9c%7!V4R^53m*3G6C1rBRiw`e3~kfEh~T>`wt9;pj8`OX#& zOPc)6to_eR(BHRRQy)`R_2v!^5&o?P&Yp>K*60C$i`m9%Z^#2Wl2;1A-GaYSlo=W4 zqh3-zFK%y=rjGskL4j-dA2QtFL6ysgWB2d!aj-dMH_5-c5-In%3qm^p1v zTNhGTL1>=&Y3(p=pBO6MVI$2+-?JWYsNLrA>lGZ^&1|cjaR|0cv zH0hNj^XC?9d3Q239H$~dGBx?>?XslT-=-b>`JpkP!Msif8ZXdH@GFhe%@7u46JDB+ zf$(vExz%Sp;1C51oKqm;J!)|_5EXHve|fPXFRC@B7>I)WC(fg&eVR*?ie(Wk>U7D0rUfwuD6dy zrkWvA!D!jg9=gYC?Oso{f4KQu=XXko+}+&%(rYw1Ic9(V#E+~GN~bc~ZD(dukBcqs z!dJ7mDdLK$Ha-U$KXo^a_7;E6-v8Y0`$C|3)xx6oV8o7J&Vo&41q6ME*M9|U|MlDQ z#C}QSC@GaYY-7tM;_a-a_CQx}1slll8pBmDy*Bgwm@Pfn{825b%&k#dxWD`xZI+p; zMjTr+%yvA8C9KpDOeqTp_Ecx%uGIX#z(xW?7^jp}o`)EyAb(WPL!!-4hmfljxg7IbyU|-NJH2A-5}MB6jrTrv*VZ|*Z6qk38*~t zPbu|~@d9^`g+anS&|z(hb|pV+Z_o4^J;_0{O@XPiS)Z~Q112lW6XQAYrLU9eU4v*e zn*V9`2QmXvYxgcntLea|lylMR6BAbGTi+j)Ymq8_$9BR2f`Rka$)j4v9`?|s(apPK zR=GeX2UbrcGwQ3?tN-B~3BG=LF~dd*&vdSF9!;J)JXrP3HXH?YFv~<8E~mp!P)w}; zow$O$|I+i{pZ3-&E2%M+uZsRIX;INqhNjx?-70m9Dr_(|xqps2oaf2tRl4S8Qi2D4y}!P&fH`2~{K!D{T{?kWR+k zX{o688qEr!BKDtvQOzw#r(=fG19k7o44A|3zIw63DbeCvs-g34?6S$}j*m);lsS`R zXKGx+`dCYgXOGY*p@JbwtOYs|Glm{$maFJ^*`%9wREQq$qXjd6R;Ce1=}KE#lmLot z*Uy`Lj%FhUadrBPgPu7HdG1cj+GlAfQP5ky4vFxQ;j^q|yJj~wuA*i`dXDrj?N`%< zT^g9Y6fCu|8Pfa=kslTzj9MQeH*9FY*h&#B;S3v_%Q9I>MZs4w?Zu~8;(f7{Ti<74 z;Ikk|z(S8pPzvZgiKn-M_lAp0BVQE|1e>u{mn;+b*aXj>&2Puo1^mL!$tmK3z6|rH zF$PpYLfu3FdmkPuBq0VW`H9B<7}UZa-92n^)ty~RHxC`s{4vdyw>v_Z@afQ2tS4r1 zf^B42M1!2q8j;UWZ#{6&*LRIyOw0lty5I!stz*+FSD>#lPQQ*hA^?C0fNwDazxVXC zX&-v&wtr4(d2`6UCB6drLN6%rsw%6CLEx1fcqiirG<%)Aj8bZZ!1ypnC8EX->Mdfb z&?`Cy(liWYH`&?Tw~$EFgxM>0#yfWH>5tCMErKjh1FF3!ruC7gU|gU-W$~kY#*>K=Q$5`#_)01F};PQCBi$OBCIv_3Y1N==Ta!@>*PH~ zZ4NO4(tMgw*T-UAIc!U^D`eiNVj%^V|FX3<8%?T(TD;P8h9}7D#+-qt?d# zHQ46urVR>jn}{2j!iBe7{8T$2;`p&>mS05V+U%yKHX#C;9sK47;Kc?_%4;=iDeTCQUu~Ona>>qO2|q>; zUsMx-sZ+4$Yll3?#&R^Gz{JqWk!AmDL0n;(ag(x-fN*Qiw;vr*=PXBl#h1g|7uTd~ zB|SkNKmy;KH%fK9*1A?ES@PVZG6FM%Q61Jq5Q_W zc(3u%#$rs`DQeKj3E=Bv&p{;$(9O$%DPC{sF0qjCT!0roiWY!3Y6;8paVzu-uvfmx zTk7xsurOwbwf~wAJ=_qxZ?<58|iV7QiCVk2Pdz1010FyPY7JNM0nY2>cC&xDEQ~f zNvTd9GAHlr;^cTTT_x>|=SM|R? z@Za_N-&OkWT5Q|)|JBwQa>Q@@YW_jq$Cy~zL4c?Xz-kW6@Bq;}3@cW5n>WfcSyY7g z@}h@J;HDbm68Q?rlX@SLf#iwS2Q2;b_weA=Y|f=rp&=u~|2od}2gk3t7cY)MeWI%Q z9S;B%w!IE&(B5v#ksi&;NTn`=zaC|OuABk50C2?q$kI%dndSt6+U2l2H^4z6U~Kwu z-bQUSoH%7rmVp0>Zi|KrW;U1)D1kZ>Crsda1$bB{u9h-_IYGimSv2pmozL(FVW4iN z?fUA@k6j}ASKfYp@_71!w)TiXN_2wHbpV7hp9jq$t10?ayn9Sh_LEhcB zrc&|^;Drk@;nEs*N?L@779Re5!M(?-JkH_mkP%pgXSE48Tnku#u489c;9N*B z#W2y(Ox23N#hX8G?ai)`U|!+9v!4h zrxo@_I(sbB2VJ1B-~m1*`nc@(2C;;8FjJ`xw4@cDgPCo(!g!Cj2@0b!pn*;)T_g?3 zA0ehigYB*s$#+PI2Yo7+h8z(yQ@UBRl}s3a7Ptf5`v-OSB5f^7dDda3fTQc4GP~at zT7!M0z$lvvTG8bWj!OF;o`xGy$0h4;GVkeW+>RfkC!EaUVXdG8v8S&?yv+aO9@A3y zhbocBb8)2Em~(~3>n|bs1`nFX7r>{kafCkY#&NO02(^noK6~;UX>zcx3MJEO zx^>y?mYfeS_jt1n%DTMssT^4@1oJwe1oHuT&CcbuW4Me6Ds5#o4!-&lN$H*jO>|f* zsgd~22hwAx{RH^rl$mD?RGL;LNBDoglk(f)K6_XYrbQe4CJ!x?PXQ0nV#jWVMt6QN z5~z^h*a{3(RCE)lnbdNf=+&8pdDeoZDM&5ZIVJ=JsjnirhcN{O_pEVkHZ*X65i^D1$$cf6auRFd zL3Z8!-u!1rU({H-p=~-=wXA$+M#%GSS@$CR4#HM4~MKC)c{vYLp{DNu(K}I_v)MXFrg@85#fg-J-CWK z(_Lt&S3Cj4oj~Zht~1x9&_w1+gRsAbNrEcqgfe$|SQ09PN|_Kfe~m@bewwsXuQIS= zB}sw+f#O{((%(Nqc`Yg`UO7&mnq9bX_7de8P(09kdA|_KHW>GOmT@bT-pP7h%I=Fv z9bF+uY8n^EFCYBMPq&|yN_?1KjQhc{~ z{iSq2s+|CpHTZjvOadEO;M!%6$}}T?`<-QJG;5Efcb|r7`Q2KOzNHMZB!k&$j!6%? zoQ02r19;6c+ocb$Ld%Ug|7UFf^XpZ)-}}9`Uq(5tk8&`1%yanwcpdlZa1=&=&fPkO z@F4^V=edr*eLqs}x_RQYsfHsy#$6KGUEYp_F;dG2*%qSQWq8#-i+4F2n)|a6H$I;w zE_I$zhyk9ZtsIh`JSZ9>%R`$DWq`MUs03p6_$73_*B~J=)vNejfNhveIASp|)qh+X z%;NO2fo^!>(${mR6Q;5RI?-FH2XVRe44(eQqA4A0pHZrgb`zHbteg&b4#l2BFgb{D zac%J=5^7Wkoe#hpNAD~b#)Uf02_o<|2Xu6t?`3GOX!NH%4j?F=_-O^+nCz5rdkab9 z=V$ra#Ac&|ermjWgutw#T8h#W7s@eDI(D!gRl($)46)f28vOAPLThU`xW+q>2985i zo?p}bxRWtyX*CtqptcQI9lm^?&)IXW_KkR_Ob4kEt6rYcF`{J7CNF08?NG#dwd(48 zs2T*l8D!SPX*mn*b|Xato8of$8DuJ}2e?`+%+0y29}p1G|;M+QzmJsWs zuW_`F-ry%MvFgw=lhP>)Q-Q`-MA&~ju9wZI5-l`dc^oIqZ8YtXk&*bZr>Fl;y~Rzu z1Nv`cgW>+aUWB-Hn^`zQ8GAlu|9ik74aQ2_ZKMx2%tRc=ObxYlXkw>-a|i{9*LT^k z7l{L4$5Oji843pBlriPhXV}DifgP>IDoV$M_ete&RV<> zUVTs1d$2}!Ggjg;70JR1F@emE1)mb57yvB^9+?*}%Ao_7VL0 z@6*_T32PEE_v!e^qdUjcwKWP#79kuJH7nBbVF-E+vUW|6K@XjN^6Xhr$>LAv!8QTr z$zKrQ7f-CG%^%EvDUSE7D_7~1>5pP#=n&8MCc+ub#PCELYzWsm!*p2K4GJ79<<6;b zj(L7+Z_|vwW6aJmGU^{^knL{qcJ6KXi)#h z2j12$C4Ma7``pE?f|+oLi;h1!!y@n>TBNH~I^S7x1mS;LgEviKkhpE;*IiIiG+5HWdowT>#e1cDP=pnU3C?0KV8PQJROKO zSC}NkG2<2_a^=~C)v-PYG(xGO?%c~iEf ztjLw$Z#iR3uF1>GiS_z)VB_gdiECHyo>Qx~-YF3hLLGf^e&c10s_b!T#G(!Kc|@zL_Akz~X*mY?|v<&zOPQ zjmi9Ao6ap+zf^umzajQbkAn!q{DkyP+)7=F>`0nM&5-`I$6UX-?f4>S{I592|Gal@ zjc)o1{j!~}+)>G#$$}>(DNQs8@C$z`cC>^6=Blxs2lq$zG1$5a+!2tNJ_x|VoQta| z?Ki-(>j|JW;LwW$bxWQ>(pyNYTeBApg}3w}**1>w+*|jFGtA)eo<7<37RhOQ7LHVr z1QS(jDT7oG(9x8^uwcY^DK@Mw3mZnb$b!Eam)<=*)tpAUr3h<;iwT^}&U! zvbliCZWQ1U%zF%ebAj;Oo{x;EXyg4hGP2B8nBU-}L1#Dk6 z6ZD5N2ZA;vLvEaXy1RC&2wXa+(qXou7hN?2`vzlNnqFJ$IhLYRIWU#e=Un7&>M|wTp`il;eOIL%K-H(*tKY(2RFe?Gwc_K;Q^~dgi)8R`cu+n-|)-;q9a0@qR`Yt zyFja*Hk+7qUEpPuZ1O=&t!tMApHN`W^M}O44g{pPf9(prxb{h9Y|Q#nJ8c?FsS6wL z^6Ns{zOix_a$lOCexWH_T&4C`A1wLH=M-kb>V-s$ zV9WJwN@2pfGmLJ$0G~OzI!|JvtmmRlE4Z_;;SCwDzOYUd*1!JoBg?My*~BuvMh)8f zp-(zM5)wto?J%d5^Z-P*o5nm&1f~j>Ef0RI0N{EfUmO7FCyG2bE%%BdU|=V!BXhz# z5puA;--Qyla-^JJ6|}dXWpz}j+vu(7xV=2N7Mv(Giy$)qvmC5<#<6ml7cDmgwc5*9#Jy6^DW}!ct39a>eHheBl*GiENTukD&8EzHO>j_k|^xcEi{qT zVbU2(W!C}1#H#tTg{n%#;gfO!thAqq+?A*_!M?WVdLFPRQ28mP>@UJ?P5X5uF$q_=z+tF`Hh8Uj97>&tx(+Bl;R7qg#ZJ?*))ks7r|KEl#92>ZPG1(fY|pW zn+J6B*9!;D^PwyP@nbZzl3f&wNiNf|)T}bGu-H5f%0|;V_lGM}rUf$!vq0(pJ>tDF zVU`JF-@X-scn;^%P}}&;#Gy5iu}TVAC)2~3lE9`W%XHp(g(D*c6Efs9Zy=yFS3R>L zxd(X3`tfh6$ood=cMeYVaoyZNz?lDNs2nMEThx3A69reUr3x*!KOS{~9wv)W8ZV!7 z!JH2gS;JEF{arB}`Qg=VH6$E_R>dOJ)R1CB`y8=J_>7pAf}c`W_R|&_d5xRKx$ozx zR#JGuiYuys;-**S80D#%d#|m9_T3i(JlN)DfGK2wg2079LB-e;VK7_&9Kgguq%$08 z705)K^5RHu($;iA`dJHuttWmZZ= z@sVytb*P&&+!kZQz&Z1IduxNolcw+YmzQDk`IipHNYw$euOAFRKS$lNsJjWdi?c9} z%TB~ z)OGEqD+3<<^KVS+mVKr1GJwHH(6gq3%``8-=rm%HC6eWwQL~j87U?MnwL(6SunwQy zgF$tKHMpjxmR`TH!AqR2FLL>Vd!ywfq!Z=c0haz=Ar;7ke4R`sLtygtv8+ari2z;G zow4Sk9wkimN>U+hsAVIL!T1wQmm)WF@-9-vt1dntz&4G`r%oh}wgS>M>dAZ}nBlevR#$iz`%Uj}|y zsbxwyXjdk-6utnPsz|r1V!l2Gxd}5qw=tkLEpXL_Y)6rP|Iu$NMRAaq|C>F_9$LAx!cS1{Eu5a^)$dpQFPg)BFjG-6U7@G#FI^W zK=YpSe1zvNN2e3X>ksZgr~0;U?F+{0Ph#Q{zs`YsywrK#f*z(kuxmuAARg_Q4_mMI zLkhO>h2gbzg5U`A)PnSDjR%Dj@|mQX}26XLm4@UcrNze}mwFkoE?2Xf=IcU@L*VzmeA0psm1AjdZBNs`tizz+E_ zGn0)CYcMCT_v}9CV+eVJOx;g9nc#*KOsvw!ca6;Re9QFCp3;S5VFvracVpBoWSJa( z%^C4MSw~klZyy=~Y^WaTJ1mbUAT`N@#M-fKgs1j=YOhU&*6(yPg!?zWZ^3tx@PPzA z9`iys7n+XYxQ<%xFAw`imeOZ}?&s)jm$rojOS4O<=lwTogGd>{tO!K_*|p8k`L8UsbCLCq}PWu}~J zZu|nBA3ztF`C+WrSGZ={7N1Npog|Ot5@$DYL%-fNVWP(=B6yQ1@Qu!3uHO0cohY>k z(83{;0Rz6KT8jZlR<>M8xIP@tL4uUNgoq=+;rmW3QlRmNuhYfTl zs6(#nT0O(k5rb~l|H9SjU>u8%PoJ7Ptgcw517~rCExf~&K8Elznf3~*+5Y>^pfd;M zzhy$#!lD)cVLD{{ePRbPn`i5P-L;$W`Bh0v>A$Nzyo%+X^Ov~fYOc|g z#56!65IZCDY85};xh}q!>!hwFz=3X*`mC%7Ru7p0zGRWAC%U>TkvVZ5ywLNU{tD#(r~ihzvGOQ3j*d_#e@ zfK$IV3IjnmHxIS8%by|Z-(G=IMqzQoCgEo6mbZAjjd$py=1IuiqqKI}Xs61X-%%y@ zZ1Ijypgk7|44B9DKzR12%Jl2(LqHS+Ky3%Q)sPs^Nj4_gLthc@f55;Rn8!@?ZpIw; zTZYqrc{N(_$Mj+2nHmtLLUemTGEb^7s@8Xed`ogVzNBKlhG4lV^h+Ytx3L4}YiMq1 zZ*9n_qd>*XEEvsu1bYj7czk@;(4~X#&L&Ob=%Dx3gqKbzc`FQD+kqc(JN~#CmGMX~`@|)ms(Sx?9K4dD>gQL$|@#Zkc6jCCsIC zw|}0L6u#S%QOkT|q$*L12hN`~&TQ7KsrEGNaGyrq=!T{n=C&kO0T8Se8p4H?O6bKk zx-tVqRLsl38-nox6!Y7w&uB`Zr-!`h)}PHFm2mS}DHU#j*YDqv7`n?ON{hi@0H$)``fhhrj3Zvr7?VxgD)*Ap$#Cr-9S9^DfF@bAp5M2wvXjVTPa03GnJ@e~}b@*KC z9#4D;d>){~DL8(}cYWu}cV;Jl!9qV7pd8h6PcSy4VIP6Ua2|!K9C9v$wOYVhy+$=p zQm&wY@*Ag%tw+pwX<%mOI@@8=>s1gz;&&jX8_-a63F#f{>exREwbLkQ* zcT)I}?Q!?6TvgfTlvZgh3hO-J`@*pBm^*AkpdRB?iDb=i#nZ%};d=ae@%e0Cyz{MAGbvvprjGcw8z# zazMH+&C{<*tdzJ0%*|};c(q=}>^nQT`E%dw8+*@B??)0rq6349xPZ3Pf>xYsVRycy z0#bGhIzQmRwW?%d-|*6r%wdA96!O*70z|+NJkx`j-#ye^hL|Dn zO}+Tp%!y)51NdnflNR3`(M;OV7P451B$Yy8=`i_+5tr=M<6-I0n>RJS!8qILQ%JaT zER2%Em& zTMOR@;a=lDuGsk%);#xvx?@}tnG}hhgPBTw-j*Xmjm3isfCnUtqxeiLVi<~N=8 zpeXX{kk0c5ZOu6le&RLXG(Cgfxik=vbwx(xFKoUwQpz1>aAV&-5tfff;Whapr(aVO z?T>{qBR-Bay(1B*TUL5BDgLSjf}>w+j|6CTL0xQ! zZdjWgw10}ie!8Lh*eGVydQ7$@Qz2n?fv!YWSu&@ z(?=%8mc_n-nEuyZ5C+!NRt&;J4A91W6G?4X#T; z<`Q37$0n?+%B3X7(w^*J?9Fq-AID+Fv$DCnZFxv}YP2qZ(MJW)wxY*8M}>GO)w%al z9zNR#lk|2HGho`D0WO_4p#ygZ8T~O=-8Qi{05RS{lUPG+ zyb;0TaFK^aPqLER?Q+$k6TJcz4M#=p8&LZLbne_LO*>`eVWUv^sF5n^w(wl+_*&P` z!MamL?p!jUK<=oyHv(LWRTYDs5()m2u5$`n9@(g?EPMBQB*6YGs*rWvoCE-TeFaY{ zEa&^pn<=P3T86L_3d+jP$|lYwfjOliG2zgm&y;TGXFcZjT&DwS5%`mv14`Z&7Q@0G zO--Q&vZY@rH4SBc4(j&He(~Le#V!o5MRb&hEZ#T4VRkw1S@B#BOo`U4+fYeN-E45K z*=(*PWcFVQ4ONbh92R2qnAybvVaJCL&mzX*xnRm8DYwgyPFm^K9+$8?zomOMI}g$Fo7BhK zqL@3GQYeIatO0!j*T_Ejn!Kl_D(zH@wdO6?9r4v0wXNQ)xPxy`A4H5}21}|wP->L2 zVwm?tO2pDPGpF&&0e#tr^tBBf{6Fn*@uf9%tLeYp{P=u_>sS2q=F zD1%!B6esG8(6VcJYJahtS#C)~gJbdU85U)=wY3JicTw$Nn_JW;i@Bz(r zsDjC1^p61}Gbp1CO;s2PZnM765O)mW!*%4&AkN6JUK9OUSDc z7>D z{B<)n>KvYwGo~@zEp%A1DD=rsdG;lxW7L{$X#!wYk^cSrI|sS0e(4)3neq3`O>Hk( zj+|WWRf7HMp#<9ouZyz*nSDyD@| z$8&SJbRIO76UWhyH9E-q3}i*b8zm0}&TvVRCtpSgdrZrk>oCJkl2?3HJMbihOFl9( zxykR=b*JmOXNrl_>t2KBAd!z#rNgu<>Vt5Od`)6{WHo7?1%sFW=^=JH0_SG|W;TSk zJFu8pd5uV?ir-qQOcrOdanvvNk9sbhRk-3az9c{jIO7&R0EkVE#i1( z(WpA6rAl`4mw`3>nXcrV zS^>|`@(D*~C6K=n)DA5t8m-G~bIBGD+Mhghs4y=l#c_HQos#=rQ0JWgu&UyOa3&?#$rshRtf`mL24%z4>)o zqh8Y@A}Esbju}_Vx@~E!-N^9y*m~NV`my!dhMGyM?iu&~gqwj{qu;-0i1o+CByXmC zY|Cwz%=7WWBfvfk##;~lc(>PXa9T>pOe}k_Qx4_+e01VXnlDT~v(2a0cr~b`r$?lW zV-~8-YQGvNEYfnc(x)hWg)PRr(1geR$V%$mTgg~xhOY|=AD*4(^coOEd8;o3f{MJ; z9{C}g&7i7_NF1>@*X^XmonznHB#l{PHfM#E8g4JwPa5V{V;*g=@t9I2A|2(fYi7tA zuGc2U_&cDxbroh;hE9p~<z8van_T}{#>TR*_dXXJ&UMW1-ZJEu2o}|dw*y$`%=_752QnaW0&Xo1A7k?c_Q*^ zG*2|R?R4p4l}VY66H3jPD#&t>an#=UrKL;3FG5g!+c+G6ZAJdA_DB+?3y3NC`W|HE zpYI$v*Kvm^01Y~_zKLgN@ar!!?P1o4%omQGjprStzHKa)l&)s z(?O5q&Qc`%(@sYV4so3PjV#gGp~>%EcV0;YUN$(31PpAIRh|WEDJpJ{oKGdO2rhF+ zWeFt(x^6g$9+Ma!jK`Q;YGS5F^3&3G=We;UW@+rv{b{powlWDA(dkkmK;q`v;st%b z6k5zbxaW_|qnKY4@w?uUftPEZmzyBly>sCnN%Fj#3tSrZj*+6?ow>20H+DYHWyX3H zIS=fXbkO%se^c6M9;Dn7iR`0Uj_|3WHcj;_Gcx=&8LK(&_^O(-Ld(T4F5s-1Sb{%l zZH})Ep>+GxIk4Jp`CTfhr_76x%RPdJngL*qZtKR>x%)-A;3}T?rEdq<=!lem=G0U) zH@bALU+G;C9BVaXco!rRUbS=%kX@(S}1gNxqVw< zZFRS7^O{e>>wzb2=4jYCXHGO5P)e%LUc9KDS+rJkFWFYBe_ayo=idphc}h(KE4OqHdOOA4ZQ{$3Ax0{aQ+Jl*A29ro+rhz-?s!w%(>*sfW9wa0|ty*p4v7({p* zY0yQ&H$Nc!PGkuQ+4J~)iZyPe()+P#W%U;OIA7?p4lqdCWYdAde|Z^O>+r`1Os6 zuk|WspPP+8x6C8)IkWDkhh;v=-1ENHH{%^$uUlA9}C zLxUU;n4x`Xc5iHU&dFZB+2^rM5yhH!(oMiRC019Dm6Bto81?qnd`k&re~|iqJ>~*& zB%cbyS7FA3HpSy}AyOeSvDl?6O845eJ+z{N5QpS}X{l)x7=zNjvDcwaIIiCK0lqfJ{W^C8jGKC9w#^@k13s}C5z=kWC%^POdgabZg%E5s2Mtk!&||@m;dbiQwt-t#|Gz{lwrJ!fkW#RaHPaSWR5T2 z9dZQ%GS*;f+uEK-t#sNO`>tVWfiq`n1|2oz>oxJC95OMTBJV}E*2`UwRWiKs5Jk6{^UTKyoYZ-HOzb=tvS-KXLP;NB_;dE2)pRACpU#g-`ytCZO9S}#m zKNG2*I#m7#87rd5RaDR5n;fKC2re^HU%K5y2lE+y{pk{a( z92tWm=Tc@K$*#F9_U4ezM~*ukdOy6+^TmbGIqS{t#1@1xcqun zY3o;Il?ucDnf@EH44QT0I<&|N>ms$>^G7UIGSy%Ttxltg^A9S=MN9N$$obc2ACZv# z3~%)2o^3aIEz6&gv5(H4@SHyAlDG8+-+CYp3XSFE_`_g4=_KjgXTYXZpV28R2K1)6 zT_o=fy_}d${FKDU{^hNdzt#sEYKK0ZOY^ail}q!X{V-vcqvt?`(~&4n<(z(Oc`D>> z8n``RP(!ES)K`6b`X%%O!bnCm^EH|Ldfa(d^; zTdZTImW$`^TqAR)T&hRF!UIaG>qLD3C%NX8w=ee}c($|kV(@>o053>LJsX>hm01%E zB$ft9kkEH2mn`(T+0c?qT1R6YPz>?KLR>U_uv_`HaiJ{vy4~Z z7?l4*j}G8HdyU%$9b?pBojrqPg{++^wn#S77KHQjT)y>9OXf4Y^G)aVfV!s`zXc@0 zMpv%jo~cByv(;*xRZ+_Q`XY>b#K`pWVj|VD2Rt#Bz)+;s)JkWzev|;47<^du!FP>y z$}-*AEKuLg?d9mEpejS}bb5pUqsqDBE<`#u)ik1=1oH;KGn@nZzI&UOE%`-@Q@Q=z zH4~mM*6|w&1ojspM>u;hXzl=a%}{ET_B1#wDCTn!Z8W055hYI(uc2RL!Q$gb7d$(f z2eP5GrKO!}x^0FWWJ-w$guUSXT^10C8J8G`Djnmryk+YA7A~rFzr03WqHL}ElqsDn zduidnyfktePr~ith1OK^-(HtVSgkMYHOk8+^bJ zEW1mV8!R84(8XU$Ees4fb`Zb7xjY?&Kd}2=tYfJuOPM$A%=8y2GdMLtj;K67bcDIA z#>O#&W%%m~z7cw*lSqS_mb)MO!cdk1kkXz<59YQ%8{N-}Oskj{0W;$+%oQuASe~bN zsjZci17SVePr=;Xwe?+UQ3u3eSV4OUuJ}_y)Nj~x`Cm*YC;e?J<1bV!pMsIM`7483 zDMOhddkhWe)v1(EZuhg_H835(cCvMWCzkhd`r0lz)LU?!*P5ln2kd8QXJ%=7FqcqZ zO4JXxgC0liFbcPOKN&=B)!CX@k^_i8Z&);P9+B06jP?Q_J!@f697KvE^VQV8dj+P=ONDWCOh|`e0jNCeCRUj3sO7Iq zwV{F8q`v;j{(a5`AHoU=B|UplQ(~{*;j+f~1=IM|cEz16G?O!c&UeG^#|W{B9FQJg z2jB7DQ(}hDf32S@oQYX3O@IhW?Y~LbtZReme3qc_2c35gQUM2p`?p>+z}RX(+BAYP zsp~iH@pW`sB)Sp}No{7P(}VM>P{KoXCGYzj)*lO9w07DXWKkQhJ~hbQLLW&$NGcmF zJAsKzQ5C51(T<<_U@enyq$pYqe;y3EA1sKieYh*1? zqZ5LV-X?hHL9&n=9PBC?NlANU$RJE)m{BC!VWy*N`kBA! z>^N9|N!%&Xr2#h?e6DwD$$V`s0j6q~Gk4UprA$cDqOES(86Q@@ejVgy zcVa0gpSJRg{CN#&D}U=+3uaLr*mvTqcDvnDH)^zX)lxjQ3F;y@=kN=-=@+JX`>To} z7qf3K7cr<3K6T1GrRJF~JW+>qfxo7U@mgWLZ))&D==#rC)B`Op8K z`}P0z17Cl!DL3upk3mB6@lv|1aO9hv0yp!Gx2LM!tiG z*pK|kdlQv;ZI6*7F)l&Nab?D&z{dk^1ZTwp+g>p1dUb}P+-CPf=_keHwr%oPj_=qO z%<>4{oFGLKW=ImA8bfRXt>v-hb6)4p9UV!N6ea^42mqCCJOz$akp)o%e`{>a1duxlk$_1 zwWm_f8-~mnDkELqUd|g`WLn8tpvXbW;jY8Qe>PrMwWjx(tp5lpIqtnkXO^y-v8-RU z1;G6g_^1y~T6(E62p=D^meRy{)?`U;-$x>`2&YkZ+vMVaY+SLLjR&TE+_S|4ZL38O zNY3%&eue$?sTqa%Is8<;VfOG8=6!rxN+_Vz8$#ndPE1nrj*-(l2% zWoW2RYwOKkC|#LX4-`W$NScIt6Ei0sr4z zuk*Gj488aW?yI{hA4&}m2U1AhwP5{VDjszICUc#=hpVpAhLlv9AO#dl4hyHZU1BSP z>Lt!QXyTZQ`BrTG>QbC+!DLacn!YN@jaC^sKZ96Yo{9MuD=P>iOqlT1S&&ge5;i%3 zP9>nE>kYX6+-q_*`abUrY4#CPttuk^mlzmXl(gIt?+rsx_16lZ&TqY;gn@Dd zlm5CPa)m3L|6(oET2x`!Z)4I1Hlgq$I926GcHd$xmC=0MQpwLdeg?qHJ`_w7``bTN zO~(DZwh>_br=Ck)V7}g^QVT|$@9M0eAbY1g5e$m61yvPtvkv3IS4*c!U58W2pDx{z zylIDs-yQ=*+l7nr7}HMhYvZchTKV80LoMQ!ueHx!0SsIir6^Ibsnbh1B1I z_Zt||!0fKjv~x`mGv)Z{93~UI%LeT`?Ig$x-?R-?O)l)2_5S;>d9w!dFochd_{-=3 zisqS!w|=J&7!0;T4j?LIf~djfW;(%(cL*>}FrLxxx87FHE4O$Z5kD92*+LqzXTEGu zv{OD)cPp&_a43Jmb*tYRF?YY=r!Cp3no}dZEsvGjABc;fHn=BJnQcd&CoQJEckLqd zTQ_dvWJ*)>S4wp%Ag&1%|L8?=UM>XwNjA{Q5fMKhZzZ;7_vH^;38$SS^X23(B|<2~ zPph_#J2Qm0(+>!o#Cg&+;l=oaK^e_6Cjs|_`Y^9#@f&6G83J@(LL|=)!i7g=OvO}isntT$wvL> zx0Q#{^u}JU4Q1SJ^>`6Y^`#ZQuFhKashZPJI$c%2W$0FF`gcb zW#LY~gS#^mmA#AR{Wd9q#JLEl{A-z?sSIyoqRi-gjqr{V`+vIF z*t;0&FTt&{{&s~>fz-6Oyk99QKhDG;psqU?@-{OdZsX#>l+>=>Dpebu4&~ror3|$% zJZ;083Mf&T)qX<4V+i4bkhGpYeUKe$+=mZO=&uiz0+-SE`B4P82A+3xONYvW{rF(j z;LMk*O~C+069OVX;g)mLlouYx7-s%3S84Kgsl`;+>DgsKC z7IYj%L_noU38+*FMX6E(Dmti$j36LgrAY}@2t6v&OX#76h(H1ah!98!A<4HN=e%cJ z=dAZz-@otAo3)g+Aj$JQciH>e*S_w(&Ght&;M0e+souO0 z8$%2Rh!gi)?wQepwhzuI8@Ilw{b^IUXP!1B^9&Ex=fYAECtteaYzC>0d#CrA<($n$ zc))4H(%y8Kk)`*V=5S!NpaIgYZs$>@M!>_G0uT4oruId}1ZaGG1>rjE?J?t`+jN|#_r_ijF`;?ZS{Wbnv=HVUD_>&?KS=x)XJ%*04Q zGaOs%;8f^RRT2_ZJff7pXW@zN*eQ6!rVw5#kP9_P13AdnoU+fWt`2$*4aQ)>fg3`) z!h&u3R&j-iQ)w|+c05V+g>%R8Kx}u$JAU8!mw2GRu?!+79Xn+s4Mf- zBTfow8sXnMTFF`^0rTd8pFet}t*5)*!+CtQ0LkS_We10vA+t!tOuq^0LgU{)5}rk!|{%{zDRK9Xsw1I{2pkv>?vECZb_&H?2eqD3I2 zUNU*E0Hf`P%Bh$ShLqHK;MMn&40D z%h^D1^p)!gH)1SdkwJ4Z@Cv!F6MVaYbGT?<2i?u7JHZTO)bcz4s`?2kKmh~9hdNSM zp2a}V>}XSq59<3ZGcsVgRu8*MKH}jaI8WY2@JjKWTRG$CmC!~tiT5H_i*%bLDm8BcXv~6ig{?$ zzcyG>x%1jt<>eQ%4ClMb zzzX+5li5DC#^Z-j|w~_!{;PQUd0AY`~QtLN5V93EdZrp~oBy zyN8gH2Z=jVhy&po?*6u-~7}<42_WBxPFXRpv9XV8J6MxDDq%~%^wTnOO zMRYc4UC{CJK-6ptkq8ZkUO`LgzKYhVp9s4DX${upBhJld;>+q~8b(Qrlrg-gW@ScC z2qZ1HhD!opnaPDva9)o5FE0?@L^~j|XR!54wBe;(L? z(3kCR_0DS)8AtV|k+wkhUkOM&brn&sd^p&iv{1fv)+!G1Y$`~D+JQ=`l~oQ9I( z)9G<`L0|LsD&^Z#yvpULMBr-Gbk`x81Hq`n>U5*b^PBc*pkRg??zhkQ87AaI7Wasj z0K^ypa~bO=^PAgFi)abwTK#Beabh2VLuj z${b=5`Up9GE;bz84f|}WTUOkUzLqnzH0%drZoLOk^e0?-c{~wWC-VDlhUM3?91s>w zB1`9WoiJ&t-CVw3GQ>7}YL|Aawo_x-U;=+`LrdEUc^G+6h7{-*+_nZ0TNM9xgj0~< zFJDGNf%d{CW#=YrrTfV9pETFGL(;h?b5vd-I%;WskDn-BZif{cuj$dHOX8PUNUHIV(dg;d9_Y?6WW9ds~W!-G&O? z6N2M;AuUZOpizW5IpB$DoV(o)@ojPv5+M%h5`BDZtBN11#IpK}DLH6Z#zjnRV7!XO zu!0+T-!jPnLa^e44_KZ6cKbE>lFU=PDY^Z(LQCzqqH^e^KYhVvr2R;kZg#>Sl6rfo zf|hq>^(nO@*bLwZm}8gT7a^EWp8~}SFpw)4E?av8O?dxER1MB`vvPE48;Db$h!WNg zu--eZizNTwdT}8rgNz$IVIIPXBLcMdpEBS;U-G$;SJ=Q^kPiB;KPdB(olU27oDTJu zjt~w3D>}ANoQLM!s35QvIpt!VZwJr6bzMkYU8aS!UT-!7)_PwE*9l4|2V`}`K!j*n zHDe4loXQ~9H36^(DH%;z%-JK%NKwn&ovoujxv`MoBpE63^9|8w=})T&(U1T_3GAyc zN3rQpve+0RO;`;I)86c%$M*)E!d-?cX76N5593N^NRbErgWZI^8FTXFb{ekt`G$;+ zum>vHeHtx4buUTWjsuQ4ralUn{xNygt&W6blP&N8^9YA7||xn|3sQXVST3q-5WRCp49+_+JJ&F-G2`82RaFq|kn zWFUX`C-O=VACu(+*(LDoSuX~H1Li__a75Ci#BmL6hPey;ZrO*x9G8_Qr@mZb`;kI> z*|Dax$N^r}M2v1DRI0vw`SVt7&aC4Z)hEVa=THLgYC9ZQCj~D-MxewCD=NA*_Ci-A zMdv6)9q-<4G)U6wk)HKsVYDVoUm-M!Y;0}XhkMo$1guLu`7#^GOCoBYOo-s3_G+&s zBqHTYo_>{4lo|Dv-wJGB8!PfmO+9XBt3mElQZNR1(;aJ|bHZmi_Z;D_U(T5e5(xd` ze?1O*Cg$`KZy0=8RII3`K)W?%x0&x72kaO7-24n>*-6y))~)1&U{KhZ*4aQYz~PVA zo^|1O?;@x~2+3lKP{hWmX>axdN4>gKw;##5KuT^WWPu_+NG7P`FrdB@(~RtG>JoIb zDI*1Vn<^8(3#%RD+yJ&%0boa{rv=AOV}X{nkSAYg^TS0laBXiQuvM)r;ClBf&*!56ymiNP87a8zXw;*nmjTxqu8R3-m*ONkP`~Z1j90 z?$3y!6F4R~S!hzwVMLTvDgEXH z_bR5okg%p8^m}0L`#`{n@bh)~L1!r;UPyJWDnK@fB2^t%<2Wk|=G!wNae*9ah`v-% z!B=?@rb*~gJa{qvmYt7;)P8x(_`&CLW;;>E{FUoLtFTr&F=YhL9N9 z{6i@8=1u^sSlhM?^!C9EYi0^4ia~Q0%Y`zUk)X}I5m7T1;VD5>>p6HB(8Xza|BDbE zx%^7HL*082+z|z3dLugwFhKwS|K%}o@Q*@VFW0QfwT|ot9uW2_O_|1!2)hhrUAtiWtysWyO_5wpJQGf>1N1d?kLlBJFEoB5|J!dv z8EMzoI{cxMmND$$U5$24&3duwYJE4*{*15D1>{o?AV7~)BeIqkJNdmYU>_BZ2Vu%q z;4BGf2cqNOAyVsq87@oiPIfvAZ&iZH-OvAV(h)VHnzZu1r1t!A502IoA`}4Idu^+>n*HeEflS=+PbuM6L zLOkwQ=K#y!0wb^tvb03DaEVmv6Q z%10WbZ`y~B29J9JR+UN)Ho8#F)&(i<BRJNqr#CabR~drAqZ|t$ zoDLm(lk(knACgh*IO~NMHY-lLS@Jl*9f)e`;+P#AmFs->p6&eZrCtCxqE%EZUK11p z+viuI;mWn0DgVXz97-(8-?Z*X8sK&C9Ie&O6SARWL{6EzkJ&or6X3ec1gEy|91eKd z6V&5~PHuob6&v6PI~dUwK9zrzT=n#@T9W^t;J}S{mx5^g@`qgkuh5)TNW> z|75qvZ5K;6#OSvU1k>6EmdBTLeZZ({X#ZJQcqq=$&%x)MCa|*LvWJe>u0#p9Y;j82 zCMueJHEQvg>_rNFWe2Gb~M`uxij=7$gRS!LxksAC1ij3TYE?gz8JhJ}=@qBLwENXE;c? z7xa3C-kYiV{(?R?UoH|-6j>CCF!0zupwPLm^q-63<-RrbXxEcM5dP>VLqv+H_=OFe zuzD2^V15@holZKFU?}p z;1q+X6BNPmjK@S9&ORr*dnF_aT0@Rhr-6ecG2radT%d zbZ)*Lr#*RMx9Y|t^;z1U`S5$_BWoR8sqyH2 zQIuZ*Wzh07gM*?aC+Hx_hOlB}E}$bA1!R>aumN!@T(&&V?&`5}Y?)N4tIsq2&bM0Y z@22<|YMD=|r}i){OjFpvWV=|LJyxALFsF)L99ss?i+J3xuAR{WTDmzUa2RK8(F=aY zXFA~6w2AWzCLdZhn|U+EA4lw;P?iAksMWy>rf|eUNJtIPwD#*$r{}%Y6(D(!s8<@x zfm?y_r5WyvpOgt4VJxLq!D|izMCuNH)oP{r$WM!NBPh}&;}4ga19(iHJk$-D*s;0B zb3)+1CZhHc=6FicrPOk1A&{i;UGC%pbCd5HIwl<{&v8Y^pf2Bg%fqKNV_STtPFSyB zKjyMi^W=6J;!*Z2WXq0#Yi&F+*7QU2g`qjBq=uZ5(j|}<+Iieg`|wWgKcn4u+Q@MU zMgJJ_qbIg2a+Ngj`a^IK9+`F^>uy;L17y`+TJfyWkTzy(ujKwVqvB^#0uopaU+)q- z(ZORK8ItDykW=n0<7GTu0D*N(a?Ava4^_DE{iRPhY5S8PmyKxJu(}3Ujxh*^>nZZ& zeAXM|t8~@fnm+HWN0t0s`{sEg+8&j?q_pdH=^Zx1w237luqzn;d0*Eu*8OXID5EWX${!mJBmWo?CVb zOFL56YQjZJV$PeU`02q3TV0=6<5%qjEMtlHGZ;Y2`mG?&KN~S@&cR+)4lun%pwr$` z-c_AP4+F>s^``JrH~lc8L_A*;$X8G};S(|6&$EnlaUJGghNPNig9FxMj#AY&UGobp z)O>QmE&9`vx=^S4_m#b?8fGqn6tu$0$7L&=+}UUukmE;Lc$(VNv;D32!hZKTO)f)k zt;4o2T~GLo3jK4jJV-JR>YOktxX|1wX_R+4`pwhH6gq8p-YAy;23R;usc=XLm=Alt?Czh+ee;V|GB{6!btypjz^Lwr@OiZuMhpd{5MDvxvn>Pt@$ie5Z1Fw^hl4KTt2Ye2=7wykT?imDE}w+s ze=S~0d6wIO+w_@H%()zh>;Fy;y;9keltm1a%K8}%0xl5sW*E`N=mfg@_g z5Lje@F_33k4C;YG8!f!kzX49zg*KVR3|09Nug6ssemN9L{BaBBvvNm^#wF?yFjI(E z6sO$EkNO1@Lwu9xm8u5R4$O)+N=E8qg{-qb(aHex^Ip1dSe4ftgo3D_aBbW}Z;N_X zMrdhHjQz{4Ng*1QL|7Wo?uc$#xw1tid_Eskai9!lv4B96! zPg^zOcPLCRIeCE67`ox^28KNg6lRA&VTSPdp#QgK1^WBTg4Em0gmyspoX5?Q((ytexQQrIT2#y z;}p$B`sRO?unmFkNw-E_hVsIV&y784Te72_IjIC!ebUf^{XSCK)ia*C{3GNtGj(Z6 z`)6B~vdnW*lmO8}at9&G5g8w7@l#fWI>KjJN643U(oh~C4hB`P7OIh?&~(GPkA^z} zm151S-)z>6)XV|1qwQ1UW1&-G1Tb??{eijwx<%6`G~(ey zGf?$Hp|pTfw~%TQ_^Ob?t75lj3yz(s%cFZ8SJ{=jX~l z0!)AY`HvkIx9V#@428_hR93QzeJ^c0gWh>6fFbR@QSaBk41W(G+ACtIY~8D>GD^`C zQt^7{P^t9A%0(2BiDGEes%hF9ag++?I72LTXsA!fYt!xv9X$30chtNo>QEhfZ}e#q zO&v)QlqR~8HQQ+^LkJ3ae~S=YmElEm7qdJaXsPzm`iZ%f7XHs2yuAid?&OwDPi18{ z>15%ssb#xfjG7q)bMEf4!}$!!pY>-PXtrG6?xXp{{hXfOjqt0pRE?!VrWcQr?>Zm6 zHZ*%H9_8lB8sffCCGO=mc^F^59A!7U`d-d*(>Jc+yM*Bfm6bDV3o~qwMNV2|`3Yf( z)egBUml_8!D@FcOcT@3uQZ=1^XK8*)-AZx6f$hwfO6B7Tx7I zi|2tC>lnCF|7S6knD{*I;As5eXo;4#y+)3ck2!k%_bpeK2Gwi0v(IN{9=GRX^exyv zR%PD4C~h`CvBo1V->RU>4xgVGEP=D6EjzoowCqOJaIU@XpHI7#rf>m^HsE{CO=joj zx-&;I^qo}v{AYEpMkaBd7Es^V@ulIFh$cOCj?@+*Hlln2gPE;N(tar$)1pJ;DOD)s zpLQUN*qnt`l}TA-9G0bbAMla4Vp+bwg%`(aOjL?x&<~;*i3$6xsy)JY8w@KFaXyvZ zwF_%D!&EI>jiE~R#VGIj?wXjG{T^hJ^YV;CHZFT)iqVpf4s>5|GPkfGiSqheJ=tOu zck#f9_qJtwJ6&B}o9rUj4hl;Ij3&H0{LP?SJ-ON)96TC@$Ip<=}mX2RPV4{>(cW20UBZLLcr1#zBw?~ z_lQ2Fw#xM;+Su4G1-t6uKgCaVSbbZh*S~fY(v2^+2@@piSQQGHka!E32h_}Hnn&%INvGi}HP4ox`{<>r z&ZkK}t(B@`sB5TMv*W9k7dq~_C*Uk9C;HZ=6IvHP-ydcw2v)OpiP;XG;LdW(f;gD% zOd?$;j+Vl=nxSJzRkg*QH{2`7!uRUTX9i7dSIaWzy!6Etlw~TGs>BG{p{u-Ig^8@P zZ1((2U#nG6<6IGKtYUVN;BKaku3S3DKs~rNtEQot?`9mDVO5u7Dkr%4p6YuIjn}*x zm1kY?>jvSu(n~at4yHeLRD-%W;zjdIOnn6djqV6xM|S6u-tEH3JSC{K#&&eP5D9*Z zcKODK4|M(LyqMVsZ<_Ucrx(BU87(wkaG_Gcz`#JP`<6%7hitv5QLLuwOOoYOT6NIP z)ny6}U7%?71f<|dvT}wT%JOP6S18!)t}O$;b#C_^wgok?4ny~ zp{m1aK6U!bJ}PtkfZ4aq^_&3$IaXTV(Q&a=#D3_xuA*B@nnn4|^NBPq!K_YqDTZjh zco#ENS~h3FKxs~PxAI>wqXNds5lSdI~M?_%0(?nOXS|%j~PAr9Duc`jamX@(8+T7jV5v~l9tCjg^;JIB2 z38O*QwzkQcnGMgMKQH5!3U3}z(v{%e6~)d9M@j9J-EH485vDYqQN`^3s96#;h!LWv z?%{@s22EA$^>0$2vl(XP!TfF2Tzf6*yK+V^Dko=WJZibynUkJ{>U!69V zXyvij4rQe*Jn+rUwqm2ea$N2l^wJf$*1pn@6QAzKY4!E(Y`627TN-)`Y4l1@i`6B! z!84v#CN`tRe6XzTLnZlTIrUe-Tql;&Vm(KOQQe}Q7ov0}_&$cHIVB+?qdq*-p*!4< zc8|Sgk9ofFA45@i`sdD(t=`k!lBt44C9A3@xa$)KoSd2rxlZrb;x;u%_Xj!Ai$hU<)Y7R{QWmB2-W|vK79p{IHy^9F?uF&q*@tD#<e$%zvzISRs25drGE2cJo2x(D&)C(K?G4puuyUD6PN54q$!i) z=}_gOcz~T+VV|z(1H2VkVIu?U1{kIe_B;- z&-JzGEPhlDm@9R=)*H@mTJP_6@3<@3aW2a+d3f29KIBK(Zuvyc<^&F%U+O&8yEa~6 zzT-)9(2!GE^G(O7UXrO3IFuVME-uIM6u!(ZQBrT-d1L}ihg6-&BuR^&TWXO&MXT&8UzV=z>iyNrm8=u82itQbvCOA&{tvROQULy+<W&YXBF318L@tMu|Q)?#{~8ip9cANQ(Q z%?Y=BVk8=3^?m_aC%=hSqF`A2HEpe|;w=hLi2%gRX!@ElJ4HR-?Ekc%nURrf*)~@~ zS=f8RnQ^bE-JhJ0u#br=kVueeuqkN{bT!!U!&Xe!kIR#BstnZXGLaH*<-T@4e4(M? z&+0`e0mUGt=@Oo3O(aprOY1)14wKvNP^*16zS)&F#jVMn4u#ewr=hXm&*50m*#O9Hpj|CVkU#0fS?6`Eo*CWO?~j*VUy)wX%_2 zjvcpiJ~2rZUTjf~)q4h`1=`Q!L^=+nb$FoM5r`&Y8zbdE@ygbrV61W1_qcBce_#$6Pqv5`+g=J(usPut?GkX>pY!tG_!c1) z#>EWcfO(wn<=NhBuMQ0^M#xS%W*|aN;9UUF~hvz)P9@l2o3It$1YKV)^v)A zIS%rC)QeKC1Jgmr@9mnQ}KQve7id(y=G=6 zM{OnPwh}nO1f|gh2_ZWG)&~p{_xvu#9@!GF#;%8<8o53{M+>U?besA_My(=u-q^@G z5m|2e`!_BXaBGY!a^~3i)MYM~e2lT*P@5SpvS6tP1CPr9_X|KlHDl7DnACJ#7K@RPha-m8}-{XIr}bwIeK zaskOu2E4Uhuy)z-1n2Q)ieK94xi@)?ve= zo8Ol0TIV9SG7wu?nR6k&nE!5gRpYfZ_@4*Kmt>FZ%J(BkhdbGKeySNx(phT?FCl%g zON`vz79u^KBA^AZU0bp2wPTtL&#R-Jozscl{IaXWYr52?Gzuli8eOU=qO;U$Fhu7E z2ERzD`GNW-O~K74`16WYvFr5gYc^K${s64e*~;PfbhPHp&e3T=-{D?rXR%nfl;A}o z{fVlZ=N&)e(sG)48J4JEp(P1hR`KSiLRC^*s@h@jzb~gW`h(|KBlI_~i3|?Ptw+Avw8b)a=FrH`M&F2Pr9_VfW+FEJ>J_3%;Y1 z@2KOCA3s10R(EdD#jV=2Xsd5~Uf&Uerf0)3bz4LHP+wjV()054nFDk9H7EW8Nw)0V zNhg4Mi&eR!$u)3K3@w4?nPe-gs>)C0F59bi~x zZJWjLSV@^w*5KyB>_SaP3yZkT;>8~C2a-rO15-5;!Jl>y`qS_`swGN&OocF`Q||p~ zP6RXd6a?~Bo5i|Sz2A96Rem6I{bk8A3{^< z0ZU`K2%@i8iL%A-m3I@NkLs$N`TpnO#T5PE7&7}r9%rS)itx@YTt!I=-iwf!5~c$%*+2@;mTBoTQO2k;Jk+wzg9RD)itE zxGz=uT0%lQHwh}XPo9>jI)GiB9noUp2|=%?=Km7W{!-EwupDo_RBM}&o}S*P61Udc zCqxm7)M0U}*SfXOplR>9Aqi(TWl_bTviJ|A`6@vJh0&9#9a~(SKj_0gJ#6juq1k-L z{SHRuxD_3$1(Iyp(^STNd33;pWNP_g?SQv@vC=Zw$-TH`F>~V@muSu8UE}3G8V<-( zY^+`m6++j4W6qr=zDscRI~!4ZOoH1hHf@S}<3D?s%a_sN^M5=OraamStDMW=Tnb(c zjqWL+xN}I6aAs1bS<2$=)${Kc79C2$XXZ%>fCj8r-|INS*1*D;d&RO3_5#Zzh>PYZ7*bDjCsdWmA|W=1LkQELnP6Hi+JgkDUv zO(Ar>>H|bHkwB?Y;LeBq{`AC5)N(%da}mYq!zR3|w_CJLwX9O6&NG+`q2z^rT49}n z3*T=tM><}0vTI9POy0$6gFGGyb<7oSiq#yUAJ+N4VSh-}=V`biwC(T?EMmL|^xIF6w#6Ml4=Xtb)tM_7{DU_*wyX2FioKn{Gqb8D=wWVD&w|ug%L=4-O z6-K?tj*b)@x0B$^olUkfE;&Nr^$AUbU##?e!gyFj-Rh#jzv;l z)MCR9S}PX%f@9xKHa>nzr%Rh||1G(7cJAr4?n_FIA11MOhN%sR1HaZv;QNQ7Pf`k9 z2WNZxOw}X+6|4C1TnTuh`~PSGjC93)^xkXR0&u}Ut*9m!d_&Nk?4HKha)(G|zT2#N zjDl10Tr-}HHEnB_Kdo6SUiRefhA@YvvE2?GNek^`4>R;_+6Qz);wp!7W)+uSdXrB! zR;abTVBO}gaP^r}rwJY6f#NAfHvZ;bg&x>g`Q#YbevbULIHk!LVK15+rEPK2D}lCu z|9(ZE#na#wi8DEq*?HDcF|yPwFmC9oWlLhm0{}u3U(!YsCtDq9rGpCTWxhTsL7yY{ zD%ukeI>RkR4afsdyF!QlX{;NH!(gXFsGUn^?eV=03mM@mYHj?mnbnIIx2i9V>^ktK zl+B-0pu|KQ^4OxcdZnkkGjtoY{jgE?z#UGLJV>);jc<C+VYNzOPc#bJ zE!pseDIqM0cJgOxTkrv0Q6ArWdNG8&1A{TA;R%($@>b^(N{Bp$YE@m$E5FoaMVBQZ ze}`^t_M0m&z>_<|Qnx4YjGVWg#O3DaYlw_+)7Cg55=dyAq>uW-1u_oD)=0#R-D|ce zzI~S3jy)c2Qz^q9;UwqTq8${ya>wT~DY-*0mnziZ2$!mAR)JN1B!YcDx zxx{FPD55#4Ug>g$%dHgunS#A#q)S5Nv!wps-WM_wg44l%eP{L_yBhhG4g*#}u3vlk zW2r^8b3jx&1j+uaX@bL-zpy1tdEtC~Cb*k+k6=zdtR`Ab9AA|yadYu3@2KWn(8+^O z2r4@Z{0#E0RQ#G2SzX>9c)bHN&SVPICBwvST{6^~Y|*+cFxq4@ej{2!&&|ygqAuf0 zMaO_Xo$jyki&9zN$zdLJ0GcaaeY|lVmKEH`&drT0Mo-PI9LkW1jef#J=HG!$B zbP46#w-Mk8pOMz1w#UENCP{gQ#M(AJU`Yx5>8~sne=;=0Ww{1oon+)&r7$+^-7+I7 zV8!hRMs*9=%%Yp`C)O5aJdDoNe@F^grCE8?FdhhsLZZ@!$g0DDQrmqPDr-PwTfDvL z616-de8ImB2qUvLUt{OaP2B?*Z97Z-fFddJUTAAeRzhY? zmOaX;F)@|%NU^P*Err3$c=bv?CU;j>ZS6tehCNbJnL{f_(Z$rY1+Y^H*g194W8rnS zMWwgdzI`*7i#$((yLSW_HQiMbqTw^N;&cw|jn~vQMvH9pd^^VSAH*` z-^|=RCXlge!)FhP&|W_CAO@ zA9#S4@kqXW$O>6{Ffeu8b6U87{AT_GxiTip*n(EAI6W$b;op4s@_n6>H|d!WT|D5E zlmA)~g%%~UhQe~^Do3^T^;;EJABJBB(5d946~9xK>M-J^W}k|s#E!ZJg_xV;+9F6H zDE#P>gkBU1>)X*-Q0`SjOh(>_EcWuNo)F3^`;D?9c7<%b-XbfKS^G*=rEjN2smm?1 zeCxj;=37Q>cx>8VfkDg&0`R3EkdNQ%^`Q|zz+d++7JuD;aUvQ=#4dR0S#bHp3;%}g zWiO*L+udqd2i4Z@Oq7x=pAy)gCkpEjdzJ^zT#Gl6>P3&RJv?=%AGVRG;>?<;*38Ik zQRCFoe2KA_Z~?GtN5R1>7*f<@;v2FqWiMNU2w4zciV zrzNp*UjZjdK@WCch!=B*qO$uR~;A~>|Dy6j9i3koV7*tC- zrE)0j)@5idIze8|70hik$;cyaz>t4pXQ0^Adnfpw4R&qPg?@Q!W^D#4H1^ zAS*1f*s*!fiKEGyeyspCm_P(DfsIG@tD*MzCiS^C1r23;QX39i_BON^=Tv6Lr9$thBrFzN3D*OWoyLx z`SSA*5Gbg#XmUs)9a-dxF`er8m-B_EDOorBRRswKKR9JuU z(MH_aAL=^h9FVCUt0Yc5pm|(~npK}|5)J7lI6%mi?m>8!eWl_Uk{*nP_!yESfqybI z46m)?GI1R|(%uY-&{?M?s|l~bKLxKj*Q-@?`Ij$vA|%`tq5RTNiKr9XWbm ze6wK9i0&o3O9rhrPx_}Awd;oOm4%f3HbRQTpPDUbACI(2&Ndb|#Ne?+n+@PWQXwPI zZs*{D_G)^=^jx*D9lDAq_-HS$l*X$rcS&I?x5vhMpVzyQMg7^z?ljsZ$6VTC`%hTO zHO0lhypRlv+BEIL*96M)$JE6SOhFrX3E8R7u~JBSqv>=<$1`2qgbiD@O5fC&=f6m8 zl&I1m>Tn|wcLg^k#6)&7GJDfb*z7ax5=h02_;B%yz1vAhN);jLU^&TnEfvMNnZ%W< zv2HIe=s3z~smx6Wfs4U_#)#BEB_&NV&*UFf5l7(fJY%BqlaHgjZt_ zbvKmNQ8mg-djjmFTS^GBUbjc0qa$r^If3~$xQXEulRSyZly)W&oeDu;*$Jo4Ph($` z8Dr^24xe7us9v$teW5Y=ObgZvVjqA@KKcUc>O}D}QEZDzde}4WjAtpoLG4t))qu~2xESSNuwWH+X98Zg=^h`%n042qM z2&pU4d>m(uF5okelrALUyqrE3caXa|%kl)D(p+O(^Ag8`nV1^^Jf=5Qv$pd6owZe9 z?E~9sOPu{mkUWs1azzFtkyJ56A6lV5h)^czN6{LxMp`WH6A3?KM`A#2eNZY&llE?# z6E)pfr)IRHeZL}xs#GBum2iR`y{R@laCzSg#B&*Haas(1+N=h4f#X!rT26Cs(pMOb znaPR8_4w`8_)T(aFgHQRrLc#;zm)ND0gqsCDGMffDBG9@_JAC?WDo^-TG=+Y_ElL$ zE*EVA@AqT9i1a%c~_1rAlWFT zES+aUn+`g0iU+f^ZDIg6c+Z)o1oM2`|4L@HBHs)TACh%03ZP;->^VeDD#BpM!f&rOMXp} z0|SS|V6b&EA$V+Q70xoEpvzX2veFP!C0KZH&7Z4oOPP=#S$DGWn-Wd~!5f`_a{g}J zmxI2o5w^`Wepofi%KWVA>A`jH%Aoo4|6t6k+)I_ENEEGV0PHCUGStA8{yz2(23>b& z>p|pPna5?KHVqtHxexeGf%s#Wv#w>7}~ zzn+g9eiF4yl3c~Uahx@xM4ANSN}KfyR+5(H%WD5~XYcwy3EDx+HT-Zr@CIPA+8cSo zv(L60R=mFYm6e%Ok!X6ROV9y~k(;LfP0I6=&(~*)ICS`MbCm+$U&Ci6>3t}>d1tEs zuLx+Bf(6@#_|R0|)Z5MbeeDs~Q|4Lv&$ZWSmKA?}vM(W9PkiY`VqKaM$vU7>6W0f+Kk7>4WHMvb5Qql%xy#=$c)rem--dtdsVtffK}Bx7k&KL^5eS6N zJ_!muE9&XH%BEm3ao;EePkyhwe%;l?UL*koxqkK8FX3gr-^y{`zV`k)(cj$c7sqex z%Gcjtl=_c~VRwG}5mw^2uN`{-tiZ3oe|hdd>sg)orSqFng*P3FLdtY~^E&wqx!rGH zkEQ-x2f%Ivy*{Y?F=;^L>d|2|uGryXA>tQ^R4 z#a3rl+R>4LzsfZygN!&}>6}LCLfFTD&&7Z$@`a0w{f)VQ&(Xk#oE%FDMqlpVpZog8 zt4!og??WvmY^%%v=le+gjHEv|&ktz)^IbujK_|UZ$8eDf)}2K@$nOhzR@HBo7s`Tl zp%UfauXkno@TUGoTASX?j0R+<;8o_Kl!-^xQfkGl{#oRS9$_NR;;K2z3#+U4)V8g1 z$XDE%8;Fu_?smWtBV5M)O#c2#_}{h4cjXTCl<>g~KfFb$T?=aLN7nH>7A9yv0W;Hk z*q>e`X7vvT`SrVFpG!4H-oVaR&`93h$P&KOzC5dhi z&(R88WI_Igl)!vD46>fDa+Ta%6#d-kUbIwF(LaWv&|#zVL3R3*bdS`2+I*GT4cFNL zI3=}i-9YV#ml1tDSwng^y7NCjFx@X#F-67^d!k=dj6UT5OZ`dzmeFyoTr89^u zUL~^|J+L}5lQTgK(Mw3sDEqouM@RS^qJ48zKdnJDPSnf$@9QHs{S}Z@#1;grPxqB9 zSD4!v&ey`~KnCDbJ3TuqN+#7An{S*oF--Z_V}AYAK=Jp=q+)u0^KL>XYYpuu9jVoQ zYZ>{|7pk(q=VBy%C`CYOjk*-(YyFQsclDQsgq?v^)k8NuG}`mS;btXb8Oqi&A;~Y; zv+cN;72>_td2HQodm*1!mq1Y}b&MoO%QPOua=l#ogcswa+Bu2@I~fKP{zM21aC7Dd56`M2e}+Pb~dwGM}uVbq?u;p`mP z{skMwu2q{(8%93K5I?ESY1Jjwl~(>ju3lN|Kf7z)wi zFrG8h&9@q*lQn!Ue7!-}{Rs(>Aux2WkOu0BhtctJSd1v}`}>byZ~v{%`t~g=qax7- zK|Xc#)ny~Y69?2kKTOw;V}0e(@8Gg(QT}5OCTattIZU-`zO90O@aj0EqSyEpUvWC&cJZi1jc{|C6{9XA77 zM{}c2!V~NtC;q`pfmxx{gO-KAa;W%d9sc3${L!I4WOxfzd}f|o-wa-iQIHN~l$Pcq zllt}bQWAzNlf#Toh0+8}Thjfn%Vpr!(pc0(!5OC;! zs%Q;=hxl>TmS`h5zn#5YaSgg_9rU(W`PXA1KMH+f+~@wi!2kZksO$f^<^KaK$XfV6 z2)AzC|Ifg71$yK8UD-k6s(uN4_S=yo8y~;9^iljw*OlvfA4fII1|n4Y_gG!m@0D`N zJAT$+R;Wmpb+0IVwKVO`%h%_0zdwAWkj4v@U>47Qr&;$QXC#%Lpzr6~p-wznRZ>z# ziw}GFzr5_P-#fVNe}6r@aG_J`xBvYW_2|chKmK1{ipNhy|1VcYetquXLFZro_p5Jf z{`kGY|9DMZRL1^3g%B~{n$O4JO2K7%LZy&d}x{5@MjK_*0A*f zTze|C?!UhLb>zoK+hs1|-O(deej;e}DgTVQ`mkW zP>22*pVwN44`57TzcP))rD=7kcfmE{LtFkI&c6P6YQ~Xp3Xn2s!G!=@5%TIjUpmp1qBM%uU~&6_VhPU z@cxc>C;#>Q`F(i6v|!$9!`4U0vpjsb_?H4 z>HTraWZS-dkJmWN{pv@4Yst;GB|L@8N-8Q|wu7slgj#lQ$r1b2K7Iat{rMg&7JKW< zr&BxREO+eMwd>Humv8S`0@rBO|{8(RqZKgL{U0icpSEF-t zl(c1IXWNMrCtlhTf-h#9sPBn!4-=7Ss0n1-mqHSM=ooy88&T;ND54BtLg*N1Q3 z96D-SD>~i~q2zn+UkgK5&Z=zlb{WI_IGkL*b;WlwGBSUUnY~G7!`3^0kL<&Thwwr| zLSwUoCEar`UhEN7_xzq*>7#Vrv^9wAx-#tA&Gu?1`c^6AvOrOhH?GpNF z$DIccgx2lJXxV?srYuAdyu_eL6crV%yKEDx!(WkvuXLJdIv01~^q-$#nco)hwXfUR zZ4(!Ns_8fHY+`2UvGBRRBIRX;@0{fhdFwr0U0oUsg^MrOx%A~c_(l5s%d7A2T`rxx zUjKN~@x@uvtJA_e6l_F~A3uJ3b?I;r78@bfEt4I@S=@8%>N;3kKkwT0C#?TwLvQ}i zFx(r1gM$l8OY4V9F%e>0|7EE7t5A|fJ8%~Yg<6@fViY>G?)uk+D<3()zMP4S>vI`@ zTcKL_d@icd^Id3F#ojIO;Y%!K=gxItL-x^+%E`gD_(@h)R`Sf5Kb8a!9z1yE&!m?7 zF;W^<_p7UGMXKp2v9{$N9e27nw3LGi_O; z1H3~+=`@Qh{Xnjo==|^9A+<2-w7w$nqsS@%p=y#LZr#64v(VfmA!TrRvB!5+Ap)qjRI zM&zguA!gqBP8uz7l05bk>IR-~I`RBw*B5)Xk~H&;KMuo z6tKBY{Vb-b4>?^QTsJe`o_PiT+$^y(dA;Z+H*H9ts+_vNF68ucq!otu(>6nOeLstB z$)`j4T^gDytt!?JTK#_iNH*~kvNgiph54wstMB$b2c?U4P#*S*zVLv72kSSWk!Q4b zZGAnlTPaEI(j&6%Hsy73qfiy%8zm$q`;Zc9D2JXXy?3-W@Qgio?b@~1<9|n*V(MQ~-;|0FwD9@l zv4@3?O=`Rx50>#bvm)mtPtnbIsTA#E-lJj<*)yN}`FVJH?kHdX*L~P;VDww^%-r0k zES*x`pTh=jObY33j&p;%F!pGZ;3gtcdUzDiN^V5iGoG8PK1_~UD#M( z)blev%f`kQCSZ2(q?}8YGG}mO+Wzs5?55eAj%+D z=thc&)!1?tX!_xHuN93nga@V%T*bpg=0EQ^bIgA7hsPC9%0AReFF(JpZRfERVyurI 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

1;gBXNt8fy^Vlh@^1_Jh6f?2dR0sL+TK#Tg&H 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%0AR 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 y{14;CNUY?LuADu-o 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%0D^)5 zOEKI?iYvoRqDiu|v*ia!Lplg+zM`yX2mpy96Tj`jdxZvZ^#0pgGlFqY3Wqk-5vE_ZTnQ|Stho*f=w{aG(


g-^y%uP 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

&tAP4UGtI_YGKT56q4K( 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

LmQsos=h41O1TlexuzDgM18x1cWA$P4; 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�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

QSdK5$=q|j zy`=|`BRQAfO17vlmJBwS!+D}AU!<&x2(I3GFxzIeVUv>pRz)U4pOo(R{x*?kUG}=x z7!9)2d7_snxI-H#ZG|U|1v>dDR|vUpAYu}8Pd+KD`t)gaYpUwvan9Eu1PC%Bf>fl( zgSfnsca4o+aeYb^G?qLF_Nzm0)F+Jkl8^4uD_-3%a~q@*-lbVK8l-*9^bq|;@Pe>M zEgG25CQo!6@10_G&U0k(Yz#S4Eogh9KYw1f*+uGwaNtPvmf36a?d^7SDSrK%%i_U4 z;sOuuUhN`#xfi(}YZLVYy_BGi$0vHYa{z7k5rRB_bQ5}|;2j=3-p(&dMI)v@^TU2NW3P@n z#s9o^Qc;QADLgl#RQZJ7Vg#vUdYb5#;*vL?{mx;QLnapy-Z|*mA!R@RU}aK~lO$`)n0~(EP0jFI^i0^(A|%4|;8}lJO6gURc!& z8tbW<=UW3iOJT9g#a=h0&r4)---%}mg*0`&v~2@_we#0UgBTEZ)YP1=&v!5zPS?ah ziyBK<@1SDq<(_#qXk`N7cr&Ei=jDooY+F$554PW_(8cPeLh17I%F6HI?0cev3!}+z zA9)E8(NPZiI8Uup~c^)T!c+~h6@pbx@a;yZd&pIEtZZRk2{52y{NcW&@yFvXz z$Mw3OWo9VZz-Yx&K_LO-^X_1X|8f>4SY9twS2^dx1hZf$ke0GG>!JF+CvP|SN*}k{ zKJ%Q^enC5_Ep&6zzmjjB-qb|juVAN&92V#7DK zL!vDcgpBNyLWG`B+s79Ce4gOUI++UAm{npMosXbdr-RFp{b|jnktu74M*SQ4x$&^< z&N{quEjM!^0v^^UPvE=h)P5Uze-r-8W}DaV%*>?dvi8W^j1|32o&I128XBwTOg*Cd zX}8AM(a-Fk{1X=5yrUO-Efo!FBaMk*Z;7!#oljxp7k_G zEospoV;_F-^O<_kc-aSJEk(w7HTY7Wtv<~xl)>Vyj!JyKjsZuF6`kWVxp~2DZL~OG z;RV{l(ZVP=BQ{$1esC6^hQu@D!QHdh>dDxUk1`mJr(?W{TsQd6!M21^3OjF4;}a6N zt@=PiYN)M*nm$G947CueZUt*Xf<$J1&?}Si3=h*^9k0jhHadpp9=I%TB=EUhH=l2d zkjV41{jPKO6>=)yUA_pOb-3;(dL`Q!rl@fu2`0htLJ4+|I0k?$D`r!6-M@Z0I30G5 zk=)swN?v>>^aQelt$w~o2?nxw!~P+qeA*YZ4H1zytX!fpF4$maX%@1mu(iD677UO9a`!D3tTrKKgy(#W_9 zY=DBpLEb5zt4w`(Dt3L*g}1uejtEg@ejG)v8JR$|!=o`}_H$$E*cw_{{2ELg9>v9V z&50=&eQoPhH@g|wGp=P0Uo8>rUUmI(=^yr%F#8XPkjIa;Jhh)iHJxGpXYb&(wtmyf z_hu1c-k7)5zhD#`0DjapjuRk8i{o_`VOCEiGW}*Yr=6v=oUjeRq{bEIhXmTQhd;hH z8Y;YxLgGP7K9pf%X2~rrFE6S#04OPk{(WYu8!xndOj(*ucb7R~y%=c2&5J+K6ZyV3l;Qk&ktFaj zLRh}md=rckGBi-HQ_-)ar1SxF)N4(2w9mS0$=mzI84c4jQ#&)VlAraWvE((}hI3<6d}#@%f#iei5!EBq71w5O{-? z=HrMVeBpNOlm10Z_fx=*j=`{u9**+@)b!_?87^FH{u#t9* zyKlNP5$wVgn&!EoGrGDr`+XH;oM%atJXc^|fX*Z4BXet~qi#t)^-tfEluhz?w+@b$vYq|NJWpd)l2whY-nj&1S{bTL%Da4iQkQDZ`k_7Le=Hz`Y(EJ z_uVhsprug81Ut`j%;0+k`$rn-djNL4tB>lySM&=vWhpT_Nq*>kYRa$f{T6?)sgxuz zL@@hExQQ}V;HXjkmq1K6I>0Afbx#>~W4HzA2yR@R-)>)Ek>re)vHKY(ePpGM36BfKCv+i(cd& zkNf2`?UN9?w!Dd&e%e@h`fH8b8w$2z{`3y8-EG>=!nXJ{wXG5~E&Jv!Jf!mrV<(fZ zzH3?UZ0injzA2q(iZ~86OWMlZjkd7W&`5s#H_4pLj>9zY_E_V7JyCg&HYGCM&j6F+ zw!uu`dQG41vHq~7+rb>aNzP(tO_=O)l!}rPy0r8&kb2{gIBKexmTQAhSY_{X&n;V# znw|GiZmjOB+~C)Y%w!MUqSI7{GFL?VPp9J+$2^WQKm&8I(Z8Jv)7$U}fV#SRt|*T;>jdgL9_OJ#KWrJU@A` zHgJcViWowC!1$N$$cOQH6TfCWrc61j^f0FWlkjp8;&X@PPt&#QNh&Bj0pJugU|Fy^ zQe`mfX4xw#R9=fErhNC|gL2%J(AWy@lz=f{ z6mowEz0r$#P9bo11`4)b#)Y5Gx!|YxHCn(K^xVwN2~g)BG4{Lu@;Pr*=%2(J(yNe* zNhNqtQ2Dxo^`Z8gp^xUrRj_ixY{lj-z)6_x&iL$52o5!_ukv4Q6vIyF!Zk`dpe~IR z!cLhJu1?Ep&{Yo=z54P8l#P@b6@EiQ7uvHOFG#uv6|IKI&t@M;{UMWfH6|unirBYA z)YVbQh4b$;t-03=V96xzB?wmg3XV>Vu9nT%$xM3XxnfOU^j^Tmc8DcHy z%wQF%yLO&gGte>}6e^@(nESO(-tl5lmfUYWe4OTf#;OstI5(P+7%Yy_a6DrtpJfd8 zrR(#4Zjix;D0}REm@Y3zguh9V$Zi1hi^uwUl?Ki$1;t!G(e7VdHWwEjpeZgSVZdHgMwyW=mV9-so%(pw75)wH2Acbh zoa?3g<03A;>VFmlP1Xb}6Yl*7<9<&v@Ht?+BH#a@d|Vi@(v5s*DCt^v<{$*Ju+XVC z*f;P&>Npi2M@u`~Ej=lDwfRzY@#Mm8O!}De+@$TDZN?87CcF7_3@~-!kRmD-C20(t zB)oJ96ZsfVat~Y|$a6IEl2x2l7?~YbF4-_iPQOUs03vv9ULaF77Q@TyOg-hv5V1<0 z-@8(40q%JA6{7($wgjFH9x$^qU^m@k*dVFMsD_GCwM0zcbz(2djc$j7og*&K$KJDvtB~ybbAV7pk%4M*AklY6AZ6;|bEoTGSljx_*yC^Bai7K

c5SfuArL_5#H6}Zi>2po{@58ud60x{pT3JStC)JAI9Jo8;%pb$=!F8{0N9OC z`k;*y!u%%^nmV(S(|Od^tp4it3s|Iwm{F8kfyHtsWL1FB+}F9nr02axntGc0%0 zVc{VC`49k7q?|^0Y-X=x*J@swM21DPb$$AsPE6i5*vzi_gE{nx?Hf~53`l7?p7mpi z&k0082M{k%6<62CY^hnyBwpSgc_jNey(@C7-eI>7J2Z+v0Nf@V^cNuK6xGW0SJl4H zz+fLia!1%1Wl+rfydqhY%3pIErL0jvP%v;awb^Y^3v|Um7iY6+KN+G3jTVYte6~ez z;OXh|9fW31*X!9*n6usf%HL^Ba}=irnXN_&*)6NP))Q@KN&CC|$1g{-NRB-jNWFLz zQ;m%PnelKds`k;`P`IvhY@)}tTQp!fI2Fj-YRGTWb}4WDCENUFBb12S&C$*-H`n8Q zk0_g)C=&x2Q7)yHG>*Q6qp(>fx4rt#3)wAO!Rl0xzZt>4(Ya783?b5S_xOxh@K_6K z<4-=U^V2o)5Vx$hpkxqI(U(nn^$R$W@YI7zlGYb5*Hf31<~ zGbe<|VYjSIE_7@U*_5Ho)TmDJ9{rHj$_-_vYufQLY-dEu)w3!sbM%jgX*y#S6o1Of z${KrPWbUg^V`H02W!L%RIFcG{5(9B}ZEn_-{#Rlc>>zQ!VqHova)~ZbZLx1g zkX=OhqP;F;TX`QD5tCdH8wqtVFo%vzOKTYP7zxqb{@|bSv$VpwpyCchs%I)WGeP3G zm)PFufL9Ox@qsHRCn&R+n-Z`PPgrf2evjYVxw+i9ws{6p5n@2U0&U_};fLy-_2wci z$O9tCkC>&RJO}{4(mn7Y1ia6$UymJJPXmf{P~+_9r2Ya-Xji&Gz?|+)SDnkfG~XW$ z2Y>UEq}IwJy0H9yl>*gdj2mm^TOV8(l?cD>{q?Cb+ZZzgf%G~S3y?WYRe5C6Ga*A{ z9@m~*PjY3iZIcU<`q#+}!uK!KQ{SMVnsAUKe>;g!Ad7C8LtgzwKbB%+79nw^ZW;R& z;lx;^^bE93${`)UTZ?S21TRrh-{L7ex@wl{GAmrov957hVUN3fNMugKAV3J`I_5lQ zH5e#W<1{{}a2xF0#>XqiU22SN+84vq(ZPi?X06>D>w7XED&$C4s{1jh6M7+#)6-oL zqMG>k9_jCZ#CU0ZcfoeC+TLS2r_eQ?z!YR``Xee}-MFt!Kae^(*}wm;sHoYjKA%JW zh}a6KE1;ESgg;~j&xM7>x|vAMi`DwfKJ){rG2<$MOC>js1nuG=!2@qhFvY=o5X)6I zoIk55^I8`O4S$~J+|=72Hu_}`$SY*r8qS3`*F7eWQM5_Bx~lUgTs=2gv#<1p&W&3-!TKgc#{ZF~Bvh&i{oL2})Ld$s$!qRVoLA^;7LP4uAe z^PMC%2`TvRM;UJOU?mw;_xx_l+H)?F#kDMj709omrF}s5wQLM*YM0oBcO~+$!RW8w z;v;uTl$qprksvoHf}qHusbspzVV42GUmi;^oFc=jZE&d{B&PlqvR9s0@~H>x@V%s> z(e3Q&<0lg`AwX`8=&w@P7@x@FbV5n6|H|FojKt=Aw&2ISU<_nw09nr_xNY*$uh@txQ2@}~y|K6G9@ z6-neCoZnEXakp!nXi}Ee52x$-D;GL`ZhG+cck!L3B~$4xgQ(R^$#3m1f!Rd-ZX}W4 zC5SR!mVmyQ=2e7%twDBq6b5))qmBJ_PQa|4yKR)5bv_3d1Lsh1aQHC6m>Amc**Q6x z*#db15%GN{*ma1xwzb~+SRlqd{foC}O55K1Z%sa+yxa4G$jTmdNc>rDCd~8}ctUTS zoL7$N#Xf!J7B=K$IzR^qUhs6+*FXgUEx-AlnXi8ALe6ks#H;Kzm$Un0x|#-BOdUUw z?pp7lBmq1{s1`mx0Fwc5*xtp0c(8!S-f;98qv_h_e%0+I4afw>S9AKgh0sK0OykvI zt#u}*bHnv_%N{Fu8_6?!&5dTt%b+paU64#}5TKbic$W@5XU)yKEP!_XIQgN0f`U!< z<@&^?f%@m@4 zl>$JgL#WSJ;gC7)=uAN9jx%_?P(b1Q%are ziwGo9@3|LHlZ~-e4v<;zL*wtG!{>iM!P8x}-?Q~sKJ8t49L&4d*K{`52Wak|mIhk+ z$^{=|d}s4H3&(vGFb-qoHnA-jW{FlAXjxCp8hv8%N|sm4?%oWj+>I7|Oh_ZN8*6wG zY&mssl_J%p1yu7A73iRP{R&3M3#0D)|8>+T)1&?Ji@~zb0)kYtC{%x$t2~IAfRb6gR_*)(>dwov_q7P^+##K|6_aeR0 z3Ey1hfMU6u#q2+8SE;w6O5Nb2C1W-FQ~aq?EJk}{>EyqAmn3$%N}m5p*8@sFPc{y- z%8TW{iLKTBaJ3?JDA#&WZf?tr{V^pzdH}&*(o<3^w2qDzUKCI!&O=%X(e3C*1e)!u}*1P8G8XTGUqzlzjQ3Y4Y_Y&Dt)B zZv7z{Tml8nVCC#-TKcBb+d4bHzxgsTaSF#b{P75&zu@-_>OtZY&3fc$v2&=;$Ik@B z^pp2&sjsIbCJsLw&~v5FXu?>jsgVnq47IO7e)DzUoWW-2%hry8 z@|R$;Nw?qI>1t^S|M+pJ#KitmT8TbqM0{$B--=oN*Drc178Z1X zGi&fY9(G~*MJY>v``XN(^bEycSxDVd7|_ii|JV{Vi|Hl}4C#|_RN@EfG>r&58g4Z< zP0f}j^n)XhbZ#&ZuqgT5w0&BSj<+MKKc|5nxFUgrP+?ai4LD4aMoUn7{qY?@1FvLj z1MINnxf4Hu(Fvt&PL0~g$A|bYeKRhzH~=lfVNWf06;e@XLGCJ#=puD#i}|Pyw3miW ztjz7Vt?cjdLGUr@umLqsyS_Jh2x#yx&o5x=YTwF71Yh-{Qzay1*Dy*9T9ZT<7hCL1 zmUnu{6%>mD8-*%!{K8~8SQp^7e2gauu9-UG^IkFl%|VC4lo%`hC1c?X!&alFdU7-f z+$N?{)SN%LqR6jR89dlnR7+pI$SB`6|li=ygJpb=f zsU@UER3ao=NlM)VP2n2?U5>~5=Gq4=@#yUfLVDR9e%T0MlgkJ0t#7W{&vD??2k6K|ED<6Enlv|$$w0!xgh6jZuI?Y< zO5j~EV&dsTa@vb(@EwUEZ>+b1z;i~X0da@wgVItQk}nlCeE1?h0!Y(ZZo~F1_=y)& z$)3z?`3}1gyS!=4@#uP#q}XoJEp=(J^gx}dW@J$j$pb#68dndNYk|}E^)E$JZ@_gM zU42fV#<_n0@XY>%N{pb;$>&R-j~=MJ;%+~;f7@5$(E(cHV~@;hEv2u|o54QW)++8} zJv{e?&&2!%Ez47MH=5|Bsh@*9W$L{@BHk$%fO!-MSWit&O{=DtOl$*^>T4A6X~K3& zjzxK%FmU#c#IoAZ&@c=*k^WMM$G&X$5D`4jQqg2tblN4;->GVc4i(M*Ty*sR9`q8# z{P)<``1QVi7$7hJw4$$7N#t|c|Lv$2D&IID5}4Jh3L=9zNPuYUDZ%Y=#0ftsIf{+7 zxvuh{9!OWya6AU?4X`5rW|cc&{v4F8^9T)#euK$ zuSk0O!z5hI9+q=uJ2EVD!1)F)=w7%QNJ1t&Szi#UCzJ7xd9xZD4=i_oAMY-S-$(_f z3ql%}lR8$`psYeXSI-HY08xLy*R~7{kPIs^WGFM?64v1Z-U=Y>V|5h-f4JyL&m17McRF=4l0K zk$CE2OM9N=>Wwj<1HG<0Ow8w5?ABz88y zv}S#MyTRemCJK!h&i0SF_M#v5k;vfsibev%J_k4Bfkc?E^ekJd0|Nq7!~Nx60kBd{ zQg?vJQ?@o501&tJsl4~GP+#JWefF9XGr_r4|0~d8t3FopiR%l{>JQG(H~BV_okAj1 z0l-|I94GoE!u1PDP;gh?Mq30J#@0cXQSam50vI5Bmay4Fsnrc>efJQqQsf?yeN1*j z0Xek;!|8JrryKY7&vUig&rd|6Tc}Rl3dwxEb?p&t^vwD% z@Bp=;VxCeuL@{+XDFe7hF)ExaufdnY6=!d2>Mq+R21o!R3I$}AM#=T5TWkVrXM`6L zU{d^{&^YOXF;%t4T}dj7OBL>>p_1w#EVra~)7Cip5CM?@ z5Z6n?1(Zf(i5e&L&cw6=ETmga>5(AZLN-6t;6KvBVlQFq?g{INK`NqVWp6Ey*LXlb zRP5e`3IZ;DfBkV|c(Rol_!Zl?zo1qX>E|MF-z>xd)WB}vj8+PWdfyo5(g*yu>L$Fd zllC)8qXt@IsmX;0WOK75y?EP5*)Q{TkiBp0mJofMw8O;+`}t9H2k^wnkyby`5il1# zTP6gF5=?1j%zUeaod($N0ONkzu0bqdST?*7j&@v7QPENmSj+9;Jg@gz z^z!)0xa6RDk1RQR# zwT5pSpva6yR?pxR4+5k&!QJX{>*O=rH7h|b)5nmdz5@GF=c|;`GMDyP({&})Pf-TE z1MlPGDWrt1`RiOMP>Fc`0FIDQ*MHa7Cjd9CCa~EA6*mwYcQyuVIX4Y?D{LJCp1Vdh zn;!;#?b8qDzSKMX5KOPCh1A_sMPT5g(HLjB(t>C+n4KXm-eW2-evFATkAMKmo%WkH|N0aMD-gpUf7u*5Nw=_*uJvL2Gy-VY|=SdWHKn?K+#I|uuMjntE z@59GNraUImfkcDd9xk8*um|UuM$LTC!TgO|F4zI=cj;b9Jg~*zd8MXD==+RqHAF)3 zKcJ7|5O`pMUklJ>3(U=Bee~##kY4Cg*v5u}jN9DO@{zATuZFYnJycXhx#V(03VuxZ zjsm*Uivy4ip9%b^(Zd3NgoeYt9CKqKo;@!(O$2d??+v_CPa5+B$Xs*3wZx@LTBhNh zh})AF;&U$`{&8`^zoJM9T#{=M|ayYp51c)SD3A;HYsY2vExUlGj5&^BcwX=s~+)F{qIeriR z(2l^()<;A}oSH6VVbRi_7BlfEIm{Ag3v5tM)uoFsjB~$-n7MYI@%@N9{$Vg8hGyul zng=4pG@hJ*>%^KlPC7%Cd1=GFMBHT3ZiSk#zV(MTW=t>vvN*Mk75%G1RmKEDgx3s3 zfd8|wm*f&{Mo`SqNKdNq-EjjtRXA8Yp+M9dmjY2;qALLIj|NKJo8$EiHbTPB#Jq-R zArJfz5+r;(;7}Ggu5_DnQi-YYw6dM|iI2B))9N#OXvQ06T>hxm@v(i!#+ z4kEnP=tke=$0`{VvEg_QBtR?=l=4F(kdKHl;!Ip)*4t3-;zW*OzbF^Ao7bD+A(lS*dU=)FM@xin!N*0L>McbD?Kh?={RLh)+fq)mFv` zD#4nf&R0Sx7N-v=mkD6bMI_)t10n;rhWniKf4l%)fHvkZ8j}UEHJNUHCLPto^f}1y zR9}mHPClA^3ugTG{EhGrnIpLOCL~%r^b~BQU@XY}m9_3AZ7;0ENQcKHB>2yLabGoA ze4)K5FVE#&TX~<%&l68}vEIUIoLA-TE*B}GI4)p(4KLh^0YL>ldJE*F!iVvjHMhQ$ z=aqYwBZ5F<4+MB=3G6{Z`d1W|OuUW`i_Fj*T3K1Lw|md;?KSyn#pS5){Jz*)S{X&6 zCgO#!N-V52_qUtx0Y`6|9s5P#EqQ2eFZ=Q-)CY_tw&a{}r~vNE${8SqWdhTKX8Cmk zJzA}&Pa*w7?G}Y?^s=c3Mqa#A;qyy7vl2!9z@C>;DD$mA(!$cT=tMZ*SC~L8KEIez z0+?#H{16dpYC&}WMdSb=A>5+|Y~km>XGvho_?bFqVVVuw#cP~n^f>pq4>az!R8}}O zwPwJqi|}h`zz1RHJMdb2A8H9Iq-%!v68R0MsP1e|AlzJvL~*VxjFA=zD-IgG|2E%A z%PEWuJiBl<4xWcF^0aAV26nyqe$)*AgB}OEnwQMnF%G!$^NX{# z6-8*r5H99+M=ZVr{B|WXhi}8i;63*9|yKzg~+bS#9R+)`<8_%0P zujcAUKY(m?=ZIx2Y%yO6Xa@S2@yckmS%|qQn81IuH|tu_i~!C9HhHa9W298qvN_c7+ffTx(xXa|6t&n{m5gw}(k zKhlSGNbcj(Ew?w@l1twLFrN3y1e|OIhy?~%svroI-Maom-)o#!mkl=cXyQUnNl>5c}h~7n}dP&i2{j8sd)&9!_f@7&wvsHznayBMR!KRF7n3oIqRj0I;9v&Rv64CfE6q z8Y446*%GM{mV4i%>uesVG83Rc?!+5of_CVf@>L-S0K>vCzKwHs;h@wq?yePPy7-;{X1;YIxPG?Jcd^drbdYiixb z>H&3x4%C?pps8mD-**2aECpzDJW=Z!w;yetec$<3mDE0z@fbd!zb`~2#ik-E+_V} z?vZdh0RsHVoW0&IYRKi~<$-R1&d5oB&G;^^B6?cCB3Y8g8YC?#Cqh=1mThM*FlvA+ zHSWu_ealMX&AA_`;Ag;v_jw#P?;q`j_ot-YgXGW|ytI-b26jpw=>{k;0s-ngk5JZ* z>+~APN7-?>@f+IjM5#C~1&wXu6-4!7YQO#X2y(oojj@5HgU;6lpFVzCZRzQ$*Xk^R zn!T8ZtAu|Yrr}yfmPNpgMNZzRz4{fxS~h?YOarFr_{9SJb+HQHrXsXp8u)aco~|Bn z{rtH~O3mf3$!Vfz5Sz~jGw~TlXp?nKYNeb{+{e*8{{9|6nDVRqoHvWtp`h%hOoJDT5Eh#)=3zzdQl5?F`)tdN3jIuS9JZ zTR_0-wu+0eE}s2~iZkVb3^>q=0a;0?1~7qv%2)^l_%eU~p04fb#M?0Y}A0kW{9v35@Yq%xOi_p^mBsJZfB$l5epskv3o46$ zpjW_v7%Rntf3P=6+XUhH1`+_>^yYtzKuWWnf9_I4L%kIq3)j=VjB@1}6JrL3V5{4` zo!RW3PUv7RMhcv$xeHKCwpF09x&h)nHC_S!Fvek=5_6Ajd6`P=Uh1BApL-Ln6_a$B z1`d%IR@+N9oBz5P5Ys)xCbG$~ zP14js+H1sUmqeiSyI)gZ{hy1HM1~L&wtSgxi4Sj~1Pu}YR-W!sg398oXIlq(6JVJV zK^y>-3(~!=Ra(gf#l$z!&X9cktTYch{3lQPoV~t*#7#_JE2?aTD8*Em#!BaFzwUz) zS3LxXxuPGO9km&Ae?HB5{&TC~H3*sLtQ_{=J;9M#Igt59c&!@%Vu^x2YO?SDmP<%V znk{W3H#B3us=?U4L`vjA!kLA=RsH8KViRWKY%F4*FE4JU4_Du!A8$^NDE*xVJgiEx zsG^c%ufN$*?5~Z)O`VV8!|Cb?1AU;O-IGhdU?NYQArXoKp`aqKsRM|IqHGD@!HkES zL{sY{>^e90Y5`>f#D8qKml%j2{ag&VFjlyF@7&{PbNyQy&OI5_e}QIo{LJ+g1Aa-`F6eNE> ztkMy@S_ozdq~J1}Uuxt6*UuGF&nZD>*Lq^@_hx9xV?$)0=`AKPCJW2Fju9}0clU+1 z_m|GscpsPpE0-u;c`JaLZ$K?2@Lbw`KCh_QHQHilf71;_XNP^kiaroC<0@pm0N;mY zuHYMK{BmLm(BSa8J+NZ3?lSUlh`Gh>3FP8s!hmsi4)Y2lf&JzkcnbIbitI~+VxPxg zm(^Yx#z~4UZa@a~)q};;Mh@GxJXQ*=uyBeN~UYA>NTV1z3pKi_m29$Ahw zFQ`ksqHm357f=YBEI`T}8oEnlBp_;2a{H&|E_6ez9lpemz~(2HcFGCtSP>s(Mc`Du zZe1xZ(Ev2?wFLqYdcoQ-G_?!|s0OG;ph8BRjU5$IdA1cu-Im_9uY~b)d)sj{srd|Ny)O`3cgGBtSZXgeNG4d4~R4HY8;@o!2LRM^Z|ga z2DuqL3pAN>-aq|~m3}Jpb9Hszh%=h>NISe=UeY!J@HC+CBlIUNkvM%E6)h_{2}ula zf=Yr~%2g+lAVg{)uTnj_=5Fw*Yn!b`)z!Pv;eSh0fdT4izw32Xy(RunFbWsY4bm%$ucuFUhxO6qWkwr7e+GwdVBsE z{r~zR^tvxCgDC+C&UfRNr7`^1cmB6$Fa)`W+f~7ga~ZEI!998Z6POh@g0vCK1L0>Ii`PyzaggX*e$&MZI5LrEB#V z_-jS^`)N`BFE=Kj-Lx?yo3_;R#qCvJBAd*=-y_Kqe=fzLO4vR6CY_0*|8B5I6q6YK zyU`pjlFx)7B4R8o=02sui`U|#{|;i!zdyJ_RZ)(A8|?dPaZ&m9KPB#$qk#PTSmO>C zh5YxE<^O(9zGC@@hIWtTSUSFvj|@;|dY_^rKPAhY$p5cPgLxgyusdlh7~b!4x^5Hc zR|$`4goMz*e_rLHy;4*ZkJdL3U4Gp&W{5`;EFP2lywf@AN;0Pxk2>x#jet%_^`e%^ zCXPG}i|hyIJdNeUT#8T+Ukz&mDE|(p#Xft!Ry{Ns_1)F9 zNI#{Ze=2rFkdTyw?);SV33OYI;saK#AQE#f`Lim8+@=YVyIYmC7x8ZXWsclVjyglZ6_!s9)H*8wi{U-`xzV4Q!$#U z%whut5Mo;^iQ2ICN=sHK4Cg)x^A4jslA$NiNwRO4jvrH+2OfX)$a? z4Bicug~dzdJqox&FIVrNkKwbK>MTlw^<0^D-ph3VkP8%#(X!fV zkU<={i4qbJen*wBRA!{tm+0{bD{2=w1v2Doa7rIRfTURJGg_}%v!PWhcl@}`)V#OU zdiEhWbOhB3hW>!GDU1{UnFLLN#pcledg1^4e}llpY!edtBiX!v;`}y&@rmB!j%9hwk5wNhGhzK|pRPTjb|?i6Q9Y zR9oDZqr6;wg|FLGi4QIs;;??oX)}BLEiC)r=79zQsBstR@0>sb@CXDz~ZKtHB9*bmxZ8hqdSJTaUx zh`)lKu=ry)cBt@$nl=pP%oKN?|F&S9S@*#-bkz6k)Umr_RQ_K!99-PSO|Tx2TgIVZ z3nZv$IiBLL&)V79DRstd;Dt$Y3^Fvmn~@C%Q|-wUn;$lfhpUGj6t8@73#RQx^{btX z66{9b7#c#S?dIM>1PhHDa>7yJL{`U^ZS9q+rIwdR_0uIKsBDXjgK!yDnNj~S>E z(;C3E6=J+ZWY+9kZ}0Wc#J`pJYM1v zn~&U73Ad+1sIqIYvS>x*yTI-Q>6o|cxc@ouvg5k>g_&QzmHJJpQw*CcrX|hpIaYg;?UpCZ^ zMc2-1YDe^yX5NV<5Ezx$pkr&^LR7n%+&~i!HDnBUyIZ^>o|ux&9pW7F-|heZms;f~ z==LE!e;w2}+X!)_-SK^p{SYrco|lwSw*(&@N8SHhYfSWyV=YIv-%U#E0F|VPFo`L7 z*E0uxl@=F&E0)h=H6J#`@J2+u&@ZnE3=+-x3Fi%{mhaNwOxV^}&B!7<2?i zv=3+ohvnl4*pVB?WNWxsU)>rujfP*KM^v@!f{G@o3GhWOe6YUXX9>|qV8*`Vrimj5+0shj^Pe{?FPY(vHN zOWYXVlfz$dql4OfCB~~(U;ppF_vooTLhO@Jh1zu!HPXRB-7gAHKoGedC`t`9%zgV% z!k2OnqNrgpTU%$N-RSHV*IZJfjqVUlAOQapM_i(Mvz7u%VPUeGJDTvbpZk0e%>5j~ zF{ltpgXP@m>0+%vrEdkMQ$D&K{eVC{ftQ1h>YX$Cpn~4V7?PVMew?JFGXRElcKP4L zo2XV9KG48QKp!2V}x^lfBr4xRHN6bGKoSvmx_LZ59 zEmG>?pm)xQ+KnV_v3La z@IG*Z3*MTodXpp<^k?s>XRpo_v~6H`d#Qg3u%_1M+Mee1&S%IO^(Yy~vtM@*D4>uanb;ZTS{(gSg3=9?zFiaog zPjvm1{%`yNmjMN#pzw8%dy!J#WDhWfw{$|>zULcC{Zg^&>fz>PoWu1CQUNR+vH6+` zC+jN)g~&8ujWN{u2p{9WK|a2s0yW_&g)h@gR%?L>qxlT?Z58I7Z*o#g4Vo&&X%muJ`^P762(~ZPnyCLYfgQxLd}EL20q$UMMJYK53sTD(z!(vaj76JhnmYXEahGr$U{|2PBLv zrqid_#sb4?1IOd)u0mc8CeQ-Jg34Id*r+gnoZi;ybh`Ymx8%IfCdu{I_jJtc%>l#` zjrj;kRKg$9hlEv23qH0lq(68`QU_#Yz$T?L@^!MV99BH{wxb(vx}N@xiNgh^Vd{>{ z1>!5E)!JrNnWLZMMe?o*AHl)>Lnb?>47U4KA~;L)m&_5k6oqA1mkqCRE(@}8zGEGlRgIdiUt{(XduY^JlL&oN9=BI4p$zudEun(6vvJ1g=$ zs$I{l+W4FFhWnmC9I1#nfI;Lbzq=bT)^h^rG~XIngd@RLdXtyy$|>@#C)K+7E-$~x zzpTK~&@g*@x@r_uVd(rIx`T?__^zeKOhA^LUEffctWtlmy!Nq!8_tM;IsuQivLOkR z_T>Af+r2*0G1(Pz$w^xCJWo`5)Q}@yR{edcuk;rsyDWXRguIIDXurJDH`yW#W|W^P z!&fUO4SKpY=T}kDmU{A^`@_o(fCq}c{TnxmZKv*KD@k%#PErV3bhZq369n#sTl46H zjOJtA;mKnqp?Z6k z*Pl$CmT+8UPHc43oY=u4(fdcN!&k$tO0cQ3t~)#WG&Ce;hKoe_eb{~Q`A|EIf`CI9 z&=h}o<8?&W3(qf6sl;UVcQ;0FF<8s+xvDhi{^*P9jNNT&DBIor#)Ei5Njt#j%qYz)oY={%xk^0mmm`47=>xK+o8c!B--?YQMT+{ENc_eIg} zd`+`@xI3)|E@oOwfAW^!Q9oFJ&B%yL-D2p5|Kr}6Zs#{|6wck3UExBYXDHl; zWD5J{i!WuO&aeN%%%FsQSNJJYG+UF@JBv@pxa9L3_(Gf=@6su|h#EDv3ss0p|FuZ+ z-HR(ukA5TI?R$|(wj*Tz8+@lkfXd-f8F_T8SC7^)BA%2A)rSjx=B^q zh{#s`jjcMx{eY1Zy)Riy)Vg1sl$Yg3=cU>QO93I#A}*uW!S2HTnqXe5xOfv!_d17m z93%qH>0-D#oLW zWYx7JzWjV-I24})uI8E^KvB`anD%NIWw&HHn$WmQVHg8E@cbjaI#r zGOWfim3_$L8h7a)my_ikk^E<{d}R*|HJ#Y}iT&;rC$@k~pIDKg_WGl$gY|v<80PJe)q$$L z$NacI2pu~%i;4*1-J-@;r1(lKhMck$u~gqo=(WYo4RjlQQch8;fL?CP!FcemMZTs0 z!lpz=wI-id@c5Wzc6VK2nPfnotK^*t4iq=t!)deK>`B!uIe`F4sKeM?Rv~SfLZH9$ zVBH@JZ7$1Ffq5M{7W!0|Br%0MWPF|&8IrIK)0xwsV?02AvO-3&rrEEnP^am~m|0}$ z%`jn4<{${gh=_>%vL=ys-fXS34CP3b=-klxsXYOG{q*^Xp**;Qip%>Eu?kN*ck)h` zgvW{PehZTA+|s-j(IuUg;^)T+i&<1)$CBICh5Fn15#ZgZkR9$to&NV>|DYre<3q9~7U*_QoAfJW<>;R$U|tQfSh# zDp-Dw;I?s#_*IgWbaT?NODLzxA?Yxo6SC(6)`!=KiN8A?{-pzuh8@&eC(Nv>I{5$! zyL<%K$2eS_{^NuSxBkXfeSO2s2Ty6Fqi%hURfrF@&%3b**Mf-W5U2bPamMSCa@#5s z)l=IW0GIAKd61Qs84wAX1PJfJ%+KK6e6`V=dp0--#7Hhz>o}(RtM;@A**Q3}e16N( zqa#UO0-4hpP8;zvd$}?D5(+9#NA}l)YVEHCJg#GKJD(dB2+p{=qm;SLM%B=%n0&OV zQ}`V;{oZKYyAmv6@0^`GGylqrFieMFe*^TeFjJM|L(RY7HzB{&eJ_{h2e| z8cnr?Q(SV*dsH`VmL>(={(dj{EVh0PAjweM=TkYqx6zUjR&!|qP3?0MO%ma=WmqSl z*S#Tfaqp1(t~A+oY}Tk8`0HHkh*}>V z?oqBX6)pd{m49WyvOO(`{$RE2Xy(YlL`kTk!d{#{CBk_29Y&=&kxyRi(F1O4D!jXt zy9>ijc8#bX+Lev_cV#$?k25nFt9Xr=Ak&v0B`F%4AKu2lIg=t)psdpuhJ(Dsi01BY za-RT3QT4gN+USr(1YDx9HeZb6txGg@t}s!JO?NQCHfWjs=T7Bfj8!-)8$rly{_TB( z_PkF{fPG}&yNQW9-L75yWBZpXh-dH&q|;Z_{voPgj(AawJX@2KC`56G0RXeCEcs-w zj#M;X0?g^iF4-tCSW<;sU*d3pa69OcsjhV);1>VV)#6{#3T0n+InMq$O&6ynFJg(- zqLZSj0aX}x{_02%|!Rpl9Kn|9Fs9M2<2d)D;ee8jkTESpBG6upkDVR%jQ$jpK|^Y`E5o$a@I@mc$J9_&s}UOR*2+4f}QUs*63i;qse%8E0TvWo7Sk8jZ>g7R)D4 z`fQf_!GOO9?FP;-H`|*}pN6%E2~)t<;UYu7CYA2WU0$%G2_q2W6LmVxe9tMU+|QW% z`IYI)N{%}nKDar^>~K$(-w$}Y)d7392{&((QQUK>UtXC>C9J>7@y0|LoyWqSF2uYS zl~&0ge0?R37xRLx?epSyG+;@I9wnzNtu1^``TZv&$#~EWH-XbrV#i50dG1@cfj|U6 zS;VWlFlNE?<;VF2)YrrA1d3TZ*NHphmg{xZ&y;;zBju&OB#Qg|a)q&Ts4@u+p)YsN@QGER#aUQi56lp9 zd}jVrfZ?))QSfwG_5BF0=8UOnJL$UZL2X#QSU3y-59|;NG+CdlCPx{e2 zi!UmX-~6YYC-59HgthfmED^7+!57xN5lM3mF4B17Cr)Qc&#%)MHU5NfzdJh>3b^PS zG2V|dnPSd4~C*nl-tqX<+6t-731eT>AM5;CeBVu`ypc#%YwjG zZq4DzXREJNqOiRlb!3oBQdH1a#qN^d;diQSEQAovlN~4&GJHX5%+$%NozUmn&#isf z4Orbf8lZS}6dI&8l@{ICN-!>e2-_gwafJeY=ZhR>NC%N z9xjL3WtdiA6mw?*jC)j za7)}?;$K;kg6#=BsI^!K;Mu=f<(&%Cg^rn-SFHEQe{V=uR@W6lJKTX)Edw5zQ z-*KC+)L++}$>otBbuun)S3uCpyrV&ckkmDHElUI4Amw2ifa+>QNzab`thYq=KVzcj z^gx5r)2Euno?mSY*5s!>?4I*z>Kn*Cc)M+l-nJzy13}YwF2PK$1UTMHqWp)$LckA>lY&F!pli64F<3 zc`3Uw_Jgdi^S=(#?m&0(te2I=WAUjEoqTPr3v67;gIRT|N5vUA?;B zWO0T4sCj@8hL=Ko!PulaSLm3_3}F2XP8H$aq&L?y6beTO@QHKB5;BArU*)Jqb5phW zlt%`i9cm+B-(R0!0HB^n8OKB9-5gBoa*v6#H=7F3bExnE5EicoNM3c%ZUT(S9 z1yu~101u30FLEa=2RALC$4~FFIokf*yuUW3W|8R@{-5=$2FdR8b!S3Cm^?YZ;xn)H z78O%VmVnJIxr~0#2w4p(o4&J)(34Hl$juSEf#^}YJ&=c|TPQAbW=7q7PkD=uo?a%4 zv5HMi2RhH2CF2TZ?(~0I6zTl5_TY%kYY-qNmH0u@zz61zjce#Q%C!LRY%$ej*3W&j zq(b;Y`;ov1zelD~bbstf;gZ=a&zm<}7g4>WzNy>ncL?`5_=vm9Uu3ksbsw=BpPFYy zz=qv!1-W@}nsPvVe9i3AeK?KSnE}JphmI?TR$2Lwn#4*+=k?b;%7_;m$AK6)-tjd= zJ?ghdT*G4fR6w6F$tigrR%3e>H@dgFsUWjsT6{w7MWSFoI{x$LPwd=ZHMEOx zc&^?|aj!)m$HczS_XlmstdhbvNw}-s!X?zbCNk|ow)Mrj*59>)tJP1U$$dGWKD7vC zMdGCxlMA`JJm0ZLG(%kgiUpfQPZD^q+ZQ`#1(gnsekz&08!NWca7&!5o8}W~KA{7@ z;_4_jX1XzKpF69!?{ZR>@~>oGcKxfIzjY{uPa3dT6@D*l$SF25Xw?%16EL=XeI8tF z_gmq0fT);0+iGvp&}SS%Mm692T$cZcc3;PO^OR;kWQRD7nq#Y|$TgfvJ%YVhGX{@E z&W!XQEltNOsaa?pxUMy5Z6_%4lbBZS%m~Q8{i7e6P+&i4I%@iQnS_AgsoHl9AV4GW zC^pE_tg@b{O$o1#{T6u2$VuR6N#-Y4XQLMQGGk#yzu@Nk`?!1AyWQ`cYmlrKE+N&P z0tFB>VWgjnMn+2yc6ECUjCKrn<4If+QR5PZ2FxP0`HqYJd6G>xC zlBiZ70tFdcGA5eaIHhQCa50F~c5}B%ZHiGnyuVIFcXnBxot+g}z4Wp1KZ}$2LIqep z6{c164v{&)xfN^y{vF9-QM)IM`>Mdjwx>pd!dctVisMoXLIZFLDA+OWv6VNv*HQ zCvowT3=3I37xSYm>%Zi(A{A54JY=3*UhU5t&>fuc4)({ApqI6r|mv# zpp!+vVd1S-;9Hbz6C-92?s?bdUJ%21W3JF?JtxkV8!fP7gcJptD6o~n<~n|`=v&iF z^)67EZpfx+WL9W4_%Do@*(&8sVjzL0sgA;;-gLc9|9sGA|Hkb_{_l~0D0^47mDZO$ z#!V1Boy|eiGoYOA{B4YfX_C2zRP61kL^3N1$#j_&8>b>b?{fr5RM4nRE#RO^lEyx~ z)_a**vGpb|boS-&;i2WR+u?QCiSm|-NlCVP5j(HLWidy~ziIJwgQ54iir;>_Mk?sW zJ!k5R<#&yhmGwhlpzzzb4;n8H)$O*YiRV181STtnuB;}g?dO|Oe#Wt)%B2X7OvEN7 zh4%Nq^7Z%E9m!Q%o2;N$F4DqgW-ek2-chP_IWTqm^PQG=OWWgw+T(cP#$B;bu&aqZWKpR{L#5LKR$e$C?M%e%Gis4QbmG$ZtZ;9NKXG_U-1@41rb&AN@E3JV<_ zY}Yd^^rEFr4J9)^)&==S%mm#MYG4iC4=iyZrIAniFJV~S!Q=Qr zWwaWZRD_jVpSUrb)MP(-OQzU-_T3u2dW0N}O!E-!q@#wt{XWB?8)XDBaL}+l_4~{% zfRyO8#xZbc@wvwKkOM<+${TE9Tm(XnT)PDt9r^DwH=!%RE;)!tfM z&e6b$FAtfiS+qM_T9}jSSS+R1oQUYQP^GnHg@5{FT!2-Ccs0_z+N7Jo#p3qY>bc{; zM+)`8z(Aa!JMZDvRMrU}HR40N?r@>zeI_QRk1rl|_4bOpx$$q$HQ`jKVI#O*4;gqJ zHb0!~uj=)F=3!xHKTkk+&lxdwJ6;G-t#c?)t_ujb!7m`7V`LQI>x8-Qaedc$@gP(}1s>Z=F2>0&~7im)z78U|? zw70icZM%B=lO(mSuI~KKP9Iv&I|gd%>%d`k{ru@$Q^WH)DM>y}96PRQTje$gw$YJo zZDKx=uq(~lL8>xpc*?!{s|@Xf`byx}KjHB4#o~pk;76p!t3PLn_0co%$+JiCYWos7 zS}7f)YV27uUfRVIEy)8$7jOwY1WABhwC-BMgKX@efvTl@1!z66{&jbEwQstIwQiqM z0l#!Ht7Y7;)=rHVuhX_RS7PeSTp$?%q!R|_tpCUP&+DeJTtU=ggcRvT(}Vt1qOdJ$yn} z6{O1qrA-6tg|Y{k-^~6P&khg4zQD&H-zP-rh4*KZ?xOeUsJHaxe6@V^s4j zHwrWNlJvi`dXlUq-TVB>D6>z!tBbK={nqDPU zA&13kmY?6_oap{j^T(t1+|T9nMu<2~?>X$uVk4k%5D9tkXUZn!MtQ-G{WjavJm=^8 zeY;0T5{8B};vq!u^Ya-(?sN67l{7H@`Wf#7PmgGhW7T^Q_1zjWTU0w$>?@SvPVpjZxUIQ zb6#iR!g%mdXLmPNPa>B@il94-9?t=DX6RQpA~Z2 zeh+2sZBDTFgi`)pSzh-2A}W>DC2Vfa(3>m}TwY$T+Xt)UhPJl$aJGEwW7dq!%$B)1 zikB}>v}xD3wnA@{@e&ynXq+8x(OV1P;NT$NDV#DRt{G+L?Bb#e-^akf=s&&uqyi~@ zd$vK{KLYMfG!vKvR$71N>sw)0q|(`Ws+s1GR&p@j4koDNa7wa^KNNa2OqU_NR90s2 z0i($aD1bX4Q!MK4EIl8*D--#(A{6yg5QEQ>%NzV~IJLJ^CF)b|EB%E*KgP95J@NN? z*ZPWl8q%);#8UiPf&GswNp{>D9897Gy;shkzT?>d#)n3&<9!3We4ec9UuQF>`ul(B zDysDd(PUcWm|R_}6x8L6+~0Wj?!)D&&?PGZHlw04ICuKRDQh~VrHA5m(w&+}ZT_Lj z%F38e-4vzWdBFT7J*Ahb!|O4LH*%AdvaQ5|F!ScCw=qgjqzYQrhFHNbKMA^@zTN-Tll|(8$d@HZO{}KFk3&d#@XSW@zY%J?f$dA$e6k!9pH8tE5PAst z29D5q>dRg`2ZxT!i?e|m+f}zSH8r)b65-@)18FxZt>(f4@6w7e#p(^Fzs!b2_kQW} zN1;|j5cd722n0GdiEn{=)#9I(A2d?^0NUD`-=p3kI^GFA-rC$`fp~Y@YbUg}etf)B z3L#G<;9~d2_oWLS8cLnRR?Bpa?VUScTp7E5l$MnNxD1(}f6Jg+jGz(^X@B{>8C_K85b`X~Wa3^Pn7#L&<=lmQswFQsXA=w=L zKs|7gppM8CHG*0s+J9n?WV;|ZAk_^QE(MQTh<_`~#L0Ey@NWA;*``Z>ery3JRLwq? zH-}!?SP2^&>ljtDR<7?T_88i~YJ3+A_$okEqtY?gWQ83IpT6NenL5ow-gU!>3+UO4 zO`WaEE&0%?I`jSf{PsLisAYnOOnxLzDVP+N>NXd$w!=aTWWB!cN0M2r<_k2$s-O<|Ke%$0nk7;XrQ`*T22MWc9)~hp; z`1l;ZLzTyDcSx)6sE9h~9k0#J4>_0S_PZhXJKLC<6ntZh~-DjpLy*ivrG+z#ly)%vGD2U z3#w*e6PGrKOY5^k3vNEX`;3h$Ne?jMc_qeQP zeZd?;7d>8SasM_cx7SFXir(h;vx_=lX_Koqnv%9`Rw-6uqrA+6-cD{h(oV~oQWV-RxjFsr@@TZq_Ow=af zeOsJxa`e>R`(*Z~|JAmLorOh7F($VR@0$BDug)}IxL#JL*FSdH zYaC{78_)b2sfo(bNd7XUOc2fYuV#eo^OEv%F=OM$Oj`9A6>3LTI?rTRQlXG47O3G% z#WM9&g{v}%L)DRDS1hPNylwVE8Ev=`if0kdSweuMD zlJ-2mqF2uE=L0^tNULENlEz{%b7S-VY9A~7H2+Omhw)y+dZopbKV%<7GkjzI_ivL@ zRW^3^fh;)+nRl5P8PqWhZ@j~WF30s*<@aW)ZBX6M4%^`wI4v4n4q8Hp+4~FBxq5gW z7sbU9nNL^WL3YDc5bGh|`h|IL~PfEQw9$Ol< zD$CIH^z>_Ipx3;Nq7kNxh6C-zj{#t?>a?Ii9GcJ86Wjj!$$HB3h?|?}{rmS2i`P3Y zmcQS9@d!_*V!a;dq4}jHy>iJKxIV2=_9LK!x=Snj_Tuya@y@ch#BzqWYvmn-X6-$_ zj*usN`w0aSFs~96*pg~J9uhet{@c`V`o#Ea{DI3VR zMQ}#&VkUwoHvqKeuToWVAtb@z;*d=gNj4egq>aZH{J&lREGnDqxW3a2&w7Ou*iFkH zx{e+PL-8QYv?s2Ik#4g-LHT$+Ij`0l1GfG+7sb+!j^dT?un=$YEkEjOa@xBEE9b$v z4q|)e^8U-0a^Il8BlJ6{d@%J^bB{x(GHNHU+MAlQ~G*MZDM&L?N z5zyqY+WwM`>R>k+eB|rvi|EQJc3SSbQ*JRenht@gQRjfIS?BQF)U;Qo49Y?Xl4&OoO6>4xcI`4>^8I2r_&$NDQ0`UN4-H%eFYU0flz((CVJvX z$ko;L@6H?r;$vJ~w#m+P4STx6lS=amZ|Lri&(6{SW>Bk{L69b_p10x%4NErejF&8V z^0Kn4WXUG==e(x<$87mmjomVbi;^z##iPNOEY!c(pBthU$@asJu_-xSAp24ej64CkUpYhk24E zShYM3j?wluH1VV%lxR!4IbQ6L-MdQj(Kfl4o=TvGq2*s|CnX&#bfZqLuJf{i$Nh#s7e{lkWoUC6DLU^@DD;H8M%B9oT*jXtU2773(t~+6QVjo zh|`>VktMvF1Z>&TsUD(Rd^VWgUdPn|8KtA&F0@T7#&TzF7r4QWs#;#J)-I9u!ks?3 zgM>U$+AY2zwCm?6!d>w~K-Ytd^9$Tj9ZSnEj&2F`!;w@t{-*J zCR7e)&#N?jIb=RsT9R5-ed6T4wZzHDNC3_s0}@eZ`N2oEDkZs^vr9M#av`jz!jCfL ztF&mr|72D{O)dE3&N!;2 z!ZdK}W%F(Of|oneFDnuj?)vttaZnZ*&WbBzj4K4fj(6%M{uR4?(E2q$4^mIGq!hol zxH$UubPWihLz&a|?QOB2K#1TFrQAe~74rM~#1$hvaMv`3TTZAkQ-%@&oya`th~f z(#m~CJKbgo1!=K0?}RS**vIytQJ+_NN?8es?4Pl;fcNdmz+QUI6`DM+R}teKk-RB)@8^WdAXe513^m!|Jx&p5P}n>H0l-A* z)4f13F!Cjdh{uHi_rTg`b)Ubt%+PGOa3gPmDRloUYlS(dhS}NgrH^j(O6&A6u<*2q z0$cbM;kbl;<^_KJn%KB!n9Umb(yw0x#>44N%2P`c-_U8t8aIansjD4V#Y#H=Z9F4h z(z2Z&VQpjcWX~-yFfgI10XUKvCqabMYLX)ubgv`EE6if$f4Sk4@jKymhEv=?NGI{) zL(}s-Z=tGtyyfBuZ9Ir)hrx$NSQ}9e*b=n9-gC- zfudG9D*Kl1`<}~IcM8m3-Hb1Ki!Tf2_5urGP3vpQ9+c#oEQZ_$Egc^;kWOL(7_-OdHjLt9fMU@ZUyT(cNPf2 z3r}cPcy?5N_uGA#C>qJ#@YG^5Q(?Y(lW*gnOt`c}u?Sj8S2||9TG1n3yGsN(DmbS= zGi=#DA#`nQ3cvgSX2$n!kxy(VCV9;)jPT#Np)yk}9iD9O%sAc#NX|LM_J(qsaNp>~ z2b@l%3k)oM&kv(t-i1x&(!?+e{*~Vm>$r!9_tklGWkqT61n=%$&TvglO(}i~1R#8* zR07B9;=XcP9aB_RCJ;Q^WJh?_)$#r6OR*YsdTKQrlAr%Mkx?%3DK_*$947pVZgXz? z*vs#D5c2@5#E!OSLV242&jC$>#>dA8W}FH$Br}*+xK|3XsJAoQaQr(fg$1e0edf7~ z6mTNIVQbQFr|F8k%&@1W)Zm9TJS%1AlY3Z5in8ha&rQRg z1V4EB`Pl~743a#xf{xYzoQ2iZfak#k3wcG2EkEPgOF$6H*Qmksyf`3?jEa)t^#985 zw2OddxC5#ivj6y*zp9^dnA6hK4h(nmCno1hGJnZeu!>Pe{Ic)rjrlF0T%f$DHmhHS zr&vudHRIwD)Vy!T`P~-0Qq>;z%xab7I{o~T8Ki{QxaR+HO#OLWUIb;0jqUP6;ekwW zKtqFiqxj){h~F?P6|u@B*woirK1J%^px+6UV|kMt-;=micL^I`W?Yn#)j$(dV!12c?2!xX6?48&N2RrK$gKv{oK;bCNu+A3ZS2a0#gnCN zf8T5v%d^NEQ1d)!1_-Ydk5f$O=4e7`t0Ln=L$P697!Io5vWK++(k2m-k*uhA4(bt- zYUSo#_Y58101ST(z#9S~At7;oycC{MDhqN1vVUXHsK$L)1G|$kwF7Cozva5xOO~%$ zM*vTAvVFB2CD#v>M#0k@#h`amFCKR*>bUJ7p{~`oH9b?dLB;~T4?hmYc0LaoO zD(dwB*#VNZ0txjxEFa#$(mD4dvh|U?8yO0LNO28X#E+60ytcPUxp6nfipFw|88EJm z7N`eMc%I*pOIcTL{0(Fs$g-iPBe}#YMkrppyVk&-pu^|>5EMjLUIgg|G*^Ed!D9sU zdH&JS_>hkXm^3heTZ2`e*S}#Hv;?_AwM6%N7==(6fYN)DV;vpnWW07rh|6O5lW2T$ zl3;R96>b>%fzWk|jE9>7+943e)72#dcmMpL7sf3H5m}?rZNm6_*HD(61TaV;Y=n32 z40yglj><<%IMaX28R^Cg9SeYMKxsUS3F%|(d|>VzUbD`K7ktz?O4suqAMGTygqoeP zdJH;%7GSnzYg6!LNC3?+h9=Z!9P#^oKXbugrhY}R()GoP&hTg_OK)pM&t3Zv%mhLoOjEmZ{u^3qJL7+a67j)ls~umG4()dKpn$mj}T(kn) z`o^7aj{c18Ls=@jo8R%_nA@gC(I`Vy9gAlpy|!5@4}YDI^&Ea+HIx6Y*~C}*%Y8-( zy>Yv}z$pP<0`gm`Xx0%n3E@ef^FW=j985Ug8)pUs4Hyp}9I-D5012uzzoAJ2`7J~O z2Ni}!=@IiVeugyrfE#T%)%n~(4(YY|>t^fl_Zi=B=RS*L64?_rZ14Dek-ge!{(f-{S>obm4kV+K!(hO|? zl3P!5ht+{>4lesAt0RNbBv`PLNH~Q?cTfDxjrMpN^o0L;DwQ} zynR;N;yXzKI*RRTFExA;6%`ev2wGyZcvghu>H`8KN|)RYMpQ7bCGa_JFHc!DtpJCm zHgf0Qy*5Cl6E(K9hlhthQ-okX#Wdr$*+hdY*In97w-nT7kfnw=w$CW3sG_h-GdqQ@ z&eQA`M@A#5rR*FoLAqUBUjDRP89^lxDdg#aWZQ3(^T%xx@i}bHgPKapYxe@v1pUU1 zrM0ze-_WR1xGYQ>)m~r{SovYJd6`gL%t9j_=M@|rJWBS4lLVWPNdw6&OD8@J1(yFV zDd|s0Y6#=ed}3|4z32YxL5@4K0w4r;gPS0F)zP%2rG?vR_rVPua{bA26W~f&-!>zX z0>tO4Jlv<uV^j|V1g zH2+QOhdWf|ybh4v#UwgsM2~pv`}jRC>qqCPETH1N$y&mE=!=_@*LPIK`*3z)=ZgE= z>U)&QhHrP6o3CDa_lb&@n_XA`nl5m=LE}?%J6RFc<|ONzjs4Rz0o{xB#!q?ul;33? z+ATId@`YP?+Z)N&nQ~T+6^Lpyl+w#1cG`mzF$Fyj1{3Q~BuzBgz1)4iVG4$Sz{m`1 zpfatnWLrW(!Sp1znlrsZKbe`5;903r+qlrv{knU;%7q}|BzvEeqZD)&;D?S!eyDuH z&kuE5=bHnWAq|FpZNXN`T1g^lC{2PAJ?RGwIqthEphSBVQ5bUq1vFzkW0~;hB>weA zbeQ)fa)QXyk|faGM|eD@Ym&=r&NB=honOlFMOo<#oK!*BXSGYS>zvz(cB4V}Y;>=D zgXONf&z0fWu(9s$kre-rH>FExP0F=#9XD@DPaUjZbV|p?JRD+MN%*4_>)gFsq~%iP zVXs}_;|boDHup3A_2D!B$c+2xwN08MMR;!8_VmBG^7QmLVT?bt+kvdyqKot`t%uyiKY_XYX5_cxAYzbNFuCpHZ_o2^OW#-$)5`##WG>nf_DKI3{N9vFGp zy=u9E{#ZxCf|RE`?gwGjKt(58NQgqp_k!-T@V&&BLLH(a=X zu==}77Z`2H)qpPb6cDD?IeZd=YKm6+yh6Si~H`beS1^TOYMs* zf&t<5KmRa2myp;8=8hdafe0)DhOXh9Cszdu>Z7Bhl8&8aM)vzhEVQ(=S`984ZXR2c zoJk>PB}iYy!-o&SsSv}Yneh94{BZq!UR!JHt`5mT!^O71m;UT1T8(ZmL6>ko`C~w! z65X(fYH@mc%8OG}&+K`5Zns6k^}DR8NeB>_W8@j9)vQL|ZnSus4yZYH>%%WGjYx=y z`m1g9JT6a+K&{|${_`l7NprFPi)eLiEt}Ks+aSU#t3L*Ea&qfqMd880hex(3;9dM( zUS^;GlC<%7@fX=nQ2ZF42h&)-jZiWjD@-y!nj0Ti1vFLQ%N`mM0>U&0P|+*rC;R88 z8%5nm=Yttif7eHDdVTx|(;jA-{4p{zGVvTHc+f1Z!lM}8l#20e15UDA>wjNmHAf@= z-T_7c-#0V}0JKwTi8rlC01&nZ%~!F-)KhROwL+@m_Ppem2qRrMn)5X3`uOnP69uuH zH2aNF=@dat;-i!O;hn6Z4zO`#D;JP}QC6`f-g*C52D~v)Hp{H$1d&gZAr;H*cFY1U zmAA`X5%4*m=+(QOL<;+$4`j;RKR-XWQ&3R=w^M=d#p?v82Y>+KEuwtbKsYbIm`n(C z3qsm70h%F#37KhVXb${u?j`x7fKs|PE3kJll#+`_E%~Zc|NADBD8$B#M*%#WGtuV( z$%hyDf@*mE_fjhQ`w_hAEQZmty^L0ch{Igs>lR;S*y@50yPAO3lm`!LKyt5SoI}}^_2G7Myy=Ur z?hG=9RKc?>;jc^Jz1)RHE3wzs>$Z$+mg|zP+_;5H9nD;wX4|1|TRc;Mj zYJxXpY>a5S98CDy-k7R&@jkH9>dKZOoIII|j*h?G=Gu9R^;&bi*hV;oW-l1RUSAOV z`X1XJexfhZo{=iPY!hnQ|Ffc5(1;_G5T2*j8hRIa; zn@IHUNxe6@t0>uuD^fwR+56f_ohmfM{sO;if?^x1OvWD_aE)GEP|%)|ceIJY2G^t_ z-mg7Tds|9j&MZlJo!8TWD$iph*G^2PcZ9x9m80lkM8ucu5f{7Pm5)ad8ubt=OrNJd zJ$~$TxtUqsAgei%1i_K#TJDjAg}G;RGU$L=`-GO3WtTWlg&X&N-WU72oO@5y1llj6 zZdT0I*mIBA{!V!Ro|USDG~Fe%TBzDD;6{nD7OLgU3lADmuk37Vhpo7uqdjRR6NY%v zx#eT)ZlMWb%`K%~e`-1}YhG&IINVNnpPY!KUAZ3m8lkmV>{) z|E>E^LjrIp-W~7iTpl%D?XARWD}cp&b92)ea3oU2Zg2NHJK8BT>Lbrp39l1^KnwaJ z8t`Yvan9tz9@?-!@IlcyJ3Ma@?am3f8})vE`HsRu@ER)W$$DP-j9wfG2vy|#P9N86 zmVC-@46e}xjdbq&; z*$IDbtgYvPDMD}<_j@IBS+M~nwYjyGqt(C*zMy%?%Zk~rfVi}>g2wNe3vB8)kRe3~ zmVxYis5lYB)EeEKH8eGy|14v|9!a;zct62AmoGDvL0+%vYNY4G z2o!ydTDw4S0SuKH$r<2zfpDT{Wz{#7l{0tsiF|K{eFVsmYMHRKw6xNCxMk8gt9p_2 zDoiV`@4$Bq#;W9X);yIWfRS8?TNHw%R8(n-VaImM-O<57hh?6*kY0WH5!M048O`fG z3Wv$(bBU*YJ)fxUh6-grgm<~`+~sCAky0H`)IUPTZJAL=&)2jpBQKfDchboo*FS8q zaGIEVw6x4VnzCnnyhgph+GdZz!NStf-0W*oW*I?c)cEMANTGsii6&V;YKmpsHKlof z+zJ|*IP}l}`H4c*7-hfyA@&E&SD0E=w{1=q9SXH)L?{0A{2rU*oUlQWjInIa-s@DY zDkWsro~4G=wT?gId_2$4qaG$_oe%ZFY4a++ENf|&EBRiYyUG^qI*={RjXNzR-|M{q%r|0*-U$4iv=N_N&9_L)= zI@dWLA{?99sn+NG>z#nm*2~&r)OwjTlF3WVs6G|n)|~ILmY!aee0@fD$ue-E@j>;I z1)OJXg@cPXVw4#Ak}q;wJrq4#vW~5gp-jT85%x-nLyzuCyM~m_Skea0?QAO zVY!TwynR!-;(~v)|2z4|6*vX!0BFW+yFFcWO!$z@LhBHL(}{tvV@R*RqWYTY}!_1T)b@@1MeO>=Tyue8C?D^B(uLm|}F9E2W0 zLHygM&DS0`Z|iR6=`7!itE3zFe*S{&MzwPcb!up$Wp|K^LN`|Q-jqVt`bh%kdRVP7 z0w25q$SNc%KHOQim-*!wOj4vC=(c}Y>nKU#;%Y{Gp8PZB4%_U=kQWi%k5|6(teILa!FayQkTvi|=cE?WA|-FSpZ1M_S1! z?F}xE3ciA;&nWJd2|KzdIL0bwt$+BU9lmVvsV$Qn;Cb?g8%))*$8oC^wbIts{jYIz z>ovDhJa}+5=3Lic`9;^AJcET)h1NKuyRTJ=(-kW2zuSNAsb#t3N3nZgMZ^6m{(KGt zCUxJBq(&CC>+Q)uSBCFTKi+D9rT*e3m*=x*c%!GjiLDS74OA@P-g>@op@s2=zyogJ zZQY%$$7XTSZ{IRfiI&&qP~h@Sl|_w>^@Edr+1Msw#S`#_2i1kb;62ma z>aT<{55v=SxwxYYX#SFF@G{N|m$3#NwVO2!F1v-A?La#PXEWgmgI(c|m@@ z;;o{AAK(kbG`<3Hmu+R20$#DL|bT8g>+fx? z>>W6N!&!lpnF08D7KUEOHlgIm&w_obC>MN$jS8wx7XL#!&Yl{xdN7B2EY|=EDm^ zBQZ8VAC=1f0>Tf7BQWq&q*wyzm#FsmU=a3@LHIT$G}-8{1K7X_e_SO`D;D&ao^Ja) zT{Z6RRHANv5fM?h~ zvntVZq@<}Yx-c!BpHC6A>@{~N$aP%4dGeYBvCM6Uv%u4tU%Mf>6|d%6Rk|Z+cMwTl zv*H)-hU@xfjzrcnI)k-iT^5@)ZaZ3AG5nDaN9Hz|okJCfejg~^-W zzJ2og^`MIv-(KY(*=1HWYYC;!UETZ$)nXsQDIXsC>~2VYZ&x}7CX0sV`HJ&CO4wCA zs_3HBsw#1?t6!y*TnDOXr{-XIr+IQ_)Wi?%mGMgNxy}SN?@FLGt$4vBZQ#XH^9Xhr5^j4oA*2smDGO zF9BGi6E%9WHMS}I(AE8P;J&E!-dh5WxY0-B9qV2Fytk8HUAdv^=~{oqW~rEQ;QFak z#3JW=jD`LD4=YYo9$s?U+>O8F>PlNZ&l%zE?_&)i5%lEx2wrEP%9{D?1si{NLivmy zl9C)5O6R-4DoJF`M5yP)PxmuT+Pj%CtL$i{^(^DmuOGPPToQ6&I8Jc?@!}`qJ?kE_ zz?4=v1|K9$F_BLD&y^u zQ_Lh-^#&9^74`h)XxiZYbNTBr%p+~^u-s~9(^OL-O*G% zKE~~DqHiWsgXP|tK4$EaXIcL5e=)$Gp@Ka{!c3qZ}6(P`{l?V32i`q-ASqMKm0q2o-H3E)x? zbA&%g=ChtY6&Dxxb!dp8EDr<+ zAVb5Qs2+ucMSHWN7c!f{boL6bJ7hmh@N7TcsIsBX%QJtQIH{ymq;8O@x*!ca#%7h= z*|R@GOUzxa@f3XmxO?YyZ>@m+3U{E1uC8qNc^#v{C#(l(Ro>?@X{sPkCO z1J>mi110(|lPs!cP1)$DKOM)tz#O`4x6q&5O%C(A<8}%6=~ZUt7*4(DWampBdF8EB zS?t!`t}bQxY-HS~xGI@;%6(z5JMyQZfGfYaJk;c{It}^Gk8h*YApjEb9qOa8k0Z(m z(5&f_pXViyS{hUgroF3GZu9W=OfG@L+D{=4K&D&M{MWmJ9!xRcs&+|X(tpTulUEk3 zFaUh7$VeXj>9Xs*9sZGJw%>fz*mJObe`+)Il&|Cd1RnunDskYJo_lKR=!X-4*(Kpn zU{FY_%I?f>yQ*Fs8JaQkzL51EoNGI?MF=2QU3XIi9^T6RTYB3Bp=mY)jjyWH*wke{ z)pp`oTbs1DtzO+CtE@3kqNg?N(Y;-6!m5A~>CT1T0U{fOxH_X2*Pda?Au-sqXB{W; z-27j?qT{!kh7EY)fjVh(rz3c`&gvxMr!_Gj>vs(x5R(zBC2qC;o~W^X{`;4QoDGxF zH>kzCr*$}$#jUK=E;J9C6KSYO=#7vTTWm5srD-hFl}j7fd*wQj|Yv`@vl!qt>TqQgZkAu&@yQHrPKz=bZs~(EVVW;m2T6OHcW05~f>FHv%Tf$#=I1=w+patv67{EU(t? z`^K~q%BHN==T+d^9Cy}?-Zd#0Pt->OZLAM^ojH7i>MU`e(+G4sMb7;aNN@>%@;iWI zp^{c=|4|~>`Sa)ZK!B!ho1UeV7VwJ?G>VTv+`#0`HK~%L9>(^t7&W%A5IyZN9V=)b zI#unun>zP(Q%zlcVr;AyR6!`rz7qgu9q-eW2o;Nh!m}^(d|Yv$oB$#_1vEmCvGf22 zrNDAh!f9ZTWx@s>P4~dR>@gee=(dab(00h z58hS+i08t=8nqV7NDYO)fM(2(P%{pcAlbV{n>2XYcNRoV)vu1I5T z8yPEC^<3V$bua;I>x9=i`^*|UvgH#V-N7fxew#4^(W44IZYK{mHgR*fdG4y^ktzLW z?R_>KF1Jmx7)NU4a79H$U0hxH?UybA?RJHg)ejO5$Y{f7pc_n-@NeC&_yKvtuLTBY zprgYCkZ9ay-`*mGl#WiwgeBCAz-XcI%$0LBBKfVSuYSENC&!^=eDDV9Opk-e3We0S zR3G?Q4n1*^5qo}G1B8Tlx03Db>=3U8Zs3XT+USc7P?KNcw|a57zwC}sU!eB@j_niZ zVP>H@L~7sC#KbKK5Kf*sBWL9d`V1quh19;ER~$DMBlBar-sq@T?v?_lCK-htb@sw- za3X2#<+X&D_}+j#B>!>!i8xXBc3@UPx#BI`cz#f=(C{3cRI1RNix2_9Yn&#d-HT4V zdt{@oTx=8KZ_f6=5=e^THhPD{y*eYOE$#!m?<@%k&L=Mk=k@up@$!kO_E-uCj36z2 zPg?p^2!mWItSB-!;a@8&NpHh*%SiO)f_Pz4@5RALTp8`GvDasiqG zB!c1@c^AqkpjnM3I*d8&Q9Ss*@wquXG1xSW4~tFhLYa|?3rapS8GHJ-{Xn_b+y!e& zRJ7B5NSpjW76raQV+$#t6gV~G6J$Ktj#$Dmc?Mktne%WDfdY=pKOe*E|m zrEdG+^~~gCeW~T-&y5Yp1*+fG)@;ts&c4WPcoqrL$^)SEg$7aVPaG?OF~B^wC0jKs zy?!u*lq@4X8c=?Ies6irsX)kgH%FC0Kub<85O%QT#-bX~rcE3*d$*L8NuU}k#bx_f zB>AO``*~D{d#h()LZ?A`j{e#_I2Z-6iqi;_EG@X{!+7;7&P#%*szaAn>1FSm-9v=- zTR+D`S?QNQrW=1?ZjygUvRq8^0R z-O=fQbbtV`^Xc>FmmJkwG;K}0J3GIcsNGSP9g{#a>!-&h_hj7<1S^#f0|f;uh}r;> z>r&p0HrCckT7kQOgi>{Cwx=lqF7Y4xWIG-s>}=<4yiMXqDHslG=3STJ16YRu67h^pEEQ)r_a!EiL=G#wQC~s`bI_>wuG=6>)P66(zGLPK&4|uu7^IDP(;%OyY_8l z z|Gt!dMT<=96_JyPiCEt%79_ozpB7Y*{2xeg<*w}oB4IRp;aEojPl0@jH zdYEAo*8?QQP-dkE`!j!$R=e5-+%u!*Co< zc=n-AoH$`5QVl2k-Vv`ILB|AQ;563dp%Mcys#u&h92C-off zL_XSuLDB=Z_Z-y%^zA{=%1eUE)FP>zj0`3iZR{~n_&7K? zBv*vXc|leTs;Q4bF>NRqI+h{exKdv@q&TM@4ft)yE32`me3?6N9aTUS3Gsr6^`ybq$aM)o3u0RL_V)`G>zkSwG@tdu z&4VZiCH9Jl4unLeQB9vsm+c-xcL+W($EdxvZaK6C6WiMQx}}|+YIzB?Q+UW=>)R6< z8HsiF(xq&h?pAz&eX`2p>X5|}iA*JZ;hJoE)qzh(N<~A!f=(T}I>;K*9=2ksRTqU^lx9mqkQVQ@@z++FKDL zW9gz_cMF^U{W1dtBYtsOg9c&9S3fmf;f!>q!B}=Y|2y39fC8}hpE)JCh0)=Y{LRkotW5?C+ zG=nrHoppD6TOmR087u!Xg#Dp<6co|i)bVP=Tv(v1^??>rNnKD88)7tbj+%puiwkyq zGaMdCMb31@KKX}&kJre_ih}2(QEqTsDi!sBSW{MiB2Ik21xo;2VCc&h_~q@XAqGR2&RotL5Q16aJq z;o(?dv-NfySHFJ|j}vk%961E_{)yVUy61{1XgyW6foZTmtm=g)J%D5B1|Mmf%V_kQ z`aXO9{0R?eZUgB3W{#?X;Wy|7!uT;2b{JZWi-3efOGB+19BTM+kWN?Pd7x9!O1$43 z!o$M_a%V-synJts45_UZgY+=h521<4O~^O@g8x~8Xb4iF4d4$ELM4z&nC8Zf^DhZ_ z;vh*5xo3L5V%V^Je0^!>fhs>!#Frj^QEGwZ z0V!;SLc_*ot%8!0`{CxJ)v@C%x95Rf3Y`K+>I3#%Z-?L0(=#lLAGX< z9^yV7sAK~$>IJoCY1_6kIjTDP`V#W;XH!#C1s0k!{L|CZZ755ix}5SpkpWmDY8f#u zP#AzpQ)vcE1~dT>;(dg5i5xV)8ptgxVI*ezgv-)`9c9e(KyM^jbb?kPo6&)8Wu!YR zLQVTMGM@Q?c^yyt^5&%c2dmN*vhLbNAinvf^af|-;pWhw{!>b19{!H}Fy5hk_{Ps< zeUpw8U@_=G^aRDlP%t04$j%UCFHVWX&5h{%Mz9o^;lxGFWjm}&D7A#u{TMPfWK{j_ z?EwTA*b~yynjre%6rvJ4*xL@9iuh7>o!urAR&4VxxT6rd8K{DMLA2zwxo3n_&uE5+ zdH^1UOwDB}Z1aik$4{O-kB!xQj^g$JJsYqBP_sn|AxK?)J(Lh2YB)$v`8^#fhA#%E zTElz?f_d>h&z5PEx-VblwjTu`@t9?eHT2`5t=FM~FGD$fb9 z9>Pkm2d5o&?LF|I@a0G=_M_3z{QL`S1S&;}jYYS2Z)rl2?}*~AZY{Ii)cw?_ywA)zMF z-A*eaT4pu%4n_?M+s{M(3bA+K-Cz0oJ{hfcU0WKCh7Ff$Bn^wLvZ`w3R}JxrioaTb zUo_XQot0`iQ$pMcMY5snUCsA%C3-BGAU5VuA5CYXyv=Id4<8Z~^;~6;_4wJz z^-}*6UER20J!If%2!u*;uV0rmXVGRiF**0oigg*BsAwd+cv07y4sZWg3kUkbXRv_4 zJO+RXwubIw@zC-~&mjgz9Fd)%fJ|uySimJTy*uBNk;IDdxIpvhJ4i$Ht~W3^C{RC% z_rqm>y&noIUc=}kV+1CT>xTw7pVG22EX!x#A&yTqi2-?{p88uGV4It*oEC^_ctB#< z@a4-ZdYP!sa$6H%jRv5}3CNj~p=?V%P^rqv7Et*sV9lW)kj>)P>%>{@Z?|N>LUff1 z7*v346)Ek)V1mKiLw}RETn49icC22z@7by%V?bT~^W@ta#_bmeV~%B$qZ1`aFGpP8_dvS|2SgxrxU>&&B;BBV>G3!ks2s z2~=KnxFiG6*Fk&YlZ$7-}E@`22TqiO`V~YLv&U z6-xk%-aP2^-@X0GCr=kIUHP0uz_YJkdp7&~1EWu7tMeF+kVNr3`&QO%zr-L{J8916 zg2S%mOQ3J8ve0qHnlIeeKbNhj_eHDsz| zVq$=4IDv%!gyh_xI~@R;-w%g2P@L*FfJ*G_*>h2T#wkT6-JwBq}>zym749%xCvZ;hC4^ zxnALeyswEOb)mUsvlS=+3qAxNN=I?OsyRHMcu5chvNe`y7NX^O=)jffZa}0_>0s&I z^mfI!TfQfAYm1NhS;6O`}N08D-8#HxvK{Fa47jbGE8jeGUu-E`z;xNZhE4Mmw1hCn4iKQ{Ro*}bc4GA^*wUv?Hd0Qm7T02gql=1;#vA!V zvwG=3aBf{cwKMl=UmwlisetgDJ*nE0DWuyiMgrTQ{rO})$(Q8{bJ0*%>`D6C zwueTd5$c32?w+SHvy4NrBCasa(9;Z4{B)xli;RMzWo@oI5?C!H4$gj9a@yK@)ig)y zDzKycDM|xC5P`&8x4cOJgysygF(^c~hy=_6Akt69a=L@DC4)P07GQBLZ!> z`2d8pYIYR0L8$h+7kFadR`c8s51^|5mce9441Wmpfx&viYp#{@@R5@%)WV<;A{@}y zDr5y=-2?BU-yVba>G()EhjzfTXE)26AZ}3#?pzCaXJWWLg;0l z011Ya+kkCR%v8=ewSPoiz6^}U;l5M6{Y&a|P^+`Q`(e)TqSs&3@?z`#a3$UuYWk`l zS$VbJSm&Pp=aaLyK1FllHTp>(u2ffBOrd`b$;J6DBt%j%lk#yK_sN|TJg}Y`AO8qV zh>qnIV{DvRu+lvbroraNpbDN87OO_-8_3z}K9r$xgqnEZ zn~351;eNY&y`V!_Fpxcr@p3VI3K4Yl*Yui6G&D3`%Dih>2By+zAb-kW$n^)X6KOzJ zqQLyW0J?2HS#aw4ae~m90(8m~7%V)26RAzm8MzIt)=^tg*ikbeJT;Yb1cIf7C^Ca-i%JR?AUP7Leky4^(tpsP#)fWF5j9x|7s(b#P;%fdF=Q zJ|;42k0wHGfe{)gx6R5ogG+LOP80*GA@|fkc@%0f1lAMm&h02qDag%Cf#VX>;G1jV zsOfQxJ$s>X7ZDeKn}IK7gJ@T&{Vlk*7-#rKwoGae9UbOG!-Ws8a7HIE}oeo^XS z>eAoq2X$fWz+er3>2>2P=S(1x=Q$~BO3GEi9x3>@#&H z$itKc8EPO%y7@p2u~+eDkg4J^#<@rV4rEs0jpXgWHtS_z|47x(c@@miVBzyjJGF;_ ze*+f)Jq{Vl?+r!PmLj3bqREKzM#me^14hAqc&Xr;?hVyIN*@_uR5ibz&w^I}oy9_OW8v=*}Iyoe6EC7!VT~wh6 z5ErRh0n1eg;%7kctKblru5baPc>ruLY|+$^L70f!kcvP-x2$*CHEu@LvP~7h6ad}; z(jf+p*8M@}ZmgX-$sAIoRJ}8wWrO<```9s{Rdpfl*jx^swv+&;*z|vg!2qK58Pr>Y z1BBS57UA|L8yXuSX?+g9atmSs;7Lv-IIK*d-w5&mc2E^y*_;b0M_=+k4ZTZxyf1K(>$G$*p5;+a z;K;qz+pN-G5{z2AAuRlslV7UkpAaA(6^5_j=4H?^{xfJXNAIWDMP31ClY71}NZ@%H zfCBmQ1M+sLBlkf`4>h0NF0D{ElxO4k8hRlBYy!)TbXkJB#(Th`rK@C}-`SBI9hruT z0f;5uin@z{EmG=>;LxT5B!G}`OL;S{5R^_p>IQOOuQbZ6=mw#8!bg}yXrw0y_fLQI z>g@sj$B#e43Y+~_R?t4bO+qQ+@)jZVx+XVz1-Vd5LnUV*A&HO_>V=H3T2$-o%OU1@ z0qPJa;e<5w8y=HBi-}Ko00;rL3O6p>(sUYfBbh^(KI=IQ9qJSzp<0Oh2Vn-frWqi^!q@?Pxb_y*Lq9UkIS|nf!vU8gj6IZ_mDw(+KK}s(f>i(J3Zx?zM{7hs7TutO zRIEZcK-|EL45Q4ZPud12PG5Ta-IjVnV4%FT)B;#nz(&M4`2hM~1Gn4Q*a)q9{bACK zRTh9-v9Psm%b$d@D`;2x7!V*FHXfqRE~q7dYmHd6rX7I@3#k;T+25c5u1BR0BvG0S zSksVcQAF?{A%z5Z8JIME_&Ed)uYt@{0+LBb})vgAb&s?N|py+2U5zU z!opQo12;D}XG%uhCSf{2whGK%vguHf$pzfgm+rlHhZ-{@m^Fa#ojWFLzY`}=V8;1z zXLi<5Z=knV1*tm*LQ^1&EHmfn|55_i6Zo$TQ}80AP%QiC`97fcn}~A+_9e;~>8c4MDaUQ}u_E>^s82sZdf*x-Cp?TJ z0Khu^a6cFnYh^GEdCLnQslWXNRTYpF zf$*_4!8eS_@b(P?eDCJo%Vl^D=+GB8JuinHF8@dCF@X)y0_#KkFEV4o4wv`xubG%Y z*uOHjZFe4yn>`17)lC2Z zU){m|0`QT~`srT`IXK9CT>u+^S0xN9b#6~Ru4WchmQVxKG?fE*$Lwd5+LLh^xV`hd# zf{0!XbZ@WfUI0ro0m~{07zVOj14!>7jsHBL>0l?YS~x>cTMcnB0#m^h+{QDYO9A4% z&~zXe%ntzSi1EST0@qzTh^L8cI$A*j17;){+{)XiC}`S$6Y`Eg$wN-m6H?*yWKWu7 z1$hx13q_D$yeET+Nl0EmhY3h_k{v`9UUynEJkKt@b4DGBvSCwTjALM($^%i!9T(7)Y$a2H<%hYAY?Od4KP5JW+;bt9HfSxKo%`1=o}mvLSUF5Y(%be zS?mnhp;{36h2mYbnS$9w!gb(m=pLAxndNGPK+tsk+O;w0%mI#rsbezPjT)9O2^cou z6RtNjjY5Tf$o>FB6KIK$bxhq4MPt*ju#E(K&?ys$0FYgS@1qkUe7HG~jR+Khhz)rZ z`}#Ej$aiGA`J9}bD&6+g7rtBo(u)alB~k5ImLa!5_`%oK)L_z?fQ4)+OKRBvh{|Tk zTGtDnwh#+-qFC=i4WCls>U8JM9e@AEsMk-5G(!- z;I_VQZ+X0y`ZeC_vi+#BFgxdnPyZ87tN)tzDq=}|itE6U6fp+}qFxZGw19dQZ0I6c z3kl!+3X&WZxE^SQX8{>aHz*B;{4v6+p6z%20r6W#Kv$uWQuX1%?x|tZ_)B5vJJ4X| zYl%5EJWBw&1pC6SqpPTav?FNQAA$1&1>-_xoLo?1;uSdjG+;t?YS@8t0EoGAQi1cd z0Id|#-x3@H90Gc_Lap4mZlDnq{=+Ft=-2EyRyk5|DmK=Z9?LzNzq%7fmD z{!B`#NEc!h*fdXY<5W~sU#LLg_#!EZmP^0&bH1!5B*h^k(*?k-3mKLm! za}c8gefl|s;S5kw$>5jO6yf?~q3%IPp`r@%nhqqyqg5Ifz$% z?hu18RZHj<0aXB11HtJ9dT6A7CcW0VK0Hkb z3cTY@BR<1DFkPALc=hZV7HE{zHF-JFVEaL!pu6J;@a$z_^RLrU2M3*5+L)oWwMUx) z+1U~<_fDL8Ci*RSRI8kO%^GL&%uhnI|3p%?^*-7$r-wzyoO34yYxPv@KiC7Gpaf~iQ~u|mxeIvIZBge<%2DOA zCd<8Oo31Lx!o{ixX$9Rc67nRLEaH}lrB&?ex>C{{7LQxf={TfTD#$Xkd|&ocw@ta%LtC7GWlE z4CMS)x?U&Nlk3dvK-W{G-})9woT}M==Op(xhVpliX(eM}pD=`pw`pa?z8hZxPm-~- z|H_;P@tYCEcj~1Ui6BZgSJ6>c4)s1moeL>gLs)w388f#asf9@j6v+g*q$WV>?c-wt z+sSD<(%`!!?+Y4f`VeGuw#5qG2mYfUcsgGj$5SUy%7fUD2NJ`>Zo5BZ&*+Eu-7Mhb zij)RPL1gvrk|0D6xnCbC!}B)a>`4$I&-t?Cb^<*RW7k$bFJjQKAdN=*LW4`RP%3=- zi)mbm()VG~yXn|?lN-^mg{pz$M$QR1tp~D8B-GUA*03qodm%a?ym(CvVqFDgW#v~h z*5S|@7b+kx(_!J4Px!LHei8*c-H|vp>IjYd(6X|{3lAV! z4Rk<9?#~%7NbYB~wmxxt?{qGyD;*a3fXh?f=r&-7k{_0*J3Bg(&doBB+ErGSb{ks? z2?;6ZX$kvO%ui2EG11dE>X&FeY`6c&o(GCYWZ=|4Jn>3Na<;H|zf^PRR<(waO40HR zdsZN5i1yli2~j1!JC*l~7mTc|*|$2d_=qXFEi)24Qz?!`8MNQ?f4%*NM6RRGT!3AM zEK)H~1XI1=K&_M&ZZo5)$UoY09EH4Oi}n2rEuJZ3Iv&Qkmj5KwN1Tr2}uWcz%?B zJd@pw)%Kc>j*dx0L@OgBBN!hW4Ke{mdHFZdES_A+X=yB1uH3}K!-KVokB_eiJ>Q#2 z?6Obl7pMVx^!4{wk(CXA#5&R)4^mzg72Fy$ib_hP)YKdh*7U+cLc3nObq9wV>#Kwq zaRmOcC`BH3hjjGbe)6_;N;P(Jfx%O1VhR@5pVUTUmov;q=iQ$jLxxFyfQ}x$>K3}O z#I{{}Jt<`--d08i`2d9~<=)!57w^ivUZ%d2;<3z;h5?Yds6d6+5M{HI5>=#FN*;Xvax5n zL3Zi{_?(tGO*1U#ich;F7xSqig(+TT(NW7)4GOQ}UXag7e=Hu44F$;a?EyTby8P#6h{!?buuAC# zEE#11%0a1?@O!j*9E)$&V!l2w+OfxAw3DeKq%;MjuDDzzJ~}vQqiJ{mWyp=E!NpI* ztgNNtxm?n@_bI*%RZJ{kAAO@XWv(|O<@oDlE(2!${iWe#XL{wAYtA1tf zZ)xGN#YV};>gh=_ynDL5x)DUqYiGodLM1%c(~}%fQ`B%7_qlq9I^;A}Fs6G^Tj!f5 z=I&vTkRvYs(S@N%8Lx>sO~qq`H~HP4dfs%Jk@;e1bMWWVAR0nahF2v4SG@Ct-6LC< z*OZ8XUajgi5>adK*Xm<1fxOWv-Dw0hM~Cy+?Mc5 zDK@oTD(4-3@b%`=sAX~%3}iFJIoyH;5S$FQwzP}}g~~i5GDH}r{>WpkEdmo7nDSoU z{{HVFM0Y1u6q=EaOaH#^((o?Es!hAcO;QFc>uigyc*xr-!vq|a2~gsv77SrPB8+I+ z?}HwTN+)U@VfyindD!;uIK}+YF%qm^y=2_;ND*}l87#E3hi9rIuTqlrS$6;OKF0-_ zxT`#dW0mX3yS2SYJ4(C72UQ0<3&B@CKPCXuffZfb7KVkAcXcSQK-FsTn4pzJgW?>d zofasK`b?QPI)+t_mY9W6meO6PwZ}$vd|x^`hI^4C!qh8n)>&iZ2G# zy}W|?=xW$0MMN;Y`^iIQVG^ezDyxPy&mFywl25l~F>0NyJ9EGu_~ndL;+6IcJd}lz z(|ktS8a&A7Ld9X(OkB5hhp>Tl{KrR~z&Pgt|8!s35#_5gBE!?9`O?RP@ zUt{*niVWFp z7iiXh(5^2sZFjT%-gT(3p4ASt^^D~9wq7*#d3qVA+AvTANvWA?k(!s6XI4H(k2oAa1dop^pFp8tP}I}!=e;*+dRlTIY`2je8bgzkCY6z~ zltl=8@yQ|9+y{oI%dfN9T>0CIU@ds~PR=nM$GLaq3bF|=jxG8A9wyW-j|uZIw?x#6 z>%cU$EL?ttg=$_7krPpXfUB7#6|8#~aDAFsup}}wP4cQ#L0Qrb@+B$ZzLpj#prVZj z@>8H24;uj83(6-^wJEPX=reOZf3D+zwQ}j;pkaA+J#1&wT9fV18DVrJRKUpjKwqnG@CsZhe)41>(YnfZc0@BRLy zG*oEgr4E)1HTB%HUFKY9oOkr<4Fr+PpMU@Uk9=2d<*oTH&B6Cw)syB_w0G{PnEr7( zVz$BY96!FP>>acSNS^Rqn770|_P;;QOp!eEmAW%#O{}5s&*_zUGmJ2#Rj)_m& zvGto`f7bAyH;Qgddrxc*+axXgHcjA}tIl@f{5j##f8=xgFFvl2(hq4=oN3X}h6mjv zuOn~q`=7u6dKj}Y%9C@Z&u+~w(0P7b|If`*{okA2kQkM>F>UqF&HHU&VXOUrm&I%P zk_4WiZr5^Nv7&hCKiA)T_y1o1%nXAj*WU8ea)Uo3%E%#iKmHn*Qq;ER4_ApK?j`pA zzCY*reW7ERYda^5`WEX%N3S(k75%w~^c@YVPHD*?DwnStB64#7XY!dF6R;E?r1vB| z>&Z;1$U3sEFjT!|LJ3Fq|33q

ndzf{6_*=Do3?#d2A`ZTdEgAp5Xpc-bQSHIxci~PQugiIF3H$+6qvpSfM;+X0xMOD?g)#*LPAHxi6 zQ5?M)N-MT-g$X+}|EwdvpaItXN&Y#{K(uIIiMNd&N5;c5Oz-p?`oV1=FJ%TQDuC)< z+QZKG933%n!kEl3MH`zh)|-oAJEud>bG(V-wU#V{Z>D?yJ8ZIRb)r&d44fP#_jjeL zcF%ir|GD$f_=pI|){OTjieuh+LEpBOrg*+9gp^luwq!Ezci8^E#%q8z{_{#G-r9w}S4bC?w%~MmM~A6(r#oOcbJVp8|fJc_zZXb8RJP zXS1NHqrSfA@BV|2+Vh{JtOd^aj+$S)=XpX38y77hB0>85jOi8zi)$5SP5jIkiuOrKIOv5g( zd&&w-7XB=X%e@)2GH%K{E>R?|tsB>+A|#hxFAE>MG%*2#A=cYyu=?NCGsSI`Z?lp8 z!Z{IO{YemtcsiB3-LKQ~n?qFH{A?cu;ki9ueW;Rlli7!tAG+y88SM$cZ8 zWY^uN%L{#)nWMD`zBzhXw5BU~Q5WmC^cdylAkI{U_Td4*%`kLF`^TXApP%sM zs+m*F0Vd4WZpHtlg+SO_}^M>c96lu(kk4(+!?(w|>e7 zze;!dcek7#e6N6(DyhnQ$lL$d<0mZ6_lCTCXS)3Gz{kYo=&r>7xhsp#%--Ur{k@d% z9F4!o2AZK|7yMYUT}ZAJIy#O=rq>Z4@cZ(|5^UWEsm%M7Ie!sDlVs$TfHoSb+i-C5 zF4Rf;bCSA1pFax@KF6ixGjy($RO;`;N^ojvmsQf&5B{}k-BKj0r4=5+e6(g0oHDiL zeytQ&EkC-xd>nZz`1{;Eag?+o+IVGGTwLS+e}UInx}Wsin$gfMjY&oEc~q~sn_B?1 zR!Z{3Rh@NMlW2$&O#bv@k~3N+TxSovj+9(o`|03m)rx@rbjy%9PI6(irt`>R)A~$# z-g=)q5%aGrF#cu(14hlC@5wu<$8chZNiHfsT&K{OUdq>KH@(3`D|{2GppcIxoSsLO z%+hMtNUdI2fW|WT@x<<~9L5sdDnCAlFR>G#|nLUqbF|QVJ~YIKiFB+X51F zT#D%_eS7|AT%4j)@X-Q;PmtH8bHucfZN-~+ZkNK%s0__1RTMfkkUSmXQ;LkFJA5xh zTXik;thH5zo90exoyiT=!)Jl>zAQ~GLrtU8F~Sw$hTG=LlEGHiTvI=O%&av5)Jc*~ zb#dJuVDrNIw1y+~lU-D_X}+|2pE`2`tIgHft+!e9;NjIbjvoxPzvY(qf~q~rO0_^= z=+QP+%%SrkObxE%V)Kd$^{mt4wkH_}%9EdMS7cG+IhHZB~b( z$h9R<;JtggyO ztf!3s;e!uolxgfE6qs~pl8u^*x0l$lQ5LUQma3}Oh(^vJmg;{t#yz6TJ=n&lB(QUo|_p= z21SoXxCY-JP`F;V^$VbKyv^(9c>jc_LNK?%bUj*9s<3TaQ68h9pbFC$1Dn|~G#!Ix6kGYRW5)A?3x_$`t-2`& zS7*Pkun9OmiLPjY(Bz5n)>kSymg#*lxSe}g2N*x|*Q4+_%5wE@|Fa)~rW=}!i}Si7 zgL+TLw2~|m&#B(kbVJ?0KVwL%WO%)doM&mN)9L2NpmLpW_sjD)g?C(<{dXoe4;h8o zR7(Q)(av^kU5%n?f(6hNEvC_Mtux_@+(Z8yO<|c)cfl?h(lWXI6R|2aHw{|s+}v_S zTsDm<`70a!RmyzgwbM@!?)&t9?I6(V;SjBvPlXsSf~Mn%hzpzGP?0TMxia0z2!=2T zL4aic;xH7dcVJ~!#%Z#MU3FX87Y8!5Sj+mO8(_FHC;lqp3 zk;_qSdzm^|v&oy1634O`C8n1@A1Jr>{rfe_Z-+h=Qa4FqEoG%q;q~{&6We9s3kg?| zk|+-$YxGLu`Zvv6Dd#RJMvSq;Fo3aMbJ#pGbw~dX<$-S@MK&E+O*+eQ zOKSo0SkKNyIUEN5`t{3pzFbW2O&rzo5|R9Iz2v4A(;F2Pr}%0+L|cdHl<^O+#+TR= zF_8CB^(TLZYysqza2v?Y-={$STI6q)((bI)n}kM(JmwK`_*yWJ`7w>pZ!o+=$ur#- z$gKOcHkK1&`%~-tFyOauw0@!(g7|G}0!in|ytFfo1KR zaNean34dqhS$@=gL1+E=3MnyCn+?_u1Uw-x(!hVb2M}Y079$0)$W4M)6p}`PNWSkC zH}vS5;ivR|=Cw;6ERk*Wu|gl(hV>Hg1uQFP7q0z23W|^7AHNFg^y>6?yZsM)o-~u| z^Y)5E8}%BB;#qyzJ;`&V?EDwxyV_$$vSMOv>?58r&u)G2Ut<3=D7ADR|9d^0u!lJ# z@qPU^DSo~@b;7e{es*wDH6oTE{a%F~tCc-o`g8CIHs61$+eiF4#u$;S`j@aTxNQT%#pUe0Xr~GkbSJ5j~SG4@OEepKM z{~&3U2Qlm656$RFN&!t4>UdN{AJN&1iK%V5Hgo(~1`n&Od?zLYN-It&U!OCwR6of2 z(XaFOI5#5PHS}}TG1Z#In`EbcW060fp$zUx@+VbQL=1lGPyO-e!hNOm$CFC}HWn!l z+X+Ma%L;H|PPkwJsrU_;_HB+1XRWO{*hl*hQh5Ht`)Ft-gDlg%na-t$Rlta@M6(oNS5OFpF z_uqAzZnm*_&@k;FZ;|}mGf6{3Ch-K};b}w2Dn>ZQ_JkG;es~IKNCR?NA!r%?q*lMH z+dE#2e8~ZI^%R+Et0VJ0+fK)EBto}^AQb?WQqA`Q?}M|(9PXH_JH;Hsrs*l@cZgnv zw1Dl}PxXc-N)j77ov$ZS zQe#vAOStTdlU}+6t~96Ty#g=UDQ~OZ(D?Y(`-HE;o$zaxSMUkU)6Im<3Y>GYvq@l! zv+U4&&yb>1H zIpdyWAE>~})o05M?s{PB?$5}^rfO{<{H~3{pnPgizd#aqgROrl_BAPSfw)n|OlbId z7P&L#FvyJD+0WFA$PzXva}~fop3aMpjy5X0!IpQ$T{F*hM>xGUVeroM_bI)(*`Re_ z{xVHitic1U+K2L9-hE1w^uj7!?_P0HIlYo?SnL6~6BpSlc5jI=*9c#@s#+d6KqhR+u8f@x-`+lZ}o#X6cwLyI(-Vmc@RLuav19;h<)p}&~xS*Hzd9^ zGpn~4l?{e9Zfm+$#?c0m%#?9VMaLos_hD&kixSZgovm2x4Ihzev*ks@oa^H8FXGQ6 z7#|;S<)w2$XoZlc^jjZR@DDrd{fCnxr`~6g25suTAI~;SwsVvVzWU~zDtCXQFdRuP zM@QdV`u%(H&xNJlvC(d0M5#%aO4R#PMgl+NNQq|MNSm9ZN=uKI)m%U`ndMZEVRb4P zXCjq~Fl93s`{qiWEXP#c%XEG&JW*tCqY>F?Tx9=#qwK5iO=j#(<$Q8qwUK%L9CBeb zHI}9M-+7z4GF>lcW?a?>E_GEcw`f>ze3#PrWbu1pwA5x;51@AF-wDpZCXIw>i-55E z=aPCe^$K+01vw25d(jK&xKjfk$ zD~ac{u2Z{lo7cehL^3!yMDt)frZzMvJ~1}-Kr?V->abPnMzpVs!y6-c327)8@6#_d z1C3_Q-+Hrb&r~V^pdAh{;e~;0-9o|!Czm}>D5EJ>`b^nybDBwnyEPn;8=cxoFnp}$ zX>~U7xQNLlc1VKRw}HV$Yk+xq%9oWRc~>edPG7AK8`@a(*LXW|Kj%|{#vRRejT&`iROJ_{26<}Vc%!u~ zZxGUc{YjPZ*bTyDL%qBr;P#OTM@4l6kLOO+&@Qj)ja6p&N8rw6_U0l zSCm!H@sX>=j8oo0KqDZ=qW1;kTxH#(H5?MuJlo&MvOLYcE0vM}iuUY+(e*o0b)sA^ z%4X+65m`^Vs{BSW31{W(>{4(>Uzt1k@|MGc#|aJ_N9kadZcv7H5r^>|V%#+nQVHbpW9F2{dliL_VxaspR#AOJ3H{vY2mAgmYUkjq4eo{hui0$mCEWSlBz_sSYt{xF3XkJ z5sGPK3E^a?x7~AOH?ARvDEW=#oYRq|0_cd*WO!xO%7nbtVIt+``k%->dE0l6%d4w~ zJ-@t4bcgk_mFrVXE48vGY>6~}%S1;-9mxMP$FaPkt$!KKQ0lzFJzVF&M)2@d@P0el$Cia(V7D8n;+qN)s9p z7Nv5!?jYO-L6MwQyC*LJ< zHxY0(xv-@5#G2>JogC}QH~4ubBS$9t%tmLIA`-rX3m%A}cvauSxo4uwtN81G>}kFL zurlkK83^`ZQ08-{Q&!LGXR9?sV~vjhRwC=_lzVGGUeakw()p-^%6h{*W}66M{ll#i zmXfup@f%pfGEzb%?k8I0s6hQEU05b(Tw%m@|OZ=CY=S){Coy z1c*}I$tK0Jc1DhTg5z-MIbF7VeF!im9o87DgLcmDg!9k5A2>KYy-ACR}RBGP)LnNGaR$!sW0T4G=iHs`dsLnPXo}I-1U_ zr$3O=)j2i3*FMh@&ATd$EPZ6pUlfL)9VDazI+M)N z0hj9cuiv%7sX*`t>1^NAm12x%MaGG|`zB|j>x1(^Lcc4W)aoqsFs3JO5^E$?D7;g< zb95-MV6g60y&>F?p$r5+D1pZL)sCy0&S(8B;aiXE-Z&h!Y=!r2dare#{ke2QBCPG` zKY0MFODhA$jR$V;sO9nBmQ!d&y=$*DI`c;`Yc^zQNt)BrupFeoupp8G{@d~f8!Mz% zy9I{amlwLolEGA0DfIJ+p95AUMg*y(^dRI1%iBc}xi>G_y>Q%X||=4-a(A_+N(WfE=|@6Z$}N$E{4 zhWZ8iX{$-fy`v)<8*!CQjaq~aspv`BnM*=*aq`RP7K=*75O$VY79C zL0?~nDCR8j7=qXNZ2ps|S80!GoBq_R*~yx+020NFUw&_wS9E`GMmbMZ>lyqYb~idf zHR$`EFf?|__`3|j8uH3%790Xd6Cj;T1df%K*7AES=y0Owx7X8Y!vt6Ra=5+2z;X`9 zDN}}0$HS_$HX~YGUcZiNSStAMUI5US0sF)ZZ)~o`%*fYY3miKfGvTn;%t^mER_Zd6 zQc$?zAHyy!7Of_^Q1i@dbS=lAoEla$Y~DJRStoNZ@q`JJ@!4_&f7Na{HgUdQcW2hw z{P}GiM%;J7RW|hkydwD-9xSkRo~*MZe6kS z15_l;WO)|7=IxqWygsEA9J(~fX!drYCZw?k^1wlpnu1 z5hf0tNe!GKP5t&Qy~^^U+$Vc5J#wPUg|uG5V()qFsgk^o4#mdy`AW8`*L+%!@Vjp# zuCs*Nr{Axo^h>kN?72A{J2&K8;yqmY-S;yL;0bKatAZ<$c4$;D1xS0?{HrH-Uc9_m zpU}=-8Ie7MyCg?`$diC7#5&sDDbhchFq;pBq0H~})MI@{7^4$6zz^6Ysp|_F&}7Ml z0co-9y4eHh&K~0cnsBDMPOvpq_gYFLasQ`RM5dzej86Uyl+N|?*;MuLhs5>C83*<1 zs<0y<(a`aa#&6#O;~mFc``_aks>;|OBymDgIq&-XXKw^v$neGd|LABRek?2o;#M=X z_x$10`5qGkQCGxSFyBO}FFekK;#D+k*Jx>Lk|(;%OmSM3EQzUq*;JInr(O1U^1x@|7k1y7%2xs~x5mi%+N9P4QYen=aqL^C3 zQt#fWdbkgj8mkW5@-GrTk4wzQcN@zlU2y zeVqi5<95#eJ$`ntO0p>CEv&KaF!?7rBZ!Ra*+)s`_55G*Y-#wIwZn6b;t zff6;}$4RG*f9c+y`)lc`*5QVFx?J9Eb`?GIaJth7ydKw{qUn^?xGLvO`7|3B|IFd{ zi8_xOnTmYTB2X(>lFh8z5vR z)p)BQ4S3q`Gs0QP$s>N>yAdM+##x{!`}#Sm4B;~T^P(}UH)hQ8_Th|jE#0)%<&DO} zc4->XEl#}`1lIdo3Dlr4#hmRx3XDLLz6o zyF2P_#JL`ajvJrRFuRs-JO81q?umiE#&7k&(e%5s%B`OMc9Km(;UrkBpll;M4~*HR zbypXxqJPR6$7{^fZH!|WgsXN}u(z=EM5I2wBlfS=^PF)Uv?snFf+Mj$h+QC=()!8@ z#vaWkkIRoovr~DX!mW=ivflD~+hNQ)c{o*NJ8-@BvVf$sM?9n>v|xNzLh92eV(XgC zDx6i3U=VhLMhlOKh1M_2bDMlKG;P*v*$RT;jY0`ZX{}=P^1?u>tY=eioo(lsLvux0 z*h94)aenoWf32e@koLNv33?l(MDAdgNdAEkZ{|ZFPo)&7xGdN2XiG6&fVcMJ_|ZPbuz$Ie zf??lEjc#{=)Oo-&x=Cf$?t!Dc{aCe(T9^7v44o#y>7nEG4x8Sc>0_6i0AFAHD`^ld zXsqL5hhgD;#1Kpssv?Hp1*Z0CFCV{pNJOMFzU_F}^12Z`9zPZ$_P6C^78 zae6{i?~m5X!O?PKV>9>@9Wr#m6BE(8POpA$@0S~}RkTNT$RzI6Jc+xTO+J=_ccr?+ED-rc%o4`jx& z!V`m-vyhLs`;tpRrHSnw+w76|^r&@8>-2EthJW~0+$6sKpywl-?zr8pS90^ekPu_+ zTf`>K1%qn!Y%=tUiZ&)JOLaui6Uu=_+RT1s7%EX@$Usf2KR3+1e*GD9KL~fgDUj4I zI8}^Lcg9|PtlFl&B|9hW z87O+Wz)}>;Msv^JZ;U$q?t6@H6Gy8(0#Zw+P%qbT+GIED>ev9R**PYlM(nR5SCFed zCxH?)sb0fJ{Y^$&@s3G-eGUSx&|oxNxa95Z`nf6!T|5@!W?wn24Ds#0Upw2D z`ouza4Q$iHz=V-Y)i1ns>-n#@IGp}^e1 zsGYHMDkot*D!erP=kHcH22})&6jfB~&VT;5{DY7xw-?+xb zc$`@@Lt<;>#8Gej(s}>SAE`@E)!bI-_G^t!?Q8ZD58+FW0J-w$A#a`katOT*M{9k=4E!;o_Bsz8kSpS67ZFP>Z_kuTELWDbu)Ya~nVJ@UyU3bCX06{BfYrL4GY@J;`8pD-CJs5(0GT?Tw z*qsz(A>(uvwT)q#A?cvNuz_-ZX>hP6QM7A(9?CGRwP74&<7N%dkVJ47p0Wn*Nl0u{$zq6NjnLkQ^_NB zYdC4JRBm#z>=&r?kE&N5W1>#K+!kf2_~$^6HRfP=wH%}wZEs80*vm-JRE972CRrA$ zMv3w#WuZktJD^h}zvFFVom=z$=SP`ytY^8caY3GB7}nkOHjPRR&wc6I`%4YsB}%FJ+q8 z+KY%uZQoYg($gQEEcVBge7drf(*l6H_2JVWKBV+uO(L6KiAzp@^liBp&}SYe8E3LU zj*EEK>Yt=x@yb9-E;~|&?b(+?Sd;jsSkP69bJ)sjEmP?`9h1aII3@$!TA#QKXUvo3 zg3Zh7R<&f5E&4t0&pBW2%pN-ix!N9VA15|F(P3avFEwOpFEU|`*>Z9I+lp<7qee)4 z`Jcrsv$>|$7h7X#b-AK2xJa>VNxicdQ7z6}-}f|*k{Ai|a^{qvzZHJDCm1!_)gdhJ z3n!T)XX&*9?VB;o+bZ_Mudqh%5y*5IaxpOE{CX1RJN&88a?zuv#t^An`S>xY9RyEL z6TRZDfu?};%H!-{;H#IFM@Bh6Q14cE&hq}6FGb3UxdLW6KR}EROW}kaZu>dOfhHx7 zjizlryc7aMkISyyFO7hoChC@js#hKDPuGDjwD&R$F^0$EWiX@%NW$>%<^b(|5XxYd zMv7_GVNY+TOnDBi>V-p)QMUEuPaUNkvFayslW=e3;PJhvk4L9czW90`h=M^;9v)rZSN9mU z9@?W55XXL;C87dZiBNwzGQY0|ZLQ5&UmpPX2B(&=3+C#0@?1xWlC~y@o4ZDvO6ztH z2FD^#JYaulUR1Aod9ajlxM&DX4GdLM$vk#8{yJ?by0}Uxm46E3hAyRl(9n2eW!%QP zQ02_B|C93ut4=k3Y32ztW6))glC7K;sNS;mKXr7J3VsUo5`t*f7Ldy@s07FjC}a;5=KA#IWgXl~ zR^yjZ=q1pb@bN3(_~hTjqLRsd95+mpuHbPetw{ZLu>VF?B$hX_3+d+EmDd{0xQ*yR&FJtAQpp=QSyJ`W!fWwCDM@~=Vzrhe>>y4u>?16^XyiUC7f0L%P8 zhcQ$y&LYF2atB{lcb5FS$vt1Ha;E!#Xknrc8coumEYMjD8uKa8$$hQLa)`$Vo*Rv3 zPd6ebmok?vE$zMo{_VC+o$uDSyC)>`y6^-``n`)2BlAD!uk4Vfhvya0GuBz}6IG8E z4jYtkP81sn2mJscbAo+<2S{#SnU)sz^JmX~{Mz7n%El(`g_TRiNFtj-6i8VVHhi?} zTV*+sqUvSD49z7djetQ}O-^Qt;$T--f-9#|F!Sz}J$fY-iro0-baC#x+vUhUHr4?2 z8#|7Zdn$FdQswL4tTL+Bm#sW}xD>|8aJH5JYoI0z9+8yLeGtD@z7~&F<#$;U57n(z ziNh)b`hh?|F|L&H$VE0|LU~d4Xky6q8;ETl1IFczjb5`+!UCIqkS@bu)5)t`R+B znNeFKPSYenGAZp`mC;#&<0rzLE6w65e~Y2a&HvML2;~Qc)v{fTyO#O>Xj@H58%fBe zN3aUU$MW~bY5qynweK`P;|zAzppZ8h%Tx~fap~wvgF{^%3cGs-e@hEgf4X&h^!a`? zs8S~JZMayZDmqNe4~V3W+8#V4GANCURw~OcA5}TeRw`N7V>!CCePF$EKmr}K-@aK| zp|MUPNEG{+ZA)>*L3O#IZr0Z?Z1tQL_fjq5(0*}!v}BsK@p}*YQG@{Oe-tO0RndkG zme$|>H#iTI>q(2pwV5JUdUgZ^0HzOD&)yJdm53k922z}zLE_&B;%HwHIbsC#OKK*j zEWQo%70a3aPuj0vi}_b<%lapR6eC*(*WR>&3dxVou>FNHnj~01xKU;YF8PY*TiK$;o2(=ox zi#y&166zbm>0{$t(w&VXoVO9ZGtO-+*0ruE2r`YGEC{lzz!z`!P$;h`uPDuzn@C8R zH8fH#9g)OmHy^3Z#CVgQh5czyonO7w6FFTN@N z=-laGeNgnCf<9r4s%J!R!Tj>R5ef?GS8qIufI_ojY@qdCwfwwMIo&=_M>p(l(3gCW zmGz#AC3}dco1FOqLqI_Bop=?)P~h$Pjo@Tvvw0L;S+S(-%-sUMzKMR>B?8H?@Qt{J z{6Qj}w9|`ovD&Av{`;8vz#3XKF7E3Og=;1v{v>z*`||&{{gUGC>|8G_+ePyt1xNuyDZwuaKF<$QDT|g0j7(}jlMY||#gwS7uoEgv zCjGH==3StQ=RFLw?}_ekE|RO(VO+8ke-N~$AgyNV^C8AF-EB(qdw6F3T@<@5B2)^| zGSU=p2NFY)(VbZgUhL0KA-7|2$jNbOFOTqS%t-ypvm}hRx)#lM>0hDm45Zw{Te#(X z1Eb=us{c&Seqw5>)Q-ZE1Mw<)LX(ap+>y{x?0cm6K1-?R?N0c8H;aE-^u~)=bIKIrcxVf-NTSS9%0p&c{xVSn1j&B|W|xye}1w3IWm47#|z z;+)m}NUG5y7@QdTX3{3#zKBX_?F|PPBms(I<&w=W;dIp6MOPyK^_i>$q4+y(ab42Pc(c28nW&7IfQPt*NXNv+m7 zvE)Wx_0@RXC@GD3Bi(hc4qv`$cE|RXkSdqtPJeT41Qnj;h2rGV7jI$0%I1_LgU1OWIbM+V4HQfYY5H?KdGc(|sMa_1=l>ui zWruOb)s&(~+k==@lY=)=KCXSUJ`~}Tc_=B{#XNNQ!eL7Hel4!v_ZUi?2aUI~#niZW z&OaHu}*+o&tha=w$Q}qU&$s+1x zL4{Ff=6ZhugwNf5A6fI@@-{uc!Z&=)WYZ^$s+e}%YH?bFGdyi&-Ohh5qt9P3mKnI~ z6N+0bygE@+^F5J&a>1&q`k(^ylAs{90cXGr!i z|JrlIm3{XhJq_)`TBTo-3XfbL>67e!Z_gXtpIRY_=!23{r&$c-)`bXv#zaH=3BHZD z7Gl`VHAB4rdf%mHX%vq`Uh8Xp{mcf(%n77_J{W`CC3^JtN(XsX3Q$HymbFwLP$ikX z?7u=6?fcas?w%k2oZxAArkwoXeU5aI_l&_M&E(ygS-vw2Sqa!-)rJE@%=%03qUp^$ zl#Ff0DWejfukXspi5%^8wl?cV%sX!rx|MbM;1C^<1j_Pq>+h}J6cfAgB8oPt`K`?Z zr+mWb>}Xa3OwSLDBwkH&AKrd0vtbI_TF8I1mz+<3=Exu}tMhfcJnMz2u9x|P@*5~3 zK9)g|1a8eIpUBAH{pGo_i8ujgU*h`8(G;~^a%)(q@RwrsK41* zNBeaQ)+Qz;6*R0Z@eiG&nFoqaS(iRn^Zi>6{tjfa1RaL|m{a-l$yn%0Kc(gfajGLz zyc>n|4YU>&7jK2fq`!xUd)Cx&dtWVnf*l_JItsQBuATX}AL&WtQ!N#T!s_}Ef3=~x z#J_z@iBmIJiF!F?=qY`_v`~hJ$_nL|X4%f65rdibASyW*m&Y^p689^`RG!KU*qifv z4t;$4D&D6P=hj=P>Oo4p1(S7Yt8GrTf9|u=Fkw*!^qAr#utY@QKcVCj)|R^e_2F`kzF9G0`) zV6tYoMyPP-&^3a@<9mZD`nM97&Mx0VqZk^#FE$utdI1Er*DUd3uV{mrt|gYdJ-KwR zIL1*@5`0RNF7M*DD)ir_Pn|V8@n3%-9!Daq+hF5CMU7MIP(fy8W%W@@>js|a2}XJ= zUq{s2pqV;nUvLfi2YkU9)M}9a=8}?<*HFMT*F7$dxXN}XK%>c11B{-~U&%#(@$x6TTky99i7;^J0nyKc1}*#ckfl`@xcj$ii+yHJr*4u-PptgpRlkC z>5p3beN+w(j;G};W-~-9D=QY0_$c5`jo#AI$SbGyf&g69!C?C!<#+2xJv}e5IYYJG zp2{j!7ZE`(DlR5`PW|`Xo?>Lg51Mc798$GQ;OqBxh`-gmARa5VFc`8^F8x-jbJlefGExcF%GuCj7+U(>^rkayXzZkq?vB#f5cJ=|zevweuKqt&#c zon&%`8ve9xX*sR2eJnkRKZNVX{lJV|X42(l0kQO_`tRoG-_G!&oy%RmaJ+iX?P&4H z>sVsJ%=PR9=lW%Nqjmc+x?d4zzyl%fLc4L6l8qNC`qg!Hx6m;dZ%#nfXO*)P^U06T z>a$Mfdw*-T_2WmXvx=TxQQYd+Zrp3@Q9j1_^4%xWtuQN3rPWJz*wLw}tzCDLa&u9Y zx%9>+IJBDA?%u)X`b>i_k4Cn2>(*w&KWq{&2oeOH(MSS)`Ohi-dHF;ou@=#wL%_Kp zbW4ETRfYbxhsPtnEr+vY-U!_nk#NorlnCZUU-AB1ocQjXT1bAO_*-C3bImJNz})CQ z-221$9I)H8`!nZ8lpL(qz4ZRUg9l&<_77MgKG_|TVd5yxY7x?g$LRgRC1w$<&N8#J zamFdx*zm!v=mgxv3&D{`K}o4`aPR?SHh2~lSv(WUwFBSvPqwyRVEqS9Zp+aX0__=V z;4q3z)2dK0osKj5AT7=B;J|rsxLm(i0k&S?!m<8JB1bOo&)%|VW$X^PPa=&FeWzi> zI&wQ6VS;WwbACO$cNPM%vaHQLz%fh{94alwN$&@CXlsI_yY-QBjonMI6dt{E|6i|3 z#pg6R8o$Q6*;kmP^_3OA*``qH^VnP6N9ju%)DM~r3zg9@oFOsD>b*HJyIL32btQ1g zKARubMH%9^nUbCOLA~r zshC927RR{vi}JOh_WnDf-|D}LuGW7|O2S>Cc}}4c*sZY;tW8Y=O?VYIXi)-W8&zji!zqQ+f~ns7tH ztltr~)Kqp}qa8t-y;@>oc4OC?@6eG5|93CI+i4tqqmdfiR=?Tg#BYxUTdN6zh8glq z9KI22nM{gOz1jaiW2nEJU0gA z#-etL;s}0&eWIx7yfuV;Zdir2o4F8@!ik{rdL@r;(wdA!HT?)CX^|d@#cl)X;c>iHZ3FtY?Fq6=?Cm zDhmtGcli4}`u&L5-*a<)ndaY~(Q_1oR~CAJ-;j{FI2IVD`$N{t-sG?D?p=sx(gK&- zry*utot?j+1W{)0${LR5trp- z>kVLO_(o0+kC~ad5KMoAoFm^;sHmzYfjeD9B!tI%gX3IMa`JVEJ#Yh?JwT~_N#M4B zBe1Orf+N5mQEtZ>RuxT%oPTeaZ$Q(J;(i63tg%6{F{1c{WU>Xc-S z>bGC%{nM~x`^S#kWpYD%{w=Q}8Ray7MX%=b6#mth7Ev*GsGs);@Tp{eaO|BaCX44+ zLyO)MsR$|^pbl)yD}AgFK-KPO$>;TCPUP#TBiTWKk+HnR*O|BjUe7l0(OZsq{`{CI zw4+#IeyHbmG!{9zHsUN&yXv~TN!{3l^>IF!<|89H!X*_7{q19aAxRC26}l=ErhTmI z$cp*Wwx8qTN>tv3&rIVDD%MVdJMQeQ;q%h=*Z%bgp;fls?DH4RH8x5dn4jG=MBUJv zU`e%$BSIsboGJ3`JRaRWEd-`jce#wH+p zZf?1G1!dftSh7~p(`i}!)zK2kxd?%bCO6AqC$id_(;kIl;lTPT*|zKpJMR2ntE(in zdh-kR5-uLCMFURuo}(Y7q)9Mj;o+ds`^rf*tZ8ZX)<^T7#=iMi-c8Z-@~wLV->Ke& z{5wsKz!h&TXU9`JoLVY8GsHjVsgD;RM@ZR1}<$+==0Bn zWT>gB6~F`-!bOtODO_+rT3cIVlJXD%`)UIN^g{jqr*8!XlVL<6ZKZ{U(eUV1#uTu> z4mE+rUE12cc0ECPd3><6bk1{zcl`nHof{}%`|1TYJ7~c8n!uX)-lIp};5`euF>?9l z);lxAV8Vu9Jq>e0QBkpPXvnza_%;?6*2(GWI;o6x9f9_Z+6`x}sW zncL0YbZc&F!|qKg-zQ=(!_A+glmKz!K28P3NLg)PR#%16d30pi8)$*;UX0IPl*Mk6 zEv?pi#Mjx^YEn`EdZ=%?U49Q0HJq{clwf@7(ZmSynIkesZn`kN8cMv z%F&}%E<{v0Z(!H>puGjhtlE_z&#un}_t)z0LV)>2StJ$0fn3u0(_ts#Dld~p_{*Xz zee5M_hxhRu=MtCII-{I6DL+5WuUJdW^CQ271j+{w8qJp%sQqFpYSqk*^dBcC&JiPA za5J_&4ydoh2&82P@hamww0{n7am8}cReYBp@{KtZ?{fm#4-|o$%Wk3@ED~ChlKr1I zzVFOCnzPjVcjfWDw?YBl{h_OUA}o9;u7W~*gY~P1#`vSG=MpC-k9IV_!_#WoVTuMf z&&--&zK2HOqnm83Ge2T0xcu_VPyV88OyBiWB~eyzv=Md4Ki(4efuY?$roM@lce|5W zO;PbKID`sz#t5OHh|xVm&YA(K1hmqq$daHc2MUyjE>@<&Y{EU(r5%n5K9QNq*G=A2 zVC3@~BAnD^WijY)gg5M*64Sno66giSpmPvx zcNd54$&F)_G&oYwU7FwsVdeYpg620P_xbR38oN5`WN4C z0#h7!SgYTAQXw8VRi7P>6-O-Ln&IXlKBx7K7|{0}%_W@CUC9@(7cmoHqP9w$Nw3A? zJ2~prYEnP94{Ud&{HWW1e+4hjy^JY}7L)X_xG!=of^DO8_KX|g3q*g z<>>HkhNP3q{mZY>1+Ky{_&_Xbe?}Ixw?8vt>iW$3BFHKMi4u5pjCU%1wd| zsYE}E^@ej$2p>Ow3bhMTGZ?!wa&!H_3QY5GeI2)ig9r-}M!X@Cv9jg;om1{l>_iZ5 zjDymbAwdef^*T!W`zWC9)+i0Irh`VBR!9(o#HKF8zn}*H1H^Zw5)2S`!BHBeAyYC1 zh%03T!GDHzql%YP;7|3-gxAWFl6W@8=Jzwp$Qg*R2!*i3TPBAxBDtqAbXSPU9*=^? zNAZ4~yblj=fm~85gbEb#Zxxo`UBN-^W2fI`DFqKpdSFg8E3R!5c8W}^kHHli+cVG^ z5=}rjD=glj8RnK_eRXqNG#FD+TH%ix6-^FCsl42~giV8w`p-kzV`DoIzXV%ero|Dt=KsHBW+=?lI2M^w+V{!D_N|77nxe18oE;dBiJo*f2GeH%qvTe|_04WI0?-~y-wHRmRZ z3_#Ok({b06<0Pos$h?xn0RMj>y;L=nyf&)i*_#tkoPGw-(c8sc1Wp}E%S8v?P}ADI z$YO|9#Y@yP!_I2us-|sd_=&hAO!|kHI76H^loJcC9TO#fN-lH4>H|#J8 zE7jI34Jl5RuVUUl6Qd0}mPnp$NaLH_(|PA4BRl+sf5Yv%iLf`AF+3o)#z28~P-)Mp zP~fyX>sH;uECT~gbJFF5pYw%j0W1`qq)Bh8`+w{cB(45<3Dx44;wPnlUcP*_b&Eds zR51PYy6L6cNyP`uM`ePUMcGtPA8h%K=hu=9<}7mh8k_Iy;t`Wi;QOZeWierY?$F+y zgj)Tn&oTDBaN}QX!0p`Q)+0XQU!(v!>~IP1IC@=OH~*%oIe}LU)8O6v8i!@qcOo@3 z*0IJm905eJ=)kzOC{083-%DzQe~6*=)_i^0YXDrbJ2dsD$;m1nxeJ(^5Q%Umz;g+m0G&?G92|(T`8`~gfsa;^clg|pAA-lO;GXM z%#f`EzUyfPGm1*lULXN|Zd*h*2{{5b2xTUM;X-|ySm2$A-)q3@D2ZnE0@vGu*u~~K zXF8MWKUj~1vSFtwwSVbao?8z?Bwv>iMt>&b?TV%wXe>DZ9EDJ3k%Ep$QN%u zPR4Rro|Hp~>O`ali!j92Bl7`Jz_$4Y6+L~p10=NF1p94Vl)gM=wu*|1b{4^ZDegCY ze$Tv?*jswgQ*AM$q3&!f>+S(ACb&XvOPZR-)3j61foyB8joD*Tybm&w#6RA3O^n!g zMc_Fe%wb-?Bo}>rJv+pbKJNHo=FHNR*%QHlQ-O5_#u+q3Brg+_xTn3QJGF_9UTc?( zv#89MH#XtMvdxBuTWdbRXw1(?NO1x?I(@v3w}Y-1B-juOeq4#w;`1g8E-bda|LzY> zyF>)LcSR~Yew#D*T%W@~Rh(it6Y-(+6E^wo}Hx}BT% zYaQL+56cr1-F{Qv>V*AF!g~ubmmp0=)9oc4Xn@l_3&Ps_`0cwC(rB-(8z+*SAAH}X z7hE8qficzRNHj30_Hnb>gin^Y#h!9+ib`2PSJF~PkNh1=+jkA4ezOMGj^*cOB=b|h zb)@37p6w*OO+?7Kx&OunF88&YKE#e5TFr`<5_iZ%>g_L4CHW347CH#H5mn_U%W;1{>S5e&Gx zl}Chn$Jo~&>s|#ZKxveZppz|}xx71X9(waurmV7AuudE*hIL)(QfN;KuyiiI{GFfS@wS=+b8~FSwCzu z)6krRF!qtbu@DRw4if_cLQowY9W!%sXgG(iHgbf;)bF6 zhqWy}0U7S!cED@6+CY6ZK7K@jVA2xEx_EP}j*sQ_wYm8%vW-AVc^memzhGtcgmeke zhTx5f-z)a^_vbe@Fi;3yIWR-S&doAxf)^<8{IuQW8B4xetxs$$5y7KJ&z}xayb%z% z1(xtl;C}u+BEk#Vv;?PrsqP<^tKy$3hiU#uAHM&0x<8he&k#mJW)SQDtQ_7z8Rqpl zuCIL58?WLv**6T@2YP5I8G_9i)C|+1E^DBAZ4)&%M4 zTc1uFkLN5nDy*)!mb58J^Q-?lwl>LknSXlqt?`SkzQzRV<8_CR&$AjTqKJovb9i@P6uxzszyNd%GRQM% zG#x*6a$m7W@Z4$({PjhPkPSKqe5$JWot=g+UYgMKWmHfR!oopC-}A;|z?s|L>WzNB zuU@@?h6bu%%=jDS>PILIeSPSluUPYJ2U>5lUZZMGu))iTE{= zK3&(b8*};7@D=*%`UZsjaBQA}BYgwem$Rp;aTJR`d0nB9ZlGj8&;;s?SG<~lBf@vL z?vhfCQb-fZ01oMm_4O)+J%7@kIHgVr)+&7So8yXTk;QYER)_Cf0(6SI?msTMJ?i8N zffPL9j;MR;H+(dweqqh#)dn`5Q_RU4-$R*Os0@4Oc#av8Za=JqmIrl{E&s}|Z|+s0 z{y460ggX9Nb@8~)JNx}Rw@!bz+u{3WNYFo_JB;d6Ikh)4-~59KdnE3HxTSgAp&RjJ zTlUTuvz@narb%09<{BrzZ#%LdE8mnZw(09Pz#`XSAs{HrJuFR0P4zJ-#`@`aeCNvO zv<$&&WgU&VsB3fGd4DFO@p!@@qX#WLiXp{a*9jg?&i$$LrlRZSf8)Y=H8yr* z@Rd_v<;ICp8wL4HOQp0ZREnD^Q?C58F1~M%a&oEO2ny1&6S2bPl%QRDQ~)n%hobhE z_w=sL9v|hMA@416Q&4(3-FMo^kT~~&0dAR4{G?1O3^?d-2sX4$EmvaDXH4T?Fc+;P zv_-QNdqr0Tv=e~;I)(W3jT=qj6&B{WcHAT&J-F``UH|omU24M`ivHY)zkkKmvBW21 zuA7$lu^y`yKYMq4p{omB$*SY%Yan^RUJ9tSce<6osdLMK3ZTwV@9C>2|CB7#;pdmz zh*&^JWH#v=Q<7l{0z(NvvmTb9E%gIaOyThDY!b-`C^MU3p*fYMGcz{Sx!@ zF`hjm%qn2pgKvG22(>8r<_(qlEKAAHuwjLWcfk$zwtSG2Yx_bTAyAhdy=U#T$84sp zM?MEEy`HYY3?rJw%tOst*VlD(S%BTr;ywv4cOVk#$oD?Hp&~yA2;hQewBQQ!cH0|$ z=#KzMa4KTbXr}I z($Wh1e~HBR*518$@vgL7ZEVXp^F5e#Ill|(jkx2GL66kd z*%%q$7P#|5zArR{(M!ENJmvv`fppFfw&d+UXz?&0=&~8Y$mZtfuVG;9@-}C7LCz(F zt$6J1S-9DN<@HpxEjG#=NH}jJ@v5pSWI|}6;V^Y2MR-J5*gV8Ku{$2o0?7v%m#VCww)Pdontf~W z#ZQ5xkPGCo>KhtD5TmTAx$_4psV{&|n?O#5l&bdLUi@+BLncF-B>|)M9f(fr2i#fN z_Ou6r$$scd9%A?9tJfpD>u86kzcUj4K<4+2OmTXZIw$*-<`D?RK{h#|E7lI>J=EFd z*W@H2NWCm5bI>m%U^6B9yl$DAmPU^3b(om=S5&YEwSA?6gbIjXer<0464ub5(9oMY z%j=}MkXh;Nss>?etf+T!_FH!zSVLSQ#I3$wuvAw?c4Q#hs!NC7fL5)B;QUAyagT|I zhXfvsviAFDX}`?s)~9zTw$Uh`NnKG~6s9Y7zcX~vxqdugpSRJ`nLDQQC&dO4u5sA{ z_LzA9@4o*o|3)?q-r*X{gE-FWreq!YAT;b{9glC`Xs?HS3GE)*qlSg0eUKk*8ADU< zuioLVY>5iJ=jOZ0eTw_Aw8X!^x|gT~`T(e&;ZS4UAlE!Kt+rvGQvRMjf{dC*^qP#k z(_=Psu3Qrbk&=S1GmE9ep6kJ!&LAbr;gb(BXX3gzQ07KlWi4Xd zGha=7Zz&dMkK%mRgJ1n>`H=tODkkLrvGtY#S++~p@P$fa(k)7ebVv(|ASfsbBHdEb z-7P9D-Ccq-O1E?)E!{|W$2XUH?|bj}`S?MJXB;uJX3d&o9*l$#A5X0mAO_D>14!k# zYx=V8A6-`V1|1pb94HYrAfW@4@D6Rg;k(Q8O$I#Rr`?VZgu06=H>$sAo3V_dFLW|4 z$T5HYX3+@2ox0W_>C>m@POn4v1@R%Ky#@3H_`;dxxxt<+JBE}rfyQ~YvVqcg5WY0f zra5Jm@Su;EKgM{qZ3rX?WPCj5nG};#s0lS{Re@GSRXVPcui7e-e9{^~5#za@dat?T z2^s=|wIs3JNWDR4A{;-%gmhi+f-T{cD!X@!pOtJOZv)g$&(9uw8C~*siHV_o$A-w5 zkjkxm(&m&qB@%g%<#Das{F zZ<(`cF+X~8Xy7tq82hxE=j1f66o@TmqSxJ1b6%srqKi-~Ey0qaP?>b0)i+r1jjPnH z?W=IwU3Ra1VBBd?;a%#t815|ovHBtt({11Q6J4k)0Y*LlbiYcvX@}~4=$ErE<0T+1 zs<5?&!W9DMUC|Hz$xADQq!y%vomrD|$WAT7)eqaclNWIG^w0Ns?SO~_fu-n+nk#R# z8xzkH=1#mF7zhR{AH@3^nb_upWkt>QHier4Aad4z0m z0fgLuSPB%ZzHT0Jbs(>M5X2YI^vL?P0P;P=yNzcnr99o-Xy%#u&>0MRCR(&1Gqymf z=r#H}ys^YzPFA*N{|CvXi8Gl={*SPr)jy5ETI~0$78eGE6H*I1QhfG6TND%gjvt(D zwA~aVn7>+yrSy*$;6(yfMnM4yphqP9%*>3EUn9n_@Ol2NvD7)6$-E%=U|)&9Omnyu zK~4MayTiUXYs~}7@WaJ^UH=Et7H|)UCvQ^gai3Ryjw-u?cJ)vQ$9(%;f%#ZdBK3Hx z*vt<*DUs@(nPT1|@(bYUH8g*q9lZ~mG%Iaxc_J(sB9x>$S_6vb1c;dEdn%IlRzW9P2lzL0QJ2$NuiV^=)6UOkpc z^P=hKd3?p=+`p>5M@7gm81ZiGIPOQCuD^n7O1m(EKgK&$9@v=)5YmJ;$-7ZAT30CrMb6Jo zQ%N`s1{h0e^o|Y=kiB7V74!1*f3L5<1h;OabUC3akb-dTY`^+^3fvG6^yC(z_iLKb zfY|3?>H}rXlzAWC=cFYIgS3!q5?)^9c_k0pwen0rZd#JlSevfk2W6nhqw@=yAz{*Nx!Ny<)xk z(-Ue#mCGzKap|7E9-D&hp+L-_AsCg4eB)ydOMU$P-$T2(+0y5+-@bhlzQOsMN^f3p zYk89h!luPB-79s%71t?>;^TRO;`a%PjScIwNl8H@1%h7E#YIl^;M8}J>YZIkPyWn` z3kDA~x+#!ZCeT>?NJ*2kK|@bkE_h(vaUVh>ldmo zlLuEZ{V5#H{j% zrjniC`x$}Yp#&>kin0C|E;a}Vu3BBbk2jm1n3)-LF2A~RoCJCK#o>{QlC%=@P6K^y zc2~%LmfSkni!XuL$P067sMP2tD5DcnwQ;oZtwQh?lD=|Y1;nt}Ya{sBcO0?na&8?2 z&;(z6FUv11?7D#5hZ*CNtL_(yklKF`3f&Dc9Drmfq%9@qu?iqcO9TS41b5o6`IruZ z5F#7l3NyNTr8h1zg?pxy)u{uQ_(e7HL)e--aPK=f++i9hW75R}7uXr!q&mqMfx8jyY1v~qKH(~% z^t`wT9KS3!n<-vuy75QqHP&EH9%%~mfOc4P4^sUPtKB5n3}=t{7@F_WXKck&;^RL9 z#@@A79gC*RoW~HlqPfh=sJ_Nv4!B4@Mj#x}+dTAGy#k5>y3Lw}x|}(6JGSF^vdLBQ ztxq}LeIT!?{CHd3X&WQF({B0)lq`Q)1{n_#NE#qJJzG7W=5VkPdC9S4+a>ajyhdo>|29Zt;Y!!UeUBr&^hw(zobc}3cZ4kQ?XhWV-ve5lqVlM{ zHaj|cW2Z+{q_V{AGa+}4I%~ogT{IdRSv-P@N7~x-p!w=)vZHt(aHjA^)6(eprF7W( zg@9>C+t{I@y+)j?lz&iP`r$`xS9h}V;T!v~UWhObspK2C8l(-bu#t0!*sJt zMMcF1bcgmCwFcyiL(F~&XyPCP&&sqlXr6g80zr(C$J!U8ks@eBEc)O9A}Bc64E_=t zDr4^k)7q^;gG^*%89KZj7=b+_60l`eEH=Ij%8t(&8B`#C1PTn}>Tjt=&7Ap5P@~22 z+e}0Lro?p0y;;7#XK)bRr{P8<&K;@8kH4Ki5L4vi<9qS)~G^ zc_91bn3PpQFZE?; z?rT90S?Irr)EtAn3bM3amoh&&dsQ9Ildg=F6M|wH{A2K)hlQD$Sa4-Dgr2^>#+l=0 zsInlpqM{-wMR65l-2P;)E7+qJFPqKj!+Vf@n=x9#eRUc=x$~#^;g5WMvsSXvD4BL8;J3 z2YlbGb{@R>YUF>=(_4BZ)rG?(IZ`vwsW81{$&?*4yLTcPZ6(gU-RIfz%3b0-ck0Kv zL4`}ad&!VGVBCj*+-;Sa0feio>!FsvW@cs0!y{@_XPp`~Nu0DxZnP7TkvMADhnMd* znUvlkEx|iH)c@#%DXcoK1TW+&BZ~>fy?e0OHT2n4U~EDMWl(^Pl8l@8^pdf@O~1)J zo+c;?i861jLgZ_}zi}FjV*$X&tVDYz`7;3-EHs@=Y`<{2(*J|=op+`q!RwHBp4z&O z_fA}h*bV(2WC7}b1gCU=3Xa`bcX&5==Wgr!8xp7_QE1(R+#kLfu^?}&N986p$2b0? z6_Z1UvNlEEAu#L+CnH1Z6GRhG-!^IbB>@%#($kufU4jCXKnuuaB5m~O`<%ybTX9V@ z?`r7uyfhxPh9`s^Cke1ikd8!7-yQl+&!B?4$Z{dM!Aqc~($M_*nECk2GtdY1ly#^> zk>E|Pc`kE{puqU}_XR&LKu`*QiI+CNs-ZQaG%rf<55sg#H2KoAKU{e;Apj99uu5OP zNl8lLJdfd_Dyo}UpuK(jA{fvM2&85l44v_Y6SM^-1&uAj6%r2KlHMQ=h1RI(PbDM{ zji67paQ~gkii$j-Yn(;D0*+LN-lSkdO|vnzfqB~4+Ny(2eO@Ogj>yzscfvzt=VG0% zIHsPN#er;6FiqE?zvWjW=q$XkyNilIcFdm7OnDDoiO-|IzU{|?3Wtw=e%aq9K=F2+ zi0ICs)5RLd4PFP8`q!_V&_7Kgd~#Lg^deHYp$=C;AY^1@plLe#+S=MlJ~kn9Jpg)E z%f%OX1O#enKTg4dhr3MrH$795$y#ZEbBg7^vSG7-&HQ zYxy!udP5^419BxrMQ>2~X@Xkyqqp~k@V17uXVFOEd(3@@qK7vI11N<$g`A-iv4X(_ zv`ybo3kLaWEsPoczO5h)lnN2?TQhdX3k3k91*%hYr{leBt9DOp!cS3ASP4hUS-C9E zsYhLYz!xD06CYpJWxvcxK4^2yDZR3y8)-7aSC`O@Q zNxy-Eh7C56mDLav=w8ngTa{-j=uiS>v~%j*0=m1}(WGEuEp>Ky^+6pWGL{9en@1Eib7jl;=}~Rd2i7MyNP-nS2lkAbGHUZ= z>V;>JWjwH?fvChsmJjcfxB%qzkbvWsvd5kbl%Jv}{Sa0&@U<|5-UZ=}W)vUkW9-n5btuF&}y1Vhe3 zXLAq*LOAWZbZN8fu4Y+z`6DT*t3XlmSS{f}AIn>t+h?VUrRFrSa<3wWij0(EF{Ajc zR{*H`tK@5ndNd98K?~rTdXb&CyFtkAx-y)9&|aTExCx+Te0>en3_tuq0)H$P%;y~n znI4qCzY~X5Nprjqka8-B4p?Jq;*7_vfGRRFauatwPSB}U>RRYyTU#Cw(_&Brpj%j2 zK-exG6LZMsB&GF74^2&3rKP12eJb~H z5qZ$O=MhkMM*BQQK9?7f@cA=FFzqv8U?LEc z=V$BZdBEDR68YM9EYHrqo19c%Tw1z-C^DJwhvG^5rsLWVce7!cMDSTrfSdY`AI=kL+(B zb7zNF{Moa)3E0)fUr)JA#$#NLAEDk?04q%Zu|uesI5-{j>KkK_axvRkd|BEqL0#;8 zYQM8Sp_WudS*<#lt9DgaSJ$iY7qnY4ffU0Ne99NGuTI>cbfIs?fP_^YalY4-|KxYU z?aXJBiK?LzGp)**qXf{14HfEMMS#d>GZ{N=p-gdAZ?dVQwxA{sslX zZ89#Rqm!mQeHh|Lai0XH6p8j+``CjtR+2iOA6pUxnaKP=wf+IkbEh1?Yu7Qu4j z>iP0RRZjfXOOs&m=D4^6+aVJ~vvzD|)f^B^Mj90wihsTb>wo$F#KGna8>EaRV|cDt z+V2M0JA%Sp$W0nP3knLtb$0!iwII3D)SdVU1p#_b3~cN#`!R&f$`9aA5bE>okdJ^1eiRG^wAc;UK5g_0b{V@0$j*>?~Kpf~-HW7f!shy#TfdIq#Nsh-6B=rk) zPPEk2H~IJ!*N$(-bJ^I~oUKAH-kFYQ?%gOUB_&d*g@bS|OR{AO{J}h(A{eGfwI?sf zVcR!UGX8|)7|5Rv>o;xP*Xb5dQGe$P;ZqV%$UiLT;WW%$4LAi{T1nUP zat9BZd-tp;Z`8ekHWB#I9rF`sB{z~%$jHfi(w>ppy|3p6e(-D+JjcCe!RGYkXp<_p zZ{O}AZqn0ZLI$s?%xd{lM8xM$wkM~jhsA_Uihb(GzXo$D$;ikM2yWxi&x6X4fjqez zgG=}P9VFXc&G`BGv1!&re_QYvn?MKJH*E8EcX!uJH~63+peBI_h((tXXpDRKq(UN` z`7|k05ymh{TZXKzFLF9oR-LzC0tmMkiZ`coZ4Q#-jdgBECHAT&05Rc%#bqJ?O z{rh_Kt*zc-+M-?$l%Bu7HMG*G67sJ_?++ny_>h`f^Q$nam@TqqMZu5s>fh;h%uxKQ zhk}5Tx#qSukNkYIXkXudMb*4;aD5Azat z{GVROzmyV=A--OTD}7V@2OY;cWnf@LoFw}t=lE|05xfh$$HR2G^D!E8E5lH7VgYPD z;{6r!r&D#FtI=@eFMKpVx_j#cjoT#dreLSIp&<_;%cZTRHPnp8(^3;&U>#rO+;B~| zVH+KDx+9&!ct(>sLS+CWQmPiw@g#<~(vw=|f|=RN(Gq80p?xNad(494%{v*Z8A{ds z&JACt=jZ)=e9&bxzZE?ifMQnU$JKB+XTtZRYhdyZ)rHxV3(w$c*X>x_qwe`2QT@2X zde1ilIfwMyL1|FjphOwZYe74K#mS;v@=524LTI>MS!wCZ&o8KM-M%e@7vw$KHZ~UP zg-gc{)o`zKlv{p&Gk}FC<=q)cMMY&eT;K_^t(2i6$w+o!d;B5o+zVM{*v=Lq9>a#T zJUm3=Yfq1X6tLYfGScG;^jGB6oI)W|(#)4Xm^eQ}io-rB*YE@NAKgjw=cN^FpgB(%vprj{ z8G%n^rJK(XX-RV#V?qb^j?3P1g`^Zft~CoYv%vO)uUcV^sukCo8?fC57APo058fQD zRy=(Me}Mcr3tC5w`ZJCmR|OAT!4R<-{p7^gYjyepuz8>f+~q4!6#52Ao*tMt z702KyJr)re;$vbc9F~NIh5&bB#}yzz1VEOE&+-nqRn#DC8mU;m1~@~2$LWX@+{Y|* zUWGJ;S4s-?%~Dn~STT$+12DQAa63NB#ZRlHz=8qtt9!#fY#Cp03yKKEMmpk!CXRTh zsN6tj8a>Ma8Fk@Oh4?_5XXJ==~v5WA= zXLt-8DTMpq15q^9V*79 z`ZG9KO3TZ29ik&5hz!D|TwGjQLt0KRr-3s^t~SHbl0ZP+GG&&(l$+WOY=j7BWfKnp zFhg~minlhbypG_~Kkq_q0Nq0#eQ$JHiG2^_hxcM_O|ar{Eq?F$qrZQkQYAW>yN+Y8 zm+|1w`_EFzRy#XA4ZYg{K{*nv!89d`2i~&dTY$OA4k)+$6_iW_roZSZT_`{kB}#D7 zf?e~0AABH3M$T`Y0uOMqAassQxWUHqM9N=$8tOh!I)8+EjUOpbhP@q%A8glq;Q}(7 z`)tZyou&A#RWXJ~s}bjDZ#8;3f}YZg(g*F)mU#tgw-A>eYZy z$8}ctM2ym@uT#P6&#L&Z&jKZ6E3vMBelhd`$~JYo;t(QYV%w|56Z5|uVcNi$U?U)2 zwBK0_Oy+@TY7z?IizGYV?k@EYG{F|{4CWPqcWr{O^bmG-b{oWZ?ciez@zWti2Z>zT z0-JT!=y^Q@K(XivFgTX$<72dJ=r}~k2oM2h!4y7eN3R7$jFb!&n@s2cUAy;O?C%2m z_sgtX+8+~lJ@5m_Prqjc0E6*FQ&Tgp2 z00+=(1_#3d5DhzC33Tuy=MU43gM(jSM*`Ff&R*rWTvT^*EJkcOL*eZ`=krq=1dOgv zbaeEyX>culii=K1JNnk^<3_?pj28|LW&(%>9eDr? zv>UyByI4_7HWk*KIZMSUn) z>?)))SV{bliBqsz)62^Sg`fu1c66F!c74I0ln@76j1ON+9+Ccm`#g-qrX_g zzh3bO<~u{7Fzwj_5wAHlKtep#< z(`GA4J5xgtF~Kli*q9BL`jM+96y3nAR#mZUCN3^sRJ6ObHGQ}czfjmEc$7`c@c^3+ifp$u|Gb|~7A9=W4Z#tBiF?%~#)WHi@hNLNR9QWfEnlD2{EDTS~+ zCnu*bTPYlN$Ou2v|11;a4}oMBc{Uf2PAJIc?Vx+SoQG6mdlM~fU5{4Y8+w8BTd%Uv zIuvWac2No3GT0{Pzrs>^VeT&UZQO`IuPd7

mT*yT_;$QXDHF3PHxRNOtXm!RoUH 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

ptwkqzl*d?f!cOqi0r^@IanccTlbI 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

K+QT(&M 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

)LG;v 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%0A{TnfuXGE->s@h-Rz~9gln(@bx#iay`EZd>e8M;! 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

ox|AXcl(_BaOt{BS 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 z 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 Pkqdc;!-IYZJaO?qK6GU` diff --git a/Deprecated/assembler_bug.jl b/Deprecated/assembler_bug.jl deleted file mode 100644 index b318e859..00000000 --- a/Deprecated/assembler_bug.jl +++ /dev/null @@ -1,43 +0,0 @@ -using Gridap, Gridap.FESpaces, Gridap.Helpers - -## Current version @ Line 310 of Assemblers.jl - -## Proposed version -function Gridap.FESpaces.assemble_matrix_and_vector!(a,l,K,b,assem_U,U,V,uhd) - du = get_trial_fe_basis(U) - dv = get_fe_basis(V); - data = collect_cell_matrix_and_vector(U,V,a(du,dv),l(dv),uhd) - assemble_matrix_and_vector!(K,b,assem_U,data) -end - -function main(with_standard::Bool) - model = CartesianDiscreteModel((0,1,0,1),(2,2)); - - Ω = Triangulation(model) - dΩ = Measure(Ω,2) - - # FE Problem - V = FESpace(model,ReferenceFE(lagrangian,Float64,1),dirichlet_tags=["boundary"]) - U = TrialFESpace(V,2) - a(u,v) = ∫( ∇(v)⋅∇(u) )*dΩ - l(v) = ∫(v)*dΩ - - assem_U = SparseMatrixAssembler(U,V); - op = AffineFEOperator(a,l,U,V,assem_U); - - K = get_matrix(op); - b = get_vector(op); - b_old = copy(b); - - if with_standard - assemble_matrix_and_vector!(a,l,K,b,U,V) - else - assemble_matrix_and_vector!(a,l,K,b,assem_U,U,V,zero(U)) - end - - norm(b - b_old,Inf) -end - -main(true) - -main(false) \ No newline at end of file diff --git a/Deprecated/auto_diff_elastic_compliance_serial.jl b/Deprecated/auto_diff_elastic_compliance_serial.jl deleted file mode 100644 index 53bf8681..00000000 --- a/Deprecated/auto_diff_elastic_compliance_serial.jl +++ /dev/null @@ -1,214 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.FESpaces -using PartitionedArrays - -using ChainRulesCore -using Zygote -include("ChainRules.jl"); - -# Heaviside function -function H_η(t;η) - M = typeof(η*t) - if t<-η - return zero(M) - elseif abs(t)<=η - return M(1/2*(1+t/η+1/pi*sin(pi*t/η))) - elseif t>η - return one(M) - end -end - -function DH_η(t::M;η::M) where M<:AbstractFloat - if t<-η - return zero(M) - elseif abs(t)<=η - return M(1/2/η*(1+cos(pi*t/η))) - elseif t>η - return zero(M) - end -end - -# Material interpolation -Base.@kwdef struct SmoothErsatzMaterialInterpolation{M<:AbstractFloat} - η::M # Smoothing radius - ϵₘ::M = 10^-3 # Void material multiplier - H = x -> H_η(x,η=η) - DH = x -> DH_η(x,η=η) - I = φ -> (1 - H(φ)) + ϵₘ*H(φ) - ρ = φ -> 1 - H(φ) -end - -function isotropic_2d(E::M,ν::M) where M<:AbstractFloat - λ = E*ν/((1+ν)*(1-ν)); μ = E/(2*(1+ν)) - C = [λ+2μ λ 0 - λ λ+2μ 0 - 0 0 μ]; - SymFourthOrderTensorValue( - C[1,1], C[3,1], C[2,1], - C[1,3], C[3,3], C[2,3], - C[1,2], C[3,2], C[2,2]) -end - -###################################################### -# begin -## FE Setup -order = 1; -el_size = (200,200); -dom = (0.,1.,0.,1.); -model = CartesianDiscreteModel(dom,el_size); -## Define Γ_N and Γ_D -xmax,ymax = dom[2],dom[4] -labels = get_face_labeling(model) -entity = num_entities(labels) + 1 -prop_Γ_N = 0.4 -prop_Γ_D = 0.2 -f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) ? true : false; -f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/4 + eps()) ? true : false; -# Vertices -vtx_coords = model.grid_topology.vertex_coordinates -vtxs_Γ_D = findall(isone,f_Γ_D.(vtx_coords)) -vtx_edge_connectivity = Array(model.grid_topology.n_m_to_nface_to_mfaces[1,2][vtxs_Γ_D]); -# Edges -edge_entires = [findall(x->any(x .∈ vtx_edge_connectivity[1:end.!=j]),vtx_edge_connectivity[j]) for j = 1:length(vtx_edge_connectivity)] -edge_Γ_D = unique(reduce(vcat,getindex.(vtx_edge_connectivity,edge_entires),init=[])) -labels.d_to_dface_to_entity[1][vtxs_Γ_D] .= entity -labels.d_to_dface_to_entity[2][edge_Γ_D] .= entity -add_tag!(labels,"Gamma_D",[entity]) -# Γ_N -entity = num_entities(labels) + 1 -# Vertices -vtxs_Γ_N = findall(isone,f_Γ_N.(vtx_coords)) -vtx_edge_connectivity = Array(model.grid_topology.n_m_to_nface_to_mfaces[1,2][vtxs_Γ_N]); -# Edges -edge_entires = [findall(x->any(x .∈ vtx_edge_connectivity[(1:end.!=j)]),vtx_edge_connectivity[j]) for j = 1:length(vtx_edge_connectivity)] -edge_Γ_N = unique(reduce(vcat,getindex.(vtx_edge_connectivity,edge_entires),init=[])) -labels.d_to_dface_to_entity[1][vtxs_Γ_N] .= entity -labels.d_to_dface_to_entity[2][edge_Γ_N] .= entity -add_tag!(labels,"Gamma_N",[entity]) -## Triangulations and measures -Ω = Triangulation(model) -Γ_N = BoundaryTriangulation(model,tags="Gamma_N") -dΩ = Measure(Ω,2order) -dΓ_N = Measure(Γ_N,2order) -## Spaces -reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) -V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["Gamma_D"], - dirichlet_masks=[(true,true)],vector_type=Vector{Float64}) -U = TrialFESpace(V,[VectorValue(0.0,0.0)]) -# Space for shape sensitivities -reffe_scalar = ReferenceFE(lagrangian,Float64,order) -V_L2 = TestFESpace(model,reffe_scalar;conformity=:L2) -# FE space for LSF -V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) -# FE Space for shape derivatives -V_reg = TestFESpace(model,reffe_scalar;conformity=:H1, - dirichlet_tags=["Gamma_N"],dirichlet_masks=[true]) -U_reg = TrialFESpace(V_reg,[0.0]) -###################################################### -eΔ = (xmax,ymax)./el_size; -interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(eΔ)) -C = isotropic_2d(1.,0.3) -g = VectorValue(0.,-1.0) -φh = interpolate(x->-sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)+0.25,V_φ) - -## Weak form -I = interp.I; - -function ϕ_to_ϕₕ(ϕ::AbstractArray,Q) - ϕ = FEFunction(Q,ϕ) -end -function ϕ_to_ϕₕ(ϕ::FEFunction,Q) - ϕ -end -function ϕ_to_ϕₕ(ϕ::CellField,Q) - ϕ -end - -function a(u,v,φ) - φh = ϕ_to_ϕₕ(φ,V_φ) - ∫((I ∘ φh)*(C ⊙ ε(u) ⊙ ε(v)))dΩ -end -a(φ) = (u,v) -> a(u,v,φ) - -l(v,φh) = ∫(v ⋅ g)dΓ_N -l(φ) = v -> l(v,φ) - -res(u,v,φ,V_φ) = a(u,v,φ) - l(v,φ) - -φ = φh.free_values - -## Solve finite element problem -op = AffineFEOperator(a(φ),l(φ),U,V) -K = op.op.matrix; -## Solve -uh = solve(op) -## Compute J and v_J -_J(u,φ) = (a(u,u,φ)) # ∫(interp.ρ ∘ φ)dΩ -# _J(u,φ) = ∫(1+(u⋅u)*(u⋅u)+φ)dΩ # <- weird stuff works here - - -φ_to_u = AffineFEStateMap(a,l,res,V_φ,U,V) -u_to_j = LossFunction(_J,V_φ,U) - -u, u_pullback = rrule(φ_to_u,φ) -j, j_pullback = rrule(u_to_j,u,φ) -_, du, dϕ₍ⱼ₎ = j_pullback(1) # dj = 1 -_, dϕ₍ᵤ₎ = u_pullback(du) - dϕ = dϕ₍ᵤ₎ + dϕ₍ⱼ₎ - -function φ_to_j(φ) - u = φ_to_u(φ) - j = u_to_j(u,φ) -end - -j,dφ = Zygote.withgradient(φ_to_j,φ) - -sum(_J(uh,φh)) -j - -## Shape derivative -# Autodiff -dϕh = interpolate_everywhere(FEFunction(V_φ,dϕ),U_reg) - -# Analytic -J′(v,v_h) = ∫(-v_h*v*(interp.DH ∘ φh)*(norm ∘ ∇(φh)))dΩ; -v_J = -(C ⊙ ε(uh) ⊙ ε(uh)) -b = assemble_vector(v->J′(v,v_J),V_reg) -analytic_J′ = FEFunction(V_reg,b) - -abs_error = abs(dϕh-analytic_J′) -rel_error = (abs(dϕh-analytic_J′))/abs(analytic_J′) - -############################# -## Hilb ext reg -α = 4*maximum(eΔ) -A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; -hilb_K = assemble_matrix(A,U_reg,V_reg) - -## Autodiff result -# -dϕh is AD version of J′ that we plug in usually! -op = AffineFEOperator(U_reg,V_reg,hilb_K,dϕh.free_values) -dϕh_Ω = solve(op) - -## Analytic result -b = assemble_vector(v->J′(v,v_J),V_reg) -op = AffineFEOperator(U_reg,V_reg,hilb_K,b) -v_J_Ω = solve(op) - -hilb_abs_error = abs(dϕh_Ω-v_J_Ω) -hilb_rel_error = (abs(dϕh_Ω-v_J_Ω))/abs(v_J_Ω) - -path = dirname(dirname(@__DIR__))*"/results/AutoDiffTesting"; -writevtk(Ω,path,cellfields=["phi"=>φh, - "H(phi)"=>(interp.H ∘ φh), - "|nabla(phi)|"=>(norm ∘ ∇(φh)), - "uh"=>uh, - "J′_abs_error"=>abs_error, - "J′_rel_error"=>rel_error, - "J′_analytic"=>analytic_J′, - "J′_autodiff"=>dϕh, - "hilb_abs_error"=>hilb_abs_error, - "hilb_rel_error"=>hilb_rel_error, - "v_J_Ω"=>v_J_Ω, - "dJϕh_Ω"=>dϕh_Ω -]) -# end \ No newline at end of file diff --git a/Deprecated/dg_upwinding_tests.jl b/Deprecated/dg_upwinding_tests.jl deleted file mode 100644 index 006584fe..00000000 --- a/Deprecated/dg_upwinding_tests.jl +++ /dev/null @@ -1,63 +0,0 @@ - -using Gridap -using Gridap.Geometry, Gridap.FESpaces, Gridap.ReferenceFEs -using GridapDistributed, PartitionedArrays - -nprocs = (2,1) -ranks = with_debug() do distribute - distribute(LinearIndices((prod(nprocs),))) -end - -D = 2 -nc = (10,1) -domain = (0,1,0,1) -model = CartesianDiscreteModel(ranks,nprocs,domain,nc;isperiodic=(true,false)) - -order = 2 -poly = QUAD -reffe = LagrangianRefFE(Float64,poly,order) -V = FESpace(model,reffe) - -cell_masks = map(local_views(model)) do model - coords = get_node_coordinates(model) - cell_ids = get_cell_node_ids(model) - JaggedArray(map(ids -> lazy_map(Reindex(coords),ids),cell_ids)) -end -gids = get_cell_gids(model) -p_coords = PVector(cell_coords,partition(gids)) -consistent!(p_coords) |> fetch - - -function mark_nodes(f,model) - local_masks = map(local_views(model)) do model - topo = get_grid_topology(model) - coords = get_vertex_coordinates(topo) - mask = map(f,coords) - return mask - end - gids = get_face_gids(model,0) - mask = PVector(local_masks,partition(gids)) - assemble!(|,mask) |> fetch - consistent!(mask) |> fetch - return mask -end - -fΓ(x::T) where T = (x ≈ zero(T)) -mask = mark_nodes(fΓ,model) - - -gids = get_face_gids(model,0) -local_masks = map(local_views(model),partition(gids)) do model, gids - topo = get_grid_topology(model) - coords = get_vertex_coordinates(topo) - mask = map(fΓ,coords) - println(mask) - println(local_to_owner(gids)) - return nothing -end - - - -_model = CartesianDiscreteModel(domain,nc) -coords1 = get_node_coordinates(_model) -coords2 = get_vertex_coordinates(get_grid_topology(_model)) diff --git a/Deprecated/elastic_compliance_for_jordi.jl b/Deprecated/elastic_compliance_for_jordi.jl deleted file mode 100644 index ad149f7f..00000000 --- a/Deprecated/elastic_compliance_for_jordi.jl +++ /dev/null @@ -1,128 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR - -import GridapDistributed.DistributedCellField -import GridapDistributed.DistributedFESpace -import GridapDistributed.DistributedDiscreteModel -import GridapDistributed.DistributedMeasure - -include("Utilities.jl"); # <- For some useful functions - -# Make script for Jordi that can take msh size and processors for modifying PETSc (3D) + lsf fn. - -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - el_size = (100,50,50) - coord_max = (2.,1.,1.) - order = 1; - Δ = coord_max./el_size; - path = (@__DIR__)*"/Results/LinearElastic3DSolverTesting"; - t = PTimer(ranks) - GridapPETSc.with(args=split(options)) do - model,Ω,V_φ,solve_data = fe_setup(ranks,mesh_partition,order,coord_max,el_size) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(Δ)) - C = _isotropic_3d(1.,0.3) - g = VectorValue(0.,0.,-1.0) - φh = interpolate(x->-sqrt((x[1]-0.5)^2+(x[2]-0.5)^2+(x[3]-0.5)^2)+0.25,V_φ) - J,v_J,uh = elastic_compliance(φh,g,C,solve_data,interp,t) - display("Objective = $J") - writevtk(Ω,path,cellfields=["phi"=>φh,"H(phi)"=>(interp.H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) - end - t -end - -function elastic_compliance(φh::DistributedCellField,g,C::S,solve_data::NT,interp::T,t) where { - S<:SymFourthOrderTensorValue,T<:SmoothErsatzMaterialInterpolation,NT<:NamedTuple} - I = interp.I; dΩ=solve_data.dΩ; dΓ_N=solve_data.dΓ_N; - ## Weak form - a(u,v,φh) = ∫((I ∘ φh)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v) = ∫(v ⋅ g)dΓ_N - ## Solve finite element problem - tic!(t) - op = AffineFEOperator(a,l,solve_data.U,solve_data.V,solve_data.assem) - toc!(t,"Assembly time") - K = op.op.matrix; - ## Solve - ls = PETScLinearSolver() - tic!(t) - uh = solve(ls,op) - toc!(t,"Solve time") - u = correct_ghost_layout(uh,K.col_partition) - ## Compute J and v_J - # J = dot(u,(K*u)) - _J(φh) = sum(a(uh,uh,φh)) - J = _J(φh) - - # dJ/dφ_h # <- AD? - - tic!(t) - v_J = interpolate(-C ⊙ ε(uh) ⊙ ε(uh),solve_data.V_L2) - toc!(t,"Interpolate shape sensitivity") - return J,v_J,uh -end - -function fe_setup(ranks,mesh_partition,order::T,coord_max::NTuple{3,M}, - el_size::NTuple{3,T}) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2],0,coord_max[3]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - xmax,ymax,zmax = coord_max - prop_Γ_N = 0.4 - f_Γ_D(x) = (x[1] ≈ 0.0) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps() && zmax/2-zmax*prop_Γ_N/4 - eps() <= x[3] - <= zmax/2+zmax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,coord_max,"Gamma_D") - update_labels!(2,model,f_Γ_N,coord_max,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["Gamma_D"], - dirichlet_masks=[(true,true,true)]) - U = TrialFESpace(V,[VectorValue(0.0,0.0,0.0)]) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V_L2 = TestFESpace(model,reffe_scalar;conformity=:L2) - # FE space for LSF - V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=dΓ_N) - return model,Ω,V_φ,solve_data -end - -function _isotropic_3d(E::M,nu::M) where M<:AbstractFloat - λ = E*nu/((1+nu)*(1-2nu)); μ = E/(2*(1+nu)) - C =[λ+2μ λ λ 0 0 0 - λ λ+2μ λ 0 0 0 - λ λ λ+2μ 0 0 0 - 0 0 0 μ 0 0 - 0 0 0 0 μ 0 - 0 0 0 0 0 μ]; - return SymFourthOrderTensorValue( - C[1,1], C[6,1], C[5,1], C[2,1], C[4,1], C[3,1], - C[1,6], C[6,6], C[5,6], C[2,6], C[4,6], C[3,6], - C[1,5], C[6,5], C[5,5], C[2,5], C[4,5], C[3,5], - C[1,2], C[6,2], C[5,2], C[2,2], C[4,2], C[3,2], - C[1,4], C[6,4], C[5,4], C[2,4], C[4,4], C[3,4], - C[1,3], C[6,3], C[5,3], C[2,3], C[4,3], C[3,3]) -end - -t = with_debug() do distribute - main((3,3,3),distribute) -end; -display(t) diff --git a/Deprecated/get_dof_coords.jl b/Deprecated/get_dof_coords.jl deleted file mode 100644 index 99b909bb..00000000 --- a/Deprecated/get_dof_coords.jl +++ /dev/null @@ -1,72 +0,0 @@ - -using Gridap, GridapDistributed, PartitionedArrays, GridapPETSc -using Gridap.Geometry, Gridap.FESpaces, Gridap.ReferenceFEs, Gridap.CellData, Gridap.Arrays -using FillArrays - -function get_dof_coordinates(space::GridapDistributed.DistributedSingleFieldFESpace) - coords = map(local_views(space),partition(space.gids)) do space, dof_ids - local_to_own_dofs = local_to_own(dof_ids) - return get_dof_coordinates(space;perm=local_to_own_dofs) - end - - ngdofs = length(space.gids) - indices = map(local_views(space.gids)) do dof_indices - owner = part_id(dof_indices) - own_indices = OwnIndices(ngdofs,owner,own_to_global(dof_indices)) - ghost_indices = GhostIndices(ngdofs,Int64[],Int32[]) # We only consider owned dofs - OwnAndGhostIndices(own_indices,ghost_indices) - end - return PVector(coords,indices) -end - -function get_dof_coordinates(space::FESpace;perm=Base.OneTo(num_free_dofs(space))) - trian = get_triangulation(space) - cell_dofs = get_fe_dof_basis(space) - cell_ids = get_cell_dof_ids(space) - - cell_ref_nodes = lazy_map(get_nodes,CellData.get_data(cell_dofs)) - cell_dof_to_node = lazy_map(get_dof_to_node,CellData.get_data(cell_dofs)) - cell_dof_to_comp = lazy_map(get_dof_to_comp,CellData.get_data(cell_dofs)) - - cmaps = get_cell_map(trian) - cell_phys_nodes = lazy_map(evaluate,cmaps,cell_ref_nodes) - - node_coords = Vector{Float64}(undef,maximum(perm)) - cache_nodes = array_cache(cell_phys_nodes) - cache_ids = array_cache(cell_ids) - cache_dof_to_node = array_cache(cell_dof_to_node) - cache_dof_to_comp = array_cache(cell_dof_to_comp) - for cell in 1:num_cells(trian) - ids = getindex!(cache_ids,cell_ids,cell) - nodes = getindex!(cache_nodes,cell_phys_nodes,cell) - dof_to_comp = getindex!(cache_dof_to_comp,cell_dof_to_comp,cell) - dof_to_node = getindex!(cache_dof_to_node,cell_dof_to_node,cell) - for (dof,c,n) in zip(ids,dof_to_comp,dof_to_node) - if (dof > 0) && (perm[dof] > 0) - node_coords[perm[dof]] = nodes[n][c] - end - end - end - return node_coords -end - -function ReferenceFEs.get_dof_to_node(a::LagrangianDofBasis) - return a.dof_to_node -end -function ReferenceFEs.get_dof_to_comp(a::LagrangianDofBasis) - return a.dof_to_comp -end - -np = (2,1) -ranks = with_debug() do distribute - distribute(LinearIndices((prod(np),))) -end - -model = CartesianDiscreteModel(ranks,np,(0,1,0,1),(4,2)) -Dc = num_cell_dims(model) - -order = 3 -reffe = ReferenceFE(lagrangian,VectorValue{Dc,Float64},order) -space = FESpace(model,reffe) - -node_coords = get_dof_coordinates(space) diff --git a/Deprecated/permutation_tests.jl b/Deprecated/permutation_tests.jl deleted file mode 100644 index 7fbed8c4..00000000 --- a/Deprecated/permutation_tests.jl +++ /dev/null @@ -1,72 +0,0 @@ -using Gridap -using Gridap.Geometry, Gridap.FESpaces, Gridap.ReferenceFEs, Gridap.Helpers -using GridapDistributed, PartitionedArrays -using CircularArrays - -function create_dof_permutation(model::CartesianDiscreteModel{Dc}, - space::UnconstrainedFESpace, - order::Integer) where Dc - function get_terms(poly::Polytope, orders) - _nodes, facenodes = Gridap.ReferenceFEs._compute_nodes(poly, orders) - terms = Gridap.ReferenceFEs._coords_to_terms(_nodes, orders) - return terms - end - desc = get_cartesian_descriptor(model) - - periodic = desc.isperiodic - ncells = desc.partition - ndofs = order .* ncells .+ 1 .- periodic - @check prod(ndofs) == num_free_dofs(space) - - new_dof_ids = CircularArray(LinearIndices(ndofs)) - n2o_dof_map = fill(-1,num_free_dofs(space)) - - terms = get_terms(first(get_polytopes(model)), fill(order,Dc)) - cell_dof_ids = get_cell_dof_ids(space) - cache_cell_dof_ids = array_cache(cell_dof_ids) - for (iC,cell) in enumerate(CartesianIndices(ncells)) - first_new_dof = order .* (Tuple(cell) .- 1) .+ 1 - new_dofs_range = map(i -> i:i+order,first_new_dof) - new_dofs = view(new_dof_ids,new_dofs_range...) - - cell_dofs = getindex!(cache_cell_dof_ids,cell_dof_ids,iC) - for (iDof, dof) in enumerate(cell_dofs) - t = terms[iDof] - n2o_dof_map[new_dofs[t]] = dof - end - end - - return n2o_dof_map -end - -function create_dof_permutation(model::GridapDistributed.DistributedDiscreteModel, - space::GridapDistributed.DistributedFESpace, - order::Integer) where Dc - local_perms = map(local_views(model),local_views(space)) do model, space - create_dof_permutation(model,space,order) - end - return local_perms -end - -D = 2 -np = Tuple(fill(2,D)) - -ranks = with_debug() do distribute - distribute(LinearIndices((prod(np),))) -end - -nc = (D==2) ? (2,2) : (2,2,2) -domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) -#model = CartesianDiscreteModel(ranks,np,domain,nc) -model = CartesianDiscreteModel(domain,(4,3),isperiodic=(true,false)) - -order = 2 -poly = (D==2) ? QUAD : HEX -reffe = LagrangianRefFE(Float64,poly,order) -space = FESpace(model,reffe) - -perm_gids = create_dof_permutation(model,space,order) - -uh = interpolate(x->x[1]-x[2],space) -x = get_free_dof_values(uh) -x_perm = pfill(0.0,partition(perm_gids)); diff --git a/Deprecated/test_periodic_finitediff.jl b/Deprecated/test_periodic_finitediff.jl deleted file mode 100644 index 08d9b16a..00000000 --- a/Deprecated/test_periodic_finitediff.jl +++ /dev/null @@ -1,160 +0,0 @@ -using SparseMatricesCSR -using SparseArrays -using Gridap, Gridap.TensorValues, Gridap.Geometry -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using DelimitedFiles -using LinearAlgebra -using Printf - -import GridapDistributed.DistributedCellField -import GridapDistributed.DistributedFESpace -import GridapDistributed.DistributedDiscreteModel -import GridapDistributed.DistributedMeasure - -include("Utilities.jl"); -include("LevelSet.jl"); -include("Setup.jl"); - -function setup_mock_2d() - ## FE setup name and objective - prob = mock_2d - obj = thermal_compliance - vf = 0.5; # Required volume fraction - ## Material and loading - D = 1.0 # Thermal coefficient - g = 1.0; # Heat flow - ## FE Parameters - fe_order = 1; - coord_max=(1.0,1.0); - el=(200,200); # Elements in axial directions - ## LS Paramters - lsf = gen_lsf(4,0.2); # Initial LSF - η_coeff = 2 # Interpolation radius coefficent - α_coeff = 4 # Hilbertian smoothing coefficent - μ=0.005 # Line search parameter - γ,γ_min,γ_max = [0.05,0.001,0.1] # CFL Coefficent - steps = Int(floor(minimum(el)/10)) # Finite diff. steps - reinit_tol = min(4*prod(inv,el),10^-4) # Reinit tol. - - return prob,obj,lsf,vf,D,g,fe_order,coord_max,el, - η_coeff,α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol -end - -function mock_2d(ranks,mesh_partition,order::T,coord_max::NTuple{2,M}, - el_size::NTuple{2,T},α::M,isperiodic) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(isperiodic,isperiodic)); - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;conformity=:H1) - U = TrialFESpace(V) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - V_L2 = TestFESpace(model,reffe;conformity=:L2) - # Space in Hilb. ext.-reg. endowed with H-regularity - V_reg = TestFESpace(model,reffe;conformity=:H1) - U_reg = TrialFESpace(V_reg) - # FE space for LSF - V_φ = TestFESpace(model,reffe;conformity=:H1) - ## Build stiffness matrix for Hilbertian ext-reg - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=nothing) - hilb_data = (U_reg=U_reg,V_reg=V_reg,assem=Hilb_assem,dΩ=dΩ,K=K) - return model,Ω,V_φ,solve_data,hilb_data -end - -function setup_mock_3d() - ## FE setup name - prob = mock_3d - obj = thermal_compliance - vf = 0.5; # Required volume fraction - ## Material and loading - D = 1.0 # Thermal coefficient - g = 3.0 # Heat flow - ## FE Parameters - fe_order = 1; - coord_max=(1.0,1.0,1.0); - el=(100,100,100); # Elements in axial directions - ## LS Paramters - lsf = gen_lsf(4,0.2); # Initial LSF - η_coeff = 2 # Interpolation radius coefficent - α_coeff = 4 # Hilbertian smoothing coefficent - μ=0.005 # Line search parameter - γ,γ_min,γ_max = [0.1,0.001,0.1] # CFL Coefficent - steps = Int(floor(minimum(el)/3)); # Finite diff. steps - reinit_tol = min(1000*prod(inv,el),10^-3) # Reinit tol. - - return prob,obj,lsf,vf,D,g,fe_order,coord_max,el, - η_coeff,α_coeff,μ,γ_max,γ_min,γ,steps,reinit_tol -end - -function mock_3d(ranks,mesh_partition,order::T,coord_max::NTuple{3,M}, - el_size::NTuple{3,T},α::M,isperiodic) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2],0,coord_max[3]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(isperiodic,isperiodic,isperiodic)); - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;conformity=:H1) - U = TrialFESpace(V) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - V_L2 = TestFESpace(model,reffe;conformity=:L2) - # Space in Hilb. ext.-reg. endowed with H-regularity - V_reg = TestFESpace(model,reffe;conformity=:H1) - U_reg = TrialFESpace(V_reg) - # FE space for LSF - V_φ = TestFESpace(model,reffe;conformity=:H1) - ## Build stiffness matrix for Hilbertian ext-reg - A(u,v) = α^2*∫(∇(u) ⊙ ∇(v))dΩ + ∫(u ⋅ v)dΩ; - Hilb_assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg) - K = assemble_matrix(A,Hilb_assem,U_reg,V_reg) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=nothing) - hilb_data = (U_reg=U_reg,V_reg=V_reg,assem=Hilb_assem,dΩ=dΩ,K=K) - return model,Ω,V_φ,solve_data,hilb_data -end - -mesh_partition = (3,3); -isperiodic = false; -prob_setup = setup_mock_2d; - -ranks = with_debug() do distribute - ranks = distribute(LinearIndices((prod(mesh_partition),))); -end - -prob,obj,lsf,vf,mat,g,fe_order,coord_max,el,η_coeff,α_coeff,_,_,_,γ,steps,reinit_tol = prob_setup() -Δ = coord_max./el # Element size -η = η_coeff*maximum(Δ); α = α_coeff*maximum(Δ) # Smoothing parameters -interp = SmoothErsatzMaterialInterpolation(η=η) # Material interpolation -model,Ω,V_φ,solve_data,hilb_data = prob(ranks,mesh_partition,fe_order,coord_max,el,α,isperiodic); - -φh = interpolate(lsf,V_φ) -φ = get_free_dof_values(φh) -reinit!(φ,model,Δ,0.5,2000,reinit_tol) - -vh = interpolate(x->1,V_φ) -v = get_free_dof_values(vh) -advect!(φ,v,model,Δ,γ,50) -reinit!(φ,model,Δ,0.5,2000,reinit_tol) - -writevtk(Ω,(@__DIR__)*"\\Results\\test_reinit_2d_plus_advect",cellfields=["phi"=>φh,"H(phi)"=>(interp.H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]); diff --git a/Deprecated/tests.jl b/Deprecated/tests.jl deleted file mode 100644 index d0232114..00000000 --- a/Deprecated/tests.jl +++ /dev/null @@ -1,173 +0,0 @@ -using FillArrays - -using Gridap -using Gridap.Geometry, Gridap.Arrays -using Gridap.Geometry: get_faces - -using GridapDistributed, PartitionedArrays - -############################################################################################ - -function EdgeTriangulation(model::DiscreteModel{Dc}) where Dc - EdgeTriangulation(model,Base.OneTo(Geometry.num_faces(model,1))) -end - -function EdgeTriangulation(model::DiscreteModel{Dc},tags) where Dc - labeling = get_face_labeling(model) - face_to_mask = get_face_mask(labeling,tags,1) - face_to_bgface = findall(face_to_mask) - return EdgeTriangulation(model,face_to_bgface) -end - -function EdgeTriangulation( - model::DiscreteModel{Dc}, - face_to_bgface::AbstractVector{<:Integer}) where {Dc} - - topo = get_grid_topology(model) - bgface_grid = Grid(Geometry.ReferenceFE{1},model) - bgface_to_lcell = Fill(1,Geometry.num_faces(model,1)) - - face_grid = view(bgface_grid,face_to_bgface) - cell_grid = get_grid(model) - glue = Geometry.FaceToCellGlue(topo,cell_grid,face_grid,face_to_bgface,bgface_to_lcell) - trian = BodyFittedTriangulation(model,face_grid,face_to_bgface) - - BoundaryTriangulation(trian,glue) -end - -function EdgeTriangulation(model::GridapDistributed.DistributedDiscreteModel) - trians = map(EdgeTriangulation,local_views(model)) - return GridapDistributed.DistributedTriangulation(trians,model) -end - -function get_edge_coordinates(model::DiscreteModel) - topo = get_grid_topology(model) - get_edge_coordinates(topo) -end - -function get_edge_coordinates(topo::GridTopology) - e2n_map = Geometry.get_faces(topo,1,0) - node_coords = Geometry.get_vertex_coordinates(topo) - edge_coords = lazy_map(nodes->lazy_map(Reindex(node_coords),nodes),e2n_map) - return edge_coords -end - -function get_tangent_vector(trian::Triangulation{1}) - function my_tangent(m) - t = m(VectorValue(1.0)) - m(VectorValue(0.0)) - return t/norm(t) - end - cmaps = get_cell_map(trian) - return CellField(lazy_map(my_tangent,cmaps),trian) -end - -function get_tangent_vector(trian::GridapDistributed.DistributedTriangulation) - fields = map(get_tangent_vector,local_views(trian)) - GridapDistributed.DistributedCellField(fields) -end - -""" - `edge_orientation(edge_coords)` - - Returns: - 1 : if the edge is in the x-direction - 2 : if the edge is in the y-direction - 3 : if the edge is in the z-direction (only 3D) -""" -function edge_orientation(edge_coords) - v = edge_coords[1]-edge_coords[2] - return findfirst(x -> abs(x) > 1.e-3,v.data) -end - -""" - Returns a table that for each node contains the adjacent edge ids. - - If the edge is missing (for instance in boundaries), the corresponding entry is -1. - - For each node, the edges are ordered as follows: - [x-outgoing, x-incoming, y-outgoing, y-incoming, z-outgoing, z-incoming] -""" -function get_node_edge_nbors(model::DiscreteModel{Dc}) where Dc - num_edges_x_node = (Dc==2) ? 4 : 6 - ptrs = zeros(Int,num_faces(model,0)+1); ptrs[1] = 1; ptrs[2:end] .= num_edges_x_node; - Gridap.Algebra.length_to_ptrs!(ptrs) - - e2n_map = Geometry.get_faces(get_grid_topology(model),1,0) - orientations = lazy_map(edge_orientation,get_edge_coordinates(model)) - - data = fill(-1,ptrs[end]-1) - e2n_map_cache = array_cache(e2n_map) - orientations_cache = array_cache(orientations) - for E in 1:num_faces(model,1) - E_nodes = getindex!(e2n_map_cache,e2n_map,E) - E_orientation = getindex!(orientations_cache,orientations,E) - for (iN,N) in enumerate(E_nodes) - # Edge ordering in each node: - # [x-outgoing, x-incoming, y-outgoing, y-incoming, z-outgoing, z-incoming] - id = 2*(E_orientation-1) + iN - data[ptrs[N]+id-1] = E - end - end - return Table(data,ptrs) -end - -function get_node_edge_nbors(model::GridapDistributed.DistributedDiscreteModel) - return map(get_node_edge_nbors,local_views(model)) -end - -""" - Returns a table that for each node contains the directional derivatives in adjacent edges: - - If the edge is missing (for instance in boundaries), the corresponding entry is 0.0. - - For each node, the derivatives are ordered as follows: - [d/dx⁺, -d/dx⁻, d/dy⁺, -d/dy⁻, d/dz⁺, -d/dz] -""" -function evaluate_derivatives(φ::FEFunction,Λ::Triangulation,edge_nbors,t) - quad = CellQuadrature(Λ,0) - pts = get_cell_points(quad) - - vals = lazy_map(first,(∇(φ)⋅t)(pts)) - idx = lazy_map(PosNegReindex(vals,[0.0]),edge_nbors.data) - return Table(idx,edge_nbors.ptrs) -end - -function evaluate_derivatives(φ::GridapDistributed.DistributedCellField, - Λ::GridapDistributed.DistributedTriangulation, - edge_nbors, - t) - return map(evaluate_derivatives,local_views(φ),local_views(Λ),edge_nbors,local_views(t)) -end - -############################################################################################ - -parallel = true -D = 3 - -if D == 2 - np = (2,1) - domain = (0,1,0,1) - nc = (4,4) -else - np = (2,1,1) - domain = (0,1,0,1,0,1) - nc = (4,4,4) -end - -if parallel - ranks = with_debug() do distribute - distribute(LinearIndices((prod(np),))) - end - model = CartesianDiscreteModel(ranks,np,domain,nc) -else - model = CartesianDiscreteModel(domain,nc) -end - -Ω = Triangulation(model) -Λ = EdgeTriangulation(model) -t = get_tangent_vector(Λ) -edge_nbors = get_node_edge_nbors(model) - -reffe = ReferenceFE(lagrangian,Float64,1) -V = FESpace(model,reffe) - -x = !parallel ? randn(num_free_dofs(V)) : prandn(partition(get_free_dof_ids(V))) -u = FEFunction(V,x) - -derivatives = evaluate_derivatives(u,Λ,edge_nbors,t) diff --git a/Deprecated/tests2.jl b/Deprecated/tests2.jl deleted file mode 100644 index 3ee428d8..00000000 --- a/Deprecated/tests2.jl +++ /dev/null @@ -1,42 +0,0 @@ -using GridapDistributed -using Gridap -using PartitionedArrays -using Gridap.FESpaces - -np = (2,1) -ranks = with_debug() do distribute - distribute(LinearIndices((prod(np),))) -end -model = CartesianDiscreteModel(ranks,np,(0,1,0,1),(5,1);isperiodic=(true,false)) - -reffe = ReferenceFE(lagrangian,Float64,1) -V = FESpace(model,reffe) - -dim = 2 -trian = Triangulation(model) -coords = map(local_views(trian)) do trian - node_coords = Gridap.Geometry.get_node_coordinates(trian) - coords = Vector{Float64}(undef,dim*length(node_coords)) - k = 1 - for p in node_coords - for d in 1:dim - coords[k] = p[d] - k += 1 - end - end - return coords -end - -x_vals = map(local_to_global,partition(V.gids)) -x = PVector(x_vals,partition(V.gids)) - -local_sizes = DebugArray([(5,2),(6,2)]) -y_vals = map(local_values(x),local_sizes) do x,sz - reshape(circshift(reshape(x,sz),(-1,0)),prod(sz)) -end -y = PVector(y_vals,partition(V.gids)) - -partition(y) -consistent!(y) |> fetch -partition(y) - diff --git a/Deprecated/tests3.jl b/Deprecated/tests3.jl deleted file mode 100644 index e9a31c6f..00000000 --- a/Deprecated/tests3.jl +++ /dev/null @@ -1,43 +0,0 @@ - -using Gridap, GridapDistributed, PartitionedArrays -using Gridap.Geometry, Gridap.FESpaces, Gridap.ReferenceFEs, Gridap.Adaptivity - -function get_terms(poly::Polytope, orders) - _nodes, facenodes = Gridap.ReferenceFEs._compute_nodes(poly, orders) - terms = Gridap.ReferenceFEs._coords_to_terms(_nodes, orders) - return terms -end - -function get_dof_map(poly::Polytope, orders) - maps1D = map(ord -> map(t -> t[1], get_terms(SEGMENT, [ord])), orders) - terms = get_terms(poly, orders) - dofmap = map(t -> CartesianIndex(map((x, m) -> findfirst(mi -> mi == x, m), Tuple(t), maps1D)), terms) - return dofmap -end - -model = CartesianDiscreteModel((0,1,0,1),(4,4)) - -order = 2 -reffe = ReferenceFE(lagrangian,Float64,order) -V = FESpace(model,reffe) - -reffe2 = LagrangianRefFE(Float64,QUAD,(2,1)) - -cell_dof_ids = get_cell_dof_ids(V) -n2c_map = Geometry.get_faces(get_grid_topology(model),0,2) - -rr = RefinementRule(QUAD,(2,2)) -rr_grid = Adaptivity.get_ref_grid(rr) -node_ids = get_cell_node_ids(rr_grid) - - -terms = get_terms(QUAD,(2*order,2*order)) -lindices = LinearIndices((2*order+1,2*order+1)) - -dof_to_node_layout = map(t -> lindices[t],terms) -node_to_dof_layout = Vector{Int}(undef,length(dof_to_node_layout)) -for (dof,node) in enumerate(dof_to_node_layout) - node_to_dof_layout[node] = dof -end - -cell_dofs = map(nodes -> node_to_dof_layout[nodes],node_ids) diff --git a/Deprecated/tests4.jl b/Deprecated/tests4.jl deleted file mode 100644 index e6646b9f..00000000 --- a/Deprecated/tests4.jl +++ /dev/null @@ -1,203 +0,0 @@ - -using Gridap -using Gridap.Arrays -using BenchmarkTools - -struct Stencil{D,S,T} <: Map - Δ::NTuple{D,T} - function Stencil(D::Integer,S::Tuple,Δ::Tuple) - T = eltype(Δ) - new{D,S,T}(Δ) - end -end - -@generated function get_stencil_indexes(::Stencil{2,S}, idx) where {S} - ileft = "(idx-1) % $(S[1]) == 0 ? -1 : idx - 1" - iright = "(idx-1) % $(S[1]) == $(S[1]-1) ? -1 : idx + 1" - idown = "(idx-1) ÷ $(S[1]) == 0 ? -1 : idx - $(S[1])" - iup = "(idx-1) ÷ $(S[1]) == $(S[2]-1) ? - 1 : idx + $(S[1])" - return Meta.parse("return ($ileft, $iright, $idown, $iup)") -end - -@generated function compute_derivatives(s::Stencil{2,S},i,x) where S - im = "i - 1" - ip = "i + 1" - jm = "i - $(S[1])" - jp = "i + $(S[1])" - - dx⁻ = "(i-1) % $(S[1]) == 0 ? 0.0 : (x[i]-x[$im])/s.Δ[1]" - dx⁺ = "(i-1) % $(S[1]) == $(S[1]-1) ? 0.0 : (x[$ip]-x[i])/s.Δ[1]" - dy⁻ = "(i-1) ÷ $(S[1]) == 0 ? 0.0 : (x[i]-x[$jm])/s.Δ[2]" - dy⁺ = "(i-1) ÷ $(S[1]) == $(S[2]-1) ? 0.0 : (x[$jp]-x[i])/s.Δ[2]" - return Meta.parse("return ($dx⁻,$dx⁺,$dy⁻,$dy⁺)") -end - -@generated function compute_derivatives(::Stencil{3,S},i,x) where S - im = "i - 1" - ip = "i + 1" - jm = "i - $(S[1])" - jp = "i + $(S[1])" - km = "i - $(S[1])*$(S[2])" - kp = "i + $(S[1])*$(S[2])" - - dx⁻ = "(i-1) % $(S[1]) == 0 ? 0.0 : (x[i]-x[$im])/s.Δ[1]" - dx⁺ = "(i-1) % $(S[1]) == $(S[1]-1) ? 0.0 : (x[$ip]-x[i])/s.Δ[1]" - dy⁻ = "((i-1) ÷ $(S[1]) % $(S[2])) == 0 ? 0.0 : (x[i]-x[$jm])/s.Δ[2]" - dy⁺ = "((i-1) ÷ $(S[1]) % $(S[2])) == $(S[2]-1) ? 0.0 : (x[$jp]-x[i])/s.Δ[2]" - dz⁻ = "(i-1) ÷ $(S[1]*S[2]) == 0 ? 0.0 : (x[i]-x[$km])/s.Δ[3]" - dz⁺ = "(i-1) ÷ $(S[1]*S[2]) == $(S[3]-1) ? 0.0 : (x[$kp]-x[i])/s.Δ[3]" - return Meta.parse("return ($dx⁻,$dx⁺,$dy⁻,$dy⁺,$dz⁻,$dz⁺)") -end - -@generated function compute_derivatives(::Stencil{3,S},i,x,dx) where S - im = "i - 1" - ip = "i + 1" - jm = "i - $(S[1])" - jp = "i + $(S[1])" - km = "i - $(S[1])*$(S[2])" - kp = "i + $(S[1])*$(S[2])" - - body = "" - body *= "dx[1] = (i-1) % $(S[1]) == 0 ? 0.0 : (x[i]-x[$im])/s.Δ[1]; " - body *= "dx[2] = (i-1) % $(S[1]) == $(S[1]-1) ? 0.0 : (x[$ip]-x[i])/s.Δ[1]; " - body *= "dx[3] = ((i-1) ÷ $(S[1]) % $(S[2])) == 0 ? 0.0 : (x[i]-x[$jm])/s.Δ[2]; " - body *= "dx[4] = ((i-1) ÷ $(S[1]) % $(S[2])) == $(S[2]-1) ? 0.0 : (x[$jp]-x[i])/s.Δ[2]; " - body *= "dx[5] = (i-1) ÷ $(S[1]*S[2]) == 0 ? 0.0 : (x[i]-x[$km])/s.Δ[3]; " - body *= "dx[6] = (i-1) ÷ $(S[1]*S[2]) == $(S[3]-1) ? 0.0 : (x[$kp]-x[i])/s.Δ[3]; " - return Meta.parse("begin $body return dx end") -end - -macro index_to_tuple(idx, D1, D2, D3) - return esc(:( - ($idx - 1) % $D1 + 1, - (($idx - 1) ÷ $D1) % $D2 + 1, - ($idx - 1) ÷ ($D1 * $D2) + 1)) -end - -function reinit!(s::Stencil{2},φ_out,φ_in,S,Δt,caches) - D⁻ˣ,D⁺ˣ,D⁻ʸ,D⁺ʸ,∇⁺,∇⁻ = caches - for i in 1:length(φ_in) - D⁻ˣ[i],D⁺ˣ[i],D⁻ʸ[i],D⁺ʸ[i] = compute_derivatives(s,i,φ_in) - end - - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2) - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2) - φ_out .= @. φ_in - Δt*(max(S,0)*∇⁺ + min(S,0)*∇⁻ - S) - return φ_out -end - -function reinit!(s::Stencil{3},φ_out,φ_in,S,Δt,caches) - D⁻ˣ,D⁺ˣ,D⁻ʸ,D⁺ʸ,D⁻ᶻ,D⁺ᶻ,∇⁺,∇⁻ = caches - res = zeros(6) - for i in 1:length(φ_in) - compute_derivatives(s,i,φ_in,res) - D⁻ˣ[i],D⁺ˣ[i],D⁻ʸ[i],D⁺ʸ[i],D⁻ᶻ[i],D⁺ᶻ[i] = res[1], res[2], res[3], res[4], res[5], res[6] - end - - #∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2); - #∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2); - #φ_out .= @. φ_in - Δt*(max(S,0)*∇⁺ + min(S,0)*∇⁻ - S) - return φ_out -end - -function reinit_step!(φ::T,φ_tmp::T,S::T,g_loc::NTuple{4,Bool},Δ::NTuple{2,M},Δt::M,caches) where {M,T<:Array{M,2}} - (X⁻,X⁺,Y⁻,Y⁺) = g_loc - D⁻ˣ,D⁺ˣ,D⁻ʸ,D⁺ʸ,∇⁺,∇⁻ = caches - Δx,Δy = Δ - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)); - circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)); - # Forward (+) & Backward (-) - D⁺ʸ .= @. (D⁺ʸ - φ)/Δy; - D⁺ˣ .= @. (D⁺ˣ - φ)/Δx; - D⁻ʸ .= @. (φ - D⁻ʸ)/Δy; - D⁻ˣ .= @. (φ - D⁻ˣ)/Δx; - # Check for boundaries with ghost nodes - (~Y⁺) ? D⁺ʸ[:,end] .= zero(M) : 0; - (~X⁺) ? D⁺ˣ[end,:] .= zero(M) : 0; - (~Y⁻) ? D⁻ʸ[:,1] .= zero(M) : 0; - (~X⁻) ? D⁻ˣ[1,:] .= zero(M) : 0; - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2); - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2); - # Update - φ_tmp .= @. φ - Δt*(max(S,0)*∇⁺ + min(S,0)*∇⁻ - S); - return nothing -end - -function reinit_step!(φ::T,φ_tmp::T,S::T,g_loc::NTuple{6,Bool},Δ::NTuple{3,M},Δt::M,caches) where {M,T<:Array{M,3}} - (X⁻,X⁺,Y⁻,Y⁺,Z⁻,Z⁺) = g_loc - D⁻ˣ,D⁺ˣ,D⁻ʸ,D⁺ʸ,D⁻ᶻ,D⁺ᶻ,∇⁺,∇⁻ = caches - Δx,Δy,Δz = Δ - # Prepare shifted lsf - circshift!(D⁺ʸ,φ,(0,-1)); circshift!(D⁻ʸ,φ,(0,1)); - circshift!(D⁺ˣ,φ,(-1,0)); circshift!(D⁻ˣ,φ,(1,0)); - circshift!(D⁺ᶻ,φ,(0,0,-1)); circshift!(D⁻ᶻ,φ,(0,0,1)); - # Forward (+) & Backward (-) - D⁺ʸ .= (D⁺ʸ - φ)/Δy; - D⁺ˣ .= (D⁺ˣ - φ)/Δx; - D⁺ᶻ .= (D⁺ᶻ - φ)/Δz; - D⁻ʸ .= (φ - D⁻ʸ)/Δy; - D⁻ˣ .= (φ - D⁻ˣ)/Δx; - D⁻ᶻ .= (φ - D⁻ᶻ)/Δz; - # Check for boundaries with ghost nodes - (~Y⁺) ? D⁺ʸ[:,end,:] .= zero(M) : 0; - (~X⁺) ? D⁺ˣ[end,:,:] .= zero(M) : 0; - (~Z⁺) ? D⁺ᶻ[:,:,end] .= zero(M) : 0; - (~Y⁻) ? D⁻ʸ[:,1,:] .= zero(M) : 0; - (~X⁻) ? D⁻ˣ[1,:,:] .= zero(M) : 0; - (~Z⁻) ? D⁻ᶻ[:,:,1] .= zero(M) : 0; - # Operators - ∇⁺ .= @. sqrt(max(D⁻ʸ,0)^2 + min(D⁺ʸ,0)^2 + max(D⁻ˣ,0)^2 + min(D⁺ˣ,0)^2 + max(D⁻ᶻ,0)^2 + min(D⁺ᶻ,0)^2); - ∇⁻ .= @. sqrt(max(D⁺ʸ,0)^2 + min(D⁻ʸ,0)^2 + max(D⁺ˣ,0)^2 + min(D⁻ˣ,0)^2 + max(D⁺ᶻ,0)^2 + min(D⁻ᶻ,0)^2); - # Update - φ_tmp .= @. φ - Δt*(max(S,0)*∇⁺ + min(S,0)*∇⁻ - S); - return nothing -end - -# 2D -sz = (1000,1012); n = prod(sz) -s = Stencil(2,sz,(0.5,0.5)) - -x = randn(n) -vel = ones(n); vel[[1,3,6,8,12,14]] .= 0; - -y1 = zeros(n) -caches = zeros(n),zeros(n),zeros(n),zeros(n),zeros(n),zeros(n) -y1 = reinit!(s,y1,x,vel,0.1,caches) - -y2 = reshape(copy(x),sz) -y_tmp = reshape(zeros(n),sz) -caches2 = zeros(sz),zeros(sz),zeros(sz),zeros(sz),zeros(sz),zeros(sz) -reinit_step!(y2,y_tmp,reshape(vel,sz),(false,false,false,false),(0.5,0.5),0.1,caches2) -#y_tmp = reshape(y_tmp,n) -#y_tmp ≈ y1 - -vel2 = reshape(vel,sz); - -@benchmark reinit!(s,$y1,$x,$vel,0.1,$caches) -@benchmark reinit_step!($y2,$y_tmp,$vel2,(false,false,false,false),(0.5,0.5),0.1,$caches2) - -# 3D - -sz = (104,108,10); n = prod(sz) -s = Stencil(3,sz,(0.5,0.5,0.5)) - -x = randn(n) -vel = ones(n); vel[[1,3,6,8,12,14]] .= 0; - -y1 = zeros(n) -caches = zeros(n),zeros(n),zeros(n),zeros(n),zeros(n),zeros(n),zeros(n),zeros(n) -y1 = reinit!(s,y1,x,vel,0.1,caches) - -y2 = reshape(copy(x),sz) -y_tmp = reshape(zeros(n),sz) -caches2 = zeros(sz),zeros(sz),zeros(sz),zeros(sz),zeros(sz),zeros(sz),zeros(sz),zeros(sz) -reinit_step!(y2,y_tmp,reshape(vel,sz),(false,false,false,false,false,false),(0.5,0.5,0.5),0.1,caches2) -#y_tmp = reshape(y_tmp,n) -#y_tmp ≈ y1 - -vel2 = reshape(vel,sz) - -@benchmark reinit!($s,$y1,$x,$vel,0.1,$caches) -@benchmark reinit_step!($y2,$y_tmp,$vel2,(false,false,false,false,false,false),(0.5,0.5,0.5),0.1,$caches2) diff --git a/Deprecated/tests_solver.jl b/Deprecated/tests_solver.jl deleted file mode 100644 index f418acb3..00000000 --- a/Deprecated/tests_solver.jl +++ /dev/null @@ -1,128 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR - -import GridapDistributed.DistributedCellField -import GridapDistributed.DistributedFESpace -import GridapDistributed.DistributedDiscreteModel -import GridapDistributed.DistributedMeasure -import GridapDistributed.DistributedTriangulation - -include("Utilities.jl"); # <- For some useful functions -include("src/Solvers.jl") - -function elastic_compliance(φh,g,C,solve_data,interp,t,solver) - I = interp.I; dΩ=solve_data.dΩ; dΓ_N=solve_data.dΓ_N; - ## Weak form - a(u,v) = ∫((I ∘ φh)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v) = ∫(v ⋅ g)dΓ_N - ## Solve finite element problem - tic!(t) - op = AffineFEOperator(a,l,solve_data.U,solve_data.V,solve_data.assem) - toc!(t,"Assembly time") - K = op.op.matrix; - ## Solve - tic!(t) - uh = solve(solver,op) - toc!(t,"Solve time") - u = correct_ghost_layout(uh,K.col_partition) - ## Compute J and v_J - J = dot(u,(K*u)) - tic!(t) - v_J = interpolate(-C ⊙ ε(uh) ⊙ ε(uh),solve_data.V_L2) - toc!(t,"Interpolate shape sensitivity") - return J,v_J,uh -end - -function fe_setup(ranks,mesh_partition,order::T,coord_max::NTuple{3,M}, - el_size::NTuple{3,T}) where {T<:Integer,M<:AbstractFloat} - ## Model - dom = (0,coord_max[1],0,coord_max[2],0,coord_max[3]); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - ## Define Γ_N and Γ_D - xmax,ymax,zmax = coord_max - prop_Γ_N = 0.4 - f_Γ_D(x) = (x[1] ≈ 0.0) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/4 + eps() && zmax/2-zmax*prop_Γ_N/4 - eps() <= x[3] - <= zmax/2+zmax*prop_Γ_N/4 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,coord_max,"Gamma_D") - update_labels!(2,model,f_Γ_N,coord_max,"Gamma_N") - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,[VectorValue(0.0,0.0,0.0)]) - ## Assembler - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - assem=SparseMatrixAssembler(Tm,Tv,U,V) - # Space for shape sensitivities - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V_L2 = TestFESpace(model,reffe_scalar;conformity=:L2) - # FE space for LSF - V_φ = TestFESpace(model,reffe_scalar;conformity=:H1) - ## Collect data - solve_data = (U=U,V=V,assem=assem,V_L2=V_L2,dΩ=dΩ,dΓ_N=dΓ_N) - return model,Ω,V_φ,solve_data -end - -function _isotropic_3d(E::M,nu::M) where M<:AbstractFloat - λ = E*nu/((1+nu)*(1-2nu)); μ = E/(2*(1+nu)) - C =[λ+2μ λ λ 0 0 0 - λ λ+2μ λ 0 0 0 - λ λ λ+2μ 0 0 0 - 0 0 0 μ 0 0 - 0 0 0 0 μ 0 - 0 0 0 0 0 μ]; - return SymFourthOrderTensorValue( - C[1,1], C[6,1], C[5,1], C[2,1], C[4,1], C[3,1], - C[1,6], C[6,6], C[5,6], C[2,6], C[4,6], C[3,6], - C[1,5], C[6,5], C[5,5], C[2,5], C[4,5], C[3,5], - C[1,2], C[6,2], C[5,2], C[2,2], C[4,2], C[3,2], - C[1,4], C[6,4], C[5,4], C[2,4], C[4,4], C[3,4], - C[1,3], C[6,3], C[5,3], C[2,3], C[4,3], C[3,3]) -end - -############################################################################################ - -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - options = " - -ksp_type cg -ksp_rtol 1.0e-12 -ksp_norm_type unpreconditioned - -pc_type gamg -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky - -ksp_converged_reason -ksp_error_if_not_converged true - " - el_size = (20,20,20) - coord_max = (2.,1.,1.) - order = 1; - Δ = coord_max./el_size; - path = (@__DIR__)*"/Results/LinearElastic3DSolverTesting"; - t = PTimer(ranks;verbose=true) - GridapPETSc.with(args=split(options)) do - model,Ω,V_φ,solve_data = fe_setup(ranks,mesh_partition,order,coord_max,el_size) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(Δ)) - C = _isotropic_3d(1.,0.3) - g = VectorValue(0.,0.,-1.0) - φh = interpolate(x->-sqrt((x[1]-0.5)^2+(x[2]-0.5)^2+(x[3]-0.5)^2)+0.25,V_φ) - - solver = ElasticitySolver(solve_data.V) - J,v_J,uh = elastic_compliance(φh,g,C,solve_data,interp,t,solver) - display("Objective = $J") - writevtk(Ω,path,cellfields=["phi"=>φh,"H(phi)"=>(interp.H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) - end - t -end - -t = with_mpi() do distribute - main((2,1,1),distribute) -end; -display(t) diff --git a/Deprecated/tests_solver2_mpi.jl b/Deprecated/tests_solver2_mpi.jl deleted file mode 100644 index 1589a392..00000000 --- a/Deprecated/tests_solver2_mpi.jl +++ /dev/null @@ -1,96 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.ReferenceFEs -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR -using MPI - -import GridapDistributed.DistributedCellField -import GridapDistributed.DistributedFESpace -import GridapDistributed.DistributedDiscreteModel -import GridapDistributed.DistributedMeasure -import GridapDistributed.DistributedTriangulation - -using LevelSetTopOpt - -function isotropic_3d(E::M,nu::M) where M<:AbstractFloat - λ = E*nu/((1+nu)*(1-2nu)); μ = E/(2*(1+nu)) - C =[λ+2μ λ λ 0 0 0 - λ λ+2μ λ 0 0 0 - λ λ λ+2μ 0 0 0 - 0 0 0 μ 0 0 - 0 0 0 0 μ 0 - 0 0 0 0 0 μ]; - return SymFourthOrderTensorValue( - C[1,1], C[6,1], C[5,1], C[2,1], C[4,1], C[3,1], - C[1,6], C[6,6], C[5,6], C[2,6], C[4,6], C[3,6], - C[1,5], C[6,5], C[5,5], C[2,5], C[4,5], C[3,5], - C[1,2], C[6,2], C[5,2], C[2,2], C[4,2], C[3,2], - C[1,4], C[6,4], C[5,4], C[2,4], C[4,4], C[3,4], - C[1,3], C[6,3], C[5,3], C[2,3], C[4,3], C[3,3]) -end - -function isotropic_2d(E::M,nu::M) where M<:AbstractFloat - λ = E*nu/((1+nu)*(1-nu)); μ = E/(2*(1+nu)) - C = [λ+2μ λ 0 - λ λ+2μ 0 - 0 0 μ]; - SymFourthOrderTensorValue(C[1,1],C[3,1],C[2,1],C[1,3], - C[3,3],C[2,3],C[1,2],C[3,2],C[2,2]) -end - -############################################################################################ - -function main(distribute,np,n,order) - D = length(np) - ranks = distribute(LinearIndices((prod(np),))) - - n_tags = (D==2) ? "tag_6" : "tag_22" - d_tags = (D==2) ? ["tag_5"] : ["tag_21"] - - nc = (D==2) ? (n,n) : (n,n,n) - domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) - model = CartesianDiscreteModel(ranks,np,domain,nc) - Ω = Triangulation(model) - Γ = Boundary(model,tags=n_tags) - - poly = (D==2) ? QUAD : HEX - reffe = LagrangianRefFE(VectorValue{D,Float64},poly,order) - V = TestFESpace(model,reffe;dirichlet_tags="boundary") - U = TrialFESpace(V) - assem = SparseMatrixAssembler(SparseMatrixCSR{0,PetscScalar,PetscInt},Vector{PetscScalar},U,V,FullyAssembledRows()) - - dΩ = Measure(Ω,2*order) - dΓ = Measure(Γ,2*order) - C = (D == 2) ? isotropic_2d(1.,0.3) : isotropic_3d(1.,0.3) - g = (D == 2) ? VectorValue(0.0,1.0) : VectorValue(1.0,1.0,1.0) - a(u,v) = ∫((C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v) = ∫(v ⋅ g)dΓ - - op = AffineFEOperator(a,l,U,V,assem) - A, b = get_matrix(op), get_vector(op); - - options = " - -ksp_type gmres -ksp_rtol 1.0e-12 -ksp_max_it 200 - -pc_type gamg - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg - -ksp_converged_reason -ksp_error_if_not_converged true -ksp_monitor_short - -mat_use - " - GridapPETSc.with(args=split(options)) do - solver = ElasticitySolver(V;rtol=1.e-12,maxits=500) - ss = symbolic_setup(solver,A) - ns = numerical_setup(ss,A) - - x = pfill(PetscScalar(0.0),partition(axes(A,2))) - solve!(x,ns,b) - end -end - -with_mpi() do distribute - np = (2,2) - n = 100 - order = 1 - main(distribute,np,n,order) -end \ No newline at end of file diff --git a/Deprecated/tests_solvers2.jl b/Deprecated/tests_solvers2.jl deleted file mode 100644 index f6c872c2..00000000 --- a/Deprecated/tests_solvers2.jl +++ /dev/null @@ -1,150 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.ReferenceFEs -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR -using MPI - -import GridapDistributed.DistributedCellField -import GridapDistributed.DistributedFESpace -import GridapDistributed.DistributedDiscreteModel -import GridapDistributed.DistributedMeasure -import GridapDistributed.DistributedTriangulation - -function isotropic_3d(E::M,nu::M) where M<:AbstractFloat - λ = E*nu/((1+nu)*(1-2nu)); μ = E/(2*(1+nu)) - C =[λ+2μ λ λ 0 0 0 - λ λ+2μ λ 0 0 0 - λ λ λ+2μ 0 0 0 - 0 0 0 μ 0 0 - 0 0 0 0 μ 0 - 0 0 0 0 0 μ]; - return SymFourthOrderTensorValue( - C[1,1], C[6,1], C[5,1], C[2,1], C[4,1], C[3,1], - C[1,6], C[6,6], C[5,6], C[2,6], C[4,6], C[3,6], - C[1,5], C[6,5], C[5,5], C[2,5], C[4,5], C[3,5], - C[1,2], C[6,2], C[5,2], C[2,2], C[4,2], C[3,2], - C[1,4], C[6,4], C[5,4], C[2,4], C[4,4], C[3,4], - C[1,3], C[6,3], C[5,3], C[2,3], C[4,3], C[3,3]) -end - -function isotropic_2d(E::M,nu::M) where M<:AbstractFloat - λ = E*nu/((1+nu)*(1-nu)); μ = E/(2*(1+nu)) - C = [λ+2μ λ 0 - λ λ+2μ 0 - 0 0 μ]; - SymFourthOrderTensorValue(C[1,1],C[3,1],C[2,1],C[1,3], - C[3,3],C[2,3],C[1,2],C[3,2],C[2,2]) -end - -############################################################################################ - -function ksp_setup(ksp) - rtol = PetscScalar(1.e-12) - atol = GridapPETSc.PETSC.PETSC_DEFAULT - dtol = GridapPETSc.PETSC.PETSC_DEFAULT - maxits = GridapPETSc.PETSC.PETSC_DEFAULT - - @check_error_code GridapPETSc.PETSC.KSPView(ksp[],C_NULL) - @check_error_code GridapPETSc.PETSC.KSPSetType(ksp[],GridapPETSc.PETSC.KSPCG) - @check_error_code GridapPETSc.PETSC.KSPSetTolerances(ksp[], rtol, atol, dtol, maxits) - - pc = Ref{GridapPETSc.PETSC.PC}() - @check_error_code GridapPETSc.PETSC.KSPGetPC(ksp[],pc) - @check_error_code GridapPETSc.PETSC.PCSetType(pc[],GridapPETSc.PETSC.PCGAMG) -end - -function get_coords(trian::DistributedTriangulation{Dc},V) where Dc - coords = map(local_views(trian),local_views(V),partition(V.gids)) do trian, V, dof_indices - node_coords = Gridap.Geometry.get_node_coordinates(trian) - dof_to_node = V.metadata.free_dof_to_node - dof_to_comp = V.metadata.free_dof_to_comp - - o2l_dofs = own_to_local(dof_indices) - coords = Vector{PetscScalar}(undef,length(o2l_dofs)) - for (i,dof) in enumerate(o2l_dofs) - node = dof_to_node[dof] - comp = dof_to_comp[dof] - coords[i] = node_coords[node][comp] - end - return coords - end - return Dc, coords -end - -function my_numerical_setup(ss::GridapPETSc.PETScLinearSolverSS,A::AbstractMatrix,coords,dim) - pcoords = convert(PETScVector,coords) - @check_error_code GridapPETSc.PETSC.VecSetBlockSize(pcoords.vec[],dim) - - B = convert(PETScMatrix,A) - null = Ref{GridapPETSc.PETSC.MatNullSpace}() - #@check_error_code GridapPETSc.PETSC.MatSetBlockSize(B.mat[],dim) - @check_error_code GridapPETSc.PETSC.MatNullSpaceCreateRigidBody(pcoords.vec[],null) - @check_error_code GridapPETSc.PETSC.MatSetNearNullSpace(B.mat[],null[]) - - ns = GridapPETSc.PETScLinearSolverNS(A,B) - @check_error_code GridapPETSc.PETSC.KSPCreate(B.comm,ns.ksp) - @check_error_code GridapPETSc.PETSC.KSPSetOperators(ns.ksp[],ns.B.mat[],ns.B.mat[]) - ss.solver.setup(ns.ksp) - @check_error_code GridapPETSc.PETSC.KSPSetUp(ns.ksp[]) - GridapPETSc.Init(ns) -end - -############################################################################################ -D = 3 -order = 1 -n = 20 - -np_x_dim = 1 -np = Tuple(fill(np_x_dim,D)) #Tuple([fill(np_x_dim,D-1)...,1]) -ranks = with_debug() do distribute - distribute(LinearIndices((prod(np),))) -end - -n_tags = (D==2) ? "tag_6" : "tag_22" -d_tags = (D==2) ? ["tag_5"] : ["tag_21"] - -nc = (D==2) ? (n,n) : (n,n,n) -domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) -model = CartesianDiscreteModel(domain,nc) -Ω = Triangulation(model) -Γ = Boundary(model,tags=n_tags) -ΓD = Boundary(model,tags=d_tags) - -poly = (D==2) ? QUAD : HEX -reffe = LagrangianRefFE(VectorValue{D,Float64},poly,order) -V = TestFESpace(model,reffe;dirichlet_tags=d_tags) -U = TrialFESpace(V) -assem = SparseMatrixAssembler(SparseMatrixCSR{0,PetscScalar,PetscInt},Vector{PetscScalar},U,V)#,FullyAssembledRows()) - -dΩ = Measure(Ω,2*order) -dΓ = Measure(Γ,2*order) -C = (D == 2) ? isotropic_2d(1.,0.3) : isotropic_3d(1.,0.3) -g = (D == 2) ? VectorValue(0.0,1.0) : VectorValue(0.0,0.0,1.0) -a(u,v) = ∫((C ⊙ ε(u) ⊙ ε(v)))dΩ -l(v) = ∫(v ⋅ g)dΓ - -op = AffineFEOperator(a,l,U,V,assem) -A, b = get_matrix(op), get_vector(op); - -dim, coords = get_coords(Ω,V); -pcoords = PVector(coords,partition(axes(A,1))) - -#pcoords = pfill(0.0,partition(axes(A,2))) -#copy!(pcoords,_pcoords) -#consistent!(pcoords) |> fetch - -options = " - -ksp_type cg -ksp_rtol 1.0e-12 - -pc_type gamg -mat_block_size $D - -ksp_converged_reason -ksp_error_if_not_converged true - " -GridapPETSc.with(args=split(options)) do - solver = PETScLinearSolver(ksp_setup) - ss = symbolic_setup(solver,A) - ns = my_numerical_setup(ss,A,pcoords,dim) - - x = pfill(PetscScalar(1.0),partition(axes(A,2))) - solve!(x,ns,b) -end diff --git a/README.md b/README.md index 8fa50d55..f49144ea 100755 --- a/README.md +++ b/README.md @@ -4,9 +4,12 @@ LevelSetTopOpt is computational toolbox for level set-based topology optimisation implemented in Julia and the [Gridap](https://github.com/gridap/Gridap.jl) package ecosystem. See the documentation and following publication for further details: -> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. +> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable Julia toolbox for level set-based topology optimisation". In preparation. ## Documentation - [**STABLE**](...) — **Documentation for the most recently tagged version.** -- [**LATEST**](...) — *Documentation for the in-development version.* \ No newline at end of file +- [**LATEST**](...) — *Documentation for the in-development version.* + +## Citation +In order to give credit to the `LevelSetTopOpt` contributors, we ask that you please reference the above paper along with the required citations for [Gridap](https://github.com/gridap/Gridap.jl?tab=readme-ov-file#how-to-cite-gridap). \ No newline at end of file diff --git a/results/.gitignore b/results/.gitignore deleted file mode 100644 index c96a04f0..00000000 --- a/results/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index cd4126b4..c3dc701c 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -11,11 +11,13 @@ global NAME = ARGS[1] global WRITE_DIR = ARGS[2] global PROB_TYPE = ARGS[3] global BMARK_TYPE = ARGS[4] -global N = parse(Int,ARGS[5]) -global N_EL = parse(Int,ARGS[6]) -global ORDER = parse(Int,ARGS[7]) -global VERBOSE = parse(Int,ARGS[8]) -global NREPS = parse(Int,ARGS[9]) +global Nx = parse(Int,ARGS[5]) +global Ny = parse(Int,ARGS[6]) +global Nz = parse(Int,ARGS[7]) +global N_EL = parse(Int,ARGS[8]) +global ORDER = parse(Int,ARGS[9]) +global VERBOSE = parse(Int,ARGS[10]) +global NREPS = parse(Int,ARGS[11]) function nl_elast(mesh_partition,ranks,el_size,order,verbose) # FE parameters @@ -360,7 +362,7 @@ end with_mpi() do distribute # Setup - mesh_partition = (N,N,N) + mesh_partition = (Nx,Ny,Nz) ranks = distribute(LinearIndices((prod(mesh_partition),))) el_size = (N_EL,N_EL,N_EL) verbose = Bool(VERBOSE) ? i_am_main(ranks) : false; diff --git a/scripts/Benchmarks/benchmark_gadi.jl b/scripts/Benchmarks/benchmark_gadi.jl deleted file mode 100644 index c3dc701c..00000000 --- a/scripts/Benchmarks/benchmark_gadi.jl +++ /dev/null @@ -1,460 +0,0 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR - -using LevelSetTopOpt: get_deriv_space, get_aux_space,benchmark_optimizer, - benchmark_forward_problem,benchmark_advection,benchmark_reinitialisation, - benchmark_velocity_extension,benchmark_hilbertian_projection_map,benchmark_single_iteration - -using GridapSolvers: NewtonSolver - -global NAME = ARGS[1] -global WRITE_DIR = ARGS[2] -global PROB_TYPE = ARGS[3] -global BMARK_TYPE = ARGS[4] -global Nx = parse(Int,ARGS[5]) -global Ny = parse(Int,ARGS[6]) -global Nz = parse(Int,ARGS[7]) -global N_EL = parse(Int,ARGS[8]) -global ORDER = parse(Int,ARGS[9]) -global VERBOSE = parse(Int,ARGS[10]) -global NREPS = parse(Int,ARGS[11]) - -function nl_elast(mesh_partition,ranks,el_size,order,verbose) - # FE parameters - xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - prop_Γ_N = 0.2 # Γ_N size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - E = 1000 # Young's modulus - ν = 0.3 # Poisson's ratio - μ, λ = E/(2*(1 + ν)), E*ν/((1 + ν)*(1 - 2*ν)) # Lame constants - g = VectorValue(0,0,-1) # Applied load on Γ_N - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - ## Piola-Kirchhoff tensor - function S(∇u) - Cinv = inv(C(F(∇u))) - μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv - end - ## Derivative of Green strain - dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) - ## Right Cauchy-Green deformation tensor - C(F) = (F')⋅F - ## Deformation gradient tensor - F(∇u) = one(∇u) + ∇u' - ## Volume change - J(F) = sqrt(det(C(F))) - ## Residual - res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE ∘ (∇(v),∇(u))) ⊙ (S ∘ ∇(u))) )*dΩ - ∫(g⋅v)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - lin_solver = ElasticitySolver(V) - nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose) - state_map = NonlinearFEStateMap( - res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - nls = nl_solver, adjoint_ls = lin_solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((dE ∘ (∇(u),∇(u))) ⊙ (S ∘ ∇(u))))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) -end - -function therm(mesh_partition,ranks,el_size,order,verbose) - # FE parameters - xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = PETScLinearSolver() - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map, - analytic_dJ=dJ,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = solver - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) -end - -function elast(mesh_partition,ranks,el_size,order,verbose) - # FE parameters - xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - prop_Γ_N = 0.2 # Γ_N size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor - g = VectorValue(0,0,-1) # Applied load on Γ_N - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v⋅g)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = ElasticitySolver(V) - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(u)))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map, - analytic_dJ=dJ,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose) -end - -function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) - ## Parameters - dom = (0,1,0,1,0,1) - γ = 0.05 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(2order^2)/minimum(el_size) - C = isotropic_elast_tensor(3,1.0,0.3) - η_coeff = 2 - α_coeff = 4 - vf=0.4 - δₓ=0.5 - ks = 0.01 - g = VectorValue(1,0,0) - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && - (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && - (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && - (0.3 - eps() <= x[3] <= 0.7 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) - update_labels!(1,model,f_Γ_in,"Gamma_in") - update_labels!(2,model,f_Γ_out,"Gamma_out") - update_labels!(3,model,f_Γ_out_ext,"Gamma_out_ext") - update_labels!(4,model,f_Γ_D,"Gamma_D") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_in = BoundaryTriangulation(model,tags="Gamma_in") - Γ_out = BoundaryTriangulation(model,tags="Gamma_out") - dΩ = Measure(Ω,2*order) - dΓ_in = Measure(Γ_in,2*order) - dΓ_out = Measure(Γ_out,2*order) - vol_D = sum(∫(1)dΩ) - vol_Γ_in = sum(∫(1)dΓ_in) - vol_Γ_out = sum(∫(1)dΓ_out) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_in","Gamma_out","Gamma_out_ext"]) - U_reg = TrialFESpace(V_reg,[0,0,0]) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.1),V_φ); - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_in,dΓ_out) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + ∫(ks*(u⋅v))dΓ_out - l(v,φ,dΩ,dΓ_in,dΓ_out) = ∫(v⋅g)dΓ_in - - ## Optimisation functionals - e₁ = VectorValue(1,0,0) - J(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅e₁)/vol_Γ_in)dΓ_in - Vol(u,φ,dΩ,dΓ_in,dΓ_out) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; - dVol(q,u,φ,dΩ,dΓ_in,dΓ_out) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - UΓ_out(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out - - ## Finite difference solver - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) - - ## Setup solver and FE operators - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = ElasticitySolver(V) - - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver, adjoint_ls = solver - ) - pcfs = PDEConstrainedFunctionals(J,[Vol,UΓ_out],state_map,analytic_dC=[dVol,nothing]) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension( - a_hilb,U_reg,V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - - ## Optimiser - return HilbertianProjection(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=verbose) -end - -with_mpi() do distribute - # Setup - mesh_partition = (Nx,Ny,Nz) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - el_size = (N_EL,N_EL,N_EL) - verbose = Bool(VERBOSE) ? i_am_main(ranks) : false; - if PROB_TYPE == "NLELAST" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - opt = nl_elast - elseif PROB_TYPE == "THERM" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - opt = therm - elseif PROB_TYPE == "ELAST" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - opt = elast - elseif PROB_TYPE == "INVERTER_HPM" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - opt = inverter_HPM - else - error("Problem not defined") - end - - # Output - i_am_main(ranks) && ~isdir(WRITE_DIR) && mkpath(WRITE_DIR) - # Run - t_start = PTimer(ranks); - GridapPETSc.with(args=split(options)) do - tic!(t_start;barrier=true) - optim = opt(mesh_partition,ranks,el_size,ORDER,verbose) - toc!(t_start,"startup") - startup_time = map_main(t_start.data) do data - map(x -> x.max,values(data)) - end |> PartitionedArrays.getany - bstart = i_am_main(ranks) && [startup_time; zeros(NREPS-1)] - ## Benchmark optimiser - if occursin("bopt0",BMARK_TYPE) - bopt0 = benchmark_optimizer(optim, 0, ranks; nreps=NREPS) - else - bopt0 = i_am_main(ranks) && zeros(NREPS) - end - if occursin("bopt1",BMARK_TYPE) - bopt1 = benchmark_single_iteration(optim, ranks; nreps = NREPS) - else - bopt1 = i_am_main(ranks) && zeros(NREPS) - end - ## Benchmark reinitialisation - if occursin("breinit",BMARK_TYPE) - breinit = benchmark_reinitialisation(optim.ls_evolver, get_free_dof_values(optim.φ0), 0.1, ranks; nreps=NREPS) - else - breinit = i_am_main(ranks) && zeros(NREPS) - end - ## Benchmark forward problem - if occursin("bfwd",BMARK_TYPE) - bfwd = benchmark_forward_problem(optim.problem.state_map, optim.φ0, ranks; nreps=NREPS) - else - bfwd = i_am_main(ranks) && zeros(NREPS) - end - ## Benchmark advection - reinit!(optim.ls_evolver,optim.φ0,optim.params.γ_reinit) - if occursin("badv",BMARK_TYPE) - vh = interpolate(FEFunction(get_deriv_space(optim.problem.state_map),optim.problem.dJ), - get_aux_space(optim.problem.state_map)) - v = get_free_dof_values(vh) - badv = benchmark_advection(optim.ls_evolver, get_free_dof_values(optim.φ0), v, 0.1, ranks; nreps=NREPS) - else - badv = i_am_main(ranks) && zeros(NREPS) - end - ## Benchmark velocity extension - if occursin("bvelext",BMARK_TYPE) - bvelext = benchmark_velocity_extension(optim.vel_ext, optim.problem.dJ, ranks; nreps=NREPS) - else - bvelext = i_am_main(ranks) && zeros(NREPS) - end - ## HPM - if occursin("bhpm",BMARK_TYPE) - @assert typeof(optim) <: HilbertianProjection - J, C, dJ, dC = Gridap.evaluate!(optim.problem,optim.φ0) - optim.projector,dJ,C,dC,optim.vel_ext.K - bhpm = benchmark_hilbertian_projection_map(optim.projector,dJ,C,dC,optim.vel_ext.K,ranks) - else - bhpm = i_am_main(ranks) && zeros(NREPS) - end - ## Write results - if i_am_main(ranks) - open(WRITE_DIR*NAME*".txt","w") do f - bcontent = "startup,bopt(0),bopt(1),bfwd,badv,breinit,bvelext,bhpm\n" - for i = 1:NREPS - bcontent *= "$(bstart[i]),$(bopt0[i]),$(bopt1[i]),$(bfwd[i]),$(badv[i]),$(breinit[i]),$(bvelext[i]),$(bhpm[i])\n" - end - write(f,bcontent) - end - end - end -end \ No newline at end of file diff --git a/scripts/Benchmarks/generate_benchmark_scripts.jl b/scripts/Benchmarks/generate_benchmark_scripts.jl index 4ad06b06..f142b86b 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts.jl @@ -2,6 +2,21 @@ using Pkg Pkg.activate() using Mustache +# These are generated by solving +# Minimise X + Y + Z s.t. X*Y*Z=i*48 for X,Y,Z∈ℤ⁺ (See bottom) +mesh_partitions = [(4, 4, 3),(4, 4, 6),(4, 6, 6),(4, 6, 8),(5, 6, 8),(6, 6, 8),(7, 6, 8),(6, 8, 8),(6, 9, 8),(10, 6, 8), + (11, 6, 8),(9, 8, 8),(13, 6, 8),(12, 7, 8),(10, 9, 8),(12, 8, 8),(6, 8, 17),(12, 9, 8),(6, 8, 19), + (10, 12, 8),(14, 9, 8),(11, 12, 8),(6, 8, 23),(12, 12, 8),(10, 10, 12),(13, 12, 8),(12, 12, 9),(12, 14, 8), + (6, 8, 29),(10, 12, 12),(6, 8, 31),(8, 12, 16),(11, 12, 12),(8, 12, 17),(10, 12, 14),(12, 12, 12),(6, 8, 37), + (8, 12, 19),(13, 12, 12),(10, 12, 16),(6, 8, 41),(12, 12, 14),(6, 8, 43),(11, 12, 16),(12, 12, 15),(8, 12, 23), + (6, 8, 47),(12, 12, 16),(12, 14, 14),(10, 15, 16),(12, 12, 17),(12, 13, 16),(6, 8, 53),(12, 12, 18),(11, 15, 16), + (12, 14, 16),(12, 12, 19),(8, 12, 29),(6, 8, 59),(12, 15, 16),(6, 8, 61),(8, 12, 31),(12, 14, 18),(12, 16, 16), + (13, 15, 16),(11, 16, 18),(6, 8, 67),(12, 16, 17),(12, 12, 23),(14, 15, 16),(6, 8, 71),(12, 16, 18),(6, 8, 73), + (8, 12, 37),(15, 15, 16),(12, 16, 19),(11, 16, 21),(13, 16, 18),(6, 8, 79),(15, 16, 16),(12, 18, 18),(8, 12, 41), + (6, 8, 83),(14, 16, 18),(15, 16, 17),(8, 12, 43),(12, 12, 29),(12, 16, 22),(6, 8, 89),(15, 16, 18)] + +@assert Int.(prod.(mesh_partitions)/48) == collect(1:length(mesh_partitions)) + function generate( template, name, @@ -9,7 +24,7 @@ function generate( bmark_type, cputype, wallhr, - n_mesh_partition, + mesh_partition, n_el_size, fe_order, verbose, @@ -18,53 +33,58 @@ function generate( nreps ) - ncpus = n_mesh_partition^3 - wallhr = occursin("STRONG",name) && n_mesh_partition <= 3 ? 100 : wallhr - mem = occursin("STRONG",name) && n_mesh_partition == 1 ? 256 : - occursin("STRONG",name) && n_mesh_partition == 2 ? 32 : gb_per_cpu; + ncpus = prod(mesh_partition) + wallhr = occursin("STRONG",name) && ncpus == 1 ? 100 : + occursin("STRONG",name) && ncpus == 8 ? 24 : + occursin("STRONG",name) && ncpus == 27 ? 10 : wallhr + mem = occursin("STRONG",name) && ncpus == 1 ? 100 : + occursin("STRONG",name) && ncpus == 8 ? 128 : + occursin("STRONG",name) && ncpus == 27 ? 192 : Int(gb_per_node*ncpus/cps_per_node); + Nx_partition, Ny_partition, Nz_partition = mesh_partition settings = (;name,type,bmark_type,cputype,wallhr,ncpus,mem, - n_mesh_partition,n_el_size,fe_order,verbose,dir_name,write_dir,nreps) + Nx_partition,Ny_partition,Nz_partition,n_el_size,fe_order,verbose,dir_name,write_dir,nreps) Mustache.render(template, settings) end function generate_jobs(template,phys_type,ndof_per_node,bmark_types) - npart = (N).^3; + npart = prod.(parts) weak_el_x = @. floor(Int,(dofs_per_proc*npart/ndof_per_node)^(1/3)-1); dof_sanity_check = @.(floor(Int,ndof_per_node*(weak_el_x+1)^3/npart)), maximum(abs,@. ndof_per_node*(weak_el_x+1)^3/npart/dofs_per_proc - 1) - sname(phys_type,ndof_per_node,n,elx) = "STRONG_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" - wname(phys_type,ndof_per_node,n,elx) = "WEAK_$(phys_type)_dof$(ndof_per_node)_N$(n)_elx$(elx)" + sname(phys_type,ndof_per_node,n,elx) = "STRONG_$(phys_type)_dof$(ndof_per_node)_N$(prod(n))_elx$(elx)" + wname(phys_type,ndof_per_node,n,elx) = "WEAK_$(phys_type)_dof$(ndof_per_node)_N$(prod(n))_elx$(elx)" strong_el_x = ceil(Int,(strong_dof/ndof_per_node)^(1/3)); strong_jobs = map(n->(sname(phys_type,ndof_per_node,n,strong_el_x), generate(template,sname(phys_type,ndof_per_node,n,strong_el_x),phys_type,bmark_types, - cputype,wallhr,n,strong_el_x,fe_order,verbose,dir_name,write_dir,nreps)),N) + cputype,wallhr,n,strong_el_x,fe_order,verbose,dir_name,write_dir,nreps)),parts) weak_jobs = map((n,elx)->(wname(phys_type,ndof_per_node,n,elx), generate(template,wname(phys_type,ndof_per_node,n,elx),phys_type,bmark_types, - cputype,wallhr,n,elx,fe_order,verbose,dir_name,write_dir,nreps)),N,weak_el_x) + cputype,wallhr,n,elx,fe_order,verbose,dir_name,write_dir,nreps)),parts,weak_el_x) strong_jobs,weak_jobs,dof_sanity_check end -job_output_path = "./scripts/Benchmarks/jobs/"; +dir_name= "LevelSetTopOpt"; +job_output_path = "$(ENV["SCRATCH"])/$dir_name/scripts/Benchmarks/jobs-gadi/"; mkpath(job_output_path); # SETUP PARAMETERS -cputype="6140"; -gb_per_cpu = 8 # GB +cputype=""; # Not needed here +gb_per_node = 192 # GB +cps_per_node = 48 wallhr = 3 ; # Hours (Note may want to manually change some afterwards) nreps = 10; # Number of benchmark repetitions dofs_per_proc = 32000; fe_order= 1; verbose= 1; -dir_name= "LevelSetTopOpt"; -write_dir = "\$HOME/$dir_name/results/benchmarks/" +write_dir = "\$SCRATCH/$dir_name/results/benchmarks/" -N = 1:10; # Number of partitions in x-axis +parts = [(2,2,2);(3,3,3);mesh_partitions[[1,2,3,5]];mesh_partitions[8:5:23]] strong_dof=(100+1)^3*3; # Number of dofs for strong scaling # Phys type and number of dofs per node, and what to benchmark @@ -76,7 +96,7 @@ phys_types = [ ]; # Template -template = read("./scripts/Benchmarks/jobtemplate.sh",String) +template = read("$(ENV["SCRATCH"])/$dir_name/scripts/Benchmarks/jobtemplate_gadi.sh",String) ## Generate Jobs jobs_by_phys = map(x->(x[1],generate_jobs(template,x[1],x[2],x[3])),phys_types); @@ -92,4 +112,9 @@ for jobs in jobs_by_phys write(f,content) end end -end \ No newline at end of file +end + +# Mathematica code: +# F[N_]:=Minimize[{X+Y+Z,X*Y*Z==N*48, X>0, Y>0, Z>0,X\[Element] Integers,Y\[Element] Integers,Z\[Element] Integers},{X,Y,Z}] +# For[i=1,i<=50,i++,X[i]=F[i]]; +# For[i=1,i<=90,i++,Print[{X[i][[2]][[1]][[2]],X[i][[2]][[2]][[2]],X[i][[2]][[3]][[2]]}]] \ No newline at end of file diff --git a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl b/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl deleted file mode 100644 index f142b86b..00000000 --- a/scripts/Benchmarks/generate_benchmark_scripts_gadi.jl +++ /dev/null @@ -1,120 +0,0 @@ -using Pkg -Pkg.activate() -using Mustache - -# These are generated by solving -# Minimise X + Y + Z s.t. X*Y*Z=i*48 for X,Y,Z∈ℤ⁺ (See bottom) -mesh_partitions = [(4, 4, 3),(4, 4, 6),(4, 6, 6),(4, 6, 8),(5, 6, 8),(6, 6, 8),(7, 6, 8),(6, 8, 8),(6, 9, 8),(10, 6, 8), - (11, 6, 8),(9, 8, 8),(13, 6, 8),(12, 7, 8),(10, 9, 8),(12, 8, 8),(6, 8, 17),(12, 9, 8),(6, 8, 19), - (10, 12, 8),(14, 9, 8),(11, 12, 8),(6, 8, 23),(12, 12, 8),(10, 10, 12),(13, 12, 8),(12, 12, 9),(12, 14, 8), - (6, 8, 29),(10, 12, 12),(6, 8, 31),(8, 12, 16),(11, 12, 12),(8, 12, 17),(10, 12, 14),(12, 12, 12),(6, 8, 37), - (8, 12, 19),(13, 12, 12),(10, 12, 16),(6, 8, 41),(12, 12, 14),(6, 8, 43),(11, 12, 16),(12, 12, 15),(8, 12, 23), - (6, 8, 47),(12, 12, 16),(12, 14, 14),(10, 15, 16),(12, 12, 17),(12, 13, 16),(6, 8, 53),(12, 12, 18),(11, 15, 16), - (12, 14, 16),(12, 12, 19),(8, 12, 29),(6, 8, 59),(12, 15, 16),(6, 8, 61),(8, 12, 31),(12, 14, 18),(12, 16, 16), - (13, 15, 16),(11, 16, 18),(6, 8, 67),(12, 16, 17),(12, 12, 23),(14, 15, 16),(6, 8, 71),(12, 16, 18),(6, 8, 73), - (8, 12, 37),(15, 15, 16),(12, 16, 19),(11, 16, 21),(13, 16, 18),(6, 8, 79),(15, 16, 16),(12, 18, 18),(8, 12, 41), - (6, 8, 83),(14, 16, 18),(15, 16, 17),(8, 12, 43),(12, 12, 29),(12, 16, 22),(6, 8, 89),(15, 16, 18)] - -@assert Int.(prod.(mesh_partitions)/48) == collect(1:length(mesh_partitions)) - -function generate( - template, - name, - type, - bmark_type, - cputype, - wallhr, - mesh_partition, - n_el_size, - fe_order, - verbose, - dir_name, - write_dir, - nreps - ) - - ncpus = prod(mesh_partition) - wallhr = occursin("STRONG",name) && ncpus == 1 ? 100 : - occursin("STRONG",name) && ncpus == 8 ? 24 : - occursin("STRONG",name) && ncpus == 27 ? 10 : wallhr - mem = occursin("STRONG",name) && ncpus == 1 ? 100 : - occursin("STRONG",name) && ncpus == 8 ? 128 : - occursin("STRONG",name) && ncpus == 27 ? 192 : Int(gb_per_node*ncpus/cps_per_node); - Nx_partition, Ny_partition, Nz_partition = mesh_partition - - settings = (;name,type,bmark_type,cputype,wallhr,ncpus,mem, - Nx_partition,Ny_partition,Nz_partition,n_el_size,fe_order,verbose,dir_name,write_dir,nreps) - Mustache.render(template, settings) -end - -function generate_jobs(template,phys_type,ndof_per_node,bmark_types) - npart = prod.(parts) - weak_el_x = @. floor(Int,(dofs_per_proc*npart/ndof_per_node)^(1/3)-1); - dof_sanity_check = @.(floor(Int,ndof_per_node*(weak_el_x+1)^3/npart)), - maximum(abs,@. ndof_per_node*(weak_el_x+1)^3/npart/dofs_per_proc - 1) - - sname(phys_type,ndof_per_node,n,elx) = "STRONG_$(phys_type)_dof$(ndof_per_node)_N$(prod(n))_elx$(elx)" - wname(phys_type,ndof_per_node,n,elx) = "WEAK_$(phys_type)_dof$(ndof_per_node)_N$(prod(n))_elx$(elx)" - - strong_el_x = ceil(Int,(strong_dof/ndof_per_node)^(1/3)); - - strong_jobs = map(n->(sname(phys_type,ndof_per_node,n,strong_el_x), - generate(template,sname(phys_type,ndof_per_node,n,strong_el_x),phys_type,bmark_types, - cputype,wallhr,n,strong_el_x,fe_order,verbose,dir_name,write_dir,nreps)),parts) - weak_jobs = map((n,elx)->(wname(phys_type,ndof_per_node,n,elx), - generate(template,wname(phys_type,ndof_per_node,n,elx),phys_type,bmark_types, - cputype,wallhr,n,elx,fe_order,verbose,dir_name,write_dir,nreps)),parts,weak_el_x) - - strong_jobs,weak_jobs,dof_sanity_check -end - -dir_name= "LevelSetTopOpt"; -job_output_path = "$(ENV["SCRATCH"])/$dir_name/scripts/Benchmarks/jobs-gadi/"; -mkpath(job_output_path); - -# SETUP PARAMETERS -cputype=""; # Not needed here -gb_per_node = 192 # GB -cps_per_node = 48 -wallhr = 3 ; # Hours (Note may want to manually change some afterwards) - -nreps = 10; # Number of benchmark repetitions -dofs_per_proc = 32000; -fe_order= 1; -verbose= 1; -write_dir = "\$SCRATCH/$dir_name/results/benchmarks/" - -parts = [(2,2,2);(3,3,3);mesh_partitions[[1,2,3,5]];mesh_partitions[8:5:23]] -strong_dof=(100+1)^3*3; # Number of dofs for strong scaling - -# Phys type and number of dofs per node, and what to benchmark -phys_types = [ - ("THERM",1,"bopt0,bopt1,bfwd,badv,breinit,bvelext"), - ("ELAST",3,"bopt0,bopt1,bfwd,badv,breinit,bvelext"), - ("NLELAST",3,"bopt0,bopt1,bfwd"), - # ("INVERTER_HPM",3,"bhpm"), -]; - -# Template -template = read("$(ENV["SCRATCH"])/$dir_name/scripts/Benchmarks/jobtemplate_gadi.sh",String) - -## Generate Jobs -jobs_by_phys = map(x->(x[1],generate_jobs(template,x[1],x[2],x[3])),phys_types); - -for jobs in jobs_by_phys - strong_jobs,weak_jobs,dof_sanity_check = jobs[2] - - println("$(jobs[1]): Weak dofs = $(dof_sanity_check[1])\n Error = $(dof_sanity_check[2])\n") - for job in vcat(strong_jobs,weak_jobs) - name = job[1] - content = job[2] - open(job_output_path*"$name.pbs","w") do f - write(f,content) - end - end -end - -# Mathematica code: -# F[N_]:=Minimize[{X+Y+Z,X*Y*Z==N*48, X>0, Y>0, Z>0,X\[Element] Integers,Y\[Element] Integers,Z\[Element] Integers},{X,Y,Z}] -# For[i=1,i<=50,i++,X[i]=F[i]]; -# For[i=1,i<=90,i++,Print[{X[i][[2]][[1]][[2]],X[i][[2]][[2]][[2]],X[i][[2]][[3]][[2]]}]] \ No newline at end of file diff --git a/scripts/Benchmarks/jobtemplate.sh b/scripts/Benchmarks/jobtemplate.sh index 049acb79..4bee92f9 100644 --- a/scripts/Benchmarks/jobtemplate.sh +++ b/scripts/Benchmarks/jobtemplate.sh @@ -1,32 +1,26 @@ -#!/bin/bash -l +#!/bin/bash -#PBS -P LSTO +#PBS -P np01 +#PBS -q normal #PBS -N "{{:name}}" -#PBS -l select={{:ncpus}}:ncpus=1:mpiprocs=1:ompthreads=1:mem={{:mem}}GB:cputype={{:cputype}} +#PBS -l ncpus={{:ncpus}} +#PBS -l mem={{:mem}}GB #PBS -l walltime={{:wallhr}}:00:00 #PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/{{:dir_name}}/ +source $HOME/hpc-environments/gadi/load-intel.sh +PROJECT_DIR=$SCRATCH/{{:dir_name}}/ -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/Benchmarks/benchmark.jl \ +mpiexec -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 \ + $PROJECT_DIR/scripts/Benchmarks/benchmark_gadi.jl \ {{:name}} \ {{{:write_dir}}} \ {{:type}} \ {{:bmark_type}} \ - {{:n_mesh_partition}} \ + {{:Nx_partition}} \ + {{:Ny_partition}} \ + {{:Nz_partition}} \ {{:n_el_size}} \ {{:fe_order}} \ {{:verbose}} \ - {{:nreps}} - -read _ _ PBS_WALLTIME <<< `qstat -f $PBS_JOBID | grep "resources_used.walltime"` -PBS_WALLTIME_SECS=$(echo $PBS_WALLTIME | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }') -echo $PBS_WALLTIME_SECS >> {{{:write_dir}}}/{{:name}}_walltime.txt \ No newline at end of file + {{:nreps}} \ No newline at end of file diff --git a/scripts/Benchmarks/jobtemplate_gadi.sh b/scripts/Benchmarks/jobtemplate_gadi.sh deleted file mode 100644 index 4bee92f9..00000000 --- a/scripts/Benchmarks/jobtemplate_gadi.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -#PBS -P np01 -#PBS -q normal -#PBS -N "{{:name}}" -#PBS -l ncpus={{:ncpus}} -#PBS -l mem={{:mem}}GB -#PBS -l walltime={{:wallhr}}:00:00 -#PBS -j oe - -source $HOME/hpc-environments/gadi/load-intel.sh -PROJECT_DIR=$SCRATCH/{{:dir_name}}/ - -mpiexec -n {{:ncpus}} julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/Benchmarks/benchmark_gadi.jl \ - {{:name}} \ - {{{:write_dir}}} \ - {{:type}} \ - {{:bmark_type}} \ - {{:Nx_partition}} \ - {{:Ny_partition}} \ - {{:Nz_partition}} \ - {{:n_el_size}} \ - {{:fe_order}} \ - {{:verbose}} \ - {{:nreps}} \ No newline at end of file diff --git a/scripts/MPI/3d_elastic_compliance_ALM.jl b/scripts/MPI/3d_elastic_compliance_ALM.jl index 558d05d8..cb221837 100644 --- a/scripts/MPI/3d_elastic_compliance_ALM.jl +++ b/scripts/MPI/3d_elastic_compliance_ALM.jl @@ -1,12 +1,13 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] """ (MPI) Minimum elastic compliance with augmented Lagrangian method in 3D. @@ -15,10 +16,10 @@ global Pz = parse(Int,ARGS[6]) Min J(Ω) = ∫ C ⊙ ε(u) ⊙ ε(v) dΩ Ω s.t., Vol(Ω) = vf, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)³, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)³, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ = ∫ v⋅g dΓ_N, ∀v∈V. """ -function main(mesh_partition,distribute,el_size) +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -35,9 +36,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_elastic_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -87,7 +87,7 @@ function main(mesh_partition,distribute,el_size) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = ElasticitySolver(V) - + state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -121,10 +121,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end; \ No newline at end of file diff --git a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl index 6cd67d04..fe6d8f61 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl @@ -1,19 +1,20 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR using GridapSolvers: NewtonSolver -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] """ (MPI) Minimum hyperelastic compliance with augmented Lagrangian method in 3D. -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -28,9 +29,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) @@ -108,7 +108,7 @@ function main(mesh_partition,distribute,el_size) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) @@ -124,10 +124,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end \ No newline at end of file diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index 8ad44dc4..7d781947 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -1,19 +1,20 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR using GridapSolvers: NewtonSolver -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] """ (MPI) Minimum hyperelastic compliance with augmented Lagrangian method in 3D. -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -28,9 +29,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_hyperelastic_compliance_neohook_ALM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) @@ -122,7 +122,7 @@ function main(mesh_partition,distribute,el_size) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) @@ -138,10 +138,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end \ No newline at end of file diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index 1746a942..087372b4 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -1,13 +1,14 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) - +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] + """ (MPI) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 3D. @@ -15,10 +16,10 @@ global Pz = parse(Int,ARGS[6]) Min J(Ω) = -κ(Ω) Ω s.t., Vol(Ω) = vf, - ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, + ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, ⎣∫ ∑ᵢ C ⊙ ε(uᵢ) ⊙ ε(vᵢ) dΩ = ∫ -∑ᵢ C ⊙ ε⁰ᵢ ⊙ ε(vᵢ) dΩ, ∀v∈V. -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -33,9 +34,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/3d_inverse_homenisation_ALM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)) @@ -109,7 +109,7 @@ function main(mesh_partition,distribute,el_size) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) @@ -125,10 +125,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end \ No newline at end of file diff --git a/scripts/MPI/3d_inverter_ALM.jl b/scripts/MPI/3d_inverter_ALM.jl index 4fa6ee26..aa7fb6fd 100644 --- a/scripts/MPI/3d_inverter_ALM.jl +++ b/scripts/MPI/3d_inverter_ALM.jl @@ -1,12 +1,13 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] """ (MPI) Inverter mechanism with Hilbertian projection method in 3D. @@ -15,14 +16,14 @@ global Pz = parse(Int,ARGS[6]) Min J(Ω) = ηᵢₙ*∫ u⋅e₁ dΓᵢₙ Ω s.t., Vol(Ω) = vf, - C(Ω) = 0, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + C(Ω) = 0, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. - + where C(Ω) = ∫ -u⋅e₁-δₓ dΓₒᵤₜ. We assume symmetry in the problem to aid convergence. -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -39,18 +40,17 @@ function main(mesh_partition,distribute,el_size) δₓ=0.5 ks = 0.01 g = VectorValue(1,0,0) - path = dirname(dirname(@__DIR__))*"/results/3d_inverter_ALM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && + f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && (0.3 - eps() <= x[3] <= 0.7 + eps()) f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) update_labels!(1,model,f_Γ_in,"Gamma_in") @@ -105,7 +105,7 @@ function main(mesh_partition,distribute,el_size) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = ElasticitySolver(V) - + state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -123,7 +123,7 @@ function main(mesh_partition,distribute,el_size) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol,:UΓ_out]) @@ -139,10 +139,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end \ No newline at end of file diff --git a/scripts/MPI/3d_inverter_HPM.jl b/scripts/MPI/3d_inverter_HPM.jl index 3aacbfe1..681450d0 100644 --- a/scripts/MPI/3d_inverter_HPM.jl +++ b/scripts/MPI/3d_inverter_HPM.jl @@ -1,12 +1,13 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] """ (MPI) Inverter mechanism with Hilbertian projection method in 3D. @@ -15,14 +16,14 @@ global Pz = parse(Int,ARGS[6]) Min J(Ω) = ηᵢₙ*∫ u⋅e₁ dΓᵢₙ Ω s.t., Vol(Ω) = vf, - C(Ω) = 0, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + C(Ω) = 0, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. - + where C(Ω) = ∫ -u⋅e₁-δₓ dΓₒᵤₜ. We assume symmetry in the problem to aid convergence. -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -39,18 +40,17 @@ function main(mesh_partition,distribute,el_size) δₓ=0.5 ks = 0.01 g = VectorValue(1,0,0) - path = dirname(dirname(@__DIR__))*"/results/3d_inverter_HPM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && + f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && (0.3 - eps() <= x[3] <= 0.7 + eps()) f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) update_labels!(1,model,f_Γ_in,"Gamma_in") @@ -105,7 +105,7 @@ function main(mesh_partition,distribute,el_size) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = ElasticitySolver(V) - + state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -123,7 +123,7 @@ function main(mesh_partition,distribute,el_size) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - + ## Optimiser ls_enabled=false # Setting to true will use a line search instead of oscillation detection optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,ls_enabled,α_min=0.7, @@ -140,10 +140,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end \ No newline at end of file diff --git a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl index e3bbfde2..08bcb6f2 100644 --- a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl @@ -1,14 +1,15 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR using GridapSolvers: NewtonSolver -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] """ (MPI) Minimum thermal compliance with augmented Lagrangian method in 3D with nonlinear diffusivity. @@ -19,10 +20,10 @@ global Pz = parse(Int,ARGS[6]) s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ(u)*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. - + In this example κ(u) = κ0*(exp(ξ*u)) -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -38,9 +39,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_nonlinear_thermal_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -92,7 +92,7 @@ function main(mesh_partition,distribute,el_size) Tv = Vector{PetscScalar} lin_solver = PETScLinearSolver() nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose=i_am_main(ranks)) - + state_map = NonlinearFEStateMap( res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -111,7 +111,7 @@ function main(mesh_partition,distribute,el_size) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = lin_solver ) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) @@ -127,10 +127,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end; \ No newline at end of file diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index ce4849db..4bf81ede 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -1,12 +1,13 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -global elx = parse(Int,ARGS[1]) -global ely = parse(Int,ARGS[2]) -global elz = parse(Int,ARGS[3]) -global Px = parse(Int,ARGS[4]) -global Py = parse(Int,ARGS[5]) -global Pz = parse(Int,ARGS[6]) +global elx = parse(Int,ARGS[1]) +global ely = parse(Int,ARGS[2]) +global elz = parse(Int,ARGS[3]) +global Px = parse(Int,ARGS[4]) +global Py = parse(Int,ARGS[5]) +global Pz = parse(Int,ARGS[6]) +global write_dir = ARGS[7] """ (MPI) Minimum thermal compliance with augmented Lagrangian method in 3D. @@ -18,7 +19,7 @@ global Pz = parse(Int,ARGS[6]) ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. """ -function main(mesh_partition,distribute,el_size) +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -35,9 +36,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/3d_thermal_compliance_ALM_Nx$(el_size[1])/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -87,7 +87,7 @@ function main(mesh_partition,distribute,el_size) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = PETScLinearSolver() - + state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -121,10 +121,10 @@ end with_mpi() do distribute mesh_partition = (Px,Py,Pz) el_size = (elx,ely,elz) - all_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + all_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(all_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end; \ No newline at end of file diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index 48bacf32..2c434df7 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -1,6 +1,8 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global write_dir = ARGS[1] + """ (MPI) Minimum elastic compliance with augmented Lagrangian method in 2D. @@ -8,10 +10,10 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, Min J(Ω) = ∫ C ⊙ ε(u) ⊙ ε(v) + ξ dΩ Ω s.t., Vol(Ω) = vf, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ = ∫ v⋅g dΓ_N, ∀v∈V. """ -function main(mesh_partition,distribute,el_size) +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -28,9 +30,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM_MPI/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) @@ -80,7 +81,7 @@ function main(mesh_partition,distribute,el_size) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = ElasticitySolver(V) - + state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -112,10 +113,10 @@ end with_mpi() do distribute mesh_partition = (2,2) el_size = (200,100) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end \ No newline at end of file diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index 6cbe688b..032e93c8 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -1,6 +1,8 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global write_dir = ARGS[1] + """ (MPI) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 2D. @@ -8,10 +10,10 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, Min J(Ω) = -κ(Ω) Ω s.t., Vol(Ω) = vf, - ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, + ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, ⎣∫ ∑ᵢ C ⊙ ε(uᵢ) ⊙ ε(vᵢ) dΩ = ∫ -∑ᵢ C ⊙ ε⁰ᵢ ⊙ ε(vᵢ) dΩ, ∀v∈V. -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -26,9 +28,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4*max_steps*γ vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM_MPI/" iter_mod = 10 - #i_am_main(ranks) && mkdir(path) + #i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true)); @@ -79,7 +80,7 @@ function main(mesh_partition,distribute,el_size) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = ElasticitySolver(V) - + state_map = RepeatingAffineFEStateMap( 3,a,l,U,V,V_φ,U_reg,φh,dΩ; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -97,7 +98,7 @@ function main(mesh_partition,distribute,el_size) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) @@ -113,10 +114,10 @@ end with_mpi() do distribute mesh_partition = (2,2) el_size = (200,200) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end; \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs deleted file mode 100644 index 9ab66596..00000000 --- a/scripts/MPI/jobs/3d_elastic_compliance_ALM.pbs +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -l -#PBS -P LSTO -#PBS -N 3d_elastic_compliance_ALM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_elastic_compliance_ALM.jl \ - 160 \ - 80 \ - 80 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs deleted file mode 100644 index 58b91b3a..00000000 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_ALM.pbs +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -l -#PBS -P LSTO -#PBS -N 3d_hyperelastic_compliance_ALM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_ALM.jl \ - 160 \ - 80 \ - 80 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs b/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs deleted file mode 100644 index 67935f3b..00000000 --- a/scripts/MPI/jobs/3d_hyperelastic_compliance_neohook_ALM.pbs +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -l -#PBS -P LSTO -#PBS -N 3d_hyperelastic_compliance_neohook_ALM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl \ - 160 \ - 80 \ - 80 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs b/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs deleted file mode 100644 index 5a1e636d..00000000 --- a/scripts/MPI/jobs/3d_inverse_homenisation_ALM.pbs +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -l -#PBS -P LSTO -#PBS -N 3d_inverse_homenisation_ALM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_inverse_homenisation_ALM.jl \ - 100 \ - 100 \ - 100 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_inverter_ALM.pbs b/scripts/MPI/jobs/3d_inverter_ALM.pbs deleted file mode 100644 index 1eb0f7f2..00000000 --- a/scripts/MPI/jobs/3d_inverter_ALM.pbs +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N 3d_inverter_ALM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_inverter_ALM.jl \ - 100 \ - 100 \ - 100 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_inverter_HPM.pbs b/scripts/MPI/jobs/3d_inverter_HPM.pbs deleted file mode 100644 index 66365043..00000000 --- a/scripts/MPI/jobs/3d_inverter_HPM.pbs +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N 3d_inverter_HPM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_inverter_HPM.jl \ - 100 \ - 100 \ - 100 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs deleted file mode 100644 index 985235f3..00000000 --- a/scripts/MPI/jobs/3d_nonlinear_thermal_compliance_ALM.pbs +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N 3d_nonlinear_thermal_compliance_ALM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl \ - 100 \ - 100 \ - 100 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs b/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs deleted file mode 100644 index 5d69d821..00000000 --- a/scripts/MPI/jobs/3d_thermal_compliance_ALM.pbs +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N 3d_thermal_compliance_ALM - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/MPI/3d_thermal_compliance_ALM.jl \ - 150 \ - 150 \ - 150 \ - 5 \ - 5 \ - 5 \ No newline at end of file diff --git a/scripts/MPI/nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/nonlinear_thermal_compliance_ALM.jl index a4a835e5..ceb760da 100644 --- a/scripts/MPI/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/nonlinear_thermal_compliance_ALM.jl @@ -1,6 +1,8 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global write_dir = ARGS[1] + """ (MPI) Minimum thermal compliance with augmented Lagrangian method in 2D with nonlinear diffusivity. @@ -10,10 +12,10 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ(u)*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. - + In this example κ(u) = κ0*(exp(ξ*u)) -""" -function main(mesh_partition,distribute,el_size) +""" +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters order = 1 @@ -28,16 +30,15 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/nonlinear_thermal_compliance_ALM_MPI/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())); - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()); update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -85,7 +86,7 @@ function main(mesh_partition,distribute,el_size) α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) @@ -99,5 +100,5 @@ function main(mesh_partition,distribute,el_size) end with_mpi() do distribute - main((2,2),distribute,(200,200)) + main((2,2),distribute,(200,200),write_dir) end \ No newline at end of file diff --git a/scripts/MPI/thermal_compliance_ALM.jl b/scripts/MPI/thermal_compliance_ALM.jl index db881e3e..a90225d5 100644 --- a/scripts/MPI/thermal_compliance_ALM.jl +++ b/scripts/MPI/thermal_compliance_ALM.jl @@ -1,5 +1,7 @@ using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt +global write_dir = ARGS[1] + """ (MPI) Minimum thermal compliance with augmented Lagrangian method in 2D. @@ -10,7 +12,7 @@ using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. """ -function main(mesh_partition,distribute) +function main(mesh_partition,distribute,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -28,9 +30,8 @@ function main(mesh_partition,distribute) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -96,5 +97,5 @@ function main(mesh_partition,distribute) end with_mpi() do distribute - main((2,2),distribute) + main((2,2),distribute,write_dir) end \ No newline at end of file diff --git a/scripts/MPI/thermal_compliance_ALM_PETSc.jl b/scripts/MPI/thermal_compliance_ALM_PETSc.jl index 366f13ef..0344f063 100644 --- a/scripts/MPI/thermal_compliance_ALM_PETSc.jl +++ b/scripts/MPI/thermal_compliance_ALM_PETSc.jl @@ -1,6 +1,8 @@ -using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, +using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +global write_dir = ARGS[1] + """ (MPI) Minimum thermal compliance with augmented Lagrangian method in 2D. @@ -11,7 +13,7 @@ using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. """ -function main(mesh_partition,distribute,el_size) +function main(mesh_partition,distribute,el_size,path) ranks = distribute(LinearIndices((prod(mesh_partition),))) ## Parameters @@ -28,9 +30,8 @@ function main(mesh_partition,distribute,el_size) η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_MPI+PETSc/" iter_mod = 10 - i_am_main(ranks) && mkdir(path) + i_am_main(ranks) && mkpath(path) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); @@ -78,7 +79,7 @@ function main(mesh_partition,distribute,el_size) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = PETScLinearSolver() - + state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -112,10 +113,10 @@ end with_mpi() do distribute mesh_partition = (2,2) el_size = (400,400) - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" - + GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute,el_size) + main(mesh_partition,distribute,el_size,write_dir) end end \ No newline at end of file diff --git a/scripts/Serial/elastic_compliance_ALM.jl b/scripts/Serial/elastic_compliance_ALM.jl index 6b8e4d17..25c7aeb7 100644 --- a/scripts/Serial/elastic_compliance_ALM.jl +++ b/scripts/Serial/elastic_compliance_ALM.jl @@ -7,10 +7,10 @@ using Gridap, LevelSetTopOpt Min J(Ω) = ∫ C ⊙ ε(u) ⊙ ε(v) dΩ Ω s.t., Vol(Ω) = vf, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ = ∫ v⋅g dΓ_N, ∀v∈V. -""" -function main() +""" +function main(path="./results/elastic_compliance_ALM/") ## Parameters order = 1 xmax,ymax=(2.0,1.0) @@ -26,9 +26,8 @@ function main() α_coeff = 4max_steps*γ vf = 0.4 g = VectorValue(0,-1) - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_ALM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size) @@ -81,7 +80,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/Serial/elastic_compliance_HPM.jl b/scripts/Serial/elastic_compliance_HPM.jl index d13be2c1..14e734fe 100644 --- a/scripts/Serial/elastic_compliance_HPM.jl +++ b/scripts/Serial/elastic_compliance_HPM.jl @@ -7,10 +7,10 @@ using Gridap, LevelSetTopOpt Min J(Ω) = ∫ C ⊙ ε(u) ⊙ ε(v) dΩ Ω s.t., Vol(Ω) = vf, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ = ∫ v⋅g dΓ_N, ∀v∈V. -""" -function main() +""" +function main(path="./results/elastic_compliance_HPM/") ## Parameters order = 1 xmax,ymax=(2.0,1.0) @@ -26,15 +26,14 @@ function main() α_coeff = 4max_steps*γ vf = 0.4 g = VectorValue(0,-1) - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_HPM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size) el_Δ = get_el_Δ(model) f_Γ_D(x) = (x[1] ≈ 0.0) - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -82,7 +81,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/Serial/elastic_compliance_LM.jl b/scripts/Serial/elastic_compliance_LM.jl index 3accdfac..135cccd8 100644 --- a/scripts/Serial/elastic_compliance_LM.jl +++ b/scripts/Serial/elastic_compliance_LM.jl @@ -6,10 +6,10 @@ using Gridap, LevelSetTopOpt Optimisation problem: Min J(Ω) = ∫ C ⊙ ε(u) ⊙ ε(v) + ξ dΩ Ω - s.t., ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + s.t., ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ = ∫ v⋅g dΓ_N, ∀v∈V. -""" -function main() +""" +function main(path="./results/elastic_compliance_LM/") ## Parameters order = 1 xmax,ymax=(2.0,1.0) @@ -24,15 +24,14 @@ function main() η_coeff = 2 α_coeff = 4max_steps*γ g = VectorValue(0,-1) - path = dirname(dirname(@__DIR__))*"/results/elastic_compliance_LM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size) el_Δ = get_el_Δ(model) f_Γ_D(x) = iszero(x[1]) - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -78,7 +77,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true) for (it, uh, φh) in optimiser diff --git a/scripts/Serial/hyperelastic_compliance_ALM.jl b/scripts/Serial/hyperelastic_compliance_ALM.jl index 63b9e1bf..e3f15cfd 100644 --- a/scripts/Serial/hyperelastic_compliance_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_ALM.jl @@ -2,8 +2,8 @@ using Gridap, LevelSetTopOpt """ (Serial) Minimum hyperelastic compliance with augmented Lagrangian method in 2D. -""" -function main() +""" +function main(path="./results/hyperelastic_compliance_ALM/") ## Parameters order = 1 xmax,ymax=2.0,1.0 @@ -17,9 +17,8 @@ function main() η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.6 - path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_ALM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size); @@ -81,7 +80,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl index 72738c4e..d6ae9163 100644 --- a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl @@ -2,8 +2,8 @@ using Gridap, LevelSetTopOpt """ (Serial) Minimum hyperelastic (neohookean) compliance with augmented Lagrangian method in 2D. -""" -function main() +""" +function main(path="./results/hyperelastic_compliance_neohook_ALM/") ## Parameters order = 1 xmax,ymax=2.0,1.0 @@ -17,9 +17,8 @@ function main() η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.6 - path = dirname(dirname(@__DIR__))*"/results/hyperelastic_compliance_neohook_ALM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size); @@ -95,7 +94,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index 0ffdd411..d06b2d47 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -7,10 +7,10 @@ using Gridap, LevelSetTopOpt Min J(Ω) = -κ(Ω) Ω s.t., Vol(Ω) = vf, - ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, + ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, ⎣∫ ∑ᵢ C ⊙ ε(uᵢ) ⊙ ε(vᵢ) dΩ = ∫ -∑ᵢ C ⊙ ε⁰ᵢ ⊙ ε(vᵢ) dΩ, ∀v∈V. -""" -function main() +""" +function main(path="./results/inverse_homenisation_ALM/") ## Parameters order = 1 xmax,ymax=(1.0,1.0) @@ -24,9 +24,8 @@ function main() η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/inverse_homenisation_ALM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)) @@ -81,7 +80,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/Serial/inverter_ALM.jl b/scripts/Serial/inverter_ALM.jl index 132a32e3..f9a8e3be 100644 --- a/scripts/Serial/inverter_ALM.jl +++ b/scripts/Serial/inverter_ALM.jl @@ -7,14 +7,14 @@ using Gridap, LevelSetTopOpt Min J(Ω) = ηᵢₙ*∫ u⋅e₁ dΓᵢₙ/Vol(Γᵢₙ) Ω s.t., Vol(Ω) = vf, - C(Ω) = 0, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + C(Ω) = 0, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. - + where C(Ω) = ∫ -u⋅e₁-δₓ dΓₒᵤₜ/Vol(Γₒᵤₜ). We assume symmetry in the problem to aid convergence. -""" -function main() +""" +function main(path="./results/inverter_ALM/") ## Parameters order = 1 dom = (0,1,0,0.5) @@ -30,10 +30,9 @@ function main() δₓ = 0.2 ks = 0.1 g = VectorValue(0.5,0) - path = dirname(dirname(@__DIR__))*"/results/inverter_ALM/" iter_mod = 10 - mkdir(path) - + mkpath(path) + ## FE Setup model = CartesianDiscreteModel(dom,el_size) el_Δ = get_el_Δ(model) @@ -96,7 +95,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol,:UΓ_out]) diff --git a/scripts/Serial/inverter_HPM.jl b/scripts/Serial/inverter_HPM.jl index 39ed22a0..2274a2f4 100644 --- a/scripts/Serial/inverter_HPM.jl +++ b/scripts/Serial/inverter_HPM.jl @@ -7,14 +7,14 @@ using Gridap, LevelSetTopOpt Min J(Ω) = ηᵢₙ*∫ u⋅e₁ dΓᵢₙ/Vol(Γᵢₙ) Ω s.t., Vol(Ω) = vf, - C(Ω) = 0, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + C(Ω) = 0, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. - + where C(Ω) = ∫ -u⋅e₁-δₓ dΓₒᵤₜ/Vol(Γₒᵤₜ). We assume symmetry in the problem to aid convergence. -""" -function main() +""" +function main(path="./results/inverter_HPM/") ## Parameters order = 1 dom = (0,1,0,0.5) @@ -30,10 +30,9 @@ function main() δₓ = 0.2 ks = 0.1 g = VectorValue(0.5,0) - path = dirname(dirname(@__DIR__))*"/results/inverter_HPM/" iter_mod = 10 - mkdir(path) - + mkpath(path) + ## FE Setup model = CartesianDiscreteModel(dom,el_size) el_Δ = get_el_Δ(model) @@ -97,7 +96,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser ls_enabled=false # Setting to true will use a line search instead of oscillation detection optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh; diff --git a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl index 621060a2..16ffa9b4 100644 --- a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl @@ -9,10 +9,10 @@ using Gridap, LevelSetTopOpt s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ(u)*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. - + In this example κ(u) = κ0*(exp(ξ*u)) -""" -function main() +""" +function main(path="./results/nonlinear_thermal_compliance_ALM/") ## Parameters order = 1 xmax=ymax=1.0 @@ -27,16 +27,15 @@ function main() η_coeff = 2 α_coeff = 4max_steps*γ vf = 0.4 - path = dirname(dirname(@__DIR__))*"/results/nonlinear_thermal_compliance_ALM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())); - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()); update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -84,7 +83,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/Serial/thermal_compliance_ALM.jl b/scripts/Serial/thermal_compliance_ALM.jl index 9cd0883e..1201db0d 100644 --- a/scripts/Serial/thermal_compliance_ALM.jl +++ b/scripts/Serial/thermal_compliance_ALM.jl @@ -9,8 +9,8 @@ using Gridap, LevelSetTopOpt s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. -""" -function main() +""" +function main(path="./results/thermal_compliance_ALM/") ## Parameters order = 1 xmax=ymax=1.0 @@ -26,16 +26,15 @@ function main() vf = 0.4 η_coeff = 2 α_coeff = 4max_steps*γ - path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -82,7 +81,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl index 1cbc6344..3db4ea46 100644 --- a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl +++ b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl @@ -3,8 +3,8 @@ using Gridap, LevelSetTopOpt """ (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D. - This problem uses a higher order level set function than the FE solution for - the state equation. In future, second order upwind schemes will require a + This problem uses a higher order level set function than the FE solution for + the state equation. In future, second order upwind schemes will require a higher order FE function. Optimisation problem: @@ -13,8 +13,8 @@ using Gridap, LevelSetTopOpt s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. -""" -function main() +""" +function main(path="./results/thermal_compliance_ALM_higherorderlsf/") ## Parameters fe_order = 1 order = 2 @@ -31,16 +31,15 @@ function main() vf = 0.4 η_coeff = 2 α_coeff = 4max_steps*γ - path = dirname(dirname(@__DIR__))*"/results/thermal_compliance_ALM_higherorderlsf/" iter_mod = 10 - mkdir(path) + mkpath(path) ## FE Setup model = CartesianDiscreteModel(dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -88,7 +87,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl b/scripts/_dev/3d_hyperelastic_compliance_ALM.jl deleted file mode 100644 index ddc16243..00000000 --- a/scripts/_dev/3d_hyperelastic_compliance_ALM.jl +++ /dev/null @@ -1,203 +0,0 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -using GridapSolvers: NewtonSolver - -function main(mesh_partition,distribute,el_size,δₓ) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - - ## Parameters - order = 1 - xmax,ymax,zmax=(1.0,1.0,1.0) - dom = (0,xmax,0,ymax,0,zmax) - η_coeff = 2 - prop_Γ_N = 0.2; - path = dirname(dirname(@__DIR__))*"/results/testing_hyper_elast" - i_am_main(ranks) && ~isdir(path) && mkdir(path) - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) - f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2order) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D","Gamma_N"]) - U = TrialFESpace(V,[VectorValue(0.0,0.0,0.0),VectorValue(δₓ,0.0,0.0)]) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - # φh = interpolate(initial_lsf(4,0.2),V_φ) - φh = interpolate(x->-1,V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - ## Material properties and loading - _E = 1000 - ν = 0.3 - μ, λ = _E/(2*(1 + ν)), _E*ν/((1 + ν)*(1 - 2*ν)) - - ## Saint Venant–Kirchhoff law - F(∇u) = one(∇u) + ∇u' - E(F) = 0.5*( F' ⋅ F - one(F) ) - Σ(∇u) = λ*tr(E(F(∇u)))*one(∇u)+2*μ*E(F(∇u)) - T(∇u) = F(∇u) ⋅ Σ(∇u) - res(u,v,φ,dΩ) = ∫((I ∘ φ)*((T ∘ ∇(u)) ⊙ ∇(v)))dΩ - - ## Setup solver and FE operators - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - lin_solver = MUMPSSolver() - nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose=i_am_main(ranks)) - - state_map = NonlinearFEStateMap( - res,U,V,V_φ,U_reg,φh,dΩ; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - nls = nl_solver, adjoint_ls = lin_solver - ) - - ## Optimiser - u = LevelSetTopOpt.forward_solve!(state_map,φh) - uh = FEFunction(U,u) - writevtk(Ω,path*"/struc_$δₓ",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -function main_alt(mesh_partition,distribute,el_size,gz) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - - ## Parameters - order = 1 - xmax,ymax,zmax=(2.0,1.0,1.0) - dom = (0,xmax,0,ymax,0,zmax) - η_coeff = 2 - prop_Γ_N = 0.8; - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(5order^2)/minimum(el_size) - path = dirname(dirname(@__DIR__))*"/results/testing_hyper_elast" - i_am_main(ranks) && ~isdir(path) && mkdir(path) - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size) - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) - f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - # φh = interpolate(initial_lsf(4,0.2),V_φ) - φh = interpolate(x->-1,V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - ## Material properties and loading - _E = 1000 - ν = 0.3 - μ, λ = _E/(2*(1 + ν)), _E*ν/((1 + ν)*(1 - 2*ν)) - g = VectorValue(-gz,0,0) - - # Deformation gradient - # F(∇u) = one(∇u) + ∇u' - # J(F) = sqrt(det(C(F))) - # # Derivative of green Strain - # dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) - # # Right Caughy-green deformation tensor - # C(F) = (F')⋅F - # # Constitutive law (Neo hookean) - # function S(∇u) - # Cinv = inv(C(F(∇u))) - # μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv - # end - # # Cauchy stress tensor - # σ(∇u) = (1.0/J(F(∇u)))*F(∇u)⋅S(∇u)⋅(F(∇u))' - # res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE∘(∇(v),∇(u))) ⊙ (S∘∇(u))) )*dΩ - ∫(g⋅v)dΓ_N - - # ALT - F(∇u) = one(∇u) + ∇u' - E(F) = 0.5*( F' ⋅ F - one(F) ) - Σ(∇u) = λ*tr(E(F(∇u)))*one(∇u)+2*μ*E(F(∇u)) - T(∇u) = F(∇u) ⋅ Σ(∇u) - res(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((T ∘ ∇(u)) ⊙ ∇(v)))dΩ - ∫(g⋅v)dΓ_N - - ## Finite difference solver and level set function - # ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) - # reinit!(stencil,φh,γ_reinit) - - ## Setup solver and FE operators - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - lin_solver = MUMPSSolver() - nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose=i_am_main(ranks)) - - state_map = NonlinearFEStateMap( - res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - nls = nl_solver, adjoint_ls = lin_solver - ) - - ## Optimiser - u = LevelSetTopOpt.forward_solve!(state_map,φh) - uh = FEFunction(U,u) - writevtk(Ω,path*"/struc_neohook_$gz",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (2,2,2) - el_size = (43,43,43) - # solver = "-pc_type jacobi -ksp_type cg -ksp_monitor_short - # -ksp_converged_reason -ksp_rtol 1.0e-3 -mat_block_size 3" - # solver = "-pc_type mg -mg_levels_ksp_max_it 2 -snes_monitor_short -ksp_monitor_short -npc_snes_type fas - # -npc_fas_levels_snes_type ncg -npc_fas_levels_snes_max_it 3 -npc_snes_monitor_short -snes_max_it 2" - # solver = "-snes_type aspin -snes_monitor_short -ksp_monitor_short -npc_sub_snes_rtol 1e-2 -ksp_rtol 1e-2 -ksp_max_it 14 - # -snes_converged_reason -snes_max_linear_solve_fail 100 -snes_max_it 4 -npc_sub_ksp_type preonly -npc_sub_pc_type lu" - # solver = "-snes_rtol 1e-05 -snes_monitor_short -snes_converged_reason - # -ksp_type fgmres -ksp_rtol 1e-10 -ksp_monitor_short -ksp_converged_reason - # -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type upper - # -fieldsplit_deformation_ksp_type preonly -fieldsplit_deformation_pc_type lu - # -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi" - - GridapPETSc.with() do #args=split(solver)) do - # main(mesh_partition,distribute,el_size,0.02) - # main(mesh_partition,distribute,el_size,0.05) - main(mesh_partition,distribute,el_size,0.1) - # main_alt(mesh_partition,distribute,el_size,-20) - # main_alt(mesh_partition,distribute,el_size,-50) - # main_alt(mesh_partition,distribute,el_size,-100) - # main_alt(mesh_partition,distribute,el_size,-150) - end -end \ No newline at end of file diff --git a/scripts/_dev/OptimiserHistoryTests.jl b/scripts/_dev/OptimiserHistoryTests.jl deleted file mode 100644 index 4e4b64a8..00000000 --- a/scripts/_dev/OptimiserHistoryTests.jl +++ /dev/null @@ -1,8 +0,0 @@ - -using LevelSetTopOpt - -h = LevelSetTopOpt.OptimiserHistory(Float64,[:L,:J,:C1,:C2,:C3],Dict(:C => [:C1,:C2,:C3]),100,true) - -push!(h,(1.0,2.0,3.0,4.0,5.0)) - -write_history("results/tmp.txt",h) \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl deleted file mode 100644 index f3e23201..00000000 --- a/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl +++ /dev/null @@ -1,105 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -function main(mesh_partition,distribute,write_dir) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax,ymax,zmax = (2.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - el_size = (160,80,80) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor - g = VectorValue(0,0,-1) # Applied load on Γ_N - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "$write_dir/elast_comp_MPI_3D/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v⋅g)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = ElasticitySolver(V) - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(u)))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((C ⊙ ε(u) ⊙ ε(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map, - analytic_dJ=dJ,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, - verbose=i_am_main(ranks)) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (4,6,6) - write_dir = ARGS[1] - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute,write_dir) - end -end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl deleted file mode 100644 index d164c73d..00000000 --- a/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl +++ /dev/null @@ -1,121 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -using GridapSolvers: NewtonSolver - -function main(mesh_partition,distribute,write_dir) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax,ymax,zmax = (2.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - el_size = (160,80,80) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) # Γ_D indicator function - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - E = 1000 # Young's modulus - ν = 0.3 # Poisson's ratio - μ, λ = E/(2*(1 + ν)), E*ν/((1 + ν)*(1 - 2*ν)) # Lame constants - g = VectorValue(0,0,-1) # Applied load on Γ_N - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "$write_dir/hyperelast_comp_MPI_3D/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - ## Piola-Kirchhoff tensor - function S(∇u) - Cinv = inv(C(F(∇u))) - μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv - end - ## Derivative of Green strain - dE(∇du,∇u) = 0.5*( ∇du⋅F(∇u) + (∇du⋅F(∇u))' ) - ## Right Cauchy-Green deformation tensor - C(F) = (F')⋅F - ## Deformation gradient tensor - F(∇u) = one(∇u) + ∇u' - ## Volume change - J(F) = sqrt(det(C(F))) - ## Residual - res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE ∘ (∇(v),∇(u))) ⊙ (S ∘ ∇(u))) )*dΩ - ∫(g⋅v)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - lin_solver = ElasticitySolver(V) - nl_solver = NewtonSolver(lin_solver;maxiter=50,rtol=10^-8,verbose=i_am_main(ranks)) - state_map = NonlinearFEStateMap( - res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - nls = nl_solver, adjoint_ls = lin_solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*((dE ∘ (∇(u),∇(u))) ⊙ (S ∘ ∇(u))))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, - verbose=i_am_main(ranks)) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (4,6,6) - write_dir = ARGS[1] - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute,write_dir) - end -end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl deleted file mode 100644 index 83175010..00000000 --- a/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl +++ /dev/null @@ -1,108 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -function main(mesh_partition,distribute,write_dir) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - el_size = (100,100,100) # Mesh partition size - f_Γ_D(x) = iszero(x) # Γ_D indicator function - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor - vf = 0.4 # Volume fraction constraint - lsf_func(x) = cos(2π*x[1]) + cos(2π*x[2]) + # Initial level set function - cos(2π*x[3]) - iter_mod = 10 # VTK Output modulo - path = "$write_dir/inverse_hom_MPI_3D/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)); - update_labels!(1,model,f_Γ_D,"origin") - # Triangulation and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["origin"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar) - U_reg = TrialFESpace(V_reg) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - εᴹ = (TensorValue(1.,0.,0.,0.,0.,0.,0.,0.,0.), - TensorValue(0.,0.,0.,0.,1.,0.,0.,0.,0.), - TensorValue(0.,0.,0.,0.,0.,0.,0.,0.,1.), - TensorValue(0.,0.,0.,0.,0.,1/2,0.,1/2,0.), - TensorValue(0.,0.,1/2,0.,0.,0.,1/2,0.,0.), - TensorValue(0.,1/2,0.,1/2,0.,0.,0.,0.,0.)) - a(u,v,φ,dΩ) = ∫((I ∘ φ) * C ⊙ ε(u) ⊙ ε(v))dΩ - l = [(v,φ,dΩ) -> ∫(-(I ∘ φ) * C ⊙ εᴹ[i] ⊙ ε(v))dΩ for i in 1:6] - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = ElasticitySolver(V) - state_map = RepeatingAffineFEStateMap( - 6,a,l,U,V,V_φ,U_reg,φh,dΩ; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver, adjoint_ls = solver - ) - # Objective and constraints - Cᴴ(r,s,u,φ,dΩ) = ∫((I ∘ φ)*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ εᴹ[s]))dΩ - dCᴴ(r,s,q,u,φ,dΩ) = ∫(-q*(C ⊙ (ε(u[r])+εᴹ[r]) ⊙ (ε(u[s])+εᴹ[s]))*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - κ(u,φ,dΩ) = -1/9*(Cᴴ(1,1,u,φ,dΩ)+Cᴴ(2,2,u,φ,dΩ)+Cᴴ(3,3,u,φ,dΩ)+ - 2*(Cᴴ(1,2,u,φ,dΩ)+Cᴴ(1,3,u,φ,dΩ)+Cᴴ(2,3,u,φ,dΩ))) - dκ(q,u,φ,dΩ) = -1/9*(dCᴴ(1,1,q,u,φ,dΩ)+dCᴴ(2,2,q,u,φ,dΩ)+dCᴴ(3,3,q,u,φ,dΩ)+ - 2*(dCᴴ(1,2,q,u,φ,dΩ)+dCᴴ(1,3,q,u,φ,dΩ)+dCᴴ(2,3,q,u,φ,dΩ))) - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(κ,[C1],state_map, - analytic_dJ=dκ,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, - verbose=i_am_main(ranks)) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] - iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))]) -end - -with_mpi() do distribute - mesh_partition = (4,6,6) - write_dir = ARGS[1] - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute,write_dir) - end -end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl b/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl deleted file mode 100644 index 5ecde638..00000000 --- a/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl +++ /dev/null @@ -1,120 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -function main(mesh_partition,distribute,write_dir) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - el_size = (100,100,100) # Mesh partition size - f_Γ_in(x) = (x[1] ≈ 0.0) && # Γ_in indicator function - (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out(x) = (x[1] ≈ 1.0) && # Γ_out indicator function - (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out_ext(x) = ~f_Γ_out(x) && # Γ_out_ext indicator function - (0.9 <= x[1] <= 1.0) && (0.35 - eps() <= x[2] <= 0.65 + eps()) && - (0.35 - eps() <= x[3] <= 0.65 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function - (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - C = isotropic_elast_tensor(3,1.,0.3) # Stiffness tensor - g = VectorValue(1,0,0) # Applied load on Γ_N - ks = 0.01 # Artificial spring stiffness - δₓ = 0.4 # Required displacement - vf = 0.4 # Volume fraction constraint - sphere(x,(xc,yc,zc)) = -sqrt((x[1]-xc)^2+(x[2]-yc)^2+(x[3]-zc)^2) + 0.2 - lsf_func(x) = max(initial_lsf(4,0.2)(x), # Initial level set function - sphere(x,(1,0,0)),sphere(x,(1,0,1)),sphere(x,(1,1,0)),sphere(x,(1,1,1))) - iter_mod = 10 # VTK Output modulo - path = "$write_dir/inverter_MPI_3D/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_in,"Gamma_in") - update_labels!(2,model,f_Γ_out,"Gamma_out") - update_labels!(3,model,f_Γ_out_ext,"Gamma_out_ext") - update_labels!(4,model,f_Γ_D,"Gamma_D") - # Triangulation and measures - Ω = Triangulation(model) - Γ_in = BoundaryTriangulation(model,tags="Gamma_in") - Γ_out = BoundaryTriangulation(model,tags="Gamma_out") - dΩ = Measure(Ω,2*order) - dΓ_in = Measure(Γ_in,2*order) - dΓ_out = Measure(Γ_out,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=[ - "Gamma_in","Gamma_out","Gamma_out_ext"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ); - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_in,dΓ_out) = ∫((I ∘ φ)*(C ⊙ ε(u) ⊙ ε(v)))dΩ + ∫(ks*(u⋅v))dΓ_out - l(v,φ,dΩ,dΓ_in,dΓ_out) = ∫(v⋅g)dΓ_in - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = ElasticitySolver(V) - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - # Objective and constraints - e₁ = VectorValue(1,0,0) - vol_Γ_in = sum(∫(1)dΓ_in) - vol_Γ_out = sum(∫(1)dΓ_out) - vol_D = sum(∫(1)dΩ) - J(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅e₁)/vol_Γ_in)dΓ_in - C1(u,φ,dΩ,dΓ_in,dΓ_out) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_in,dΓ_out) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - C2(u,φ,dΩ,dΓ_in,dΓ_out) = ∫((u⋅-e₁-δₓ)/vol_Γ_out)dΓ_out - pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map,analytic_dC=[dC1,nothing]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, - verbose=i_am_main(ranks)) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (4,6,6) - write_dir = ARGS[1] - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute,write_dir) - end -end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs deleted file mode 100644 index 9fb3b55b..00000000 --- a/scripts/_dev/Paper_scripts/jobs-gadi/elast_comp_MPI_3D.pbs +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -l -#PBS -P np01 -#PBS -q normal -#PBS -N elast_comp_MPI_3D -#PBS -l ncpus=144 -#PBS -l mem=576GB -#PBS -l walltime=10:00:00 -#PBS -j oe - -source $HOME/hpc-environments/gadi/load-intel.sh -PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ - -mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl \ - $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs deleted file mode 100644 index f9b7897f..00000000 --- a/scripts/_dev/Paper_scripts/jobs-gadi/hyperelast_comp_MPI_3D.pbs +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -l -#PBS -P np01 -#PBS -q normal -#PBS -N hyperelast_comp_MPI_3D -#PBS -l ncpus=144 -#PBS -l mem=576GB -#PBS -l walltime=10:00:00 -#PBS -j oe - -source $HOME/hpc-environments/gadi/load-intel.sh -PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ - -mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl \ - $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs deleted file mode 100644 index 9cbe2ad9..00000000 --- a/scripts/_dev/Paper_scripts/jobs-gadi/inverse_hom_MPI_3D.pbs +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -l -#PBS -P np01 -#PBS -q normal -#PBS -N inverse_hom_MPI_3D -#PBS -l ncpus=144 -#PBS -l mem=576GB -#PBS -l walltime=24:00:00 -#PBS -j oe - -source $HOME/hpc-environments/gadi/load-intel.sh -PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ - -mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl \ - $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs deleted file mode 100644 index d16868d7..00000000 --- a/scripts/_dev/Paper_scripts/jobs-gadi/inverter_MPI_3D.pbs +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -l -#PBS -P np01 -#PBS -q normal -#PBS -N inverter_MPI_3D -#PBS -l ncpus=144 -#PBS -l mem=576GB -#PBS -l walltime=16:00:00 -#PBS -j oe - -source $HOME/hpc-environments/gadi/load-intel.sh -PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ - -mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl \ - $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs deleted file mode 100644 index d859dc27..00000000 --- a/scripts/_dev/Paper_scripts/jobs-gadi/therm_comp_MPI_3D.pbs +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -l -#PBS -P np01 -#PBS -q normal -#PBS -N therm_comp_MPI_3D -#PBS -l ncpus=144 -#PBS -l mem=576GB -#PBS -l walltime=3:00:00 -#PBS -j oe - -source $HOME/hpc-environments/gadi/load-intel.sh -PROJECT_DIR=$SCRATCH/LevelSetTopOpt/ - -mpirun -n 144 julia --project=$PROJECT_DIR --check-bounds no -O3 \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl \ - $PROJECT_DIR/results diff --git a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs deleted file mode 100644 index b257f199..00000000 --- a/scripts/_dev/Paper_scripts/jobs/elast_comp_MPI_3D.pbs +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N elast_comp_MPI_3D - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/elast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs deleted file mode 100644 index c2fd001a..00000000 --- a/scripts/_dev/Paper_scripts/jobs/hyperelast_comp_MPI_3D.pbs +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N hyperelast_comp_MPI_3D - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/hyperelast_comp_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs deleted file mode 100644 index e56cd3d1..00000000 --- a/scripts/_dev/Paper_scripts/jobs/inverse_hom_MPI_3D.pbs +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N inverse_hom_MPI_3D - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/inverse_hom_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs deleted file mode 100644 index a2c4e55c..00000000 --- a/scripts/_dev/Paper_scripts/jobs/inverter_MPI_3D.pbs +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N inverter_MPI_3D - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/inverter_MPI_3D.jl diff --git a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs b/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs deleted file mode 100644 index 775f4a00..00000000 --- a/scripts/_dev/Paper_scripts/jobs/therm_comp_MPI_3D.pbs +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -l - -#PBS -P LSTO -#PBS -N therm_comp_MPI_3D - -#PBS -l select=125:ncpus=1:mpiprocs=1:ompthreads=1:mem=8GB:cputype=6140 -#PBS -l walltime=23:00:00 -#PBS -j oe -#PBS -v I_MPI_HYDRA_BOOTSTRAP=rsh -#PBS -v I_MPI_HYDRA_BOOTSTRAP_EXEC=pbs_tmrsh -#PBS -v I_MPI_HYDRA_IFACE=ib0 -#PBS -v OMP_NUM_THREADS=1 - -source $HOME/hpc-environments-main/lyra/load-intel.sh -PROJECT_DIR=$HOME/LevelSetTopOpt/ - -julia --project=$PROJECT_DIR -e "using Pkg; Pkg.precompile()" - -mpirun -n 125 julia --project=$PROJECT_DIR --check-bounds no -O3 --compiled-modules=no \ - $PROJECT_DIR/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI.jl deleted file mode 100644 index a5476e50..00000000 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI.jl +++ /dev/null @@ -1,104 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -function main(mesh_partition,distribute,write_dir) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax,ymax = (1.0,1.0) # Domain size - dom = (0,xmax,0,ymax) # Bounding domain - el_size = (200,200) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/10)# Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "$write_dir/results/therm_comp_MPI/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = PETScLinearSolver() - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map, - analytic_dJ=dJ,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = solver - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (2,2) - write_dir = ARGS[1] - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute,write_dir) - end -end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl b/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl deleted file mode 100644 index be63b8db..00000000 --- a/scripts/_dev/Paper_scripts/therm_comp_MPI_3D.jl +++ /dev/null @@ -1,107 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -function main(mesh_partition,distribute,write_dir) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax,ymax,zmax = (1.0,1.0,1.0) # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - el_size = (150,150,150) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())&& - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/5) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "$write_dir/therm_comp_MPI_3D/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = PETScLinearSolver() - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map, - analytic_dJ=dJ,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = solver - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, - verbose=i_am_main(ranks)) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (4,6,6) - write_dir = ARGS[1] - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute,write_dir) - end -end \ No newline at end of file diff --git a/scripts/_dev/Paper_scripts/therm_comp_serial.jl b/scripts/_dev/Paper_scripts/therm_comp_serial.jl deleted file mode 100644 index 69fc7d73..00000000 --- a/scripts/_dev/Paper_scripts/therm_comp_serial.jl +++ /dev/null @@ -1,82 +0,0 @@ -using LevelSetTopOpt, Gridap - -function main(write_dir) - # FE parameters - order = 1 # Finite element order - xmax,ymax = (1.0,1.0) # Domain size - dom = (0,xmax,0,ymax) # Bounding domain - el_size = (200,200) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,order*minimum(el_size)/10)# Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "$write_dir/therm_comp_serial/" # Output path - mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C1(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC1(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C1],state_map, - analytic_dJ=dJ,analytic_dC=[dC1]) - # Velocity extension - α = 4max_steps*γ*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit, - verbose=true) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",get_history(optimiser)) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -main("results/") \ No newline at end of file diff --git a/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl b/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl deleted file mode 100644 index 9a0c3e3f..00000000 --- a/scripts/_dev/benchmark_tests/MPI_benchmark_test_2D_themal.jl +++ /dev/null @@ -1,108 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt - -""" -(MPI) Minimum thermal compliance with Lagrangian method in 2D. - -Optimisation problem: - Min J(Ω) = ∫ D*∇(u)⋅∇(u) + ξ dΩ - Ω - s.t., ⎡u∈V=H¹(Ω;u(Γ_D)=0), - ⎣∫ D*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. -""" -function main(mesh_partition,el_size,ranks) - ## Parameters - order = 1 - xmax=ymax=1.0 - prop_Γ_N = 0.2 - prop_Γ_D = 0.2 - dom = (0,xmax,0,ymax) - γ = 0.1 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(order^2*10)/minimum(el_size) - D = 1 - η_coeff = 2 - α_coeff = 4 - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) && ((x[2] <= ymax*prop_Γ_D + eps()) || (x[2] >= ymax-ymax*prop_Γ_D - eps())) - f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - - ## Spaces - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N - - ## Optimisation functionals - ξ = 0.3 - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(u) + ξ*(ρ ∘ φ))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((-ξ+D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; - - ## Finite difference solver and level set function - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) - reinit!(stencil,φh,γ_reinit) - - ## Setup solver and FE operators - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - pcfs = PDEConstrainedFunctionals(J,state_map,analytic_dJ=dJ) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - ## Optimiser - return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit) -end - -with_debug() do distribute - mesh_partition = (2,2) - el_size = (50,50) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - opt = main(mesh_partition,el_size,ranks) - ## Benchmark optimiser - bopt = benchmark_optimizer(opt, 1, ranks) - ## Benchmark forward problem - bfwd = benchmark_forward_problem(opt.problem.state_map, opt.φ0, ranks) - ## Benchmark advection - v = get_free_dof_values(interpolate(FEFunction(LevelSetTopOpt.get_deriv_space(opt.problem.state_map), - opt.problem.dJ),LevelSetTopOpt.get_aux_space(opt.problem.state_map))) - badv = benchmark_advection(opt.stencil, get_free_dof_values(opt.φ0), v, 0.1, ranks) - ## Benchmark reinitialisation - brinit = benchmark_reinitialisation(opt.stencil, get_free_dof_values(opt.φ0), 0.1, ranks) - ## Benchmark velocity extension - bvelext = benchmark_velocity_extension(opt.vel_ext, opt.problem.dJ, ranks) - ## Printing - if i_am_main(ranks) - open("TEST.txt","w") do f - bcontent = "bopt,bfwd,badv,brinit,bvelext\n" - for i ∈ eachindex(bopt) - bcontent *= "$(bopt[i]),$(bfwd[i]),$(badv[i]),$(brinit[i]),$(bvelext[i])\n" - end - write(f,bcontent) - end - end -end \ No newline at end of file diff --git a/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl b/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl deleted file mode 100644 index b04bbac8..00000000 --- a/scripts/_dev/benchmark_tests/MPI_benchmark_test_3D_themal.jl +++ /dev/null @@ -1,134 +0,0 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR - -""" - (MPI) Minimum thermal compliance with Lagrangian method in 3D. - - Optimisation problem: - Min J(Ω) = ∫ D*∇(u)⋅∇(u) + ξ dΩ - Ω - s.t., ⎡u∈V=H¹(Ω;u(Γ_D)=0), - ⎣∫ D*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. -""" -function main(mesh_partition,distribute,el_size) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - - ## Parameters - order = 1 - xmax=ymax=zmax=1.0 - prop_Γ_N = 0.2 - prop_Γ_D = 0.2 - dom = (0,xmax,0,ymax,0,zmax) - γ = 0.1 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(order^2*10)/minimum(el_size) - D = 1 - η_coeff = 2 - α_coeff = 4 - path = dirname(dirname(@__DIR__))*"/results/MPI_main_3d" - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) - f_Γ_N(x) = (x[1] ≈ xmax) && (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - - ## Spaces - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ); - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N - - ## Optimisation functionals - ξ = 0.1 - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(u) + ξ*(ρ ∘ φ))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) - reinit!(stencil,φh,γ_reinit) - - ## Setup solver and FE operators - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver = PETScLinearSolver() - - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver - ) - pcfs = PDEConstrainedFunctionals(J,state_map,analytic_dJ=dJ) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = solver - ) - - ## Optimiser - make_dir(path;ranks=ranks) - return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit) -end - -with_mpi() do distribute - mesh_partition = (3,3,2) - el_size = (100,100,100) - all_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - - GridapPETSc.with(args=split(all_solver_options)) do - opt = main(mesh_partition,distribute,el_size) - ## Benchmark optimiser - bopt = benchmark_optimizer(opt, 1, nothing) - ## Benchmark forward problem - bfwd = benchmark_forward_problem(opt.problem.state_map, opt.φ0, nothing) - ## Benchmark advection - v = get_free_dof_values(interpolate(FEFunction(LevelSetTopOpt.get_deriv_space(opt.problem.state_map), - opt.problem.dJ),LevelSetTopOpt.get_aux_space(opt.problem.state_map))) - badv = benchmark_advection(opt.stencil, get_free_dof_values(opt.φ0), v, 0.1, nothing) - ## Benchmark reinitialisation - brinit = benchmark_reinitialisation(opt.stencil, get_free_dof_values(opt.φ0), 0.1, nothing) - ## Benchmark velocity extension - bvelext = benchmark_velocity_extension(opt.vel_ext, opt.problem.dJ, nothing) - ## Printing - ranks = distribute(LinearIndices((prod(mesh_partition),))) - if i_am_main(ranks) - println("bopt => $bopt") - println("bfwd => $bfwd") - println("badv => $badv") - println("brinit => $brinit") - println("bvelext => $bvelext") - end - nothing - end -end; - diff --git a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl b/scripts/_dev/benchmark_tests/serial_benchmark_test.jl deleted file mode 100644 index 6ad4eec8..00000000 --- a/scripts/_dev/benchmark_tests/serial_benchmark_test.jl +++ /dev/null @@ -1,101 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt - -function main() - ## Parameters - order = 1 - xmax = ymax = 1.0 - prop_Γ_N = 0.2 - prop_Γ_D = 0.2 - dom = (0,xmax,0,ymax) - el_size = (200,200) - γ = 0.1 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(order^2*10)/minimum(el_size) # <- We can do better than this I think - D = 1 - η_coeff = 2 - α_coeff = 4 - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || - x[2] >= ymax-ymax*prop_Γ_D - eps())) ? true : false - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/2 + eps()) ? true : false - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - - ## Spaces - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N - - ## Optimisation functionals - ξ = 0.2; - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(u) + ξ*(ρ ∘ φ))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫((ξ-D*∇(u)⋅∇(u))*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) - - ## Setup solver and FE operators - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - pcfs = PDEConstrainedFunctionals(J,state_map,analytic_dJ=dJ) - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - ## Optimiser - return AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true) -end - -function main_benchmark() - opt = main() - ## Benchmark optimiser - bopt = benchmark_optimizer(opt, 1, nothing) - ## Benchmark forward problem - bfwd = benchmark_forward_problem(opt.problem.state_map, opt.φ0, nothing) - ## Benchmark advection - v = get_free_dof_values(interpolate(FEFunction(LevelSetTopOpt.get_deriv_space(opt.problem.state_map), - opt.problem.dJ),LevelSetTopOpt.get_aux_space(opt.problem.state_map))) - badv = benchmark_advection(opt.stencil, get_free_dof_values(opt.φ0), v, 0.1, nothing) - ## Benchmark reinitialisation - brinit = benchmark_reinitialisation(opt.stencil, get_free_dof_values(opt.φ0), 0.1, nothing) - ## Benchmark velocity extension - bvelext = benchmark_velocity_extension(opt.vel_ext, opt.problem.dJ, nothing) - return bopt,bfwd,badv,brinit,bvelext -end -bopt,bfwd,badv,brinit,bvelext = main_benchmark(); - -bopt -bfwd -badv -brinit -bvelext - -opt = main() - ## Benchmark optimiser -bopt0 = LevelSetTopOpt.benchmark_optimizer(opt,0, nothing; nreps = 10) -bopt = LevelSetTopOpt.benchmark_single_iteration(opt, nothing; nreps = 10) \ No newline at end of file diff --git a/scripts/_dev/bug_issue_46/thermal_MPI.jl b/scripts/_dev/bug_issue_46/thermal_MPI.jl deleted file mode 100644 index f318893d..00000000 --- a/scripts/_dev/bug_issue_46/thermal_MPI.jl +++ /dev/null @@ -1,91 +0,0 @@ -using LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, - SparseMatricesCSR - -function main(mesh_partition,distribute,use_l::Bool) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax = ymax = 1.0 # Domain size - dom = (0,xmax,0,ymax) # Bounding domain - el_size = (200,200) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) # @$\lvert\lvert$@ - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Advection tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "./results/AD_tut1_MPI_lobj_$use_l/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = if use_l - ∫(g*u)dΓ_N #+ ∫(0)dΩ - else - ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - end - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map) - # Velocity extension - α = 4*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension(a_hilb, U_reg, V_reg) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; - γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|nabla(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser);ranks) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|nabla(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (2,2) - main(mesh_partition,distribute,false) - main(mesh_partition,distribute,true) # <- this should crash -end \ No newline at end of file diff --git a/scripts/_dev/bug_issue_46/thermal_serial.jl b/scripts/_dev/bug_issue_46/thermal_serial.jl deleted file mode 100644 index 2d0e2017..00000000 --- a/scripts/_dev/bug_issue_46/thermal_serial.jl +++ /dev/null @@ -1,87 +0,0 @@ -using LevelSetTopOpt, Gridap - -function main(use_l::Bool) - # FE parameters - order = 1 # Finite element order - xmax = ymax = 1.0 # Domain size - dom = (0,xmax,0,ymax) # Bounding domain - el_size = (200,200) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) - # FD parameters - γ = 0.1 # HJ eqn time step coeff - γ_reinit = 0.5 # Reinit. eqn time step coeff - max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection - tol = 1/(5order^2)/minimum(el_size) # Reinitialisation tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # VTK Output modulo - path = "./results/tut1_lobj_$use_l/" # Output path - mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = if use_l - ∫(g*u)dΓ_N - else - ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - end - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map, - analytic_dJ=dJ,analytic_dC=[dC]) - # Velocity extension - α = 4*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; - γ,γ_reinit,verbose=true,constraint_names=[:Vol]) - # Solve - for (it,uh,φh) in optimiser - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"out$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser)) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"out$it",cellfields=["φ"=>φh, - "H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -main(false) -main(true) \ No newline at end of file diff --git a/scripts/_dev/fileio_testing.jl b/scripts/_dev/fileio_testing.jl deleted file mode 100644 index 4562d157..00000000 --- a/scripts/_dev/fileio_testing.jl +++ /dev/null @@ -1,52 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt - -using LevelSetTopOpt: save, load, load!, psave, pload, pload! - -with_debug() do distribute - mesh_partition = (2,2) - el_size = (10,10) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - model = CartesianDiscreteModel(ranks,mesh_partition,(0,1,0,1),el_size) - Ω = Triangulation(model) - reffe_scalar = ReferenceFE(lagrangian,Float64,1) - V_φ = TestFESpace(model,reffe_scalar) - - φh = interpolate(x->x[1]^2*x[2]^2,V_φ) - φ = get_free_dof_values(φh) - φ0 = copy(get_free_dof_values(φh)) - - linear_indices(φ) - - #save_object("./results/afolder/LSF_Data_1",φ) - #fill!(φ,0.0) - #load_object!("./results/afolder/LSF_Data_1",φ) - #@assert φ == φ0 - - psave("./results/afolder/LSF_Data_1",φ) - fill!(φ,0.0) - pload!("./results/afolder/LSF_Data_1",φ) - @assert φ == φ0 - -end - -begin - el_size = (10,10) - model = CartesianDiscreteModel((0,1,0,1),el_size) - Ω = Triangulation(model) - reffe_scalar = ReferenceFE(lagrangian,Float64,1) - V_φ = TestFESpace(model,reffe_scalar) - - φh = interpolate(x->x[1]^2*x[2]^2,V_φ) - φ = get_free_dof_values(φh) - φ0 = copy(get_free_dof_values(φh)) - - #save_object("./results/afolder/LSF_Data_1",φ) - #fill!(φ,0.0) - #load_object!("./results/afolder/LSF_Data_1",φ) - #@assert φ == φ0 - - save("./results/afolder/serial_LSF_Data_1.jld2",φ) - fill!(φ,0.0) - load!("./results/afolder/serial_LSF_Data_1.jld2",φ) - @assert φ == φ0 -end diff --git a/scripts/_dev/full_piezo_script.jl b/scripts/_dev/full_piezo_script.jl deleted file mode 100644 index 7ed4c1ab..00000000 --- a/scripts/_dev/full_piezo_script.jl +++ /dev/null @@ -1,236 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.FESpaces, Gridap.Helpers, Gridap.Algebra -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR -using ChainRulesCore -using LevelSetTopOpt - -using GridapSolvers -using Gridap.MultiField - -function main(mesh_partition,distribute,el_size) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - - ## Parameters - order = 1 - xmax,ymax,zmax=(1.0,1.0,1.0) - dom = (0,xmax,0,ymax,0,zmax) - γ = 0.05 - γ_reinit = 0.5 - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(2order^2)/minimum(el_size) - C = isotropic_elast_tensor(3,1.,0.3) - η_coeff = 2 - α_coeff = 4 - vf = 0.5 - path = dirname(dirname(@__DIR__))*"/results/MPI_main_3d_PZ_inverse_homenisation_ALM" - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)) - el_Δ = get_el_Δ(model) - f_Γ_D(x) = iszero(x) - update_labels!(1,model,f_Γ_D,"origin") - - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2*order) - vol_D = sum(∫(1)dΩ) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) - P = TrialFESpace(Q,0) - - mfs = BlockMultiFieldStyle() - UP = MultiFieldFESpace([U,P];style=mfs) - VQ = MultiFieldFESpace([V,Q];style=mfs) - - ## Create FE functions - lsf_fn(x) cos(2π*x[1]) + cos(2π*x[2]) + cos(2π*x[3]) - φh = interpolate(lsf_fn,V_φ) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - ## Material tensors - C, e, κ = PZT5A(3); - k0 = norm(C.data,Inf); - α0 = norm(e.data,Inf); - β0 = norm(κ.data,Inf); - γ = β0*k0/α0^2; - - ## Weak forms - εᴹ = (TensorValue(1.,0.,0.,0.,0.,0.,0.,0.,0.), # ϵᵢⱼ⁽¹¹⁾≡ϵᵢⱼ⁽¹⁾ - TensorValue(0.,0.,0.,0.,1.,0.,0.,0.,0.), # ϵᵢⱼ⁽²²⁾≡ϵᵢⱼ⁽²⁾ - TensorValue(0.,0.,0.,0.,0.,0.,0.,0.,1.), # ϵᵢⱼ⁽³³⁾≡ϵᵢⱼ⁽³⁾ - TensorValue(0.,0.,0.,0.,0.,1/2,0.,1/2,0.), # ϵᵢⱼ⁽²³⁾≡ϵᵢⱼ⁽⁴⁾ - TensorValue(0.,0.,1/2,0.,0.,0.,1/2,0.,0.), # ϵᵢⱼ⁽¹³⁾≡ϵᵢⱼ⁽⁵⁾ - TensorValue(0.,1/2,0.,1/2,0.,0.,0.,0.,0.)) # ϵᵢⱼ⁽¹²⁾≡ϵᵢⱼ⁽⁶⁾ - Eⁱ = (VectorValue(1.,0.,0.), - VectorValue(0.,1.,0), - VectorValue(0.,0.,1.)) - - a((u, ϕ),(v, q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - - 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + - -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + - -γ/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q))) )dΩ; - - l_ε = [(v, q) -> ∫((I ∘ φ) * (-C ⊙ εᴹ[i] ⊙ ε(v) + k0/α0*(e ⋅² εᴹ[i]) ⋅ -∇(q)))dΩ for i = 1:6]; - l_E = [(v, q) -> ∫(I ∘ φ) * ((Eⁱ[i] ⋅ e ⊙ ε(v) + k0/α0*(κ ⋅ Eⁱ[i]) ⋅ -∇(q)))dΩ for i = 1:3]; - l = [l_ε; l_E] - - ## Optimisation functionals - J(u,φ,dΩ) = @notimplemented # ∫(-(I ∘ φ)*_K(C,u,εᴹ))dΩ - dJ(q,u,φ,dΩ) = @notimplemented # ∫(-_v_K(C,u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - Vol(u,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; - dVol(q,u,φ,dΩ) = ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,tol,max_steps) - reinit!(stencil,φh,γ_reinit) - - ## Setup solver and FE operators - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - solver_u = ElasticitySolver(V) - solver_ϕ = PETScLinearSolver() - P = BlockDiagonalPreconditioner([solver_u,solver_ϕ]) - solver = GridapSolvers.LinearSolvers.GMRESSolver(100;Pr=P,rtol=1.e-8,verbose=i_am_main(ranks)) - - - state_map = RepeatingAffineFEStateMap( - 9,a,l,UP,VQ,V_φ,U_reg,φh,dΩ; - assem_U = SparseMatrixAssembler(Tm,Tv,UP,VQ), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,VQ,UP), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver, adjoint_ls = solver - ) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) - - J, C, dJ, dC = Gridap.evaluate!(pcfs,φh) - - # ## Hilbertian extension-regularisation problems - # α = α_coeff*maximum(el_Δ) - # a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - # vel_ext = VelocityExtension( - # a_hilb,U_reg,V_reg, - # assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - # ls = PETScLinearSolver() - # ) - - # ## Optimiser - # make_dir(path;ranks=ranks) - # optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) - # for (it, uh, φh) in optimiser - # write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) - # write_history(path*"/history.txt",optimiser.history;ranks=ranks) - # end - # it = optimiser.history.niter; uh = get_state(optimiser.problem) - # write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) -end; - -with_mpi() do distribute - main((2,2,2),distribute,(25,25,25)) -end; - -function dh(stuff) - C(M,N) = @notimplemented - e(i,M) = @notimplemented - dh = (C23^2*e31 - C22*C33*e31 + C13^2*e32 + C11*C23*e32 - C11*C33*e32 + - C12*C33*(e31 + e32) + C12^2*e33 + C11*(-C22 + C23)*e33 - C12*C23*(e31 + e33) + - C13*(-(C23*(e31 + e32)) + C22*(e31 + e33) - C12*(e32 + e33)))/( - C13^2*C22 - 2*C12*C13*C23 + C12^2*C33 + C11*(C23^2 - C22*C33)) -end - -## TESTING -model = CartesianDiscreteModel((0,1,0,1),(10,10)); -Ω = Triangulation(model) -dΩ = Measure(Ω,2) -V = TestFESpace(model,ReferenceFE(lagrangian,Float64,1)) -uh = interpolate(x->x[1]^2*x[2]^2,V); -Cmock = [i*j*∫(uh)dΩ for i = 1:3, j =1:3] - -## Piezo helpers -function PZT5A(D::Int) - ε_0 = 8.854e-12; - if D == 3 - C_Voigt = [12.0400e10 7.52000e10 7.51000e10 0.0 0.0 0.0 - 7.52000e10 12.0400e10 7.51000e10 0.0 0.0 0.0 - 7.51000e10 7.51000e10 11.0900e10 0.0 0.0 0.0 - 0.0 0.0 0.0 2.1000e10 0.0 0.0 - 0.0 0.0 0.0 0.0 2.1000e10 0.0 - 0.0 0.0 0.0 0.0 0.0 2.30e10] - e_Voigt = [0.0 0.0 0.0 0.0 12.30000 0.0 - 0.0 0.0 0.0 12.30000 0.0 0.0 - -5.40000 -5.40000 15.80000 0.0 0.0 0.0] - K_Voigt = [540*ε_0 0 0 - 0 540*ε_0 0 - 0 0 830*ε_0] - elseif D == 2 - C_Voigt = [12.0400e10 7.51000e10 0.0 - 7.51000e10 11.0900e10 0.0 - 0.0 0.0 2.1000e10] - e_Voigt = [0.0 0.0 12.30000 - -5.40000 15.80000 0.0] - K_Voigt = [540*ε_0 0 - 0 830*ε_0] - else - @notimplemented - end - C = voigt2tensor4(C_Voigt) - e = voigt2tensor3(e_Voigt) - κ = voigt2tensor2(K_Voigt) - C,e,κ -end - -""" - Given a material constant given in Voigt notation, - return a SymFourthOrderTensorValue using ordering from Gridap -""" -function voigt2tensor4(A::Array{M,2}) where M - if isequal(size(A),(3,3)) - return SymFourthOrderTensorValue(A[1,1], A[3,1], A[2,1], - A[1,3], A[3,3], A[2,3], - A[1,2], A[3,2], A[2,2]) - elseif isequal(size(A),(6,6)) - return SymFourthOrderTensorValue(A[1,1], A[6,1], A[5,1], A[2,1], A[4,1], A[3,1], - A[1,6], A[6,6], A[5,6], A[2,6], A[4,6], A[3,6], - A[1,5], A[6,5], A[5,5], A[2,5], A[4,5], A[3,5], - A[1,2], A[6,2], A[5,2], A[2,2], A[4,2], A[3,2], - A[1,4], A[6,4], A[5,4], A[2,4], A[4,4], A[3,4], - A[1,3], A[6,3], A[5,3], A[2,3], A[4,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a ThirdOrderTensorValue using ordering from Gridap -""" -function voigt2tensor3(A::Array{M,2}) where M - if isequal(size(A),(2,3)) - return ThirdOrderTensorValue(A[1,1], A[2,1], A[1,3], A[2,3], A[1,3], A[2,3], A[1,2], A[2,2]) - elseif isequal(size(A),(3,6)) - return ThirdOrderTensorValue( - A[1,1], A[2,1], A[3,1], A[1,6], A[2,6], A[3,6], A[1,5], A[2,5], A[3,5], - A[1,6], A[2,6], A[3,6], A[1,2], A[2,2], A[3,2], A[1,4], A[2,4], A[3,4], - A[1,5], A[2,5], A[3,5], A[1,4], A[2,4], A[3,4], A[1,3], A[2,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a SymTensorValue using ordering from Gridap -""" -function voigt2tensor2(A::Array{M,2}) where M - return TensorValue(A) -end \ No newline at end of file diff --git a/scripts/_dev/full_piezo_script_2d.jl b/scripts/_dev/full_piezo_script_2d.jl deleted file mode 100644 index f56e65fa..00000000 --- a/scripts/_dev/full_piezo_script_2d.jl +++ /dev/null @@ -1,246 +0,0 @@ -using LevelSetTopOpt, Gridap - -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.FESpaces, Gridap.Helpers, Gridap.Algebra -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR -using ChainRulesCore - -using GridapSolvers -using Gridap.MultiField - -## Piezo helpers -function PZT5A(D::Int) - ε_0 = 8.854e-12; - if D == 3 - C_Voigt = [12.0400e10 7.52000e10 7.51000e10 0.0 0.0 0.0 - 7.52000e10 12.0400e10 7.51000e10 0.0 0.0 0.0 - 7.51000e10 7.51000e10 11.0900e10 0.0 0.0 0.0 - 0.0 0.0 0.0 2.1000e10 0.0 0.0 - 0.0 0.0 0.0 0.0 2.1000e10 0.0 - 0.0 0.0 0.0 0.0 0.0 2.30e10] - e_Voigt = [0.0 0.0 0.0 0.0 12.30000 0.0 - 0.0 0.0 0.0 12.30000 0.0 0.0 - -5.40000 -5.40000 15.80000 0.0 0.0 0.0] - K_Voigt = [540*ε_0 0 0 - 0 540*ε_0 0 - 0 0 830*ε_0] - elseif D == 2 - C_Voigt = [12.0400e10 7.51000e10 0.0 - 7.51000e10 11.0900e10 0.0 - 0.0 0.0 2.1000e10] - e_Voigt = [0.0 0.0 12.30000 - -5.40000 15.80000 0.0] - K_Voigt = [540*ε_0 0 - 0 830*ε_0] - else - @notimplemented - end - C = voigt2tensor4(C_Voigt) - e = voigt2tensor3(e_Voigt) - κ = voigt2tensor2(K_Voigt) - C,e,κ -end - -""" - Given a material constant given in Voigt notation, - return a SymFourthOrderTensorValue using ordering from Gridap -""" -function voigt2tensor4(A::Array{M,2}) where M - if isequal(size(A),(3,3)) - return SymFourthOrderTensorValue(A[1,1], A[3,1], A[2,1], - A[1,3], A[3,3], A[2,3], - A[1,2], A[3,2], A[2,2]) - elseif isequal(size(A),(6,6)) - return SymFourthOrderTensorValue(A[1,1], A[6,1], A[5,1], A[2,1], A[4,1], A[3,1], - A[1,6], A[6,6], A[5,6], A[2,6], A[4,6], A[3,6], - A[1,5], A[6,5], A[5,5], A[2,5], A[4,5], A[3,5], - A[1,2], A[6,2], A[5,2], A[2,2], A[4,2], A[3,2], - A[1,4], A[6,4], A[5,4], A[2,4], A[4,4], A[3,4], - A[1,3], A[6,3], A[5,3], A[2,3], A[4,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a ThirdOrderTensorValue using ordering from Gridap -""" -function voigt2tensor3(A::Array{M,2}) where M - if isequal(size(A),(2,3)) - return ThirdOrderTensorValue(A[1,1], A[2,1], A[1,3], A[2,3], A[1,3], A[2,3], A[1,2], A[2,2]) - elseif isequal(size(A),(3,6)) - return ThirdOrderTensorValue( - A[1,1], A[2,1], A[3,1], A[1,6], A[2,6], A[3,6], A[1,5], A[2,5], A[3,5], - A[1,6], A[2,6], A[3,6], A[1,2], A[2,2], A[3,2], A[1,4], A[2,4], A[3,4], - A[1,5], A[2,5], A[3,5], A[1,4], A[2,4], A[3,4], A[1,3], A[2,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a SymTensorValue using ordering from Gridap -""" -function voigt2tensor2(A::Array{M,2}) where M - return TensorValue(A) -end - -## Parameters -el_size = (100,100) -order = 1 -xmax,ymax=(1.0,1.0) -dom = (0,xmax,0,ymax) -γ = 0.1 -γ_reinit = 0.5 -max_steps = floor(Int,order*minimum(el_size)/10) -tol = 1/(5order^2)/minimum(el_size) -η_coeff = 2 -α_coeff = 4*max_steps*γ -vf = 0.5 -path = dirname(dirname(@__DIR__))*"/results/2d_PZ_inverse_homenisation_ALM" - -## FE Setup -model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)) -el_Δ = get_el_Δ(model) -f_Γ_D(x) = iszero(x) -update_labels!(1,model,f_Γ_D,"origin") - -## Triangulations and measures -Ω = Triangulation(model) -dΩ = Measure(Ω,2*order) -vol_D = sum(∫(1)dΩ) - -## Spaces -reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) -reffe_scalar = ReferenceFE(lagrangian,Float64,order) -V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) -U = TrialFESpace(V,VectorValue(0.0,0.0)) -Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) -P = TrialFESpace(Q,0) -# mfs = BlockMultiFieldStyle() -UP = MultiFieldFESpace([U,P])#;style=mfs) -VQ = MultiFieldFESpace([V,Q])#;style=mfs) - -V_φ = TestFESpace(model,reffe_scalar) -V_reg = TestFESpace(model,reffe_scalar) -U_reg = TrialFESpace(V_reg) - -## Create FE functions -φh = interpolate(initial_lsf(4,0.2),V_φ) - -## Interpolation and weak form -interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ))#,ϵ=10^-9) -I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - -## Material tensors -C, e, κ = PZT5A(2); -k0 = norm(C.data,Inf); -α0 = norm(e.data,Inf); -β0 = norm(κ.data,Inf); -γ = β0*k0/α0^2; - -## Weak forms -εᴹ = (SymTensorValue(1.0,0.0,0.0), - SymTensorValue(0.0,0.0,1.0), - SymTensorValue(0.0,1/2,0)) -Eⁱ = (VectorValue(1.0,0.0,), - VectorValue(0.0,1.0)) - -a((u,ϕ),(v,q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - - 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + - -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + - -γ/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q))) )dΩ; - -l_ε = [((v,q),φ,dΩ) -> ∫(((I ∘ φ) * (-C ⊙ εᴹ[i] ⊙ ε(v) + k0/α0*(e ⋅² εᴹ[i]) ⋅ -∇(q))))dΩ for i = 1:3]; -l_E = [((v,q),φ,dΩ) -> ∫((I ∘ φ) * ((Eⁱ[i] ⋅ e ⊙ ε(v) + k0/α0*(κ ⋅ Eⁱ[i]) ⋅ -∇(q))))dΩ for i = 1:2]; -l = [l_ε; l_E] - -state_map = RepeatingAffineFEStateMap(5,a,l,UP,VQ,V_φ,U_reg,φh,dΩ) - -x = state_map(φh) -U = LevelSetTopOpt.get_trial_space(state_map) -xh = FEFunction(U,x) -# u1,ϕ1,u2,ϕ2,u3,ϕ3,u4,ϕ4,u5,ϕ5 = xh - - -function Cᴴ(r,s,uϕ,φ,dΩ) # (normalised by 1/k0) - u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] - ∫(1/k0 * (I ∘ φ) * (((C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ εᴹ[r]) + ((1/α0*∇(ϕ_s) ⋅ e) ⊙ εᴹ[r])))dΩ; -end - -function eᴴ(i,s,uϕ,φ,dΩ) # (normalised by 1/α0) - u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] - ∫(1/α0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ Eⁱ[i])))dΩ; -end - -function κᴴ(i,j,uϕ,φ,dΩ) # (normalised by 1/β0) - u_j = uϕ[6+2j-1]; ϕ_j = uϕ[6+2j] - ∫(1/β0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_j)) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_j) + Eⁱ[j])) ⋅ Eⁱ[i]))))dΩ; -end - -function dᴴ(uϕ,φ,dΩ) - _Cᴴ(r,s) = sum(Cᴴ(r,s,uϕ,φ,dΩ)) - _eᴴ(i,s) = sum(eᴴ(i,s,uϕ,φ,dΩ)) - (_Cᴴ(2,2)*_eᴴ(2,1) + _Cᴴ(1,1)*_eᴴ(2,2) - _Cᴴ(2,1)*(_eᴴ(2,1) + _eᴴ(2,2)))/ - (_Cᴴ(1,1)*_Cᴴ(2,2) - _Cᴴ(2,1)^2) -end - -# map(rs->sum(Cᴴ(rs[1],rs[2],xh,φh,dΩ)), CartesianIndices((1:3, 1:3))) -# map(is->sum(eᴴ(is[1],is[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:3))) -# map(ij->sum(κᴴ(ij[1],ij[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:2))) -dᴴ(xh,φh,dΩ)#*α0/k0 - -C_mat = map(rs->sum(Cᴴ(rs[1],rs[2],xh,φh,dΩ)), CartesianIndices((1:3, 1:3))) -e_mat = map(is->sum(eᴴ(is[1],is[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:3))) -d_mat = e_mat*inv(C_mat); -dh = d_mat[2,1] + d_mat[2,2] - -nothing -# ## Optimisation functionals -# J((u, p),φ,dΩ) = ∫(0)dΩ -# dJ(q,(u, p),φ,dΩ) = ∫(0q)dΩ -# Vol((u, p),φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; -# dVol(q,(u, p),φ,dΩ) = ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - -# ## Finite difference solver and level set function -# stencil = AdvectionStencil(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) - -# ## Setup solver and FE operators -# state_map = RepeatingAffineFEStateMap(5,a,l,UP,VQ,V_φ,U_reg,φh,dΩ) -# pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) - -# evaluate!(pcfs,φh) - -# ## Hilbertian extension-regularisation problems -# α = α_coeff*maximum(el_Δ) -# a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; -# vel_ext = VelocityExtension( -# a_hilb,U_reg,V_reg, -# assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), -# ls = PETScLinearSolver() -# ) - -# ## Optimiser -# make_dir(path;ranks=ranks) -# optimiser = AugmentedLagrangian(pcfs,stencil,vel_ext,φh;γ,γ_reinit,verbose=i_am_main(ranks)) -# for (it, uh, φh) in optimiser -# write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -# write_history(path*"/history.txt",optimiser.history;ranks=ranks) -# end -# it = optimiser.history.niter; uh = get_state(optimiser.problem) -# write_vtk(Ω,path*"/struc_$it",it,["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh];iter_mod=1) - - -function dh(stuff) - C(M,N) = @notimplemented - e(i,M) = @notimplemented - dh = (C23^2*e31 - C22*C33*e31 + C13^2*e32 + C11*C23*e32 - C11*C33*e32 + - C12*C33*(e31 + e32) + C12^2*e33 + C11*(-C22 + C23)*e33 - C12*C23*(e31 + e33) + - C13*(-(C23*(e31 + e32)) + C22*(e31 + e33) - C12*(e32 + e33)))/( - C13^2*C22 - 2*C12*C13*C23 + C12^2*C33 + C11*(C23^2 - C22*C33)) -end diff --git a/scripts/_dev/inv_hom_block_assem_testing.jl b/scripts/_dev/inv_hom_block_assem_testing.jl deleted file mode 100644 index 14d2b24a..00000000 --- a/scripts/_dev/inv_hom_block_assem_testing.jl +++ /dev/null @@ -1,132 +0,0 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR - -nothing - -np = (2,3); - -ranks = with_debug() do distribute - distribute(LinearIndices((prod(np),))) -end; - -## Parameters -order = 1; -xmax,ymax=(1.0,1.0) -dom = (0,xmax,0,ymax); -el_size = (10,10); -γ = 0.05; -γ_reinit = 0.5; -max_steps = floor(Int,minimum(el_size)/10) -tol = 1/(order^2*10)/minimum(el_size) -C = isotropic_elast_tensor(2,1.,0.3); -η_coeff = 2; -α_coeff = 4; -path = dirname(dirname(@__DIR__))*"/results/block_testing" - -## FE Setup -model = CartesianDiscreteModel(ranks,(2,3),dom,el_size,isperiodic=(true,true)); -# model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)); -el_Δ = get_el_Δ(model) -f_Γ_D(x) = iszero(x) -update_labels!(1,model,f_Γ_D,"origin") - -## Triangulations and measures -Ω = Triangulation(model) -dΩ = Measure(Ω,2order) -vol_D = sum(∫(1)dΩ) - -## Spaces -reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) -reffe_scalar = ReferenceFE(lagrangian,Float64,order) -_V = TestFESpace(model,reffe;dirichlet_tags=["origin"]) -_U = TrialFESpace(_V,VectorValue(0.0,0.0)) -mfs = BlockMultiFieldStyle() -U = MultiFieldFESpace([_U,_U,_U];style=mfs); -V = MultiFieldFESpace([_V,_V,_V];style=mfs); -V_reg = V_φ = TestFESpace(model,reffe_scalar) -U_reg = TrialFESpace(V_reg) - -## Create FE functions -lsf_fn = x->max(initial_lsf(2,0.4)(x),initial_lsf(2,0.4;b=VectorValue(0,0.5))(x)); -φh = interpolate(-1,V_φ); -φ = get_free_dof_values(φh) - -## Interpolation and weak form -interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) -I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - -εᴹ = (TensorValue(1.,0.,0.,0.), # ϵᵢⱼ⁽¹¹⁾≡ϵᵢⱼ⁽¹⁾ - TensorValue(0.,0.,0.,1.), # ϵᵢⱼ⁽²²⁾≡ϵᵢⱼ⁽²⁾ - TensorValue(0.,1/2,1/2,0.)) # ϵᵢⱼ⁽¹²⁾≡ϵᵢⱼ⁽³⁾ - -a(u,v,φ,dΩ) = ∫((I ∘ φ)*sum(C ⊙ ε(u[i]) ⊙ ε(v[i]) for i = 1:length(u)))dΩ -l(v,φ,dΩ) = ∫(-(I ∘ φ)*sum(C ⊙ εᴹ[i] ⊙ ε(v[i]) for i ∈ 1:length(v)))dΩ; -res(u,v,φ,dΩ) = a(u,v,φ,dΩ) - l(v,φ,dΩ) - -## Optimisation functionals -_C(C,ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q; -_K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],εᴹ[2]))/4 -_v_K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],ε(u1)+εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],ε(u2)+εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],ε(u2)+εᴹ[2]))/4 - -J = (u,φ,dΩ) -> ∫(-(I ∘ φ)*_K(C,u,εᴹ))dΩ -dJ = (q,u,φ,dΩ) -> ∫(-_v_K(C,u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; -Vol = (u,φ,dΩ) -> ∫(((ρ ∘ φ) - 0.5)/vol_D)dΩ; -dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - -## Finite difference solver and level set function -ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol); -reinit!(stencil,φ,γ_reinit) - -## Initialise op -uhd = zero(U); -Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} -Tv=Vector{PetscScalar} -assem = DiagonalBlockMatrixAssembler(SparseMatrixAssembler(Tm,Tv,U,V)); -@time op = AffineFEOperator((u,v) -> a(u,v,φh,dΩ),v -> l(v,φh,dΩ),U,V,assem); -K = get_matrix(op); b = get_vector(op); -x = GridapDistributed.allocate_in_domain(K) - -## Initialise adjoint -assem_adjoint = DiagonalBlockMatrixAssembler(SparseMatrixAssembler(V,U)); -adjoint_K = assemble_matrix((u,v) -> a(v,u,φh,dΩ),assem_adjoint,V,U); - -## Update mat and vec -LevelSetTopOpt._assemble_matrix_and_vector!((u,v) -> a(u,v,φh,dΩ),v -> l(v,φh,dΩ),K,b,assem,U,V,uhd) -# numerical_setup!(...) - -## Update adjoint -LevelSetTopOpt.assemble_matrix!((u,v) -> a(v,u,φh,dΩ),adjoint_K,assem_adjoint,V,U) - -### Test -@time op_test = AffineFEOperator((u,v) -> a(u,v,φh,dΩ),v -> l(v,φh,dΩ),U,V,SparseMatrixAssembler(U,V)) -K_test = get_matrix(op_test); b_test=get_vector(op_test) -x_test = GridapDistributed.allocate_in_domain(K_test) -@show Base.summarysize(K) -@show Base.summarysize(K_test) - -using BlockArrays -if typeof(K_test) <: BlockArray - @assert K_test == K -else - for I ∈ CartesianIndices(K.blocks) - @assert K.blocks[I].matrix_partition.items[:] ≈ K_test.blocks[I].matrix_partition.items[:] - end -end - -## Solver -options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky"; - -GridapPETSc.with(args=split(options)) do - P = BlockDiagonalPreconditioner(map(Vi -> ElasticitySolver(Vi),V)) - solver = GridapSolvers.LinearSolvers.CGSolver(P;rtol=1.e-8,verbose=i_am_main(ranks)) - P2 = BlockDiagonalPreconditioner(map(Vi -> ElasticitySolver(Vi),V)) - solver2 = GridapSolvers.LinearSolvers.CGSolver(P2;rtol=1.e-8,verbose=i_am_main(ranks)) - - @time ns = numerical_setup(symbolic_setup(solver,K),K) - @time ns_test = numerical_setup(symbolic_setup(solver2,K_test),K_test) - - @time numerical_setup!(ns,K) - @time numerical_setup!(ns_test,K_test) -end \ No newline at end of file diff --git a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl b/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl deleted file mode 100644 index 3c7e57a6..00000000 --- a/scripts/_dev/inv_hom_block_assem_testing_3D_MPI.jl +++ /dev/null @@ -1,172 +0,0 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -using Gridap.MultiField: BlockMultiFieldStyle - -""" - (MPI) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 3D. - - Optimisation problem: - Min J(Ω) = -κ(Ω) - Ω - s.t., Vol(Ω) = Vf, - ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, - ⎣∫ ∑ᵢ C ⊙ ε(uᵢ) ⊙ ε(vᵢ) dΩ = ∫ -∑ᵢ C ⊙ ε⁰ᵢ ⊙ ε(vᵢ) dΩ, ∀v∈V. -""" -function main(mesh_partition,distribute,el_size,diag_assem::Bool) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - t = PTimer(ranks) - - ## Parameters - order = 1; - xmax,ymax,zmax=(1.0,1.0,1.0) - dom = (0,xmax,0,ymax,0,zmax); - γ = 0.05; - γ_reinit = 0.5; - max_steps = floor(Int,minimum(el_size)/3) - tol = 1/(order^2*10)/minimum(el_size) - C = isotropic_elast_tensor(3,1.,0.3); - η_coeff = 2; - α_coeff = 4; - path = dirname(dirname(@__DIR__))*"/results/MPI_main_3d_inverse_homenisation_ALM" - - ## FE Setup - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = iszero(x) - update_labels!(1,model,f_Γ_D,"origin") - - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2order) - vol_D = sum(∫(1)dΩ) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - _V = TestFESpace(model,reffe;dirichlet_tags=["origin"]) - _U = TrialFESpace(_V,VectorValue(0.0,0.0,0.0)) - mfs = BlockMultiFieldStyle() - U = MultiFieldFESpace([_U,_U,_U,_U,_U,_U];style=mfs); - V = MultiFieldFESpace([_V,_V,_V,_V,_V,_V];style=mfs); - V_reg = V_φ = TestFESpace(model,reffe_scalar) - U_reg = TrialFESpace(V_reg) - - ## Create FE functions - lsf_fn = x -> cos(2π*x[1]) + cos(2π*x[2]) + cos(2π*x[3]) - φh = interpolate(lsf_fn,V_φ); - φ = get_free_dof_values(φh) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - εᴹ = (TensorValue(1.,0.,0.,0.,0.,0.,0.,0.,0.), # ϵᵢⱼ⁽¹¹⁾≡ϵᵢⱼ⁽¹⁾ - TensorValue(0.,0.,0.,0.,1.,0.,0.,0.,0.), # ϵᵢⱼ⁽²²⁾≡ϵᵢⱼ⁽²⁾ - TensorValue(0.,0.,0.,0.,0.,0.,0.,0.,1.), # ϵᵢⱼ⁽³³⁾≡ϵᵢⱼ⁽³⁾ - TensorValue(0.,0.,0.,0.,0.,1/2,0.,1/2,0.), # ϵᵢⱼ⁽²³⁾≡ϵᵢⱼ⁽⁴⁾ - TensorValue(0.,0.,1/2,0.,0.,0.,1/2,0.,0.), # ϵᵢⱼ⁽¹³⁾≡ϵᵢⱼ⁽⁵⁾ - TensorValue(0.,1/2,0.,1/2,0.,0.,0.,0.,0.)) # ϵᵢⱼ⁽¹²⁾≡ϵᵢⱼ⁽⁶⁾ - - a(u,v,φ,dΩ) = ∫((I ∘ φ)*sum(C ⊙ ε(u[i]) ⊙ ε(v[i]) for i = 1:length(u)))dΩ - l(v,φ,dΩ) = ∫(-(I ∘ φ)*sum(C ⊙ εᴹ[i] ⊙ ε(v[i]) for i = 1:length(v)))dΩ; - res(u,v,φ,dΩ) = a(u,v,φ,dΩ) - l(v,φ,dΩ) - - ## Optimisation functionals - _C(C,ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q; - - _K(C,u,εᴹ) = (_C(C,ε(u[1])+εᴹ[1],εᴹ[1]) + _C(C,ε(u[2])+εᴹ[2],εᴹ[2]) + _C(C,ε(u[3])+εᴹ[3],εᴹ[3]) + - 2(_C(C,ε(u[1])+εᴹ[1],εᴹ[2]) + _C(C,ε(u[1])+εᴹ[1],εᴹ[3]) + _C(C,ε(u[2])+εᴹ[2],εᴹ[3])))/9 - - _v_K(C,u,εᴹ) = (_C(C,ε(u[1])+εᴹ[1],ε(u[1])+εᴹ[1]) + _C(C,ε(u[2])+εᴹ[2],ε(u[2])+εᴹ[2]) + _C(C,ε(u[3])+εᴹ[3],ε(u[3])+εᴹ[3]) + - 2(_C(C,ε(u[1])+εᴹ[1],ε(u[2])+εᴹ[2]) + _C(C,ε(u[1])+εᴹ[1],ε(u[3])+εᴹ[3]) + _C(C,ε(u[2])+εᴹ[2],ε(u[3])+εᴹ[3])))/9 - - J = (u,φ,dΩ) -> ∫(-(I ∘ φ)*_K(C,u,εᴹ))dΩ - dJ = (q,u,φ,dΩ) -> ∫(-_v_K(C,u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; - Vol = (u,φ,dΩ) -> ∫(((ρ ∘ φ) - 0.5)/vol_D)dΩ; - dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(3,Float64),model,V_φ,el_size./order,max_steps,tol) - reinit!(stencil,φ,γ_reinit) - - ## Setup solver and FE operators - Tm=SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv=Vector{PetscScalar} - P = BlockDiagonalPreconditioner(map(Vi -> ElasticitySolver(Vi),V)) - solver = GridapSolvers.LinearSolvers.CGSolver(P;rtol=1.e-8,verbose=i_am_main(ranks)) - - assem_U,assem_adjoint = if diag_assem - DiagonalBlockMatrixAssembler(SparseMatrixAssembler(Tm,Tv,U,V)), - DiagonalBlockMatrixAssembler(SparseMatrixAssembler(Tm,Tv,V,U)) - else - SparseMatrixAssembler(Tm,Tv,U,V), - SparseMatrixAssembler(Tm,Tv,V,U) - end - - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ; - assem_U = assem_U, - assem_adjoint = assem_adjoint, - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls=solver, - adjoint_ls=solver) - - tic!(t) - state_map(φ) - toc!(t,"Assembly and solve") - - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) - - J_init,C_init,dJ,dC = Gridap.evaluate!(pcfs,φ) - u_vec = pcfs.state_map.fwd_caches[4] - - return [J_init,C_init,dJ,dC],u_vec,t - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg, - assem=SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls=PETScLinearSolver()) - - ## Optimiser - make_dir(path;ranks=ranks) - optimiser = AugmentedLagrangian(φ,pcfs,ls_evo,vel_ext,interp,el_size,γ,γ_reinit); - for history in optimiser - it,Ji,Ci,Li = last(history) - λi = optimiser.λ; Λi = optimiser.Λ - print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi];ranks=ranks) - write_history(history,path*"/history.csv";ranks=ranks) - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] - iszero(it % 10) && writevtk(Ω,path*"out$it",cellfields=data) - end - it,Ji,Ci,Li = last(optimiser.history) - λi = optimiser.λ; Λi = optimiser.Λ - print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi];ranks=ranks) - write_history(optimiser.history,path*"/history.csv";ranks=ranks) - writevtk(Ω,path*"/out$it",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) -end - -# RUN: mpiexecjl --project=. -n 8 julia ./scripts/inv_hom_block_assem_testing_3D_MPI.jl -with_mpi() do distribute - mesh_partition = (2,2,2) - el_size = (20,20,20) - hilb_solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12 -mat_block_size 3 - -mg_levels_ksp_type chebyshev -mg_levels_esteig_ksp_type cg -mg_coarse_sub_pc_type cholesky" - - GridapPETSc.with(args=split(hilb_solver_options)) do - main(mesh_partition,distribute,el_size,false) - main(mesh_partition,distribute,el_size,true) - - _OBJ_VALS,_U,T = main(mesh_partition,distribute,el_size,false) - _OBJ_VALS_diag,_U_diag,T_diag = main(mesh_partition,distribute,el_size,true) - - @show _OBJ_VALS[1] - _OBJ_VALS_diag[1] - @show _OBJ_VALS[2] - _OBJ_VALS_diag[2] - @show maximum(abs,_OBJ_VALS[3] - _OBJ_VALS_diag[3]) - @show maximum(maximum.(abs,_U.blocks - _U_diag.blocks)) - - display(T) - display(T_diag) - end -end; \ No newline at end of file diff --git a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl b/scripts/_dev/inv_hom_block_assem_testing_full_script.jl deleted file mode 100644 index 46d9baf3..00000000 --- a/scripts/_dev/inv_hom_block_assem_testing_full_script.jl +++ /dev/null @@ -1,151 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt -using GridapSolvers: LinearSolvers -using Gridap.MultiField: BlockMultiFieldStyle - -""" - (Serial) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 2D. - - Optimisation problem: - Min J(Ω) = -κ(Ω) - Ω - s.t., Vol(Ω) = Vf, - ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, - ⎣∫ ∑ᵢ C ⊙ ε(uᵢ) ⊙ ε(vᵢ) dΩ = ∫ -∑ᵢ C ⊙ ε⁰ᵢ ⊙ ε(vᵢ) dΩ, ∀v∈V. -""" -function main(diag_block) - ## Parameters - order = 2; - xmax,ymax=(1.0,1.0) - dom = (0,xmax,0,ymax); - el_size = (200,200); - γ = 0.05; - γ_reinit = 0.5; - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(order^2*10)/minimum(el_size) - C = isotropic_elast_tensor(2,1.,0.3); - η_coeff = 2; - α_coeff = 4; - path = dirname(dirname(@__DIR__))*"/results/main_inverse_homogenisation_ALM" - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size,isperiodic=(true,true)); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = iszero(x) - update_labels!(1,model,f_Γ_D,"origin") - - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2order) - vol_D = sum(∫(1)dΩ) - - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - _V = TestFESpace(model,reffe;dirichlet_tags=["origin"]) - _U = TrialFESpace(_V,VectorValue(0.0,0.0)) - mfs = BlockMultiFieldStyle() - U = MultiFieldFESpace([_U,_U,_U];style=mfs); - V = MultiFieldFESpace([_V,_V,_V];style=mfs); - V_reg = V_φ = TestFESpace(model,reffe_scalar) - U_reg = TrialFESpace(V_reg) - - ## Create FE functions - lsf_fn = x->max(initial_lsf(2,0.4)(x),initial_lsf(2,0.4;b=VectorValue(0,0.5))(x)); - φh = interpolate(lsf_fn,V_φ); - φ = get_free_dof_values(φh) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - εᴹ = (TensorValue(1.,0.,0.,0.), # ϵᵢⱼ⁽¹¹⁾≡ϵᵢⱼ⁽¹⁾ - TensorValue(0.,0.,0.,1.), # ϵᵢⱼ⁽²²⁾≡ϵᵢⱼ⁽²⁾ - TensorValue(0.,1/2,1/2,0.)) # ϵᵢⱼ⁽¹²⁾≡ϵᵢⱼ⁽³⁾ - - a(u,v,φ,dΩ) = ∫((I ∘ φ)*sum(C ⊙ ε(u[i]) ⊙ ε(v[i]) for i = 1:length(u)))dΩ - l(v,φ,dΩ) = ∫(-(I ∘ φ)*sum(C ⊙ εᴹ[i] ⊙ ε(v[i]) for i = 1:length(v)))dΩ; - res(u,v,φ,dΩ) = a(u,v,φ,dΩ) - l(v,φ,dΩ) - - ## Optimisation functionals - _C(C,ε_p,ε_q) = C ⊙ ε_p ⊙ ε_q; - _K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],εᴹ[2]))/4 - _v_K(C,(u1,u2,u3),εᴹ) = (_C(C,ε(u1)+εᴹ[1],ε(u1)+εᴹ[1]) + _C(C,ε(u2)+εᴹ[2],ε(u2)+εᴹ[2]) + 2*_C(C,ε(u1)+εᴹ[1],ε(u2)+εᴹ[2]))/4 - - J = (u,φ,dΩ) -> ∫(-(I ∘ φ)*_K(C,u,εᴹ))dΩ - dJ = (q,u,φ,dΩ) -> ∫(-_v_K(C,u,εᴹ)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ; - Vol = (u,φ,dΩ) -> ∫(((ρ ∘ φ) - 0.5)/vol_D)dΩ; - dVol = (q,u,φ,dΩ) -> ∫(1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - - ## Finite difference solver and level set function - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) - reinit!(stencil,φ,γ_reinit) - - ## Setup solver and FE operators - P = LinearSolvers.JacobiLinearSolver() - pcg = LinearSolvers.CGSolver(P;rtol=10e-12,verbose=true) - - assem = if diag_block - DiagonalBlockMatrixAssembler(SparseMatrixAssembler(U,V)) - else - SparseMatrixAssembler(U,V) - end - - state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ; - ls = pcg, - adjoint_ls = pcg, - assem_U=assem, - assem_adjoint=assem) - pcfs = PDEConstrainedFunctionals(J,[Vol],state_map;analytic_dJ=dJ,analytic_dC=[dVol]) - - J_init,C_init,dJ,dC = Gridap.evaluate!(pcfs,φ) - u_vec = pcfs.state_map.fwd_caches[4] - - return pcfs,[J_init,C_init,dJ,dC],u_vec - - ## Hilbertian extension-regularisation problems - α = α_coeff*maximum(el_Δ) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; - vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - - ## Optimiser - make_dir(path) - optimiser = AugmentedLagrangian(φ,pcfs,ls_evo,vel_ext,interp,el_size,γ,γ_reinit); - for history in optimiser - it,Ji,Ci,Li = last(history) - λi = optimiser.λ; Λi = optimiser.Λ - print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi]) - write_history(history,path*"/history.csv") - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh))] - iszero(it % 10) && writevtk(Ω,path*"out$it",cellfields=data) - end - it,Ji,Ci,Li = last(optimiser.history) - λi = optimiser.λ; Λi = optimiser.Λ - print_history(it,["J"=>Ji,"C"=>Ci,"L"=>Li,"λ"=>λi,"Λ"=>Λi]) - write_history(optimiser.history,path*"/history.csv") - writevtk(Ω,path*"/out$it",cellfields=["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) -end - -using LinearAlgebra -using BlockArrays -function LinearAlgebra.diag(A::BlockArray) - @assert ndims(A) == 2 "diag only supports matrices currently" - _blk_axes = blockaxes(A); - blkrng = (_blk_axes[1]<_blk_axes[2]) ? _blk_axes[1] : _blk_axes[2] - - mortar(map(I->diag(A[I,I]),blkrng)) -end -function Gridap.Algebra.numerical_setup!(ns::LinearSolvers.JacobiNumericalSetup, A::AbstractMatrix) - ns.inv_diag .= 1.0 ./ diag(A) -end - -# The above is a crappy solver for this problem, use AMG instead (see MPI version) - -_PSFs,_OBJ_VALS,_U = main(false); -_PSFs_diag,_OBJ_VALS_diag,_U_diag = main(true); - - - -_without = Base.summarysize(_PSFs.state_map.fwd_caches[2]) -_with = Base.summarysize(_PSFs_diag.state_map.fwd_caches[2]) - -_with/_without \ No newline at end of file diff --git a/scripts/_dev/mem_leak.jl b/scripts/_dev/mem_leak.jl deleted file mode 100644 index 278ec667..00000000 --- a/scripts/_dev/mem_leak.jl +++ /dev/null @@ -1,114 +0,0 @@ -using Gridap, LevelSetTopOpt - -# FE parameters -order = 1 # Finite element order -xmax=ymax=zmax=1.0 # Domain size -dom = (0,xmax,0,ymax,0,zmax) # Bounding domain -el_size = (10,10,10) # Mesh partition size -prop_Γ_N = 0.4 # Γ_N size parameter -prop_Γ_D = 0.2 # Γ_D size parameter -f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/4 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/4 + eps()) && - (zmax/2-zmax*prop_Γ_N/4 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/4 + eps()) -f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) -# FD parameters -γ = 0.1 # HJ equation time step coefficient -γ_reinit = 0.5 # Reinit. equation time step coefficient -max_steps = floor(Int,minimum(el_size)/3) # Max steps for advection -tol = 1/(2*order^2)*prod(inv,minimum(el_size)) # Advection tolerance -# Problem parameters -κ = 1 # Diffusivity -g = 1 # Heat flow in -vf = 0.4 # Volume fraction constraint -lsf_func = initial_lsf(4,0.2) # Initial level set function -iter_mod = 10 # Output VTK files every 10th iteration - -# Model -model = CartesianDiscreteModel(dom,el_size); -update_labels!(1,model,f_Γ_D,"Gamma_D") -update_labels!(2,model,f_Γ_N,"Gamma_N") -# Triangulation and measures -Ω = Triangulation(model) -Γ_N = BoundaryTriangulation(model,tags="Gamma_N") -dΩ = Measure(Ω,2*order) -dΓ_N = Measure(Γ_N,2*order) -# Spaces -reffe = ReferenceFE(lagrangian,Float64,order) -V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) -U = TrialFESpace(V,0.0) -V_φ = TestFESpace(model,reffe) -V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) -U_reg = TrialFESpace(V_reg,0) -# Level set and interpolator -φh = interpolate(lsf_func,V_φ) -interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) -I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ -# Weak formulation -a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ -l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N -state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) -# Objective and constraints -J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ -dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -vol_D = sum(∫(1)dΩ) -C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ -dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -pcfs = PDEConstrainedFunctionals(J,[C],state_map,analytic_dJ=dJ,analytic_dC=[dC]) -# Velocity extension -α = 4*maximum(get_el_Δ(model)) -a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ -vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) -# Finite difference scheme -scheme = FirstOrderStencil(length(el_size),Float64) -ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) -# Optimiser -optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) -# Solve -for i = 1:10 - LevelSetTopOpt.rrule(state_map,φh) -end - -evaluate!(pcfs,φh); -uh = get_state(state_map) - -GC.gc() -Sys.free_memory() / 2^20 - -for i = 1:10 - begin - u = LevelSetTopOpt.forward_solve!(state_map,φh); - uh = FEFunction(LevelSetTopOpt.get_trial_space(state_map),u); - # LevelSetTopOpt.update_adjoint_caches!(state_map,uh,φh); - end; -end; - -Sys.free_memory() / 2^20 - -GC.gc() -Sys.free_memory() / 2^20 - -for i = 1:10 - begin - # u = LevelSetTopOpt.forward_solve!(state_map,φh); - # uh = FEFunction(LevelSetTopOpt.get_trial_space(state_map),u); - - LevelSetTopOpt.update_adjoint_caches!(state_map,uh,φh); - end; -end; - -Sys.free_memory() / 2^20 - -GC.gc() -Sys.free_memory() / 2^20 - -for i = 1:10 - begin - u = LevelSetTopOpt.forward_solve!(state_map,φh); - uh = FEFunction(LevelSetTopOpt.get_trial_space(state_map),u); - LevelSetTopOpt.update_adjoint_caches!(state_map,uh,φh); - end; -end; - -Sys.free_memory() / 2^20 diff --git a/scripts/_dev/nonlinear_adjoint_MWE.jl b/scripts/_dev/nonlinear_adjoint_MWE.jl deleted file mode 100644 index df5fe18a..00000000 --- a/scripts/_dev/nonlinear_adjoint_MWE.jl +++ /dev/null @@ -1,83 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt - -""" - (Serial) Minimum thermal compliance with Lagrangian method in 2D with nonlinear diffusivity. - - Optimisation problem: - Min J(Ω) = ∫ D(u)*∇(u)⋅∇(u) + ξ dΩ - Ω - s.t., ⎡u∈V=H¹(Ω;u(Γ_D)=0), - ⎣∫ D(u)*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. - - In this example D(u) = D0*(exp(ξ*u)) -""" -function main() - ## Parameters - order = 1; - xmax=ymax=1.0 - prop_Γ_N = 0.2; - prop_Γ_D = 0.2 - dom = (0,xmax,0,ymax); - el_size = (200,200); - γ = 0.1; - γ_reinit = 0.5; - max_steps = floor(Int,minimum(el_size)/10) - tol = 1/(order^2*10)/minimum(el_size) # <- We can do better than this I think - η_coeff = 2; - α_coeff = 4; - path = dirname(dirname(@__DIR__))*"/results/main_nonlinear" - - ## FE Setup - model = CartesianDiscreteModel(dom,el_size); - el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || - x[2] >= ymax-ymax*prop_Γ_D - eps())) ? true : false; - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= - ymax/2+ymax*prop_Γ_N/2 + eps()) ? true : false; - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - - ## Triangulations and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2order) - dΓ_N = Measure(Γ_N,2order) - - ## Spaces - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe_scalar) - V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - - ## Create FE functions - φh = interpolate(initial_lsf(4,0.2),V_φ); - φ = get_free_dof_values(φh) - - ## Interpolation and weak form - interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ)) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - - D0 = 1; - ξ = -1; - D(u) = D0*(exp(ξ*u)); - - res(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(D ∘ u)*∇(u)⋅∇(v))dΩ - ∫(v)dΓ_N - - ## Optimisation functionals - ξ = 0.2; - J = (u,φ,dΩ,dΓ_N) -> ∫((I ∘ φ)*(D ∘ u)*∇(u)⋅∇(u) + ξ*(ρ ∘ φ))dΩ - - ## Finite difference solver and level set function - ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,el_size./order,max_steps,tol) - reinit!(stencil,φ,γ_reinit) - - ## Setup solver and FE operators - state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) - pcfs = PDEConstrainedFunctionals(J,state_map) - - J,C,dJ,dC = Gridap.evaluate!(pcfs,φ) -end - -main(); diff --git a/scripts/_dev/nonlinear_adjoint_testing.jl b/scripts/_dev/nonlinear_adjoint_testing.jl deleted file mode 100644 index 52c96044..00000000 --- a/scripts/_dev/nonlinear_adjoint_testing.jl +++ /dev/null @@ -1,41 +0,0 @@ - -using LinearAlgebra -using Gridap, Gridap.FESpaces, Gridap.CellData - -function transpose_contributions(b::DomainContribution) - c = DomainContribution() - for (trian,array_old) in b.dict - array_new = lazy_map(transpose,array_old) - add_contribution!(c,trian,array_new) - end - return c -end - -function assemble_adjoint_matrix!(f::Function,A::AbstractMatrix,a::Assembler,U::FESpace,V::FESpace) - v = get_fe_basis(V) - u = get_trial_fe_basis(U) - contr = transpose_contributions(f(u,v)) - assemble_matrix!(A,a,collect_cell_matrix(V,U,contr)) -end - -model = CartesianDiscreteModel((0,1,0,1),(4,4)) - -reffe = ReferenceFE(lagrangian,Float64,1) -V = FESpace(model,reffe) -U = TrialFESpace(V) - -Ω = Triangulation(model) -dΩ = Measure(Ω,4) - -e = VectorValue(1.0,-1.0) -a(u,v) = ∫((∇(u)⋅e)⋅v)*dΩ - -A = assemble_matrix(a,U,V) -At = assemble_matrix((u,v) -> a(v,u), V, U) - -A ≈ transpose(At) # true - -assem = SparseMatrixAssembler(V,U) -Ad = copy(At); LinearAlgebra.fillstored!(Ad,0.0) -Ad = assemble_adjoint_matrix!(a,Ad,assem,U,V) -Ad ≈ transpose(A) # true diff --git a/scripts/_dev/operations/ops_testing.jl b/scripts/_dev/operations/ops_testing.jl deleted file mode 100644 index fe4a38b3..00000000 --- a/scripts/_dev/operations/ops_testing.jl +++ /dev/null @@ -1,85 +0,0 @@ -using LevelSetTopOpt -using Gridap -using Gridap.CellData: DomainContribution -using Gridap.FESpaces: _gradient -using GridapDistributed: DistributedDomainContribution -import Base.*, Base./ - -ContributionTypes = Union{DomainContribution,DistributedDomainContribution} - -struct DomainContributionOperation{A} - a - b - op :: A -end - -(F::DomainContributionOperation)(args...) = F.op(sum(F.a),sum(F.b)) - -function (*)(a::ContributionTypes,b::ContributionTypes) - DomainContributionOperation(a,b,*) -end - -function (*)(a::ContributionTypes,b::DomainContributionOperation) - DomainContributionOperation(a,b,*) -end - -(*)(a::DomainContributionOperation,b::ContributionTypes) = b*a - -Gridap.gradient(F::DomainContributionOperation{typeof(*)},xh) = gradient(F.a,xh)*sum(F.b(xh)) + gradient(F.b,xh)*sum(F.a(xh)) - -# function Gridap.FESpaces._gradient(f,xh,fuh::DomainContributionOperation) -# @show typeof(fuh.a) -# _gradient(f,xh,fuh.a)#*sum(fuh.b(xh)) + _gradient(f,xh,fuh.b)*sum(fuh.a(xh)) -# end - -## TESTING -model = CartesianDiscreteModel((0,1,0,1),(10,10)); -Ω = Triangulation(model) -dΩ = Measure(Ω,2) -V = TestFESpace(model,ReferenceFE(lagrangian,Float64,1)) -uh = interpolate(x->x[1]^2*x[2]^2,V); -F(u) = ∫(u)dΩ; -G(u) = ∫(u*u)dΩ; -# H(u) = ∫(cos ∘ u)dΩ; - -struct FunctionOperation - a - b - op -end - -function (*)(a::Function,b::Function) - FunctionOperation(a,b,*) -end - -function (*)(a::Function,b::FunctionOperation) - IntegrandWithMeasureOperation(a,b,*) -end - -(*)(a::FunctionOperation,b::Function) = b*a - -(F*G) - -# d/du F*F -dF = gradient(F,uh); -dFxF = 2dF*sum(F(uh)); -dFxF_new = gradient(FG,uh); -@assert get_array(dFxF_new) == get_array(dFxF) - -# # d/du F*G -# dF_iwf = gradient(F_iwf,uh); -# dG_iwf = gradient(G_iwf,uh); -# dFxG = dF_iwf*sum(G_iwf(uh)) + dG_iwf*sum(F_iwf(uh)); -# dFxG_new = gradient(F_iwf*G_iwf,uh); -# @assert get_array(dFxG) == get_array(dFxG_new) -# # d/du (F*G)*H -# dF_iwf = gradient(F_iwf,uh); -# dG_iwf = gradient(G_iwf,uh); -# dH_iwf = gradient(H_iwf,uh); -# # dFxGxH = dF_iwf*sum(G_iwf(uh)) + dG_iwf*sum(F_iwf(uh)); -# dFxGxH_new = gradient(F_iwf*G_iwf*H_iwf,uh); - -# sum(F_iwf(uh))*sum(G_iwf(uh)) -# (F_iwf*G_iwf)(uh) - -# # get_array(dFxG) == get_array(dFxG_new) \ No newline at end of file diff --git a/scripts/_dev/operations/ops_testing_fn_version.jl b/scripts/_dev/operations/ops_testing_fn_version.jl deleted file mode 100644 index d710c66b..00000000 --- a/scripts/_dev/operations/ops_testing_fn_version.jl +++ /dev/null @@ -1,96 +0,0 @@ -using LevelSetTopOpt -using Gridap -using Gridap.CellData: DomainContribution -using Gridap.FESpaces: _gradient -using GridapDistributed: DistributedDomainContribution -import Base.*, Base./ - -struct FunctionOperation{A} <: Function - a - b - op :: A -end - -(F::FunctionOperation)(args...) = F.op(sum(F.a(args...)),sum(F.b(args...))) - -function (*)(a::Function,b::Function) - FunctionOperation(a,b,*) -end - -function (*)(a::Function,b::FunctionOperation) - FunctionOperation(a,b,*) -end - -(*)(a::FunctionOperation,b::Function) = b*a - -Gridap.gradient(F::FunctionOperation{typeof(*)},xh) = gradient(F.a,xh)*sum(F.b(xh)) + gradient(F.b,xh)*sum(F.a(xh)) - -## Testing with ChainRules.jl -D = 1 -model = CartesianDiscreteModel((0,1,0,1),(10,10)); -Ω = Triangulation(model) -Γ_N = BoundaryTriangulation(model,tags=[6,]) -dΩ = Measure(Ω,2) -dΓ_N = Measure(Γ_N,2) -reffe_scalar = ReferenceFE(lagrangian,Float64,1) -V = TestFESpace(model,reffe_scalar;dirichlet_tags=[1]) -U = TrialFESpace(V,0.0) -V_φ = TestFESpace(model,reffe_scalar) -V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=[6,]) -U_reg = TrialFESpace(V_reg,0) - -## Create FE functions -φh = interpolate(x->-1,V_φ) -interp = SmoothErsatzMaterialInterpolation(η = 2maximum(get_el_size(model))); -I,_H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - -a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(v))dΩ -l(v,φ,dΩ,dΓ_N) = ∫(v)dΓ_N - -## Optimisation functionals -J1(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*D*∇(u)⋅∇(u))dΩ -J2(u,φ,dΩ,dΓ_N) = ∫(ρ ∘ φ)dΩ - -J = J1*J2 - -J_iwm = LevelSetTopOpt.IntegrandWithMeasure(J,(dΩ,dΓ_N)); -uh = interpolate(x->x[1]^2*x[2]^2,V); -gradient(J_iwm,[uh,φh],1) - -function Gridap.gradient(F::LevelSetTopOpt.IntegrandWithMeasure{<:FunctionOperation},uh::Vector{<:FEFunction},K::Int) - _f(uk) = F.F(uh[1:K-1]...,uk,uh[K+1:end]...,F.dΩ...) - return gradient(_f,uh[K]) -end - -# state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) -# pcfs = PDEConstrainedFunctionals(J,state_map) - -## TESTING -model = CartesianDiscreteModel((0,1,0,1),(10,10)); -Ω = Triangulation(model) -dΩ = Measure(Ω,2) -V = TestFESpace(model,ReferenceFE(lagrangian,Float64,1)) -uh = interpolate(x->x[1]^2*x[2]^2,V); -F(u) = ∫(u)dΩ; -G(u) = ∫(u*u)dΩ; -H(u) = ∫(cos ∘ u)dΩ; - -# d/du F*F -dF = gradient(F,uh); -dFxF = 2dF*sum(F(uh)); -dFxF_new = gradient(F*F,uh); -@assert get_array(dFxF_new) == get_array(dFxF) - -# d/du F*G -dF = gradient(F,uh); -dG = gradient(G,uh); -dFxG = dF*sum(G(uh)) + dG*sum(F(uh)); -dFxG_new = gradient(F*G,uh); -@assert get_array(dFxG) == get_array(dFxG_new) -# d/du F*G*H -dF = gradient(F,uh); -dG = gradient(G,uh); -dH = gradient(H,uh); -dFxGxH = dF*sum(G(uh))*sum(H(uh)) + dG*sum(F(uh))*sum(H(uh)) + dH*sum(F(uh))*sum(G(uh)); -dFxGxH_new = gradient(F*G*H,uh); -get_array(dFxG) == get_array(dFxG_new) \ No newline at end of file diff --git a/scripts/_dev/operations/ops_testing_iwm.jl b/scripts/_dev/operations/ops_testing_iwm.jl deleted file mode 100644 index 1f50bd63..00000000 --- a/scripts/_dev/operations/ops_testing_iwm.jl +++ /dev/null @@ -1,72 +0,0 @@ -using LevelSetTopOpt -using Gridap -using LevelSetTopOpt: IntegrandWithMeasure -import Base.*, Base./ - -struct IntegrandWithMeasureOperation{A<:Function} - a - b - op :: A -end - -(F::IntegrandWithMeasureOperation)(args...) = F.op(sum(F.a(args...)),sum(F.b(args...))) - -function (*)(a::IntegrandWithMeasure,b::IntegrandWithMeasure) - IntegrandWithMeasureOperation(a,b,*) -end - -function (*)(a::IntegrandWithMeasure,b::IntegrandWithMeasureOperation) - IntegrandWithMeasureOperation(a,b,*) -end - -(*)(a::IntegrandWithMeasureOperation,b::IntegrandWithMeasure) = b*a - -Gridap.gradient(F::IntegrandWithMeasureOperation{typeof(*)},xh) = gradient(F.a,xh)*sum(F.b(xh)) + gradient(F.b,xh)*sum(F.a(xh)) - -# function (/)(a::Number,b::DomainContribution) -# DomainContributionOperation(a,b,/) -# end - -# function (/)(a::DomainContribution,b::DomainContribution) -# DomainContributionOperation(a,b,/) -# end - -# function (/)(a::DomainContribution,b::DomainContributionOperation) -# DomainContributionOperation(a,b,/) -# end - -# function (/)(a::DomainContributionOperation,b::DomainContribution) -# DomainContributionOperation(a,b,/) -# end - -## TESTING -model = CartesianDiscreteModel((0,1,0,1),(10,10)); -Ω = Triangulation(model) -dΩ = Measure(Ω,2) -V = TestFESpace(model,ReferenceFE(lagrangian,Float64,1)) -uh = interpolate(x->x[1]^2*x[2]^2,V); -F_iwf = IntegrandWithMeasure((u,dΩ)->∫(u)dΩ,(dΩ,)); -G_iwf = IntegrandWithMeasure((u,dΩ)->∫(u*u)dΩ,(dΩ,)); -H_iwf = IntegrandWithMeasure((u,dΩ)->∫(cos ∘ u)dΩ,(dΩ,)); -# d/du F*F -dF_iwf = gradient(F_iwf,uh); -dFxF = 2dF_iwf*sum(F_iwf(uh)); -dFxF_new = gradient(F_iwf*F_iwf,uh); -@assert get_array(dFxF_new) == get_array(dFxF) -# d/du F*G -dF_iwf = gradient(F_iwf,uh); -dG_iwf = gradient(G_iwf,uh); -dFxG = dF_iwf*sum(G_iwf(uh)) + dG_iwf*sum(F_iwf(uh)); -dFxG_new = gradient(F_iwf*G_iwf,uh); -@assert get_array(dFxG) == get_array(dFxG_new) -# d/du (F*G)*H -dF_iwf = gradient(F_iwf,uh); -dG_iwf = gradient(G_iwf,uh); -dH_iwf = gradient(H_iwf,uh); -# dFxGxH = dF_iwf*sum(G_iwf(uh)) + dG_iwf*sum(F_iwf(uh)); -dFxGxH_new = gradient(F_iwf*G_iwf*H_iwf,uh); - -sum(F_iwf(uh))*sum(G_iwf(uh)) -(F_iwf*G_iwf)(uh) - -# get_array(dFxG) == get_array(dFxG_new) \ No newline at end of file diff --git a/scripts/_dev/piezo_repeating.jl b/scripts/_dev/piezo_repeating.jl deleted file mode 100644 index 4c069651..00000000 --- a/scripts/_dev/piezo_repeating.jl +++ /dev/null @@ -1,354 +0,0 @@ -using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR -using Gridap.TensorValues, Gridap.Helpers, Gridap.MultiField -using GridapSolvers.BlockSolvers - -function PZT5A(D::Int) - ε_0 = 8.854e-12; - if D == 3 - C_Voigt = [12.0400e10 7.52000e10 7.51000e10 0.0 0.0 0.0 - 7.52000e10 12.0400e10 7.51000e10 0.0 0.0 0.0 - 7.51000e10 7.51000e10 11.0900e10 0.0 0.0 0.0 - 0.0 0.0 0.0 2.1000e10 0.0 0.0 - 0.0 0.0 0.0 0.0 2.1000e10 0.0 - 0.0 0.0 0.0 0.0 0.0 2.30e10] - e_Voigt = [0.0 0.0 0.0 0.0 12.30000 0.0 - 0.0 0.0 0.0 12.30000 0.0 0.0 - -5.40000 -5.40000 15.80000 0.0 0.0 0.0] - K_Voigt = [540*ε_0 0 0 - 0 540*ε_0 0 - 0 0 830*ε_0] - elseif D == 2 - C_Voigt = [12.0400e10 7.51000e10 0.0 - 7.51000e10 11.0900e10 0.0 - 0.0 0.0 2.1000e10] - e_Voigt = [0.0 0.0 12.30000 - -5.40000 15.80000 0.0] - K_Voigt = [540*ε_0 0 - 0 830*ε_0] - else - @notimplemented - end - C = voigt2tensor4(C_Voigt) - e = voigt2tensor3(e_Voigt) - κ = voigt2tensor2(K_Voigt) - C,e,κ -end - -""" - Given a material constant given in Voigt notation, - return a SymFourthOrderTensorValue using ordering from Gridap -""" -function voigt2tensor4(A::Array{M,2}) where M - if isequal(size(A),(3,3)) - return SymFourthOrderTensorValue(A[1,1], A[3,1], A[2,1], - A[1,3], A[3,3], A[2,3], - A[1,2], A[3,2], A[2,2]) - elseif isequal(size(A),(6,6)) - return SymFourthOrderTensorValue(A[1,1], A[6,1], A[5,1], A[2,1], A[4,1], A[3,1], - A[1,6], A[6,6], A[5,6], A[2,6], A[4,6], A[3,6], - A[1,5], A[6,5], A[5,5], A[2,5], A[4,5], A[3,5], - A[1,2], A[6,2], A[5,2], A[2,2], A[4,2], A[3,2], - A[1,4], A[6,4], A[5,4], A[2,4], A[4,4], A[3,4], - A[1,3], A[6,3], A[5,3], A[2,3], A[4,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a ThirdOrderTensorValue using ordering from Gridap -""" -function voigt2tensor3(A::Array{M,2}) where M - if isequal(size(A),(2,3)) - return ThirdOrderTensorValue(A[1,1], A[2,1], A[1,3], A[2,3], A[1,3], A[2,3], A[1,2], A[2,2]) - elseif isequal(size(A),(3,6)) - return ThirdOrderTensorValue( - A[1,1], A[2,1], A[3,1], A[1,6], A[2,6], A[3,6], A[1,5], A[2,5], A[3,5], - A[1,6], A[2,6], A[3,6], A[1,2], A[2,2], A[3,2], A[1,4], A[2,4], A[3,4], - A[1,5], A[2,5], A[3,5], A[1,4], A[2,4], A[3,4], A[1,3], A[2,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a SymTensorValue using ordering from Gridap -""" -function voigt2tensor2(A::Array{M,2}) where M - return TensorValue(A) -end - -## Parameters -#function main(mesh_partition,distribute) - #ranks = distribute(LinearIndices((prod(mesh_partition),))) - -mesh_partition = (1,1) -ranks = with_mpi() do distribute - distribute(LinearIndices((prod(mesh_partition),))) -end - -el_size = (100,100) -order = 1 -xmax,ymax=(1.0,1.0) -dom = (0,xmax,0,ymax) -γ = 0.1 -γ_reinit = 0.5 -max_steps = floor(Int,order*minimum(el_size)/10) -tol = 1/(5order^2)/minimum(el_size) -η_coeff = 2 -α_coeff = 4*max_steps*γ -vf = 0.5 -path = dirname(@__DIR__)*"/results/2d_PZ_inverse_homenisation_MPI_Nx$(mesh_partition[1])Ny$(mesh_partition[2])/" -#i_am_main(ranks) && mkpath(path) - -## FE Setup -model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true)) -el_Δ = get_el_Δ(model) -f_Γ_D(x) = iszero(x) -update_labels!(1,model,f_Γ_D,"origin") - -## Triangulations and measures -Ω = Triangulation(model) -dΩ = Measure(Ω,2*order) -vol_D = sum(∫(1)dΩ) - -## Spaces -reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) -reffe_scalar = ReferenceFE(lagrangian,Float64,order) -V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) -U = TrialFESpace(V,VectorValue(0.0,0.0)) -Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) -P = TrialFESpace(Q,0) -mfs = BlockMultiFieldStyle() -UP = MultiFieldFESpace([U,P];style=mfs) -VQ = MultiFieldFESpace([V,Q];style=mfs) - -V_φ = TestFESpace(model,reffe_scalar) -V_reg = TestFESpace(model,reffe_scalar) -U_reg = TrialFESpace(V_reg) - -## Create FE functions -lsf_fn = initial_lsf(2,0.2) -φh = interpolate(lsf_fn,V_φ) - -## Interpolation and weak form -interp = SmoothErsatzMaterialInterpolation(η = η_coeff*maximum(el_Δ),ϵ=10^-9) -I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - -## Material tensors -C, e, κ = PZT5A(2); -k0 = norm(C.data,Inf); -α0 = norm(e.data,Inf); -β0 = norm(κ.data,Inf); -γ0 = β0*k0/α0^2; - -## Weak forms -εᴹ = (SymTensorValue(1.0,0.0,0.0), - SymTensorValue(0.0,0.0,1.0), - SymTensorValue(0.0,1/2,0)) -Eⁱ = (VectorValue(1.0,0.0,), - VectorValue(0.0,1.0)) - -a((u,ϕ),(v,q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - - 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + - -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + - -γ0/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q))) )dΩ; - -l_ε = [((v,q),φ,dΩ) -> ∫(((I ∘ φ) * (-C ⊙ εᴹ[i] ⊙ ε(v) + k0/α0*(e ⋅² εᴹ[i]) ⋅ -∇(q))))dΩ for i = 1:3]; -l_E = [((v,q),φ,dΩ) -> ∫((I ∘ φ) * ((Eⁱ[i] ⋅ e ⊙ ε(v) + k0/α0*(κ ⋅ Eⁱ[i]) ⋅ -∇(q))))dΩ for i = 1:2]; -l = [l_ε; l_E] - -## Optimisation functionals -# Note, uϕ unpacks as -> uϕ = u1,ϕ1,u2,ϕ2,u3,ϕ3,u4,ϕ4,u5,ϕ5 -# where entries 1,2,3 correspond to εᴹ[1],εᴹ[2],εᴹ[3] and -# 4,5 correspond to Eⁱ[1],Eⁱ[2]. - -function Cᴴ(r,s,uϕ,φ,dΩ) # (normalised by 1/k0) - u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] - ∫(1/k0 * (I ∘ φ) * (((C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ εᴹ[r]) - ((-1/α0*∇(ϕ_s) ⋅ e) ⊙ εᴹ[r])))dΩ; -end - -function DCᴴ(r,s,q,uϕ,φ,dΩ) # (normalised by 1/k0) - u_r = uϕ[2r-1]; ϕ_r = uϕ[2r] - u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] - ∫(- 1/k0 * q * ( - (C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - - (-1/α0*∇(ϕ_s) ⋅ e) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - - (e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ (-1/α0*∇(ϕ_r)) - - (κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ (-1/α0*∇(ϕ_r)) - ) * (DH ∘ φ) * (norm ∘ ∇(φ)) - )dΩ; -end - -function eᴴ(i,s,uϕ,φ,dΩ) # (normalised by 1/α0) - u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] - ∫(1/α0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ Eⁱ[i])))dΩ; -end - -function Deᴴ(i,s,q,uϕ,φ,dΩ) # (normalised by 1/α0) - u_i = uϕ[6+2i-1]; ϕ_i = uϕ[6+2i] - u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] - ∫(- 1/α0 * q * ( - - (C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ (1/k0*ε(u_i)) + - (-1/α0*∇(ϕ_s) ⋅ e) ⊙ (1/k0*ε(u_i)) + - (e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) + - (κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) - ) * (DH ∘ φ) * (norm ∘ ∇(φ)) - )dΩ; -end - -function κᴴ(i,j,uϕ,φ,dΩ) # (normalised by 1/β0) - u_j = uϕ[6+2j-1]; ϕ_j = uϕ[6+2j] - ∫(1/β0 * (I ∘ φ) * (((e ⋅² (1/k0*ε(u_j)) ⋅ Eⁱ[i]) + ((κ ⋅ (-1/α0*∇(ϕ_j) + Eⁱ[j])) ⋅ Eⁱ[i]))))dΩ; -end - -function Dκᴴ(i,j,q,uϕ,φ,dΩ) # (normalised by 1/β0) - u_i = uϕ[6+2i-1]; ϕ_i = uϕ[6+2i] - u_j = uϕ[6+2j-1]; ϕ_j = uϕ[6+2j] - ∫(- 1/β0 * q * ( - - (C ⊙ (1/k0*ε(u_j))) ⊙ (1/k0*ε(u_i)) + - ((-1/α0*∇(ϕ_j) + Eⁱ[j]) ⋅ e) ⊙ (1/k0*ε(u_i)) + - (e ⋅² (1/k0*ε(u_j))) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) + - (κ ⋅ (-1/α0*∇(ϕ_j) + Eⁱ[j])) ⋅ (-1/α0*∇(ϕ_i) + Eⁱ[i]) - ) * (DH ∘ φ) * (norm ∘ ∇(φ)) - )dΩ; -end - -# Equiv to -# C_mat = map(rs->sum(Cᴴ(rs[1],rs[2],xh,φh,dΩ)), CartesianIndices((1:3, 1:3))) -# e_mat = map(is->sum(eᴴ(is[1],is[2],xh,φh,dΩ)), CartesianIndices((1:2, 1:3))) -# d_mat = e_mat*inv(C_mat); -# dh = d_mat[2,1] + d_mat[2,2] -function dᴴ(uϕ,φ,dΩ) - # We leave eᴴ_21 and eᴴ_22 as DomainContribution so that result is a DomainContribution. - # Note that this means AD applied to this functional would be incorrect. - Cᴴ_11 = sum(Cᴴ(1,1,uϕ,φ,dΩ)); - Cᴴ_22 = sum(Cᴴ(2,2,uϕ,φ,dΩ)); - Cᴴ_21 = sum(Cᴴ(2,1,uϕ,φ,dΩ)); - eᴴ_21 = eᴴ(2,1,uϕ,φ,dΩ); - eᴴ_22 = eᴴ(2,2,uϕ,φ,dΩ); - (Cᴴ_22*eᴴ_21 + Cᴴ_11*eᴴ_22 - Cᴴ_21*(eᴴ_21 + eᴴ_22))*(1/(Cᴴ_11*Cᴴ_22 - Cᴴ_21^2)) -end - -function Ddᴴ(q,uϕ,φ,dΩ) - Cᴴ_11 = sum(Cᴴ(1,1,uϕ,φ,dΩ)); DCᴴ_11 = DCᴴ(1,1,q,uϕ,φ,dΩ) - Cᴴ_22 = sum(Cᴴ(2,2,uϕ,φ,dΩ)); DCᴴ_22 = DCᴴ(2,2,q,uϕ,φ,dΩ) - Cᴴ_21 = sum(Cᴴ(2,1,uϕ,φ,dΩ)); DCᴴ_21 = DCᴴ(2,1,q,uϕ,φ,dΩ) - eᴴ_21 = sum(eᴴ(2,1,uϕ,φ,dΩ)); Deᴴ_21 = DCᴴ(2,1,q,uϕ,φ,dΩ) - eᴴ_22 = sum(eᴴ(2,2,uϕ,φ,dΩ)); Deᴴ_22 = DCᴴ(2,2,q,uϕ,φ,dΩ) - (-1*Cᴴ_11^2*eᴴ_22*(DCᴴ_22)+Cᴴ_22^2*(-eᴴ_21*(DCᴴ_11)+Cᴴ_11*(Deᴴ_21))+ - Cᴴ_21^3*((Deᴴ_21)+(Deᴴ_22))+Cᴴ_11*Cᴴ_22*(-1*((eᴴ_21+eᴴ_22)*(DCᴴ_21))+ - Cᴴ_11*(Deᴴ_22))-Cᴴ_21^2*(eᴴ_22*((DCᴴ_11)+(DCᴴ_21))+eᴴ_21*((DCᴴ_21)+(DCᴴ_22))+ - Cᴴ_22*(Deᴴ_21)+Cᴴ_11*(Deᴴ_22))+Cᴴ_21*(Cᴴ_11*(2*eᴴ_22*(DCᴴ_21)+(eᴴ_21+eᴴ_22)*(DCᴴ_22))+ - Cᴴ_22*((eᴴ_21+eᴴ_22)*(DCᴴ_11)+2*eᴴ_21*(DCᴴ_21)-Cᴴ_11*((Deᴴ_21)+(Deᴴ_22)))))*(1/(Cᴴ_21^2-Cᴴ_11*Cᴴ_22)^2) -end - -Bᴴ(uϕ,φ,dΩ) = 1/4*(Cᴴ(1,1,uϕ,φ,dΩ)+Cᴴ(2,2,uϕ,φ,dΩ)+2*Cᴴ(1,2,uϕ,φ,dΩ)) -DBᴴ(q,uϕ,φ,dΩ) = 1/4*(DCᴴ(1,1,q,uϕ,φ,dΩ)+DCᴴ(2,2,q,uϕ,φ,dΩ)+2*DCᴴ(1,2,q,uϕ,φ,dΩ)) - - -J(uϕ,φ,dΩ) = -1*dᴴ(uϕ,φ,dΩ) -DJ(q,uϕ,φ,dΩ) = -1*Ddᴴ(q,uϕ,φ,dΩ) -C1(uϕ,φ,dΩ) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ; -DC1(q,uϕ,φ,dΩ) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -C2(uϕ,φ,dΩ) = Cᴴ(2,2,uϕ,φ,dΩ) - ∫(0.05/vol_D)dΩ -DC2(q,uϕ,φ,dΩ) = DCᴴ(2,2,q,uϕ,φ,dΩ) - -# ## Finite difference solver and level set function -stencil = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps) - -# ## Setup solver and FE operators -Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} -Tv = Vector{PetscScalar} -solver_u = LUSolver() #ElasticitySolver(V) #GridapSolvers.LinearSolvers.ElasticitySolver(V) -solver_ϕ = LUSolver() #PETScLinearSolver() - -# P = GridapSolvers.BlockDiagonalSolver([solver_u,solver_ϕ]) -# solver = GridapSolvers.LinearSolvers.GMRESSolver(100;Pr=P,rtol=1.e-8,verbose=i_am_main(ranks)) -solver = BlockTriangularSolver([solver_u,solver_ϕ]) - -state_map = RepeatingAffineFEStateMap(5,a,l,UP,VQ,V_φ,U_reg,φh,dΩ; - assem_U = SparseMatrixAssembler(Tm,Tv,UP,VQ), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,VQ,UP), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = solver,adjoint_ls = solver -) -pcfs = PDEConstrainedFunctionals(J,[C1,C2],state_map;analytic_dJ=DJ,analytic_dC=[DC1,DC2]) - -# ## Hilbertian extension-regularisation problems -α = α_coeff*maximum(el_Δ) -a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; -vel_ext = VelocityExtension( - a_hilb,U_reg,V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() -) - -# ## Optimiser -has_oscillations(m,os_it) = LevelSetTopOpt.default_has_oscillations(m,os_it;itlength=25) -optimiser = HilbertianProjection(pcfs,stencil,vel_ext,φh;γ,γ_reinit,has_oscillations, - verbose=i_am_main(ranks),ls_enabled=true) -for (it, uh, φh) in optimiser - u1,ϕ1,u2,ϕ2,u3,ϕ3,u4,ϕ4,u5,ϕ5 = uh - data = ["φ"=>φh,"H(φ)"=>(H ∘ φh),"|∇(φ)|"=>(norm ∘ ∇(φh)), - "u1"=>1/k0*u1,"ϕ1"=>1/α0*ϕ1,"u2"=>1/k0*u2,"ϕ2"=>1/α0*ϕ2,"u3"=>1/k0*u3,"ϕ3"=>1/α0*ϕ3, - "u4"=>1/k0*u4,"ϕ4"=>1/α0*ϕ4,"u5"=>1/k0*u5,"ϕ5"=>1/α0*ϕ5] - writevtk(Ω,path*"out$it",cellfields=data) - write_history(path*"/history.txt",optimiser.history) -end -#end - -#with_debug() do distribute -# mesh_partition = (2,2) -# solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -# -ksp_converged_reason -ksp_rtol 1.0e-12" -# GridapPETSc.with(args=split(solver_options)) do -# main(mesh_partition,distribute) -# end -#end - -# mesh_partition = (2,2) -# ranks = with_debug() do distribute -# distribute(LinearIndices((prod(mesh_partition),))) -# end - -# el_size = (200,200) -# order = 1 -# xmax,ymax=(1.0,1.0) -# dom = (0,xmax,0,ymax) -# γ = 0.1 -# γ_reinit = 0.5 -# max_steps = floor(Int,order*minimum(el_size)/10) -# tol = 1/(5order^2)/minimum(el_size) -# η_coeff = 2 -# α_coeff = 4*max_steps*γ -# vf = 0.5 - -# ## FE Setup -# model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true)) -# el_Δ = get_el_Δ(model) -# f_Γ_D(x) = iszero(x) -# update_labels!(1,model,f_Γ_D,"origin") - -# ## Triangulations and measures -# Ω = Triangulation(model) -# dΩ = Measure(Ω,2*order) -# vol_D = sum(∫(1)dΩ) - -# ## Spaces -# reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) -# reffe_scalar = ReferenceFE(lagrangian,Float64,order) -# V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) -# U = TrialFESpace(V,VectorValue(0.0,0.0)) -# Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) -# P = TrialFESpace(Q,0) -# mfs = BlockMultiFieldStyle() -# UP = MultiFieldFESpace([U,P];style=mfs) -# VQ = MultiFieldFESpace([V,Q];style=mfs) - -# Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} -# Tv = Vector{PetscScalar} -# assem = SparseMatrixAssembler(Tm,Tv,UP,VQ) diff --git a/scripts/_dev/piezo_script.jl b/scripts/_dev/piezo_script.jl deleted file mode 100644 index f4e7faae..00000000 --- a/scripts/_dev/piezo_script.jl +++ /dev/null @@ -1,154 +0,0 @@ -using Gridap, Gridap.TensorValues, Gridap.Geometry, Gridap.FESpaces, Gridap.Helpers, Gridap.Algebra -using GridapDistributed -using GridapPETSc -using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code -using PartitionedArrays -using SparseMatricesCSR -using ChainRulesCore -using LevelSetTopOpt - -using GridapSolvers -using Gridap.MultiField - -function PZT5A(D::Int) - ε_0 = 8.854e-12; - if D == 3 - C_Voigt = [12.0400e10 7.52000e10 7.51000e10 0.0 0.0 0.0 - 7.52000e10 12.0400e10 7.51000e10 0.0 0.0 0.0 - 7.51000e10 7.51000e10 11.0900e10 0.0 0.0 0.0 - 0.0 0.0 0.0 2.1000e10 0.0 0.0 - 0.0 0.0 0.0 0.0 2.1000e10 0.0 - 0.0 0.0 0.0 0.0 0.0 2.30e10] - e_Voigt = [0.0 0.0 0.0 0.0 12.30000 0.0 - 0.0 0.0 0.0 12.30000 0.0 0.0 - -5.40000 -5.40000 15.80000 0.0 0.0 0.0] - K_Voigt = [540*ε_0 0 0 - 0 540*ε_0 0 - 0 0 830*ε_0] - elseif D == 2 - C_Voigt = [12.0400e10 7.51000e10 0.0 - 7.51000e10 11.0900e10 0.0 - 0.0 0.0 2.1000e10] - e_Voigt = [0.0 0.0 12.30000 - -5.40000 15.80000 0.0] - K_Voigt = [540*ε_0 0 - 0 830*ε_0] - else - @notimplemented - end - C = voigt2tensor4(C_Voigt) - e = voigt2tensor3(e_Voigt) - κ = voigt2tensor2(K_Voigt) - C,e,κ -end - -""" - Given a material constant given in Voigt notation, - return a SymFourthOrderTensorValue using ordering from Gridap -""" -function voigt2tensor4(A::Array{M,2}) where M - if isequal(size(A),(3,3)) - return SymFourthOrderTensorValue(A[1,1], A[3,1], A[2,1], - A[1,3], A[3,3], A[2,3], - A[1,2], A[3,2], A[2,2]) - elseif isequal(size(A),(6,6)) - return SymFourthOrderTensorValue(A[1,1], A[6,1], A[5,1], A[2,1], A[4,1], A[3,1], - A[1,6], A[6,6], A[5,6], A[2,6], A[4,6], A[3,6], - A[1,5], A[6,5], A[5,5], A[2,5], A[4,5], A[3,5], - A[1,2], A[6,2], A[5,2], A[2,2], A[4,2], A[3,2], - A[1,4], A[6,4], A[5,4], A[2,4], A[4,4], A[3,4], - A[1,3], A[6,3], A[5,3], A[2,3], A[4,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a ThirdOrderTensorValue using ordering from Gridap -""" -function voigt2tensor3(A::Array{M,2}) where M - if isequal(size(A),(2,3)) - return ThirdOrderTensorValue(A[1,1], A[2,1], A[1,3], A[2,3], A[1,3], A[2,3], A[1,2], A[2,2]) - elseif isequal(size(A),(3,6)) - return ThirdOrderTensorValue( - A[1,1], A[2,1], A[3,1], A[1,6], A[2,6], A[3,6], A[1,5], A[2,5], A[3,5], - A[1,6], A[2,6], A[3,6], A[1,2], A[2,2], A[3,2], A[1,4], A[2,4], A[3,4], - A[1,5], A[2,5], A[3,5], A[1,4], A[2,4], A[3,4], A[1,3], A[2,3], A[3,3]) - else - @notimplemented - end -end - -""" - Given a material constant given in Voigt notation, - return a SymTensorValue using ordering from Gridap -""" -function voigt2tensor2(A::Array{M,2}) where M - return TensorValue(A) -end - -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - - order = 1; - el_size = (30,30,30); - dom = (0.,1.,0.,1.,0.,1.); - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size,isperiodic=(true,true,true)); - ## Define Γ_N and Γ_D - f_Γ_D(x) = iszero(x) - update_labels!(1,model,f_Γ_D,"origin") - ## Triangulations and measures - Ω = Triangulation(model) - dΩ = Measure(Ω,2order) - ## Spaces - reffe = ReferenceFE(lagrangian,VectorValue{3,Float64},order) - reffe_scalar = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags=["origin"]) - U = TrialFESpace(V,VectorValue(0.0,0.0,0.0)) - Q = TestFESpace(model,reffe_scalar;conformity=:H1,dirichlet_tags=["origin"]) - P = TrialFESpace(Q,0) - - mfs = BlockMultiFieldStyle() - UP = MultiFieldFESpace([U,P];style=mfs) - VQ = MultiFieldFESpace([V,Q];style=mfs) - - C, e, κ = PZT5A(3); - k0 = norm(C.data,Inf); - α0 = norm(e.data,Inf); - β0 = norm(κ.data,Inf); - γ = β0*k0/α0^2; - - ϵ⁰ = TensorValue(1.,0.,0.,0.,0.,0.,0.,0.,0.); - - a((u, ϕ),(v, q)) = ∫(1/k0*C ⊙ ε(u) ⊙ ε(v) - - 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + - -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + - -γ/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q)) )dΩ; - - l((v, q)) = ∫(-C ⊙ ϵ⁰ ⊙ ε(v) + k0/α0*((e ⋅² ϵ⁰) ⋅ -∇(q)))dΩ; - - assem = SparseMatrixAssembler(SparseMatrixCSR{0,PetscScalar,PetscInt},Vector{PetscScalar},UP,VQ) - op = AffineFEOperator(a,l,UP,VQ,assem) - ## Solve - #options = "-pc_type bjacobi -ksp_type gmres -ksp_error_if_not_converged true - # -ksp_converged_reason -ksp_rtol 1.0e-10 -ksp_monitor_short" - options = "-ksp_converged_reason -pc_type gamg -ksp_type cg " - GridapPETSc.with(args=split(options)) do - # ls = PETScLinearSolver() - # xh = solve(ls,op) - solver_u = ElasticitySolver(V) - solver_ϕ = PETScLinearSolver() - P = BlockDiagonalPreconditioner([solver_u,solver_ϕ]) - solver = GridapSolvers.LinearSolvers.GMRESSolver(100;Pr=P,rtol=1.e-8,verbose=i_am_main(ranks)) - A = get_matrix(op) - b = get_vector(op) - ns = numerical_setup(symbolic_setup(solver,A),A) - x = allocate_in_domain(A); fill!(x,0.0) - solve!(x,ns,b) - end -end; - -with_mpi() do distribute - main((2,2,1),distribute) -end; diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl deleted file mode 100644 index 91dbabaa..00000000 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation.jl +++ /dev/null @@ -1,76 +0,0 @@ -using Gridap, LevelSetTopOpt - -# FE parameters -order = 1 # Finite element order -xmax = ymax = 1.0 # Domain size -dom = (0,xmax,0,ymax) # Bounding domain -el_size = (200,200) # Mesh partition size -prop_Γ_N = 0.2 # Γ_N size parameter -prop_Γ_D = 0.2 # Γ_D size parameter -f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) -f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) -# FD parameters -γ = 0.1 # HJ equation time step coefficient -γ_reinit = 0.5 # Reinit. equation time step coefficient -max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection -tol = 1/(5order^2)/minimum(el_size) # Advection tolerance -# Problem parameters -κ = 1 # Diffusivity -g = 1 # Heat flow in -vf = 0.4 # Volume fraction constraint -lsf_func = initial_lsf(4,0.2) # Initial level set function -iter_mod = 10 # Output VTK files every 10th iteration -path = "./results/tut1/" # Output path -mkpath(path) # Create path -# Model -model = CartesianDiscreteModel(dom,el_size); -update_labels!(1,model,f_Γ_D,"Gamma_D") -update_labels!(2,model,f_Γ_N,"Gamma_N") -# Triangulation and measures -Ω = Triangulation(model) -Γ_N = BoundaryTriangulation(model,tags="Gamma_N") -dΩ = Measure(Ω,2*order) -dΓ_N = Measure(Γ_N,2*order) -# Spaces -reffe = ReferenceFE(lagrangian,Float64,order) -V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) -U = TrialFESpace(V,0.0) -V_φ = TestFESpace(model,reffe) -V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) -U_reg = TrialFESpace(V_reg,0) -# Level set and interpolator -φh = interpolate(lsf_func,V_φ) -interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) -I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ -# Weak formulation -a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ -l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N -state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) -# Objective and constraints -J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ -dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -vol_D = sum(∫(1)dΩ) -C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ -dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -pcfs = PDEConstrainedFunctionals(J,[C],state_map,analytic_dJ=dJ,analytic_dC=[dC]) -# Velocity extension -α = 4*maximum(get_el_Δ(model)) -a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ -vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) -# Finite difference scheme -scheme = FirstOrderStencil(length(el_size),Float64) -ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) -# Optimiser -optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) -# Solve -for (it,uh,φh) in optimiser - data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"struc_$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser)) -end -# Final structure -it = get_history(optimiser).niter; uh = get_state(pcfs) -writevtk(Ω,path*"struc_$it",cellfields=["phi"=>φh, - "H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) \ No newline at end of file diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl deleted file mode 100644 index 8218dabf..00000000 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d.jl +++ /dev/null @@ -1,78 +0,0 @@ -using Gridap, LevelSetTopOpt - -# FE parameters -order = 1 # Finite element order -xmax=ymax=zmax=1.0 # Domain size -dom = (0,xmax,0,ymax,0,zmax) # Bounding domain -el_size = (40,40,40) # Mesh partition size -prop_Γ_N = 0.2 # Γ_N size parameter -prop_Γ_D = 0.2 # Γ_D size parameter -f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) -f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) -# FD parameters -γ = 0.1 # HJ equation time step coefficient -γ_reinit = 0.5 # Reinit. equation time step coefficient -max_steps = floor(Int,minimum(el_size)/3) # Max steps for advection -tol = 1/(2order^2)/minimum(el_size) # Advection tolerance -# Problem parameters -κ = 1 # Diffusivity -g = 1 # Heat flow in -vf = 0.4 # Volume fraction constraint -lsf_func = initial_lsf(4,0.2) # Initial level set function -iter_mod = 10 # Output VTK files every 10th iteration -path = "./results/tut1_3d/" # Output path -mkpath(path) # Create path -# Model -model = CartesianDiscreteModel(dom,el_size); -update_labels!(1,model,f_Γ_D,"Gamma_D") -update_labels!(2,model,f_Γ_N,"Gamma_N") -# Triangulation and measures -Ω = Triangulation(model) -Γ_N = BoundaryTriangulation(model,tags="Gamma_N") -dΩ = Measure(Ω,2*order) -dΓ_N = Measure(Γ_N,2*order) -# Spaces -reffe = ReferenceFE(lagrangian,Float64,order) -V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) -U = TrialFESpace(V,0.0) -V_φ = TestFESpace(model,reffe) -V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) -U_reg = TrialFESpace(V_reg,0) -# Level set and interpolator -φh = interpolate(lsf_func,V_φ) -interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) -I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ -# Weak formulation -a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ -l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N -state_map = AffineFEStateMap(a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) -# Objective and constraints -J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ -dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -vol_D = sum(∫(1)dΩ) -C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ -dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -pcfs = PDEConstrainedFunctionals(J,[C],state_map,analytic_dJ=dJ,analytic_dC=[dC]) -# Velocity extension -α = 4*maximum(get_el_Δ(model)) -a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ -vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) -# Finite difference scheme -scheme = FirstOrderStencil(length(el_size),Float64) -ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) -# Optimiser -optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) -# Solve -for (it,uh,φh) in optimiser - data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"struc_$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser)) -end -# Final structure -it = get_history(optimiser).niter; uh = get_state(pcfs) -writevtk(Ω,path*"struc_$it",cellfields=["phi"=>φh, - "H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) \ No newline at end of file diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl deleted file mode 100644 index 10c1dacf..00000000 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc.jl +++ /dev/null @@ -1,99 +0,0 @@ -using Gridap, GridapPETSc, SparseMatricesCSR, LevelSetTopOpt - -function main() - # FE parameters - order = 1 # Finite element order - xmax=ymax=zmax=1.0 # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - el_size = (100,100,100) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) - # FD parameters - γ = 0.1 # HJ equation time step coefficient - γ_reinit = 0.5 # Reinit. equation time step coefficient - max_steps = floor(Int,minimum(el_size)/3) # Max steps for advection - tol = 1/(2order^2)/minimum(el_size) # Advection tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # Output VTK files every 10th iteration - path = "./results/tut1_3d_petsc/" # Output path - mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - # State map - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = PETScLinearSolver(),adjoint_ls = PETScLinearSolver() - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map,analytic_dJ=dJ,analytic_dC=[dC]) - # Velocity extension - α = 4*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) - # Solve - for (it,uh,φh) in optimiser - data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"struc_$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser)) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"struc_$it",cellfields=["phi"=>φh, - "H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" -GridapPETSc.with(args=split(solver_options)) do - main() -end \ No newline at end of file diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl deleted file mode 100644 index 1b88fd91..00000000 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_3d_petsc_mpi.jl +++ /dev/null @@ -1,104 +0,0 @@ -using Gridap, GridapPETSc, GridapDistributed, PartitionedArrays, SparseMatricesCSR, LevelSetTopOpt - -function main(mesh_partition,distribute) - ranks = distribute(LinearIndices((prod(mesh_partition),))) - # FE parameters - order = 1 # Finite element order - xmax=ymax=zmax=1.0 # Domain size - dom = (0,xmax,0,ymax,0,zmax) # Bounding domain - el_size = (100,100,100) # Mesh partition size - prop_Γ_N = 0.2 # Γ_N size parameter - prop_Γ_D = 0.2 # Γ_D size parameter - f_Γ_N(x) = (x[1] ≈ xmax) && # Γ_N indicator function - (ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) && - (zmax/2-zmax*prop_Γ_N/2 - eps() <= x[3] <= zmax/2+zmax*prop_Γ_N/2 + eps()) - f_Γ_D(x) = (x[1] ≈ 0.0) && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps()) && - (x[3] <= zmax*prop_Γ_D + eps() || x[3] >= zmax-zmax*prop_Γ_D - eps()) - # FD parameters - γ = 0.1 # HJ equation time step coefficient - γ_reinit = 0.5 # Reinit. equation time step coefficient - max_steps = floor(Int,minimum(el_size)/3) # Max steps for advection - tol = 1/(2order^2)/minimum(el_size) # Advection tolerance - # Problem parameters - κ = 1 # Diffusivity - g = 1 # Heat flow in - vf = 0.4 # Volume fraction constraint - lsf_func = initial_lsf(4,0.2) # Initial level set function - iter_mod = 10 # Output VTK files every 10th iteration - path = "./results/tut1_3d_petsc_mpi/" # Output path - i_am_main(ranks) && mkpath(path) # Create path - # Model - model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); - update_labels!(1,model,f_Γ_D,"Gamma_D") - update_labels!(2,model,f_Γ_N,"Gamma_N") - # Triangulation and measures - Ω = Triangulation(model) - Γ_N = BoundaryTriangulation(model,tags="Gamma_N") - dΩ = Measure(Ω,2*order) - dΓ_N = Measure(Γ_N,2*order) - # Spaces - reffe = ReferenceFE(lagrangian,Float64,order) - V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) - U = TrialFESpace(V,0.0) - V_φ = TestFESpace(model,reffe) - V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) - U_reg = TrialFESpace(V_reg,0) - # Level set and interpolator - φh = interpolate(lsf_func,V_φ) - interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) - I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ - # Weak formulation - a(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(v))dΩ - l(v,φ,dΩ,dΓ_N) = ∫(g*v)dΓ_N - # State map - Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} - Tv = Vector{PetscScalar} - state_map = AffineFEStateMap( - a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_N; - assem_U = SparseMatrixAssembler(Tm,Tv,U,V), - assem_adjoint = SparseMatrixAssembler(Tm,Tv,V,U), - assem_deriv = SparseMatrixAssembler(Tm,Tv,U_reg,U_reg), - ls = PETScLinearSolver(),adjoint_ls = PETScLinearSolver() - ) - # Objective and constraints - J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*κ*∇(u)⋅∇(u))dΩ - dJ(q,u,φ,dΩ,dΓ_N) = ∫(κ*∇(u)⋅∇(u)*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - vol_D = sum(∫(1)dΩ) - C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ - dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ - pcfs = PDEConstrainedFunctionals(J,[C],state_map,analytic_dJ=dJ,analytic_dC=[dC]) - # Velocity extension - α = 4*maximum(get_el_Δ(model)) - a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ - vel_ext = VelocityExtension( - a_hilb, U_reg, V_reg; - assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), - ls = PETScLinearSolver() - ) - # Finite difference scheme - scheme = FirstOrderStencil(length(el_size),Float64) - ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) - # Optimiser - optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; - γ,γ_reinit,verbose=i_am_main(ranks),constraint_names=[:Vol]) - # Solve - for (it,uh,φh) in optimiser - data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"struc_$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser)) - end - # Final structure - it = get_history(optimiser).niter; uh = get_state(pcfs) - writevtk(Ω,path*"struc_$it",cellfields=["phi"=>φh, - "H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) -end - -with_mpi() do distribute - mesh_partition = (2,2,2) - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true - -ksp_converged_reason -ksp_rtol 1.0e-12" - GridapPETSc.with(args=split(solver_options)) do - main(mesh_partition,distribute) - end -end \ No newline at end of file diff --git a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl b/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl deleted file mode 100644 index 3642fb95..00000000 --- a/scripts/_dev/tutorial_test/minimum_thermal_compliance_implementation_nonlinear.jl +++ /dev/null @@ -1,74 +0,0 @@ -using Gridap, LevelSetTopOpt - -# FE parameters -order = 1 # Finite element order -xmax = ymax = 1.0 # Domain size -dom = (0,xmax,0,ymax) # Bounding domain -el_size = (200,200) # Mesh partition size -prop_Γ_N = 0.2 # Γ_N size parameter -prop_Γ_D = 0.2 # Γ_D size parameter -f_Γ_N(x) = (x[1] ≈ xmax && # Γ_N indicator function - ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) -f_Γ_D(x) = (x[1] ≈ 0.0 && # Γ_D indicator function - (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) -# FD parameters -γ = 0.1 # HJ equation time step coefficient -γ_reinit = 0.5 # Reinit. equation time step coefficient -max_steps = floor(Int,minimum(el_size)/10) # Max steps for advection -tol = 1/(5order^2)/minimum(el_size) # Advection tolerance -# Problem parameters -κ(u) = exp(-u) # Diffusivity -g = 1 # Heat flow in -vf = 0.4 # Volume fraction constraint -lsf_func = initial_lsf(4,0.2) # Initial level set function -iter_mod = 10 # Output VTK files every 10th iteration -path = "./results/tut1_nonlinear/" # Output path -mkpath(path) # Create path -# Model -model = CartesianDiscreteModel(dom,el_size); -update_labels!(1,model,f_Γ_D,"Gamma_D") -update_labels!(2,model,f_Γ_N,"Gamma_N") -# Triangulation and measures -Ω = Triangulation(model) -Γ_N = BoundaryTriangulation(model,tags="Gamma_N") -dΩ = Measure(Ω,2*order) -dΓ_N = Measure(Γ_N,2*order) -# Spaces -reffe = ReferenceFE(lagrangian,Float64,order) -V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"]) -U = TrialFESpace(V,0.0) -V_φ = TestFESpace(model,reffe) -V_reg = TestFESpace(model,reffe;dirichlet_tags=["Gamma_N"]) -U_reg = TrialFESpace(V_reg,0) -# Level set and interpolator -φh = interpolate(lsf_func,V_φ) -interp = SmoothErsatzMaterialInterpolation(η = 2*maximum(get_el_Δ(model))) -I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ -# Weak formulation -R(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(v))dΩ - ∫(g*v)dΓ_N -state_map = NonlinearFEStateMap(R,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) -# Objective and constraints -J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(u))dΩ -vol_D = sum(∫(1)dΩ) -C(u,φ,dΩ,dΓ_N) = ∫(((ρ ∘ φ) - vf)/vol_D)dΩ -dC(q,u,φ,dΩ,dΓ_N) = ∫(-1/vol_D*q*(DH ∘ φ)*(norm ∘ ∇(φ)))dΩ -pcfs = PDEConstrainedFunctionals(J,[C],state_map,analytic_dC=[dC]) -# Velocity extension -α = 4*maximum(get_el_Δ(model)) -a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ -vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) -# Finite difference scheme -scheme = FirstOrderStencil(length(el_size),Float64) -ls_evo = HamiltonJacobiEvolution(scheme,model,V_φ,tol,max_steps) -# Optimiser -optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) -# Solve -for (it,uh,φh) in optimiser - data = ["phi"=>φh,"H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh] - iszero(it % iter_mod) && (writevtk(Ω,path*"struc_$it",cellfields=data);GC.gc()) - write_history(path*"/history.txt",get_history(optimiser)) -end -# Final structure -it = get_history(optimiser).niter; uh = get_state(pcfs) -writevtk(Ω,path*"struc_$it",cellfields=["phi"=>φh, - "H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) \ No newline at end of file From ed2c63921ab585bbdddaad6bd5a52a26d30993b0 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Tue, 7 May 2024 11:29:24 +1000 Subject: [PATCH 85/90] Rename package --- .gitignore | 2 +- Project.toml | 2 +- README.md | 8 +- compile/compile.jl | 4 +- compile/warmup.jl | 4 +- docs/make.jl | 6 +- docs/src/dev/shape_der.md | 12 +- docs/src/getting-started.md | 18 +-- docs/src/index.md | 10 +- docs/src/reference/benchmarking.md | 16 +-- docs/src/reference/chainrules.md | 66 +++++------ docs/src/reference/io.md | 16 +-- docs/src/reference/levelsetevolution.md | 32 +++--- docs/src/reference/optimisers.md | 26 ++--- docs/src/reference/utilities.md | 10 +- docs/src/reference/velext.md | 2 +- .../tutorials/minimum_thermal_compliance.md | 84 +++++++------- scripts/Benchmarks/benchmark.jl | 32 +++--- .../Benchmarks/generate_benchmark_scripts.jl | 12 +- scripts/MPI/3d_elastic_compliance_ALM.jl | 2 +- scripts/MPI/3d_hyperelastic_compliance_ALM.jl | 2 +- .../3d_hyperelastic_compliance_neohook_ALM.jl | 2 +- scripts/MPI/3d_inverse_homenisation_ALM.jl | 2 +- scripts/MPI/3d_inverter_ALM.jl | 2 +- scripts/MPI/3d_inverter_HPM.jl | 2 +- .../3d_nonlinear_thermal_compliance_ALM.jl | 2 +- scripts/MPI/3d_thermal_compliance_ALM.jl | 2 +- scripts/MPI/elastic_compliance_ALM.jl | 2 +- scripts/MPI/inverse_homenisation_ALM.jl | 2 +- .../MPI/nonlinear_thermal_compliance_ALM.jl | 2 +- scripts/MPI/thermal_compliance_ALM.jl | 2 +- scripts/MPI/thermal_compliance_ALM_PETSc.jl | 2 +- scripts/Serial/elastic_compliance_ALM.jl | 2 +- scripts/Serial/elastic_compliance_HPM.jl | 2 +- scripts/Serial/elastic_compliance_LM.jl | 2 +- scripts/Serial/hyperelastic_compliance_ALM.jl | 2 +- .../hyperelastic_compliance_neohook_ALM.jl | 2 +- scripts/Serial/inverse_homenisation_ALM.jl | 2 +- scripts/Serial/inverter_ALM.jl | 2 +- scripts/Serial/inverter_HPM.jl | 2 +- .../nonlinear_thermal_compliance_ALM.jl | 2 +- scripts/Serial/thermal_compliance_ALM.jl | 2 +- .../thermal_compliance_ALM_higherorderlsf.jl | 2 +- src/ChainRules.jl | 104 +++++++++--------- src/{LevelSetTopOpt.jl => GridapTopOpt.jl} | 4 +- src/Optimisers/Optimisers.jl | 14 +-- test/seq/InverseHomogenisationALMTests.jl | 8 +- test/seq/InverterHPMTests.jl | 14 +-- .../seq/NonlinearThermalComplianceALMTests.jl | 12 +- test/seq/PZMultiFieldRepeatingStateTests.jl | 16 +-- test/seq/ThermalComplianceALMTests.jl | 14 +-- 51 files changed, 298 insertions(+), 298 deletions(-) rename src/{LevelSetTopOpt.jl => GridapTopOpt.jl} (94%) diff --git a/.gitignore b/.gitignore index d43b6663..ddd3c8e5 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ docs/site/ # environment. Manifest.toml LocalPreferences.toml -LevelSetTopOpt.so +GridapTopOpt.so diff --git a/Project.toml b/Project.toml index 8f014570..1ad4f421 100755 --- a/Project.toml +++ b/Project.toml @@ -1,4 +1,4 @@ -name = "LevelSetTopOpt" +name = "GridapTopOpt" uuid = "27dd0110-1916-4fd6-8b4b-1bc109db1170" authors = ["Zach Wegert ", "JordiManyer "] version = "0.1.0" diff --git a/README.md b/README.md index f49144ea..d75a3ce5 100755 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# LevelSetTopOpt +# GridapTopOpt | **badges** | -LevelSetTopOpt is computational toolbox for level set-based topology optimisation implemented in Julia and the [Gridap](https://github.com/gridap/Gridap.jl) package ecosystem. See the documentation and following publication for further details: +GridapTopOpt is computational toolbox for level set-based topology optimisation implemented in Julia and the [Gridap](https://github.com/gridap/Gridap.jl) package ecosystem. See the documentation and following publication for further details: -> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable Julia toolbox for level set-based topology optimisation". In preparation. +> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "GridapTopOpt.jl: A scalable Julia toolbox for level set-based topology optimisation". In preparation. ## Documentation @@ -12,4 +12,4 @@ LevelSetTopOpt is computational toolbox for level set-based topology optimisatio - [**LATEST**](...) — *Documentation for the in-development version.* ## Citation -In order to give credit to the `LevelSetTopOpt` contributors, we ask that you please reference the above paper along with the required citations for [Gridap](https://github.com/gridap/Gridap.jl?tab=readme-ov-file#how-to-cite-gridap). \ No newline at end of file +In order to give credit to the `GridapTopOpt` contributors, we ask that you please reference the above paper along with the required citations for [Gridap](https://github.com/gridap/Gridap.jl?tab=readme-ov-file#how-to-cite-gridap). \ No newline at end of file diff --git a/compile/compile.jl b/compile/compile.jl index 60943604..f3fc72d6 100644 --- a/compile/compile.jl +++ b/compile/compile.jl @@ -1,5 +1,5 @@ using PackageCompiler -create_sysimage([:LevelSetTopOpt], - sysimage_path=joinpath(@__DIR__,"..","LevelSetTopOpt.so"), +create_sysimage([:GridapTopOpt], + sysimage_path=joinpath(@__DIR__,"..","GridapTopOpt.so"), precompile_execution_file=joinpath(@__DIR__,"warmup.jl")) diff --git a/compile/warmup.jl b/compile/warmup.jl index c2b6e5e3..feed08f6 100644 --- a/compile/warmup.jl +++ b/compile/warmup.jl @@ -1,4 +1,4 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt +using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, GridapTopOpt """ (MPI) Minimum thermal compliance with Lagrangian method in 2D. @@ -83,7 +83,7 @@ function main(mesh_partition,distribute) vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) ## Optimiser - _conv_cond = t->LevelSetTopOpt.conv_cond(t;coef=1/50); + _conv_cond = t->GridapTopOpt.conv_cond(t;coef=1/50); optimiser = AugmentedLagrangian(φ,pcfs,ls_evo,vel_ext,interp,el_size,γ,γ_reinit,conv_criterion=_conv_cond); for history in optimiser it,Ji,_,_ = last(history) diff --git a/docs/make.jl b/docs/make.jl index 6edb2324..7755b4c2 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -3,15 +3,15 @@ # using Pkg; Pkg.activate(".") using Documenter -using LevelSetTopOpt +using GridapTopOpt makedocs( - sitename = "LevelSetTopOpt.jl", + sitename = "GridapTopOpt.jl", format = Documenter.HTML( prettyurls = false, # collapselevel = 1, ), - modules = [LevelSetTopOpt], + modules = [GridapTopOpt], pages = [ "Home" => "index.md", "Getting Started" => "getting-started.md", diff --git a/docs/src/dev/shape_der.md b/docs/src/dev/shape_der.md index 8d4ddb8d..f0477089 100644 --- a/docs/src/dev/shape_der.md +++ b/docs/src/dev/shape_der.md @@ -32,7 +32,7 @@ The final result of course does not yet match ``(\star)``. Over a fixed computat J_1^\prime(\Omega)(-v\boldsymbol{n})=-\int_{D}vf(\boldsymbol{x})H'(\varphi)\lvert\nabla\varphi\rvert~\mathrm{d}s. ``` -As ``\varphi`` is a signed distance function we have ``\lvert\nabla\varphi\rvert=1`` for ``D\setminus\Sigma`` where ``\Sigma`` is the skeleton of ``\Omega`` and ``\Omega^\complement``. Furthermore, ``H'(\varphi)`` provides support only within a band of ``\partial\Omega``. +As ``\varphi`` is a signed distance function we have ``\lvert\nabla\varphi\rvert=1`` for ``D\setminus\Sigma`` where ``\Sigma`` is the skeleton of ``\Omega`` and ``\Omega^\complement``. Furthermore, ``H'(\varphi)`` provides support only within a band of ``\partial\Omega``. !!! tip "Result I" Therefore, we have that almost everywhere @@ -71,9 +71,9 @@ Consider ``\Omega\subset D`` with ``J(\Omega)=\int_\Omega j(\boldsymbol{u})~\mat In the above ``\boldsymbol{\varepsilon}`` is the strain tensor, ``\boldsymbol{C}`` is the stiffness tensor, ``\Gamma_0 = \partial\Omega\setminus(\Gamma_D\cup\Gamma_N\cup\Gamma_R)``, and ``\Gamma_D``, ``\Gamma_N``, ``\Gamma_R`` are required to be fixed. ### Shape derivative -Let us first consider the shape derivative of ``J``. Disregarding embedding inside the computational domain ``D``, the above strong form can be written in weak form as: +Let us first consider the shape derivative of ``J``. Disregarding embedding inside the computational domain ``D``, the above strong form can be written in weak form as: -``\quad`` *Find* ``\boldsymbol{u}\in H^1_{\Gamma_D}(\Omega)^d`` *such that* +``\quad`` *Find* ``\boldsymbol{u}\in H^1_{\Gamma_D}(\Omega)^d`` *such that* ```math \int_{\Omega} \boldsymbol{C\varepsilon}(\boldsymbol{u})\boldsymbol{\varepsilon}(\boldsymbol{v})~\mathrm{d}\boldsymbol{x}+\int_{\Gamma_R}\boldsymbol{w}(\boldsymbol{u})\cdot\boldsymbol{v}~\mathrm{d}s=\int_\Omega \boldsymbol{f}\cdot\boldsymbol{v}~\mathrm{d}\boldsymbol{x}+\int_{\Gamma_N}\boldsymbol{g}\cdot\boldsymbol{v}~\mathrm{d}s,~\forall \boldsymbol{v}\in H^1_{\Gamma_D}(\Omega)^d. @@ -137,7 +137,7 @@ As required. Note that in the above, we have used that ``\boldsymbol{\theta}\cdo ### Gâteaux derivative in ``\varphi`` -Let us now return to derivatives of ``J`` with respect to ``\varphi`` over the whole computational domain. As previously, suppose that we rewrite ``J`` as +Let us now return to derivatives of ``J`` with respect to ``\varphi`` over the whole computational domain. As previously, suppose that we rewrite ``J`` as ```math \hat{\mathcal{J}}(\varphi)=\int_D (1-H(\varphi))j(\boldsymbol{u})~\mathrm{d}\boldsymbol{x}+\int_{\Gamma_N} l_1(\boldsymbol{u})~\mathrm{d}s+\int_{\Gamma_R} l_2(\boldsymbol{u})~\mathrm{d}s @@ -212,7 +212,7 @@ This exactly as previously up to relaxation over ``D``. Finally, The derivative \end{aligned} ``` -where we have used that ``v=0`` on ``\Gamma_D`` as previously. As previously taking ``\boldsymbol{\theta}=v\boldsymbol{n}`` and relaxing the shape derivative of ``J`` over ``D`` with a signed distance function ``\varphi`` yields: +where we have used that ``v=0`` on ``\Gamma_D`` as previously. As previously taking ``\boldsymbol{\theta}=v\boldsymbol{n}`` and relaxing the shape derivative of ``J`` over ``D`` with a signed distance function ``\varphi`` yields: !!! tip "Result II" ```math @@ -227,7 +227,7 @@ Owing to a fixed computational regime we do not capture a variation of the domai In addition, functionals of the signed distance function posed over the whole bounding domain ``D`` admit a special structure under shape differentiation ([Paper](https://doi.org/10.1051/m2an/2019056)). Such cases are not captured by a Gâteaux derivative at ``\varphi`` under relaxation. !!! note - In future, we plan to implement CellFEM via GridapEmbedded in LevelSetTopOpt. This will enable Gâteaux derivative of the mapping + In future, we plan to implement CellFEM via GridapEmbedded in GridapTopOpt. This will enable Gâteaux derivative of the mapping ```math \varphi \mapsto \int_{\Omega(\varphi)}f(\varphi)~\mathrm{d}\boldsymbol{x} + \int_{\Omega(\varphi)^\complement}f(\varphi)~\mathrm{d}\boldsymbol{x}. diff --git a/docs/src/getting-started.md b/docs/src/getting-started.md index 80775cda..841ad21c 100644 --- a/docs/src/getting-started.md +++ b/docs/src/getting-started.md @@ -2,11 +2,11 @@ ## Installation -`LevelSetTopOpt.jl` and additional dependencies can be installed in an existing Julia environment using the package manager. This can be accessed in the Julia REPL (read-eval–print loop) by pressing `]`. We then add the required packages via: +`GridapTopOpt.jl` and additional dependencies can be installed in an existing Julia environment using the package manager. This can be accessed in the Julia REPL (read-eval–print loop) by pressing `]`. We then add the required packages via: ``` -pkg> add LevelSetTopOpt, Gridap, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, SparseMatricesCSR +pkg> add GridapTopOpt, Gridap, GridapDistributed, GridapPETSc, GridapSolvers, PartitionedArrays, SparseMatricesCSR ``` -Once installed, serial driver scripts can be run immediately, whereas parallel problems also require an MPI installation. +Once installed, serial driver scripts can be run immediately, whereas parallel problems also require an MPI installation. ### MPI For basic users, [`MPI.jl`](https://github.com/JuliaParallel/MPI.jl) provides such an implementation and a Julia wrapper for `mpiexec` - the MPI executor. This is installed via: @@ -19,18 +19,18 @@ Once the `mpiexecjl` wrapper has been added to the system `PATH`, MPI scripts ca ``` mpiexecjl -n P julia main.jl ``` -where `main` is a driver script, `P` denotes the number of processors. +where `main` is a driver script, `P` denotes the number of processors. ### PETSc -In `LevelSetTopOpt.jl` we rely on the [`GridapPETSc.jl`](https://github.com/gridap/GridapPETSc.jl) satellite package to interface with the linear and nonlinear solvers provided by the PETSc (Portable, Extensible Toolkit for Scientific Computation) library. For basic users these solvers are provided by `GridapPETSc.jl` with no additional work. +In `GridapTopOpt.jl` we rely on the [`GridapPETSc.jl`](https://github.com/gridap/GridapPETSc.jl) satellite package to interface with the linear and nonlinear solvers provided by the PETSc (Portable, Extensible Toolkit for Scientific Computation) library. For basic users these solvers are provided by `GridapPETSc.jl` with no additional work. ### Advanced installation For more advanced installations, such as use of a custom MPI/PETSc installation on a HPC cluster, we refer the reader to the [discussion](https://github.com/gridap/GridapPETSc.jl) for `GridapPETSc.jl` and the [configuration page](https://juliaparallel.org/MPI.jl/stable/configuration/) for `MPI.jl`. ## Usage and tutorials -In order to get familiar with the library we recommend following the numerical examples described in: +In order to get familiar with the library we recommend following the numerical examples described in: -> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. +> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "GridapTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. In addition, there are several driver scripts available in `/scripts/..` @@ -38,5 +38,5 @@ More general tutorials for familiarising ones self with Gridap are available via ## Known issues - PETSc's GAMG preconditioner breaks for split Dirichlet DoFs (e.g., x constrained while y free for a single node). There is no simple fix for this. We recommend instead using MUMPS or another preconditioner for this case. -- Currently, our implementation of automatic differentiation does not support multiplication and division of optimisation functionals. We plan to add this in a future release of `LevelSetTopOpt.jl` -- Issue [#38](https://github.com/zjwegert/LSTO_Distributed/issues/38). -- Analytic gradient breaks in parallel for integrals of certain measures -- Issue [#46](https://github.com/zjwegert/LSTO_Distributed/issues/46) \ No newline at end of file +- Currently, our implementation of automatic differentiation does not support multiplication and division of optimisation functionals. We plan to add this in a future release of `GridapTopOpt.jl` -- Issue [#38](https://github.com/zjwegert/GridapTopOpt/issues/38). +- Analytic gradient breaks in parallel for integrals of certain measures -- Issue [#46](https://github.com/zjwegert/GridapTopOpt/issues/46) \ No newline at end of file diff --git a/docs/src/index.md b/docs/src/index.md index e3b8ed44..c8239bcd 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,10 +1,10 @@ -# LevelSetTopOpt.jl -Welcome to the documentation for `LevelSetTopOpt.jl`! +# GridapTopOpt.jl +Welcome to the documentation for `GridapTopOpt.jl`! ## Introduction -`LevelSetTopOpt.jl` is computational toolbox for level set-based topology optimisation implemented in Julia and the Gridap package ecosystem. The core design principle of `LevelSetTopOpt.jl` is to provide an extendable framework for solving optimisation problems in serial or parallel with a high-level programming interface and automatic differentiation. See the following publication for further details: +`GridapTopOpt.jl` is computational toolbox for level set-based topology optimisation implemented in Julia and the Gridap package ecosystem. The core design principle of `GridapTopOpt.jl` is to provide an extendable framework for solving optimisation problems in serial or parallel with a high-level programming interface and automatic differentiation. See the following publication for further details: -> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "LevelSetTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. +> Zachary J. Wegert, Jordi Manyer, Connor Mallon, Santiago Badia, and Vivien J. Challis (2024). "GridapTopOpt.jl: A scalable computational toolbox for level set-based topology optimisation". In preparation. ## How to use this documentation @@ -16,7 +16,7 @@ Welcome to the documentation for `LevelSetTopOpt.jl`! ## Julia educational resources -A basic knowledge of the Julia programming language is needed to use the `LevelSetTopOpt.jl` package. +A basic knowledge of the Julia programming language is needed to use the `GridapTopOpt.jl` package. Here, one can find a list of resources to get started with this programming language. * First steps to learn Julia form the [Gridap wiki](https://github.com/gridap/Gridap.jl/wiki/Start-learning-Julia) page. diff --git a/docs/src/reference/benchmarking.md b/docs/src/reference/benchmarking.md index 617ee276..59594ae3 100644 --- a/docs/src/reference/benchmarking.md +++ b/docs/src/reference/benchmarking.md @@ -1,16 +1,16 @@ # Benchmarking ```@docs -LevelSetTopOpt.benchmark +GridapTopOpt.benchmark ``` ## Existing benchmark methods ```@docs -LevelSetTopOpt.benchmark_optimizer -LevelSetTopOpt.benchmark_single_iteration -LevelSetTopOpt.benchmark_forward_problem -LevelSetTopOpt.benchmark_advection -LevelSetTopOpt.benchmark_reinitialisation -LevelSetTopOpt.benchmark_velocity_extension -LevelSetTopOpt.benchmark_hilbertian_projection_map +GridapTopOpt.benchmark_optimizer +GridapTopOpt.benchmark_single_iteration +GridapTopOpt.benchmark_forward_problem +GridapTopOpt.benchmark_advection +GridapTopOpt.benchmark_reinitialisation +GridapTopOpt.benchmark_velocity_extension +GridapTopOpt.benchmark_hilbertian_projection_map ``` \ No newline at end of file diff --git a/docs/src/reference/chainrules.md b/docs/src/reference/chainrules.md index 36559333..00d6f058 100644 --- a/docs/src/reference/chainrules.md +++ b/docs/src/reference/chainrules.md @@ -3,42 +3,42 @@ ## `PDEConstrainedFunctionals` ```@docs -LevelSetTopOpt.PDEConstrainedFunctionals -LevelSetTopOpt.evaluate! -LevelSetTopOpt.evaluate_functionals! -LevelSetTopOpt.evaluate_derivatives! -LevelSetTopOpt.get_state +GridapTopOpt.PDEConstrainedFunctionals +GridapTopOpt.evaluate! +GridapTopOpt.evaluate_functionals! +GridapTopOpt.evaluate_derivatives! +GridapTopOpt.get_state ``` ## `StateParamIntegrandWithMeasure` ```@docs -LevelSetTopOpt.StateParamIntegrandWithMeasure -LevelSetTopOpt.rrule(u_to_j::LevelSetTopOpt.StateParamIntegrandWithMeasure,uh,φh) +GridapTopOpt.StateParamIntegrandWithMeasure +GridapTopOpt.rrule(u_to_j::GridapTopOpt.StateParamIntegrandWithMeasure,uh,φh) ``` ## Implemented types of `AbstractFEStateMap` ```@docs -LevelSetTopOpt.AbstractFEStateMap +GridapTopOpt.AbstractFEStateMap ``` ### `AffineFEStateMap` ```@docs -LevelSetTopOpt.AffineFEStateMap -LevelSetTopOpt.AffineFEStateMap(a::Function,l::Function,U,V,V_φ,U_reg,φh,dΩ...;assem_U = SparseMatrixAssembler(U,V),assem_adjoint = SparseMatrixAssembler(V,U),assem_deriv = SparseMatrixAssembler(U_reg,U_reg),ls::LinearSolver = LUSolver(),adjoint_ls::LinearSolver = LUSolver()) +GridapTopOpt.AffineFEStateMap +GridapTopOpt.AffineFEStateMap(a::Function,l::Function,U,V,V_φ,U_reg,φh,dΩ...;assem_U = SparseMatrixAssembler(U,V),assem_adjoint = SparseMatrixAssembler(V,U),assem_deriv = SparseMatrixAssembler(U_reg,U_reg),ls::LinearSolver = LUSolver(),adjoint_ls::LinearSolver = LUSolver()) ``` ### `NonlinearFEStateMap` ```@docs -LevelSetTopOpt.NonlinearFEStateMap -LevelSetTopOpt.NonlinearFEStateMap(res::Function,U,V,V_φ,U_reg,φh,dΩ...;assem_U = SparseMatrixAssembler(U,V),assem_adjoint = SparseMatrixAssembler(V,U),assem_deriv = SparseMatrixAssembler(U_reg,U_reg),nls::NonlinearSolver = NewtonSolver(LUSolver();maxiter=50,rtol=1.e-8,verbose=true),adjoint_ls::LinearSolver = LUSolver()) +GridapTopOpt.NonlinearFEStateMap +GridapTopOpt.NonlinearFEStateMap(res::Function,U,V,V_φ,U_reg,φh,dΩ...;assem_U = SparseMatrixAssembler(U,V),assem_adjoint = SparseMatrixAssembler(V,U),assem_deriv = SparseMatrixAssembler(U_reg,U_reg),nls::NonlinearSolver = NewtonSolver(LUSolver();maxiter=50,rtol=1.e-8,verbose=true),adjoint_ls::LinearSolver = LUSolver()) ``` ### `RepeatingAffineFEStateMap` ```@docs -LevelSetTopOpt.RepeatingAffineFEStateMap -LevelSetTopOpt.RepeatingAffineFEStateMap(nblocks::Int,a::Function,l::Vector{<:Function},U0,V0,V_φ,U_reg,φh,dΩ...;assem_U = SparseMatrixAssembler(U0,V0),assem_adjoint = SparseMatrixAssembler(V0,U0),assem_deriv = SparseMatrixAssembler(U_reg,U_reg),ls::LinearSolver = LUSolver(),adjoint_ls::LinearSolver = LUSolver()) +GridapTopOpt.RepeatingAffineFEStateMap +GridapTopOpt.RepeatingAffineFEStateMap(nblocks::Int,a::Function,l::Vector{<:Function},U0,V0,V_φ,U_reg,φh,dΩ...;assem_U = SparseMatrixAssembler(U0,V0),assem_adjoint = SparseMatrixAssembler(V0,U0),assem_deriv = SparseMatrixAssembler(U_reg,U_reg),ls::LinearSolver = LUSolver(),adjoint_ls::LinearSolver = LUSolver()) ``` ## Advanced @@ -47,32 +47,32 @@ LevelSetTopOpt.RepeatingAffineFEStateMap(nblocks::Int,a::Function,l::Vector{<:Fu #### Existing methods ```@docs -LevelSetTopOpt.rrule(φ_to_u::LevelSetTopOpt.AbstractFEStateMap,φh) -LevelSetTopOpt.pullback +GridapTopOpt.rrule(φ_to_u::GridapTopOpt.AbstractFEStateMap,φh) +GridapTopOpt.pullback ``` #### Required to implement ```@docs -LevelSetTopOpt.forward_solve! -LevelSetTopOpt.adjoint_solve! -LevelSetTopOpt.update_adjoint_caches! -LevelSetTopOpt.dRdφ -LevelSetTopOpt.get_state(::LevelSetTopOpt.AbstractFEStateMap) -LevelSetTopOpt.get_measure -LevelSetTopOpt.get_spaces -LevelSetTopOpt.get_assemblers -LevelSetTopOpt.get_trial_space -LevelSetTopOpt.get_test_space -LevelSetTopOpt.get_aux_space -LevelSetTopOpt.get_deriv_space -LevelSetTopOpt.get_pde_assembler -LevelSetTopOpt.get_deriv_assembler +GridapTopOpt.forward_solve! +GridapTopOpt.adjoint_solve! +GridapTopOpt.update_adjoint_caches! +GridapTopOpt.dRdφ +GridapTopOpt.get_state(::GridapTopOpt.AbstractFEStateMap) +GridapTopOpt.get_measure +GridapTopOpt.get_spaces +GridapTopOpt.get_assemblers +GridapTopOpt.get_trial_space +GridapTopOpt.get_test_space +GridapTopOpt.get_aux_space +GridapTopOpt.get_deriv_space +GridapTopOpt.get_pde_assembler +GridapTopOpt.get_deriv_assembler ``` ### `IntegrandWithMeasure` ```@docs -LevelSetTopOpt.IntegrandWithMeasure -LevelSetTopOpt.gradient -LevelSetTopOpt.jacobian +GridapTopOpt.IntegrandWithMeasure +GridapTopOpt.gradient +GridapTopOpt.jacobian ``` \ No newline at end of file diff --git a/docs/src/reference/io.md b/docs/src/reference/io.md index e4c4ff89..ce7a6127 100644 --- a/docs/src/reference/io.md +++ b/docs/src/reference/io.md @@ -1,21 +1,21 @@ # IO -In LevelSetTopOpt, the usual IO from [Gridap](https://github.com/gridap/Gridap.jl/) is available. In addition, we also implement the below IO for convenience. +In GridapTopOpt, the usual IO from [Gridap](https://github.com/gridap/Gridap.jl/) is available. In addition, we also implement the below IO for convenience. ## Optimiser history ```@docs -LevelSetTopOpt.write_history +GridapTopOpt.write_history ``` ## Object IO in serial ```@docs -LevelSetTopOpt.save -LevelSetTopOpt.load -LevelSetTopOpt.load! +GridapTopOpt.save +GridapTopOpt.load +GridapTopOpt.load! ``` ## Object IO in parallel ```@docs -LevelSetTopOpt.psave -LevelSetTopOpt.pload -LevelSetTopOpt.pload! +GridapTopOpt.psave +GridapTopOpt.pload +GridapTopOpt.pload! ``` \ No newline at end of file diff --git a/docs/src/reference/levelsetevolution.md b/docs/src/reference/levelsetevolution.md index 3f41a926..0ddcc12f 100644 --- a/docs/src/reference/levelsetevolution.md +++ b/docs/src/reference/levelsetevolution.md @@ -1,39 +1,39 @@ # LevelSetEvolution -In LevelSetTopOpt, the level set is evolved and reinitialised using a `LevelSetEvolution` method. The most standard of these is the Hamilton-Jacobi evolution equation solved using a first order upwind finite difference scheme. A forward Euler in time method is provided below via `HamiltonJacobiEvolution <: LevelSetEvolution` along with an upwind finite difference stencil for the spatial discretisation via `FirstOrderStencil`. +In GridapTopOpt, the level set is evolved and reinitialised using a `LevelSetEvolution` method. The most standard of these is the Hamilton-Jacobi evolution equation solved using a first order upwind finite difference scheme. A forward Euler in time method is provided below via `HamiltonJacobiEvolution <: LevelSetEvolution` along with an upwind finite difference stencil for the spatial discretisation via `FirstOrderStencil`. This can be extended in several ways. For example, higher order spatial stencils can be implemented by extending the `Stencil` interface below. In addition, more advanced ODE solvers could be implemented (e.g., Runge–Kutta methods) or entirely different level set evolution methods by extending the `LevelSetEvolution` interface below. ## `HamiltonJacobiEvolution` ```@docs -LevelSetTopOpt.HamiltonJacobiEvolution -LevelSetTopOpt.HamiltonJacobiEvolution(stencil::LevelSetTopOpt.Stencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) -LevelSetTopOpt.evolve! -LevelSetTopOpt.reinit! -LevelSetTopOpt.get_dof_Δ(m::HamiltonJacobiEvolution) +GridapTopOpt.HamiltonJacobiEvolution +GridapTopOpt.HamiltonJacobiEvolution(stencil::GridapTopOpt.Stencil,model,space,tol=1.e-3,max_steps=100,max_steps_reinit=2000) +GridapTopOpt.evolve! +GridapTopOpt.reinit! +GridapTopOpt.get_dof_Δ(m::HamiltonJacobiEvolution) ``` ## Spatial stencils for `HamiltonJacobiEvolution` ```@docs -LevelSetTopOpt.FirstOrderStencil +GridapTopOpt.FirstOrderStencil ``` ## Custom `Stencil` ```@docs -LevelSetTopOpt.Stencil -LevelSetTopOpt.evolve!(::LevelSetTopOpt.Stencil,φ,vel,Δt,Δx,isperiodic,caches) -LevelSetTopOpt.reinit!(::LevelSetTopOpt.Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) -LevelSetTopOpt.allocate_caches(::LevelSetTopOpt.Stencil,φ,vel) -LevelSetTopOpt.check_order +GridapTopOpt.Stencil +GridapTopOpt.evolve!(::GridapTopOpt.Stencil,φ,vel,Δt,Δx,isperiodic,caches) +GridapTopOpt.reinit!(::GridapTopOpt.Stencil,φ_new,φ,vel,Δt,Δx,isperiodic,caches) +GridapTopOpt.allocate_caches(::GridapTopOpt.Stencil,φ,vel) +GridapTopOpt.check_order ``` ## Custom `LevelSetEvolution` To implement a custom level set evolution method, we can extend the methods below. For example, one could consider Reaction-Diffusion-based evolution of the level set function. This can be solved with a finite element method and so we can implement a new type that inherits from `LevelSetEvolution` independently of the `Stencil` types. ```@docs -LevelSetTopOpt.LevelSetEvolution -LevelSetTopOpt.evolve!(::LevelSetTopOpt.LevelSetEvolution,φ,args...) -LevelSetTopOpt.reinit!(::LevelSetTopOpt.LevelSetEvolution,φ,args...) -LevelSetTopOpt.get_dof_Δ(::LevelSetTopOpt.LevelSetEvolution) +GridapTopOpt.LevelSetEvolution +GridapTopOpt.evolve!(::GridapTopOpt.LevelSetEvolution,φ,args...) +GridapTopOpt.reinit!(::GridapTopOpt.LevelSetEvolution,φ,args...) +GridapTopOpt.get_dof_Δ(::GridapTopOpt.LevelSetEvolution) ``` \ No newline at end of file diff --git a/docs/src/reference/optimisers.md b/docs/src/reference/optimisers.md index fbbe278e..78b8287c 100644 --- a/docs/src/reference/optimisers.md +++ b/docs/src/reference/optimisers.md @@ -1,37 +1,37 @@ # Optimisers -In LevelSetTopOpt we implement optimisation algorithms as [iterators](https://docs.julialang.org/en/v1/manual/interfaces/) that inherit from an abstract type `Optimiser`. A concrete `Optimiser` implementation, say `OptEg`, then implements `iterate(m::OptEg) ↦ (var,state)` and `iterate(m::OptEg,state) ↦ (var,state)`, where `var` and `state` are the available items in the outer loop and internal state of the iterator, respectively. As a result we can iterate over the object `m=OptEg(...)` using `for var in m`. The benefit of this implementation is that the internals of the optimisation method can be hidden in the source code while the explicit `for` loop is still visible to the user. The body of the loop can then be used for auxiliary operations such as writing the optimiser history and other files. +In GridapTopOpt we implement optimisation algorithms as [iterators](https://docs.julialang.org/en/v1/manual/interfaces/) that inherit from an abstract type `Optimiser`. A concrete `Optimiser` implementation, say `OptEg`, then implements `iterate(m::OptEg) ↦ (var,state)` and `iterate(m::OptEg,state) ↦ (var,state)`, where `var` and `state` are the available items in the outer loop and internal state of the iterator, respectively. As a result we can iterate over the object `m=OptEg(...)` using `for var in m`. The benefit of this implementation is that the internals of the optimisation method can be hidden in the source code while the explicit `for` loop is still visible to the user. The body of the loop can then be used for auxiliary operations such as writing the optimiser history and other files. -The below describes the implemented optimisers along with the `OptimiserHistory` type. Custom optimisers can be implemented by creating types that inherit from `Optimiser` and extending the interfaces in [Custom optimiser](@ref). +The below describes the implemented optimisers along with the `OptimiserHistory` type. Custom optimisers can be implemented by creating types that inherit from `Optimiser` and extending the interfaces in [Custom optimiser](@ref). -## Lagrangian & Augmented Lagrangian method +## Lagrangian & Augmented Lagrangian method ```@autodocs -Modules = [LevelSetTopOpt] +Modules = [GridapTopOpt] Pages = ["Optimisers/AugmentedLagrangian.jl"] ``` ## Hilbertian projection method ```@autodocs -Modules = [LevelSetTopOpt] +Modules = [GridapTopOpt] Pages = ["Optimisers/HilbertianProjection.jl"] ``` ```@autodocs -Modules = [LevelSetTopOpt] +Modules = [GridapTopOpt] Pages = ["Optimisers/OrthogonalisationMaps.jl"] ``` ## Optimiser history ```@docs -LevelSetTopOpt.OptimiserHistory -LevelSetTopOpt.OptimiserHistorySlice +GridapTopOpt.OptimiserHistory +GridapTopOpt.OptimiserHistorySlice ``` ## Custom `Optimiser` ```@docs -LevelSetTopOpt.Optimiser -LevelSetTopOpt.iterate(::LevelSetTopOpt.Optimiser) -LevelSetTopOpt.iterate(::LevelSetTopOpt.Optimiser,state) -LevelSetTopOpt.get_history(::LevelSetTopOpt.Optimiser) -LevelSetTopOpt.converged(::LevelSetTopOpt.Optimiser) +GridapTopOpt.Optimiser +GridapTopOpt.iterate(::GridapTopOpt.Optimiser) +GridapTopOpt.iterate(::GridapTopOpt.Optimiser,state) +GridapTopOpt.get_history(::GridapTopOpt.Optimiser) +GridapTopOpt.converged(::GridapTopOpt.Optimiser) ``` \ No newline at end of file diff --git a/docs/src/reference/utilities.md b/docs/src/reference/utilities.md index 02bc4ba7..6fc92a5f 100644 --- a/docs/src/reference/utilities.md +++ b/docs/src/reference/utilities.md @@ -2,18 +2,18 @@ ## Ersatz material interpolation ```@docs -LevelSetTopOpt.SmoothErsatzMaterialInterpolation +GridapTopOpt.SmoothErsatzMaterialInterpolation ``` ## Mesh labelling ```@docs -LevelSetTopOpt.update_labels! +GridapTopOpt.update_labels! ``` ## Helpers ```@docs -LevelSetTopOpt.initial_lsf -LevelSetTopOpt.isotropic_elast_tensor -LevelSetTopOpt.get_el_Δ +GridapTopOpt.initial_lsf +GridapTopOpt.isotropic_elast_tensor +GridapTopOpt.get_el_Δ ``` \ No newline at end of file diff --git a/docs/src/reference/velext.md b/docs/src/reference/velext.md index 7e94e680..4179b745 100644 --- a/docs/src/reference/velext.md +++ b/docs/src/reference/velext.md @@ -1,6 +1,6 @@ # Velocity extension ```@autodocs -Modules = [LevelSetTopOpt] +Modules = [GridapTopOpt] Pages = ["VelocityExtension.jl"] ``` \ No newline at end of file diff --git a/docs/src/tutorials/minimum_thermal_compliance.md b/docs/src/tutorials/minimum_thermal_compliance.md index 3d52db3c..966a71f3 100644 --- a/docs/src/tutorials/minimum_thermal_compliance.md +++ b/docs/src/tutorials/minimum_thermal_compliance.md @@ -3,7 +3,7 @@ The goal of this tutorial is to learn - How to formulate a topology optimisation problem - How to describe the problem over a fixed computational domain ``D`` via the level-set method. -- How to setup and solve the problem in LevelSetTopOpt +- How to setup and solve the problem in GridapTopOpt We consider the following extensions at the end of the tutorial: - How to extend problems to 3D and utilise PETSc solvers @@ -63,7 +63,7 @@ For this tutorial, we consider minimising the thermal compliance (or dissipated \right. \end{aligned} ``` -where ``\operatorname{Vol}(\Omega)=\int_\Omega1~\mathrm{d}\boldsymbol{x}``. This objective is equivalent to equivalent to maximising the heat transfer efficiency through ``\Omega``. +where ``\operatorname{Vol}(\Omega)=\int_\Omega1~\mathrm{d}\boldsymbol{x}``. This objective is equivalent to equivalent to maximising the heat transfer efficiency through ``\Omega``. ## Shape differentiation @@ -74,7 +74,7 @@ Suppose that we consider smooth variations of the domain ``\Omega`` of the form !!! note "Definition [3]" The shape derivative of ``J(\Omega)`` at ``\Omega`` is defined as the Fréchet derivative in ``W^{1, \infty}(\mathbb{R}^d, \mathbb{R}^d)`` at ``\boldsymbol{\theta}`` of the application ``\boldsymbol{\theta} \rightarrow J(\Omega_{\boldsymbol{\theta}})``, i.e., ```math - J(\Omega_{\boldsymbol{\theta}})(\Omega)=J(\Omega)+J^{\prime}(\Omega)(\boldsymbol{\theta})+\mathrm{o}(\boldsymbol{\theta}) + J(\Omega_{\boldsymbol{\theta}})(\Omega)=J(\Omega)+J^{\prime}(\Omega)(\boldsymbol{\theta})+\mathrm{o}(\boldsymbol{\theta}) ``` with ``\lim _{\boldsymbol{\theta} \rightarrow 0} \frac{\lvert\mathrm{o}(\boldsymbol{\theta})\rvert}{\|\boldsymbol{\theta}\|}=0,`` where the shape derivative ``J^{\prime}(\Omega)`` is a continuous linear form on ``W^{1, \infty}(\mathbb{R}^d, \mathbb{R}^d)`` @@ -97,7 +97,7 @@ and \operatorname{Vol}'(\Omega)(-q\boldsymbol{n}) = -\int_{\Gamma}q~\mathrm{d}s. ``` -## Discretisation via a level set +## Discretisation via a level set Suppose that we attribute a level set function ``\varphi:D\rightarrow\mathbb{R}`` to our domain ``\Omega\subset D`` with ``\bar{\Omega}=\lbrace \boldsymbol{x}:\varphi(\boldsymbol{x})\leq0\rbrace`` and ``\Omega^\complement=\lbrace \boldsymbol{x}:\varphi(\boldsymbol{x})>0\rbrace``. We can then define a smooth characteristic function ``I:\mathbb{R}\rightarrow[\epsilon,1]`` as ``I(\varphi)=(1-H(\varphi))+\epsilon H(\varphi)`` where ``H`` is a smoothed Heaviside function with smoothing radius ``\eta``, and ``\epsilon\ll1`` allows for an ersatz material approximation. Of course, ``\epsilon`` can be taken as zero depending on the computational regime. Over the fixed computational domain we may relax integrals to be over all of ``D`` via ``\mathrm{d}\boldsymbol{x}= H(\varphi)~\mathrm{d}\boldsymbol{x}`` and ``\mathrm{d}s = H'(\varphi)\lvert\nabla\varphi\rvert~\mathrm{d}\boldsymbol{x}``. The above optimisation problem then rewrites in terms of ``\varphi`` as @@ -122,14 +122,14 @@ C(\varphi)&=\int_D (\rho(\varphi) - V_f)/\operatorname{Vol}(D)~\mathrm{d}\boldsy &=\int_D \rho(\varphi)~\mathrm{d}\boldsymbol{x}/\operatorname{Vol}(D) - V_f\\ &=\int_\Omega~\mathrm{d}\boldsymbol{x}/\operatorname{Vol}(D)-V_f = \operatorname{Vol}(\Omega)/\operatorname{Vol}(D)-V_f \end{aligned} -``` +``` where ``\rho(\varphi)=1-H(\varphi)`` is the smoothed volume density function. !!! note - In LevelSetTopOpt we assume constraints are of the integral form above. + In GridapTopOpt we assume constraints are of the integral form above. -The shape derivatives from the previous section can be relaxed over the computational domain as +The shape derivatives from the previous section can be relaxed over the computational domain as ```math J'(\varphi)(-q\boldsymbol{n}) = \int_{D}q\kappa\boldsymbol{\nabla}(u)\cdot\boldsymbol{\nabla}(u)H'(\varphi)\lvert\nabla\varphi\rvert~\mathrm{d}\boldsymbol{x} @@ -141,16 +141,16 @@ C'(\varphi)(-q\boldsymbol{n}) = -\int_{D}qH'(\varphi)\lvert\nabla\varphi\rvert~\ ## Computational method -In the following, we discuss the implementation of the above optimisation problem in LevelSetTopOpt. For the purpose of this tutorial we break the computational formulation into chunks. +In the following, we discuss the implementation of the above optimisation problem in GridapTopOpt. For the purpose of this tutorial we break the computational formulation into chunks. The first step in creating our script is to load any packages required: ```julia -using LevelSetTopOpt, Gridap +using GridapTopOpt, Gridap ``` ### Parameters -The following are user defined parameters for the problem. -These parameters will be discussed over the course of this tutorial. +The following are user defined parameters for the problem. +These parameters will be discussed over the course of this tutorial. ```julia # FE parameters @@ -199,7 +199,7 @@ dΓ_N = Measure(Γ_N,2*order) ``` where `2*order` indicates the quadrature degree for numerical integration. -The final stage of the finite element setup is the approximation of the finite element spaces. This is given as follows: +The final stage of the finite element setup is the approximation of the finite element spaces. This is given as follows: ```julia # Spaces reffe = ReferenceFE(lagrangian,Float64,order) @@ -223,7 +223,7 @@ For this problem we set `lsf_func` using the function [`initial_lsf`](@ref) in t ```math \varphi_{\xi,a}(\boldsymbol{x})=-\frac{1}{4} \prod_i^D(\cos(\xi\pi x_i)) - a/4 ``` -with ``\xi,a=(4,0.2)`` and ``D=2`` in two dimensions. +with ``\xi,a=(4,0.2)`` and ``D=2`` in two dimensions. We also generate a smooth characteristic function of radius ``\eta`` using: @@ -238,7 +238,7 @@ This the [`SmoothErsatzMaterialInterpolation`](@ref) structure defines the chara |:--:| |Figure 2: A visualisation of the initial level set function and the interpolated density function ``\rho`` for ``\Omega``.| -Optional: we can generate a VTK file for visualisation in Paraview via +Optional: we can generate a VTK file for visualisation in Paraview via ```julia writevtk(Ω,"initial_lsf",cellfields=["phi"=>φh, "ρ(phi)"=>(ρ ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh))]) @@ -292,17 +292,17 @@ In this case, the analytic shape derivatives are passed as optional arguments. W ### Velocity extension-regularisation method -The Hilbertian extension-regularisation [4] method involves solving an -identification problem over a Hilbert space ``H`` on ``D`` with -inner product ``\langle\cdot,\cdot\rangle_H``: +The Hilbertian extension-regularisation [4] method involves solving an +identification problem over a Hilbert space ``H`` on ``D`` with +inner product ``\langle\cdot,\cdot\rangle_H``: *Find* ``g_\Omega\in H`` *such that* ``\langle g_\Omega,q\rangle_H =-J^{\prime}(\Omega)(q\boldsymbol{n})~ \forall q\in H.`` -This provides two benefits: - 1) It naturally extends the shape sensitivity from ``\partial\Omega`` +This provides two benefits: + 1) It naturally extends the shape sensitivity from ``\partial\Omega`` onto the bounding domain ``D``; and - 2) ensures a descent direction for ``J(\Omega)`` with additional regularity + 2) ensures a descent direction for ``J(\Omega)`` with additional regularity (i.e., ``H`` as opposed to ``L^2(\partial\Omega)``). For our problem above we take the inner product @@ -317,7 +317,7 @@ where ``\alpha`` is the smoothing length scale. Equivalently in our script we ha a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ ``` -We then build an object [`VelocityExtension`](@ref). This object provides a method [`project!`](@ref) that applies the Hilbertian velocity-extension method to a given shape derivative. +We then build an object [`VelocityExtension`](@ref). This object provides a method [`project!`](@ref) that applies the Hilbertian velocity-extension method to a given shape derivative. ```julia vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) @@ -360,7 +360,7 @@ We may now create the optimiser object. This structure holds all information reg optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=true,constraint_names=[:Vol]) ``` -As optimisers inheriting from [`LevelSetTopOpt.Optimiser`](@ref) implement Julia's iterator functionality, we can solve the optimisation problem to convergence by iterating over the optimiser: +As optimisers inheriting from [`GridapTopOpt.Optimiser`](@ref) implement Julia's iterator functionality, we can solve the optimisation problem to convergence by iterating over the optimiser: ```julia # Solve @@ -379,7 +379,7 @@ end ``` !!! warning - Due to a possible memory leak in Julia 1.9.* IO, we include a call to the garbage collector using `GC.gc()`. + Due to a possible memory leak in Julia 1.9.* IO, we include a call to the garbage collector using `GC.gc()`. Depending on whether we use `iszero(it % iter_mod)`, the VTK file for the final structure may need to be saved using @@ -398,7 +398,7 @@ writevtk(Ω,path*"_$it",cellfields=["phi"=>φh, ``` ```julia -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt # FE parameters order = 1 # Finite element order @@ -504,7 +504,7 @@ The first and most straightforward in terms of programmatic changes is extending |:--:| |Figure 4: The setup for the three-dimensional minimum thermal compliance problem.| -We use a unit cube for the bounding domain ``D`` with ``50^3`` elements. This corresponds to changing lines 5-7 in the above script to +We use a unit cube for the bounding domain ``D`` with ``50^3`` elements. This corresponds to changing lines 5-7 in the above script to ```julia xmax=ymax=zmax=1.0 # Domain size @@ -539,7 +539,7 @@ tol = 1/(2order^2)/minimum(el_size) # Advection tolerance ``` ```julia -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt # FE parameters order = 1 # Finite element order @@ -623,10 +623,10 @@ writevtk(Ω,path*"struc_$it",cellfields=["phi"=>φh, ``` -At this stage the problem will not be possible to run as we're using a standard LU solver. For this reason we now consider adjusting Script 2 to use an iterative solver provided by PETSc. We rely on the GridapPETSc satellite package to utilise PETSc. This provides the necessary structures to efficiently interface with the linear and nonlinear solvers provided by the PETSc library. To call GridapPETSc we change line 1 of Script 2 to +At this stage the problem will not be possible to run as we're using a standard LU solver. For this reason we now consider adjusting Script 2 to use an iterative solver provided by PETSc. We rely on the GridapPETSc satellite package to utilise PETSc. This provides the necessary structures to efficiently interface with the linear and nonlinear solvers provided by the PETSc library. To call GridapPETSc we change line 1 of Script 2 to ```julia -using Gridap, GridapPETSc, SparseMatricesCSR, LevelSetTopOpt +using Gridap, GridapPETSc, SparseMatricesCSR, GridapTopOpt ``` We also use `SparseMatricesCSR` as PETSc is based on the `SparseMatrixCSR` datatype. We then replace line 52 and 63 with @@ -655,13 +655,13 @@ respectively. Here we specify that the `SparseMatrixAssembler` should be based o Finally, we wrap the entire script in a function and call it inside a `GridapPETSc.with` block. This ensures that PETSc is safely initialised. This should take the form ```Julia -using Gridap, GridapPETSc, SparseMatricesCSR, LevelSetTopOpt +using Gridap, GridapPETSc, SparseMatricesCSR, GridapTopOpt function main() ... end -solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true +solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do main() @@ -675,7 +675,7 @@ We utilise a conjugate gradient method with geometric algebraic multigrid precon ``` ```julia -using Gridap, GridapPETSc, SparseMatricesCSR, LevelSetTopOpt +using Gridap, GridapPETSc, SparseMatricesCSR, GridapTopOpt function main() # FE parameters @@ -769,7 +769,7 @@ function main() "H(phi)"=>(H ∘ φh),"|nabla(phi)|"=>(norm ∘ ∇(φh)),"uh"=>uh]) end -solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true +solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do main() @@ -788,10 +788,10 @@ We can run this script and visualise the initial and final structures using Para ### Serial to MPI -Script 3 contains no parallelism to enable further speedup or scalability. To enable MPI-based computing we rely on the tools implemented in PartitionedArrays and GridapDistributed. Further information regarding these packages and how they interface with LevelSetTopOpt can be found [here](../usage/mpi-mode.md). To add these packages we adjust the first line of our script: +Script 3 contains no parallelism to enable further speedup or scalability. To enable MPI-based computing we rely on the tools implemented in PartitionedArrays and GridapDistributed. Further information regarding these packages and how they interface with GridapTopOpt can be found [here](../usage/mpi-mode.md). To add these packages we adjust the first line of our script: ```julia -using Gridap, GridapPETSc, GridapDistributed, PartitionedArrays, SparseMatricesCSR, LevelSetTopOpt +using Gridap, GridapPETSc, GridapDistributed, PartitionedArrays, SparseMatricesCSR, GridapTopOpt ``` Before we change any parts of the function `main`, we adjust the end of the script to safely launch MPI inside a Julia `do` block. We replace lines 95-99 in Script 3 with @@ -799,7 +799,7 @@ Before we change any parts of the function `main`, we adjust the end of the scri ```julia with_mpi() do distribute mesh_partition = (2,2,2) - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do main(mesh_partition,distribute) @@ -838,7 +838,7 @@ That's it! These are the only changes that are necessary to run your application ``` ```julia -using Gridap, GridapPETSc, GridapDistributed, PartitionedArrays, SparseMatricesCSR, LevelSetTopOpt +using Gridap, GridapPETSc, GridapDistributed, PartitionedArrays, SparseMatricesCSR, GridapTopOpt function main(mesh_partition,distribute) ranks = distribute(LinearIndices((prod(mesh_partition),))) @@ -936,7 +936,7 @@ end with_mpi() do distribute mesh_partition = (2,2,2) - solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + solver_options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" GridapPETSc.with(args=split(solver_options)) do main(mesh_partition,distribute) @@ -980,7 +980,7 @@ As we're considering a 2D problem, we consider modifications of Script 1 as foll κ(u) = exp(-u) # Diffusivity ``` -We then replace the `a` and `l` on line 48 and 49 by the residual `R` given by +We then replace the `a` and `l` on line 48 and 49 by the residual `R` given by ```julia R(u,v,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(v))dΩ - ∫(g*v)dΓ_N ``` @@ -991,7 +991,7 @@ state_map = NonlinearFEStateMap(R,U,V,V_φ,U_reg,φh,dΩ,dΓ_N) ``` This by default implements a standard `NewtonSolver` from GridapSolvers while utilising an LU solver for intermediate linear solves involving the Jacobian. As with other `FEStateMap` types, this constructor can optionally take assemblers and different solvers (e.g., PETSc solvers). -Next, we replace the objective functional on line 52 with +Next, we replace the objective functional on line 52 with ```julia J(u,φ,dΩ,dΓ_N) = ∫((I ∘ φ)*(κ ∘ u)*∇(u)⋅∇(u))dΩ @@ -1009,7 +1009,7 @@ Notice that the argument `analytic_dJ=...` has been removed, this enables the AD ``` ```julia -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt # FE parameters order = 1 # Finite element order @@ -1103,11 +1103,11 @@ A 3D example of a nonlinear thermal conductivity problem can be found under `scr ## References > 1. *Z. Guo, X. Cheng, and Z. Xia. Least dissipation principle of heat transport potential capacity and its application in heat conduction optimization. Chinese Science Bulletin, 48(4):406–410, Feb 2003. ISSN 1861-9541. doi: 10.1007/BF03183239.* -> +> > 2. *C. Zhuang, Z. Xiong, and H. Ding. A level set method for topology optimization of heat conduction problem under multiple load cases. Computer Methods in Applied Mechanics and Engineering, 196(4–6):1074–1084, Jan 2007. ISSN 00457825. doi: 10.1016/j.cma.2006.08.005.* > > 3. *Allaire G, Jouve F, Toader AM (2004) Structural optimization using sensitivity analysis and a level-set method. Journal of Computational Physics 194(1):363–393. doi: 10.1016/j.jcp.2003.09.032* -> +> > 4. *Allaire G, Dapogny C, Jouve F (2021) Shape and topology optimization, vol 22, Elsevier, p 1–132. doi: 10.1016/bs.hna.2020.10.004* > > 5. *Osher S, Fedkiw R (2006) Level Set Methods and Dynamic Implicit Surfaces, 1st edn. Applied Mathematical Sciences, Springer Science & Business Media. doi: 10.1007/b98879* diff --git a/scripts/Benchmarks/benchmark.jl b/scripts/Benchmarks/benchmark.jl index c3dc701c..c31d395c 100644 --- a/scripts/Benchmarks/benchmark.jl +++ b/scripts/Benchmarks/benchmark.jl @@ -1,7 +1,7 @@ -using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, + PartitionedArrays, GridapTopOpt, SparseMatricesCSR -using LevelSetTopOpt: get_deriv_space, get_aux_space,benchmark_optimizer, +using GridapTopOpt: get_deriv_space, get_aux_space,benchmark_optimizer, benchmark_forward_problem,benchmark_advection,benchmark_reinitialisation, benchmark_velocity_extension,benchmark_hilbertian_projection_map,benchmark_single_iteration @@ -75,7 +75,7 @@ function nl_elast(mesh_partition,ranks,el_size,order,verbose) F(∇u) = one(∇u) + ∇u' ## Volume change J(F) = sqrt(det(C(F))) - ## Residual + ## Residual res(u,v,φ,dΩ,dΓ_N) = ∫( (I ∘ φ)*((dE ∘ (∇(v),∇(u))) ⊙ (S ∘ ∇(u))) )*dΩ - ∫(g⋅v)dΓ_N Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} @@ -281,11 +281,11 @@ function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) ## FE Setup model = CartesianDiscreteModel(ranks,mesh_partition,dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + f_Γ_in(x) = (x[1] ≈ 0.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && + f_Γ_out(x) = (x[1] ≈ 1.0) && (0.4 - eps() <= x[2] <= 0.6 + eps()) && (0.4 - eps() <= x[3] <= 0.6 + eps()) - f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && + f_Γ_out_ext(x) = ~f_Γ_out(x) && (0.9 <= x[1] <= 1.0) && (0.3 - eps() <= x[2] <= 0.7 + eps()) && (0.3 - eps() <= x[3] <= 0.7 + eps()) f_Γ_D(x) = (x[1] ≈ 0.0) && (x[2] <= 0.1 || x[2] >= 0.9) && (x[3] <= 0.1 || x[3] >= 0.9) update_labels!(1,model,f_Γ_in,"Gamma_in") @@ -337,7 +337,7 @@ function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) Tm = SparseMatrixCSR{0,PetscScalar,PetscInt} Tv = Vector{PetscScalar} solver = ElasticitySolver(V) - + state_map = AffineFEStateMap( a,l,U,V,V_φ,U_reg,φh,dΩ,dΓ_in,dΓ_out; assem_U = SparseMatrixAssembler(Tm,Tv,U,V), @@ -355,7 +355,7 @@ function inverter_HPM(mesh_partition,ranks,el_size,order,verbose) assem = SparseMatrixAssembler(Tm,Tv,U_reg,V_reg), ls = PETScLinearSolver() ) - + ## Optimiser return HilbertianProjection(pcfs,ls_evo,vel_ext,φh;γ,γ_reinit,verbose=verbose) end @@ -365,21 +365,21 @@ with_mpi() do distribute mesh_partition = (Nx,Ny,Nz) ranks = distribute(LinearIndices((prod(mesh_partition),))) el_size = (N_EL,N_EL,N_EL) - verbose = Bool(VERBOSE) ? i_am_main(ranks) : false; + verbose = Bool(VERBOSE) ? i_am_main(ranks) : false; if PROB_TYPE == "NLELAST" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" opt = nl_elast - elseif PROB_TYPE == "THERM" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + elseif PROB_TYPE == "THERM" + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" opt = therm elseif PROB_TYPE == "ELAST" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" opt = elast elseif PROB_TYPE == "INVERTER_HPM" - options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true + options = "-pc_type gamg -ksp_type cg -ksp_error_if_not_converged true -ksp_converged_reason -ksp_rtol 1.0e-12" opt = inverter_HPM else @@ -439,7 +439,7 @@ with_mpi() do distribute end ## HPM if occursin("bhpm",BMARK_TYPE) - @assert typeof(optim) <: HilbertianProjection + @assert typeof(optim) <: HilbertianProjection J, C, dJ, dC = Gridap.evaluate!(optim.problem,optim.φ0) optim.projector,dJ,C,dC,optim.vel_ext.K bhpm = benchmark_hilbertian_projection_map(optim.projector,dJ,C,dC,optim.vel_ext.K,ranks) diff --git a/scripts/Benchmarks/generate_benchmark_scripts.jl b/scripts/Benchmarks/generate_benchmark_scripts.jl index f142b86b..071177a4 100644 --- a/scripts/Benchmarks/generate_benchmark_scripts.jl +++ b/scripts/Benchmarks/generate_benchmark_scripts.jl @@ -34,11 +34,11 @@ function generate( ) ncpus = prod(mesh_partition) - wallhr = occursin("STRONG",name) && ncpus == 1 ? 100 : - occursin("STRONG",name) && ncpus == 8 ? 24 : + wallhr = occursin("STRONG",name) && ncpus == 1 ? 100 : + occursin("STRONG",name) && ncpus == 8 ? 24 : occursin("STRONG",name) && ncpus == 27 ? 10 : wallhr - mem = occursin("STRONG",name) && ncpus == 1 ? 100 : - occursin("STRONG",name) && ncpus == 8 ? 128 : + mem = occursin("STRONG",name) && ncpus == 1 ? 100 : + occursin("STRONG",name) && ncpus == 8 ? 128 : occursin("STRONG",name) && ncpus == 27 ? 192 : Int(gb_per_node*ncpus/cps_per_node); Nx_partition, Ny_partition, Nz_partition = mesh_partition @@ -68,7 +68,7 @@ function generate_jobs(template,phys_type,ndof_per_node,bmark_types) strong_jobs,weak_jobs,dof_sanity_check end -dir_name= "LevelSetTopOpt"; +dir_name= "GridapTopOpt"; job_output_path = "$(ENV["SCRATCH"])/$dir_name/scripts/Benchmarks/jobs-gadi/"; mkpath(job_output_path); @@ -103,7 +103,7 @@ jobs_by_phys = map(x->(x[1],generate_jobs(template,x[1],x[2],x[3])),phys_types); for jobs in jobs_by_phys strong_jobs,weak_jobs,dof_sanity_check = jobs[2] - + println("$(jobs[1]): Weak dofs = $(dof_sanity_check[1])\n Error = $(dof_sanity_check[2])\n") for job in vcat(strong_jobs,weak_jobs) name = job[1] diff --git a/scripts/MPI/3d_elastic_compliance_ALM.jl b/scripts/MPI/3d_elastic_compliance_ALM.jl index cb221837..a5ff5c02 100644 --- a/scripts/MPI/3d_elastic_compliance_ALM.jl +++ b/scripts/MPI/3d_elastic_compliance_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global elx = parse(Int,ARGS[1]) global ely = parse(Int,ARGS[2]) diff --git a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl index fe6d8f61..35836c01 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR using GridapSolvers: NewtonSolver diff --git a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl index 7d781947..a8c8b110 100644 --- a/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/MPI/3d_hyperelastic_compliance_neohook_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR using GridapSolvers: NewtonSolver diff --git a/scripts/MPI/3d_inverse_homenisation_ALM.jl b/scripts/MPI/3d_inverse_homenisation_ALM.jl index 087372b4..359a1cf2 100644 --- a/scripts/MPI/3d_inverse_homenisation_ALM.jl +++ b/scripts/MPI/3d_inverse_homenisation_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global elx = parse(Int,ARGS[1]) global ely = parse(Int,ARGS[2]) diff --git a/scripts/MPI/3d_inverter_ALM.jl b/scripts/MPI/3d_inverter_ALM.jl index aa7fb6fd..93b4a36b 100644 --- a/scripts/MPI/3d_inverter_ALM.jl +++ b/scripts/MPI/3d_inverter_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global elx = parse(Int,ARGS[1]) global ely = parse(Int,ARGS[2]) diff --git a/scripts/MPI/3d_inverter_HPM.jl b/scripts/MPI/3d_inverter_HPM.jl index 681450d0..ccaf8dcd 100644 --- a/scripts/MPI/3d_inverter_HPM.jl +++ b/scripts/MPI/3d_inverter_HPM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global elx = parse(Int,ARGS[1]) global ely = parse(Int,ARGS[2]) diff --git a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl index 08bcb6f2..dd6a0503 100644 --- a/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_nonlinear_thermal_compliance_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR using GridapSolvers: NewtonSolver diff --git a/scripts/MPI/3d_thermal_compliance_ALM.jl b/scripts/MPI/3d_thermal_compliance_ALM.jl index 4bf81ede..2b238351 100644 --- a/scripts/MPI/3d_thermal_compliance_ALM.jl +++ b/scripts/MPI/3d_thermal_compliance_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global elx = parse(Int,ARGS[1]) global ely = parse(Int,ARGS[2]) diff --git a/scripts/MPI/elastic_compliance_ALM.jl b/scripts/MPI/elastic_compliance_ALM.jl index 2c434df7..2cdafccf 100644 --- a/scripts/MPI/elastic_compliance_ALM.jl +++ b/scripts/MPI/elastic_compliance_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global write_dir = ARGS[1] diff --git a/scripts/MPI/inverse_homenisation_ALM.jl b/scripts/MPI/inverse_homenisation_ALM.jl index 032e93c8..5946f589 100644 --- a/scripts/MPI/inverse_homenisation_ALM.jl +++ b/scripts/MPI/inverse_homenisation_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global write_dir = ARGS[1] diff --git a/scripts/MPI/nonlinear_thermal_compliance_ALM.jl b/scripts/MPI/nonlinear_thermal_compliance_ALM.jl index ceb760da..beccd0e9 100644 --- a/scripts/MPI/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/MPI/nonlinear_thermal_compliance_ALM.jl @@ -1,5 +1,5 @@ using Gridap, Gridap.MultiField, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global write_dir = ARGS[1] diff --git a/scripts/MPI/thermal_compliance_ALM.jl b/scripts/MPI/thermal_compliance_ALM.jl index a90225d5..9c78fbb1 100644 --- a/scripts/MPI/thermal_compliance_ALM.jl +++ b/scripts/MPI/thermal_compliance_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, LevelSetTopOpt +using Gridap, GridapDistributed, GridapPETSc, PartitionedArrays, GridapTopOpt global write_dir = ARGS[1] diff --git a/scripts/MPI/thermal_compliance_ALM_PETSc.jl b/scripts/MPI/thermal_compliance_ALM_PETSc.jl index 0344f063..9248276f 100644 --- a/scripts/MPI/thermal_compliance_ALM_PETSc.jl +++ b/scripts/MPI/thermal_compliance_ALM_PETSc.jl @@ -1,5 +1,5 @@ using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR + PartitionedArrays, GridapTopOpt, SparseMatricesCSR global write_dir = ARGS[1] diff --git a/scripts/Serial/elastic_compliance_ALM.jl b/scripts/Serial/elastic_compliance_ALM.jl index 25c7aeb7..9f0b7024 100644 --- a/scripts/Serial/elastic_compliance_ALM.jl +++ b/scripts/Serial/elastic_compliance_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum elastic compliance with augmented Lagrangian method in 2D. diff --git a/scripts/Serial/elastic_compliance_HPM.jl b/scripts/Serial/elastic_compliance_HPM.jl index 14e734fe..9f787c30 100644 --- a/scripts/Serial/elastic_compliance_HPM.jl +++ b/scripts/Serial/elastic_compliance_HPM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum elastic compliance with Hilbertian projection method in 2D. diff --git a/scripts/Serial/elastic_compliance_LM.jl b/scripts/Serial/elastic_compliance_LM.jl index 135cccd8..b09e501c 100644 --- a/scripts/Serial/elastic_compliance_LM.jl +++ b/scripts/Serial/elastic_compliance_LM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum elastic compliance with Lagrangian method in 2D. diff --git a/scripts/Serial/hyperelastic_compliance_ALM.jl b/scripts/Serial/hyperelastic_compliance_ALM.jl index e3f15cfd..dce96bd5 100644 --- a/scripts/Serial/hyperelastic_compliance_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum hyperelastic compliance with augmented Lagrangian method in 2D. diff --git a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl index d6ae9163..eca9d1ce 100644 --- a/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl +++ b/scripts/Serial/hyperelastic_compliance_neohook_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum hyperelastic (neohookean) compliance with augmented Lagrangian method in 2D. diff --git a/scripts/Serial/inverse_homenisation_ALM.jl b/scripts/Serial/inverse_homenisation_ALM.jl index d06b2d47..972d4328 100644 --- a/scripts/Serial/inverse_homenisation_ALM.jl +++ b/scripts/Serial/inverse_homenisation_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 2D. diff --git a/scripts/Serial/inverter_ALM.jl b/scripts/Serial/inverter_ALM.jl index f9a8e3be..ad2d8786 100644 --- a/scripts/Serial/inverter_ALM.jl +++ b/scripts/Serial/inverter_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Inverter mechanism with Hilbertian projection method in 2D. diff --git a/scripts/Serial/inverter_HPM.jl b/scripts/Serial/inverter_HPM.jl index 2274a2f4..fbe13122 100644 --- a/scripts/Serial/inverter_HPM.jl +++ b/scripts/Serial/inverter_HPM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Inverter mechanism with Hilbertian projection method in 2D. diff --git a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl index 16ffa9b4..2bf32486 100644 --- a/scripts/Serial/nonlinear_thermal_compliance_ALM.jl +++ b/scripts/Serial/nonlinear_thermal_compliance_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D with nonlinear diffusivity. diff --git a/scripts/Serial/thermal_compliance_ALM.jl b/scripts/Serial/thermal_compliance_ALM.jl index 1201db0d..aaf45b24 100644 --- a/scripts/Serial/thermal_compliance_ALM.jl +++ b/scripts/Serial/thermal_compliance_ALM.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D. diff --git a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl index 3db4ea46..51f8e1a1 100644 --- a/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl +++ b/scripts/Serial/thermal_compliance_ALM_higherorderlsf.jl @@ -1,4 +1,4 @@ -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D. diff --git a/src/ChainRules.jl b/src/ChainRules.jl index 501c4f7b..361f8daa 100644 --- a/src/ChainRules.jl +++ b/src/ChainRules.jl @@ -1,8 +1,8 @@ """ struct IntegrandWithMeasure{A,B<:Tuple} -A wrapper to enable serial or parallel partial differentation of an -integral `F` using `Gridap.gradient`. This is required to allow automatic +A wrapper to enable serial or parallel partial differentation of an +integral `F` using `Gridap.gradient`. This is required to allow automatic differentation with `DistributedMeasure`. # Properties @@ -30,13 +30,13 @@ evaluate the partial derivative of `F.F` with respect to `uh[K]`. # Example Suppose `uh` and `φh` are FEFunctions with measures `dΩ` and `dΓ_N`. -Then the partial derivative of a function `J` wrt to `φh` is computed via +Then the partial derivative of a function `J` wrt to `φh` is computed via ```` J(u,φ,dΩ,dΓ_N) = ∫(f(u,φ))dΩ + ∫(g(u,φ))dΓ_N J_iwm = IntegrandWithMeasure(J,(dΩ,dΓ_N)) ∂J∂φh = ∇(J_iwm,[uh,φh],2) ```` -where `f` and `g` are user defined. +where `f` and `g` are user defined. """ function Gridap.gradient(F::IntegrandWithMeasure,uh::Vector{<:FEFunction},K::Int) @check 0 < K <= length(uh) @@ -49,8 +49,8 @@ function Gridap.gradient(F::IntegrandWithMeasure,uh::Vector,K::Int) local_fields = map(local_views,uh) |> to_parray_of_arrays local_measures = map(local_views,F.dΩ) |> to_parray_of_arrays contribs = map(local_measures,local_fields) do dΩ,lf - # TODO: Remove second term below, this is a fix for the problem discussed in - # https://github.com/zjwegert/LSTO_Distributed/issues/46 + # TODO: Remove second term below, this is a fix for the problem discussed in + # https://github.com/zjwegert/GridapTopOpt/issues/46 _f = u -> F.F(lf[1:K-1]...,u,lf[K+1:end]...,dΩ...) #+ ∑(∫(0)dΩ[i] for i = 1:length(dΩ)) return Gridap.Fields.gradient(_f,lf[K]) end @@ -62,7 +62,7 @@ Gridap.gradient(F::IntegrandWithMeasure,uh) = Gridap.gradient(F,[uh],1) """ Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector,K::Int) -Given an an `IntegrandWithMeasure` `F` and a vector of `FEFunctions` or `CellField` `uh` +Given an an `IntegrandWithMeasure` `F` and a vector of `FEFunctions` or `CellField` `uh` (excluding measures) evaluate the Jacobian `F.F` with respect to `uh[K]`. """ function Gridap.jacobian(F::IntegrandWithMeasure,uh::Vector{<:Union{FEFunction,CellField}},K::Int) @@ -93,7 +93,7 @@ function GridapDistributed.to_parray_of_arrays(a::NTuple{N,T}) where {N,T<:Debug aj.items[i] end end -end +end function GridapDistributed.to_parray_of_arrays(a::NTuple{N,T}) where {N,T<:MPIArray} indices = linear_indices(first(a)) @@ -130,7 +130,7 @@ end StateParamIntegrandWithMeasure(F::IntegrandWithMeasure,U::FESpace,V_φ::FESpace, U_reg::FESpace,assem_U::Assembler,assem_deriv::Assembler) -Create an instance of `StateParamIntegrandWithMeasure`. +Create an instance of `StateParamIntegrandWithMeasure`. """ function StateParamIntegrandWithMeasure( F::IntegrandWithMeasure, @@ -151,7 +151,7 @@ end """ (u_to_j::StateParamIntegrandWithMeasure)(uh,φh) -Evaluate the `StateParamIntegrandWithMeasure` at parameters `uh` and `φh`. +Evaluate the `StateParamIntegrandWithMeasure` at parameters `uh` and `φh`. """ (u_to_j::StateParamIntegrandWithMeasure)(uh,φh) = sum(u_to_j.F(uh,φh)) @@ -165,7 +165,7 @@ end """ ChainRulesCore.rrule(u_to_j::StateParamIntegrandWithMeasure,uh,φh) -Return the evaluation of a `StateParamIntegrandWithMeasure` and a +Return the evaluation of a `StateParamIntegrandWithMeasure` and a a function for evaluating the pullback of `u_to_j`. This enables compatiblity with `ChainRules.jl` """ @@ -200,7 +200,7 @@ end """ abstract type AbstractFEStateMap -Types inheriting from this abstract type should enable the evaluation and differentiation of +Types inheriting from this abstract type should enable the evaluation and differentiation of the solution to an FE problem `u` that implicitly depends on an auxiliary parameter `φ`. """ abstract type AbstractFEStateMap end @@ -208,7 +208,7 @@ abstract type AbstractFEStateMap end """ get_state(m::AbstractFEStateMap) -Return the solution/state `u` to the FE problem. +Return the solution/state `u` to the FE problem. """ get_state(::AbstractFEStateMap) = @abstractmethod @@ -222,7 +222,7 @@ get_measure(::AbstractFEStateMap) = @abstractmethod """ get_spaces(m::AbstractFEStateMap) -Return a collection of FE spaces. The first four entires should correspond to +Return a collection of FE spaces. The first four entires should correspond to [`get_trial_space`](@ref), [`get_test_space`](@ref), [`get_aux_space`](@ref), and [`get_deriv_space`](@ref) unless these are overloaded for a particular implementation. """ @@ -231,8 +231,8 @@ get_spaces(::AbstractFEStateMap) = @abstractmethod """ get_assemblers(m::AbstractFEStateMap) -Return a collection of assemblers. The first two entires should correspond to -[`get_pde_assembler`](@ref) and [`get_deriv_assembler`](@ref) unless these are +Return a collection of assemblers. The first two entires should correspond to +[`get_pde_assembler`](@ref) and [`get_deriv_assembler`](@ref) unless these are overloaded for a particular implementation. """ get_assemblers(::AbstractFEStateMap) = @abstractmethod @@ -326,7 +326,7 @@ This should solve the linear problem `dRduᵀ*λ = ∂F∂uᵀ`. """ function adjoint_solve!(φ_to_u::AbstractFEStateMap,du::AbstractVector) @abstractmethod -end +end """ dRdφ(φ_to_u::AbstractFEStateMap,uh,vh,φh) @@ -347,7 +347,7 @@ end """ pullback(φ_to_u::AbstractFEStateMap,uh,φh,du;updated) -Compute `∂F∂u*dudφ` at `φh` and `uh` using the adjoint method. I.e., let +Compute `∂F∂u*dudφ` at `φh` and `uh` using the adjoint method. I.e., let `∂F∂u*dudφ = -λᵀ*dRdφ` @@ -365,10 +365,10 @@ function pullback(φ_to_u::AbstractFEStateMap,uh,φh,du;updated=false) λh = FEFunction(get_test_space(φ_to_u),λ) ## Compute grad - dudφ_vecdata = collect_cell_vector(U_reg,dRdφ(φ_to_u,uh,λh,φh)) + dudφ_vecdata = collect_cell_vector(U_reg,dRdφ(φ_to_u,uh,λh,φh)) assemble_vector!(dudφ_vec,assem_deriv,dudφ_vecdata) rmul!(dudφ_vec, -1) - + return (NoTangent(),dudφ_vec) end @@ -381,7 +381,7 @@ end """ rrule(φ_to_u::AbstractFEStateMap,φh) -Return the evaluation of a `AbstractFEStateMap` and a +Return the evaluation of a `AbstractFEStateMap` and a a function for evaluating the pullback of `φ_to_u`. This enables compatiblity with `ChainRules.jl` """ @@ -452,7 +452,7 @@ struct AffineFEStateMap{A,B,C,D,E,F} <: AbstractFEStateMap Create an instance of `AffineFEStateMap` given the bilinear form `a` and linear form `l` as `Function` types, trial and test spaces `U` and `V`, the FE space `V_φ` - for `φh`, the FE space `U_reg` for derivatives, and the measures as additional arguments. + for `φh`, the FE space `U_reg` for derivatives, and the measures as additional arguments. Optional arguments enable specification of assemblers and linear solvers. """ @@ -567,9 +567,9 @@ struct NonlinearFEStateMap{A,B,C,D,E,F} <: AbstractFEStateMap adjoint_ls::LinearSolver = LUSolver() ) - Create an instance of `NonlinearFEStateMap` given the residual `res` as a `Function` type, - trial and test spaces `U` and `V`, the FE space `V_φ` for `φh`, the FE space `U_reg` - for derivatives, and the measures as additional arguments. + Create an instance of `NonlinearFEStateMap` given the residual `res` as a `Function` type, + trial and test spaces `U` and `V`, the FE space `V_φ` for `φh`, the FE space `U_reg` + for derivatives, and the measures as additional arguments. Optional arguments enable specification of assemblers, nonlinear solver, and adjoint (linear) solver. """ @@ -605,7 +605,7 @@ struct NonlinearFEStateMap{A,B,C,D,E,F} <: AbstractFEStateMap adjoint_x = allocate_in_domain(adjoint_K); fill!(adjoint_x,zero(eltype(adjoint_x))) adjoint_ns = numerical_setup(symbolic_setup(adjoint_ls,adjoint_K),adjoint_K) adj_caches = (adjoint_ns,adjoint_K,adjoint_x,assem_adjoint) - + A, B, C = typeof(res), typeof(jac), typeof(spaces) D, E, F = typeof(plb_caches), typeof(fwd_caches), typeof(adj_caches) return new{A,B,C,D,E,F}(res,jac,spaces,plb_caches,fwd_caches,adj_caches) @@ -685,16 +685,16 @@ struct RepeatingAffineFEStateMap{A,B,C,D,E,F,G} <: AbstractFEStateMap adjoint_ls::LinearSolver = LUSolver() ) - Create an instance of `RepeatingAffineFEStateMap` given the number of blocks `nblocks`, - a bilinear form `a`, a vector of linear form `l` as `Function` types, the trial and test - spaces `U` and `V`, the FE space `V_φ` for `φh`, the FE space `U_reg` for derivatives, - and the measures as additional arguments. + Create an instance of `RepeatingAffineFEStateMap` given the number of blocks `nblocks`, + a bilinear form `a`, a vector of linear form `l` as `Function` types, the trial and test + spaces `U` and `V`, the FE space `V_φ` for `φh`, the FE space `U_reg` for derivatives, + and the measures as additional arguments. Optional arguments enable specification of assemblers and linear solvers. # Note - - The resulting `FEFunction` will be a `MultiFieldFEFunction` (or GridapDistributed equivalent) + - The resulting `FEFunction` will be a `MultiFieldFEFunction` (or GridapDistributed equivalent) where each field corresponds to an entry in the vector of linear forms """ function RepeatingAffineFEStateMap( @@ -790,7 +790,7 @@ repeated_blocks(::ConsecutiveMultiFieldStyle,V0,x::AbstractBlockVector) = blocks function repeated_blocks(::BlockMultiFieldStyle{NB},V0::MultiFieldSpaceTypes,x::AbstractBlockVector) where NB xb = blocks(x) @assert length(xb) % NB == 0 - + nblocks = length(xb) ÷ NB rep_blocks = map(1:nblocks) do iB mortar(xb[(iB-1)*NB+1:iB*NB]) @@ -875,37 +875,37 @@ end """ struct PDEConstrainedFunctionals{N,A} -An object that computes the objective, constraints, and their derivatives. +An object that computes the objective, constraints, and their derivatives. # Implementation -This implementation computes derivatives of a integral quantity +This implementation computes derivatives of a integral quantity -``F(u(\\varphi),\\varphi,\\mathrm{d}\\Omega_1,\\mathrm{d}\\Omega_2,...) = -\\Sigma_{i}\\int_{\\Omega_i} f_i(\\varphi)~\\mathrm{d}\\Omega`` +``F(u(\\varphi),\\varphi,\\mathrm{d}\\Omega_1,\\mathrm{d}\\Omega_2,...) = +\\Sigma_{i}\\int_{\\Omega_i} f_i(\\varphi)~\\mathrm{d}\\Omega`` with respect to an auxiliary parameter ``\\varphi`` where ``u`` -is the solution to a PDE and implicitly depends on ``\\varphi``. +is the solution to a PDE and implicitly depends on ``\\varphi``. This requires two pieces of information: - 1) Computation of ``\\frac{\\partial F}{\\partial u}`` and + 1) Computation of ``\\frac{\\partial F}{\\partial u}`` and ``\\frac{\\partial F}{\\partial \\varphi}`` (handled by [`StateParamIntegrandWithMeasure `](@ref)). 2) Computation of ``\\frac{\\partial F}{\\partial u} - \\frac{\\partial u}{\\partial \\varphi}`` at ``\\varphi`` and ``u`` - using the adjoint method (handled by [`AbstractFEStateMap`](@ref)). I.e., let - + \\frac{\\partial u}{\\partial \\varphi}`` at ``\\varphi`` and ``u`` + using the adjoint method (handled by [`AbstractFEStateMap`](@ref)). I.e., let + ``\\frac{\\partial F}{\\partial u} - \\frac{\\partial u}{\\partial \\varphi} = -\\lambda^\\intercal + \\frac{\\partial u}{\\partial \\varphi} = -\\lambda^\\intercal \\frac{\\partial \\mathcal{R}}{\\partial \\varphi}`` - where ``\\mathcal{R}`` is the residual and solve the (linear) adjoint + where ``\\mathcal{R}`` is the residual and solve the (linear) adjoint problem: - - ``\\frac{\\partial \\mathcal{R}}{\\partial u}^\\intercal\\lambda = + + ``\\frac{\\partial \\mathcal{R}}{\\partial u}^\\intercal\\lambda = \\frac{\\partial F}{\\partial u}^\\intercal.`` -The gradient is then ``\\frac{\\partial F}{\\partial \\varphi} = -\\frac{\\partial F}{\\partial \\varphi} - +The gradient is then ``\\frac{\\partial F}{\\partial \\varphi} = +\\frac{\\partial F}{\\partial \\varphi} - \\frac{\\partial F}{\\partial u}\\frac{\\partial u}{\\partial \\varphi}``. # Parameters @@ -938,7 +938,7 @@ struct PDEConstrainedFunctionals{N,A} Create an instance of `PDEConstrainedFunctionals`. The arguments for the objective and constraints must follow the specification in [`StateParamIntegrandWithMeasure`](@ref). - By default we use automatic differentation for the objective and all constraints. This + By default we use automatic differentation for the objective and all constraints. This can be disabled by passing the shape derivative as a type `Function` to `analytic_dJ` and/or entires in `analytic_dC`. """ @@ -952,7 +952,7 @@ struct PDEConstrainedFunctionals{N,A} # Create StateParamIntegrandWithMeasures J = StateParamIntegrandWithMeasure(objective,state_map) C = map(Ci -> StateParamIntegrandWithMeasure(Ci,state_map),constraints) - + # Preallocate dJ = similar(J.caches[2]) dC = map(Ci->similar(Ci.caches[2]),C) @@ -968,7 +968,7 @@ end Create an instance of `PDEConstrainedFunctionals` when the problem has no constraints. """ -PDEConstrainedFunctionals(J::Function,state_map::AbstractFEStateMap;analytic_dJ=nothing) = +PDEConstrainedFunctionals(J::Function,state_map::AbstractFEStateMap;analytic_dJ=nothing) = PDEConstrainedFunctionals(J,Function[],state_map;analytic_dJ = analytic_dJ,analytic_dC = Nothing[]) get_state(m::PDEConstrainedFunctionals) = get_state(m.state_map) @@ -1011,7 +1011,7 @@ end Fields.evaluate!(pcf::PDEConstrainedFunctionals,φh) Evaluate the objective and constraints, and their derivatives at -`φh`. +`φh`. """ function Fields.evaluate!(pcf::PDEConstrainedFunctionals,φh) J, C, dJ, dC = pcf.J,pcf.C,pcf.dJ,pcf.dC @@ -1031,7 +1031,7 @@ function Fields.evaluate!(pcf::PDEConstrainedFunctionals,φh) # Automatic differentation j_val, j_pullback = rrule(F,uh,φh) # Compute functional and pull back _, dFdu, dFdφ = j_pullback(1) # Compute dFdu, dFdφ - _, dφ_adj = u_pullback(dFdu) # Compute -dFdu*dudφ via adjoint + _, dφ_adj = u_pullback(dFdu) # Compute -dFdu*dudφ via adjoint copy!(dF,dφ_adj) dF .+= dFdφ return j_val diff --git a/src/LevelSetTopOpt.jl b/src/GridapTopOpt.jl similarity index 94% rename from src/LevelSetTopOpt.jl rename to src/GridapTopOpt.jl index 43f948f7..c0c0dbea 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/GridapTopOpt.jl @@ -1,4 +1,4 @@ -module LevelSetTopOpt +module GridapTopOpt using GridapPETSc, GridapPETSc.PETSC using GridapPETSc: PetscScalar, PetscInt, PETSC, @check_error_code @@ -19,7 +19,7 @@ using Gridap.FESpaces: get_assembly_strategy using Gridap: writevtk using GridapDistributed -using GridapDistributed: DistributedDiscreteModel, DistributedTriangulation, +using GridapDistributed: DistributedDiscreteModel, DistributedTriangulation, DistributedFESpace, DistributedDomainContribution, to_parray_of_arrays, allocate_in_domain, DistributedCellField, DistributedMultiFieldCellField, DistributedMultiFieldFEBasis, BlockPMatrix, BlockPVector, change_ghost diff --git a/src/Optimisers/Optimisers.jl b/src/Optimisers/Optimisers.jl index c95aa097..e5e31537 100644 --- a/src/Optimisers/Optimisers.jl +++ b/src/Optimisers/Optimisers.jl @@ -1,8 +1,8 @@ """ abstract type Optimiser -Optimisers in LevelSetTopOpt.jl are implemented as iterators. -Your own optimiser can be implemented by implementing +Optimisers in GridapTopOpt.jl are implemented as iterators. +Your own optimiser can be implemented by implementing concrete functionality of the below. """ abstract type Optimiser end @@ -43,7 +43,7 @@ get_history(::Optimiser) :: OptimiserHistory = @abstractmethod """ converged(::Optimiser) -Return a `Bool` that is true if the `Optimiser` has +Return a `Bool` that is true if the `Optimiser` has converged, otherwise false. """ function converged(::Optimiser) :: Bool @@ -59,7 +59,7 @@ function finished(m::Optimiser) :: Bool return A || B end -function print_msg(opt::Optimiser,msg::String;kwargs...) +function print_msg(opt::Optimiser,msg::String;kwargs...) print_msg(get_history(opt),msg;kwargs...) end @@ -203,7 +203,7 @@ end """ write_history(path::String,h::OptimiserHistory;ranks=nothing) - + Write the contents of an `OptimiserHistory` object to a `path`. Provide MPI `ranks` when running in parallel. """ @@ -211,7 +211,7 @@ function write_history(path::String,h::OptimiserHistory;ranks=nothing) if i_am_main(ranks) open(path,"w") do f write(f,h) - end + end end end @@ -224,7 +224,7 @@ end """ struct OptimiserHistorySlice{T} end -A read-only wrapper of OptimiserHistory for IO display +A read-only wrapper of OptimiserHistory for IO display of iteration history at a specific iteration. """ struct OptimiserHistorySlice{T} diff --git a/test/seq/InverseHomogenisationALMTests.jl b/test/seq/InverseHomogenisationALMTests.jl index 82929b7d..b0b79d4a 100644 --- a/test/seq/InverseHomogenisationALMTests.jl +++ b/test/seq/InverseHomogenisationALMTests.jl @@ -1,7 +1,7 @@ module InverseHomogenisationALMTests using Test -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Maximum bulk modulus inverse homogenisation with augmented Lagrangian method in 2D. @@ -10,9 +10,9 @@ using Gridap, LevelSetTopOpt Min J(Ω) = -κ(Ω) Ω s.t., Vol(Ω) = vf, - ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, + ⎡For unique εᴹᵢ, find uᵢ∈V=H¹ₚₑᵣ(Ω)ᵈ, ⎣∫ ∑ᵢ C ⊙ ε(uᵢ) ⊙ ε(vᵢ) dΩ = ∫ -∑ᵢ C ⊙ ε⁰ᵢ ⊙ ε(vᵢ) dΩ, ∀v∈V. -""" +""" function main(;AD) ## Parameters order = 1 @@ -85,7 +85,7 @@ function main(;AD) α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/test/seq/InverterHPMTests.jl b/test/seq/InverterHPMTests.jl index ce94a389..06fffac5 100644 --- a/test/seq/InverterHPMTests.jl +++ b/test/seq/InverterHPMTests.jl @@ -1,7 +1,7 @@ module InverterHPMTests using Test -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Inverter mechanism with Hilbertian projection method in 2D. @@ -10,13 +10,13 @@ using Gridap, LevelSetTopOpt Min J(Ω) = ηᵢₙ*∫ u⋅e₁ dΓᵢₙ/Vol(Γᵢₙ) Ω s.t., Vol(Ω) = vf, - C(Ω) = 0, - ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, + C(Ω) = 0, + ⎡u∈V=H¹(Ω;u(Γ_D)=0)ᵈ, ⎣∫ C ⊙ ε(u) ⊙ ε(v) dΩ + ∫ kₛv⋅u dΓₒᵤₜ = ∫ v⋅g dΓᵢₙ , ∀v∈V. - + where C(Ω) = ∫ -u⋅e₁-δₓ dΓₒᵤₜ/Vol(Γₒᵤₜ). We assume symmetry in the problem to aid convergence. -""" +""" function main() ## Parameters order = 1 @@ -33,7 +33,7 @@ function main() δₓ = 0.2 ks = 0.1 g = VectorValue(0.5,0) - + ## FE Setup model = CartesianDiscreteModel(dom,el_size) el_Δ = get_el_Δ(model) @@ -97,7 +97,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) = ∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = HilbertianProjection(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,debug=true,constraint_names=[:Vol,:UΓ_out]) diff --git a/test/seq/NonlinearThermalComplianceALMTests.jl b/test/seq/NonlinearThermalComplianceALMTests.jl index c624d997..c4808705 100644 --- a/test/seq/NonlinearThermalComplianceALMTests.jl +++ b/test/seq/NonlinearThermalComplianceALMTests.jl @@ -1,7 +1,7 @@ module NonlinearThermalComplianceALMTests using Test -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D with nonlinear diffusivity. @@ -12,9 +12,9 @@ using Gridap, LevelSetTopOpt s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ(u)*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. - + In this example κ(u) = κ0*(exp(ξ*u)) -""" +""" function main() ## Parameters order = 1 @@ -34,9 +34,9 @@ function main() ## FE Setup model = CartesianDiscreteModel(dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())); - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()); update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -84,7 +84,7 @@ function main() α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) diff --git a/test/seq/PZMultiFieldRepeatingStateTests.jl b/test/seq/PZMultiFieldRepeatingStateTests.jl index 827f9c91..06db9bb2 100644 --- a/test/seq/PZMultiFieldRepeatingStateTests.jl +++ b/test/seq/PZMultiFieldRepeatingStateTests.jl @@ -1,8 +1,8 @@ module PZMultiFieldRepeatingStateTests using Test -using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, - PartitionedArrays, LevelSetTopOpt, SparseMatricesCSR +using Gridap, GridapDistributed, GridapPETSc, GridapSolvers, + PartitionedArrays, GridapTopOpt, SparseMatricesCSR using Gridap.TensorValues, Gridap.Helpers @@ -54,8 +54,8 @@ function main(;AD) ## Material tensors C, e, κ = PZT5A_2D(); - k0 = norm(C.data,Inf); - α0 = norm(e.data,Inf); + k0 = norm(C.data,Inf); + α0 = norm(e.data,Inf); β0 = norm(κ.data,Inf); γ0 = β0*k0/α0^2; @@ -66,9 +66,9 @@ function main(;AD) Eⁱ = (VectorValue(1.0,0.0,), VectorValue(0.0,1.0)) - a((u,ϕ),(v,q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - + a((u,ϕ),(v,q),φ,dΩ) = ∫((I ∘ φ) * (1/k0*((C ⊙ ε(u)) ⊙ ε(v)) - 1/α0*((-∇(ϕ) ⋅ e) ⊙ ε(v)) + - -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + + -1/α0*((e ⋅² ε(u)) ⋅ -∇(q)) + -γ0/β0*((κ ⋅ -∇(ϕ)) ⋅ -∇(q))) )dΩ; l_ε = [((v,q),φ,dΩ) -> ∫(((I ∘ φ) * (-C ⊙ εᴹ[i] ⊙ ε(v) + k0/α0*(e ⋅² εᴹ[i]) ⋅ -∇(q))))dΩ for i = 1:3]; @@ -84,9 +84,9 @@ function main(;AD) u_r = uϕ[2r-1]; ϕ_r = uϕ[2r] u_s = uϕ[2s-1]; ϕ_s = uϕ[2s] ∫(- 1/k0 * q * ( - (C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - + (C ⊙ (1/k0*ε(u_s) + εᴹ[s])) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - (-1/α0*∇(ϕ_s) ⋅ e) ⊙ (1/k0*ε(u_r) + εᴹ[r]) - - (e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ (-1/α0*∇(ϕ_r)) - + (e ⋅² (1/k0*ε(u_s) + εᴹ[s])) ⋅ (-1/α0*∇(ϕ_r)) - (κ ⋅ (-1/α0*∇(ϕ_s))) ⋅ (-1/α0*∇(ϕ_r)) ) * (DH ∘ φ) * (norm ∘ ∇(φ)) )dΩ; diff --git a/test/seq/ThermalComplianceALMTests.jl b/test/seq/ThermalComplianceALMTests.jl index c96225f8..fcf3704d 100644 --- a/test/seq/ThermalComplianceALMTests.jl +++ b/test/seq/ThermalComplianceALMTests.jl @@ -1,7 +1,7 @@ module ThermalComplianceALMTests using Test -using Gridap, LevelSetTopOpt +using Gridap, GridapTopOpt """ (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D. @@ -12,7 +12,7 @@ using Gridap, LevelSetTopOpt s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. -""" +""" function main(;order,AD) ## Parameters xmax = ymax = 1.0 @@ -32,9 +32,9 @@ function main(;order,AD) ## FE Setup model = CartesianDiscreteModel(dom,el_size); el_Δ = get_el_Δ(model) - f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || + f_Γ_D(x) = (x[1] ≈ 0.0 && (x[2] <= ymax*prop_Γ_D + eps() || x[2] >= ymax-ymax*prop_Γ_D - eps())) - f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= + f_Γ_N(x) = (x[1] ≈ xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps()) update_labels!(1,model,f_Γ_D,"Gamma_D") update_labels!(2,model,f_Γ_N,"Gamma_N") @@ -85,7 +85,7 @@ function main(;order,AD) α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) @@ -105,7 +105,7 @@ end s.t., Vol(Ω) = vf, ⎡u∈V=H¹(Ω;u(Γ_D)=0), ⎣∫ κ*∇(u)⋅∇(v) dΩ = ∫ v dΓ_N, ∀v∈V. -""" +""" function main_3d(;order) ## Parameters xmax = ymax = zmax = 1.0 @@ -174,7 +174,7 @@ function main_3d(;order) α = α_coeff*maximum(el_Δ) a_hilb(p,q) =∫(α^2*∇(p)⋅∇(q) + p*q)dΩ; vel_ext = VelocityExtension(a_hilb,U_reg,V_reg) - + ## Optimiser optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh; γ,γ_reinit,verbose=true,constraint_names=[:Vol]) From 03407de48819567ebab3e4bdb4baa51cd690b769 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Tue, 7 May 2024 12:06:57 +1000 Subject: [PATCH 86/90] Add folder ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ddd3c8e5..1a774d3b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ docs/site/ Manifest.toml LocalPreferences.toml GridapTopOpt.so + +# Ensure never to write results to git +results/* \ No newline at end of file From c26a526c4a2dea0289c8fb625efd5e29e4018043 Mon Sep 17 00:00:00 2001 From: Z J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 8 May 2024 14:51:04 +1000 Subject: [PATCH 87/90] Update LICENSE.md From 93a553e74ecc21e3f37cdca0a8b6eeff79f50c47 Mon Sep 17 00:00:00 2001 From: Z J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 8 May 2024 14:51:25 +1000 Subject: [PATCH 88/90] Update LICENSE.md --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 1dbccfec..fab81e84 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. From 63bda7ce16e029246afaad0c1744866ac6da3455 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Thu, 9 May 2024 16:21:25 +1000 Subject: [PATCH 89/90] update readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d75a3ce5..bd628f68 100755 --- a/README.md +++ b/README.md @@ -12,4 +12,7 @@ GridapTopOpt is computational toolbox for level set-based topology optimisation - [**LATEST**](...) — *Documentation for the in-development version.* ## Citation -In order to give credit to the `GridapTopOpt` contributors, we ask that you please reference the above paper along with the required citations for [Gridap](https://github.com/gridap/Gridap.jl?tab=readme-ov-file#how-to-cite-gridap). \ No newline at end of file +In order to give credit to the `GridapTopOpt` contributors, we ask that you please reference the above paper along with the required citations for [Gridap](https://github.com/gridap/Gridap.jl?tab=readme-ov-file#how-to-cite-gridap). + +## Known issues +- We currently require the `develop` branch of `GridapSolvers` for `GridapTopOpt`. Ensure that this is correctly loaded via `pkg> add GridapSolvers#develop`. \ No newline at end of file From 9b1d0ffee2c8347aad7dd8f555123d7579c568cf Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 10 May 2024 07:12:57 +1000 Subject: [PATCH 90/90] Cleanup docs --- docs/make.jl | 15 --------------- docs/src/{ => deprecated}/dev/shape_der.md | 0 .../2d_min_thermal_comp_final_struc.png | Bin .../2d_min_thermal_comp_initial_lsf_combined.png | Bin .../tutorials/2d_min_thermal_comp_setup.png | Bin .../tutorials/2d_min_thermal_nl_final_struc.png | Bin .../tutorials/3d_min_thermal_combined.png | Bin .../tutorials/3d_min_thermal_comp.png | Bin .../tutorials/inverse_homogenisation.md | 0 .../tutorials/inverter_mechanism.md | 0 .../tutorials/minimum_elastic_compliance.md | 0 .../tutorials/minimum_thermal_compliance.md | 0 docs/src/{ => deprecated}/usage/ad.md | 0 .../{ => deprecated}/usage/getting-started.md | 0 docs/src/{ => deprecated}/usage/mpi-mode.md | 0 docs/src/{ => deprecated}/usage/petsc.md | 0 16 files changed, 15 deletions(-) rename docs/src/{ => deprecated}/dev/shape_der.md (100%) rename docs/src/{ => deprecated}/tutorials/2d_min_thermal_comp_final_struc.png (100%) rename docs/src/{ => deprecated}/tutorials/2d_min_thermal_comp_initial_lsf_combined.png (100%) rename docs/src/{ => deprecated}/tutorials/2d_min_thermal_comp_setup.png (100%) rename docs/src/{ => deprecated}/tutorials/2d_min_thermal_nl_final_struc.png (100%) rename docs/src/{ => deprecated}/tutorials/3d_min_thermal_combined.png (100%) rename docs/src/{ => deprecated}/tutorials/3d_min_thermal_comp.png (100%) rename docs/src/{ => deprecated}/tutorials/inverse_homogenisation.md (100%) rename docs/src/{ => deprecated}/tutorials/inverter_mechanism.md (100%) rename docs/src/{ => deprecated}/tutorials/minimum_elastic_compliance.md (100%) rename docs/src/{ => deprecated}/tutorials/minimum_thermal_compliance.md (100%) rename docs/src/{ => deprecated}/usage/ad.md (100%) rename docs/src/{ => deprecated}/usage/getting-started.md (100%) rename docs/src/{ => deprecated}/usage/mpi-mode.md (100%) rename docs/src/{ => deprecated}/usage/petsc.md (100%) diff --git a/docs/make.jl b/docs/make.jl index 7755b4c2..edd81efb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -15,18 +15,6 @@ makedocs( pages = [ "Home" => "index.md", "Getting Started" => "getting-started.md", - # "Usage" => [ - # "usage/getting-started.md", - # "usage/ad.md", - # "usage/petsc.md", - # "usage/mpi-mode.md", - # ], - # "Tutorials" => [ - # "tutorials/minimum_thermal_compliance.md", - # "tutorials/minimum_elastic_compliance.md", - # "tutorials/inverter_mechanism.md", - # "tutorials/inverse_homogenisation.md", - # ], "Reference" => [ "reference/optimisers.md", "reference/chainrules.md", @@ -36,9 +24,6 @@ makedocs( "reference/utilities.md", "reference/benchmarking.md" ], - # "Developer Notes" => [ - # "dev/shape_der.md", - # ] ], ) diff --git a/docs/src/dev/shape_der.md b/docs/src/deprecated/dev/shape_der.md similarity index 100% rename from docs/src/dev/shape_der.md rename to docs/src/deprecated/dev/shape_der.md diff --git a/docs/src/tutorials/2d_min_thermal_comp_final_struc.png b/docs/src/deprecated/tutorials/2d_min_thermal_comp_final_struc.png similarity index 100% rename from docs/src/tutorials/2d_min_thermal_comp_final_struc.png rename to docs/src/deprecated/tutorials/2d_min_thermal_comp_final_struc.png diff --git a/docs/src/tutorials/2d_min_thermal_comp_initial_lsf_combined.png b/docs/src/deprecated/tutorials/2d_min_thermal_comp_initial_lsf_combined.png similarity index 100% rename from docs/src/tutorials/2d_min_thermal_comp_initial_lsf_combined.png rename to docs/src/deprecated/tutorials/2d_min_thermal_comp_initial_lsf_combined.png diff --git a/docs/src/tutorials/2d_min_thermal_comp_setup.png b/docs/src/deprecated/tutorials/2d_min_thermal_comp_setup.png similarity index 100% rename from docs/src/tutorials/2d_min_thermal_comp_setup.png rename to docs/src/deprecated/tutorials/2d_min_thermal_comp_setup.png diff --git a/docs/src/tutorials/2d_min_thermal_nl_final_struc.png b/docs/src/deprecated/tutorials/2d_min_thermal_nl_final_struc.png similarity index 100% rename from docs/src/tutorials/2d_min_thermal_nl_final_struc.png rename to docs/src/deprecated/tutorials/2d_min_thermal_nl_final_struc.png diff --git a/docs/src/tutorials/3d_min_thermal_combined.png b/docs/src/deprecated/tutorials/3d_min_thermal_combined.png similarity index 100% rename from docs/src/tutorials/3d_min_thermal_combined.png rename to docs/src/deprecated/tutorials/3d_min_thermal_combined.png diff --git a/docs/src/tutorials/3d_min_thermal_comp.png b/docs/src/deprecated/tutorials/3d_min_thermal_comp.png similarity index 100% rename from docs/src/tutorials/3d_min_thermal_comp.png rename to docs/src/deprecated/tutorials/3d_min_thermal_comp.png diff --git a/docs/src/tutorials/inverse_homogenisation.md b/docs/src/deprecated/tutorials/inverse_homogenisation.md similarity index 100% rename from docs/src/tutorials/inverse_homogenisation.md rename to docs/src/deprecated/tutorials/inverse_homogenisation.md diff --git a/docs/src/tutorials/inverter_mechanism.md b/docs/src/deprecated/tutorials/inverter_mechanism.md similarity index 100% rename from docs/src/tutorials/inverter_mechanism.md rename to docs/src/deprecated/tutorials/inverter_mechanism.md diff --git a/docs/src/tutorials/minimum_elastic_compliance.md b/docs/src/deprecated/tutorials/minimum_elastic_compliance.md similarity index 100% rename from docs/src/tutorials/minimum_elastic_compliance.md rename to docs/src/deprecated/tutorials/minimum_elastic_compliance.md diff --git a/docs/src/tutorials/minimum_thermal_compliance.md b/docs/src/deprecated/tutorials/minimum_thermal_compliance.md similarity index 100% rename from docs/src/tutorials/minimum_thermal_compliance.md rename to docs/src/deprecated/tutorials/minimum_thermal_compliance.md diff --git a/docs/src/usage/ad.md b/docs/src/deprecated/usage/ad.md similarity index 100% rename from docs/src/usage/ad.md rename to docs/src/deprecated/usage/ad.md diff --git a/docs/src/usage/getting-started.md b/docs/src/deprecated/usage/getting-started.md similarity index 100% rename from docs/src/usage/getting-started.md rename to docs/src/deprecated/usage/getting-started.md diff --git a/docs/src/usage/mpi-mode.md b/docs/src/deprecated/usage/mpi-mode.md similarity index 100% rename from docs/src/usage/mpi-mode.md rename to docs/src/deprecated/usage/mpi-mode.md diff --git a/docs/src/usage/petsc.md b/docs/src/deprecated/usage/petsc.md similarity index 100% rename from docs/src/usage/petsc.md rename to docs/src/deprecated/usage/petsc.md

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%0A#}Z9>@K3!{d(0z9r+!N0J8X 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 z zQkXH0b@zJl!@tifok=Vm06VG870=2uF-61y{~Af!cOMPL!%3f-7NhKAF#J;zr_UGU zNO;qA$GH@Hh9XUW!q>@;URVFY-}p^;Ca<1gJA3VB=l&u4>*U{|FvFiW$-gc@?=uNV zh>*HWxHZz?{ZiP6WNs0*s1ZXr3)A~C|Bprk&#CcoUvut}yjW$jOYRJ}acCm_*6v+6 zJahQTr_o1CA=$=W%&C%e)kZ@yxY_87F4Q5&;(?>h$foc2Z@m8xBux(&^mPC!hB2%7 zl@M%{3l_&rJc?c1_aBa=IJsXl?ZV4G4B_i_X-E$C1~a?&_e1I-_Nq^%z^BPt*Gv-v z>KT?^P?Z?Pze+C5f7?EkM3Y|lE=isoFwZmu`WhDTBWpi#bJrq0OVX>VGz^Jh>6fXV z9ki|7uI)?rN`C@n0nF~JY%5TKEU(WK0Tvn?bs*7NMp~TjNVulXoegjr(yokSN6ftu z5ezGHcF4AKzx)djub2Qt{(pbDh38RDbBaVJa>00NerGk;FE>*o^Bw}(gOosKnc|^%a-f)TNVOc zD`a7c$YV}W*V4453p!qqqk-~B_{@fy@_$EHes2)CNEtMojmIB69j&7g`V{FlKntih zAW1MDzTsI|ZS9XD`USCY$r95C%hPRq{8T3s_Y97LTJ~-}uPIgR>nxJpx6w{PeoIGh z0BNJJU7{3ifwoD}p78#b@`#Lcw%hJv6srcuOW2aw((*%BpsQO70xARSv%T_Nb&VNw ztFh^EQ#n>~_OptXtNlNose#{HPO)T?%id>U?L0Ob%H{t=j9i(hBYt?Qa< z?yVEE0nz)9)v~2)EVOJS{fabZ9GVGvJm~vePVipb+A5jFV*iP~>gssE<9TLxw>GoI zejP8$?k;*?ley*Ix2UWolkrY5Vq3%L7bTQHa{cQnrVic)y3;)QhpJNx*OGb*Ff$$% zz-6GtiNfZPMusN>)&#;jw`GaEFF`6>Mt zFtb&hy*w1q6`phU+%Ef^E%x~oBkPv#-A6HiwCb$D`G6`TiND*_x3xWfsQ^@F>BTbN z{(Mh?;t$~5Y4WakR#ogBRF<~q4xW&Z1WzXd1^t{!IMH3RDRm2G%fsQg^Ma-E zt`8?s$sJn%UTU(Vb}oT7&iCHV*}c9I(b5mF?l$CkbQ5em!t03isXP+RX{z(-?O$IJI=QrYb6HryfTeqE z;HBUhp-Q8MG+u(x2w3{8K9Dt~QXaD>9lB&ShJsHMlO4mGbTI-BUL|v`5jSRjDhued zhsXQLHrie(G3KQJMkJ$xGG}a~jyGha&B*yu+cU3FZ*~`y6lapfD|$6kDa-$}!l!4Hhh!opf@~Z% z?1ZIgxe;06|1p&DNB%wqn=}IrJxIym+rCTQSH_T?RYd4=h)wN>J?MMP< z=f{i30q!ZlA0lF^|1R|u7iU~G7$oM8DD%C}a7rT6nB)D!nYP!NowqM2}F2=J`vBQ4iGYwx=AN}!o z7Xn!OXdJ(t{n|kLgI*I*j);Rq(a>$XFmL=bPb6QdnOu9}tDg0N+4wwiS9FTgP@c~y zhV@TX%i{1|fS-YcW(*-A2mgKEUu4 z+y@n$v0aSGT(R7^$UDYKg5U)uz+nNv9&v(URmgx*UmGT$%6`Bm;j_Axz-jHl!pieG zJErDk9r1G)tPI;`Hwo?B9z`L;ujPx44?*$?zutznT@)mZEV^JfxHd@w#TWiVu8O0& zmU8gl`XCIl4~%gX{8m_Xw~@x@-9Z#fLO|$;8Ey92mHZB3TL>I zLhE$c=K6XzM|}HOFvV1(4y0(Ot{RXIU|;C3K7i30U|k&LRW;jdmH-35VzY{bcqRHT z#f3ou@c9Z)>$I8tYz?^+2_R}e#Bmt2T5Su%!MLU9&rD>Jr%ujDP?Uh(!2ye&MCEy^ zsx$3fPG3zUUmUUV3cHV36~4k}m|bV|zM~F=otQ?GgT?B(rgs)hpKv;4Ukh559mS%$p9lVSX zD#rW)a}`_64VN)Y0wV`XG*H2Dm`No_L2y1iF7)qB)bVY;yH+o8huV)e!n;joFZKI?6+$y^iDGUwr<)K8O zKVsZ^%b@Adehz4kEaou7NY13azvUZWCV$h@v&2+n=7In%NDccqe{47HgF{!A2;dy3cU># zk%`r)n97<$Lrk%x!xd*K_N$VzPSg`J4b)LJv{G06a(IsDH{>!^uH>Aaic7hW#kb;{`Qq)z3C^Yh|g zH%vAN7Gm#KyLl9xynhGwr<(08sFpPGOi5(lJsyo4Bjm9Eb;buua0mt*-nOWY4Z012 zZFV1s!v@IomcOXEm#Ps3g}NGq9?_=N*=5N*umCH9h^1+x+6H}UKniYeBO7}t}7 zgQ5OlLZg;eBS)2b!#NBvosDgPt1`7WWA?YSc`*n68F+$fmzzr(es$yRO+pw8VN=Nj z_6y~#RDihaE)Bv^|Kp0kcD>Uq#Lj)U+k>+QXmLasFiO3}vV`1r(p&YPH^Sc(2Z};d zajr8H2yY3W@`uqGqbzxkr%cNb7z8=E!&6XRr6w<(satLkj=whc^>O&0Zd9 zh%udS`zgHbZqh~@$&4YV!674mp|TWSnemGS%(-qY6`B&Z@iAi*Vj|lb{Q5cW4q>o! z8s%1;k(hm*142+4$e7002zvvHw@8NQkdy8v)$KCbpp4wyp8t9QV9|5)7gr~81>Y^dMPetI(oMd(kV#-ic-1!3fFp%8An;gKHn;S^6pQHbr z1&dTIqO8nHB1O>K`wsJ6lHwyWDEr;R6M)D8VjA|eH>@^Iw6YzE_bS~1XOQPYhrxjS zAV3xTaTB|X=tiK3-k_Il1)YRGw=VN{bNqgpy?q<3`*V%RKufORZ7gG>!oX{#>Cz1p zkw*f|>Q*Yv|Ax%iiEw~zJ085tfJl8HG+((s?0ftui@{d6R5wesKUWEZKj<0KDjKK1 zeav+(SS>j<5?{V-s)6l#cy0;^|BR_xuz)hiOE++IR0_r?OOd`%%}t|ZpwWl-?4#)U z#oE29ClMhr4ef=U z-cg@Bngx{bzCNXf(t^M`xMQ`HHRUM5BX|jC%LhC=ps^&=^a%eV@q^(=(VdaIH9sHQ z3n5P~68gA=m4PV)*E0@S6-Ku9Sq?_Xlc4s}^JbeA5Kfmmfo8>h<<~U6GIyDkk z#=2Q^i#!3-0_9(B`ko)pk(Jog)P zz5wc|zm_6eSx~qZ3Xr6W4nPr6cai6HsTqK%%Of4JJJCkZTm2LIJM+>oMqn>7nyz7^ znWCb4sM6U|_=(zlqz&l}<&VIwsi9Ra5d`p2zjbxt{06XOpvci~9DFujbsG5~IRcK# z@rXs)axN=KmH2g6t@jZv9i6?tzIk7b#DH(j@9)oz(sOdgU-@Q#&R(8o6g@J%6fpan z>euxeNDM#&AFXecqLy&oCWC3Y4k5R|J>cc7>IjX=1wMBKVTK4n?@fosZj{DSzeOYi z6Y91fs!w_dr4xvN3Cqj~MQ!&YKe~Jm5qOPq5_isfByr67Gj2l<3coHoJIxWpmnLk{ z*XCqXKE>%SyECmaar0LB%ih5@bkF=*$^xc0_Y^MYHY5V(ZDW{S%LeZ&%El{xCDk~+ zrQ(3|Me3ypQRb&N4_73Awyd^~dc3?pTJ$C{Fb7baqa=$8vH9GlEDrL0k9syQ=YF0T zkw4a)*#|g}wb_XQ_q4P`dz{>e5&*1i?O6Lbe|ZM^#tV28KX|=k>T6wG+T3eQqXmT0 zmW*u+(5<=Qj0N3yZ;FZ(-hwFtxB~9dQ@4jz0GEfxm~ML#09NVCuK%O2;b9SVbU;kQjZ$A6@V#~kazkc;70t! zI?t278jOK-fZ8f(65Dj*364SiXb?Z&f?f;RcD6$5z-y0~duFRkSCOQJ>^(6C8bRW$6K7i`bYKb!j z@5jY18%~(cVpcUg4vbFn13VC_5rtDwE~<4+x1FA*l;T#W7^2N`n`Q4_K|?uUlrPBY zMY}1EkGDU@9WC+YOx4_7HTVOqH^Z3TyQ}o)uRTPD-<#|FdOtB5@u#m8-g`AHjtn57 zyAzJ-+$TO3fy@woUZKf5ltqiWHS{$icn*mtNfH(9ha;~HRQ0Oag!!_${(-ll-x2EgCwFQ!mDviUJPCi#wjAh@vfD|pj!*E`vEr<gHWR&0znOIwMIN#sHef~VkVmpE<(cvoi$a_u=KI=R&PKr7wi#w9wA$D>=?q6E* ze{7B-hO4WifV=;K29Ly)J;f3hs_s z5s8vKO>^iWZw(A=;REgl49t6^JWpb9PoUNtg&*;mC6=mOK#fb!DsP6dQ1* z#q(UzAP1PhjIZW{3o=P$CYP&t8Nk$0I%4`9 z-!sDQ9mON7LDo=a8LRFZwO7n%-`(98zj6atCI_@3h9Gsr!!A(o2)HOleWsUJ`yO1L z%lRdBXRlQ=Dw-4ksdBlT;wnTS;vr+rg*AL&ff#}FA+r;5@g-3^K~NJ&UHh)8!yiHe|tlt@bm zNO!47m!x!eNxx(5ea^Z2-ut<~mp}G4mg^gH&JoY^j4@_ToiG?#d9MTryDh%EL~m*C z*I9ao|5kj@V65kp+MwxaMJ{Oe`n+O+#@ZPF!~pNZ_>phyEBL}SjFZQOtRU1XF{9Nk@lurF?QbwN`)TJy-0_zYF`%eU_8@D@xR zBx7-rky6%^pBt}y=S3=c_@32UX{iL|NZwl#z@SzSuYZS-^!alQ=Zmf-YN@3dI|(Lm z#h{^kx3wgU4N@k|U5hx)Zht5S~rW&ehfkez4q8?(utR7(hVZ4Vv`-md+$ytAg70SygfN0RTeWSYbwQ9f9ZvArISNNTsh@z{Qi}5 zr7KL?fBGf{(=NfD0lXWHbA0^^#Z3H)a>o zDZbTJ9*y2~Q&~rwleHK5-CJbOGl+bS71n=oW0J`=eg97TV_H-xs`I~e;Z0g-uj_M* zDI?E(8Wm(D72Vv@PQEGa%3D9KMnk+6MY*xmje2rmcX2G5&wRrW%8hV7BI&(^9F`tr z4M5J~w<%CLWIp(9UuOO5>hRs}WR_5SmjbB}#AtJqgw5$%-%EVQ$v$R4svZy0yI9J6#&l|nWV(brD!ed- z)v{;&ImqN(H>I9yFq|~mB#R!>Zg8y#m=G^=j^(;FrN(`1HL*W+q1L*C4hQ2+trwB+ z>CZWb_o?J@bv27E-NRR%3WVaQn#Ki*ZNx-{GeB`YI#$)(J{;Ojq^y3&u&xaIj&h`} z3pee8s3gd!yRU5AW_O*kvD46U2b;{S$_Ue!vd@A_#Q7Gtt6d#8Q;rdDSHr}Xh$gIpGQXnV-AayRO!TJ_k z;d+U8hrK)%gzy{-hVr7TPEbc{^&V} zpZRwGk5fr?viehDEHDWOgsuP`+e0r&2R8z?@OwI;gaV==YSs`9@ySk#U?gY+LUPM| z%UA{sM5aF^VxWc!ySw4l0&uO44gs`%w`7yvV*rOOYR}06>zRNK>X`+s&B6kjUPy2% zt2~fh#;%R>F&dwWcE70GNfv3NDhK>t`RVQWmw)EfW;r4!f zJc|8fvwuOgVI3`C@mOd<+y#cH>tikc>vIQcX@-OWt}kE)6U#BUN_ z!C!7p8O;?W3P%21ntt5N$S;CD6lqiqd$#+K8lr+F>WdFG{DaNpwiyC&4&=C`#W^Sp_=b4(UxbV%E|9{<64vLZ|g`ZUn@rNVxv4G7H4v;!klC}3{*Vsfv) zxThcbrxLevzej%lu|m3ewy9qA8K?Z=T_fgJqt?w7HyiI>;1=(_y+GG5+m`_and)U7 zZ6Bek>B2ZUMNrr$NZ8|$Vu(q6s$PKCkN_EC@NHTBrDdAbl89hM z!(h-{Loo*kQ|@5kd7*>S5_BG+)%w`3ZkaAyo2f`79JC@xYMX0;6pyZI%zFA}TKAaO z`Zgta$>y$mAz%$UisM-+nv~mS87HdB=>&qlN?G4*p3Q2=gxv0#RaTu2!&!h7r}+#C zKHXs4Z8!?Zt-zp~g5CSAia!j`Akb0l6XgC>i;OCOJuxv{kU+c7SXlk#Ur_eOc7YEA z9cq0)dv}mR+zRxdX?IZS&gqA?oIJKhP#kA^{I(Zf=0=?OdYlf68#Yvk5tM1fG#S*$p|ftK9%`{``jYPTds-dU*=jH-W%4@=OG61GtR8caF_+iMYgOzGp_cQ>P zgvUhm1i;E5&Pzx_!XXsm*vHk6$mz_ao)&!XZSX}yQPke3GqJc@z0KyA(DH4p{}`aZUjH=9d5vDnF9f+|ojM^bk0!LB1W6IAZB zz*^JReKK!MOGF}h$;tZZ6%`n9uC(;Ko2C%5;f7`q09KnMdcccETOpmz?z_dV8{GDN z%b!dMv*VA&59ZdkWP#L-I9R?~YTq)eIUg z%bw}yswoOc&J@@RXV4a27g}V8Y#=3e>O$@&>D>M_9pipG0c4_}moVQhUfABcOU%LH zU}|F#w_9q@d;?<+Ko(IiYWqn}6H&{bsg=fG`zxh2sKfxJw54$M|W$|CS4 zz3v4fJ)?n0MlBmA)GZOaZdmD4PgVU;?0Wb0Dj;w6@hUEWaN23=mw;jzIpfCfOJ2_)z)kji^8-P65vNfI|_svWz&7%-ce!vcz8 z{{X-}12R|uF_X1w=yP^I2!o*D&UaVXnvvHIk%BAEuF+1`SpEZtz#DUZ;g?ec02T|f{1dKVyJpW*0wb_V*qrm_y8B? zZQO#=dScwf^)O@=R8jA4|L}E}2Bc72?6ldPYma^X$0w4qqB@J?i5nKJ$ zieNih8tokt)3LsTREs}?-}T&tswB{b0}t~&y38OtEdeAkFt0Nt^9y-F0X2QX>&#M~ z)b0#x&}Bm<5SQuqTf%aBVMM_H2sqg*K)4(8*3ZyzEW@BD_qy1jQOZN!wd0jjVu*81 zEgex*a1Rz8KyR&ob|dizeUYXWU2b81;O-9P8bGr`D0`F|597l(#s{y!r0RFqZt6c2 z>CK248}mPX^(_z7H_&V`fd3MA*lyDYUJcS)f}lYGaulcb>%gHrS>r~BTAnyyqAA3> zAw+Xt8ut5`JvmFGz{01n^f{BubXQ^dx5#LY3lyjZaXK~sq#9S(e%L5z36F#QN}|0o za_v5eFNF-e0Z39&kcBiL_!9GOz#@!`<+7uve64&(GEjPQZn~~h zWZ_UYotV=ZjwQkw5)S}94B4)}+Uw`tBqHXAH;w&K-%limS9*Dpf|?++x;o@*43w>a zaMHYWnZL|QgB)IY$0N+?#^_(~m%F6Ega~?jp#tjwfdv|7__gA)((rrwk&tGjv0SYk z+iwKOzSqBzF?0BriVCmG&V+76rFTUAn*+#S%$ihcdNXzR?B|hyT~p%F!{XI8-$h1N zJ-r;cC203r9>;t2`(v{lEgYowkF)!PHb8&-iAj;LVqsQ-SXam*7cXg3|LUWeu#fUI z{I#kaq0$_|kZ-X^3}6g&hq#o+3=e!~MTmL#G)DB<@!^o+%W)*mfYFD@RS{Ph8dJ?I z58^=50O;8akj_w;VczxU$fhabX5c3^YYYPeT{L|CAaYClK|2C$7jk0Pb6tq(W`C;Q zAbXdtnHUdB=kjhu*4nfkD(r>Y@kZpro~0!N4;xiK;jn9YC!+?P`Tm z{DW%;ju)oPpvOLNI~3H5jM->-TB-BNulseL|MZQhL|RGEGom0AE)9dhDPV@3Y6PK!=-mmdsW1TU+POiUV9GSr8ui8hH-7c! zDBvRv>;8z*iVKE5-&Lq}fGMO%Y`5H5Cp;}#@-Kb4Bt73vq$W&Mg0BWl_!*e+pE6*D z$;h+$Pb)z|1?}j`>c*bu|@VTMl8`GBqHh^q=p1OcCFx zJ!MSmAOq}ymu2>yc;^BSvgjE~&pW#+gY)vFf%-OuqX%1hdC(IL*o*uD8v`gHz*N6w z!ciI|NuQR9HzHC1igvZvI5?i{b)GUTd~jSZRkVD`E3XZFA6aCnBmY zp!DTEXg+{6s=u<>K^GnhD&{7Ljq83>0+WY%$dUdfbnI7NQA@)}BYGX`lJyf>lrj5Q z{s}RkgHj=6nHMM*k3J0a)@<2_{mdm#9PX)_`o=`^5Y|1+kOLqkb3*~iRj6=u11*<#ZP6n&1Ac9{0b1w=X<=M)DF9iDWpE)^{<(`ewGPgdGS5l{h5@bES zG2}39<3jH=^XznFX)sM6Y-s>#n!jKZTO-4h^jz5C&HnH^@l(ia8SXBMYP@u$m*Bhx zLD~~~LCLznL0H$ZinXZEe&$G^08G{0Up_$bK>@g$@dXyNxrtyaK)Mx2M{&^47Jh5@ zrOf@zA*DJjrloT&4W#^#ayh#?;?t#G#Jo|$QnS+R>aIQ-ZP1i0`t|jQ=3}C>G##j6 zKzO4LvO|ERK#-Y{KYe}lSB-%3^=2Vt9<3wcS|-lko#UTGOKYACwWHtzKvp_}oq znZ)?n$V*MFpO)hBD4566RtB8eEmj;kIT$kaeP(rv*66%_xvTS3R6|qq zaI||~#!wp#AVApgX<3O4!)z@vQc5nuQ1hnt@GYTd%KT1En%G#`TFcJcaDZHO-W=Md zj+swqfPm(fT_MBZkkX3;7i3nEFu`5GQ5(5(k5$g%g2>0TvLp}sA{0Tjk17P*5S;LFI#(ULvaM`Ct;B{yovkDU0@ zdEnl`y1)SjWE&k0-0#uZlAri|%Dn^BU^X6GOq}~4Zt~FQ6%eBS;pO7fAPEWxil8^~ z@bDz-t%cK+MKYGc!@v;zmfY zouQ(PC*|sTy_Cny)YcZ?Bd)% zdsT74)Qc}LiRl=Lr8il4ofA?@ERzGh+yU)m&cN>QJI+z7no-<#wg1#nnUMKBb zTwJ+FF}ArEg5IkSs3(djxeKhe1h_rN@|NyAVEon;#{Y_lGQ;+l?NBkc-=78ba`&Wv zjV;mAhHqocSZzhSpU3(9c>q&~a;k(Qo?3U3J*Vj1!2isFXGH$o2`?$JD37@!x1T{2 z^~L$D^9X^EVd9Mjj>s+1=JDg$kwyEK5#0CEcM|A%nJ}<-0-c}O?oC*b{xy{6@5wwH zBnzlT-7MyQV#}?mMrwccf&Ir{bI+vLv#^n&Al}s+g~i8vmcJfP3uLEG(a&$NvTW5- zsrpanMEFH{4788^?>}16imyLk*xT9~6f0p8{i-HR~EG}J7O$bgJ@7URLSmgm}QT|7r+q`sFn$^Tmmc?R`qEpTz%I8{#3_^a@n^zn1zx|H-J%_wMnu zUhSu-si+IgQMk~naixA&bs)Lrx7D0|pa@@NX6qTk` zL1s1Tl5s zsnAIW!g>dIgS75Q)w7@~MKUPf!wS>76Brl>vtE)y>d&Wx^9?*4wg~?7mBhsA<^TIa z+KRY67uGYs=;T6=Bd{c3G^`|ZD<%UgD?uc-)C=Vsy#oSaCGqI%H2N9$Pj{T3I${bO z857~)m(hs-w{JH4Uyq>uygm@S)*vRpBcFJTAoL$=qG)F;CdDg2_~$(C<JI zqLp8bJpA7~_@5uX)7DIlh2Q^_Y%D8t1M$zl`JcZw=0h5d|NAG8`M)Mb|NFWA`G0Ma z|Fv=d+a>Nq{;w1I&jT!*0M_dNzB*%u^8a3;e_mew#{WKr|Ga+AOJukF|NBQv>HqKX zO&y$id$F!dRLpx;SC>=a{`2bp;uFSlsb58}T)Ps`8843tdUQ2W<4KSbTr!AkFy z95?;PR#nH}1+L-bMBaMD^ks!i`km^T1{$CqXha(F{{1hNKWgQ@ct)NI?o;E% zbQQbL*^QREV9dMbR3}A^xV6K1LA!kC&Mj370{d+24z__mWG=J{Sj=(~yXT>l7-OuI`stx;Rh`7rjHg zEl?Y0_}4x2hKvye`EuOg(Q8il*$&v7(tXWJ+T$jgV$j`>KMCn z6kz0J!9>BIN96RA;Rt19erDo1yTZuC!N?>=>FJpZ3ZL|Bs}Kx)``*?p(%Rba4D&=? z2!C=$etuJGPEfHUCV6t@_BYcPimoQsk1@zcJ}*mb%iN?PCKi)Pe_=kEw}V9>8fMDW zAlEbHWGlj)hhgO1B@bbUD)l+B!QFcu>mx@H)LVxT8?8h-2dtd^Y>@{zvAF4b|~!CZeG(>}+eKxy*|M_k9Zl!BMAXmlHbhk0i{qzlMX2-S zTNHfb_RAD1J$*6l?I)qut!IqjU%r*rJm{u6_Dd2O807tUc^QlQ=%+6icS-+K#eZ$L zq0es(2=Bcs#S^LMZdqN(+-VBhgQe_$s`u9iv|{=-=@@Tw%Z{6>p?~}&OMiQ(zM_Rb zuPlR+n}F_&MCvHEv9puf7qd35+sF#uecs2)(Q&~te+CUr#@~Yk`H5rj=rT+QQ#HyqU)|?l zJj4zomF*R6@D=LbqC8Wccclz>`^iEIxgBM9eXyNVR*F|PLAX~B#DG**7 zTZj?#Saj0U6E^!^rcG_Sa|22{xje`2hyu}`9ea7j8`B9;MeTnrG%+z4Os#uTQnWDT zJrZ_0@{YlG!?F7N0IA2U47+gz1;@@!r3Ay^CG&fJ?pYNwe{Hf1TRziWGd$WuA?BCV z;E!kj5D(?BY8~BsUxkv{aek#l5Et9!$a#O-=|xIP+D382_j1#ptgw&sF6zND5Me!m zDH(k1@^T3_X9Us3%1i%4kf`w0b z%kl)i)_Hb04uQzh_@vsszfT#m!Yd%9pg@j5CKn!84($rOfyD-YR@drUO1d*rG|6zy z3I$QhGe<<~j{3-l9Lvqkn_WTI17;?gZEYSwO3bxUj;~$qr#We5Jqj%?>{~LXy-j;! zzs`&muu|&R{QGoecs)=UM(M3anZ5^6V2_w@?}#66`8_)KZJxhT>|veT_LtpPzDDJXd;9hbGAzCJ zCYHZ~2G$IZ<{1BQ>jE+UwW~>Y8a+Mmtx=3a9P;za7Nx#>_Sdf`LGQn;F@h{<%3t2L zB4~N^-rn_JKUF_q>*jFr3S|EJhAG!yHseWwo+z4(f=`T&gS>?9LlUKL{tA)I+5Hw9 zqr&8j>cWV|@82nyI?jqF+yNC1kw!&$QVtkE`gr$FlIE+Y#pMpMgM*3(W!;mOTJUx? z9yWL}u2Yuh^g3x9;3!vJQ)*3UkgqG~PI(xT6Fx#uMrqQzOjkw|J3PN+#mF~L#@ND1 z&&`eY>){T|i+Sk>Jw%Jw2)3<-h$g+egUe&=VmcVFSeVg4wJvk#Y6VS-Okp6(93+TUyEn?H)z6t;U885) zFF5f>yU&>RrlcxNQ_vRu&$h@o=%!VJv1uf6JBUVS2j@ob_0p*&Mt1QpT9M{;X3r zc6k}jcUP2R+mAK%LshkJlkp@U89g6-9pPHUDPE}1R5P?~J1IUy*A&=6MCppd^U$=! zld0nZO;gj3T~_WO6o&A$x&4SwCd0|nP+u$shu!ySvQqzf!BbfUqmIJ08u|p~=Rem5 zE`4uaNB}rD+kbo&`h?#;^4WnG0ii)oR_E&7Y2K*qo~bw#L|7R9c3-xi_4;6Sd&S6? zBLhKyOKu*X443)dktAVrhZu*bzqi5e@(jP8#4AyaM1E_N{0*XC5G3 zW21>rxmv_smvuzME~n)`zsSsV_oieD-mz${Pgu((w9vMZP8SyyJ=M)iUe2L{Sg7z~ zs%E+-j+FCoj_v$1W@mcP5mXWYp6uKe zo!k;gCyG8}S`YnF25{Kz%-24ZLyYdVBN|;>p!$g=u1d}vz>EY3<4fDzI$c7_6ADtk zT=_QH>E`-uc_xmil9C0L#I!1_rJ9JCdhOZTyBqDiQhO9TE*`}mBWLi9CZiA_#2M`y zeY!AIdl9Zeu50?eY>2-?EM1LGCd@yQ#$ah?EForDIn2M5as!aV(%&L^!!t2P7#Q#Uy593A7h=lt`v z>}9o*HF72ES!7_%@^$IeUn$t=T@4xN@DG%IiE3md z1|p8P6)m~ip`nb_V+}-p81mN}iO9iyip{4raM&He44 z${ID6`SR=9lZ|_!%g2KJHgPZ)knx64?Vtt8EGk2yiXHbIFA99hL!r${ajZ~j49SGr zSMNyD7jp9A;0@X;GeanrmYJEq;k--{L*onm+VGffguSl5XD01j)zitD2dRJfbg1^~ z`KxcwA&mLBkhA(({*b*dYrKmmPF=%HF;@(GL|0DEEM|+x=I7-HVfU0ke?mVLbz@2b z8oh|Gi*$uM4u8ccb)CDen#K|G8?v(e-?AR+`dt2Cf@?L7ww4;lPGsSK`<6bWKefEm zka3w77yp(R)j-7KI^|pK>S#a_Vzw%t{$wq`_~LL|kmS1hPv!fOY9qYE?!jSxVYGGA zlKQKtqhoi&<4Zy-Wb#PC^*ZmI;UEGYtf_-yr|1ad=;kfDdZ1lra75t*wchc$9@bkf%Z*#!+H?Ml~^8ILjYpi z+F!F(V?AU^hKG00j`3N(oAln|;&swm*!_DaTZdM7 zn{0Jd{;nY-H9n^D#q?22cQ=08-u@@W93TQu@z_han}TelVL0 zw~U6M54WSY7{#)CQhkx<5u0^%@_MWO^9W;|;4rqs;_Xp30AD<&ob z*+FiXh2Pny8!unweO3Pz)jisZ18LOi7PtUgpZ8#&g+1O9fMYD`T890Qi7q!Yy=N>ZF}A< z9pCN|O!Cq$BIl%au+jbFO$sW545fkCF@j9hDj%DeYTiEDx;xX0_y}6rlcvkn#ii#h z<5q%W9zF|I-*ciB2#d@XULtch1mbCoD3|3~5v=5sw`(iQ%NZq_Yql{rR%iGN^mw$G z-t^7+Nv&0w+unHND7N@J?DA>n<4|Z4!GuA0I$QPQUqRM)NL+@zK?-o8tA!uR&PLPM z@2!~iqjzX1f4fxJf-OHY6B_p*vPy$2uXt=f=NUCgiGBQ_yAV2CJrNGr1DZDWGJ6O-WRMW;Seqf z%MM{!r*+~p>9svg2F|ID9Fpg^Z%YsX1Sy}iR?yoF_TuP;ZsYMhWN6+@ZECpmAwc{w zX+np9(QD)vvUWs%{UTWg-x`QSHbBH*-C; zRx-bHIeE;?Y>dclYBc|1b9PKFs&9}cFJ9d4sInGoDJng_s@=tAb?jkOUvE_VaJSLi zSxLFuh#8-(*1KCr401H}bi~9%%rY`xcp65?YUF7FTMw=r6{+-dV3m(MML(e~3_zai zoa2{2uUn zobYPwU>}d$wJYvMx5_=N<_8Rg2t;Q4MaUjz0e> z)bu|*q=4b-Po9K0Td(6I6d!o!eArwb#E_R?Ot_OD_?Ct;>6gvDFU8IX1eW{3%*03E z1T!DvZLxhJsk$=mP5D{?9<-J%p14*iHNmdPlpZ>Eo9k<;CT_~a-5GW z7G@o(vCC_CS2(>5UN3kC1n0ffD(sYM)e(I*Nc81&EU6)$|MYVr0-3e5zj-qy<2>bo zjrhH~fd6lNushzfqwBL!58=sp`l z8*^!s*0-Em{bvn4uXIo>D&hqHOfmo4TNDA0{Bi0-s_k^0SG*``o>5bPO+)U^Qz5uba1^fDIw%R{DZ? zk)>rTJ@c|42}#fkPUY~=pT(o^v&}4zQnHJlW~P__aN9CaHx+lpT$lMh*%A>`6*`gp z7)VcuDVioGP=3BU3i#T?^{0#$n@!FwL83@3GMCv$n zKq_2CdGy&HA~IlJ=}EGf9=-m2;;>{TnVcGV){*+?{TKWzQs2%6e>|3h!zgZiSJOz< z&ksYEQClcD+!qB%HD$v`5bkmcpdTMoAdeL%CqAP(C4i@KKfX7Xy`_Q#*}5PRkf771 zTk)^2BjKa!YA?8rkapF=nGIg*o1gH1Ol$!S7J^2j;ImExyA`Ol(2|lHltN{)xN&~P zcJu1F=1Ga~gKBH}4&2p0ies!4du&Um`t3z+c#NL&LaRX@9$s_g`|9nae)9(TzQO>i z$UpN|XPL($5DrVL35WiOq=2og+Qp=sqK*n2hJ`O7K=*>Fga4jhcvTpgeW;uJ%R{P_ zSN8MyOXVBDS;LOYJK4$?-;!M^F0qTfK$W=TexA|nGrxFKhFLkBh11A)DyKd>JyJ#C z$(GOqbDE*@6+T+A+Mt3iK?nf2cuE7bWvnXit`P_vebBD2*Zm5FHPYMxZ~);kUL-Rn zII|FGUp;-Hmhy)J5HsP^vSVfxtA!L&JqiYx=15%Fz|0dq#PNrtC0^!{)J@jGBwa0L zjy>9s`T5zK5inYN+BR>M+W*W0Zdm*B@RaZb4WPb!KYH6hjod+>58wQK&cCT>UOrWb zKB*u5BCqpr#1Q)Q? zptqh(d>&iD0I9TOE;K4j+P=j^!D_;vPIKAm9ho3x2opV_jI&2zZ3x9USjiL z`c%$y<-sJWmj5fpT(qKYz3dWIR}Gd;v~>kQgrA^Q7uyY9*$}DMn7zb=l<$CF>2+%0 zS?!bgNZQMKIf~`J(-@6$@7&K-7&p4T-)QM0#Kc-ijtJG>csu1TyAItJ?b1E})mP z%cXMq6j{c+e&L@$6|3q{b{(6zE(eJ+l6xo^5vOHaVUfNHQh?$`F9Kc~gh$t9|q*jucZfGi|#PqPpdN4LW-9O%CK?OH@fOa>4^d2t-3* zavTy^#aNYdwdgq(@Ami8(hCTngAtF8VKW)YK~H}Fl%-wKCh6#ZFFGa}2sVDpWxsciicv&_81QYGo2(&{ zX~7j6w@h~PS%2Jby%Tde#4cFrk3!~30Z5i~qd#Q*|}~)VK@Cb4li9Z%vODbD(a|~`r(iWd3!I?=3s_Ou&=ojyb~sP z4iteSkPXSO3@QMCXSP3@8Z}e}QOrzlAf$7isL|1Ew3nBY7+^UoJ(h@`KW{}KI8#jl zlXnk&X+^MU5THV?^G5jc*T;_cBObqd1AAU1zP~~~!cko6h(kle&@AH%;$L(`vF#|@ z+|7$fSmoC>=h<>%yB%-v2jH(l0cSJ){UX$QeHqo9lyw>FNqlN*Ai$NCe(t#4$!9c1 zH9gJlmkvl^|LIfdtP1U`Fs?joPNAOD-LHm#^oODUQS4Wj^RZ!#rM2bdD`MKI3CcIl zitL+bWFAQ;r(!2sPMTOO-~~!zLZAVp3@)O$!X_;86?sd|P{j8wHU8T#=FQ+MoWVQ- zZkMU@b%e`j|A*EK;x!j&*)Dg#YA2?j5;--9_9})K_bvJD+LGJEg2{PL|FV zk-a;K&VLFneGOb)b0p~-cgt}QdCUbp;*MIDLgyGh0by#BbaI|H0BCB03nk#?6#)bb z6AaM&JoC)v2I>oCTx7jt^@iTP4;6XeN1Un*pGPgdnfnvJ#SlL)`Dpq&7^{-PH z!0c(tqfOeN={D`kC#E+H-@CVb%>6N=6)4LJK>NA3cx!^nnu+-Uo>6sA^Y6deOE@I} z=p&Cbyt!h}^L#kxK_D}MH3c!5k>xK4qSmL+Q9c__Aq;93m-`)VVi2C6y)9)TBJm-4 zKYTw>#+(iu6%iYxb4w0N88-JLdv^+ioMaX)v++N~2j=CT5;+Q5kpYCRE+M!$sP^~Z;{Ot=rc1Z766d^kqWZ^354{05 zzjw6cYJ2o0K6{;t|0jQaX&?IT4;Q3_OlN~Vu07SH#dKhz67@kF6}(`#(Dv!pt;voD z)8%*E#mvoB+=GBSZh->~cz*&gUvlOhI*>=AUFN@cIqM`$61O7-Y(>ueyuoiHcK&0p z#*ZUM{@OuL3IAyfAjwym-D!*%@bIaC*UBiCXlm!Pfyd>@Mv!N ziQDM;095cO0R8bd5qt^M%4%U(m!7+mPC(ww$`5*Y^Bf-x2y(SDxX-`g{^;C}ve0?? z`W_67~;=CS6aDk@{4AOLwc%-U<4%;bb(-@U52SBkDk67|j#L*Xay^zHDafVu)s z;QG-fwXDYMxduQQ_`O|)(AhU7R@La!kfKv0xG1>0Ffc7|9&*D_6sWBss5_|-1{hbG zg|9KjZX9BMi|CX;OSq}BAJsaY*SC+Lc**~>>%TbkAu{dBTd%Ip4#!MJ#8wly_}wgU zFobXi@8^V1FdBYpoTE}{o=t)?`ZbKc}{e6v~{x3 z4%OzQSja^3%dG@hMTqxe17)tI<*F>%PF|3%*u)Kr)pxX`(cciFR<_tt{&wpf-$sP7 z@3hp?=Yjm!hHoH!m>%#?FIM}=Ee0!vpy#-mhI7Q!*jCO8&b7FIEkTa0yBU2ttCG|i z0UEL_j%*Op05RX2zNhtMLp;AbmSv~(TW5qkGHW1O39sx}`kXg1`%*~2CeGM*Nvri$`T5RAsP{*h!!_)d~I z&_^u3dF+EzeVBxruGXMGmt*%FXK%*Ch5z%ZlZ^C49Z#aW^?D5Q0!xlXQecT-jiuFo z6Gu}VvEHK^9aQvz^p{lapyEtccJx?(@-C94AEIV5#}yR%3TZ%0^7==!1MCMi(8{L5 zF*)$shx45U52-f!-sfO35>&z%BqT^-v^t?n$=995n(!g~ab8~Yl0QdNTzot&B6P{f zG>Y=_@_YC54v>Y!6VXM0?PcUSC;R?{bGOd5H*3b5gG7nq_k)(F}{8ocvuir?;?G zWENaf#}1Q(WUiK^fI6{qyy?m{FLpAl!)o?<;K){F!4ESkzEgj^uVLy}=u0Cns zDog_r%N_2%ET9mGsYnCv+hzZLJ}nGG8OgsaZWQda&jT6?R$e3Su6Dn7UujYjUkCut zfMIoZE3+KX$lL7W-}^oBQLJ^=etzK-nfLTjS#j?dy$0JWlp^Krw^C0tb5(A|9D_nq zujDZcl4pP$h8Xqt`Gf9Ue^el&-<m&m$qQ zUG<0`sMEj#ZTMx zLc;Up$6531vmvC)@;^`*Wb%gV35D|LEO`o{1vsL;wS%Ncz6m@_oN2AtpDXPHRzvV8N$7o2VT!}v0Z%OEGS6c znaL)P8cP3^CEob_hD`jM6U2qC024R&bvj?K+}5S?euyFL$N5O%7@2i$b8Ft2VA6gUSI}DSg zSBraYfTS6bV#r8l12HpeB?~}(V}$3jS5_#R1_vqO06_?TW7wC9@@_y@f@a~+Rg-QG`HV;`mF^e?_4V{=oAVA zdTZtAo-AuUjT?10lJ+4|r9GW?OB@)?BIT-}yyArd_DrwBI!zd5Gg7m|A1TBF*-^iD z-RFqCr8jw0cf|66Gm~5+v9hULX+Q-kJW;rTQEZ&Xn zfnd7z_#v?T5Xw7)T4JKk7XdMQN9#A058kH_AZs++>h>Te_NyOk=L19lpv5$Z1!DOj z7N~G|7s=|k#8rGEN4ju!bU?D#JdJ#HhE%*CcmQ&LK9fN#7zcl@= z`8ZIt#Hy&MkY%oUOWzhWWaSNIAGgXSi|??utNy9$7n|2?%lag1(i7`JM7wCPT4iTq zf&)xujGMsSn}11_t~R(Qou4?mGmWpl=KS7RKe=_)dyxd|iHW^gu8Z%tA1ZC|iS34J z3bE7LP!J>(YRSaDWFd1!CcmnwXN7u%r#Dh+z+n+Go^R9l6J|fS2!oHwoyNXOWeuyo zBe>1-)X~={lbb3{m?JFAvbXPQUhL1gxi?8f(Vz%w&n0d6T`n~4Y<-!nct0it0Q7y& z)ejme9~`tU?3*p`yE&f~F$K-fb3v%$N_C196{$~-3}*3)p9&)aRxc5Lu>wZ4Zxz2T6=N!^G+WC>l1$R?Y z=EwR5+f|+*mhTQ=u~hyZY<~MA0+|azd{A zBrk3E_`Hjq%H0~gx5wK)dY8s30CO9^9w+IWFp#Vl$2Y%M+ML@H0DEu%S2JEnU7c@k z&E<|n#`5cH0iTP>1mgKRJXre*UPh#6m+$xJ^6v@vp%Ty7RhsImBES})Vc_P+6bsLd z{QTK*sGkxU{qmF#3Uz?ws76NgaH>L8H}aOM939A%r#uXx=J-`g6;`1>rXc$+@4htj zTqKgGfWhzdusCJ?q@p+}wiB8?pl39dZPU8rkn;3Xefww7McwSu!T@sVdiX*mv8Ue~ zh|u1-KbU@Y3yilqi%0f$vlYASIuGI>(RZZ-XCsVi_69QGYM~z z@W$c-r{-N<4z00b86XXypfjKOE&&`txJ4u;vJmX^G*=4`zn_=)>%-9*r_Z@3FA&kt zXV@OY@oMkbyQ}x2iGXVV9_Gz|BnYI9kJ@l$2|S=3i6RxNjGz`^({dbYH68dt{QU+w zneM?7Ll9al%*B7UQ}z$kimI8II&c|PI`^}`?alpgzS4~AIyw$U5QtXFjp^g>9mG~) zc0nB?061{FId0Xo3Uwkd^M);EH=|`LeVDA@;|CDJS~F8-@5lgg?Y7TiY-db|y!9Az*_?Ne;YY=emine{p)8H!Yw3>8j~i zKTk(u#Y5`dz|Joml$Jn8pap<$vuMBi&n&@XRQ1aj($bGj0gJ#3CN&uEZ_=wgU#69C zmvR|(JvvE#^)(xeTBI?S=PQ#GM;PE;(%3#%1Q!!t%SCxJJ3IhgF3RwrAkpYQfZ!^8 z_MQO~9{smUAZg-ZT3sj_cqU?KTlRvG4jCJ!<4qs3DwBDgMc?keH?5yru;_u046yk< zOJ4Q${nW24oed4h#aJLW1c2Qb`I9kBPLrk-*MJXP_!-Q;>%fnCi-qf+APra|8!zX0 zF80k0UE>X`kGDU@!dtVNb-U52dRBb#nS)B(;(Dk?S8f|asb23gkTI;8vt|Z{HdI)y zihym7quwP&-%KCe*f8(L(P{15BSg`eJHa3d(u}I9#aQ{f{0ce;h?yJr-NXGQKonB( zwnw|Vk{;ucvpeLV5^FPCjAY%dAlLu=4 z!-dUXMhP^@S0{5;S8*>^smIIg+K&6H#^wz@4%_?cMA)cKz%pG%adOr0mEhU()Q^ts z%W+Oe8IJ-k@qcZ!fU^++KyuhHi2_vtTz2-))P7+E zfHFrVvF{u1I=JKe8xOkpa<}JWTRNWY(fabOk3~mw{LH`h`C={d*nG5YDjvl4G(rwS z>}R%mXRkJUks9E8B@7T@h!@7>s(NpA?w90WOEA78WdJf5UaLXW|5Jqv z{Gj7+%n(UX3?>v37Hph>!V-X3vh?~I6<&uCE=0MqatsiJI}KH%a0DjFv7v5nM;!dE*{dd8^r~1Sc4wXbLlRUQQksS z3Kd@%6D!k=@&@FOFW8XZ>l?A<_B!^&`)f_0y!H1hbBwYg7@sTs`k9b+(SV|?a{F@} zFsAT*)>mFt%W^_h4fVR3(okK+P&nCJZGa5|K|GsNkoJY$j zY?&7MA~U{SwfL7G8yqftF)aY$PA3|Wl9_FiAOrkQ|H~;=-vKo9QXftAGI(13Dh_w+%aY+CCWn2lDO>Q6tf!nvc zXGn!aO*Op0Y5%mF=Q{X0L3O>SDT|@9o@|~4EC}t}TaI9zlcFR1)(bA2nhXTN;1xyq zYhXRHX#X(^tqB2-iKKlTjOT$8-SAjWlTK)E5eNUb=~hJLo2XiB$+5LE=)m|{-+u?( z+c;1_BZ`#zOZuL`ryOo5=(Z@8Lkm-{kowy$1jA>xtH!xo683QO-*~}waIjsy3CGFF z@h6t5QNuTA9z8s~fl|Qsh<7*}(tl)c(k~cEdmCEnf?E7G0tv{TmS|@gmN)NYX3~*) z))i8WEHCd!y-&gfRx+AKg8h+RK`c^-y!%k=ebVdbjl2Tyq+dUYvQ!%?;U3?g`FJua zqz1W-_*M`hxiistxq}pVB%bHUn_jMm-{C&J1y)6NZ?;kt@HdQDU08tD4yFR6N(Izw zTi=Ya?>4H3&vtq{veSgx6-^`df;OXp?3w*Y$<&e(Wa1(VM(x371VmA35H^Q~y|M3? zrjD%!!N=Uai&yKtN{8yO3C-*sz?r=9`yD$z|4{ocX0_UHFb-H>Y9lQ_nKn67Mg3Nw zD%^DF_qOI!*JAw*US5r~hVdHY!+_WcE}v@l`5<3QyqhjsVz@p5})?}_f(WEFJkvcz0sBan?9s5@7Y z<1ZXJ1cb*%kYq44tSp}r>0nuaStC35WI>a1d%Ok$?68&46;#u`TYaCQN+VT%U3Beu zpE$RDr;RP@&ZTtdS4t=gk_O7Z1s%>Dzz9`3grba;Hdk4aaL~{#- zL8>s{PC4J*h}}YFa46baySp28h4&xuJ&-OJchq5%IsmIP3MT&L4d@Mdx@4vC=jYF# zfGEosM#D|`;Uvu71%p|AsAkpJ;{Kk@D!Y=T6 zw+dKJE#ERy(v{_z{}m?K;YNGyPMKN% zfeCMO1=>L?BfyGf0@{qcYlS&86D9;$;;1wPC_i zVFV<`TJLjOgk;9mj*f?zGCRwSJB^arb83_>E-pxZ6N-eap^9Jh?tSgZn&@oGb~QP|wKj?veB z;~^Q4UnrrEZc6G9%ma^EV)*c8>2%aRL7ZRxO=Qpt!SL`NNkEa-uqk7+#`sQxEI1Q@ z0Ls*6tF%2&LAtGsQy_H{8HzPwX6wznk5U_*8=XpcTT;_>jCCx|JIqLnqA(EB5z<-F z(bpO}yN99Xe#za^Q&PU?TGA0A(lM*(r1+L_sqDLv;13747Ky|g#goai;fNDo8XC73 z+hVUCc&`p@iq+h*pTUBWiyCZ$decsI25X}h3=T%u)c1ar7hHy7SPS`@Vch0ulEkn? z4Tvf82~zs8z7_8zLuUTsFB6Tpm0t0fX|y3NMFNlqa^jP<1M2naS?r~L^{QG$Y& zooa!Fm(~0aKGRAx62{UNU8gn1YK!2Ex;%Y{=x0_H>F(!JS>-v9Q-x?LUU#|r*cYc| z`tZS^mkSksY|IWD`STYtrn3}+Hs^coVy8RZ3~yu@goNE&e_M-?yb!_q{z}vKq}6Im z{7$>vMS!i|uf?mh((ZwXj!p@m-9Lh{);dS;b4u>hrd;hxc^L>HGU158mg1_m2(+hV zx9^ue9jY26KHRKAH>Dp(zGNVl%??bO_BzH1$kPmo=EPRp`x<#>rfx`5p0x7oiZ3_` zfto6Z!7t`lL7A^sB5CYEd~+)$a8PeHpE_!LsJ66iwZCjDn~2JVXrRB|{KtN;&9%`- z7!w|j-*O`P*o_L|{5kx`h#M=u@1dlMHj`ldb98c=zv1(* zpHY|i9Xv3zUK3ySr>Pitc=9SA>Pfc}w50_3?9gLlmNMt*+nd{eEcX(UE{1&%v79(f z5!Cfv9h~qm)J%#56`;$J~FUt9xVn z%t6Y}_`wR7cz;iIp(8Bya^64HWNY8+{<-nf{oAV2tthZ{WYrZDd~7&_UdtWlt3x)? zTD=1iHbVu>=j&^CD&o;Yaq{wN;BXY83nwRQFiF1qe^+4QBbPa7jbY zf(imWS>U?XV`I&$;HD-U@Qa*DMZa(C75B^W+4ya-LWF9ZLP*71+ugrS3KlIBAHrBy zNl^%~WMpJd7dH#JNXopGhx4y3Yh5n|!4`)INYV3`6)e|3y7Cs|JH>UF_xL*S_owrh zo@des4Iq^1@dUn6qkQRK8_%+U4PYI|cURiA~zN z8W;g@$Mtf8cmqF{k0(Uh7A&Ypx66GgN>DU2{R@1v|M$PQ*y)JFoemeCf zzm7tjdUz|*9~CBbl7Z^JPnzl3<<1+WQo{Z6&?~|BA=OQIa0`E4?TH!bYee8#wn+JG znwRL4J!VgSZ`+%$9l%USQ|^Mshq8CUs;EOs3r7(=I{w8s2GB|7x!z@pN@_6?FO3=c za@=7iUva8kn=^N7!Z_21As7zY=KgM=TD&I{rH)yJlTqQ{rE)#A2 zR-9xx_oLd2yS0Ao5|__;^Jig^BwL`NzoD`!-asbYjWmiljo=Q*yyB)?}N2)B5Hk{qm^jG zuY#MuUy2wOvLy(XT@BNr@)cKBxFq5ZHTt`Y7<^fe)-63(uHIM?!*ln&&fDx7;G7+r z@^y;-%#1XQ@aBBQJr@#A<5P^&xDj(}h=j`v&77eC6n9D&& zK|KBF{ezmFy|?RK*!k{$hhifX5S!#vQ(o{=ZyD9A!oedixl6C=S*%?3V!wX32Y2^$ z(HNtCEz2`9eQnB~qPU(F&~+dMZ8EurlcQkCuK`))WTpRR3hO!lK_yfvRi>)&5ODEKQ?K^z{pVDKpTo`aL~u`Ch)Mu(s}dv(;Zjz*}L$FJ>|K>lh{-C!ZbXm_1wa zm%!8@6$?TgT3 zY$;RRvgu{(@EEn!PgXYh<#`t4PSK|2^XDk?`R*tN`uaQykG-TeQmZjC2HPv!@mS@( z5qJ3B8^6^tHLY)KR7wv@j8Ig=3rvchRLSCzKjsJ*y;De zQ*E8SLf_!mKGL?Ojc;0ylvF%k8;<+u*ED$c=ZKZv-P=!AK4RzM>Wo8srG5AeOH9l> z+5!$up~LsgYq6HnJL3EDaBaVw^$u{wZtpzW@#_WtS+%$&Ioaz#nLqx3k?!Uhn$X&c zSfuXtx{}=3@6}xOfwKtKdjoRT(6vEl$T0DSlf&@HVkV5^@JNMkol8U)q6Ho!qq56p ziEuX#LPf#Rsm=b^Hmny^9h4X>-u5uz+NPVcCQlNj3OI`@^RZ@~kGj=hRw_oCQVSv#}b6{1=j5Zr$fd+gmxxC{u zxBv1T0wGYtk$a5QEEJm2>==4rsZ0NGFLYESQBpmy8{33ROo*(deCH9ydyf78<4rn3zU%?L8=G5!`(_>2N)sG6qXzgfOOx)g1cSczTJpSGRg|#8%#64n;@2ebI*~?HbvM? zMugx@uE_@8ja*dL&QsY_ZfEOXM%l}>sDkB}sGrmW28>utS5kx7@ckl?(EP=K82Zhy z$e9_L)Q5HPZu4;5V5S!b!pyQEF5Cab)7;kY-!Xf2=YpDoMLt)VId8vjbgtsu+kQx! z_reVkF!a{;s0fepsn7wxMM(;`1v}=AE2UB;ih3`(4=tyBI{ioMxz!49ynBku(EHc6 z#Ugv^sXE&x#Jty)!9CqJ_X$6-yis+Q%w_RqHIKzvi?-Wg?Sy=--yh4VORn^5m;f}0 zKrAymv@MukYdLPNQI zy4rwqd`l7(n?NW3Cti!&6&0OUIL_RTPVpMrHfM;NKqJ({{-pJ@)HFLY z>tllID+6Eqt=XI!+Y!aYo3S*TiAq-%wyV14grQ6vv%k?k8`K|}yIjF9B!8Ha@?lCn zqqyi)TTZ)wtBGa(o*L*bFT4s^q7aSEx|WNGp1ab2>K@=e#<_v@s+hcO{hD`n!N zZf1`VkBm)pm2Zz62=Lvw(WkB36))rFhk_`ld1ZZ)lxBiU&NQhdBP)wj?>(4B{R~%O zo(pnbhpfKRw63DiL4NLQ%`xe}X6Dl{)`=zCrdwP4{kP&SswrD;z=~i{EZpkpc~I2z z(uj_n+wW*879z}@qpy|rds04*_@v?)@*))!>bnk)%(rWux5x^&er*TeDW!i|XW(Qj z7BJ=aj+lw;DdWR|G9!I?9h02MYI{7Vgecy7lS$(|N)*@#0RepT8+y8lt<@G>ayWPv zEski?ub_5Gbn~CI)X^YnvW(7J|K`Gmi56gl=AEP?XCZq}XyF@tcW76%Y6(z{Xw<^d zrB!>`+1auGBGuZvyMw0Ow-5Dj?cM7h;t2UXyS+(0^$gmz@EL?|A(WKoo4i4w8_Q;{ zj#Ymm+uxch3`yPMm_mUGK`b!xq$#8$*_s?&sD+admrRpZSjA)jFe2Zn7#<7g~8qrtSc+kN#O4h4gy(PG0GR4XlR(sqemth2S9*)`RdkK zVml^$;+yj?{tYB4yxtR!Poz+?sNY_Ch|zS;Ii`@Fn0OPy1~#5D%NvOr)dy1aj zJbk)#fVOn*HC5sZwbxC6`n_b$;|j*o0fSsvbZ#Ft1iOd(W>DOYOHmMV)u)^~^Q3$z z)|PV-5%FF>{}=DnPrlfVg=u(C(s8p`s^!|Mxtxvop4hESq0Qb6;)seah0Peu2EKQx zKci%3HGa@-nUZ88UL4@CZX(4nV#|g~CU0N{-#bj8qQXh0Ts*^Ux8j;-_!CC^&QlYU zdQD@aYvbBihG$;YKqx#d6DV!I89i-wd|_@iGm5sd68&@58)k6)(lSaCST(p?vQC|85aIK z=nkyg^?#|r=2XNCRz>jYmM36Rw>XZjRKK8P-*Cr4ZF^L{+#NW{dS4-Xc7EED#_P~P zowA4s!RNf$UBJLS;{L8Jhz}jh=>1gwW7+BTXIVB&S+q*_h6eoE;w<0AI+~5%-O-6W z+7!U|J>$^x=<7L4+l0_K(c=ApvEg0*_>IHuhA6l5sgS*flD?V6BD!Sh=u3+(<%dmm zU4Zhw>~Kd+3GljqE2wN4A6lktoUfv1?XvL}?fsN2M9c({b?2*c+WDh_azbA9>Vn zoCqe2<}w>K|GUC?F(`rQi>3vU>)EOV4Zl0yh!d5A=xI~JcCvvXbl0Fw&?-N%F zbFlz6Hiojm+#p9Aokga`Yb0R-S^v@Wal7erJDi(gXzUv+Ya`dZKF7JVU#eX<3_FBP zXL3}Be*GGGGBC6_-`+hz44|7}+d*&gYGA9Mm5U2AsW^1+oq%ns{n%8e&NAKongYLa zvyb|9pBCM1(L&nT)*ww?{N{ky#?76b&H~wA;mwJqEN38f5q_eM&SuoCADZ6qfJ^BO zdwa2-%G%FaBK9ZwaCz%*<(;PjvW-=X0UJ z=fmwz6F*1DMHz&Z&E{3+ex$<0Jfh7kEIt^h3%+yk-(^|iG$r;1+%{Y(7diDoDfQYs zPxLt zhret^p*}}(9%EO{q!jJM3=RG30hyt?-1*&c)N_|@VVwC(!Vr@yuVC_5H@|%wdRnI1 zy`ii*{rYwEGpmU=b#0DuH+)b6zMmor=>lRgR9CU0yV&qfyzJ+=o|e^Uj|qrpgfU{h zFyC6gUF+h_cS+0?~zOX#UCba9hMT?&+jctoEC&Hk91|ICyZF&QEod3?k*X_3GBsrIfH!XI~O3im$n2dfP^cccl}zgnMq9r1!jT|5mdIPowsUlf$wZ=dsL$^4w9&0%!oeIMOJaQU7+g2#5pl7`vm37_lco4dW`qhBeGUP~|6AmIb4KIZF{HON3GJ9g4f zy7{p~b@*Qd;p2+pNp4nr8n`Te1Jyyud?~)Rg;3BLb|`8HdgKm1ARlO9Z2!1_GGp$Pj3IQ427krO`xW=uXIjnh{q{e1`d$n-TTj|?N*q83F&B-f9ooXby zxVfZ{N6{P%bSn_dZ0x-`Mb^LW#!r6jrF6RO_CH>@p<6fU`ON$T9559$8)%XN)lja% z7XVt1r>y3=HiqaJbKK(BKgX5TFJ!Q8h81&5#^Jb<;OcR?9`s(z7g$XP<8x8~ z@6b4c2FU|iyZ`K~#+sQqv-Keml!2i2r)ZcbmlG|~pzcUoBsLBn+P~R<7^EIFPE>%1tf*=oxdV9&p9qad$ zSy;^8cs!79^=k%?!{Ep?mF`oS$NZc{GA4Io5?QZKABpbRd_xHvAAU`_Dl&L|_wbjI zokO8}T;X*z9Lp_G(*}U*j-c}`AbCqHIsU{IW&R5!yZcs!;m0!R()XWt32`z0Q?m4n zsIU`#u2L3MNvp#;cT<&lAxAopcyfj zS8_nD5Ndfs?qti0SXt?d_C;^&QV@w%n@AYtQ81$$`j@hh!9?_%U-#6=7> zx3m5laC~NU69`S{5Q*eZ4iI`K#=%b_8%hqT=XHR|O~za7cPJyTfk3R(4E;hMmwFiA zgFai>E2C@i3MjjIQxYU6tR2F&TT}EP(D(G>C9FZsDquwuH6}XsN%xrf_+*;yK5&FqLyZfRZ0kNVK@#@>^0bk-EGyL1j^YsT4O3KRl zozKl(3VIRaDzf9f0hb$h4Xahu=4BW?&v4Ir)0fR9NB+rV3 zLEW>frICpy^Qg8EA0Kf79A~vS!V?mA2glbnHE>YyJAe}Xlx#~7?P9B7RYmBeIgX;t zyF&H7h9fvG_4Lv92L&c1w+__juIR!YgtL00T6yT&Puo_kuLE;KLmu0NqoVG=d$rpz z1K7#@18yfJ8|qqHr;oaM*7+P&DQbPC=i*W{RcA$jLJe()C|nsC=!l7_>L6g+4%ZLv zxg15=h+czm0&QU-6KhzwvB(3!B0>Y-=)pdXFXlBMKPawzM{lQ0mCrwEY}4=gvXQRn z_&MXfy@wBYv)?8Y!RlqE_ldt7-G3NNeo3mp2Tbx1FJ}2`hRCN1I(&rF!IUEqkWg{s zU1FA%SmKkmm;0P}%Z;4GzmAD1qpy8x4`KIob_RJRCPcopMopeuW60=^6!xN{i&Do7 zEfnuI)uH&Fl|S>@a&ftlnVTD2#3p{>;2;T?4Oy89OB=x|fY_QXc~GWsFC6S;=20@L zj>T*?8dF+M6D&%)ng0Kqg^ntw5Wu{cEhA9O8P;CN@*k@7t^^lGz=X%UG}6e;5+U6` zdX&qW@u=h{KpB1jcte#|zW~ghx^7}@0k#C_2PlZXKI({E@|7NnR25+Yk#G*Tx>gZ5UhQ z&VjXLAbPdc=?e-qxIob-xqL7#I5vm?HQ?VrN5a!3m(o<0yZ=Z5YkHDd#HDU}G|Ug-n_Y8QRP@V>{(a?>0VmHRIce^rGhZ2b}S6)`+tb}(jLvJNi9pqhhvN~(v8XLFN2aK0< z!pe>xAB10>cngM&-gbQ`h_Y1V%ii1=T*acd^dsAsZ5sHBg;D=rK*)?MoWeMkWP`#( z@#>WC-~U#ye^oaX70ipWcW3`^HDQ2|LWL35zvtONA)Ovp6(e!s_SseG%YIIXkg&lU zYyg7hzzb+@^nZrABj%HDe))cgxt^APiN;~!&B@hfC)v{3PG9>0wIkB zUoWG*iS|SUW)dSc04TkYnY4J2_(SqTm?uR6DK>&^@T%A`!CJ$_cEg2-r@Et2mSykc zwO>Kek~9->Q2XMu2^QN8L;l<~1?`t5y-LR)+g6hpCAi3e541j6bP^gG7nIW17l+zU z8lHRA3bl^yQ~W!PxSv|}G@ho0hMeZxOs*e6ZDbJ7{;8L!n$3@Z>OWuoUjJRp)c%TO zm%U(67@yTC{r^fJam+arM-Up&o|DPVecgNs8y$`d%fvfYlb~-`vD%G>rW~Q8<6~w0 zmwUZy(P^k*{sEGMhqof_F`+6Wd-f?+F9d4M5Rx4F-$xcjVoAjq%Isvod`N8wp#7{o zIQ1%SlcD1y0qROW!IF)>yjDory1^!&ol`H;mAa3T|7U@}si`oCP&ZN32u5zU5n&^z z?gxAiK|~MCzAf;>1bin{>uyk*mR}S>051pNzs(jEEnbIga;?jvx2W%zjN^&YqNPao zLMBnPZ95Ac+L~g0L7UO{XHVZPzc`v84G$6e;)q!+tiV8w0}rS7j7oPL`7QwVGwycW z3kiKH4;f8K`2fV!(2AiAY`mt&)etEl-NahS`m3LaI zTB1_;jo$Bd|J5@Cht!F}Lp=7a!2G2j+xV5V1nD#QGJmqW&O-)t=1boj8x@ao**rx5 zh3MtPe|$-D7yDfaNjv6e(msUMQwwd4>*4sP(a(v+?NU=4mKtbHmdAQ|0cPER%c{fN z?fvfp{pG8ry?;gCOwN{K&=?+yJd7TC zlGE%NEqJe-i1z#rDd}CiOGR4IyB(8El3LOL6HQNIDp@@Z?L*+Ffy!k+9UJiO6&Vak z0E5U=ht0&qm545f9@|DwMw*7t2|S~rTRWp*9WgKvb`18y(@!Yn?C6->@db4`y}ZGD zP|kg45*XaKDenUMq7(pjG4S##T^J|O1P%|2{ugC{BJ2!8@|xi8s~gmN!JVYq+B~K` z5>`8VIG{Nh7q4o(&UuwggEREM#LOoNE|N;eai;HG;(5oOE>yvVyzcE26Gb%q*|Ayk zaiYfbkaE|hQeMY?-soUHJKL8c*l!i=Q-2;iD#$mYz`WQl4`I$oG(QuBWMCHo%))vZ z`XzH(M&W%h(FFnd4FDh{sgPt9 zGsxAoO>JKJ!syid;DVvCz56?Ecf_Zf&^9*Ek*m|4T7Q+1GOJus1_-T5aBlM~nbFX5 zuF%I5XGpV_#M^L@=q`RszxSj`0R492WB#6+D#vIXtt%9|GC~U46Le=D0wT&w!XJuU zB;B{4U2p$5^|NQC(C5=(iq8y4-4xoqbZ5|n`6a#}uyR}X)SR$kANa~M5!2HjhmSUY zSUa!v*!G9rlI32*N)Nrxc2IZFcj5*O*HfM$mT-p=mxz9FXCP60XQ%ER?lt!6!NET^ zt*xIp;50zHyFLebbjlZbIWKe=e9Yst%hvB=J#!n(L~$AU>6{U7FZv(FJN##z;D2t# zquECc55R@*<<&`u{e9B$pHKgdqG6{e@9*a2sf0ida4Q%nD9bhvIPzx-EY|UkRY5~@ zqv8f!hs2qsM(l-`X2HHfOUvnW5I<#P->};o3%5{wq93n#{?CG#O6HUmR^XcJ883=> zMif2JHn(DGo(G|qju=P3pTcl}U9;FkWmL>=`oRY!j+Bc{xF>Bl$aHnl;H`*p9 zkna*WU`!|qUA6>B5f#fBi`aN|d2_Twk_A^+wNE)NF61?%QNDi6>Yj|1%mC{0)N&bt zjlP8Vihv?nsM27jK-jnp6wx$L z-Nf4PQ!db1jVAb6&suOm%m%$9hkkLxG58u1QWYrh+AxmI^{Mv8ZLeKY`BC)Kt z%pWN^FSbD4Zf=shMSKet zW=PXQk;viRH}T!TA)|=Rla|-jx#{poHM7|E4G1eX8F@G+>?BN4y!<-NF$#3u$TDfD zmKwMq@Lpy-f@5>kZwoJ|J-9(6XXVj#7uL^)9nI=uVWNqS@1wUt`;ZNLY>tBH=+J+I z-4GhU5=KbAs9eo{Z=mz2ccUOvs0Qd|?ANbXkOf`wOPn1TzY{mzwM@!3V`2!S3$mKJ zSdcdx;mp5QfNdgrBJuj|Lht)|MNdy2&h&Fyh}Mq{Ybq-fQa8JIr#)8uNlfYW=6|e^ zE)Iu|ec(Ug?)9GyQ}i;pBXB)tSd`@k;NAQpr~jxR!3lBhYJT;14 z0H(!kR2Ur;&o86uh=BRhXea9x+5UNa4BsYqfsZGJtbq!w@6R$gRX@5(E<}!0RN5C- zZuL&c*jcjQ`=MLx|1OVucmJQFt_zQs?EyQdt{Ryvl;1{1jK6;W-=Rm9;@|WPzJlE&oo^sZCx{<9;!0q;Zkm?dIbM_Ym!Zi%zg zARmMzFhg}U%I0%}yDzsj*%fC4WdUP{jehj^khudhO#|@8llqm_qHYppK5B4x0A^q* zCz`Z=bTwTYvZg}N@&DnkaU_3)QS1Lk;mVj9{~4uNFj|1~-uSHT8yrPw;K%BLDps#>iPRhXq3iplGy44c` zPLn6n#iem^7~uVRBiqYqHrZncldm#kFfh{J6^r|>9=~|nbjWBwnbz>QE&fkZrAvov z;q!0h#;J0^p>aH<<%J|VQRkYY?Ud);USi* zrR7UnFFNuIJ@r8v>TZ1q4v{iTj@-DCHe=0rEs!kmA$6m?c{gWucB0!{%3bIXG-qQJ zPn`Zqru|#bdJwT4GahF`tvC!tE%|Zx|LW8roB!0QvY*?+^DuQ3RaE95s*sUdR4`Oc zJ+rm3>5ULY4a}rSTA2fV01amK&6Zf&PvpXqD_Bx1tiy9(;0z_mIIY;S6g#Az1x_-8Mg|DL?RshgEpk(V>H*~6svC4lS*t*Q6hvj;& z!FH4B-eQ3W7!_>Y_4mn4uPzc}N}HwB=PO0Jlm6#hq7j>bTTEz^0`<&#l+l-W^o2?W zdSE*IMwYK(@G(Cw-KF4h0gIyM(t&}*&bbm)34e%be{~+&OgnrSbu*RvD2L-!G|p25 z1&`H;L&4Pk+P6P8)>IWwbrT2U1<-{_NG<3dTnHG8OSBeb0CAhwKP9j86)m9ltF2N< zJw1GBd*+4l(Lna{9VDAP#mU~A&-RsQj&_E$ZxwD#Nd}AXIw!DLrc~cIet98~-X$+) zxNizd9?WCRZ2LF2PaOi)S)VaARG&Ws>r!HTKh$CO0vo#ufR$n{q%#I%2#kLTu9jiM zz$nD_ai;k5r=z6%T>Zz7nD$mNNDd?);BEd>`Hb0ftxc0=g+4K-16Wj!yPhWMkLUB_sBO< zRY>~(bmNezP;@I|aRVlH!^*lR7S?|rkzX$_r(4}ugXF+@%!3$x5*;Z?R}tCVj04U$ zG=#^+GXfa~(@VC)M8SJfV45hZq`DavTzN}SbF7@t=sPpvoV-WlqnYM^EbO1nvT5nS z6Nbn%U)|%csfPUm(a{rkh>3kd6F{Q9kpfgS`3atv=WPU({-shFwPP$$^}aX%JtBXu zKdAfoS(sknQswk$<*j3sVQC8p!^>bAq9(CdYsBQyp`{E zYKF35ZA2YnZ%*?=YXMILWyO=+5kPX)#@ebEhSP8Bkt(QC?LNJ!of$shi9+9x#^rGD zA?7AcjX!1>!Y9;YQc=UxI;Xm)7^pc7V^E$s%ssL9bon_vtkF=e&MK)vFM?x@)AuH7 z7o1CQtbcznDX`z49TS639~$tU&kSZSTNQdnm&y#0u*DM-@^$^FE1pTEA!`>c%wr-l z6(lXQ(A9nq6Q=?yMd9Ne%G+v?)RcWC^RQf@bfG8F!FTc3iv^KMyVym7w*mRXJD<0= zkgXEoZr2g}AMFVhaRvcL%Y>3PqHy0tCtYk$kp~?CwxK*(Tcdckn7{fdJ6nx<0~8Ul z^ZTD_M!=ztw)1Np4^QF(p$caf3>3E!;6kLS{sVH$+c?fL&AD1d?`qdQ zkK$fH5~JgxdJ2~{>Uw1QG7NF=379JX{$KC{$cV~^L(8EVsdFFGih@EQXvA{_k8i<7|LpN zATO;r)yP5n?H*LN=9Vf$_dNBXfrvDpvhzk2Epw+IA7FbCQ3xtyQ?X|dxuxVp{3L)8DdEZw@X#hVG^N3(4aB@nzo!N5VVF27RsI3kRljbE}8t#64Wr4}cFV|a07D`+=4LWlwO+K*V`K034+c4V z0V;mYbEA*0Nrt@Okj(t`kmQK^flu|+=MTVa8Q)*k;@Fhjb|4u4-1>s)~_@q zN0oxs0;n9z zH#${H9z(?k@B6bYHvDWhhA&Gw9W{dpZ~2;VkeAm-l2Qjj z{mtgLxtwdhilbdK#mk}xMwfi!qkF6hp_1xg)qz2!OuEk#4;i;<;mQQ6Lx^1&_8(FUkG`|Xwu>Hs>x(75O zLR+MGOa^S*rxN1b5#rJJKW2S~tw7i0fsKvNtDi$+nW%b2l`#8qw06F*rHc8C-~tu? z8zDBE^HtxtO`2gm&}TFCR}BWf#nF79Uq5jL1Aebk0!-Y@kU!GE7;4&5U!UCo0!3mX z;?@rD=mh_e&t_+*sP^=S;v4fRly5WgCwFc@zOYm)3sHXpBf2OH?fQGH#_A;!CjRV) z?&y14o)W@E%tf7?RB%Hs2)?b1iHo7=aL{l zCrdga0(=jQ}yWNtYMjWrwd;qzyoI$xDJ3ozL!sQBc?-TeG2Xx)>ElKIB`SIP%|Uj-LEzd6H} z29A&XC%O}IhK2+OWEpwHw1{t$@7TwRp7jay^Z)|a1`0Ypu8Rm-aNT)8gx zjYnlv0|VbIc#VpH79XX{V>6{!dbG7Ir3xj5oR9?d@pAflqVmL{}gu8D_On{_0w2lw&VI8?2dm?h{4pwdGj_V>L{$`n@k0)BV6PY<>o z=L&cbbc|w8?Wqw9i%n@0H5S~q^8~xwp6}Dhv)vM{RgtWwi_2jvXu0#HjIHeK&s5z2 zV#c;TF-ZB464~Y8_3?%I3G^0C)LVn!@8zUAUcf2M>K<;T_v({Em1>nbrxjbIV2nUg z5x|RlIg3uKK&h{X)ht|{Ez{ysAi+%ucgLq55`!PR z_iWI>aROEgcrGW$O+^l?ZSWjNEk(|My>EwAd;j@_7u%(oNR%9T-MACBxU`2gfBYk_ z5#-|wtEq9(kz@{E1g5aJ)U^Amf6VqneSL&IZ=&vi<_`mHo!=_Hx1u^#Mc>n`f}7R5 zm4~eY7qLA%8Ijc%Me(Oc^X)ZeEbVq^(%{n%f;L$d(VIsvye?7x?KGAFlK$}U^`80583jH{-3huA;hW%$FkKfJ+G(<@*-75F)y zRobn&=&wGqeIR~mlOjVZzS~GTZwH;>FFLMDi~J<|jnC7EamgZg);|qA86F;P1r6m> zwz=e1gO4fxGSho_UA4}xVpE<`+8@6+6mX-d(QI3km{(r{L9Oxk;|o(Miga=D%o;oP zjTf3YBO9o7?)sQxS)|9~PFI?t;g!|esMrCM4R&Bo!7fH07MA?cP(m!hXgIA44NL|0 zIyh4fZ4+D)D^m*-Ea?OcEL(TYt(ALQ#H*~8b-7oR$75_LI|r?HxYP}^*$4LGn%<`m zc)G054G@X%b!n->)cnqF4GA;^vVrT_pmt}>WE@emkn^S%!c2Z*?lRFjN2_YZ7!d$% zJWSuui#hVMve2*8ZdQ6VVdE1deO&%iw8>&|MBu3uJhKu+NrC(H`85lESSLdfM}V;-qhs^ zTC^m2$7v7&k*m!eVlDo6uJM6`zM2)l#o4<8OxiYqLrLBXLuv^TbZcXt)okJ5ELomd z#6UhM=$+tKVx?C;I$#ADyLEpgK^lAWN^6igeYVtORdmkF8GZjdN1L4+OmXQoOtdJkAC^G87aclr;@-R^Xj z(%UVjyRM$J^oSa7QSjWQetFBDU8TKEq$sMe zcXqx_yma}qX10RD72L@Y;APO7232FC#WG^pRa75pVJdNM$}@6toR>DSLaU4a_j1W)e%{^46(sSc z<nSi(NKyARhqE**`}}du94D9x`EWEKh|cTHBeH@kB#~9tnPYfx&QyX0Ok$FNxvQ_ z{ZG$nw6FRA9H^hS7q0Ajl-KpIs}v!5R|lN z0cjN}MY@rYZjkOy0Z~Cxq)WO>K}>Eah|Z$;SJalEH%$D5Pjw6*x*oBH_*y? z!#I~PoU`vmss3L)a4HXd1|g^);OYU(a%TBh5A*LqSK?ZiE);r4%9%eZR_ZU`!dirk z(Pu*=0CuMrFpuP1HB4niIRwBk`T(hdK)&Cw-05G7H=#&$_~^n+nwtL(Rp8-BzG$RE zh5hP76j1gMUTCggkVWK*m&nrUsw1@e%QoV`!`|k(^F7uMZY9W;6+e&~fIN6U?g&?k zzVPh*>+Doy9lM9xL_|&mTSC=GP6)h5#)F8-{ZlGP+S2RcjNWNK;Z$PY0ax1XF1&&( zV6x?=Rr#GIktL|)jVmXal=X0 z4pkle(e?$S{-lQv{3alK&aNz=9qkCJoE6vO_9P!e17q{n&Lx)Z?Tdy=m)9KSmXtwO z4MnZMlmgTO&w~E1<^A_H+vp2;v7j!h79HWSvs1%{nA-~`<8!g*+z87BxLLg8WCgLv z4{oFI`Ff5fkE_7mav2e*(OG%7S~oWgOsFP7heLlT6t*u?z3`)@4oQA@RRw;=i~Tq- zy+GQb_~(05)nh{wO?LKY?cup=#lNYHsV4>TPcJ@wR}DmJK6{lSjSzytI-v8jJn%9` zyp)D9_eWRIx8wV{+q;pQ*!cCRkIsz|qG6CJ^bOxf1u+LIxL*sVfwl<6t0DU$<*hBJ zmtp|(k)-Gv&pHOp$M>VUJAXQn&I_npGC!N5+Od&0+0Q5N%j3B!_`ovogB@X~;h-{7 zZnm9vA>FV$)N}FnI~3-TJae8CpuwQGamg&5R`M(+&gzKoabe+3t$bP9}x&K%{ge zJ(q>A#J=mpZG$od?3fQa;IgheB;S8C!Q z2kilP@uFh)#7vWsTRnM-8*;vsx7tdilx{B<>t3q9k2rNI*E^5gK$;bYMuS4#C35fa zMXJzKU{jL4!Me1h%1}mCEH~jGOUbT+#+|0v42*7z7f+_?fNmu#Pd$z7u~Q^#5m7^y zrqf@=u{N2(OBASo_WC(CZ6Q(SH|i2@9R2+zOpkE{MvN54a?Bqcc%5+aU7_=6a+zKO;{UkKe3b4Rx7E9hikj}rJx z2?F8BUnR0?d7b}yx0b6{=kS+ta`G>XV4+01c9D%S8X?g}mUqdNZ00TRE?;n-IoaPu zJW}b!hW7Uay_>AuW zNKoVn`tQ|CNKg4H-0}*S#f3ya+uX|3GO~E#GN*s+(OXb_W-pIsT{C4sAO!$@edV6f zWHNMwPtOQt2X3gPSX_T07+mou1ga>#oA<%<&djR~C9r@NeLjDqz{V$!j9+cX4Qy%s zoIUY5%rD1z{}0{#x^dbl<;B=ksvB5$8Su626cN z=OdYldXv@BC!Bnt?Q9ZmlcY@Fgd`Y~FySTYaLw zlxzy#xVtWsTX$667AM~ZjxncLeZKLAjsYBLs{HXx?F8NJG18}qpsm!q3zx|1qKr*n zu#8Fs%(THJE0O5{y%UyPiveePh+QVsK5WRs0Vh^sG>;Sd<@dogUOmPz*{jCh`OIJ- zS^HUuf>8E2_rl4_&Y5okpEa`RX~Pr+;Aj(Mi7owAxFwHen5T03)DZ8Uw`Uu5Ky=I3?j$6GJ)Dk#P(kl@VlGeePzX!vh1N zhqNXA*`f1@R@lVzd!ETCL@MMo;9)_gX39UiKaax_h649sAjKiQd~X|DT58{RcGDPX z#}&M|9s&Iwz@H!rwFBApV5GYysE4*;{EFL~OHL0k7{pyz_TpRhGW~V!=FoXVhW`=j zBS^tMe+i(!xpETLYo^#Cx!zT!$pN)1*9@4=qdIIa>WRo*XpnU$WZ~#200k7()G(pk zO?9F&$K2|bxxeCqNBaIVtj{x6a7?9Mrf~H`GodOwCAONn_O(aSM^M9(OFuZGegM`RrjO8JALZPC z(%vp22^F^N?4Mv^B--~O#j}3k zu*$SJiyuVu6_`+f`p$kN4^!DwqvC`}nA36^ zs&Zpy3e(Zfc8sUiTKs-}qd;1!va)W8+Su^GkxnL11S30JATj_hFDkWdf}9-@6w|&j zE=(EcM(b>d0b1Vk<*TqJ(15FfyXspIfkMtHB%iNEEA)VnU(IHA2PZm?EWJqVBS@FX z-P<)us~JHqeEl?6v-$n!Z%fGf$+)lxfW=Uqb@$b%lkHX^++038+nW+;tY9Fa15YS) z%nnH&DgENH#cR2WVwL;`#MlrOu3p{a4h?v0^5G-U633zPq`a913JfcsB=l#_*jn>x zB4KJ}1!?A`MubfaPrB758F$B9CRnD@ggqHKH_nsmP6@1Xrdtpf%(4m0vempL9Hp^7 z>x#EtjLAGwyo$0DGQmbbU5TYFx+qXEkHCp^XH#@wBB{ zO*+MF^Kp0I8V*cN(p*9NV`+(Ey=#J5)kQPqDkt@72oKSifjd!T)=qKfnvw#Up|XpX z;>s$P)fWBZ44em6W7ikx-s>zhR1~}|pluzHd|`nf+wsa0y0vob1-qbf;&4salZRfR z=(TG5DN6^ll*kF?)qEAk?w;B@+5B zM#~mt;OByg(`URBTy?7qKXhYKi&W#8sdNYQr?j0DcD2-rYZqA8?Z2K{9kJm!M&GMu zfI&IRN9v&x`bSuP;>=Fc3f5N7oVV>JDwi#GiCkYxuM|U5IduyU|1}#YD@>I`#COBZ zWioy;Ax1hh1@*ovr;!o3A1Tib->nH1gyklP)YkgaJJ^cmrqEs!^sp2<+h24)Ruj>D z@(^2E`Z~-&B@(RY4NP#QXMT9}CIeqbOGeoHrDwfgt_nfAtcmBt^RockkuR(UJZn2M z$G+wmaj-7mA5RLD60o`-i4}4+!%`!rtDv%~wZp0RSfm@e&Hk+AYwMuiy_J;V-;6A$ zw*IZ}?|n$vNYwqd>|~xC9(?7r*kMq5*h6@d&oiM9r98lfdzJd^&miNS5B7a4I8Z*L zu`;s;YpQB;$}xZMSWVFUFpq{*9b zHHp^SJ5B(f#?-DH{W^Cw7vjgnIFvfnj-dhiU+}=;out@N`Z$-HZaIJJK%3oo~Cf=WnFv6OuA0U%EsVbGP$rW+Yo26x6Y&p2qKn8U*kzdcvK98#>53r^Yj*c zFJb;#!ZlKv*}J`cgG?K*fW5OjfB&cPJIA@hRFzlVE@5HQ!ZQV`1@$FG;>w4r9T&}D|Blu#zA&Hp^E$kOqFB`@;**pCZ2JB*!+7<4*QJBr&axi$PcXHd zvO*mkFy9Y!pIGdz3t@DBobg4jtfNt_??2?eRS#zvw~+*sYHHTfJMH-OrvymFXy~nZ zLQLNaNepQc*C|k(YYI)!C;BQwj>u^|K z8dYIk)4ZyE?fz!EI$6(8sY2mFb0N>EuBIkpAs3->`Zcog&1J66vT?OflZkBHmOBqW zTU0iyO@CePBMdr|7@%P5(&-ug99{0OL$r3OxqweR`PfCE~$LEBBnj`AwNm ztGHx3DCq|-Da1Fdey`}#5lL^z|NVTwc! zLiH5{p2t-ll*drpsh&?1dQ*YbeRh#FEQp|mxZg%8Khh!&qI`f_$)Uk;h#H^EGR3t$ z*7ZqYI%Ld-UlsdQ=ld_qzAU@Weaq|pdg!#D4($917bjJTuo0{;l`}9tqG2_7&FkO) zS?GbLE=&8f@D1tONbMEa>^K>O)YMFUYcFB5Rn&N|tml1;f=vOj!P@ri1jmc~o^n@D z1pPyO)%=S5f+?0JU4@0hndHDR^TvW@u41+m894bWtB=JQqQwefRjDY<*{HBPJ~|~p z&Mlj8Fx^YD8@YmwZ5|0v)+cnS0*20Br~280qELNad8>AIejX!T@x{q?g{BrN2x!aG zYs8a+zYNjQr6z63Q#ZzrU*@|EBc4)SX06`{PAJ1!Rb0UOo`(4lL#FtOnMys*rve1k zNL_gN+H}CPO@fR83RutpjG&`O$%JFZbBs-@1IkURlc!Z!j@%z7Z6_>MkLrTfPb;U2 zJ|?zf1nxDh^S2ku1A7WT3;9$AtS$6fP$h5h9?ZB){BqnpWtsw4NY7Yeywk=PC} z11=(iaN|h^4xd1W?t?5vrC2@J#@2Fn%qseZTkI_-5?W85~#cgI&Vh z!~K^`cl8=J9*W%J`|~dJ{$IVASNctNJKVRTA1BWK+Uw;{mQz8bD;lhMFSKa~hsdxm z{-y|}nO#4V7k_~1i__X_^f^=O$he-W{*XzF|9Js6V2?oTjHMCg7y|N8Vi?L>o)*yb z@y`sIM%kt}?~D*=mBP)@;-RU-zw}PuRq+)ay84w<;W-^XTHf=2Ty2XE@R0aAHySDJ z*`)H>{N^;?rHc!h$N8}$T<~L=;HC}{Z3*3y2yWIMbgyWGX~{>ru6a7U%*eLstG)3= zbr!U4=VH2+YO z=q#GvBMK9jLqa)V^dw2r8$APmd?rJqZw$hY@l$uQmGoS7N1mJe{K%42RKyGkx%X6O zBE?f(g@gSW+hLNRfWQRhRvYaq-K$nNAuXymkmPb7QEz zb*1{W7MKwuC_JpUb04s_%{1v~gZj877pc&}VdvRDV;~bV<&;HTW||OPriFsFeU(4HdnvoJlHxWkd(asUZjEoHNnAevK1}+w($)gZ25=hD*mk>9<3}{yj(&z zEKJqbc~#ReeYmCnDrK*}rF(a#vf(O4g5Cqu_22PReb+vXnP<%=is_G>=KlEX->RSU zNBiTj`g2Qu=ykSvWV?HSJ-X%kLnSh9&0CJyu7vyQYo0Yd9%SovE5VC>x;^uZ4_*Vi zu@xeGk-n#%5_{!u9#^|uMIJys_f+5j3J7h+h5pSj^UOhhMs z7#iUv1sbMMps=DmjCJ5YS~(4l>J%b^b>nnsgyerrci}I$Qr4S>~O6EpgyZy*5(sPuD<2SQX0RBhE1Qn;aVeSU58w+!A=BgcKC=&|sY) zAo3$xu!Q=e*>gIjoGzSlux|>#9JBeEqB2G)T{fxk2reymYIE;|L6u$Vb4F6`ot8zv z^K!eSd%QfQs?}4J(a|11em-)Q6#7(-PvccFEfUBKB0T zlbcIdI_?IUOi)_0J&bXInHxt#2NfqL{`!!t7N3oakExS3rJ z{mPi-PDr{xIyL{^-(nEC6!188z~r%VhLM{$zW=BWOH0EGqdfJ<=v}xL{?WFOMYrKH zcB9>}5W|a->KgpwH9QxUx zG(Wxn%2R(*_hCjB7gE4JulxpTcNsIC&Nn4(ifHn^1l`spyYg(sVh^vSv#z4`4Q z&fUR45==Y{UzK~Wk=drkM&fjPT)C0D--hY$vmhu4y^;1ocK?G`+6O4Q7n9TFVnr3x zp~Y(}*}{upCtGVHwD~>6sv*-w_PYNo8)WR^aN=`+_pN{Qnk^uK*TV~UiRa}+XF^FA znZ@{lxI}yO@_>VWzH1$;9lsu31nmhK^NVAw`ZcJmYMEex9@F(N3q~3zZpi32dr=!G4P<4zwaxZM9@F^YgTN5qHrv?`g0ua*vu zi&Vp4?OGr*cpnnbY5IwudY0CtDt>4*qUlc`VT5(Of?0K>*`|M2??>8gK6l%UDQn1r zzdX}8B@x|Gyhm(wUji?exGm1ePwGy&0mstL2|Gq5tKN^&E?I^ghYQm`>=s*ppMFMM}R z;0(VeiNiF_d?J#+q@ZJ$OuqNsa=$AMTzje}*8-r`_Of53i}&8RV(E>3ujrt`$`Od9 zf(KQzMW$?ar6*B6e5zlEfqzBSUuY2E4?B#eCufvuc(E2hZOQ;Ucs)Yft5T+a_<($U zJrBvPWK39&T&ZwN=UY6vzCLqGgNJYZVy30!W&nX_-S~8jmA&qa*wtT|x_gy`H^>DW z&3R@=qce~o<#R@x(#dq}&OWZ>VNy)LXI}~aG>Kc+2Zy7@%pZ>VP|o|HJ#XY7Zf&me zMxOdzTvx{n3dHvJA-evGnV5=N_Jfos5)%0SLMCscESG2>bcWnSoML6NJy#B+C+8on zr%=mRUcU4Q8vF4hqa(nOojhj4HRjoG%bEzizFY-;j&j%c^$doDT4)E7f@FoAL7h9U zFbMkfE90AwGTFSw%)Oqk_(Bq!W>*nhPJ3W!)RzmS57yAC`O#6SC_q?8A&p_bVRfI* zozp1iV}$KjE^+v|3VH16L+5LvH=@hbe|A588e+q}Lo~nOm=3v$=}U5I>crXA)xdZ8 zHRc6j;vqCd^x`dG0Xc0d!*(kYnLvsSG7?D4bFz|JeDimFjKWdc-?pjB33G*0lM z6VpilJUMkATXV8gTtL1dixH!o30})Dic9o2Jh*_O^j43<|HMNFsD1knfmqGKVJeKD za+K6Z@}TN}u4tec;`kqmh_JcCJ2y6awArTF)6>Bk+TDS3Q<7**>;B*xj-LN;K~&oO zNTYs@$in)%>4b4-ND&i(+^{wmXN~auFQy7IvSB07+k)@Lwz$aX4q2b~U+CY-DxN=F zx?|a#Y3*cXlKCB>aZm$d1_=Kykw=>*1c9D!W*rk#-uv-Mxnb`_Cig?BC_H3i2TBU|HiHF z4H0k(27My{Cc@jx>tK1v!7aRicXMJ_{T7g+E4{UfpO>O{) zLF{y!Qr&{~?7XF)$6Pl*nU|H5hw+9bVF44Z1VFHBc&0}u<&u%pk;-F?zrsBY9A@yn zJP*neLbKSOC!FV-R~fc@eLbwo+4cTv@bu-D?AVgD!xEWcXU>LAY5@#ih|uxmtSc0G zb!0v%vQwg={WJVjSv=QrCL2Fo0INNMvjyn$sAxwNAeDQ13byx5{kIRqVN#^{BBhVz zEr9V6G-~P}Z=N%RNy)w@?|p|Id2KvJ?cMo38fii?%-tXs#_(y=MNuEI$tA$1~Y@__#iWf@@LS;&J@ z_0ZPpyi!;pAAcJYfn?(0Z+9^ZQPX@%wchuKD2|R^8kp><8b@f{Hzl6i%{8Sxz%^#Y z^_0%pr6QoglkW^|e9B=$2KoC7siiCr$gYxQ!1o1yYr0}fA@BSKt4Sn<1{IZ&a?wFC z_iNO9XCnXO+kGZ~bnm^M`}GTWRT_^AJy>{l>9ht2dj6Hs8Q!(8b4zpqMUK9?wZ!bP zC#-$7G&fmj+RHvK0Le7FL=n=r-Q-B<{(z}OEs`ysaQ1g6)~`D`TAi*yANnumCQep^o3+``pVx(Kr&T9259CH$zCxg!@g= z)r8sgJikaQjZ)L8x_(RjmlB0+61D?2pEGs5lw)vX6tSeGjgfT0$}r^x%El~RU;R%) z#p#f@B)AYmBprVmW`*2K>Hj4*Ka2h$6sxvYy`@(K4>B;Gr{t^|z&{_aD!%%xh zRnm%WY<$zreFC{EftTR2mw>EXd|)^o>Qe(nbD{TI;;7Vr?T&0|6$nXsqC)eF1qu%XEPVkjsTMM8(`K8Q}6}t}@A0;G)6jW25 zh*f{WeSl2ggMyY1jEk?`HFm@`8RCarsa=pxc_xc@>J21A&TD1AA;8Q6HX{7ZJnhhH zNj%I;ZbCw==&tY0+&|@uBoYfXBA=+1{2_ze%x7c%#+SlGfRB%%bc!C*^r4is>?;)h z6bu3p5&-7Jq*EunLPJ@QKn(aRG3nROsi~>^dF&sR)eUfCLULJcpFf*@2c?W))&Hkx zonM4v{=7aZ;?ZPKz8Vi%zOPG~L)0CPo4{D~6`T{5PphH;s)FK_h=XgK-%qrzYA;*& zn%Gwwm(s5lhCJJh*bYjC-NkBuHK>)uuQXWfal)~n;!B(4oWH9;B&k3E4c!dSHRr9+@cQY}Av<__;8Nb&u}@+INzkdimr-eA5`lUF{w4)$0is$j8p`ZOuWUwvF4 zw?St8etVWeto^^Qo;9rQ(jZZ|7!}i(QqajQ;_jg*yFHUB6JS>K+%j|=e_lXlTFZQY zzb7YdfKhuDNMQ_?9V9`H=I4=pHgF?|vtFvHR-E7?GW;K>ZeU(XL~e!0e9YP;R!H^R&FihwhSc``kE!ky*Ux3Pz)&??C=z=t~okU7pkRv0XCGs^j zHR{XUKl96$5RyEUi<1S6^_g7}y!x%1m97sc1jvbrxucqWl-SQ4*>P~6qdyFb`P%v4X?((G22VGy`25w+`c_(y_` z%R`GE_G>#)eZ}wyDFHF6?k$Kzgkt^liAVZ^)Cd;EfVk;!OLn**;<<-P*dF#FH zLLj#g&}GADqOw&)7*ASy$#(bgr#Pet2fQ1vx*R;_R1TdJCQxsYT9a0_+*JXBe{V2+ z9u@=I@LA#>#)akuJ2H=-cHzQ&o-MYls?-ah`K;ca8T>Vn-{BGVk|XcqUoUKhl-n^V zr0u*1>cOUR*?X;fEbrz#b;7@e%p{9La)BH;ofRx2FBtimP1^Kf9n|1Gp76LPv?*Rr z`6f`%-Sj4G5H@NRrT5w^ZlGtXA#(z!a3E&BweD*4$nl9`^Nyc z*zHHdc1y*=_CT)dERzEIv0_jUfHl1K1Rf@Wfq?l#;4lvw+!~?FFEP_b9>-Z+QjH* z>3UI1OOgn>b9^91u5ll@r!p!EsWtqTO$;6LvJ|3i4(i{+{%7%iZ!^avpw4qUOYv^} zH0?nIhZt)=%jy;6fObI0v+>DvtueiM0jlft_UsG{Ibi&g>U~T;r1<6nWe!d^3IR+A zwK1{Do-{L__c8UOugMEl5F}~m|GNVJUWX3AwBOnN0B-S#yQ5!s(41Y$CBPX0L7j$1 zc>8`@1;}WizX%vyah1A>yqYv-$$S*4hdH=KMaT?*T>a%%_9}KpIxH zpLX;M{|K?ae@mRMH?tx>(r_TBwHc_CLnMIn_fAp#6z-`@d-W+Dh|@SU{(rx%zdlmJ za}XQy%Jhp6br`DYwNGXIJANs00~S#df0|L)NBqyXulgsrru@%;{nzgZvUEk>)c@L) z|NEa)mhjvDxzhh%pOj?S`~LeT|9z|f^D*Zp65IUWU&AE-Vy6FoTmSjDX)qFB{oh|@ zOt06;OiLS^>DXvl$kDhiYixG^U)M9NoK9hq^RjVbOZlN3gB~2{|MwTSd${)h^WrOb zqp`QGDFpnB{@*vLY<`a5)o1KaVygfDcDJ*n0FqWZ>#@NnG3kFnK^iksJO@b_pab$z zlHmQXhm@rb%tZaky!P3_8s7V7F8?_@qZ{*-*?#7~LE9Bx@y_dV{^$Q(@%dkmQ7Hos zYBw;mKsMdFdpV71Y@G4$t^?4Z3(kbzb5}O-jMOKN5Wc>B_n!m6)c$|1x3s57lZEaD z0$GfrBcG4-8T?n^k@ZW^KqR@_;O5uF;Jas~2mq4K2C{n{pW&F>|jc)8R67o2jIse{W6>@u!{KiB5tpB{-M zk@*A+@tt$t^qp}H=~Sf?93(=6V^tAS&1Hh!gEbD&1t4oG#gF+hNly~z_@2$i9y3oF z$aKUbn_vtn-*KLN(Lx`91V+95)0ItTKTOM-Q@DJdZF1Vj+CpZ&IPLpIBE6?6ajaXf z_&uD_U}Guc>>FCa0RkGzi-x)9wU)ZFp=;z8R?|;9+PhZ|@m=#Lw|DPS!8n2uRHhT@ zt@_Ax=|XAr?nnP_EBlJC>iMb%op?+vG~!_IV!US>@ZT3_N;*zwz|z(Fu|d0u@Un)E ztFD@YBsd0%7~n;z30q2_(<^v^jdlsTw5tVeO5FP(NKIV|hB&YifxKq=00?%x=h?Vm zkcs*+Ny%q8MLk+Ugp{-E3Wy+~MTUKFUXcip!!-hibf6wR6=El69QPw=EWIu>H#a7> zY;qvM@ckFFmEJJ zw)Raj9ILaX&}WDYp)X0o#}pSw8?R$yua3B=A$Q%W3sdRGhX^li9Y3-GpP5f z)wY}YaYE=q5UqG$w@f{CgbeH=kKEQdK?jqoN|KXgxcfz@`05Rdv{`n$eA_DW5@HbV zC}jy?x^T41IXkep{>{w~YE~d4W=j;gXNp<9?>72QrjYB~;*tAk(Lug#YaQ&#NV)Ut zdUJ=$3AneW4xTa7fDRj#7?G!>F092LZS_7@*XmLs1Kd}TqilXpl=hpw6Q{2>$l*y3G z`}Svv0^qF#XG1FEltToaTEL=Aa_RX+>xd+`DfO0|)BLC{1Za_wG?B|3uhv%xy)m?`z$Byftq1N!-lmQaMmp*Z>tio{HINCu{KDO%fKQO4+Sp-yFYt((-Dk zS^sWo)~)om(?{aJP@lRw(ZCMhCNz)C2+c%6{MjvNGA;X>VfF7)OOvvnU$)hheTa^@ z#yj`Idr-k3sOD-ocdoW?e@cPlI4E+cB9}!{k0m9Xe1P;`rzFVl=raD9q82I_9u)$V z;6!`Ew-TVednP<@Vf zoren46r|P7(K0y_QUIdALj`w~k64O(dq;aF6Utk`TAv+)%iW-?u=MoO$vaOlT0T}M z)zP)A#IS7yRMqf`n~bJtsB0_g34jAlRp#kxV!p~R19&RpHF_3er!6fdlAl0@?r^!E zmrrmQ<`df7SwI29K*MN-=&}nv16WKg)@Uy#;T4Z`LFnm{J?5l{J!XQiz~t_h=7rZdO#XT ziEEtNqamfS?{GauikeXvRm!;J7D-dwp?b;`jZpWl&FVcsIu}QC z$9kZPhKG3d@bs0qr#eVeS!G`D|N#%U-up5NMjS%Y~Mw4RI~>%cowiN z2UV6I^N=#TdxMn=87s9d@BJ6Zq5J_%5%d8oU)U-C`sDi~Z&Z&C7-DRzT&FFwDBwoJ;677=kTb%8$T^2KQR8&0J0 z(ENlbCX@Z@zo#B#Cd5;Y;NJ2F!lOz5?(i|Ht1K-^_HA(KA@AP~p+^Kzxw{ggYl;Yl0{SX5iKpbn|{Xcit!LR*i_ievGR_1?TM$o1+ z2phm~ArQdkNP`#6jN21zT5gBK-znvjlU!&cpPd&s+W=??W(@Sm?zaVYK=?zvdb;*C zh|=|!j(B)3WZ;+{ot>S5MOSGxnj04(U+uD2z|p69)UCQ~j{*8hFz}a<-B)jX|Fv1^ z^t}_lMMenN8-{8_k;^+*KuEH-*^wC8jPZ-GQ!)E_M*G0bBXZ+#uN0TPuT~ambq3PX zw?rv8DLV2BP39Bpx7E6{vlOf}I;v3}sIsPCk)UKKwj}CtVjrlEV(nlbrw6XK@%Vi> zpQH2bwuoe0FkAe+{)vYLd9KJvRODBaqp9aBYc@FMBn_MajGN+a{lKel^Lry(rUDCr zIDRvNF85qJzJL_vLAUw8uuZ}#4ZL|s7X%_jeke@+kbD`GLhz3~%HH$W+|*lhmt=nj zq*u}D(%J+$K$2{GHTdWqX_a8R8{C?)(F>k8@W_MO1J2!IkT^_Z`^^WMQdCe7;QmlQ zceg(*Rt*DRH^SN#as$&4B=hREx^)?xbx=u1Jf+rg@Y;cNJo6MzP6YUi7LKAbfIUS9 zWz%a&rDancRBQ|0;owc>P1P=Dfi3B_S2sOH}cFYkGOe+}5Tx2Bo9 z@Kxdej#-l*UO?Yfb4&zy0-BQW{tfO~+J4e_W#?|fM(JKp{`w*%Cj8iP!3$0Ewt?0` z-Fqv35n@9r0O!ch?_2?YtP=mHLY-Rxzm+6Egva9Xxmgn*Y+QU9U-`?`=af(UpS);l z3Z&{WkNTZd{{MNB)g}}k$s0?fp%WO-{^B==?l6gA(KDDngCdrO^AkQOOTnedXoKVq zXj(7^HT`&kbb$g9n`*%Q9;8sP&O!ERZ6DjzlFkn~gX7@)ZcL<>vTbhDxd!IQRMw71 zpzuI-&aGHss0GP0J7aE5QJLHO5r>UWrL<_j(Y)1y*sf`mw`A2@C+4k6(<>|qHZ!V7i2|@;?dM%#-AUCO(jJ|aqP$4f+Y0eFMzd| zo}BkAI}JotsZaPoing|rBc-jmerg8A^K!;CWn=OD4oqEtu{kvVfg0_L`nPZOp$8Z2 zB?y_#;LZmx-Qoeur-DYu+JDn*Q&Xhc&ky(N5afN__i&*8{n})Llql*c*&Rym$MQ8^ zkSYJmZv*13Ly{IR*@QMwkp_bN9&l136ITF?kQSJ5S3%7J4r6<*8Lzx$&&x!?f+B}V~`-+Ae1jf&P+nI^B-M9*NiYaICteMQ%pu0%QNhXw^o7SCGKa~j8~qn+JVI4ZoCrkS|leD-QQ2#@-%?Wl};uysyr6Q2e> z@Nq%V1m`p&qqXkd2R4Sy>;9s?Iue~fr;6XSxQcqk|l4{aqX=7+|s-F!0;p zduJ?YgJ#g`3i>Q-!K|sbfte1rRNyK5T{xn+ub1&T=wtLGsf8Yme!7!@@3`>E zumA)%-%TNwba1TSh~^u10XxE#o=;O=Nc90y8r?ft8*PG5w1}oXZdE&a5>2^0RLb>H z@YVJ=kd8<8t*G=kf585Gp!pdK3qKh2RP$R+XeOzku`ICG0ZA6 zcI^KoC5i?$@7z!Yv`|1?aSF^dW&_2he*@@o(T@H5NFctRhi-CFFa3Lc9S5q-w5LU} ztwhivrt>&61}f*0jl7LyygP>&80-iIS0rPN6w-5qud>=q_U*2UisMF*3;DX2`{xTLNjujV*Isk+{ zT3HQ@;!!ji@xX=x4E&GjJYiD!;E;tuikMRAnQ)OB_7!IJM=!L?}Df=!K$+d$EDBRbr1rlyFVES}R+x}$8c+(KoY z-Wy^8?;!#`a8Goi4+TzF%A17ejJ!*%J;@V6rLosw$%7&X+kAVUP~7@46M%%$DO{^b zO%)u;z zeb<9aF{Z@5Q#0}5g>=S(2G;)9bMt$q#g4<~pt~Zg0FlZ_(DEH>;3yz^&8@Et^Vyk_ z@#MY1O>gt?It{2(Psh7F-NKHIRR!SX_5x)g9C>tI*>O!(Tv8I~cG8K=u|0>P%0T#D zWlLu{M~3=S(^nb0Q%^+)K{(i1`eUqUem52J_PeHCuE@Yo;m-@<{#*M-8@K>xAuqQ% zYV3vgfC|bV`Lu9Tnf6HjcT`%fjtGaRSt2jvIfL@W4g;)BG=$H@UMu7!^n9NQnMhb( z8Qz>diZ#~$ry=+sj#yM+{JXYg(4^8sI_omjk zft&^Wb51KevGKt7-c+!_jsg+-Mq zEMc5?=K^Rdq=cyuj@~~wrh=i&S2%I3RAoYJ&QD%bPadN6w3~ke#5-DkO!{!U4;B0a z_W2`*hZXAid=B&Sd0O05{utQ^uXp*?sjh|6U{b+^bOHhhc*Jkq@E}CmalmpP8AyAM zw3ue?xB${KSft|u#|s~_vgH<(`Cx*10hNImeq%$y+8aw)TcNEU18cz@O8vp?3`-K8o5vKZ;xH+ypB?5w4);_?|3du23@ zSU_XiiZ3uxc;JDlh?U9x(E^%v z`$~*wlPO2G^+(w7&D}yoEmF0?7rsfkhrLE+thgGyo|-H5>PEcUV9gU&ufoRO^K4YedfGv#Zafx@UoBXHJca5=pyo2y@eQ(s4{n$8igR%KRl>DKrCgod@u9RZD1z~h(WJD=&$Ji$BV|yHLp@nhH0gnkK&Fy$kP+&eQzY3fqO7bhPxk)(pB z=I&fmuNk+FEVtQ?=fS36UiMlz+7a)K^}2X8EY`G?`R06wEuoyBLaQdZ78YfW=js|N zW*U>OTXkeutRXmA^fIr0OjDsgdF3=;agh|AKm9Bv(95V?8qkh9l&@o@eTjqE*>)8Fd(L4=KCv$S-$bo~y4R6&qZiV@Ji0miY`mE@T$=ll`sS-W@?g(&f{AS@n9p`^> zF8V}&=H`@pkC>t&$46p`51%OW_A5wts}}rzx7SOK*z#~W&+ETh;JaVs8|{Q!;gT9? z{FZ!nHv{6FU#L$$#sS>yd;5pBII^Q+YSw$r1= zWi#XHWwW_)?~MJbU5>vy(8y4T*RkINkT&tA91b zfFG9kYw|m@&co2gUiOU0Pn2)2`0yK+WjSDbTwR_|+3CFM=w=n|8}Xysvf+d4EKc() zMy@jxetaCw_strg!Hm34n&t(IG`A2vusc$WSBJHy&_u-3) zN(l=lgLcv|lE>a(-s*QiUE&bFSMD0r*VmX&P3^F-Mu%)mP4nW}U1_xK(SIGI`em$Q zbb0i=kDiixV*ZRSwXx1GWRi>N3;yi95V3+60j#}%CbzJL!=D-VJqHUZdH1hHGc`yu zpb%`QV$3iLX>?soXV^k`)tfpVJn{vKwt@}ZoUWBu1;V?ELhGYFy&X{bC&CWM0| z6lU;Py|!@89jeup`bduBu`I(wX$_;qqN zUe3GE6$n()qAh-g^Exe5-V6p>22M`ZY~!(>kecmu2IQ_Jschq+6Ax_sDn-`q*pa!T zLE_Ih$Q1eOW4mhbDgqdqL>(K)P#~_nPd2Tpb5LY*`>D2$g zJle8tJbrfd&4$a?U5nJ&mO3P$0%1z`wmA?+gK12Z1cZn4a+$-498hA6Od`ecHslj7 zENoX!l~@^eO?wmlx&pLZ;C<8J=l zQzF_u1w@d+_3}8P)Ol;aM0#UPP?M=5ta~v{OhTRV#zaFy11g+49Ngj$lvl)pg3sU< zVYzw}p!D^n!2)2pxO2{PFJME77+Lm+gkC3gxZflWM&~cgZ!PVv@9fE-rk-f(`f?{U z)EX9T&~x%*WM>yf#_wV>L?YmJ&b1ahu1vXbwaJZsRzfvKbjU?0S`=Ia_lYG5UEVnk z9GGQ*J?F;853!`AW(F3Ch~^T`uwy!N#v5Z$ToYP>r~=LdAEv z8lKht$k2GbWu6(MNnF^$enu|7K~Y|whSz!!CFsd;|8E|Y)KvfT8s3&xk*5w0-mB;H zm~bz`e=Ur_R=U8vUd`yxee;beK@6^63UOXK9E6AXI`A;HPp8>qn9Ss{#GRc{ZxeH& zqH!?XpJfnoIw6hvVjDQ~+xYH1B8K?`wATd;qC9LZBp9l~q>jP9!(X4%SmorXMHTu;F)-q@wh!n@DV7(8!@_nvUf~r}+k4LyBT55AMozW}K3)Wc0#QcP(ica&$*j`X)=cE!AYCM71@IK`4 zoKrhmokB#q{*_73L2LqXflA0^q1^>e>BNPWkrp{hBy9-h013fpX1wq z2bJ2eQr;MA=zVvX}fRkh$96qpT$XOT^$N~;XNe@j5D z42F3fPOa)#U3id_yH|H1v{VaM)zeDLr+bFW z9{lx^QPRjye)}&Xe5l&#MdQW3wVi7FXgOWGuM&X>mJH3fw!9E|L>q4m9|h}>FjBto zslj9xFEqzMFQ*j&qRTqw-TAQ_h=xVn$4!-+{g!m3&r{06PDBLnk@}pkp`|k49IO8LBrR=}LyMpgvJ*os72TE*ra}oyguVE+2toDcH zH{MwA92s40SzITjFgRO^)HrZ#c$oh@hXV}UuJevX1#fRbD-DTW`ISj>@}{oak_++l zku$tmoZ=-~RmvpINUJk0N8zkBwQ!yH&*GQa zjchxZt`rP;qH#^%pA@r(ob;v9%$9t=sR2GL+`lme0Ym(Dsh`>(5(`2x2N`vNtOAzFgq zq3?@t0$41J>^S^|h05KP)65y|`4Um4ThUi~0~ro~$F)jRkGk!)8Rmx`#UF)euo>m# zRk@^Myd98n>Kf?pm(+extN$eIf&{jj1%Cc$78ZZQ&K`2LrJ%Yh90m^kV{HC{0zXK) zvAHNChsOQIeaq%sqsoT%YR`hNM;6xZ&Q3eS+FQQ3w^bhJMZ(BD2)c`$A$S)P|Uh{(R_>&hhf=vJyz)-*H}Ld zyTJaKH<91jl?C7CBR- z-d_>Y{+I6idha;4Qq#nmopDH9zTB>VQ@`ynxjPB_U9P#9+hMB30J!S?<(FAtz(>xv9WfEElqpw{S`TH<ep*RWK2wlI1`XN8Sn0J0}y(uv*D;CbmiPzC)wG@2^aFI zd53)E`btl*36uiA3YrB31PNar6x&x)*<1cBz*kIpp%GABeiY!Qi`8q(?VsqWFP}F~U1)q{5#14KJlrr?a!cov#$&Z7w~1$4ezm&p zi&ohxNJx-uO_?>;w%_D+Uir3@@LVCJ$?@uUg_9%W-rs?p4i7@&c{DDc-Ab9l+V`*^ z@tz|M*`Kcq^Oba;X!#K^RS%n8>md4!-)?MMQ`3C-zY?z6sBJrp?a90iPX zd7m4esKNy#*JX1H6w7_( zPN5Tta1rBoBK^(&d;M_ zp<_rZgowXV`ZnM<j}&hyzvpz@?Q86@@TtLmX9lQs>x2yQVdX&u8#E|mY5Gw zgw)rlnFRF}Oqn(ubrL~jLq$OJy-~2)-ZWg`lx4#r@Rz_>i`v$JHOAV3I%;x+8hg zhlg9!$v^LQ^!cWw+|wBk%PX7VHc^dOcU;u?znUiC!(Pa|B_krMKtr?qLoPAHT@C|O zUhOiZsQq=YwI3lJ^&?tgOHJ{0X5Z5rpR+TpR2H}IFr7ZjM>p5f6m071QZ!AKR_Q@E z7b@FOUaYW83@;!Os#Yl6KNzK~cOm}l261t+>N^p_z~(nj>Q52GTc+e(>x{ItVAx0p zy=8SU3Q~_M>BhTFC%LKwa~vBcB!P}p5DzaLze2aq!RRNRaR&T}Vudj<2av zlPr8izn%f)&n+1Ms*4U^+|9TUaCpgee17wtWGf(Dy~<q7KO^seWMAQq&lI{fqvB9|9iKw!P)YDUgbsvdaq~u~xN3edIZe;VK z*tn6$$a9&mup`hZu9Mx z@)ziw+YDM@|DPA&27@9OjG+#?_uEA!;eI?+mJlaO9Bu&b{e@xnL=bMoJe*q=^*azz5CUZ@VXMVQ&6AU9UCzk2hy3!8Etj8rg}fznz9lqpEs<}(ji1#kCpopS zC$N|`ezs@W2Ge*csd)&q+{%i&A^-Qw5|>0@Tr>6g;V}HXJ}b-N7jsUp=X#EiSs>FQ zHsVq!#}4?Eos$7sV3PWC4iGEriT8#I05QaIozYJUJ#X3CB+2YVC*W*J=PbDEWlQk3 z8(rVhiW=tgXG6YA%gV+*q8%!n$my6&$5y6CMU-7KA>i$N9%T*cqchL&5cqP_Q|zuJ3n7rz<|b4X3=9kuH!E57o~~Lb z=ArRA9mtVhP7G{!DypF*z~jfc($}dy#)U(|`)WmFyTF3P_~FvoWYWtW+~TxcGo`nT z4F6E)nvpp|r&i-+ohoP9!qcv%8jDuE<66f2OF3Ix99uo@x3J_xjXDWil!MwyvtL2J z?S;O%xp|XxE1TQgoL+n z@8SRU;f9m1!roaI=#mG^mRqn{4aL zP3ZKxC`!K-!^zdMwoNrRIu{6W+T-g27%~EnE|OpA*C~Y41L1YM<=XK2Y){D`)@|lM zRK$L?>#P=S#MdzA&Gx%qHQ8^@MrI8k-z7`ZT#7>JMlxZ=$tmQ4uo6L?`sU?nbZn2a z>!@yEyf^FGlpXfpT6h)7+Fj~mUdIL$QGuigSS+5UQdUdR*W01m9Twq{wlkWPbQ^5Z zH~#*mP8>~px*aGJ7SX-PMdpWMac3ytShR9MFJ`)Ye_vknTBFN`l1s?>|58Qp#B-EC zr24%%$1|N6Z7F!4fqjdPr*Ptmt1&*D{mh`1P$3t;H}9Ka#^JH^kg-6l+Vo!4LZeEp zVQ$fVT+WnaGBcz&;^H>Ggsf(zw2owvmvp))@Dkm?dNJ7NQ zI$;d1?(cFU=_qK??2m>i{V$>$;}=&~kCF~t?1{UL{7xzF>O-{Gb+{2ul;LxYUj9pJ3VGH5<)o1On^JjJM8g4OSYxR-)Du=X#Q&=ms6W9pil19pVFHw`eGyqB@OgUVq}*7a4N4% zvNBS>S9p}ErWW=B3CT*|6N2;dVaQVWqhB3q8A_Y@`1vp2X#e;zuNfhxtQ_l<=pv;Y zaxn^QDAs#imJO0yS-b{$EO7EVtYaVfy2rXEY%ty788D99Hl8^yw#>~i?hy7Z3>~2% ze3|)_X9A!|k^ASVHj|2;mmfxG7FlbC%RUkV=lA1J9at@MdbYGDtT&U8@aCkD&hz{0 zN@h5se!W}2*EdVGFE5BG&O)8eOc&qW$!#9`kZe9U2vCCPak0oU%ol#iQjLkB=LhVV zYT4Xh$3KU6Zr9`;>V${azTBEX>Fec=X32dxQ~8_q<>A5Rk<^{1-NZOBJBuYTv)1iE z;m>jw*944@@Mj7+Q)-nWd|z<#1FsJJT-?h_K@w3MLzpon{{c6H(UX%e<82rj6NRX- zZ)J*f13da`R(B17Wc~n#iYiW!uwVKHxHG{}`M2<~MWJ z5US0lmhtK8Ubl5bYNwX+<+r{4Gbv}zIQdU|Xh*7o|M ziwg85WXcDQ>$@d2tusZ+$Ozhpf&&Ol99b+%tONP&H$#)@(^g8mi=|V+~)4 z#k}XLZuW?ksUx=zj=?dy-q*-fKNep3qws^ARSPdG2w0f}QP7e9%fF8^=p zT2pFWE*`hcW0S%o=Gw z-ZS$K;) z7Ty(p-N_{p6`y6{@a0&96uS09Gtc6IuWD_tR?j2u&M&`d|J{^V`82v9K;s5b+I^;U zzIA?rlIcd16{pv74}U2}5FO8>BA~SzU#9OwHOr&VZHP|t6a2I#9Jv+hIODw%n>^q{ z?JI@l5-Vd>xphpC^3f{KQ4Vhb07|Y+B~3Lgk`URrfTm$Sb}p}B?`R)>6HI*F;IaZn z1OlWEa56IG9&)GZ-_G&zwg6~8K91QxIH+oc5IWgeS&ipTHDO^gH_GrN`$?^?QkWhe zw?pj5*^7n<3Ox>1)rMQ)XqGurQYl5!ljK;@hSCM)T_6DsGXh~dGx<$vo-$pSRzce| zOhuQRk^UdLlbpIM8g)ILJe;jq(?T__1XPA0!K9-BAdZp6i|_v2Xi2;WETvYrseZ4? zJ@a-ZE6m1f=?p-O>-i%@p|~CEl=n`*D&-^ZQx$IQk5?@#4hNhINzwAMOKJI%42^z|Qs>%+ z9-F+u%^fIG^pJ}$qmfT=%Kd5BwYnjqYx?lPoturEg=+5S%xE#qtxmTEZW2`J(7Nv@ zL;yo~&xu1)rsWx5&EH3r1{_+2}rnZ8+>J{08xp z4xk-%g$4q}gi*kfA(l}-;%WPwTS-~JyT;b)=&ko zb^ec!#ky4rBRT|}INO*4YOX-rifaj)a_==RtGg^6%-r=#-}Ci6#YocwmIs0deC zue9}$$<5c)dhirv;=zHh`MOr7y&5z9;@NzC7YaOn&yCyi)hqW@+yI?rv=?4`+bpGL zi=&*ZoP1OJuyK!!&;SaSO|N2F*^ueu(}&wyH$p^TV1Yi0KqObmsmk8JjX>(1`d5Vr zgb3kL`n%NJ*Aox3wsjpHuT>nyWyI`4k?#wN52B$#wDO1pM(4-A@1IRXz=RDoQT36E zCl~Pv4{tyV%uBZZr>g!Z0t2jX{tb6eKmTp}Xx`mUUWLwsGBIQ6b+1f)Wf zvPvENxVuCvT8gbK5uiKeoqdy48)pCW=4cIf#5rS#yEFHBTU!~oDn+2U2uF%`;Lyy2 zrs?FUxwAi5fY4cN`WE;4GmcPKRw(O2=D1-N2WxpD+xia%t?^ThqCcpY(@7EX+Iw6k zrvzEW*lKxu_ej-rRr$C?t_zaoSpP^Cw%zE*=2@m~Yq~@6E4Pm!F#1WexLv0;HKkS# z?{`y6mNS>U`3L%39}XaYobTr1Uh0jIl-pWMZctybY}Y^U^Ctp0Hg2;sV9`+fnn#?T?4=D%t4g;3!b0gcaKh4kMD~g{7pTBPcWUenIjyY4tN7Tn zI|7!FjhXsZ`aJ-1<|Q!?tBipb$s-RR0(^XVsCWYEt8!JSK?3R@aC3!qFGGAIfYE>~ za|op^C&*`wzhWN3^>)K24yN?ougxYvLXRxEC-}K)F;kq~-p@^6PimeR;a?# zgaH@<`+$jX?cCD?5%#`)#}UF8DnIMv-!u?bvP*{Bduq7Y*b=|nK7E(drT(kNdC_G! zwOaY3{#@nNJw!wQfPn%Zs!X8;$!|=6e(_FcT^bsEfmUbV5u^IQ10Koem-i*V&()xl z{+DAr&YnC{@PLBw0S!$Cl>%+B%$m=Ox$5+u+unofEI;|!An zsfgEXb(qq~%HWA98DSOZYoZan#f2}N!YI+nQ=waSD`Yo~{V1Z(tk>XSA; z?g_BKz>&2AUBLIKmd5E3o**2&q7uvA9C#3 zFmr^C5Y?Z-lTWD3uqfWLx8Nr(bM7tWqcwrw3vP9=oZ8NNv99-bm339w$YGE!KE}x^ z0Ou%=yINDVOl)#>EF2S8+g%^T_$#|9NTYlw;xWxK!^2vFYe3~!~p^V|$$ z@a6!lGdQrluX(m6A3Xuu=kS_FIz!fxF5vT`V!Pbox&!>4Ulq^HB&CEU0rpmuP^;P` z#;ttq@yrxLb4P*sy>;flWJK<T+y~`D7+ZUf#_i z5z{?G>E}2wh|=-)9n3WP$7tXpnYFLDf4{`n&kq9+Ki|M=1`|-|Jy`D@_Jbwi%tb-U zQbyq1Df3GZxB4kN2_PGgokli*AB+2cN=-G zl`WT&UR}(X88`|5(&rxuag>BV{;{xA#N@&EHOO>%L%yF0{e<2qwA^8M5c;S2Q({!; zyOATJlX2>2&u&S}V?Twd(|@aC%Did9pF1ruU4#K=&9sxx04i-}ivj!s&1aX-fr&_0 z9?7QUwswk+!XaZlBqKL9oZ6<*j41p}uWWke^-WGIveYT0idH-eOcO;o?iW@zE)ZT? zKCPBg*jobMj2o-da>$-Rf0yHhs~li5B(Ax;gM$pznD`Th{r#%u+kASPgg()*PS?P8 z%lEj6qNlDWl>dYD?YuU|>!b`qYg`OX+qZz|?|ha9>VOeCf#FCn3| zcwbIN(mj(m$|x2wuT=|9Kmdy0{D?Cm42#6xv@Xwmx1gUlO1-xMJ!bSwr`Sg6sk7nB zOq7%wpUqPHb~}9+4;T{v8=~JakdaK*5WkJ1+vd|YS(}`aBVfd2^g0$=X^t}WxT|JD=O-VoP%ZhOd;S7 z5t-W)08-bjZ$eZ6b`yahkgxhyixgB*5I}o_eIuwg!F#wWE+kjZCgKjWw)+hGJ)+?* zFaGlVx)gA64DOn2>%x-HpfI6tUc#BCT}y)ULzHqYihRi!xqE^x|jI( zIt?qFPh2XT67V?GGsd0aw?zt{i2IU(Yw-XHOly-Qevemw0sF|EBvf9jNR4yncb_ROu#(Ce2X7xd)2iuHH*d5S2glpUSp5zNHBWj)h)6a5z0R1gR+FGqWUNg?W|wzk}VYttf2 z$Itk=-K*;u`1vsoEgv_(<$SE~KJyd2hdlMlr7kJLi(A!jU}O_I2+_C_}4mWKmTbGcQl=`Nc2GQaaF7iKsl$4AaUZDe2w;2G}_fd>8H> z3M2)$jhx)ZuQn$EhCQ}P{f zIy)z09eoNHr`oivR-RbapGN<0}!NJH0b+)^{A}p!*Ln1to{@AAV9S=n2 zh|y8XUog0TPOh)mV-{sSwO+>x3uUpU$n#sfgjZ3F`&UbQHcTcj-uX9U~)&&_G57YL0Bm<7Ydp zXiv+^`WloPaJ}`t%rbF_)0*?Gs?U?@uI%gweO9Y$R6H~44}8Q~zGmI2-KK*2XS&WN zKl$kxf?}ywR*dvOX-w$jn>TW$huY-FCv_}7g}?K{Jd#sRx15j;!kGq)i)&up`>{%g zC*W&?%8H0))gS);OEcz%vuOh4B~Gq--VBZp?jzm3IoOZdeyOWWL}?#6HUjd-q>#cB zt7WnK<>p!@Qp=Ew zEQ+y&Yrk^>odiK+m;21><(;i-g8c{OfZ3h-UsliL_$U4kl6ZO(9B!useQxOPsWbiQ zVK7{i0q;rUEn_Yuzo3;d4_E-DhlPOnEZJgZCs|V$0TpFO@B3ImJ%-5Hjz%~0fgT#r z>*6oqllp&gNdm?!E@?Z1qpx?v-{TeMxUUBm5-lV3_0+Bk}8y*cs;!yaECz#SIN( zdUnAq;hC})vW*}Rg1v40Hi1M>$nW!>Dj6z8ki-W~LK~ z(Tp)1M|lgsiZTlAf|!0z{>qGhSgZgBSgy-Ev?8MzsZY;t-Q{RNE3|PXxgZ5?R9vC2 zgy5;1$V-!LcBgBK-%ZT-oxSgH@{_G`IB2Tb5FzmJ{w#+`A9QV1fBAyH*6LNhQLC-d zzO9=cC$^eo5kr-$BYT_prK-l)-MYx?k!;Nqks+_b-$M_80Ph6^7eB@vDg7ad^nE*Q zFrT~7g=CMEtfwW<=5y_~x>T+h>4LxweZMgtP<@=R4K?r@ zYoYOWL!gquYXsZLO230qR=dZv1|f*(XF&z#>q1IdjxqXlN|(h!RixymX_=B(z9RL5 zOy4We86thhzWgEl|H0wNz$%ILvHHQ=mQPu4k)GC_%Q0khho!sfR?9ob9tZ%t+-Lvm znKJu9>>~&DR%6qT8&%GUCHG0Vur=U%h}7(>nQaqHSQHN=1lR8GpOk!SJ_2s9vCmUz zB>*?U#&^QMB9C=PByQ7v`$3<>;7x%3rb#Gw)biy^e6U3WZ@9mIx1@#Ha`Q3cqtngG zy9UyCOpd02&H( zBQBO+cz>pLJ>2m?`oKUyEzq)o(Y}6eCnmL+Ypw@|K4>b?UYY9oKQDlKob)|@<{J^T z8z>088)aHqYw?KB8CK}>^14`oo|#{V_8!Qm>RZaUnmt!RiThu|XWGqD)5?ne-t%2` zo!1AO*oLy;mU4Ih!s1iAO%j^91RlneljM(X*E4LtM)-i>mJJv4B&657s4@Q9p!pri5c^^3tB)&uWzw+bvI0VAK@`Ciy?eL<)*)LqDm9--t!x{w!l^X zxt5?_-E0AP>Oe0vb%f|nx0U5~{e}pb2vB8nmn^rhj9)k-D*}d{)<7ZJpA$zMzCvEx z#I0Hn35`Vha;-Q9W{v{1PP1h}TT%A=!MEkqm~|uss_y9c!`#}d9JmBVT_u~qkla9A z2SrCQGGcm_QhKw>#RV790Cow}pAWUR-|+aAtMZ~)%wPQQ9e5A66s)ulgh29_tluwt zvTQxxLxZ?}Q^g}y-&L4>bfWrOtq()AZkkYWpviBf$oDVmtQ~ z^Gg62IQ8PaAQbc%IXpY?lLnSPpMr$n1W6Y3Y?Fdgs7jox={$t@0xT4R3UnEN~{x>-h(JD}zE``P0 zI5CY`Y9zGCzR>YCe;`c#9#9k5Y<#;&qKU)@`_i77eR<#G?=i9N%Buth-Xy`wn^4hP zO;P~I4C)cj#9ZOlaD{?6sl`S=5hf-%A~X2Gx)OEl9KyH%Ln0tpb?tii_fpPebNkCI z9+H9%Xt{o7Y-BbQgstH^t9o=a1r;@y&$YGFTG>CV)NvW|6NU(1ZSZUw8mfhzcK5z- zhw5R7t3*iMxzOXHOEy2)96a(oE|Xxg$?{(g5Eto9Jt2swIr?UD6Aja++mnv=NvggG zDST?WESjyyk*-c*)LFGt0=iYA8p78q)+b8#OLA&z@A;Ww$IcKAtMv~>XZfd6!s1V! z$c3GBI8xgs?Y}W2j3{c&Gc8#YB6pi`8%NH?LAYiyM>5K*9 zugPJp_af;3-ANBG*iBIL885vDo`vmcYFa64V4bZ8G|zp$YOssj1W$+)LAHz-N-UCI zPH77De-_**ErS;`wmj{{m+QEDBB)w-$+FM4kO7`CB1z)@T~Wy9ke4M_MX>7$I;DdpU3Nk$_Jp>mtNT_}+h0QM&E$ zFnj#=P^Eokys-jMh6sdb>dkxy9|cbW)DIluF6IMSZ5Kr1pPE7R2853Ag?6)DmW}5$ z5m-BaABBTY&VK37$Pis#z+SXAu>3;V0Q1?4t6G;-bIIE<2mn29Pw?X_FiRZ0TP81yRJU`EngqV{f?ec@OZ9qtJ++6 zho0hV5Qu7h|54!204~w-s!#+%*bC+(h;d0i3W~VIhdhb&q6^+vSghxQhLvkaKUFNA zmx#Oq_8875xUn1-=Q%CcM}SOXQWQw^nCkZJ-l?ghWe#Uk>lR>R>+YPF4ZmnZ%my07~WYSW!BbK zMfPJXtc4h8*YqQC6 zU!SbM^zCmBKC6pcUQeD3KiDd)fu64O;xxibaNdFu8UNa$cTj14rQt%V?##Md9pN)E zZ_LY!T)NBSAu=FDTN`V6inflzHLjjgz{Y{>10A%tdFX(GUUamNDbJ|P_#zpKyt7(H zFgmGu>6URXNf5*&Z|pbst`G=_I}Om@Lv?h*wGMiJUY<7mKRV6* z=TR*z+#oQ>eV&LX=^mnbNedO9la){-z^Gvx=mSLb&sh9p{Ozz2(D=kt;p%*6{pu;W z@4{&=Z-P$SJeYTDgSu+C?ZwPJ-0m+(BNU@-&zeFrHs1w@AtsvzoK=qp{Ggq6XM!rb@dIzeb*J1 zQuKMG3|J@$cTah<%=Y^;v0lCZlZokq=8X*c>bmOx$#o(xf}W^xPpFzSv3HZ(f*8$eOoWAF zQs(3&&mySAm6ang{2Q+Z;)vL77SpK$w&KK~ASSqVUA5D84X>d2@cu-hz8eIYN*UuC zk99h@0N>reJ-2+0jDT~2*KtA+HPtu?&@8cY^r*2)_k_*W`OrqA6bV`wlP{Wh!R-Q` zi5~0q6)HmzX~}4{^XOMf&L!s8pw?8sn$>5B?8L*8W}Zn-x)$?L@(uI=sGim=y3I@w z0A~ig{+*-o4|9(prMw&S-rc~9N{-J*_6dMe5Awz5or9;-)v9ad8+9foQ%VK%%>Py1 zbc>5U&g59r#NXs4P;s9>-Eq~r9*jO(?a2MNCjzN49Bw7yLGdJ1^@Ni5b#&Ll+$*>H zd}SE)@;FbVRRwNx@I2mMV)Us;`t$boH)mfx_z*+omw$z?d~Ys|0XRYXy-_8=ImNcx zVD12J=>ctX?F4Pl5okCg74>`0HgpltefsCH9qMT3h{y+et_qg6$Sy0wYS!|{d~Jji zd=b7HY)TWA@W9ixE#{vA_gUd^&_{K2FH+k6Y)SvvOhUh`Mh!lxOj(gG$~V75`JCZlecD{%?B-2__vVY%Y?jEIzbj(E^mC!shvY(cX+_3L3So#@( za%CYz1K_79LEiri-)lGOGBS}-J!U(KktHIdr}m-U<9c43VfjVx6`>sc&`_JtS^0#b zRcaEdKqo_&sYkxLA&0&ckH{7V$f4-;`8m2ReSsi}zTV)LvRS6)-MB`XI4Z_KWV~H) zkA)fgnlCUp$j<|E6Y`wF`5&LSfahHULk|o;zOMJaa}{4N1mJvQlpDueA>zBO_Kn|g zePRj4+4VpB{Yw)c2vIQ1iT5I3l+23Veo04p4RMEz=`)Kh>(JBS7g>(#!+LCn{0?KI zX;D4Ss$&)lMyY$yfm}@jxQQALTkc^X~sz_RsBO{tyb&twlh$l1V6PCmNtnj~P zsf7GrlTBha7wXHWLl5${6|omt=E|ICI!}`*dVgrYhyj5}c3GWg0xAd7pO3UG=qoGT zj4Qq37k><>F3(*gb06J6d{EK2uQcXmdYX5^z2JU&eBa3U{F4Yj;`W`O+2Fog`&-qN z0C-*%CdQ2-J>Nb4dmo9@Wa2&aq2p7dLmt_fTmf*)7~ED2(3+g<-8xTf`es5^%=g~^ zcTKJ41|yK&n3C*6D_wE%{HDYqwZXfs;QIcgcb7mqH^F9x8wa!?gfDi~6-WS5VQnfg zDm_QLMBpA($|eM#3?bb{6CBBRUJLpeyB|(}W|!_?%pdIwz_b9BHHq6SZH(KGz|dEt z$MI1$#xe00r8?DXGP2$4SC>PC;4xr1Qg7*Nh5kbW5W5_g#=j^%W)A0g(z1Sy zr8HW)rNY&g3{{rmV>z%JKqRWH$wp?jT$c=(fwqf^QL}f!-sxq3i4LI$2?^b@3Yl9l z=vm%O)rdN^$)6``et-^V!U}umtS-N*8>_$I0^{|joMHlmLN*1MPP%7}Cx8_Z1{I{i zJppab`uw-9;e7`uNc=_@3B5>^_O`hZ3`Iz9(D21|w{Yl0-7DEd_>S^lLYSb7z9L5% zp#R|bwZ1j=%8C#iYK`lMK6&F2@kJvzdRX16_VPVh%aYP|c}WqfPEs`6jO_lJ)r>Lwf@{i7I3%<&XC;>mocm6BTZTPDzuMG-X=s`)&&WcgV9Wzcx$c`cZ$eonUT?4^ z-eH4r2di(R!HxYkC~T@fe_6*=|M~Ouo^77ToMD~PYVmn;V>4!&LoZBJt@X#6y`+#` zr#EhJ$eylrm<+5RAy#o?6V^|iQlGME5pXN z2l$qL=~DQWi_`i}QokzRzkf9}-~uudxL?qqg1mnQDeOn@3w08R+!gMt>S{K?&|x6J z<qt6*_p;Yv6>xORAS9EG7ZX|BSp%am>62bs(2=}9pCjzMbh(iQ>jfoH4f1uo}gdB z77&}5RbX0X!@urDRe-%!;FSS~&P0S1{GlqX2Xy{Jt(JA>4Go?rZWjH+e4=31|7830 zKg{7?L0sa)hORCm-~AijuRgBfUXk4pczFkC1Ox(3Xx?jtw0-}BysHe{;um!@z9uW< zHl|_izoBrOedTr?=LF`TAi%a4ZJP+%eQvCGs{(7{>`LPa{OlX}Uc;_(nU`x5SKR|F zMXjSX7WBCWRp5|AHr{%l)?tU=jMF~#7E}(&$oE28>)-vV_iLU55&PcdxxNQ-E(J^} zkU5G3_afZhV7hu2UvQ9vi=cmm-#7>7hbqLedg?Q1nKH>+s(|3pu&|9Hhamxt`N%G; zEG`u$e*VgF<5#cNytkH(zw~VDPhCZnlpK6F*u?;&(HjuBep*?5w~(+?Ym9_B5e|Q5 zg+aKygQ~BCpigGi-1XCPENQ>c1F;UeQY|kAQSaV zEem|m&^7TEnhDCTg6`!7X~%#1qh8@=!;TD3P;VgHrApQA=i&m8(x^HouR2J=g=>y% z;1l_d$6EirnXbOdD6t*u<|q#hj44?tPt`I$a0x>yejrSO?(?Rw?m!%x5!O%JUsQvT zZ`hV30aiI#)+PMb-R4wQvg0<+9;CT#7lK{ScuX3jw>W5Tmb^@mryzJW02Qi{AOGwf zZUcl@0hd#4gl~BGEg<4@UfoeZ07Z`i%*L(Aci)Zw-c>`1f%JqdpzF{3Q9WFqH-d}Z zGMnJ^J2e1Wq~r;`D_0i>!AfKicZji(cMLvNpuzUl6?;{9-c@9pnA@O0?ItFN$~hw&3C@vbT5UHxV6iJ$t(eQD8A zq~34W5K7g~1LN2cJqvDi36FEe1%T{8{zMGABHavDPf{s`pP!B8&E{nHeQ(r)g6aG5 zavJADu1Sw-8<)KP{w*+=h*8+>1((_nd(`L28vYX3yuU?N{K*o$%g%Kr@+#7uettNU z@Zan+myoK&grIj+Sxrsr0?x;=uZE^S5BUt04JpnwMK9pOua{JMz{x4C=5+TsE5Rk7e<) z(Q4fn+xGt5Ra?LsqtGl{e5iWrP8sHYe$s9w;Jx8eb3T5{T;mi3e{ z1q}GbMU2M&KsWjxGL*RD?scO;_fY`M){NHn{TrNZk<0)8XnV`BD%Y-UbP7m!OE)M8h!O(Q zp$G_)(jW*T-Q6iAARr*EbO=gFcNl;I(w)*FU3*N|v)(U`@BQ|VeeC(exfU?*dEZxz zagKAG*BAqP4g;?eQvy~r8`dq=O1LFeXPxyPOopnlU$%d~P0gu(4;MSSOk;u{ijP{k zd4}d_P3IL(y1+!+?;csYxuMUtgl=R^jz3t4v_I_Yc)2(*!(}f$ys36$QuFRqb6K34x=RFOV4{7&45>0cz4a1TO| zA8>(%==OW)oS*6q4NaV%XIEcK8E3k*y*>F-@1}qIyV(1iy!eb+)|Wm_`7arHzPEg* zUbbUiyYut$A=4#&{QJ&Mg3cM^vJo$4 zUSh#Fk#hM%tlfQ00bm>KmIiAbwgkm5EfiDBtHv5{cwR;ClwcrKUpcK&>o2jCb|uOA z;rIDt-FO0m0O2V1p~OV@z6FzkhqG_xIeHZ)W~9FaLvg>acizbnwfkw%{Ngad)1KDw z8ZUeH(s!F3^>@z+r?OG!NJ6t=VY+z)w+;>A=#*e%yVEH={AkZ=E#8|ksaJ~fNt>(V z-qWd;X2#nu2Fpg@pPC*W$-QA8dA)41T-8@@+h>Bb7ExFQtaJ}pP?O4 z(8oN%xryYc#KIBo#{`P*R?maO1iv4=a7(T6cRP?h<&+zx z`noq@y_I84B7*4aozOfF(V!GMk_`%}>ZqO;#RTI={i`wXX6h1ym_4P**dJ*NH<6mU z)8wM?=L;&`d#^HluWCI$oK+YTTUgS&F>K&9$2$S#Enz6iMaUnO5!Rob7<*N(Na_hS zks-I`at5x9wj19ZNeEM|GY9 zDNwOAH00&Q%)66y^=Rj`D@$cze(wz%;c4{z>;_4+tYNhDgB`r}(S3gW^;0^em6~=D3Xmpdh(B)Yc@X*Y zC(Xig?(BMUl#r)Kpjn)gc{nwlkLfL87oXkDr7cUs4B*)JR%P|Mm$AX4mayuB;t#pffW|>jbNmxEfe3E9cyiU%oYTgHAr> zvWd|}3vs^tkx0OLd6_=y($iUd!t7$mhMG7f42z(*3(WVccyFSQ)6ZkxE!?t55=C#x z!b)5aNvI$MIa*CzEkWL+(n^+7VUao$*vZHdb$H4OorBDvwcXdmF3A@AqozxmPX!i| z&cZI~VNq*SvdRZnzY2ZIVm1hlkFWV_NipVd=RfC=s2sm*s< zbRVpU7@-r7NBf1E6XK%NV&jxCGoMrTrjLdVKCHVreedZ!#yk|beNFw)!QzrY=+pFD z(rc81=scIpgnIAj1iF~xuNwVijwm;sl>uvUw7VA@7QPXKpT;&JoQKLlh-u?3u*A%M z8nF1b(S6?Pb5*OZQ}f8FSmDr`qpr@X!Pm>DV}Hs9z7+mNHBtV}>Kcy_s0LAjN+faP(f3WRo>#|ZJ|@pDRy1}l9isbJ3*f4uprvJdUvGklas>Uh!P)7vfnBpl zbL~H-vwn1Qvd~||-)HfMYU6T|9wg@&$>yO7uxwuVWL!;C#!FLHTfBfi)r8?J_bo(F zV#Ics5snoTunhxRGNqp+XMZ^lmLk&AGd&vqqhT?bYnU*em}vU6#k}oiTA9zq54WQq ztQJGH1PGF7+G8^D%WYDfu0I`WeZ}QtosF+qkLHIjKmPta>0>>0ynW-{<35KqMK)&W z+d;YZs~#&*5(5Ek+1rjVma_DBwK0R05#Q31Df(>NYWZz5^LbGR()Dc%ejTp$^_eUm z93#F3YK&DjQK0w}vd3KdgL5fYw^r-k+df#cHo9{yQ&mfUUxk5C;>Laepx0*&_Jb8? zO_$-Y!nI2S49(t^8mx?8PA}Rt`<$rSzI&hBJa8M@HF3A4Oq*wYV4#(jtAEKoNf)9> zu2PCuS&Jr5a2bH-+ZY@dm%1`wE4=BueLK~5(A4a0d!M*iRFM`wf_J)p6&B7IYm9%M z7A6`BBk4;o=%7Hx9)0dVFYha@?&KoL0=xXsOxEl3+GCqu z*0ahTX&T{e=1%A<<$a=rfq>z_+q)DT`8i7ho~>1fW&Tf3B_^JAgt@_p-lF>x?N`wm zzFt(zy;dj)Of)IzG<)ryhq!-!;v@szJ0CF2<39#CtSTwn{{i6$y z{*k_r^X? zVo4hL0v@1hLoVx4({BqB!TwV3p+b}TlgA&F4&`1*aV44@Oi;h7_23WC*5mcuR2nx? zO_~`>mfWZMdg@p)v$Ujk-kC6xv3t|U@Hl(&+*VoHgoQ0iCc|fdh+2H4)SI8`?z09; z%rs@|VV^4EaF!z@W%7v$?-!qZ?N!+XN_`1V)fy}R*p7aYUG+bp-IRuY1*1;3=NZtn zKAaVYovB_H-HwiI+ zl<&zvr)9dcGu>Y+H6m5LZMIGIDmmVq0P^PM-LEG4xTHQEJ-FthyW^D;){*iv&I-8~ zAG`1b7#KbqZUm^u;z}8MftoHGA)K#mc8BVNXBP@`IoB0^Q()O#nb>E-2PL)&FT zGH0|uMQ-{ZwHs@)zc@OJ_lI7VBEqiTm@#6i-m>ja<$XFJRIbXsJ?ZwV{d%>I4^K!p4#74 zygua9ASp5c7%ru&D5A|$2}*CsXzspct3_$3M$H~w()yAb>g z@Eows)H%l_UvzdAKK&WiG>?GR&x4)k{+ErupTA)JSqpfq>KC;(E&Zjm%=+TqbwbSk zs!0pDX;ie(!SC;O&;#)~ecpz6Uw>#dHq|FiHNTmmYvT~%?s%e+pU+MDa(h#LcxI8z z(pAx1xugv|nognS7z9Y!O6v%u`;HTdEUFR;EJ@_?BtAWO!|vldGh5bQw>9AW)5d$G z;_8US`)!Mu&E|t9Dls}}^D}mF&h?@Fq(rj*Sa_R$e0h)Aau7Sh@70Z;+$n98x7aKm z2O0-FYjZoTq@+{|(Tzc~Ysg{Vabcn`Qa<=$sev#`UR)O-=rj7}#oDp!))6ycck%W( z>3zE_I(rr-?6Ze_FLm@$;(N49ze7Q7PzUv0;U%aVspt`nkJIMj?^EU?Y}T-hE>SEB zk}M1UVc{qDRGHEWd?%auvkL)-d*>XD$E#xC1QS{0o8PKnBh1XODRG6r?kKU5u!)~o zS7N33eRj0_nj2I8q6>v%!99`k3W<|29?~VM(HZLeRy3|AS@Ua(e;6#qUQ^@t+SB@z z4%wd*KDbEz!L(X}%l0#~^w#K-J!s0qlQ{enkTqZ}-j<+=^#~45wM@07P$+i2?vNG@ zQv=qheKXDQ3Gwd$={ftYb4Q4;CMwdT(nATR*D%@H%UQF?cwK{Vt|})E@AWo?hRPE@ z>pk%#FFL$P1@nUEFJbXuwf6ktH$L`EBJsttUo}(Ja?yFSCYi#jEB_=0O{^QAFdQ6ET8ws?CCaZJdYEBqz z;HCP$9DaWRH}<~CH9r!n#GpphbjcV4wY7D0HD{L%Z9i*YZuE$o@#_GDlf>5V2K@2hs^5VawgPv*mi(`%(tCGd~ z=jhyT$58-X9i7Ow41K4*VMYX}46;;{S|=w78cvnk{91UlOCJmsa7mKzva6Jy?6aEc ziK7$rF~A2T^E8-2oD9hl_H;|%pW2s?&g0EBnjS-iLX2iqU!7+^88*{~F>95l4fW_VVh1r!u) zvca%PWs$(nYwIVvEEsr60*F-!kK|5xSbig~WIWAp8^!*?wMw`1MLY0vc8N8{z4a)m zTZbb>#ftv-M4CDaNM6|OfAPnTZv)eh1debm=|h8ID%Si= zf-Q@QA1*JWPSM^$AZK-El)8nX6Cdw=1p=}cBrfj(O)xWLR??R1eGjq)au!TWz*@ShAf*lAwX1+oklX(nA0iXLN#L|wA+>8UgFN>5&x5`uxoG9Pd8W$DMFSraJ7G*C?3Au;j{1``XE@1tsEp^yCOhiV;e%?r zn7IoKu|P+%cmrW6eHIH8=;e2Vuav&5t^0x;!l%rc8sQg@%7#t$ZF!zT9eu7IVHoaO zr_@L+g70PV3TZ=Nh=gi89RB^YbR`%8stN7TL>D6qGKKnTLq)VEI@Ar%|r?MXhr-I8Iq*ZHJqOCP)q_(1qJxzrlTut$`ZYW#Ie z-BV~v@jXEhW-&Ak#pqoFcI}hRK-rf@8{Njsuy*41PW(blA2GbJ)q?bWB3k}+NO2%m>= z9~w_Gzk9z~vR!wd$zDEn5qtz^u*mfTW@9E-ruv%0z_ZZrrcOjf`f+{$sg{tOcd)(Y8BWjLhJMF+IBQ0OYS$B zJ@6)>*#EBco5kS#Y65C^qdQ&j)!)Dj%PCr2I*_eX#VO~>0eLXdEs6)ogUb2(TUHxP zT+6^W0_R2R3@SHpVjcHH->fP|tsJ>WVI|cSbGnGEe(qA#pM!egBcT$%Bj9G|FMV zTF9G0FpxJ=y-xaBy%AQrn16pChLA; z#~kn_M^+10DI?>?8yZAGQbhIjZG@ABS_#V#%C^DhcqyGQVYAyWHz{Z!SDdQ)8-L(h zgzkplEVGs|%@ckY$9=ugAJEh5*AqeYcPJhgu!}ZG_4Cz+e*buPYpfhWD;!;BNBi^l zATV|m6}IW2Qn47|gB}#eSdEs*^}Gjb=t|87UF220jRV;3{+xW1iG?Wg^}VVqketyR zNm0!pV58DNua*;=Q^P^x;LeRkD6vF@pq~!&cpy{|t)meMY-PSi2X6~n_(y6{(ZHES z+Goj#_!R+&Mo|~<0QiFV9!ytP zUpJ4df~!~dzeg$O`PbjUU}Y6l)y(ySJJJ%QKRT8dJaUExY&q|a*cNv6^3`P%4@*PM zKbXxehh+cgj!jC%PAJ3#Z{KV3yQJ?oIo?I>9Sy(%P&`(Mj@`@)=NL%Zfo(NaY50rl7^_+}sr{LEEF_%Hnv1`U5~SVEFl9lTa$53q`!Q zJH+&hd4$%-jPdzAb>D?wF}Y6s3?-Y|ln+Z6+D?o8D)pf?FvxQAbkS*0u2Lr}(KP$q zXVkyOu!rgQjrl`w=lFG5NdydBD&jID_o$I_4X-o(*)< z`b#kfw8fF>+0VWLkpbAk%sWjB6ADBQX6^(9Rh8^pwGG|sv%D73oT*)R=Was#-m+L?$3`fq5P(^!`tG#O%&Yt&F@6&U<=q6y<0p znu;Zf@96890;gOwpkTqz>bx%%5f&YdADDt!FgRdL;w|vZq@1+TN7dQjW+|H~oqtqe z3NTLvA6Iqvf4eNonJ;&0jDBPclj)6`vjwGVNcAHjSjV)q*g!AY6&U*x^W&C}Tor31 z+TMw>bK)SxmW^6%7^m!A&Q&bv#z5RpX$ksN&8|owv%wiLoLE<97|0f@vFI{nZz)Q( zXRB$QOe|96jgEi{w`QTN<|uwZd7+>@1;;f1ffBwVYSVTR(n{KH71GfSzSD<^mxt^7 zLDD7=;4?85+Tw}dWcg28=ASoyVV{eeL`l482(?aZ~#wixn%89sG! zZRj}qKfe%&Hu=VAM{@zmJhl04|HT!NnQQW)@W*%yt;Z!mUL%@cJ^|wbq>GHp!BzRt zD~Rm_{G!9cs=P-RSOB*X7PJG^1~IbVLGMcrmdVwL5`lQsM+jdmA{<#4qFK~hbu$A6 zfsW^nWl}!aLZtfC0oq@~?m<9NnnnzNiJ6&yZfI3LklkWw88xTtiQzH}+QGV2zuo_Q zt6?jNi6tIPpWB3>?Gv`{WlBW4cY4r$7JDb~?dp91)RFX_-)9{i3vChP0}r~r6)i{S z^tGfRN&53!kd}n~W`6ZSr4HGz5+4%83=rZgzZzCIv?P2!LK^75XCQU_${ zkhk7BH5tJG=1h^?Z^}Ev#Yt!|4A!I7=^6<_!c<)g5RbFn-%*v>&ubyM<19QgV!yT~ zQ@s4(pP&Bo?}Ex*x!fEKb0)24cigK3;93p;n7*#wHW8R)e15B`)x{c-g zln@rr5B(@t737#vz3MSNSw`tX``cR-c_->v;+M!qDP&f9hui{XzVwrxqF*EvVQQ~8 zG~yz;zk>8@#AD>%Cy!k1)MaF%9!f}XI;}W0<+LFXLDd$9JR88j&UbCmca7erz5*Ue zNn+WCVEAi!zWeUJ?Wjd>4tZ=E4Q;DFl5TuWI_;NQ$8+*$-u3=TDtN(K{-u}S&e269 zU3Qh*<=!t#jsC>zcblXBT>w-GL^)IK z!F#&){MO4#zDDUe(r_VavIWCnU|NsS*+>>%it5!lATSPZN&|31_~n`Nrk@;I zhIRZ5!FnB*A0GCQ@?}j>Ry2N_4L}QMZQpEhM_b>v|AngF+hCmKD(EJep`w|KK(s?T z@O4*{`TN_2YStzgnGpHQhf2Ei{~m<;e8C1~m5u&AK{r#yP!OM#YB3;c;3|6e_|Xx@ zC(AJ2g4nTIcYM&064DUI+&cUYE9dV7^iAmbU(FB^#_sxSjfqrIYn|-ngUy~7c*16H zzw!e)gMVL7*nxyt8KmbuO*@5a{lYy-YW`c<++Y(6)6+hW8oIFJ)N8$&30+U>| z@5w;hT|6a<9>v{&M=3dtyKgKy4Kix#?4}ASrxK7Rz2Bz^B}q@d0oNSo;D z7x&|o5W1isy?iL#va<}Ai)7IoF(|QjW6ZTaBjIOQ*rotmyi)4%ksL$$#(m@?a841a z($2YlUAhkl;-_t%1jH%8RS`{PH~d`zK(P=aVI~+;`6Ql=Lf(fn;@6@)^d5=7T>A~3 z7N^8!|M@j?*=5Ty7ED@9i1^?GQOQJplM)EwBOH)E{2g5d+-qVuKp#rx#Am8#?j!Auko4%N9>; z4I?i{6&+Jf=QmS6rZPc|yX-n`O#IZ$nc;zI)u6OBei+H|-QALo6gx zhk}5$gc&4-@cWTjjT^@?&~41SI{W+D`UkiFYMOlUym^KKtW%3&s#t4(fzb5qQ5(C1rt4}-s zU7|90FR@aPleXX8C5Qt4P{U@Pd(Sr0;@@2uX8G)!H@y@~qEXwJD?r4Tr)*xUE3f|j zbw1GuNLY~cX6>N|O?<9bTX+NVclo0LO8>LA|9R7Rv9MB21m6Pp{(LmLe6~w=n`aiv=Q2k#oNA&+XCjS_?|86K^)Bg8){9ni7 z|MQgm|NQk22KzD8IsD5go*1%|qVR|ff7tmi)BS&V=FuWR2aE5U*KBnR*@PM4P7&(2(!)!6w^gKjNrpb)lp2;}7{g-qEX4yE~142XgN0<)*`nsbBU{M}zf zuL3t=Vy^WmY$eRVJ3~rp&Q3n`e$<;D)1b$y2#Ed^WUl}a-zKmy+q-}}f&V3~9^2lF z2tYb3ImN#duB7y=6AN@`0L<-Npw%mwy!-Fd$*P8)4?(^R@vX`A>ladlpP%0^yI2o( z_qWB7@w}A#uN3Yv5@Iqs5w~>6YT8go$>HZn5#}UrTeZ;i*mfa`evuq@Kp~A4ebrEjYN<%$bu;L>~3~9&*8Nkb<#|=;ZUTI5Iur@ z{>1)`VyDA24+1%0{t_z2p6~^1InWjXnea_YsZR13a~6O7@Ak=fFRq&e}$PN`fOmDqS(=WGNR9v6@ND0H9HM;?M2{lkq)};H8j#pn0U>x$a{aF@Z zV5;~Sm~ovbb{?s-1BDna_HJ1#1a_PE=%qo;@%kl-)wD2yp^pFxl5B1dZS<31aB`}N z`nfu72#tC@KKr+DKRz;f>-Db|07^1JJG1hSq!9PZ1=1lhhYGSTyNqVjy)U4JmE_{s z%^TmE3k}VsSX}%eKt~W_rZG4ldrFi;hKet0VpqF_+rP(@jzwKFH>f4E1K@`rGK5<` zZF7xb6kLuon|Uo2YiM&0c~cYc9VMHf0WG&{(f;ZK;rL+ToWr>2*-G`w)Lyx8MAF|` zNojOhdFe)=opN^~vV$`tNJHAAhX6*Y|qz|rK?2M&OAd6oCglI@{Y0<>e!ImC) zA6>4C6CVJu`A*(?t^Mec=tqBY4EilKDs9+-=md?UH!Xl7r|Sv9_ZvRpz?uWzkbpS6 z?mt)r{5jS30gBBtp?{E`>h0Wt0;FbUqnENXxL6tDK6y=Ec_ECbENMi}o%Sc!VECVDE zke~vWo!vfa{9!{q#mV)f%RHS)#(YC(vLJVN0RZ-ZNih&%B2FHtju9 zi->@nnkS|3oCajSK|3PkG$a2;kqs8Ec8w9&l-HqDaPoHe%BI8doU+xZC`{i0GSA7i^saDyWifFTUMdocx2tN$I;z{jX*B`pdhwv$R$VPR{yBA zv%x{K%^K7Irco~M_p28@v|H~ktF)v*u!$ddzh8S9@$th!%R4SUcMQ+CKEb94(naw-^3dNQfZ634(*PYZgbnT>($XO9YF_jaNrK-!t5 znve+`Yz5z=R#U#a!dw6=TZNt731xxMq`_jg+$55Ws--n6|cFeQF0dX(m^lz zviKPms?X<*!>#jZtds;dk4~KxXETsCQDop#9V z9I|&Hp0BJ{md@b@@-lQF@0W@1mui8He(FZFCYq<zCW!9aZX>BMRy%ch6vfSN8%s0 zJSRLaX^ODeH9mu2pz-t>F$lncZpamFB!%cd-ys7Qz|Edy*IfdO;Mv3aCpO6n8hXYe z*2zChDZ}%hkJel?U{60+PCFxk02#@KW#-dxa_*7BFiq|rK|ZRQ#T;d6ZEm9_ull$1 zuc8n_$hzwoKam=bbz8hDzOp~&@U?E=?cIdLyF$PSu&kcgJb`T7eU?q_#`PZT@kikB zKqp^uchlQ5Q9JIoE$7Xi&MZ`M6Nrs&Om6k=u|cXt{fpH4^o#L#xS&^Nbp6ILU3#v) zu&iI6^6ei8uAUH`#y*#4_DHjaC;7E#u3S&@<-!~jzW zN~(ITDsCR=Iqw#7bEFH(fz6+tC5r@%5{(}mMwJY*`If#WRlpcVq@>^dE_1Ll6mhJRm0j+PO*A zplE!*FsffE8fA0C85xx<=GehZq9^SRiYdEM`Y`gA)3aib(q?=8eBtQN{8ab%2E8Ok zl2MlZUAk|VPP`x|6cK)1Hx=xt%X>M{qRDAD`jES?vR1F4ySgZ?g70dhp_Otknjf@d z(MWy!{8>fqCs?wudXsd23H+wRMDz7^cCe3S6pOvxL^2cviM8Vl{LbT#QJ&~}vaG`# z!D++!bv-BImoFaZ?C-_MNsSXN{yK%g{SH^bM8yGZm!P(nD=G!WH7_rw8(ajqFH4-q z8I7$=xT~u-zKAt#+!MSwHYnG!$lqU<{%aG}$->)dxgYmof4z4vaP5x}xHhX}-nrp^E@r(A;ms z9|d0nD{bnWQ+?d*c3ZJ;E0gfQ2C)JlWKK>h0l!qi-Z`L00i{;ja6)D!*bHtC33jza zAYq3DmAgm1Esr$9!`1^p=t4GMQBf>w$`07!UYy7Tbn2pScD!9J_yyl6J2&&w0vq?+ z>6dYF)Y16w6~IAiYA-Eq>aM-3$WcoP= zoxewAHSHBN5tX!y0Ez*3=*I6mxRrPtwziZC%b9UqDY2vNGR=HUz227Fp$ z5DKUMyUU{}UER%1A3)Qyb4;MsHcYFU9MpcO{rtuqD)+Pr9QN$Gn0kCRzV|8iE-uba zn3_*ceHcF+qy>gSkM)v+-vspgxv1HU*^o#LpZ|xJC}ehULdXpAx>%j!>I(K6&wZ+yN>K}#$3F*aV`wXE_RGa=9Su~6_}s=2Yu zOocdldc|6Yg$kYf^NE)jXq_Vo9~g-reEB}Z9a|&Kl{iL=N;Jw{jbFyR|KP@c`yS7R z1pKASbsQMMYar>A4_)Nl{W;+flj^x2vt;wFW^`rr^udCup@iLi6hK2XwEv+&RMYCx zeFpzNZU^#VH$Y(eXN8{(sBvc}4w=DkpkhaDX#DoW_;1wvLm%mKT<=E7MQ=4Fqvfa? z+8mGU&`UGqpFT;|*KfGxcEqW@cUt`S0e@HD;C*~vmu^s9Rv8~p2}%&l`X)Z2t%n$%W)1uU7|neT+-wmfc8in?gvTV0rn~6)!8nN1Q2GtNgP;1^a15jX<8s>m zW{i*zRrnKZx*L5&Sg|l1#8P-zK}(B{yqD2}eBQwS5LW6uGI-t+;b@fo(l_|z*!$3)!z9dWhr48W@J$OkEZdj(jEwhqMlEULwupV7s-> zWn+%?|M>2>ANgIY)8==Dap8GE=>>GWIAr6H&uKYxn82e+`RE^-PMrdHtbs0!k!|D& z^Za8__kOV5swPY9>L3Ww<|;XyueO}5n~IS{L#$nT;Xs}lIRn}amgEo)(7+S%8-w1u z1&iiibd&$%^gM|o*8cnrj77HG3OGe*xKQ|?ff3mNXxtTZvGkuMvBEtx17k7B3loA{ zSyu)Ow2_T70B0FE3l)ie4@eHe@VC@l0%^*qK+!-n=;nqd#X$ILZ3k9@jcJ

qlwztw&^r)vFj9ZzduZnTOr>NuFFgwjS)=okXWfUJku!9GBCrb{5wyTu zVK+j(3%V5)_@4Lmhq&@HRDv1PAMby>%ID zf{J94TI?;&gyc%>wT83R#KjU#^gFpDyR{Ky8#m%aaZaE(>?Vd<;+$W8q2zZ%`#Gd&jH z%_aEdWhC+@lmRPz#ZYQQP}Iq~u*J)kICSegk_+$mup9Ex9wJYv?rH3sX|NRMWV?ls zA@B`uYVmDG{ROOYzFR}@P*m}yBAM0!R*{kY{1z;-XQvBpsx$Ia+2`-X51+@t2mkrA z%4i|kI9I2by28#^=4P@^4Aiclbcc0rCJWons;5*dXWx=}HdjrQFS!dbfarKF=^k>t zz6z^7+B-5PQ^T!M*MJ!N($d5sFS67rCxL7`J3_nFhQIWEWVmV5{6gc>6vT)e!TaU%cT z7ai{ZRrhD`d@)1YGO1QsL$;o)IqttpNVNJz>8Cf2%= zO8^G$1LBmLZZ?P1%uMnme)TRpKtShLu4crKzdj z+?wZ?AM_-gfi$dd^h?^<=zf9Dm9byreEJr>VwarIpaLc)NP=4Ysb( zp=dC{#kHvTg8Vdt%%HYoRM6d${cz~Q5OW!m;8@@I&%Q!(_0FCpIu;foLUOgjn9F|2 z2>VjD5B1>h@Ste5L^eWHp`zAxI=hy~DAH{+U`tb*f07?nRyJV&r{jKrRljSRY!>m_ zs0gLauZ93YPoLZYkx71?f}pB+C?WJFGTg+;d(NW#=lmo%#OtVx|IE{RPMF|ik;`9EH;eaUH@LD?^r#Wj(tQMVs~u!H&qfZG zmwue-Ij@L3$PtFcRl^&A{NR$_z-F}{Y?1K>uSYIx3;Kj0k=*Z55Am?vR#e)BhLR`{ z&&-e2LH{T&98BR!h8$*kDRrjjRrPXw4mT5{2blft+bRTGvW@z0))bM3p(C%l<`nU6 z?Pu7-TLrw3{}%-FyN<~h`tQ#9_gk*KUd?Ap4fK(MsMXZ-x+sBp{0xfSOd}cDNw=hYo0mUlRVXz`voBkoAFU` zJ|}+q-y>#S*2J#Gr{w2FMbn)SN8eXm6`N9)E7=)e&dOa=y;3+9@uRZ4_$ycWrVtJw z3yA5pwaCta3l&=OtjACNB1=@^qGNRZGbo*>D#?-14D}l3l{4kdW0M;K3l(jn+c)uU zBrGNfXc`+xkZf($<*kXO!Xz?+Z+uNOSwo+uka>Y=WTwq<#nyUHv{ zos}@{7VoD|>)h_|4hX8oAWhlYvi>MQR?vP%OX5NT1(g!@>cE9uT@6J8Ro^9l-W*?L zyifHCYzoZ_E_M&nUl+8ExxQ1fc3T^n@XVT9l>7P9;`JjHXZ;8CG6dei-y_H&5Jy0& zaP6*w^B<4Ef1f7{-G4vg@AC_$Mi;5amd5L%PdJ8>Y{nwh@OUtuEdr(LI^wa^Jyj^( zG>t+^JIqD~tJTo_L(Cqe9PaH|e&TjrJh+>(_+CZU@lvf7a)|X4I^y8KmdaQQ6O#`h zz`DhcIqmu9DFCeiwiIx1kT=ov!NcUYd?P2+*iUI|szwBbO7IbIZJ3YDY}%*YR|X9T zvx1=bFlg~-al7&!DLSw4VBAlCG$-&v(!YOB@Y#0p;1Cb(9Ai1S8XPmlL2bul$svC+kbS(b{xz2+ILz-B+Ni~>!T}M!s5;ObM64k ze$O;OwQTKbbKJ1k_E-Jy-dG-fhGOX$;%I@%@02e9G;9u)&xRSWcYkE*m^gU|$-FMIGZQUY-_ zxSTuO$;&%;d1HJ`Xa1Nun*E2nuImbqUa@$*_T72FZOwf+;)nC%BxVOY>1S5d$?3g4 zuhc&|i>$}`PmRm@|9N=HqIIOg!poM%5HHw=k^lvzLQ5l&X}D9-qTX6&MP*DtP>oeX zQ|?R|G5Fc^;ZQ!(l({vwmTnLYG|GN(`MEu3yZw5mBb^gp`zs(}f%ju3?`3^{9Tyk1 zYxXuTa+x}LDBHJ1a4;&4IPDFEHirUa%HC&Tn_`w$tLSdgm~h{WcuYV}VwLQ-+-zC5 zTH|fOehEE&^2Vpn^XZJOdU>%VG^`p!7N~d?Sz1|nnpL#Q2*o;_)?u&Il)4ia$>jJ; zSt{uR<4>8%taN#`D|~e}sq{@Yr}guXO@5F4e$w&CuSj6HdVQ2ww5$HxuNvg=s;%+V zx#!5utJwG_`VGE*tDfD_QMgc8`;Tb?D2-pefg8jy=(D~Uh;ey{)d>wiz-=UknFyxV7mg{20%kKZPuV-q-v^|MFEAADH!IXx#WPn@VJIz zQu8@;Lx53hhwD%}O6y8`pM1`-y7~bXtz4Ezn^(QCs8>s8Rq*648~ac(25t}ykCuMu zE)dES_VF#Lze=MHl|3i{2jFd9|q#v;1S!ift6Afuwb3s1mC3L`**0)g*X_J4^ z0D!oF6J;EV6^s;}R_pI_rWj;#t0&p!0HmuS>PtnZ*;>zfBkp&8x%DBHPEpz(Au9>Z(A?a10 z)9M>7{4Gzj?Kd}WL~G<=5M)n1=6->;(H61pA6G4g^ry2ncQA|=@hnnm5_E~=!VIMJ_T|H#|O zU%%Se)upkCv^*(qd0D)1kEtuDstVb}Pq|ae`SH9uTZt4}OmEy%d`LaDjX&`f9~Qg4 z>3-x#5PIw3O=qf|>B=@;z(MyXd!bLjq%d(A4k+%!7s{d>X3tviUhl^8Bv9e|SO>S|v^1H*$ycawTyks#NdGMRzqSht^jO0ZBwfDmO-d zymd-s#aj*+3%s6X63sJaoB?75XU7AMA!IJ!j69fYb-EvZ(M=_Eaw=f3i}oW5i--`4 zbdbSP3^*(wA)b$a6*q*QWaL1c+CDiX)LW2$-ZYvJc%L`3P9I%TcTN1$Ng+KC&+N3? z5c$paPsi=vl^Fkq_~oMU|3Y~7Hn(r@@c|P3@KA8Esi#M6y<%%ij%tybl`q341#YZX zaX%Ce$7j0>JJp!&=2=zGsmVvHU`6j0=RuG9J6bxT6gGuBYd{U66?t+G(8rC*$>M!i z2XzLJpbtE~*p$CRnv`ydG~Kc~CWG)x4Na@AvT-AEyas#-%-pu0rjsjNQiHHEWO_X? zKmAtOd5noFb_PvE&QEs5hcr!1#Wp5{UoEgtvAEiH1k62>iwwS)ekgrKIi5M_e$<;c zk8ZU|+_#jy1;7e4t)O}g)a76=^C>KhAlK#SyOB$KKA+L18PC$T{6V)L5~UFeue1G< zT1wtreWmNHH$G5ixajJ?E+(QHiLclw75-^q+1?)`Snk>^uzz@-h3afLtlQ834n;#a z^lr|f0^zXtt5DXP|LjSgqGX!s)2|Pw&bvqal{9UCzq|BbtNgqKg>LU;xh!ojct`#M zT$itnjZJps+S;azb$OJTX>A`>->2ULbOZ!+9p57~BJ14GB^S@iFDq%6Q>E{E$MG0_ z;mFEpG`Cv5fBovS<~Mqy6&7N)moKztk8vNO8D-er0Bksl=70@rms@eOLPoW8Bn4W`b(WM3(+y^8X)uY(2v=QnU2q@xIM9It;EyR0&v`%>; z!0Uk>6q>ID-7gZTcRE#dAF;$}_j`n8`|pw0n}7Vm;4PWY>4*W(hsXarB7?B+Z3y%h z&f`y6u0c1_JlU?COPlDPqRl8L}E6SE8m_+fzIHf5rGrumT@mru&eUN?BmuXLxz|R zT=bil&5=QG!#(f5kH5HuD>mY7 z@#VF1_Ev55uxmGNY3koHT1V@4o02doC&Y$$fdehor_>}?RoUp-SK3+9TVK@C&&W6S z+B+3T3!Zwvq}5@{zh8ucOQ-e-OdIH*4PIscHzp*K{eL#=;G5e*LY@|Z-#`AazFqFD zGnloTq!4D#n~;#8Hvb0FF;pKO+sB<)((u*Nk07Xb@+@zTEz=KijXo0&xOeT5mVBa>Tf(1S;^Vj1=PDa-vmP*1}$#387$TWV3h z_<+dj_kt;vjgRr_ph>m1#*5_ zcKgCF1t2Kt-bwll<3$U5`#nB~AQMHF_}uyf4NBGz2K}{TI0uZzmy0htEr&Lgo`112 z2Gp}(#P-|tTqpq8ki-20IGh?9Kc$45&wi!VXh;|Z7eN82EgB8>>8M}*5+oAA|ErFD zg`c5BdR?3y6UO<5D!U;sXNbvatCW9h_NH#vWUS`9TK>H5JPn}NdAx_2>gxpgr6~A} zX~i_g35C>{21z`>nCcxLry4M&e_3Efi@}=n1Mtm0NMa&9%t-3B_b!De+mS$x-X56uS8+{YN<6~!)zml0LEmgTRrD;D2Yh_i;R@M||hcK}%mT|dh! zHJw11sHw$C)sIxJQOMb0QMMZ?wrR;IPMSthD*Q7vkl9B^yU+G^4UW>V&Cvak$bjL+ zj8Cst4-`{CCOibK1heo$)?-l>ZCngBVix*So z-a?HiriRCw-qSaa{ynZH{%BAB*A33o5nhP}{jq7ypK_@B3nA*&-50EDo9v&>X5iJ= zKG{?^>Y-vG@Ixg7zy?~VxPjcz<+uJKd{O=SW;{U%Fa^fz>gdB8Y@&b`fQBftb=hvp z(U^H!lc`*f$s!Ic1QZfzc=PS-T<^=$`9pd6#8N^)U#*-=y1vOvHg0crL3arX>7K$m zZM(8BZUZ8=<$a&ua=p(& ze?V4wCcX&Oo%n_ULLB_)c{&xiEVqBOs8Q}b*d%-n?Xc0$hIQIo8;C5V411h@waSiTU&k< zm;gk>80ou`zYie8uXwAS9D#_^7BNSc{QYg{bt+kbz}xtE^EY)+Kq8|=tK7*&H@PLPw9n)5y#Envn!4 z*|{m??uPu(67H++ez(J+%fB zW(@*S9Sx(S+-twJ82$+aMDb|<7R=ZnOaeoGSPH3Pp`eZ_$#8r+kg~qM-e06AigIWJ z$>QMf@C9Z%l9*)>1egH>MpfFw)sbj86DPf6^**9S1`S0bsa%Hl6EXP)e*6Frceo9e zXRE+I)*K8V5{K@ic7p2U#-uRf!_u_YlQh>??yhP!Z0!7Fx4jzZ{#-%;z&gF6ozo!< z6(4r>XG)Op3l0dtg8Gr`FkttQEN**d-@vQL`YWMAl)za~E$F9#JWTnEuiM~`1*Dp+ znS)QN@$kfh;CMB*lo5%zBcK_rWPG1oA>2v%#yG9af$1f_VU ziPuFy5LfLe$y8-&+K@1Xu6lkXAw3ekqT*trA#c!blq81eo~7}f$G!5ZPkw@N0&`EA zUXj4tRI&i;$N4=oJAORS7%Zu9klL`)d+;@k_O}-*tY%7 zPPV(%Q4eizGX}^{uW~dHq^@BDZC`#$MwZTh%#r>n!95exra8y-_2T>4{I&;lsqGKV za|Je5w6OqMYF*l<=CV1s@!fOtQk&v(teEn1y-_beCcnE)NAA^Y?o~@??N?=Y7A(%+mUebw78hm?hs9EY_fEVl zAlx`cH(kh?|6S~XXOeL!#BfPs1!nrqe|~0s%b}N#tBV_S|LFL*X=;id90b}yr=Smn z?}n&vwip*?B`|$T#Rmi<9Moi{L8WH2#*GtXg96}>T=sHsNN_vV%--}lSQE(jr@sJQ%3O5Xp=k5WcNU&(rUvWJOXbV;uxZ&g{ zTY+tw;p#W{^_c|)%T%Lx!`k4&j$HNA)|Su1_)+Y}Qi#pQ#+t6Rn@%;S*n%Nf=L(cM z?^BZpjh02ntFS_%;URu+e1A!6SM1PY&-ZM$XI>IjK#i3g5RGLbFX; zYn74u{Wpr;9wwwxwGbu8&QAIOi$w^K}i^P89=*yCGUGY>j`Gx}vXD6?o3 zMcjB0-1s%?&*Uv4Qqn*WSHghVVFUsc2E0LVgF?`j2J}@k9DMKJM+bR|Xc%{85ErKf z!*Xd*l>l?&SD=FNR%ha4Ltx+~>#=eiP+yd`x91|owMpY*lL{wepWfVzejLZt1j4?T z;??nSaBzg|rx7sri(zMH_cY>|@AmI5rDM?#F?QfWmuY(d8_)M}cx>c|Ivn8)f7T4oJ z8_6BH&1|^XS2QOTaM;`VSVnc;1<4K9m(oOyN$KuK6&%F%S&1J*Yf}u&%(U=qG9C}0 zVRn;;vQ5vgMUp$fXgWaIj6J2ufj@dx98Ep7Vh%C1CTJf_R%3*GpQmdx{{%D!C}x(< zF@rMZ06dl|nPXnun4+%L_gEct!K4dHQKp6b4;AX)s=Ib{b>Gh^x>n}JgeXks7K}de zERIVhGmda%!3PBU>`y~mwu@asWC)ZZzzm_RwN*Fuwvb~b@i}W~21>J~o>D--d87Zm zDFDpIr(IA@&HLW(h8s3jZy~+MP}q_C&Qh%<+nsG3ViLNhZoP}emI7d!;aADyQd7%B z{-QcP2yp8bu#_PA2vxv#rcjPC zbT+(J?fl+k@9aPApf&D)>bvJ3K+hl(WG`Ufg4PN+w!TsxW&sMK5GFpw2V64(8lkH? z71l2@GZ*Oj4IJIv+Ci}E1?cNMJKCDT#>baZQ6cs`+=v8Qq2`H+I$cZV3DBi9o@ox! zgc+hMo$RXLgI*1Go({=S+x z4gv!9>q&-onuYpxA`CZg-XJBL;BLMO0>3EFrN|wNS%^PU&pr^{{d$*|1oTxyR9V<} zlHp@e?<0Ldo9GD4_bABKXx>_f` z0eG`Se1f{) z>bo(ibTQ(K3tmvmUVG#5Gg0aK)uqAEen54M*_fH@MumB_=sq*vvHzs&Ecx^{sbOpG zHO;Ep=#@k2ygX%WJRHfEw&1hwbZ8D!-}^O$>H#4Ld!;c8&2a0x{{THW2#}~D&FQbm zlJZZNP@Q%pg=zCj7;{(e5Jg!j$B7-sL+}Dj)?Z9u>eJCr`a%JD0eryUxNZ`@z% z^T==74+%>BK~aF6f~BXo`av%Q2VgRN{peIFN8&(N^ zN`$|_de_2X0Z<78fiC|#mL{D_bZaC8)rq1Ms7={n-_z4mQc}Y8P5bvysS@DppcVD#@nbZE{5vi*&;Y$HkbKPI=H`|x?nPGT zxsQ&Jl9o0CDOeMAPRa#Pa)H>xtzM*?hie9x8_3&Wf(>6Q2<(=+u4}V_IW_!I3c{o+ z8cU*lFjS8jV4RMPjeXnpy&u>fh z{n**rXXfWs*Mva|tp(D|h|g*F(;GpjAzWPM`qeEA(!VF`yhR_g|J%#^H`;-BjN)?+ zy$i_13cO#&u!wyLT|TKor?B9e>im`Q2Di}G0M{`~+(KK?*s= z=pm~s01ZI3+x+8)x{q$x?kzz<62vnL6OA>`Vz0C64~jOy#Mpr-j-aNFXl@&TW;0Db zEq6QMXwagy^NF^A-UEehCifNE?E+~ok?A7_WMjr%Xch#Nms9L52@|S&PEKJO99~Jr zLO>n8eK3l&GzMN3h4(s&x(D1(XjjQV2~6stUxz8)S2iMJX^f(}@i26J@EQ1FWPdzM z<*v5>5GstX!-pa^BTsE$3WICDkkQf@n2iEOK6o$`a&qn8x=)HpV}q72OJ#c8WBp6$ zXz$;o>HHpu@A!i%raKMXF<13Nt|hY zZ4H&}f=Yen=yeruZ!yqb3jmFd8?3B&piH{->kB8yZ@&Nq;x`({Oouz&?qjI~*HWUR z35Sc$P9q6HF-p*of6uNIELbjKVHH$!SnbYtl6+6%$3t*|!tr2{9yPt+A8!9V;7UYH{PHDww;!O=vu;(|mJo|9`!P=xS zo?@D=3iSx%+5&K7pb2icteAotTR|KdcimFG*ojiuHBe!RKXPh!Msj%B?VVf&PFzdnb{^L0OOD!3>VXdeNz~kUQj1Q@tVq22xYW1M{{2q0@H0;vx-GboI2go1$6Yu zSi_*-ZrKii{~Ot?$p%8-{nJ0OMKdJb$U&>vM=E>1zMDoWy!g8cs-O5uU!Z~Aym3xsJ2j4hcol)& z-2cF!*{{U(=o2`1yV=iAPc>YWlsSFf(+c5x>HD>F&{4wdqr^x7fiZ+~Tm?Fvk7NYU z%Uc>X(XJZFh;FMtBidfe9~-R`#p zMy-^js~3Ed;^T8otp&XP!v$~>FWx*9@o7$l?3vs5hwCRj;YZiZe^uGASbF!XSXCl# z1J_wcFzVsTMayuptYFie8nv99j(my>LW140aD|8Vf`Qa;Jt>n&m+i4pvoX!xElS;q zl?Pc01>VqkGc=9z>6h1&}>v$WK& z?9{~XbtR7R149kECW9j1+ZwRHE?mjvvKdY{lKAuTZ$y6eiiJ#?;V+^i+cYphlA1bp z;Z8$InRoI9Al7~imf%rPU0j)h{2`>HQSosp68SZjQI5-gS`yI+2`WY3Cj@A9VzFtK zNV<$S`1!#`SI8l7prfPHthB!YDyXPzXc~Ovlx~y06Lw-E#SLQdet0e6{d?+cg%ryb zo+Sh6Tg2%ga``oN_p==2wT&QV`U*tro^{4DK9ZGfhRQ4^F%bs~E5vA|FQK4-RaXz$ zkjEr0uD5Rob4!k1XD;^kk`P-E2oSZ@i0n-kCILZSX3)tm1yx&b(1?6ETvU)Hcd_BW z4VpePV3Masd$`p9VCdR$gLU7Bd)XW>P>a#={MPJqu`3N9_bXbDWIT&=R9Uvxmapjw zo&LJ0d14v7tG^zhl?-U+v*GbLfIDx)|NiLK9nBg`F4H-`e%K8Uq$@Hfw_oDc#88&AW|bTE9WbN_>%@(Hv|Clh<&O(N$AJPuD#PtZJoV^ zBF;v3KKFR#M}+=&3hUZ62fZ%MtJTf}n}A~8PyAGpT@Zya?o&?J8PAfLFSNN@v?A(to zk)CsyjJFm7%xizs91Af$7)r1F6-hAW^6tY^pI+llqu-w=Uw1m9Ay9K^J_m+E!Xtea z=W;RH8;g+3pnBt7{MYA~mM%}3o?Fs-Qu8lkn3-)l7BpSe^QsMJO&HF*j72{#8Uc+_ z<>GtM#ETLh&U7^w??TTp8Xo>~opW%%Kv!%33U%U5Kq6MS8DS4AFIhnM1rODD9Ek`U ztW`{Fp9CQ4!-!A5D$CVtE)R^wco-fPw`&2dmCN^sz}hGe5lr{AYK4xLxC)te3l|OW zLnqh>298h!UYM)6gRZ}tK|||-VPU~-@5pn8MP6M!+yv8X%}LkJ^Lr|QpcDOq-U9{)cmJJ;2r`l1}))RuG{MOx|`@AUpmwJRiW~n6( zfm^f1ahAuM-6Mtoo(W@7x)Lea>x5$ad7}Xx?1hL+4XIcC@TS+E&5^)9r$ceV+8V!v z<_6R)nl+Bs+n$VPyXD6JbC^3w+1UKk1H$X|dV8<@k@+{5Uy@(|al307pr*_2GExHP zsRd3ts+8@|l!5Dl5DyQ}_>C;)XoU?mO5b{D8}y^LL9=o7Ec6IGBS9^a3nf47ec?01 zjO=xV`pWH%EaM(FkX~)OlHDeqq4~Dw2!ktr9rX zU@a02f#5nPCn0EIxiBZk0o}oxCpo|wXb6}d1NJqU&97)qM+N1v za_W%QKp84DdLPEtkQ+Dd;*LPo^kEuuiwANu}HlH=ZRr&1}Ds1Q6Ne-~9>cS$+Rr$MDa` z^{qY2moU^6q>|T2ufu$Ug#jBzJFtL8uDytA=LnrrN70?gUhDa!_k}lGeoALPIe~|F zZhLx?Xny`v;Ld@A556s_+KYEc9f2xA0~A6@fUf%I zx{sj+jOx_`JbQlOgo|Rk1IZtYjg4id?_3cWj=`yQ=Np$;dt_VdYC=$3t4cQv5Rj`o zlDl`GJoXJvBSXGaOi_R|KCr6lT5?L=%rEN?E6F9V5x1D`f{rTztmGD(*j0zpL%!j$ zQWs*nyF$S%YTnOGObGG1WPy~VQJUTjb0IBFO(d%tgbx+|nOW$SC|C&S6Fb(%N&$byh zZumD_xmd61;rpGsp=K^t#elvdSiIQ^)zs^>w1CI3G}Uf$NGAYY=Vk)tIyxVR=)ToB zq8WDdYZq^bHt;nMPrAEqxH(OL=VS$gfQ4k`sF62Tl-~^zxA$uE z+9*OpFD>uY?KKt=*VHiI^Oc5{_(v+JDiH?9!BB+Wp_ks=CsNF17E3I;3Ik|7hK5== zK&Q!l`XyXiaX5_enbpfk<%St**tzHcI4=G0sZf~0`Uhsr*fG_? zIWm5qSHQ*oZ|CG3MWKK-B>YfPqi%r{bia1HjT#jY0rE96HlCTAd%EKC*bf3)3t)c0 zR7XQ>)}L~qY@7l{NU$$ymYWm72i*ew?)&LV&%kE0(qort)0jcU>0nJu%KoJ*Md#|GNq0hE>O(E?P`Gh z=HQ{CMwI#>T4a98D>(C7xFIT9*t*NZtABlIMIAuKg$HVA-DWch+lvGf&GvvT<_F2b z$n7VxJ~7WNJXCkRQUOS#x?&9~E@BWmk^b2TKR?7oACX)?@{}f7^o*5&{s^CNgHC$Y z)wsVznG=2-3>_Wvj(HE@iC<@05CFQ3|7)yvxD!7BZb>2NzzP!}t9$!(maVz*N-WnZ zVMYouy&NZ}`NzfySl$?ruE!*9qr(=v2|N@}s60lem6hQ;Hi~@*lLpe79d~r=%L!0p zNbr)VS$Y;xwUEfjn>@TES0O+6Vt1B>s~{@knVxnrV*bnUr9ui(97#*5)hS=fN*Iu! zj>yw3jZ^iXeB=9|1-N=;_0U70It$edN@X(ne6!{>c62HZQEaFTn5Z$GYeO~@@^!%| zL6}KhKTJK2mD7jh4<$9hm;mLngFB5YCTcPUh{cmj`)EMtzqkJ){QN<^%=1=$sfT2) zMG;U8Y2e`&yFqP6A-2X0;}1DwqQb|CJ%<(mXSKGCE7OkbSQL}>)jAvU1J6lyRs?{L zp^@VsW1+$@LTF2^O1 z1Zac#R)}ZOs956B^#z8I2dZ6NU6Zt*K(@%QB}sw+`rveC?@NdCHOEUZC=EEltMIyz zED0BBXa;WC2wa8nhwD6Fq$-a5)+XFEhxSj~w-<#ULLD<3))7ia&LC32J9D2z8r z60T2-SFh-%NwmnOv~^ne_CoZjQ@H6yVXlzU>nn?gSQ5P&=x-bl{UdYLl|_V$yB<@U z)I!Mt9joJlRrZGTFGAGqPlqq#UMrH?)L2v+Es%|^zNc}aus?G8r%L?oDN&=-HE)v3 ze1cf=)2-Xx(S;qTjzL*n%Yad;y5t7TjrUuaaw-#K3ZmfaL+`x5>i|A zEeF-NAy%2th|2a@gOC!37NPthbH#om{*L$>#LVHQJ^K>90?kzGa@;Qm`|l4IZJ*|j za4kE{tm}}g?0ZBO(ZL-S~M5*^yhQeRH3em@7;#&vH`BX_2nqF-8q0L8gBL2w zCkPx-LZCi#0Qbai@m(i442rl|SXcmnH_Fiaw06H2OysvB1H8jDY4y_O%cakn&=KGT z@t{Ecj^f+Dt&5nPv>Y>w{E@ZS6E+B?Pf~?^#qgu$l=dpE)b}M!h@J^Mx?jstuw`Ca znd;QvOf2TR#`+~geckqPc4!tj8=3xE*wm`qF=l9f03ZO^q<^`sG0A-6`AOeq-S-7| z28IpvtJf%Hb#>X&(*?2d>Y9)r{3;!fu}6w&6;&lzSR$668W@hglDIRg#;+%yE%Q5{ zlZ1pMG$4Q#aX?V?E<%9fNyVsW{s`G|yJn1-gqQgzZRoXZu-bot8=dF5SWCby~IXm%5b1uc0QBhUI z`_Dg@w)9LU=5}z+&KbQ54ZX$0^z!IPh~egD%n0xH<~y5pV*Tk{hXF%AZ;Pv#0WaE~ zgecdU$_y8u!PGu^sm<>Ea|up(r953Edn6U1EGgX+R`?;R4^I+LuAG#4%w3A2(f_({ z#jN?+zT`KRnHiyobD~s$^m3Z5dTRj-23GOnV5iO6uQLD45REdw&EmDGQ>$1j8yng@ zrM%1W1?B1LDRiOPAd3)Qz>NBkZEcgEdnP9@$8`?x?1x5GE9zP|J9H04i8ZyTNYS|qtAP0-Ld^%rbfCkc2()BehKSekaczoEO(_aci% zq=c^@DV=%c8Y}X{q1Eo~^Wt_TQBh{hE5BMd3+|d6D)=?u4=6>te7K)QR&H_lFxDcj zrw4qU%P=Y`qHtbV1)wpv2j1zda8(!`9fK20=;TeqU8>wF6@qbKih`UM1KWtK9DhULoIn2KE`zho^(@dYtsJy892}iLyLFZHeNb!ipODc)^%^B zoL{2*6B%%tU~hjBduycH%Y8exSBdHr-)F5=H=xPC%!w{pZ)bWfIfR%oO;JrEv2%F% zMRxaOrozPJ+Q}|C0sWsyyv0NNjqe;iDL>+h5K=K z)rZ{4`%gptq}y%XTMpA@}!OAm`ZF45_CW`$!_I&VwHTIuQTs1!H7ubt<;)#<}q_$~f$<}8}P;n@@e z!G^)N(uNTt$3-3;0R?$Sn{#v%i($uGoX7aUW4Za$Q$b-P^zLS8+D$!fswafv?ZHIk z)G<=@!T5hsWC z1a-J$%mVw(&m@f8D@{!Y6WZU4dGJ7A6%$z6;ZW~svP)WUQM}_Z0gu#eEYOKJ0pkkj zl{5Fh5hL<&1>fUn@T2O0Ix+W>RIh)cphK^k`8TI)Nv3YplnYDq(wR&F7K6{Z zh=|;9>V3n!4vUC9H!%sKs!;KGV?#eW<=cVK_IBw}?^4rw9o~yTE?vv)I`MCjtIR)7 zN5ll|k{>;96-Q)bwj>Ikx=fzh+XbII3E!wQ)6P=(>By;EF)pW`Hp_o6 zpr1Bhzp*icitI~+E<73>SdOO$UoQwtg=gp2qH1c$FXP33v8*gM-%i@|wV^95Ro1O` ze?3i|1C}{06D{E?Sq6`G-+X!VX4_Vhauf4iO(G7#-R`>A*TGv;9v)Fq)y~XN6oWOmDh$nf4|d z-@8{^SFNpSJJ!`-8GW^!-MT>OB(^qsRSZ;N3B_<|)^p|LkyI+sNhfhQG*>}5x zb+QyJ-LDk}YxG+}wHO0GXC<{`yr>&Tz|V-95OUj%hp{Pdtof3b`rGLfE(ne8Vm}uV z_7W@Q{UB2e}>O{uA zjCx)i6{GA>x>O#R66}aKHRV*nTfG+5coiM}73PI)H-b77rher||B}uOO+r=!d57G{ zh@sNqjP!;Z2MLuYMqDSE#)$Vks}fnX>ZRUY&$s0(#)}1Zx2{aV^@sZPs3*%m8}*wG z-sY~ZE=TW~=F0_x-jzKq1AL5DV5g*ot_T4bth^GTb)n+|92!ED!$jAc3P4E)vgF9E zZEOmw2_>QT3$1=;F0R+0&hKz>?jz4ca=i2Vrr-G=)qK@Za9x_2o_@Ap_q7_#XJjNL z5x{z577+ofm2cCFi-)5)VdNaT)8HXJ2c>}2!-q5L>)=Rd;||^(JcT1*&G{LelfV#E zN=fM|7{|1>wocE?ya)-w0(XL0@Ws1jP(N5lRfze>}??hZ!!2I<&fIGE+cDnNP>4}J%z`Y3jmYBfd$`EUr_O-vad8YteNCV=uyAF^z zH52!IU)2h`2N{(RBP(*}_hGil`+g`+!#C?~TGxM(qd}LQK1cEF-ZIZV&-h_k&sWCH zn*kk|0Wl2vYGuwwd6ALgjIwvrmIsdUF)@yJ;%^w#^CVXH#x1n%$Nkwo^t2paNm{}2 zQRE@lQ2bUY(4iDL7p*WTk=1IXYf5)I1XAjSD_mO&tZRcBnKD)KZzB-*`oXq!B`qmZaIWYPoF0L zGY8sI;N^1l>ea@dWoBBSbBywwJQxFCaug^AZyhUs0h!nAOw1AC6aoF+?}Ag_E$|>; zMMQW%=TuNo;Ikcn2S(Njp8G!zv21e`(-y)x>!+cU`nV@W!jBHcGs!vKwcts-ZBQ>} z;Jtl0Dk^F@KL*v|-v!fDCouR@)iWqJSM~+-?Sl0NXt1F;OSV(>DNC-@)YQX8dU&_I z&tac_g$)|_iC)<8R&m_{6i1puubdFNMngWlE?K%?^Q-2kBX{3Rt`3^WyX|nrU z3%u6?Gbtb@pa=x5U%!gGJ^`N|Fxqxo8q5R5wu)pikJy--GPA3zU65H?#@Exmii|V? zlSk;@1wa-_L`{9#u?ihM_wBFb%aD}99nd~GDKbDsX9nFb#C%r*p@G5Ft;LD)@vYrm zW3aW+t@DfrTbw?i!m%x{KSp^9f&-K^^Z~(NRPL#y6R@tvYduK(!8Askx7TZ=*uZQs zS2n%Ok`)(lrNz~~4yLsT-<7@wuaZ6{$fa@g>_@qJ4vK?9?V88sJdKJtI zoz6~NP^2N_LV>5wv#mHu{8pwoec~nN{S2tyAW)MOLx~xA>Y|xDBPe;<+8+etcMjG~ zdMwfcv&4g}Lc@y>N9?+}0B{op^h5mTKDmi_z=7)O=E942t0K7abv;3rXByCWMG=hJP< z3y{Q3h<#vvz=U&@tp@Za@Ygbd8`?q}=uUURA*#tN&8H2X6+j!9;pCj)&cY8bhn3m? zF1?=a2;PU1-;xx1p0fK%;PxnBH~AgTAf>n`A8_qZW?kyb%#3C|$%eorKsc|D@qf*$ z2G2)B*a(u%yKQB3eR~H7*)FTYK%sgmaefrgaDEaFCLt28DNrfQwgyVvswgWno^E`R zII%)9mtf#)2oFQO@OaB91{MEbiBTV{rOJ7GH*cotLLQZ_f>*GKy3FVI*}is9^CHHp zE$YaVh&)3Gpm!kpSR8UQw+o(vwAl$q))8gRfhDD6-qfw;$ zSR)0BD;_XdLg13#ZUon?Ps7G2YZR3KcdY#a27K}i_>`^f?Piwrim|9m1PlfdKwY~J zt`Iyf4X_$>>+4qYN`W{Uj`us4skoQ z$}8Qs8Njp57+j9|^AeW!S!9B#YpX_vUu87P!NJ?Q_fV?jrb2;lqPrhL46otvKr5c!VtuUb20} zJ)e})(P8;n;gHRPJ7om5V9)18IQ>iTuEBSM!Ocer{B)#dzC%M{08ISAYo`m`428W8 z*kH53JMhv7+53ZsFRGsyM#heNOYD58P$vNjPXtc-4Dem>_b=n5Ps73P2NIN=(7-b; zC0K;J=SRkXlPK;b zU|L4$52rTUT@RL;ZRQyM#jV7~6E>6==x=v$!^+bxvz-t*KVGCqfQ8~C;A!z@ePND) z);#zL^==6K-2t~kYCMl${T6}*Jwp0v_S(}A(--<&tn)p;<$peyx2QPnHF))^QcnCy zFBoqB^DBl%>Obl7BZ!5Ga5Nx*Kqq7x;^glxi_-_`V6g~B?#2+OBO@cPz)7Bmz!E2- zP+~E_1pe6P9aca#YlOe!MMC62x#F~=PG$C{86Va5?k>i44vr{@lDE7jU|B;WB3i8l zbSB|A#w;ZPcnba0Rxp4^yRDW_in_F*rk79TxeN{-mV>$XVi+E7?d)VoM^XV7gWF^0 zIV!6Fw>ViyY|tv*HtE2#={K}xAMLlJ0z1%yi1&}C3&C^=LCU7d^>a7RBRo19a-zPK z8<5MdI>Ih&-$>JHDunlh9ZuVI7hd5qF;mXT@v&BOBAE3}1D(!!b20@SDwRJ!e;kZY z*$gOzy^G7`XKSOSmo8oE%U5FsQ!XwF{0IOnz|j5&U=p>pwYT-E`M|Hq1j567XB^fe z?B7Megws2_fQFUx#&{x_onpKeb+ZLKO)ubOHbPWe8ZM*;rbd=jC~;*?%~NU!X&-We*ln5x%nQwp%Jq&;G*&n5usQQIzc|`V~wJ_{}VIxU7Fw zM4}=nTtq5)DvY?~91#f#P4#^yZ^ePy4uR+H&I$W_rkUw?;TMA&Z-Y|8{>DYrm*)}aNq=9n_Z`+f!OZ>+ zxFMc^V_G6~?zy?SqjkyY=z1z0=5n>lnBe5K4G+HslFMbdu;n+8oA|2Qg<j6_|{Grrw)1-M5X7j8IDd*bzXMlDT4tVaEzM3UY9K{7J`~A1l!Qa zC&z?SKa3%=zg3#a%r?8*SL0?E(H3ZM5ApyVWJ2;v6KQv4r4W-s@==Es0B_$QSwu4* zEiudp&HKB~46!0XxEkd&281FCn&u@#hp)nL=XSClT>L6~#8|L-BQ|brR3P%2oXl0{ zeTtFdl<7mYw9mrN?uU(F(P?+Wbv0!~rEXvzDJ;5=-+9gE$c^t|03|T=@+=EcDR6B;@i#-%Q#q5 z4Ss15XtXEOB>e7zmz6Vs?{a;5=VFEb-l1V4%*+4Sb-{Ze5bO__N!Ke|ZYH zuiwGqydzCQ0s$nmIiPxU+ZPkQ2Y~YRRqZF;s?88@wtvWRqLo0h5=AF&Ippie08ucE zoRi>|JYBuhqC(gRxRv+sobfm>^?fq`M;u`u1i!y(us`K9HqO+nS#T=YEVXEH2Rst= zUrTfJ0|X1}LmnwO?saTFwiR`BSNlAY)NLwIL>~?SN@Nm#&)V?co8#}7Pb^&+NkvuD zyNYpsr+aaqHl$I1J^ynb_8kcY#Uo&{K+w~zb`A|CVcz-1TC4=o0Iut=5a1LcdqANn z;37#8DGhne1GoZ#LasGz1?%kK>gqes51yhZ6VGswZ@y4^LRz8+4@~QG4lr)OdGvCL ze6L&q6eZ|eZPa#La6#Z7?twLD0vri+oTvIB_>{3TNwKadV_!AwzP7eth?Uxtc7wS@ zaA$h1i9q4?H4Gr%upK^!?)Ws<^@h^g2A6?b z=c6J+mivTjI^Q=7&JSyfhHWI;yX#&Jt%T1@0pj!6wyd;N@nCGi@4WdZujsbT-IwE4 zc&4sa{~SrwSM~VcXivz^jy7Mi`ZN0zd5uDxkN}!jVJ<@+A}e=v7F66hXnO&clQTyt_|YSyHon2Un=+y-essl%3hNY<}>IH1SN!4a(15czyT zF@^j695)3%pB;Y~Q~d=}{TG9<`Zh6=xXzA?B3EZ~=+;Pzcv;*-JggbDa;hiZQ{DLo z|JPZO_8VeEJ&&D;YDjRw7!H~nFTu4Kfzy-+l|?_q+y6t>R|ZtMZC!6bP(o3Vl$MYX zl#&ibKm<{`k?!s;6%`3VIu)ctKsuFf5NRnvknWKD=A)i-@B7{TBO0ZwS*J@PKZB>8_&@MYJ_SHQfqPcmd`o zYBwVBb3?=R7In&A&kwpP3y4e2X(PcOWZpee18Q0U;TPA#7g& zo3>D#;|(Q1G(tf$X&J>H*qP9m6w?>dS1~lL#@h?;uc)m20#F$RsHPpV4MAe)t5=4L zU!RzvB>B9iZ={)>{U%JdgCuO09nRJzoz~8hR0O!DO#n z-BTc&VrkIRZ-gQgNIQ%Pb*Y?a(XQOxyY_F~&mYYEe6#*t$tc;PGv#f3=0QN#n%C)1e8igzry&)4abY+|9nJrJ-Vrxh}SAWLS&1a6-57H*}B=xpeWO7yz>C zilkR~En7X-YNVixXZZQ4rCJnJu?OK2ZwlG ztgqW9BqZe4hR(_&g9!i-Y`_<(spVn#k@ta~rqV8Qa7IYvXuZL)K)2lX?T`KAy-9hO zL@8L7)zIU6dwC=Rl5`ZC`e!JD`nA`fp0FG#!t{mGD&v<&u6(ixf|WtK_5nB-v8n?n z|FF*ML(6bD@5%)X05mEz!#;vgm<;oXfvu-0oc^0_c&;V|Jg(>Vi0JZ3f3ok6K?RxT zv%6boi!A$Y0B8SJqHXjti`I*8)=zD1Tc3V1rRV%kwYREs6=X0izPe}wsi8|mL|9@; z)eNp}Cg+@Ve?mHO*!8xhlMmCXz+G?F?D%D8e}z3^tf7ri^FxV4;|K$OnSW1_O%FPh zxIw@;+tk*)tWJ7gRAuzH5CIM&Fsy1_>;0Raz;QIz?rm2(;UCmVzoXmH7&JjNo2(TE zq*q>E4sBOOd!bg4$_LZud*HP`T8@N+PkXCdaLpDlJ@6XM@B=V^UGG*;heE5WJfc>A z(c9VDexMLNH)0$K>0UjgpD?8B6|)~c^22QrOoV_RLnsAJVIb3282EdJbbY#@;6-2v z(4r{-iGfOc37`;>1eRBdR|kI0%*>3y$yC%+T#|IXhG(&*(aFiw2xA4u>tF>i-$Cnw zA{C|_e|>m9c=l_qdIWqd$fT`{13B0iE;K`c9zPa34;Wn*NuOLM7oe*#Qei;r>`r4Y zAW+VLxEBHm(AXgZ2{v?e@}MSp=vb~}IW5&R|0=HH_cX;kr5LNi|fHZTt|1QS7s!h{^m%`7@b{86hQ_GD;qBN(7|^M%@10*9pvk z0s)ByKn+<8##m^+t6pKxfY|W{1|p$AL~sVY?>zup$a|#A{j7lla}3MNOG_59F)?Hb ziHTX-RlJCj0|!o|T_}Ml0`3%b?a{k4K#Iz%CW?3++yHC|Y)8y38!D*T9=OQM2f?J> zH0h>5LDZE3lrmCo2d%3q&{E*E(`6Q=Yl8p8Gjp~Qor6RLi$=57%kXh#3{fP-v-$43#fYsJg~Ljxz+XXcZA z(k+Jazkxu7hJp0~N)pF`@Q=l1Wi62B0feZbN2oLK@sXnB<$D~T4&e~9nXW{!0ps(S zzt;QM9cnLrRVWrlDxFxNxSWr-sfA+aqA%1xrPkx^K^mLF51pm)6!JDxuZMa=QQsQnKkE<#&clEJ$D_qfdbxAnP)`RWYAb ze5UjG_}D>7jEk2y3f?70-Zo$1J&s%)w;m*ZSnP2A(KI#*8=0P*)xYOonYqZVT6I$> ze&N39SXGfo5@2U{V+LitYV6{_;i3@XLy3BA>@L`zzjmsdi4$u!;VZ8TN@CQe6ZJnKWA`(SY2x( zEqxAt0zJibP;dkFQeYXQ4>ODw|+iR1e+Tw0Bk3I;{(IGDPZ67f+SWP{^S+)Wwh#L}# zfq{S(+0oeY3aMydHK#z;O_m=y0-GWWYFk*JdN45vBbvPvc>YQ=tlgXOU3e6Hy_=rn z@H~)@j0bA|v$p>Es?q&&@9*^7CjKBD^iXm|Cmdb~$j$v6Tga{sjaJLMeiq_(e#_9PFy?m9gj=k3B@KczlCYp{A!{uLquN9qK^! zotY1%@ED-tpo;+^zOlL4Zi`Hi!{M&gTu*WjNOD1miQ3OBjMD>?9r_QB;>m$0g)_(N zphIg|v%)#gD5287a^kRf=<&FykC@8X;3^~=`r>CY~g_7nwaGy~J;XKev zJ*3T$4(19H*(U7V#|9B@r;R}`Ug!ZT6ubRA4>Y2M>|(na$^VoQp*v2es4q< zG{Se|1zZS=GXUx&U7uqfMEC&({F5awm(!vWq_$3==VBJ!lai96)+RwyG0~qNylFAW zMx(bm4}6rZqhqIS7l0*%7K3Hf1Pj>pN2DsJ7FPxg`xVIZjBIRpzAh7P2vgss{RhDO z*JD0!P5oI={d>NXF1>#JTI_ajYn(lhXqmN!!9e$KB2_g2+`DjuJ}wKIaeZth_-qAb zBYY%yEd3@ND0*^7$ir^*SwnPGY5i3_*&A1w0MEs;um*0gKvSbMf4k!xw#FN5N^! z*z_IX*Uuu|6rSW1D@LA-kaldpQY}j0eT027jOKDXcT#HDYq*%i`vg(HftOGYtPi|;Sa#>mpD&T=0+9M!qk4InSwAu^+#M*FH`g_ZeT6-C4K-RV z7Qbdu2)SPLh1}B*TngU66&~|946D<1++*^}NzqPgpt)O-)ZB45@j! zTfpD0xA>eMyTlCw0YI2~b9#sqq(UG4jEg;R*3OrJL1rDMSEFP%fH@8vV4aDAL)j(2 zv&+A6m{crD_1?8X1>y!!3<$MPY zCIi@K6y6nHJZfrcppC3cgb}tJM4;@9o;{zVO~kO4&HPQwn)6zWxa+@5Hk^ zxq_KXu@GhjJ2qg0#!la}hb;(!2n!YPDQr6HWvBxfFhHt#fH)6CyaW)X5Q+lFrNLn6 zU~UHyLU#Q0-axIFhsH-!VE7sIVTrkNchW$)!@p7IpD)~;joie3C(k1JA2J{G-A0-8&?WAEs{Zvb zgX&0#>&FtW)wA{iz4p+Hhgo6Jw1fz(z?udc{X%FSN z`1J)ax<=(KZ(z2+K+)7eU*;p|`12xg*Tu41o`Z<)j*f|gS_eq`1?B^ewQ?zKK^=h< zT97NzAErrP@`l8Yw|6jNlH6DA=753_E|VzW#0O-4+!Df$pB~MN0*FL`73C9DRdz1& zcW{Ks@Y7i(B_-{F|HT^!X9|Tz^8@DNKr=%kQ=jmeeoFF1D;1WT=gxqt*ykB7Afov_ z_dg7{drkp!U%fM^iIi^x7O?o$KRiZ5K`?y}->$NTdqOgbwdC#9C;;UdY@=mhu}8LA zLa8%g7(k>kv@`kNoi*p2yU(ppeX@zwq7j&7Y9DVDt{G8QbHtw zzIS)|`1nu=t8sL61OZh}wFcH3tl1{OAAU~?U>O8$07SDb0Llo2+245)(6=;{Rcj|nm`{-o~ELuH9hK+ zqJH#Vh6s*Z$^aTytZ|0T^{vtgmqrm$EC8L}zu^u_C)tJQAgA|p6+7_h3P-(E{%=Tz zzu6PxyFAB}`_( z3E#?jfo*ed|SY+-UamK zdbmFHy4 zD|4Zk3yV`z2&2|NAY~pS%lJnkY=G(|$;{*4=)y16|CycHz9c`qYy_~;XWTQ0xpk$| zF)$`(c@>M%6IZy(#D&C+kc6ZKOc{Lc+t(oZ-s^@yI%!`Gcr)jW)|V^S+|>Xxox{P= zZ+w0!rpp+h%oV7JTdUS;JCN!Qs@aHKemJfNrGp`Gq;QZP1ADp?D7^^+mUdZubceyp zRWn4y0I8FFw9KXlf(t|tdJv`4pfp2<9rm3;vMi?{)MfCm$kBW75j?IKA0JPg^gaxR zbgNmTDkvzJE}#4WJaMF8?lf|rgP6+)MW(@!hr2tce&e|b_oeF{vkxtxmFr{B>=AQ` zFAUx*$Z=dCd;q9?(id~IL;>XEI@lFHnDkHquXGozco2r8wtxd)h`UWnNZ5doPw>mx z-hOSV@H*s0A@+@(nGhg;iCC178(gBo*6N@ndj<5m`r_Jn6^ZZguv&)*5RIUd_rV;u ztdareZVEEMio%X-_=FP**2XlfBP0_5zU&8}r{ng62x6v5EPFx%n74}Ecg%sgZh~cS zy-bjg4=x>&hozxd;v)k%194X&>Nec9hRgwgb;QO6(|;F`Hn1E;5zTkP|hakwt&YTFK+=0w~f5Hm6k zX0+hFpp=r~WY~g{kD3AFhQ{qUxMu`8GyrG287n8CyZ|%|#se`~PSHl8qjwlcc5L5T zYv@^MLu6d!NCAUV6%=9}6_9TkD|~)*C&t6TCc-v-Ul|CrZY|_isD%^h`Mmen^*Zc; zxd43&f+#}qfkz{3QTRlzr;a%&C&tPFO9y&a>&)2FzuLnS{;8n*REBl63H3Z^E zPj-*X|Ac;hN-PI=Nk2oehZorG?!JwmOH#3Gc0cyZ{gd zB!)o7iLP*%2QNhY>Ty3Ed>cSpAx@f^xw&ST^)`^#qPDl`1-%Zq$19x-dXj`+Si3ko zr$b1*%&PKAtHR!HZ9*8}XbX%vT-PS=Xax~31{^Ag&BRs|LE>O)L&0&1M=4@{67vQI z1_+rARlX5GjTipG_zsSaX`qlJv?^dh@GXWX90o8f-7a@Z8_#waN$;H(-a;-&?v z65NG$TXS-7Jrd$UqNSz1XAW{8cxYRI&=3PRELDXK{1hDLcv5*)S5 z%L$7q8yKJxd^l51{Tr_d4BX0tMcx984#D^!ph~1lO&0(>@nh;!KvwMuT!onCb9!Pn z3OoZq%j3%pHKByW#FB;jO>Cc*XZZvK>>+>9hpx!S0m!`RbK*%udpUtaw-#?;tlEtW zc&$=Ni!4r$-DOA2tRzpu6m`SxNnk z;6=lsia=+jmDPz-h)_lD{Jw)KZNOK2eT$qQZWF4(fn)#^F9TB>(2dJ26^w7US zr2+J#>Pw6Jph&}U#oO>Lig?57@enluGQI;k2M8Vq;Gz)z3sS(1SXsoD{Nb@UXts7h zLxd+uz9JPbF&`kk@z|Fk#S=gbuhr>V8)osU*yQ4mHH;Qu=AJpvdFHR@;Jg8H?u zmViG@29S%Q(AvyQ1F%F?g3S4lR~9PQKog{E3Nw-%EU_MsgF+i2vJpxIpzg3k&yPh!LU= z(ncycpjAe=gdt+~z)XLJ#|J-t3-EAo&L6ob0I|(kc?q{6NB3)1d|3kssT8_aL>A`ii$_ou6E#p{OohG zMGZF#fy;m>Z&XTJTDoZ3(BdX}a25`ql$4aHeRv*VKQKy%=3XKujxroIHO>!svJl+% z^eZTEz%y9v&xDE&S2!@i%Di6`2=pV^NYWu4!QOuc88VGkI*tmiZ?qi#;0N}mL`bT3 zP{Ywj;89XiGQ*vj2o(=-4tSg}Wd1zreB}G(UKAH|K{zy%vU|0fFyRQ(@nK zfy(vXjV^;H&9M%+JX$t3Hf5eKhra@zd~h`%28thoQNHkr6%5QPa-Nr>r$>m^_)79B zU{1J+P2`^9!&`#t9{zI}vBwT6pyzaTUGE2J;3|RaUc4jGpD$l$JpCh1>A&tEVwCSZ@)Egnp5dj*iOBCKgzN{n z2z?4@qpm+z6a?u1^J?w?>n^>Q7R&L`EYfW!NBQZkLn9q8f1`SL5K}n1EdCB8%zcnLu1m?V(m}~n65S8hf6k80BBnGb zWG_)r;EBNw$pU1=>+;+1@qZ>(p0JCZ0C^O{8d3Dk`7#}0LBW0Kmh#8cpEe69e-?5S z+*2ov0!i`tT5a)WPUt_w^Y5RnTpS%tzpGa1?x{ueHT=L&4bb`d^vc8RG$->Htr4tX z)&bQL-b%0H`n7AV_SK+oLG$eJTrTq9H-H%4-3>CnmkftE9FD+4@FMBH0&;{FLKt#t z1i*dSH`qSiz??FxeRynK`unWOe?Q4)X9WpPmqxnhN$B;*oJQKBBjSHF;CqiICvHp& zmfPMma7sv=s=Jf>CH%S2G-7)I)m%|%65iu-4_UAz_~m86eZZN@bLmo>A7HqK=a;U2 zsi}n&#im2!CF< zf2f<;*Y3`NHi*S!K{Hv91kbxA`}&Jk!gf>cB7>F-@S&uXl$7FzqM;T5#9(+ESfFsl zU~mV6E6WxxoomsFXH{hfEmj)v!!@vL5LN@?B9_M|I#6i?5|b>rzP~eFVnmdBM7T^ z(svI38Mr@xwpp6UpSFEEzMreH^`!}eIjPE?zc<_ChhgY}kamqdJ+9zC-|xo#cccp~ zt=^tqG1DC?7MyJ}IQIT`E`NW)Io3WY$+?xmu9CMfw;K7K-zD^&$~Y^N$L##VrTO3A zGJ85)we}&sn-_1&_RBM4u^r{4)X6aJxbqHgKC`Bs95eEE`*-VK!>IWTj8*Ho zva&)n9k;Bb!QZ#w{rfSMk}hw);iN8B9Gcg&S<}B*Kr(#EX|a@f>sNMmRG#Fgv5X|~ zZykatxb8jg$-iictmVw_%l|opa&T{~@NbRbQ{tT=KdF87Z-_v?$dn1|i0JT?mG2pK zT_~wp&l!Z`kKjcgx8sc@A3MTE{dmsgg6yIQ0lnP>?Q@w!I@CGv?i@9hSKu^xWcfcg zdDGF}GvWXt==t;P5Opp;U2n|It^3x39xA^I0+E0H_mwFGuH=-k3^6wLL(xLycR7ew zp;ZWxIXj1h$s~4ohGh8ZmOR^^^e};bWoRf{$L-A7|2&gE=AUQMTp1Oc6k#Z{_zG98 z79I`#e*;FfI$rZ|)uFt6pOe2IFC>IYwj1^~@_NTaO!&JYVk`9Yx>nKEN#-l9bYk)E z%KiOKEck^k-732T|9t99oXqtzU5yg;6HWWkT-5eRwY}ZAGvv&(K4bRZ>*@?=ie!t^C|9MyBD6G#B zPLRst@#i9Kcqb)HX%-JOWHl)5yduN&JbC}Z;3}*0b>v_E^D?@d`be*%x$M7wP}#qj z@Pl*7!VE7jQCU>`=RfPANX^zO#qF9cgBI!DCc3+0!JGe2IgA_~lv|^j7MC#M2>3e! znKB=WF(fY(EGsLqGn)R+PRf$O+_JqCyk|a?l?Z>8b()7;n$)i1vID#cHpTe(pVqd1zf;(81SND>>Y4OjhN73#)@@VjS)THPCyBoc_(ekyaR5#xTdp4GxneG2Q$;wvk39@kA z%Y~u*Rf%uoL9mZ7TUM4S9`%b}4!(2nR;~(red9b!gxlITk>H^DAtL&k_uu?9^1f0N z1~J&W6!_I2BwiY|KNH7$#nSG}GmX3_T1ozvcUdlPUcPoYt5qdUc(>>B@bK_-1(^@| z_JBFh^Ga`2*}Ks1df(4qb10^HEe%%#U(l_4d?UEE=U$0i`QU*avN#gtiNxMW5F=VBy?lv1HhV8-0ZZ zoMSJz?8O;(X)ApWI47Y!8G3eO`r$Q&w<@gg`Os{V#lGUNzJwOw4TFO^y-ZhysRYZs zo^+7h5_{j?xAyb_@Za?zt}A(|9|~`tGRNVs>fRkr6@K9D+VMEl%QN8O7e`cF8EHt$ zRK9U=mI~|JundvWF~e(@&01B2M%Se5P%$T;MX|g}Mm@ik!}wTJ-BHlL{6>b1ozcP&irgMHff~m^!g{H&h@-O!MKc@}&dl+S(Br!)bksMVC5p`+c-3ff4 zhP92lbiI-mc*GRb9M&-L!(>>Ye62tF<%kAB`s2J~F@g$xQ z@jGYsg&KL&fM>#8Q^+Gs1Jok-`$yC zSl`aIx)J&yBLF^IQ>us4v`$-b_|D#{kEYZ>#9!K(v9lH8-7cW{K#YmuElQ~f*Ms}JoZRPHn zZryA9E~27S54ayUoX!8U2OnX&{!*R_{m~riwT-s^sfwtIijGCI(8W(uE|~hzlznRY z(c2E%clPP+9nBNty5E1k{ngr`h`J{I3eUQi5?U1cf1SXrkRdZHl4zU|!H8wMME9E1 zYE-U%YFd|6ZvBQ7OrGV~5oC(%`{HF05lqnX>#6y`l~3>p_V%36pCxeYCetN{Ej~wq z>)(XU-=3y~_GWe96|>@5!;kH*{i+=1)tNxs-_8*{7!pXlU?QJa-)-gaI`$Xb9VxQD zlZT&G!^O$93imu#*5+lHSm9Ca^26QUTHg;7PYrBPz5xMOB&8RS~q3QcTXgf<2jW?8rn^`A%N;p~YM%!n^iD{i}&iR_b|$e&5^ zg~W1q&XNeu&Ag-AgXWr{mq6`D!7VDtD*I68B5vI5)oS$!MMgPIfm#1~F<5|z5xN#PO9vS%DE?EqIN$D}P>o#07)2}~P zUNzK6GC4j}H@M))=i_|d+4A@z*}?{7ApZj08^}0!$cpLTrpGz`*anjfZGykj(DrCl zRM;<%@9>9Eo+u~Nm>C!ZO+6EyQq7}<&wI^*lQx3kJB(eJiSQFOOC${Ht*>+B%JeGF z8R`%1hT1K++Vq<9pnU67x}iPYxoR);w<`1By^n~rg!V`{xu{Vn^RJfv@M$FjBx~Ad zy`oEUrpF4swhpCbpMPyR%I1*}tJ#HyVQ3{9FA|pV8e0Nsr%!l(I%+5t^pQ45dIvCe zVZ~DH&97C?40ahbb&vb>N|ADJPdcow`z3!c7?XOK^9It4e_)2_YKyLTDcyNz1t!_p zQk?4=Az#bnVMqyEh~c^`JjfikbGkU19-xk~ynR14h}?2twqEA<+%q~PXxU$0s#@R9 zHW)ZsSg;$eK9PH(J$f#MW~9=rSlpC!6Ytx%?5np_L#kZ5zkmK!x4pNIb>2h&Yq{>j zRO1N!mZZ}=91@d!T9)y(7!wV!au;=}g}JH6$~;k#EN4YT{MOgETLKPM-#$$H+}(XC zA|qd-V=xud050O1SsAL9@hotd;4>ZIf!0TUE1DwpZ3aPlFb@akE8lwC-YTzD4uq`& zAss>`65S4jHvy#vJoA1TmDi#Mm-0n+zk6EW75{8wZvt!1OKD>XL32f4?>qP!vA&{? zKcrnh5&RuKL_I$e3M&&3`n4|AcWH`sTG1$C%^G5;Z?@}@L65P1=9$7kuwtPH1gcJG zK=8_39v(*Jv-<|&PAy@4Ex_kKhZV<*M)67%^~Xg1yp;tk?Dd-rGhuNGVF}j=Ui6k6 zT5ez2f7^zmzhS4x_hC;HdYY5aUEO`W_^Ph=+ALY|d}oiU!EvRk?czScPe+0BiXmjL zzk`f{rHl*rXKJ-Pb1I-YXx0NuH9C93F(H?+m2Xf^@(-KJGj47;xf;A=(|VeHX(M8? zUMC!92G`i6&w0f-Vz5TbNdgLymJe;n{-GEaZhr+M(9?2|Lgqc5uN%>H=lj0Ql)lW| zRiEv3bj$I5-mi;VD6!)y>zErx*q+Bv~8pG=V z=67n1?7j7JWOGhqh`zmFrv9^k%?fhm)bObJ?Riv{FAob!7Qia z(gp#10s^QkP`;LT<3#ugQPx_b5B2@$Hd5;hwhnIXcu*+S;WEmqn}>ZHt(|co;H8B}x~mBYu0meKlH~MfrjXhYvAi@pq4;b%g}2c>MjVaJqM9XEoJo zEOGSL67E98I;yZIR|vPk4zJHe;#m|2W$5-t4-^i;NabE!04(T$prC?25jz)-@Ab7d zcB`G{03CuCxK71w8>ozX$h>B5sIZY06!b2vDB=^Qv+-m;9!?)W1HqoG)XEz_5dY}O zle3r9))lGoNQLk*uzHF&DWipzb$CxSxCo)q{QJ;>O`DLLgv2yAGK>2}`1#5B>>Mw_ zO-tCgBzTg0Iu1ANJ402J_pX~CM(q{a?5X}7b`wZiIA! zCGslTXb9|se({G2J;(HXUiM_Xx$&v;ycfDi@~HLJ@_YK;_A3c-O$qNG47S87vRoyLqnl(;2PIaM@*rmC3ojpkv{v5zjDG!wO8x_SL7QZE*M$LL zEbJ$D&A8njvKX~08`E;lhrgn-%eBNirV1k*%#` zpadOH#f1_9k{9@Na2eNLx#Ki-Kq2|9h0y$QT?t5R)6)z1SFViFEq&2z8N`Qqufulf z+4eXa5a{#B@=KIT&ZjR=Q@0~&7zhNbHxJOxV7l;(ig3vL0g8u62~c2W`1R!Wy!hMC zIB{?T{U=ci6N4`f9ew!?mr(}vzly3yq=K5XOx>mRP8aCY~94DG)44p?QJw3wzcF&3#WS*PUloMM6u=M@j1 z?bk1JHmw_^&^$*E`FNEpt`SR6`%D+R(L&Ds+M?rXmNS4|0h?I=2X#bB-z*vmGWq)F z`(vFCO7WnzqD7SGS(NM2aj`K&^i%DLCz1D=7U%KI1W^4+x*782JVvmR3k{a)7(Pn| zA7cx<*BK8AbVS@v^2Zbv4mjLU-7f4N*Qt-$z{ShAGXPAkR%uJW3Kg5lL0!<>tF@e_ zsqG!?+fqnzpXr#TGI`5nOuK*`!&nY{;D-iQjtYXaoO02tYp@?L2S#(O|&=s zvHrYKD!oeA6gGY^y=`rK(1Och#kKV50>Ie#6E{k!3&-z5G0!+hao)E4#|r?b9@YYt z7A<$bNf-*lE(A&=I|L|=6TwD?TeR+*jV%~!)%ag6z%8o0F2(mR;liTp=2qXPSZ|_> zdYk9VKJNE}75DpJ+9Im_lGDWw;^09hlhM)9nfLrvT@SjU<008#fd?kQ;7ld{;Sbgi zUU(_Fjl=-R@KVqTj+0yek}z(}V1kZGv@02!T%c=U-cIRx>Lf+aC_y|X50!sY6A2*K z%*hl%$>2k>F3k|`QRk)RGCPi4p}A_i55u#vC|kRoJM;M*KXsQJ1&&JG)7x00pgaJg z$krhzWYkFmfx={vb6q|)@vz?#!c=Xy8hVLbA7Zzuz(oKKj5f_AT;ZNVxOZ#)wix&a6voV6D-q)nN zmwVmFpM@TDR|_XqD%8n8_0WpBtno&I?rCw5{HF@4Z|AQ{`q*%8*dIpW+X~Ln>v((l z6t=~ppk>z6{BaXp{iTxx%n}WCOHl*5f|cf%?+LeGgagQ|J{lD%j^L7~(0n3yS{+g? zgb7T_@P5w{!!9=d*vlV5EsOKH+8IQ~-4j~+@X5C+*ZopH&jGhI_31drIIpC7_6PHg z(+m;+*-rLx-Ny14xLq>cvNEqezZ8YO_v5%IUkr~ramXZt(dShBrB?{U_j{d?DuvB?~e34pn6y-ARB?&;oRj)Kbdf^h<`v(=%{u`Sa5TTNAM z{qA+@pAlSRALD)dX1tks0bw-iUy*g+#Xn9mFCouWzd7(T2`y9vzictoizZFL&|l085dS3%RqAOyevlW(90H(QISG*> zf`EW7EXuj8QH1XGxvR}bH04+ZHp!ooS?`}#Ak{Ct`ud+@$0@yUoWM*<#^k<$>8*~U zXHwlobSdO@QpK)?Zd`}XZH~pZAN=AsT`VDCnAG{|Fq9zeM2?<(7J`9W5T;Ap}W{?(sKu<6Oe9|J}AS5ld&BJpM*cRz< zgIPO`GfaI5m5%Sdp6gO#kIxo2V_V&nT^E29XstDAvnx=!=iWqf?*}!IMj(e z7Cc69M9!?C{;je_(~-r= zGurPJp7F4zY5-&|M1yLoq@JYEm&#?)LuN#CyuQtn{HWg)&m zxe+-sG`2wKGqonFD$ zTx+t}SCPV+uKG)(%$S&}F>pzDXdAyNvrzO7JwfE~EkQv_QJ*2oTQ(GZK1hfq>CV4i zSfFNU@KIs2du0on(O?8T^J08{|9!V4E5+F}&TMx1FBNiBOtTK8Ciz}zkDUsOf`)X% zb9>KtuPj2~txH|mPJvO8geB+I1=4HfJy#BeoUKkt+1YDJg=F_pC{4|?`^pxky|qbX z$x?EsUseT{-Qv{EacY#O}topoiO+`b8{OCdH)EUN$j${ zX)NM-Sl-8!rsEgXic6>d5wL{G2nc-3CNMQhF?Xpmmk0h(zkLz1IRlSJ!tH?M-7W;w z)mPkerD>a>(skMI^UN%lylmBxXuVjeem7Q zZ{rr^jiol;)Ymmb#e-B*JE<~^^BxAIWtMwHcdgo3Ecu2cX5i}MxZ&hKUAy7&s)a~J z$6~@>;>A51PIWq!0@nv&ri1V+ZS6Ndns%42Fyib^ZMPW#lHkrMsFJ$=Y3buf=mUOY z1HmY%Z_yzlN%I1UswfJx?VhlE4N^~%Q)*`P>y6FrohfwpqeSGE!O`1s7cN#q@r$kc zxin^=EKF#LR)r&;Zg|F8Sl6$(xa{uCN3&bvA6kF`y2i`AVFy=yckf)MPBHs=5&p-g zWgex1OZpEtxJ0^-9E3%6gN=fk&t+o_o;MA$7S`ePz%$sRN_-IbCh*w+HExJmq2-1e z5DzaANfVmdJ^r~E0j*m`Puc;=|79H^?A_z;Pit| zX7OC;V~F)awdtnvc;DdQgsE22PA|=)e1my1;~o>)4E7$}LC>9b-k@-DhP#7tuc;6M zudl4mZGd`bMtXT_iY7N9#>n`)*4uY$nAfB~7c~bjVai)Cj_>&}lnO(sZpixOOd&Kl z))2~owIW`WCm9h4>`DB>z4$KG6-WTLzJ20HpVHv{ocp0KHh z(-?RC`Z2rAkg1(fk^_PnCJPpot=8Km72kQPTzj=(<(XuJYPQp##0QzLVcpJ0LO$#VtKY3j ztT!@ShtDN^s|2TJFkD?x3e1l?xDx-YnO3@XAsP;RX*sNLMYcnqEoBQ|ToS*!LDcyx zZzjqAER#(0KJ%?Ympu~y7zw(&9lXt~7vl&(JOHi|S3lo+U`jXRec$fcU2ojT#YraY z7fl4eYoK_fuP^ILy{(=u#Z^7Wv>qBVBjmxoyDsFkys(8`PiRs9qOk&*Exv4a=Bf>6QnjkaO zChYE(aK7G*$n#L#{<>P?T1wynN?a)*u@UD>$Xv(*{wXH~of-9U$y9x3DrL$VMB3NU85bLaR9^8! zD=^;~+l_do(!)modN|gpON9Y6F$%$>9LOdrlmixOdm>l37lUIonYIg%Ppo&fD~Fv~ zEn49jwAUoje56cQcxQ*4Rwb`rW59y@nKb>g2N^_-7Nix_l?mMbLG2uMe`zS_s+ExDVxVzSSfc7U#c_x`Q5@J`A@--k!C91S?7$) z$M2@W{h*ABgI0Kj>H(E5I&d}!m%9-`a)*WI=q_A9BoIQaeeL-`=ExaPI-~0R=+FZM za0vzxB6hY!+f*U#OJarp700q{-M+o>=$spUUp^wimw?+z;QE8aeT+NLd>+Yiyafb* zJN409hcXfwOOLs)IO1Q}9zIO`qJacYoypKT|8H6q%E=BhVYMm+Gjbayv5m`twNRP>WxX$>vIt9sdhMS z{~;%RKbWX-@yy4P{iC0KhdhSH-&z(TI#LvVq@?>?W0ciF2mBCFT4s}252P(-;UZ65 zebYeCJAPauIkBD|)vLSRBMM&WQNVlid9IrTxPr2DoxG(hPr$fy)Ys?4oh*yF4EnCT zoai~~`EEGU!o!kkQOd&avnzisl2e?mTu(kHCxEynkWuv2Gp!^%5)$2@7V~du$;uYj zs+R0U$KJnJ7|BT zi>8vxQjr&WtGD=8?>o%LCI{0Ne``!79J)&nYurDnM(2yU3)mi!+U~NYD8#NtzsAO+ zz{%Cb*!D{QJ_s$Wk(Ye>bBn6;`h!ZZE(bA?^3O@VB0U!V%3@SVGz)P=JWmBje?nx3 zEvcWBI$110Z9mdVg~>EZ`EKEnXGxP6&^P$tqW}uFzok1t1KFSKrJUNdklYnpq7j)p zZ!CnP@Hm)`=pkBtOG{;YNb`Yt$uBq(Otj-Kpf04+rO}nE(=sDLSE%E50snVUt;Fkw`c7KZ z{)%4T(q9^z?(nJDP>Q130>)s@JGl6%`5FV)W20JlEa7PL8Sbc#;fI_HZ=Dp@?Arz7Q-L-MsPyU|N=vm}o5%HJdTnJgV$nBLl^2m4nFM2;(T z0j)E&ht{ERy;*DJf{5#%Kk`-F5M5&YL$toLpIgRzMTz^-;_OicxpdEs33jHlr2JTX zo+#7($peqS);)I##`~9*OxO(B7IN5{z6n`hba38fk0?w`sK(QWdJ5vk(`XmprWt;| z^2ny5-0T!=6s4ei%PM8^?L)QCZCNw-J7s!>oIJ5nDGoyr%;GoKiMiv1u1YzAwr8;G zPHkdY4ZMES44;788~DW8IyP5S`8YViM^yJPtFBEqAzhj_4D`gIHFKct2iA5XTl(j%7lmM zg{&G}dIB>ej?~*mX)Uy>u}0f5JM+;O^a~|yPs`>GqGS>gDg6g|5+0}o;nWk25cQ#C z2ZTn$xXi!uA^GjkaMIK=w zAN_ts`c*msm_Z*r!Pcs?u9kDhx}nEuyLoM@HIV(!cO1{R7E_T2M=MzsegthgAf|D! zR<;>#DwB_jeXQ)C&L4TH>uo<0f?oaB0J)D3a<>|)A9Vc0Ct$z<&3Zl8X-&E zMXZlceO8DWy05CHkp>qW8HE1`Vwb!(pd4Hn9X0-o^kIQ8$kx~di&R48#?Gf{5)ITv zAI-T2b8B%bHiUI*j?|0iZ^6mXA0ApMuezPI+vY2?JVHNGtO>)AC`o3&rxIAddVzAk zuyc+%>!pc0XKCmc&T5@p<%!8VNfP#iLwmY8CQ%DQg9*An+_WR3fp|dZJU|%@;3IgQ zyF^Mq3je;sQk~!L9kS0iqil2yg+uB-@~1On>4FMdo8pYUqi+ycxx-dho6|o37SJ}NX+9@UW)Nov znLGpqJyIRY)H78JFct?bn1*|xUVl9D{bpo|;a?@i{qs%nh@^8iuXVB`qR-q zoo8{D`@4b-$qGqHxrlww@wp7T#t-V7o!unRacBZLF`W5>`LG zE8ETCj;BoRGN-KOOmmi*34@nqF2dZFN<2Q-jC1KS)hrdUSue5Vv^U5H#FfO+-pF)# zpZ}J{lWOR*%VRLTZQNLRCNj4~@(L|r{@vZ2M`6-wk>zkB&hJ-tHp@vyu*6*o!3#$< z6Ztl!pHo@n~uC8NsXwb;Nr}9vnZ~ zlPyb6F#T&J{-RP{kVvV|+O2YzJ^wZlV7J*$tVki{qHtK0yFKl=vWHA9cdOHP)pjng z+TDXOm|6aAz-`T<{*mQ|vu;OQcjlAGu%Mh59+``EE?%05^jMS-{CQiTm=Nwf9{(b=bYXPaSnB$Pb$kO zZ+)I=A1g!J(Z*bNh8nyZ&@_Xzalj}t#f*-uxoMz4wz+_9MNq^fEX^L|>r^Y;nZ&A^ z$GiLK;X$&>LV1hai$WjOH?EoMXSOJS;gW<8$DIocD(lEERo7(8n$i^a~$k8_X)m* z@T=!<#Rz0XR-D!>jcI`*ezfT&54{m3FH-Z(5<($+5pn%}{KuH;u5m*=f@NT}rhdSp zIdmWs4Ub%@@V7w#*2cS{=_! zBt!&hkdhW91VN-rTDqh=B&0z^xFyD$Mc>0jeE!V9Ye=r%ie44 zH)cG~Gv^!f^qE8`Uh~giuYLT?g+bMpC0m+3w&3DC5y}>ZH>LF7ktLq zb{)Ip`R2kk%q>jF0}njvf`PSZF|;9F=#+V~d$>N0m|76*eeLhR0#ttR(bBur7gJn> zy{n6g=(@$tlow@NR#yB1rlbNh9jDU^o1{j#&!2}djqr3vL@PsdR6&(LPxK45volg} zDvs#Q?qs!fB6J3&0Ug%c0bT~AV%VED6Z(lT!laAeE5 z9eM9o!44t0`s})g)?YOrFhYtViPccU&>D9CK6375Uf<&1AfW7h5DKSiYKwaxpC2&9r?5(1DzZez;X|u^NX8x~R9LOm)$~vM_h@hA@3R8FaMWL5idP$Zu4HB%jlqe4y zZ$|)8I*CqvIy>cO2Y2sZvlt~HPrA5veJyxohWFi!!(wy8Xz#QP6UeixK@~i#`bqF-n&$GXs&JVF|YXhj9x}3n)@!l86uO_ymGHK<~W`6&&W_QAeL13 z!GqZio`tq2Pv2G}Bh)2-|Dkuef`$TBLt#u>s;STa#}71Q#uz9QfShmj8Xc2oIA~Y-V^q`A(LsD^zIzND7OVeM7*3^0 ze(Q>D^+VEJ4hvBVZ^=l#qG%9urK$HuvpKCvb|sZ!71q{M$R}T7A+$r_tQvcIiU)1{ zNX8b>W#-7^(;sdLbgL6@d4LY8Z2SxsaN1FW)iW)B5h`J+e5HAJR~6p^Z%pDEzYFEU zZD=386Cs=j+&&@gSJQHm((!H=p=&d))8lEye~{v=H9apH#kg{hSi#{^<(B+^6vG{1 z5d?kxMUOF&W+flt;;H_#=h8X`sy82jtQAuiC&J=!>NBQ;Q9tZ6f6E3V)AwhCk3LaM zPMTiRl?aeUh#n6TiYt4sX$G}$0c`aoyUk7RW_}tdDepo2gEVWfk4H^A^P~n_UK@hB z-O){6L976gW0A~>$`@cB)f#5S5uu%Wp);fo({f>ogr>+qsEPXaP5})L;lA*OeHR^& zjGxK*?(?8o)~&t$Zd&tPKuHwth62fi@CGE&AOwhX-Z*!uZ#~j-;CN<~JCj1{dhT_V zP5%YWR!b7gK>~}<(FQQxE7*$4x6_^ zZV20%G3t-`7LlPt*!D5)`DMqq!jJRSZq*R}vjBxOs*yy=iwY~9p0^bE{_WrC!=fFK zcx{tt{8w#x0Ts?sSO6)*#?1LGkf;$;>qt=B1BsSTWn*H+aAK6b^iiLN62U3vxwS0= zKbbBUa!PGHq64gD9|ZZRmm7n28H#!}H6tRYp}iQoCgu3DBRDFY(+eQ8z6y#XQ1E;v z&n^4)3lpDRZ#yA>=gZV&4(TgP5@~YCqhUDH{gxnd6E@kFTPvnV$n(H&GWr{r|9<3P zFP+`0m~CC;(L3_}!~NR|(KiE{SNLWHyakn;Dx*zaAYH2|L#AtIQ@Sr6-I|h`Ow!zw zsH(VT64Zu$8QAReY{hn5E<`>mL8JC+A*g~OvkKajcdVP3h`y|AgX2RJYcL{K%GIP} zsii6SelY+UUQ|dm;$Zb5!t!>4GB^)}5N=lmgmC)hjDH5z8B@{G%Rr2V)hckekWQY# znNvX(pz3+4v&kIui9ijkKXGd$3yw^RX3DOfUzpO0+&{6^0qM?L;U6=_O${Up^<^Mo zy8-&>{`!Sdu`q|tU3>tQ==~F2KWZE00}_NWY({JM?Q3fCN0Tnv5btz8wes5x{!_t% zUVLnsxa1XA0lJl~6VuCWqu}4L0q=877yZcH@WAo0aCup&p;9WKmQbgWs-PF?`|Zd< z=tA?n7ZhPk=9|64-s(wkf{$yj%>19bDo`}yP>M9y9jTrG-^pk-gMkO z;{~K9;wZ_UEF%TXx$wr%;?uTY&i`luT0R#{IvvmU7M0sQt_hWw&a zAGvAe_^1NJ_JT|clVXMvqJrGA=XtiR^k{H8sS2kOppxwBQOr8Ae~+qvP6nn-UzZ|E zdVq&8ogU4)tCN8J?$?R}2#8BKvW$#^m1w1|4=_+YR@JfU z4Wl)Zw@nLr7dL6iqM{!UtnJN_NCmQS8FgyBl#XJ?Gp@Mbn8O?K_(o$|vk1MY2u5+)1hU zhTXEVBMK$^eG5GJ;|K%qt~L36n+JKG%1Ucj?S9ZMXa6cG{&|EKbE*j)S&4)7gW9gu zBSeeq!?h`w;~@LK!?TYCx~!WCmQk3PTY>!x%UHS|1#z0XC9!PbcrI`D`&dACoF#l; zRQ~nDCK~~U&T1QtDA}K{DvN$ufN@SWJsR^Geb=BR3UN-*NQr*a<$Ivy0eMD77k7x* zL@=(@{bb{pR|+)840aQYvx|=nH_d=+NS*OKV%pLoOwe#;-D~OgGWi4=Y&g(6jES5< zaO>gW<^?7I)G1IaU~oX^EZF{#;^XrlHrnURXfyH{-1@ghT-q}x4uhD8D!@G0BK4W?}1M97bftU#ryX)3pazI>qa#N#0D(WRO&JEUT znZOT6?NG!4QO-48*jFR>4&wwWVV0IcEbo3Y_JClH>XmZ%o@{;()UELH^P9v92>xx2 z`v<-b6RwOk?ML74b;|t}lOhp0uN1uNIOQ3rf&Rx}D_+;q`r6)pTpS;D+5M*uO3|uG z+|3WT-Qk9w?nu20oH|@GyYCxpp?6NMBA79#n&~S&GQD4cV=;OKp+%{KvsEdfU;|Wd zz5vy$?kz6o{)HjvMgocl881Rj)U9cg3Oa-vxm~@zcut_ z9Sg14o-CO&cRZ1&`oIw*z4ZdMcoYpOMWLhU%>`u;{xu*_-U$(gyvsBs3r?;b%@c&- zI9l+P36Z1MuOhJNIBSW1%vjO5(?5fuyJ~!dprV+yCMl139Sk^uzeu~}t=i@@J3HlM zJTAtWc4|UT?ltua@n|q8GO)2-<-$sD>-AG%M1J{l&V24n*fGYoX@d=suu))%H#U`W zf$CP*zQF~kZAYL_y1LNO+P}kUfhr*;62tvtEz}{cNS@f^#Zz+sFHVyiY}gy;gl(Z` z@A?Rv`aVwt!Ek{H6@*eg5Y>8mq3$YnW`brndCZ0eG|#;=cH)5d^}f*3d)Zz{H3Zag zspc3mIy$$TS#M8ok<)p6pGkLa$}#II8X*%giaH-UKerweHGU2LsZluz^j%@}&mQ_x z<+MSJ{uF?_9G$+qIWB#eti|^)aP~v*m^TqjBYBzusL+jezu&T z;{w}NyfT7-vc*KVn&!3qz76G*&lfp<-8IoIEA zDJ|1Ch`q?AW|aj_YuD8IO|aUrz^2>sObQi6N`aj(zX_E*^%) zYnyj`@TbU5_IJDxMHQ(jv4=VK&H>S_2FN{f#x>n<9qWDB)uV7ja^10LDe&{}P};NM>v6|mf>4&r|#1yVOO44prxzDJ- zP4-%R9qDbR@KB+9sEZTDa@!AxZ=|n{jW-r(m_%~97NiRJo=5pi@d>p+&^o(F=E-A8 z?ghfJbn~XB3MvK$42V=!V*}vu`UfD|AuTI~!|bh=7zFydA97o>&OZe|Wlpij3`}H_$8nIN;)JOcd3V3w0Z0n1gG&2Yf@E%eL@mLI};ir>2C<-IjBP%U-8;EZZzSa%NHKI`}oqS8Q72a zDHu0hJ?<^lN9$Puio*jLF83Ebo_#`iPns^rJ$m`L!2D98O;L_yJ@j ze)~@oJu488(bz}^SedD9SGpgO_JEM(HGDH5!+nj}FS%6R5G%7hH(4AgtgeK*+tP72 zyy#g-DLjZ7vsQRsA4jkBn_@#oqSL;8?|q@H&NLA>RJf|lyWCIvz@&Cp2=DL3G|DChgeX-dFRd))X=Jq{Z&Rcv~-V;@5Wdl zheGajR!Q_z5rypG{431Ff;Y(*T2UA-vk>-2cBmCqIxUkFN~kZ?f#z<6LJmZ=?nw+3 z&^>_==jAywC}wv-R&Z$*W&`d({JG}JtKCKsrOQe^X z7NiI{1rV#CKOzIC2Ef4V_)ub%+d3)))PN+aRg#4vDwY`fQIQZu6{kn8=DQ@w+JNlu zNL_kdHZ3j2>UzH>w>ht-o_YP@g~Y|ho@m0O3PfGXYyx+8p{)r92=Wo?4#=?9BJ9th z?#d`g2T`Qw5Ecj6;_mDPG?v>E-$*R&Tm99ax@UWx;vm2NNh;fn+n8puwrR*%;g%Sf z1HvN&DmDMxZnXSdPgqXISmJX}jG$>ero7wvO6anH zBX;Mw3M>R{TvA{mdwQmgrmayyV$cNcNx?+Fv5xlS0gNvS9Bp%sDBY3MD(=Gv@&$@0`QA;;vGm0+)W8{>-A~KW>+D0TwHJzoG^TYonN$f6t+d^6)s#Pb5n#ht-q1 zU^7I$7!*oCeo!@CbKnY_4%;WwLF1>X!ZXS0x4Fs{bD$N3hCyv*u^#C<>C-2Ih;r*n zEwsn^N+ex#fCH8;Z#;}mkrIgl&XU74K)|XPd1lp{j*GdcQQ-v2(F0ro zX*e5z)L1Nu#3T@rAC%uV?I-Z<>;Pc2>XzG06D;>^Li`^%oaawFtrSJ{?}3ejI*oTv z!ZCgMufjHTvyOTa9(d-;i8Kp>-8AW%fXI?osHgG{34yRDdv-MuG$*(d&!i6J7xkZ} z%OWE|ohp=m0N*-@wei3)hppd3x*2wn)55iq(t(r*wM%gJ!UMVR2>Bf$9te;K8HYcz z;)4pye1dCsRJQ3j1^H{M2fZr~^ciRYHfd!QvDYs%*701d01yy)HI-e6r1UW;h$ZeF zwpj87Ao-Q<*~=dd1)4!UV#Vaj2U_D1gNJL$LNO{uJfV$4dl0El6P!C=KlVJD;5`*J;XOqXd0U@f*Fv16ADql&#k0*Kcpo< zLOmUE_H(QftU9_~oab%X^4ns2PEd`0NJ{Z7k`iwt@XNUeKZ z%zUN0BiaosX9oimp9$8q9J8NSyPkjR&pqM@PTt4#ddjPkIPsw)5akX}EwSN;;d`eY z5~U#{a@p6(_(GbqCX$}aTsTa)opYi4QelbD7YZbk(!QAf-qLc5OxI6ua1*OPb2|?$ zxi>1rGL7=m>o_jb?vod9PZxL=JH2&x{)g2Ig@_w7Gh8`z9@)~%ZC zcnr>Fa0hgrdAGIKx}v%`c%TJ{V1_kh%wKE^QlV3RO&Jl+&3^|?7aCKdDP&Dcb;tCc`D-a` zlW-YvfxvrK>WA~kn}(EBC49~Yu?9zcCj_#cWqN!?dVa>P`wz6+qLvW-Uevg`jPR!> z5l?N(PHg+&yNs~vnBoJ5Aj)fKjxOl;Sc}N0CiYEAXzoYmpo;n$zf>X=&Sv!T^P@OB zgAM_s!)wN|+@(Q8_QJS62A7G_61(~zBQ->w#uSaphjtEbczZl1_3>>}<-Feyr=|!f zF}hqACx}8pqN1u&&LQN&7?m!2LgMTu^9 zfdED5@)_LvHtC>RM9Ggk4{oYvJ?QlolSh{61%c+fG>y}X7fyRd;&Qpq!xQaL^!1hR zMzrIRjAQhZp;fNT=))Tx$iGgnonZ`F+nyQsQ)4KY(?d1x0}~*KZL_#lgq|&XrF_$`N2e7S(nSj}tF{_?O