Skip to content

Commit

Permalink
Merge pull request #10 from ilia-nikiforov-umn/add-aflow-and-update-l…
Browse files Browse the repository at this point in the history
…ammps-to-stable_2Aug2023_update1

Add aflow, spglib, crystal-genome-util

Update lammps to stable 2 aug2023 update1, update kim-property to 2.5.7

Update special-purpose matching to match cloud pipeline

Add functional tests
  • Loading branch information
ilia-nikiforov-umn authored Jan 18, 2024
2 parents 084de56 + 3ec0356 commit 7300a6f
Show file tree
Hide file tree
Showing 20 changed files with 421 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Docker publish
name: Docker publish and test

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
Expand All @@ -10,6 +10,7 @@ on:
types: [ published ]
pull_request:
branches: [ main ]
push:

env:
REGISTRY: ghcr.io
Expand Down Expand Up @@ -185,7 +186,7 @@ jobs:
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
if: github.event_name == 'release'
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
with:
registry: ${{ env.REGISTRY }}
Expand Down Expand Up @@ -215,20 +216,45 @@ jobs:
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG_INSTALL }}
labels: ${{ steps.meta.outputs.labels }}

# Perform final configurations and push image to registry (unless
# triggered by a PR):
# Perform final configurations
# - User creation and sudo configuration
# - Creation of local repository directory structure for KIM items
# - Vim configuration
# - Environment and shell configuration
#
# https://github.com/docker/build-push-action
- name: Configure and export minimal image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: docker/${{ env.DOCKER_DIR_CONFIG }}
load: true
file: docker/${{ env.DOCKER_DIR_CONFIG }}/${{ env.DOCKERFILE_NAME }}
push: false
build-args: |
"IMAGE_INSTALL=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG_INSTALL }}"
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test
labels: ${{ steps.meta.outputs.labels }}

- name: Test minimal image
run: |
bash test/run_tests.sh ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test pm_fast_tests
bash test/run_tests.sh ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test sm_fast_tests
bash test/run_vcs.sh ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test pm_fast_vcs
bash test/run_vcs.sh ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test sm_fast_vcs
bash test/run_tests.sh ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test equilibriumcrystalstructure
bash test/run_tests.sh ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test sp_sm_test
# Re-run the previous buildx action, except this time push the image if needed. Because of caching, this
# does not rebuild the image.
#
# https://github.com/docker/build-push-action
- name: Configure and push minimal image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: docker/${{ env.DOCKER_DIR_CONFIG }}
file: docker/${{ env.DOCKER_DIR_CONFIG }}/${{ env.DOCKERFILE_NAME }}
push: ${{ github.event_name != 'pull_request' }}
push: ${{ github.event_name == 'release' }}
build-args: |
"IMAGE_INSTALL=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG_INSTALL }}"
tags: |
Expand All @@ -255,7 +281,7 @@ jobs:
with:
context: docker/${{ env.DOCKER_DIR_ADDITIONAL }}
file: docker/${{ env.DOCKER_DIR_ADDITIONAL }}/${{ env.DOCKERFILE_NAME }}
push: ${{ github.event_name != 'pull_request' }}
push: ${{ github.event_name == 'release' }}
build-args: |
"IMAGE_MINIMAL=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}-minimal"
tags: |
Expand Down
46 changes: 20 additions & 26 deletions docker/config/excerpts/kimobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,15 +485,13 @@ def fresh_children_on_disk(self):

@property
def matching_models(self):
if not self.kimspec.get("matching-models"):
# FIXME: Uncomment this and raise an exception here once we add
# the 'matching-models' key to all runners.
return ["standard-models"]
# raise cf.MetadataKeyMissing(
# "Required key 'matching-models' not found in "
# "kimspec.edn file of {}".format(self.kim_code)
# )
return self.kimspec["matching-models"]
"""
Specifies what types of subjects the runner can match with, as a list of strings. Required to be present.
"""
if not self.kimspec:
return None
else:
return self.kimspec["matching-models"]


class Subject(KIMObject):
Expand Down Expand Up @@ -535,23 +533,6 @@ def kimspec(self):
spec = util.loadedn(f)
return spec

@property
def run_compatibility(self):
"""
Whether the SM can run against regular Tests (that are designed to run
against portable models) as opposed to Tests that are specifically
constructed to run against a particular subclass of SMs.
"""
if not self.kimspec.get("run-compatibility"):
# FIXME: Uncomment this and raise an exception here once we add
# the 'run-compatibility' key to all subjects.
return "portable-models"
# raise cf.MetadataKeyMissing(
# "Required key 'run-compatibility' not found in "
# "kimspec.edn file of {}".format(self.kim_code)
# )
return self.kimspec["run-compatibility"]


# ===============================================
# Subject Objs
Expand Down Expand Up @@ -641,6 +622,19 @@ def simulator_potential(self):
"kimspec.edn file of {}".format(self.kim_code)
)
return self.kimspec["simulator-potential"]

@property
def run_compatibility(self):
"""
Whether the SM can run against regular Tests (that are designed to run
against portable models) as opposed to Tests that are specifically
constructed to run against a particular subclass of SMs.
"""
if not self.kimspec:
return None
else:
return self.kimspec["run-compatibility"]



# =============================================
Expand Down
5 changes: 4 additions & 1 deletion docker/git/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ RUN git clone -q https://github.com/openkim/numdifftools -b master ${PACKAGE_DIR
RUN git clone -q https://github.com/openkim/kim-python-utils -b master ${PACKAGE_DIR}/kim-python-utils \
&& cd ${PACKAGE_DIR}/kim-python-utils \
&& git checkout e4e21b202264373a9f33dfc47b6e05c0af625950
RUN git clone -q https://github.com/lammps/lammps -b stable_23Jun2022 ${PACKAGE_DIR}/lammps
RUN git clone -q https://github.com/openkim/crystal-genome-util -b main ${PACKAGE_DIR}/crystal-genome-util \
&& cd ${PACKAGE_DIR}/crystal-genome-util \
&& git checkout ee3b739636eb7e2562b8baa6799d213caea68019
RUN git clone -q https://github.com/lammps/lammps -b stable_2Aug2023_update1 ${PACKAGE_DIR}/lammps
RUN git clone -q https://gitlab.com/openkim/ase -b user-species ${PACKAGE_DIR}/ase \
&& cd ${PACKAGE_DIR}/ase \
&& git checkout e00c8da0f84fb3a726c411f7ef2792241434c9a3
Expand Down
36 changes: 35 additions & 1 deletion docker/install/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ RUN ${PIP} install markupsafe==2.0.1
RUN ${PIP} install Jinja2==2.11.3
RUN ${PIP} install edn_format==0.7.5
RUN ${PIP} install kim-edn==1.3.1
RUN ${PIP} install kim-property==2.4.0
RUN ${PIP} install kim-property==2.5.7
RUN ${PIP} install kim-query==3.0.0
RUN ${PIP} install simplejson==3.17.2
RUN ${PIP} install numpy==1.19.5
Expand All @@ -48,6 +48,7 @@ RUN ${PIP} install matplotlib==3.7.1
RUN ${PIP} install pymongo==3.11.3
RUN ${PIP} install montydb==2.1.1
RUN ${PIP} install pybind11==2.6.2
RUN ${PIP} install spglib==2.1.0

#########################################
## MD++
Expand Down Expand Up @@ -110,6 +111,7 @@ RUN ${PIP} install kimpy==2.1.0
#########################################
## LAMMPS
#########################################
ARG DEBIAN_FRONTEND=noninteractive
RUN cd ${PACKAGE_DIR}/lammps/ \
&& mkdir build && cd build \
&& cmake \
Expand All @@ -131,9 +133,17 @@ RUN cd ${PACKAGE_DIR}/lammps/ \
-D PKG_REAXFF=yes \
-D PKG_MISC=yes \
-D PKG_SMTBQ=yes \
-D PKG_EXTRA-PAIR=yes \
-D PKG_CORESHELL=yes \
../cmake \
&& make -j2 \
&& make install \
&& apt-get update -qq \
&& apt-get install --no-install-recommends -qqy python3-venv \
&& make install-python \
&& apt-get purge -y python3-venv \
&& apt-get clean \
&& rm -fr /var/lib/apt/lists/* \
&& ln -s /usr/local/bin/lmp /usr/local/bin/lammps \
&& rm -r /usr/local/share/lammps/potentials \
&& cd ${PACKAGE_DIR} \
Expand All @@ -151,6 +161,12 @@ RUN cd ${PACKAGE_DIR}/ase/ \
RUN cd ${PACKAGE_DIR}/kim-python-utils \
&& ${PIP} install .

#########################################
## crystal-genome-util
#########################################
RUN cd ${PACKAGE_DIR}/crystal-genome-util \
&& ${PIP} install .

#########################################
## convergence
#########################################
Expand All @@ -159,3 +175,21 @@ RUN cd ${PACKAGE_DIR} \
&& rm convergence.txz \
&& cd convergence \
&& ${PIP} install .

#########################################
## AFLOW
#########################################
ARG AFLOW_VER=3.2.14
ARG AFLOW_PACKAGE=aflow.${AFLOW_VER}
ARG AFLOW_ARCHIVE_TXZ=${AFLOW_PACKAGE}.tar.xz
RUN cd ${PACKAGE_DIR} \
&& wget -q http://materials.duke.edu/AFLOW/${AFLOW_ARCHIVE_TXZ} \
&& tar xJf ${AFLOW_ARCHIVE_TXZ} \
&& rm ${AFLOW_ARCHIVE_TXZ} \
&& cd ${AFLOW_PACKAGE} \
&& make -j2 aflow \
&& cp aflow /usr/local/bin \
&& touch /usr/local/bin/aflow_data \
&& chmod +x /usr/local/bin/aflow_data \
&& cd ${PACKAGE_DIR} \
&& rm -r ${AFLOW_PACKAGE}
3 changes: 3 additions & 0 deletions test/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DOCKER_COMMAND="cd /home/openkim/test_scripts_and_data && bash set_up_and_run_$2.sh && python compare_dbs.py $2"
docker run --rm --mount type=bind,src=$PWD/test/test_scripts_and_data,target=/home/openkim/test_scripts_and_data --env LD_LIBRARY_PATH=:/usr/local/lib $1 /bin/bash -c "$DOCKER_COMMAND"

2 changes: 2 additions & 0 deletions test/run_vcs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DOCKER_COMMAND="cd /home/openkim/test_scripts_and_data && bash set_up_and_run_$2.sh && bash compare_vcs.sh $2"
docker run --rm --mount type=bind,src=$PWD/test/test_scripts_and_data,target=/home/openkim/test_scripts_and_data --env LD_LIBRARY_PATH=:/usr/local/lib $1 /bin/bash -c "$DOCKER_COMMAND"
127 changes: 127 additions & 0 deletions test/test_scripts_and_data/compare_dbs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
from montydb import MontyClient
import numpy as np
import json
import sys
import os


# TODO: more sophisticated checks for these keys
KEYS_TO_SKIP = ["parameter-values","excess"]


def compare_db_to_reference(reference_json_path: str, test_db_path: str, float_fractional_tolerance: float = 0.01):
"""
Compare a montydb generated by tests in the KDP to a reference json file.
The test DB is queried using MontyClient, while the reference json is accessed directly.
The reference json contains data types that are used to determine comparison tolerances.
Args:
reference_json_path:
Path to reference JSON file. This should be copied from /pipeline/db/db/data.json in the KDP
test_db_path:
Path to entire db directory generated in /pipeline/db of the KDP instance being tested
float_fractional_tolerance:
Fraction of the reference value of floating-point numbers that the test db is allowed to deviate by
"""
if os.path.exists(reference_json_path):
with open(reference_json_path) as f:
reference_db = json.load(f)
else:
reference_db = []

if os.path.exists(test_db_path):
with MontyClient(test_db_path, cache_modified=0) as client:
db = client.db
for i, reference_result in enumerate(reference_db):
print ("Processing reference result %d of %d"%(i,len(reference_db)),end="\r")
reference_uuid = reference_result["meta"]["uuid"]
reference_runner_and_subject = "-".join(reference_uuid.split("-")[:-2])
reference_instance_id = int(reference_result["instance-id"]["$numberInt"])
for key in reference_result:
if key == "vc-comment":
# VC comments may be a string with float numbers embedded, too much hassle to test
continue
if isinstance(reference_result[key],dict):
if ("source-value" in reference_result[key]) and (key not in KEYS_TO_SKIP):
# ok, this is a property key, search for this result
# generic error message
error_message_specifying_pair_and_key = "\n\nTest failed while comparing to key '%s' in instance-id %d in reference runner-subject pair %s:\n" \
%(key,reference_instance_id,reference_runner_and_subject)

# get numpy array of the source-value from the reference db
reference_source_value_array = np.asarray(reference_result[key]["source-value"])

"""
MONTYDB VERSION NOTE:
In 2.1.1, the version in the KDP, querying the /pipeline/db like this gives and requires dicts
e.g. {"$numberDouble": "0.70535806"} for typed values, just like the raw json in the reference db.
However, if we ever upgrade to 2.5.2 (or even some earlier versions might have this),
typed values just have the value.
"""

# query the test DB
query={
"meta.uuid":{"$regex":reference_runner_and_subject},
"instance-id.$numberInt":str(reference_instance_id)
}
cursor=db.data.find(query)

# get numpy array of the source-value from the DB we are testing
try:
test_source_value_array = np.asarray(next(cursor)[key]["source-value"])
except StopIteration:
assert False, error_message_specifying_pair_and_key+"No matches found in test DB."
except:
raise RuntimeError("Unexpected exception when searching test DB")

# should be only one result, test this
try:
next(cursor)
assert False, error_message_specifying_pair_and_key+"Multiple matches found in test DB."
except StopIteration:
pass
except:
raise RuntimeError("Unexpected exception when searching test DB")

# error message segment for displaying the source-values
error_message_showing_source_values = "\nMismatch found between reference value\n\n%s\n\nand test value\n\n%s\n\n" % \
(reference_source_value_array,test_source_value_array)

# arrays should be the same shape
assert reference_source_value_array.shape == test_source_value_array.shape, \
error_message_specifying_pair_and_key + error_message_showing_source_values + "Arrays are different shapes."
if reference_source_value_array.dtype != "object":
# this means it's strings, if its doubles or ints, each entry is a dict e.g. "$numberDouble": "0.70535806"
assert (reference_source_value_array == test_source_value_array).all(), \
error_message_specifying_pair_and_key + error_message_showing_source_values + "Non-numerical values are not equal."
else: # the reference ndarray is dicts, so we have to look at data types
reference_source_value_array_flat=reference_source_value_array.flat
if len(reference_source_value_array_flat[0].keys()) != 1:
raise RuntimeError("\n\nElements of reference DB value\n\n%s\n\nare not single-key dicts as expected."%reference_source_value_array)
for reference_source_value_dict,test_source_value_dict in zip(reference_source_value_array_flat,test_source_value_array.flat):
mongo_dtype = list(reference_source_value_dict.keys())[0]
if mongo_dtype == "$numberDouble":
reference_source_value = float(reference_source_value_dict[mongo_dtype])
test_source_value = float(test_source_value_dict[mongo_dtype])
assert abs(reference_source_value-test_source_value) <= abs(float_fractional_tolerance*reference_source_value), \
error_message_specifying_pair_and_key + error_message_showing_source_values + \
"Floating point values are not within the requested fractional tolerance %f"%float_fractional_tolerance
elif mongo_dtype == "$numberInt":
reference_source_value = int(reference_source_value_dict[mongo_dtype])
test_source_value = int(test_source_value_dict[mongo_dtype])
assert reference_source_value == test_source_value, \
error_message_specifying_pair_and_key + error_message_showing_source_values + \
"Integer values are not equal."
else:
raise RuntimeError("Unexpected data type %s in reference DB"%mongo_dtype)
with open(os.path.join(test_db_path,"db/data.json")) as f:
test_db = json.load(f)
assert len(test_db)==len(reference_db), "Database lengths are unequal. Because all results have been matched, this means there are extra results in the test db"
else:
assert reference_db == [], "Nonexistent test database trying to compare to a nonempty reference database"

if __name__=='__main__':
reference_json_file = sys.argv[1]+".json"
test_db = "/pipeline/db"
compare_db_to_reference(reference_json_file,test_db)
print("SUCCESS! All results provided in reference database were successfully matched.")
10 changes: 10 additions & 0 deletions test/test_scripts_and_data/compare_vcs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
sed -rn 's/Grade: (.*)/\1/p' ~/verification-results/*/report.txt > /home/openkim/tmp.grades

diffresult=$(diff /home/openkim/tmp.grades $1.grades 2>&1)

if [[ $diffresult != "" ]]; then
echo "following differences found between test and reference VCs:"
echo $diffresult
exit 1
fi
echo "All grades match"
30 changes: 30 additions & 0 deletions test/test_scripts_and_data/equilibriumcrystalstructure.json

Large diffs are not rendered by default.

Loading

0 comments on commit 7300a6f

Please sign in to comment.