Native code export for LAMMPS and Python/ASE #62
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Export CI | |
| on: | |
| push: | |
| paths: | |
| - 'export/**' | |
| - '.github/workflows/export-ci.yml' | |
| pull_request: | |
| paths: | |
| - 'export/**' | |
| - '.github/workflows/export-ci.yml' | |
| env: | |
| JULIA_NUM_THREADS: 2 | |
| jobs: | |
| build-lammps: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| lammps-version: ${{ steps.lammps-version.outputs.version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| cmake \ | |
| libfftw3-dev \ | |
| libopenmpi-dev \ | |
| mpi-default-bin \ | |
| mpi-default-dev | |
| - name: Get LAMMPS version hash | |
| id: lammps-version | |
| run: | | |
| LAMMPS_VERSION=$(git ls-remote https://github.com/lammps/lammps.git refs/heads/stable | awk '{print $1}' | cut -c1-8) | |
| echo "version=$LAMMPS_VERSION" >> $GITHUB_OUTPUT | |
| echo "LAMMPS_VERSION=$LAMMPS_VERSION" >> $GITHUB_ENV | |
| - name: Cache LAMMPS | |
| id: lammps-cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: lammps | |
| key: ${{ runner.os }}-lammps-${{ steps.lammps-version.outputs.version }}-plugin-v1 | |
| - name: Clone LAMMPS | |
| if: steps.lammps-cache.outputs.cache-hit != 'true' | |
| run: | | |
| git clone -b stable --depth 1 https://github.com/lammps/lammps.git | |
| - name: Build LAMMPS | |
| if: steps.lammps-cache.outputs.cache-hit != 'true' | |
| run: | | |
| cd lammps | |
| mkdir -p build && cd build | |
| cmake ../cmake \ | |
| -D PKG_PLUGIN=on \ | |
| -D BUILD_SHARED_LIBS=on \ | |
| -D BUILD_MPI=on \ | |
| -D BUILD_OMP=on \ | |
| -D CMAKE_BUILD_TYPE=Release | |
| cmake --build . -j $(nproc) | |
| - name: Upload LAMMPS artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: lammps-build | |
| path: | | |
| lammps/build/lmp | |
| lammps/build/liblammps.so* | |
| lammps/src/*.h | |
| lammps/src/STUBS/ | |
| lammps/src/fmt/ | |
| lammps/src/nlohmann/ | |
| retention-days: 1 | |
| test-export: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Julia | |
| uses: julia-actions/setup-julia@v2 | |
| with: | |
| version: '1.12' | |
| - name: Cache Julia packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.julia/packages | |
| ~/.julia/artifacts | |
| ~/.julia/compiled | |
| key: ${{ runner.os }}-julia-export-${{ hashFiles('export/Project.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-julia-export- | |
| - name: Install Julia dependencies | |
| run: | | |
| julia --project=export -e ' | |
| using Pkg | |
| Pkg.instantiate() | |
| Pkg.precompile() | |
| ' | |
| - name: Run Julia export tests | |
| run: | | |
| julia --project=export export/test/runtests.jl export | |
| - name: Upload compiled library | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ace-library | |
| path: export/test/build/libace_test.so | |
| retention-days: 1 | |
| test-python: | |
| runs-on: ubuntu-latest | |
| needs: test-export | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download compiled library | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ace-library | |
| path: export/test/build | |
| - name: Setup Julia | |
| uses: julia-actions/setup-julia@v2 | |
| with: | |
| version: '1.12' | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install Python dependencies | |
| run: | | |
| cd export | |
| uv sync | |
| # Install ase-ace package into the venv for Python calculator tests | |
| uv pip install -e ase-ace | |
| - name: Cache Julia packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.julia/packages | |
| ~/.julia/artifacts | |
| ~/.julia/compiled | |
| key: ${{ runner.os }}-julia-export-${{ hashFiles('export/Project.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-julia-export- | |
| - name: Install Julia dependencies | |
| run: | | |
| julia --project=export -e ' | |
| using Pkg | |
| Pkg.instantiate() | |
| ' | |
| - name: Run Python tests | |
| run: | | |
| export PATH="${{ github.workspace }}/export/.venv/bin:$PATH" | |
| export VIRTUAL_ENV="${{ github.workspace }}/export/.venv" | |
| julia --project=export export/test/runtests.jl python | |
| test-lammps-serial: | |
| runs-on: ubuntu-latest | |
| needs: [build-lammps, test-export] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download compiled library | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ace-library | |
| path: export/test/build | |
| - name: Install MPI headers | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libopenmpi-dev | |
| - name: Setup Julia | |
| uses: julia-actions/setup-julia@v2 | |
| with: | |
| version: '1.12' | |
| - name: Download LAMMPS | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: lammps-build | |
| path: lammps | |
| - name: Setup LAMMPS | |
| run: | | |
| chmod +x lammps/build/lmp | |
| echo "$GITHUB_WORKSPACE/lammps/build" >> $GITHUB_PATH | |
| echo "LD_LIBRARY_PATH=$GITHUB_WORKSPACE/lammps/build:$LD_LIBRARY_PATH" >> $GITHUB_ENV | |
| - name: Cache Julia packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.julia/packages | |
| ~/.julia/artifacts | |
| ~/.julia/compiled | |
| key: ${{ runner.os }}-julia-export-${{ hashFiles('export/Project.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-julia-export- | |
| - name: Install Julia dependencies | |
| run: | | |
| julia --project=export -e ' | |
| using Pkg | |
| Pkg.instantiate() | |
| ' | |
| - name: Build ACE LAMMPS plugin | |
| run: | | |
| cd export/lammps/plugin | |
| mkdir -p build && cd build | |
| cmake ../cmake -DLAMMPS_HEADER_DIR=$GITHUB_WORKSPACE/lammps/src | |
| make -j $(nproc) | |
| - name: Run LAMMPS tests (serial) | |
| env: | |
| LAMMPS_SRC: ${{ github.workspace }}/lammps/src | |
| run: | | |
| julia --project=export export/test/runtests.jl lammps | |
| test-mpi: | |
| runs-on: ubuntu-latest | |
| needs: [build-lammps, test-lammps-serial] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download compiled library | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ace-library | |
| path: export/test/build | |
| - name: Setup Julia | |
| uses: julia-actions/setup-julia@v2 | |
| with: | |
| version: '1.12' | |
| - name: Install MPI | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libopenmpi-dev mpi-default-bin | |
| - name: Download LAMMPS | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: lammps-build | |
| path: lammps | |
| - name: Setup LAMMPS | |
| run: | | |
| chmod +x lammps/build/lmp | |
| echo "$GITHUB_WORKSPACE/lammps/build" >> $GITHUB_PATH | |
| echo "LD_LIBRARY_PATH=$GITHUB_WORKSPACE/lammps/build:$LD_LIBRARY_PATH" >> $GITHUB_ENV | |
| - name: Cache Julia packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.julia/packages | |
| ~/.julia/artifacts | |
| ~/.julia/compiled | |
| key: ${{ runner.os }}-julia-export-${{ hashFiles('export/Project.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-julia-export- | |
| - name: Install Julia dependencies | |
| run: | | |
| julia --project=export -e ' | |
| using Pkg | |
| Pkg.instantiate() | |
| ' | |
| - name: Build ACE LAMMPS plugin | |
| run: | | |
| cd export/lammps/plugin | |
| mkdir -p build && cd build | |
| cmake ../cmake -DLAMMPS_HEADER_DIR=$GITHUB_WORKSPACE/lammps/src | |
| make -j $(nproc) | |
| - name: Run MPI tests | |
| env: | |
| LAMMPS_SRC: ${{ github.workspace }}/lammps/src | |
| OMPI_ALLOW_RUN_AS_ROOT: 1 | |
| OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 | |
| run: | | |
| julia --project=export export/test/runtests.jl mpi | |
| test-ase-ace-imports: | |
| name: ase-ace (imports and utils) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Julia | |
| uses: julia-actions/setup-julia@v2 | |
| with: | |
| version: '1.12' | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install ase-ace package | |
| run: | | |
| cd export/ase-ace | |
| pip install -e ".[dev]" | |
| - name: Run import and utility tests | |
| run: | | |
| cd export/ase-ace | |
| pytest -v tests/test_calculator.py::TestImports tests/test_calculator.py::TestUtilities tests/test_calculator.py::TestCalculatorInit -m "not requires_julia" | |
| test-ase-ace-library: | |
| name: ase-ace (library calculator) | |
| runs-on: ubuntu-latest | |
| needs: test-export | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download compiled library | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ace-library | |
| path: export/test/build | |
| - name: Setup Julia | |
| uses: julia-actions/setup-julia@v2 | |
| with: | |
| version: '1.12' | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Cache Julia packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.julia/packages | |
| ~/.julia/artifacts | |
| ~/.julia/compiled | |
| key: ${{ runner.os }}-julia-export-${{ hashFiles('export/Project.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-julia-export- | |
| - name: Install Julia dependencies | |
| run: | | |
| julia --project=export -e ' | |
| using Pkg | |
| Pkg.instantiate() | |
| ' | |
| - name: Install ase-ace package with library support | |
| run: | | |
| cd export/ase-ace | |
| pip install -e ".[dev,lib]" | |
| - name: Setup library path | |
| run: | | |
| chmod +x ${{ github.workspace }}/export/test/build/libace_test.so || true | |
| echo "LD_LIBRARY_PATH=$(dirname $(julia -e 'print(Sys.BINDIR)'))/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV | |
| - name: Run ase-ace library calculator tests | |
| env: | |
| ACE_TEST_LIBRARY: ${{ github.workspace }}/export/test/build/libace_test.so | |
| run: | | |
| cd export/ase-ace | |
| pytest -v tests/test_library_calculator.py | |
| test-ase-ace-julia: | |
| name: ase-ace (julia calculator) | |
| runs-on: ubuntu-latest | |
| needs: test-export | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Download compiled library | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ace-library | |
| path: export/test/build | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Cache Julia packages (juliapkg) | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.julia/packages | |
| ~/.julia/artifacts | |
| ~/.julia/compiled | |
| ~/.julia/environments/pyjuliapkg | |
| key: ${{ runner.os }}-juliapkg-${{ hashFiles('export/ase-ace/src/ase_ace/juliapkg.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-juliapkg- | |
| - name: Install ase-ace package with JuliaCall support | |
| run: | | |
| cd export/ase-ace | |
| pip install -e ".[dev,julia,lib]" | |
| - name: Create test model | |
| env: | |
| JULIA_NUM_THREADS: 2 | |
| PYTHON_JULIACALL_HANDLE_SIGNALS: yes | |
| working-directory: export/ase-ace | |
| run: | | |
| # Create fixtures directory and a FITTED test model using ase_ace module | |
| # This ensures juliapkg finds the correct juliapkg.json | |
| python3 -c " | |
| import os | |
| os.makedirs('tests/fixtures', exist_ok=True) | |
| # Import ase_ace to trigger juliapkg resolution with our dependencies | |
| from ase_ace.julia_calculator import ACEJuliaCalculator | |
| # Access the Julia runtime to create and fit a test model | |
| jl = ACEJuliaCalculator._init_julia(2) | |
| jl.seval('using ACEfit') | |
| jl.seval(''' | |
| # Load training data and fit model (same as export tests) | |
| dataset = ACEpotentials.example_dataset(\\\"Si_tiny\\\") | |
| data = dataset.train | |
| model = ace1_model(elements=[:Si], order=2, totaldegree=6, rcut=5.5) | |
| data_keys = ( | |
| energy_key = \\\"dft_energy\\\", | |
| force_key = \\\"dft_force\\\", | |
| virial_key = \\\"dft_virial\\\", | |
| ) | |
| weights = Dict(\\\"default\\\" => Dict(\\\"E\\\" => 30.0, \\\"F\\\" => 1.0, \\\"V\\\" => 1.0)) | |
| ACEpotentials.acefit!(data, model; data_keys..., weights=weights, solver=ACEfit.BLR()) | |
| ACEpotentials.save_model(model, \\\"tests/fixtures/test_model.json\\\") | |
| ''') | |
| print('Test model created and fitted successfully') | |
| " | |
| - name: Run ase-ace julia calculator tests | |
| env: | |
| JULIA_NUM_THREADS: 2 | |
| PYTHON_JULIACALL_HANDLE_SIGNALS: yes | |
| ACE_TEST_MODEL: ${{ github.workspace }}/export/ase-ace/tests/fixtures/test_model.json | |
| ACE_TEST_LIBRARY: ${{ github.workspace }}/export/test/build/libace_test.so | |
| working-directory: export/ase-ace | |
| run: | | |
| pytest -v tests/test_julia_calculator.py -x |