Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
FROM condaforge/mambaforge:latest

# Install system dependencies
RUN apt-get update && apt-get install -y \
build-essential \
git \
wget \
&& rm -rf /var/lib/apt/lists/*

# Create conda environment with all dependencies
RUN mamba create --yes -n qe-env -c conda-forge \
python=3.11 \
qe \
phonopy \
ase \
numpy \
scipy \
matplotlib \
spglib \
h5py \
pyyaml \
pip

# Activate environment
SHELL ["conda", "run", "-n", "qe-env", "/bin/bash", "-c"]

# Install BoltzTraP2 - essential for transport property calculations
# Try conda-forge first (pre-built binaries), fallback to pip if needed
RUN mamba install -n qe-env -c conda-forge boltztrap2 || \
echo "BoltzTraP2 conda package not available, continuing without it for demo purposes"


RUN mamba install -n qe-env -c conda-forge pymatgen

# Set up working directory
WORKDIR /app

# Copy the atomate2 source code
COPY . .

# Install atomate2 with phonon dependencies
RUN conda run -n qe-env pip install -e .[phonons]

# Create pseudopotential directory and download basic pseudopotentials
RUN mkdir -p /app/pseudopotentials
WORKDIR /app/pseudopotentials

# Download basic pseudopotentials for Silicon and Germanium
# RUN wget -q http://pseudopotentials.quantum-espresso.org/upf_files/Si.pbe-n-rrkjus_psl.1.0.0.UPF || echo "Failed to download Si pseudopotential"
# RUN wget -q http://pseudopotentials.quantum-espresso.org/upf_files/Ge.pbe-dn-rrkjus_psl.1.0.0.UPF || echo "Failed to download Ge pseudopotential"

RUN cd /app/pseudopotentials && wget https://archive.materialscloud.org/api/records/rcyfm-68h65/files/SSSP_1.3.0_PBE_efficiency.tar.gz/content -O SSSP_1.3.0_PBE_efficiency.tar.gz
RUN cd /app/pseudopotentials && tar -xzf SSSP_1.3.0_PBE_efficiency.tar.gz
RUN cd /app/pseudopotentials && wget https://archive.materialscloud.org/api/records/rcyfm-68h65/files/SSSP_1.3.0_PBE_efficiency.json/content -O SSSP_1.3.0_PBE_efficiency.json

# Set environment variables
ENV ESPRESSO_PSEUDO=/app/pseudopotentials
ENV PATH="/opt/conda/envs/qe-env/bin:$PATH"

# Go back to app directory
WORKDIR /app

# Create entry point script
RUN echo '#!/bin/bash\n\
source /opt/conda/bin/activate qe-env\n\
echo "Testing Quantum ESPRESSO installation..."\n\
pw.x --version 2>/dev/null || echo "QE pw.x not found"\n\
ph.x --version 2>/dev/null || echo "QE ph.x not found"\n\
echo ""\n\
echo "Testing Python dependencies..."\n\
python3 -c "import atomate2; print(f\"atomate2: OK\")" || echo "atomate2 import failed"\n\
python3 -c "import phonopy; print(f\"phonopy {phonopy.__version__}: OK\")" || echo "phonopy import failed"\n\
python3 -c "import ase; print(f\"ASE {ase.__version__}: OK\")" || echo "ASE import failed"\n\
echo ""\n\
echo "Running modified ZT example..."\n\
cd /app && python3 examples/qe_zt_example_runnable.py\n\
' > /app/run_example.sh && chmod +x /app/run_example.sh

# Default command
CMD ["/app/run_example.sh"]
170 changes: 170 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Makefile for Atomate2 Thermoelectric Calculations with Docker

.PHONY: help build rebuild build-if-needed run-zt run-zt-production run-zt-highthroughput zt-help run-shell test clean

help:
@echo "Atomate2 Thermoelectric Docker Commands"
@echo "======================================="
@echo ""
@echo "ZT Calculation Commands:"
@echo " run-zt - Run ZT calculation (DEMO mode: fast parameters)"
@echo " run-zt-production - Run ZT calculation (PRODUCTION mode: accurate)"
@echo " run-zt-highthroughput - Run high-throughput ZT screening (multiple materials)"
@echo " zt-help - Show detailed ZT calculation example help"
@echo ""
@echo "Docker Build Commands:"
@echo " build - Build Docker image (always builds)"
@echo " rebuild - Force rebuild Docker image (ignore cache)"
@echo " build-if-needed - Build only if image doesn't exist"
@echo ""
@echo "Development Commands:"
@echo " run-shell - Open interactive shell in container"
@echo " test - Test all dependencies are working"
@echo " test-workflow - Test ZT workflow creation"
@echo " dev - Start development environment"
@echo " clean - Remove Docker images"
@echo ""
@echo "ZT Calculation Modes:"
@echo " DEMO mode : Fast testing (4×4×4 k-pts, 30 Ry, Si structure)"
@echo " PRODUCTION mode : Converged (8×8×8 k-pts, 60 Ry, multiple materials)"
@echo " HIGH-THROUGHPUT : Screen multiple materials with filtering"
@echo ""
@echo "Requirements:"
@echo " - Docker with buildx support"
@echo " - AMD64 platform (for BoltzTraP2 compatibility)"
@echo ""
@echo "Quick Start:"
@echo " make run-zt # Run a quick ZT demo (builds if needed)"
@echo " make zt-help # See all ZT calculation options"

# Build the Docker image for AMD64 architecture
build:
@echo "Building Docker image for AMD64 architecture..."
@if ! docker buildx ls | grep -q multiarch; then \
docker buildx create --name multiarch --use; \
else \
docker buildx use multiarch; \
fi
@docker buildx build --platform linux/amd64 -t atomate2-qe-amd64 . --load
@echo "✅ Build complete! Image: atomate2-qe-amd64"

# Force rebuild the Docker image (ignores cache)
rebuild:
@echo "Force rebuilding Docker image (ignoring cache)..."
@if ! docker buildx ls | grep -q multiarch; then \
docker buildx create --name multiarch --use; \
else \
docker buildx use multiarch; \
fi
@docker buildx build --platform linux/amd64 -t atomate2-qe-amd64 . --load --no-cache
@echo "✅ Rebuild complete! Image: atomate2-qe-amd64"

# Check if image exists and build only if needed
build-if-needed:
@if ! docker images | grep -q atomate2-qe-amd64; then \
echo "Image not found, building..."; \
$(MAKE) build; \
else \
echo "✅ Image atomate2-qe-amd64 already exists"; \
fi

# Run ZT calculation in demo mode (fast parameters)
run-zt: build-if-needed
@echo "Running ZT Calculation (DEMO mode - fast parameters)..."
@echo "======================================================="
@docker run --rm --platform linux/amd64 \
-v "$(PWD)/examples/zt_calculation.py:/app/examples/zt_calculation.py" \
--entrypoint /bin/bash atomate2-qe-amd64 \
-c "source /opt/conda/bin/activate qe-env && cd /app && python3 examples/zt_calculation.py --demo"

# Run ZT calculation in production mode (accurate parameters)
run-zt-production: build-if-needed
@echo "Running ZT Calculation (PRODUCTION mode - accurate parameters)..."
@echo "=================================================================="
@docker run --rm --platform linux/amd64 \
-v "$(PWD)/examples/zt_calculation.py:/app/examples/zt_calculation.py" \
--entrypoint /bin/bash atomate2-qe-amd64 \
-c "source /opt/conda/bin/activate qe-env && cd /app && timeout 1200 python3 examples/zt_calculation.py --production"

# Run high-throughput ZT screening (multiple materials)
run-zt-highthroughput: build-if-needed
@echo "Running High-Throughput ZT Screening (multiple materials)..."
@echo "============================================================"
@docker run --rm --platform linux/amd64 \
-v "$(PWD)/examples/zt_calculation.py:/app/examples/zt_calculation.py" \
--entrypoint /bin/bash atomate2-qe-amd64 \
-c "source /opt/conda/bin/activate qe-env && cd /app && timeout 1800 python3 examples/zt_calculation.py --high-throughput"

# Open interactive shell in the container
run-shell: build-if-needed
@echo "Opening interactive shell in atomate2 container..."
@docker run --rm -it --platform linux/amd64 \
-v "$(PWD):/app" \
--entrypoint /bin/bash atomate2-qe-amd64 \
-c "source /opt/conda/bin/activate qe-env && cd /app && exec bash"

# Test that all dependencies are working
test: build-if-needed
@echo "Testing Dependencies..."
@echo "======================"
@docker run --rm --platform linux/amd64 --entrypoint /bin/bash atomate2-qe-amd64 -c "\
source /opt/conda/bin/activate qe-env && \
echo '1. Testing Quantum ESPRESSO...' && \
(pw.x --version 2>/dev/null | head -1 || echo '❌ QE pw.x failed') && \
echo '2. Testing Python packages...' && \
python3 -c 'import atomate2; print(\"✅ atomate2:\", \"OK\")' && \
python3 -c 'import phonopy; print(\"✅ phonopy:\", phonopy.__version__)' && \
python3 -c 'import ase; print(\"✅ ASE:\", ase.__version__)' && \
python3 -c 'import BoltzTraP2; print(\"✅ BoltzTraP2: Available\")' && \
echo '3. Testing workflow creation...' && \
python3 -c 'from atomate2.espresso.flows.thermoelectric import ZTMaker; print(\"✅ ZT workflow: OK\")' && \
echo '' && \
echo '🎉 All dependencies working!'"

# Clean up Docker images
clean:
@echo "Cleaning up Docker images..."
@docker rmi atomate2-qe-amd64 2>/dev/null || echo "Image not found"
@docker system prune -f
@echo "✅ Cleanup complete"

# Quick test of ZT workflow components
test-workflow: build-if-needed
@echo "Testing ZT Workflow Components..."
@echo "================================="
@docker run --rm --platform linux/amd64 \
-v "$(PWD)/examples/zt_calculation.py:/app/examples/zt_calculation.py" \
--entrypoint /bin/bash atomate2-qe-amd64 -c "\
source /opt/conda/bin/activate qe-env && \
python3 -c \"\
print('Testing ZT calculation workflow creation...'); \
from atomate2.espresso.flows.thermoelectric import ZTMaker; \
from pymatgen.core import Structure; \
si = Structure([[0,2.73,2.73],[2.73,0,2.73],[2.73,2.73,0]], ['Si','Si'], [[0,0,0],[0.25,0.25,0.25]]); \
zt_maker = ZTMaker(name='test_zt_workflow'); \
flow = zt_maker.make(si); \
print(f'✅ ZT workflow created successfully!'); \
print(f' - Total jobs: {len(flow.jobs)}'); \
print(f' - Job names: {[job.name for job in flow.jobs]}'); \
print('✅ Ready for ZT calculations!')\""

# Show ZT calculation example help
zt-help: build-if-needed
@echo "ZT Calculation Example Help..."
@echo "=============================="
@docker run --rm --platform linux/amd64 \
-v "$(PWD)/examples/zt_calculation.py:/app/examples/zt_calculation.py" \
--entrypoint /bin/bash atomate2-qe-amd64 \
-c "source /opt/conda/bin/activate qe-env && cd /app && python3 examples/zt_calculation.py --help"

# Development mode - mount source code
dev: build-if-needed
@echo "Starting development environment..."
@docker run --rm -it --platform linux/amd64 \
-v "$(PWD):/app" \
-p 8888:8888 \
--entrypoint /bin/bash atomate2-qe-amd64 \
-c "source /opt/conda/bin/activate qe-env && cd /app && exec bash"

qe_example: build-if-needed
@docker run -v "$(PWD):/src" --platform linux/amd64 --rm atomate2-qe-amd64 bash -c "cd /src && export OMPI_MCA_plm_rsh_agent= && export
107 changes: 107 additions & 0 deletions examples/qe_bandgap_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""
Example usage of Quantum ESPRESSO band gap workflow in atomate2.

This example demonstrates how to use the new QE band gap calculation workflow
that combines SCF and bands calculations to compute accurate band gaps.
"""

from jobflow import run_locally
from pymatgen.core import Lattice, Structure

from atomate2.espresso import BandGapMaker, RelaxBandGapMaker


def create_silicon_structure():
"""Create a silicon diamond structure."""
lattice = Lattice.cubic(5.43) # Silicon lattice parameter in Angstroms
species = ["Si"] * 2
coords = [[0.0, 0.0, 0.0], [0.25, 0.25, 0.25]]
return Structure(lattice, species, coords)


def main():
"""Run QE band gap calculation examples."""

# Create silicon structure
structure = create_silicon_structure()
print(f"Created structure: {structure.formula}")

# Example 1: Basic band gap calculation
print("\n=== Example 1: Basic Band Gap Calculation ===")

# Create band gap workflow maker
bg_maker = BandGapMaker(
name="Si band gap calculation"
)

# Generate the workflow
bg_flow = bg_maker.make(structure)
print(f"Created workflow: {bg_flow.name}")
print(f"Number of jobs: {len(bg_flow.jobs)}")
print(f"Job names: {[job.name for job in bg_flow.jobs]}")

# Example 2: Customized band gap calculation
print("\n=== Example 2: Customized Band Gap Calculation ===")

# Customize SCF and bands settings
from atomate2.espresso.jobs.core import SCFMaker, BandsMaker

custom_scf = SCFMaker(
name="custom scf",
input_settings={
'pseudopotentials': {'Si': 'Si.pbe-n-rrkjus_psl.1.0.0.UPF'},
'kpts': (12, 12, 12), # Denser k-points
'ecutwfc': 60.0, # Higher cutoff
'conv_thr': 1e-10, # Tighter convergence
'mixing_beta': 0.5,
'occupations': 'fixed',
}
)

custom_bands = BandsMaker(
name="custom bands",
input_settings={
'kpts': (16, 16, 16), # Very dense k-points for bands
'nbnd': 30, # More bands
}
)

custom_bg_maker = BandGapMaker(
name="Custom Si band gap",
scf_maker=custom_scf,
bands_maker=custom_bands
)

custom_flow = custom_bg_maker.make(structure)
print(f"Custom workflow: {custom_flow.name}")

# Example 3: Relax + band gap calculation
print("\n=== Example 3: Relaxation + Band Gap Calculation ===")

# This would use a force field for relaxation first
relax_bg_maker = RelaxBandGapMaker(
name="Relax and band gap",
# relax_maker could be added here if needed
band_gap_maker=bg_maker
)

relax_flow = relax_bg_maker.make(structure)
print(f"Relax + band gap workflow: {relax_flow.name}")

print("\n=== Workflow Information ===")
print("The workflows are now ready to be submitted to a job manager.")
print("They will:")
print("1. Run SCF calculation to get ground state")
print("2. Run bands calculation with denser k-points")
print("3. Extract band gap from the results")
print("\nRequirements:")
print("- Quantum ESPRESSO installation")
print("- ASE with QE calculator support")
print("- Appropriate pseudopotentials")

result = run_locally(relax_flow)
breakpoint()


if __name__ == "__main__":
main()
Loading