From bcfec7223ebbe70c19611cf321029518b17f5063 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 12 Mar 2024 12:22:31 +1100 Subject: [PATCH] Added CI structure --- .github/workflows/TagBot.yml | 15 +++++ .github/workflows/ci.yml | 55 +++++++++++++++ .github/workflows/ci_mpi.yml | 92 +++++++++++++++++++++++++ Project.toml | 1 + src/LevelSetTopOpt.jl | 2 + src/Utilities.jl | 4 +- test/mpi/runtests.jl | 20 ++++++ test/runtests.jl | 2 + test/seq/ThermalComplianceALMTests.jl | 96 +++++++++++++++++++++++++++ test/seq/runtests.jl | 7 ++ 10 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/TagBot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/ci_mpi.yml create mode 100644 test/mpi/runtests.jl create mode 100644 test/runtests.jl create mode 100644 test/seq/ThermalComplianceALMTests.jl create mode 100644 test/seq/runtests.jl diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml new file mode 100644 index 00000000..f49313b6 --- /dev/null +++ b/.github/workflows/TagBot.yml @@ -0,0 +1,15 @@ +name: TagBot +on: + issue_comment: + types: + - created + workflow_dispatch: +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ssh: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..9818d513 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +name: CI +on: [push, pull_request] +jobs: + test: + name: Tests ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1.9' + os: + - ubuntu-latest + arch: + - x64 + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: actions/cache@v1 + env: + cache-name: cache-artifacts + with: + path: ~/.julia/artifacts + key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} + restore-keys: | + ${{ runner.os }}-test-${{ env.cache-name }}- + ${{ runner.os }}-test- + ${{ runner.os }}- + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v1 + with: + file: ./lcov.info + + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@v1 + with: + version: '1.9' + - run: | + julia --project=docs -e ' + using Pkg + Pkg.develop(PackageSpec(path=pwd())) + Pkg.instantiate()' + - run: julia --project=docs docs/make.jl + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/ci_mpi.yml b/.github/workflows/ci_mpi.yml new file mode 100644 index 00000000..b0f2364a --- /dev/null +++ b/.github/workflows/ci_mpi.yml @@ -0,0 +1,92 @@ +name: CI_MPI +on: [push, pull_request] +jobs: + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + env: + P4EST_ROOT_DIR: "/opt/p4est/2.2/" + JULIA_PETSC_LIBRARY: "/opt/petsc/3.18/lib/libpetsc" + strategy: + fail-fast: false + matrix: + version: + - '1.9' + os: + - ubuntu-latest + arch: + - x64 + steps: + - uses: actions/checkout@v2 + - name: Cache p4est + id: cache-p4est + uses: actions/cache@v2 + with: + path: ${{env.P4EST_ROOT_DIR}} + key: ${{ runner.os }}-build-${{ env.P4EST_ROOT_DIR }}- + restore-keys: | + ${{ runner.os }}-build-${{ env.P4EST_ROOT_DIR }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - name: Install p4est/petsc dependencies + run: | + sudo apt-get update + sudo apt-get install -y wget gfortran g++ openmpi-bin libopenmpi-dev + - name: Install p4est + run: | + # Install p4est 2.2 from sources + CURR_DIR=$(pwd) + PACKAGE=p4est + VERSION=2.2 + INSTALL_ROOT=/opt + P4EST_INSTALL=$INSTALL_ROOT/$PACKAGE/$VERSION + TAR_FILE=$PACKAGE-$VERSION.tar.gz + URL="https://github.com/p4est/p4est.github.io/raw/master/release" + ROOT_DIR=/tmp + SOURCES_DIR=$ROOT_DIR/$PACKAGE-$VERSION + BUILD_DIR=$SOURCES_DIR/build + wget -q $URL/$TAR_FILE -O $ROOT_DIR/$TAR_FILE + mkdir -p $SOURCES_DIR + tar xzf $ROOT_DIR/$TAR_FILE -C $SOURCES_DIR --strip-components=1 + cd $SOURCES_DIR + ./configure --prefix=$P4EST_INSTALL --without-blas --without-lapack --enable-mpi -disable-dependency-tracking + make --quiet + make --quiet install + rm -rf $ROOT_DIR/$TAR_FILE $SOURCES_DIR + cd $CURR_DIR + - name: Install petsc + run: | + CURR_DIR=$(pwd) + PACKAGE=petsc + VERSION=3.18 + INSTALL_ROOT=/opt + PETSC_INSTALL=$INSTALL_ROOT/$PACKAGE/$VERSION + TAR_FILE=$PACKAGE-$VERSION.tar.gz + URL="https://ftp.mcs.anl.gov/pub/petsc/release-snapshots/" + ROOT_DIR=/tmp + SOURCES_DIR=$ROOT_DIR/$PACKAGE-$VERSION + BUILD_DIR=$SOURCES_DIR/build + wget -q $URL/$TAR_FILE -O $ROOT_DIR/$TAR_FILE + mkdir -p $SOURCES_DIR + tar xzf $ROOT_DIR/$TAR_FILE -C $SOURCES_DIR --strip-components=1 + cd $SOURCES_DIR + ./configure --prefix=$PETSC_INSTALL --with-cc=mpicc --with-cxx=mpicxx --with-fc=mpif90 \ + --download-mumps --download-scalapack --download-parmetis --download-metis \ + --download-ptscotch --with-debugging --with-x=0 --with-shared=1 \ + --with-mpi=1 --with-64-bit-indices + make + make install + - uses: julia-actions/julia-buildpkg@latest + - run: echo $PWD + - run: julia --project=. -e 'using Pkg; Pkg.instantiate();' + - run: julia --project=. -e 'using Pkg; Pkg.add("MPIPreferences")' + - run: julia --project=. -e 'using MPIPreferences; MPIPreferences.use_system_binary()' + - run: julia --project=. -e 'using Pkg; Pkg.build(); Pkg.precompile()' + - run: julia --project=. --color=yes --check-bounds=yes test/mpi/runtests.jl + - uses: codecov/codecov-action@v1 + with: + file: lcov.info diff --git a/Project.toml b/Project.toml index 481fadae..5bb5edb6 100755 --- a/Project.toml +++ b/Project.toml @@ -24,6 +24,7 @@ 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" [extras] MPIPreferences = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267" diff --git a/src/LevelSetTopOpt.jl b/src/LevelSetTopOpt.jl index b7e18669..286e87d2 100644 --- a/src/LevelSetTopOpt.jl +++ b/src/LevelSetTopOpt.jl @@ -32,6 +32,8 @@ using GridapSolvers.SolverInterfaces: SolverVerboseLevel, SOLVER_VERBOSE_NONE, S using JLD2: save_object, load_object +import Base: + + include("GridapExtensions.jl") include("ChainRules.jl") diff --git a/src/Utilities.jl b/src/Utilities.jl index 3ba00ff3..82ba9f0f 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -68,13 +68,13 @@ as `name`. Note: `f_Γ` must recieve a Vector and return a Boolean depending on whether it indicates Γ """ -function update_labels!(e::Int,model::CartesianDiscreteModel,f_Γ::Function,name::String) +function update_labels!(e::Integer,model::CartesianDiscreteModel,f_Γ::Function,name::String) mask = mark_nodes(f_Γ,model) _update_labels_locally!(e,model,mask,name) nothing end -function update_labels!(e::Int,model::DistributedDiscreteModel,f_Γ::Function,name::String) +function update_labels!(e::Integer,model::DistributedDiscreteModel,f_Γ::Function,name::String) mask = mark_nodes(f_Γ,model) cell_to_entity = map(local_views(model),local_views(mask)) do model,mask _update_labels_locally!(e,model,mask,name) diff --git a/test/mpi/runtests.jl b/test/mpi/runtests.jl new file mode 100644 index 00000000..172e27bc --- /dev/null +++ b/test/mpi/runtests.jl @@ -0,0 +1,20 @@ +module LSTOMPITests + +using Test +using MPI + +testdir = @__DIR__ +istest(f) = endswith(f, ".jl") && !(f=="runtests.jl") +testfiles = sort(filter(istest, readdir(testdir))) + +MPI.mpiexec() do cmd + for file in testfiles + path = joinpath(testdir,file) + _cmd = `$(cmd) -np 4 --allow-run-as-root --oversubscribe $(Base.julia_cmd()) --project=. $path` + @show _cmd + run(_cmd) + @test true + end +end + +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl new file mode 100644 index 00000000..64966857 --- /dev/null +++ b/test/runtests.jl @@ -0,0 +1,2 @@ +using Test +include("seq/runtests.jl") \ No newline at end of file diff --git a/test/seq/ThermalComplianceALMTests.jl b/test/seq/ThermalComplianceALMTests.jl new file mode 100644 index 00000000..1d227f11 --- /dev/null +++ b/test/seq/ThermalComplianceALMTests.jl @@ -0,0 +1,96 @@ +module ThermalComplianceALMTests + +using Gridap, LevelSetTopOpt + +""" + (Serial) Minimum thermal compliance with augmented Lagrangian method in 2D. + + 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| + 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,minimum(el_size)/10) + tol = 1/(5*order^2)/minimum(el_size) + κ = 1 + vf = 0.4 + η_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())) + 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.ρ + + 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]) + + # Do a few iterations + vars, state = iterate(optimiser) + vars, state = iterate(optimiser,state) +end + +main() + +end # module \ No newline at end of file diff --git a/test/seq/runtests.jl b/test/seq/runtests.jl new file mode 100644 index 00000000..92ccacfa --- /dev/null +++ b/test/seq/runtests.jl @@ -0,0 +1,7 @@ +module LSTOSequentialTests + +using Test + +@time @testset "Thermal Compliance - ALM" begin include("ThermalComplianceALMTests.jl") end + +end # module \ No newline at end of file