From 427c9dc977c3cd4672cfac53c56e47746563b8c2 Mon Sep 17 00:00:00 2001 From: Jean-Luc Fattebert Date: Tue, 24 Oct 2023 15:18:37 -0400 Subject: [PATCH 1/5] Update script to analyze forces on constraints --- util/analyzeMDwithDistanceDiffConstraint.py | 267 ++++++++++++-------- 1 file changed, 159 insertions(+), 108 deletions(-) diff --git a/util/analyzeMDwithDistanceDiffConstraint.py b/util/analyzeMDwithDistanceDiffConstraint.py index 5a70a9a4..91c5e31f 100644 --- a/util/analyzeMDwithDistanceDiffConstraint.py +++ b/util/analyzeMDwithDistanceDiffConstraint.py @@ -5,8 +5,12 @@ # This file is part of MGmol. For details, see https://github.com/llnl/mgmol. # Please also read this link https://github.com/llnl/mgmol/LICENSE # -#how to run in local directory: -#python analyzeMDwithDistanceDiffConstraint.py . O8203 H3041 N6678 > forces.dat +# How to run in a python script: +# sys.path.append('/home/q8j/Documents/q8j/GIT/MGmol/util') +# import analyzeMDwithDistanceDiffConstraint as analyze +# ... +# analyze.runAnalyzeForces(idir,name0,name1,name2) + import sys, string, os from math import sqrt, acos from numpy import * @@ -34,12 +38,11 @@ time=0. def getMassAtom(name): - one=name[0] mass=0. - if one[0:2] in spmass.keys(): - mass=spmass[one[0:0+2]] + if name[0:2] in spmass.keys(): + mass=spmass[name[0:0+2]] else: - mass=spmass[one[0]] + mass=spmass[name[0]] return mass def analyzeForces(filename,name0,name1,name2,dt): @@ -48,14 +51,18 @@ def analyzeForces(filename,name0,name1,name2,dt): global corrected_avg_force global avg_invsqrtz global forces + global times + global running_forces global nsteps global nravg global time - + + print("analyzeForces with arguments {}, {}, {}, {}".format(filename, name0,name1,name2,dt)) + m0=getMassAtom(name0) m1=getMassAtom(name1) m2=getMassAtom(name2) - #print '#Masses:',m0,m1,m2 + print("#Masses: {}, {}, {}".format(m0,m1,m2)) coords=[] found=0 @@ -66,10 +73,10 @@ def analyzeForces(filename,name0,name1,name2,dt): r1=zeros(3) r2=zeros(3) - file=open(filename,'r') - L1=file.readlines() - for line in L1: ## loop over lines of file - words=string.split(line) + f=open(filename,'r') + lines=f.readlines() + for line in lines: ## loop over lines of file + words=line.split() if len(words)>1: #find force on constraint if 'force' in words and 'constraint' in words and '=' in words: @@ -86,7 +93,7 @@ def analyzeForces(filename,name0,name1,name2,dt): coords.append(name+'\t'+x+'\t'+y+'\t'+z) if found==3 and found_force: for i in range(3): - swords=string.split(coords[i]) + swords=coords[i].split() name=swords[0] x=eval(swords[1]) y=eval(swords[2]) @@ -121,8 +128,12 @@ def analyzeForces(filename,name0,name1,name2,dt): times.append(time) forces.append(eval(force)) - - print filename,'time=',time,' Q=',q,' force=',force,' corrected force=',corrected_force,' Z=',z,' running avg.= ',running_avg_force + + tol = 1.e-4 + delta = corrected_force-eval(force) + if abs(delta)>tol: + print("{}, time={}, Q={}, force={}, corrected force={}, Z={}, running avg.= {}".format( \ + filename,time,q,force,corrected_force,z,running_avg_force)) #print r01, r12 time=time+dt*au2ps @@ -131,7 +142,6 @@ def analyzeForces(filename,name0,name1,name2,dt): if time>1.: avg_force=avg_force+eval(force) - running_forces.append(running_avg_force) invsqrtz=1./sqrt(z) @@ -140,96 +150,137 @@ def analyzeForces(filename,name0,name1,name2,dt): nsteps=nsteps+1 - file.close() - -#main -filesdir=sys.argv[1] -filenames=os.listdir(filesdir) - -name0=sys.argv[2] -name1=sys.argv[3] -name2=sys.argv[4] -#print name0, name1, name2 - -inputs=[] -for filename in filenames: - if 'md_run' in filename: - inputs.append(filename) - -inputs.sort() - -inputs[0] -file=open(inputs[0],'r') -L1=file.readlines() -for line in L1: ## loop over lines of file - word=string.split(line) - if len(word)>1: - if word[0]=='Timestep': - dt=eval(word[5]) - -for filename in inputs: - analyzeForces(filename,name0,name1,name2,dt) - -nf=int(ceil(1./(dt*au2ps))) -ff=running_forces[-nf:] -maxF=max(float(v) for v in ff) -minF=min(float(v) for v in ff) -print '#maxF=',maxF -print '#minF=',minF - -if nsteps>0: - print '#Average force =',avg_force/nsteps - print '#Average corrected force=',corrected_avg_force/avg_invsqrtz - print '#running_forces, spread last ',nf,' steps=',maxF-minF + f.close() + +############################################################################### +# main script +############################################################################### + + +def runAnalyzeForces(filesdir,name0,name1,name2): + + global avg_force + global running_avg_force + global corrected_avg_force + global avg_invsqrtz + global forces + global times + global running_forces + global nsteps + global nravg + global time + + avg_force=0. + running_avg_force=0. + corrected_avg_force=0. + avg_invsqrtz=0. + + forces=[] + times=[] + running_forces=[] + + nsteps=0 + nravg=0 + time=0. + + + filenames=os.listdir(filesdir) + + #screen out files that are not mgmol outputs + inputs=[] + for filename in filenames: + if '.out' in filename: + inputs.append(filesdir+"/"+filename) + + inputs.sort() + + #extract dt from first output file in MD run + inputs[0] + f=open(inputs[0],'r') + lines=f.readlines() + for line in lines: ## loop over lines of file + word=line.split() + if len(word)>1: + if word[0]=='Timestep': + dt=eval(word[5]) + + #analyze all outputs + for filename in inputs: + analyzeForces(filename,name0,name1,name2,dt) + + #number of steps/ps + nf=int(ceil(1./(dt*au2ps))) + print("nf = {}".format(nf)) + + ff=running_forces[-nf:] + maxF=max(float(v) for v in ff) + minF=min(float(v) for v in ff) + print("#maxF={}".format(maxF)) + print("#minF={}".format(minF)) + + if nsteps>0: + print("#Average force ={}".format(avg_force/nsteps)) + print("#Average corrected force={}".format(corrected_avg_force/avg_invsqrtz)) + print("#running_forces, spread last {}, steps={}".format(nf,maxF-minF)) -skip=5 -forcep = [ forces[i] for i in range(0, len(forces), skip)] -timesp = [ times[i] for i in range(0, len(forces), skip)] - -skip=25 -aves1 = [sum(forces[i-nf:i])/nf for i in range(nf, len(forces), skip)] -aves2 = [sum(forces[i-2*nf:i])/(2*nf) for i in range(2*nf, len(forces), skip)] -aves3 = [sum(forces[i-3*nf:i])/(3*nf) for i in range(3*nf, len(forces), skip)] - -times1 = [ times[i] for i in range(nf, len(forces), skip)] -times2 = [ times[i] for i in range(2*nf, len(forces), skip)] -times3 = [ times[i] for i in range(3*nf, len(forces), skip)] - -print '#time force' -for i in range(len(forces)): - print times[i],forces[i] - -print '#Running average over 2 ps, last value: ',aves2[-1] -print '#Running average over 3 ps, last value: ',aves3[-1] - - -xmax=len(forces)*dt*au2ps -xmax=max(xmax,4.) -ymin=min(forces) -ymax=max(forces) - -plt.figure(1) -plt.subplot(211) -plt.axis([0.,xmax,ymin,ymax]) -plt.plot(timesp, forcep, 'go') -plt.ylabel('force (Ha/Bohr)') -#plt.show() - -plt.subplot(212) -ymin=min(aves2) -ymax=max(aves2) -plt.axis([0.,xmax,ymin,ymax]) -#plt.plot(times1, aves1, 'ro') -plt.plot(times2, aves2, 'ro') -plt.plot(times3, aves3, 'bo') -plt.ylabel('force (Ha/Bohr)') -plt.xlabel('time (ps)') -#plt.show() -plt.savefig('aves.png') - -nn=nf/skip -max3=max(aves3[-1-nn:-1]) -min3=min(aves3[-1-nn:-1]) -print 'min aves3 over lat ps = ',min3 -print 'max aves3 over lat ps = ',max3 -print 'spread aves3 over lat ps = ',max3-min3 + skip=5 + forcep = [ forces[i] for i in range(0, len(forces), skip)] + timesp = [ times[i] for i in range(0, len(forces), skip)] + plt.figure(1) + xmax=len(forces)*dt*au2ps + ymin=min(forces) + ymax=max(forces) + plt.axis([0.,xmax,ymin,ymax]) + + fig=plt.figure(1) + plt.subplot(211) + plt.plot(timesp, forcep, 'go') + plt.ylabel('force (Ha/Bohr)') + colors=['ro','bo','go','yo','mo'] + icolor=0 + #compute running averages + skip=25 + for interval in range(1,6): + aves = [sum(forces[i-interval*nf:i])/(interval*nf) for i in range(interval*nf,len(forces), skip)] + + timesp = [ times[i] for i in range(interval*nf, len(forces), skip)] + forcep = [ forces[i] for i in range(interval*nf, len(forces), skip)] + + print("#Average over last {} ps: {}".format(interval,aves[-1])) + + sigma = [sum((forces[i-interval*nf:i]-aves[-1])*(forces[i-interval*nf:i]-aves[-1]))/(interval*nf-1) for i in range(interval*nf, len(forces), skip)] + + print("#Sigma over last {} ps: {}".format(interval,math.sqrt(sigma[-1]))) + + plt.subplot(212) + plt.plot(timesp, aves, colors[icolor]) + icolor=icolor+1 + plt.ylabel('running average (Ha/Bohr)') + plt.xlabel('time (ps)') + plt.axis([0.,xmax,ymin,ymax]) + + plt.savefig(filesdir+'_aves.png') + plt.close(fig) + + nn=int(nf/skip) + print(nn) + max3=max(aves[-1-nn:-1]) + min3=min(aves[-1-nn:-1]) + print("min aves over last ps = {}".format(min3)) + print("max aves over last ps = {}".format(max3)) + print("min-max spread aves3 over last ps = {}".format(max3-min3)) + +############################################################################### +# main script +############################################################################### + +#target directory containing multiple segments of a single run +#filesdir=sys.argv[1] +#filenames=os.listdir(filesdir) + +#read names of 3 atoms involved in constraint +#name0=sys.argv[2] +#name1=sys.argv[3] +#name2=sys.argv[4] + +#runAnalyzeForces(filesdir,name0,name1,name2) From 51b93fc3d13a96badfe9fa05368c31a311e034c4 Mon Sep 17 00:00:00 2001 From: Kevin Chung Date: Thu, 26 Oct 2023 10:53:43 -0700 Subject: [PATCH 2/5] initial ci workflow files. --- .github/workflows/ci.yml | 45 +++++++++++++++++++++++ .github/workflows/docker_image.yml | 59 ++++++++++++++++++++++++++++++ docker/Dockerfile | 38 +++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docker_image.yml create mode 100644 docker/Dockerfile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..97867619 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: CI +on: + workflow_dispatch: {} + pull_request: + types: [opened, labeled, synchronize] + branches: + - main + # push: + # branches: + # - main + +jobs: + docker-image: + uses: ./.github/workflows/docker_image.yml + build: + runs-on: ubuntu-latest + needs: [docker-image] + container: + image: ghcr.io/llnl/mgmol/mgmol_env:latest + options: --user 1001 --privileged + volumes: + - /mnt:/mnt + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.11.0 + with: + access_token: ${{ github.token }} + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 10 + - name: Check out pylibROM + uses: actions/checkout@v1 + with: + submodules: 'true' + - name: Git Submodules status + run: | + git submodule status + - name: cmake + run: | + cmake . -DCMAKE_CXX_COMPILER=mpic++ -DCMAKE_Fortran_COMPILER=mpif90 + - name: make + run: | + make -j 4 + diff --git a/.github/workflows/docker_image.yml b/.github/workflows/docker_image.yml new file mode 100644 index 00000000..6ef9c0e1 --- /dev/null +++ b/.github/workflows/docker_image.yml @@ -0,0 +1,59 @@ +name: docker-image +on: + workflow_call: + +env: + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: llnl/mgmol/mgmol_env + DOCKERPATH: docker + +jobs: + docker-ci: + runs-on: ubuntu-latest + name: "docker env" + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: Ana06/get-changed-files@v2.2.0 + id: files + - name: DockerPATH configuration + run: echo "DOCKERPATH=$DOCKERPATH" + - name: DockerPATH - check if files in docker path changed + if: contains(steps.files.outputs.all,env.DOCKERPATH) || contains(steps.files.outputs.all,'docker_librom.yml') + run: | + echo "CI container needs rebuilding..." + echo "CI_NEEDS_REBUILD=true" >> $GITHUB_ENV + - name: Log into registry ${{ env.REGISTRY }} + if: env.CI_NEEDS_REBUILD + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract metadata (tags, labels) for Docker + id: meta + if: env.CI_NEEDS_REBUILD + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: type=sha + flavor: latest=true + - name: Build Container motd + if: env.CI_NEEDS_REBUILD + run: | + echo "#!/bin/bash" > ${{env.DOCKERPATH}}/motd.sh + echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh + echo "echo pylibrom_env/CI Development Container" >> ${{env.DOCKERPATH}}/motd.sh + echo "echo \"Revision: `echo ${GITHUB_SHA} | cut -c1-8`\"" >> ${{env.DOCKERPATH}}/motd.sh + echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh + chmod 755 ${{env.DOCKERPATH}}/motd.sh + cat ${{env.DOCKERPATH}}/motd.sh + - name: Docker Image - Build and push + if: env.CI_NEEDS_REBUILD + uses: docker/build-push-action@v3 + with: + push: true + context: ${{ env.DOCKERPATH }} + tags: ${{ steps.meta.outputs.tags }} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..4ccd50ac --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,38 @@ +FROM ubuntu:22.04 + +ENV ENVDIR=env + +# install sudo +RUN apt-get -yq update && apt-get -yq install sudo + +WORKDIR /$ENVDIR + +# install packages +RUN sudo apt-get install -yq git +RUN sudo apt-get install --no-install-recommends -yq make gcc gfortran libssl-dev cmake +RUN sudo apt-get install -yq libopenblas-dev libmpich-dev libblas-dev liblapack-dev libscalapack-mpi-dev libhdf5-mpich-dev +RUN sudo apt-get install -yq libboost-all-dev +RUN sudo apt-get install -yq vim +RUN sudo apt-get install -yq git-lfs +RUN sudo apt-get install -yq valgrind +RUN sudo apt-get install -yq wget +RUN sudo apt-get install -yq astyle + +# install lldb and gdb for debugging +RUN sudo apt-get install -yq lldb gdb + +RUN sudo apt-get clean -q + +# NOTE: currently docker does not have a way to set environment variable with a command output. +# The following environment variable should use $(uname -m) for different architecture. +# ENV SCALAPACK_ROOT=/usr/lib/aarch64-linux-gnu/ +ENV SCALAPACK_ROOT=/usr/lib/x86_64-linux-gnu/ + +# create and switch to a user +ENV USERNAME=test +RUN echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers +RUN useradd --no-log-init -u 1001 --create-home --shell /bin/bash $USERNAME +RUN adduser $USERNAME sudo +USER $USERNAME +WORKDIR /home/$USERNAME + From 7705fd918005fff52047aa6ea57eba32bdd5bfb7 Mon Sep 17 00:00:00 2001 From: Kevin Chung Date: Thu, 26 Oct 2023 16:48:55 -0700 Subject: [PATCH 3/5] default branch name release. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97867619..ce4b2f00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,10 +4,10 @@ on: pull_request: types: [opened, labeled, synchronize] branches: - - main + - release # push: # branches: - # - main + # - release jobs: docker-image: From 275b8df10082bc3bd070b0d91649d4361e4f3501 Mon Sep 17 00:00:00 2001 From: Kevin Chung Date: Thu, 26 Oct 2023 16:55:09 -0700 Subject: [PATCH 4/5] create build directory for compilation. --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce4b2f00..a88d7b48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,8 +38,10 @@ jobs: git submodule status - name: cmake run: | - cmake . -DCMAKE_CXX_COMPILER=mpic++ -DCMAKE_Fortran_COMPILER=mpif90 + mkdir build + cd build + cmake .. -DCMAKE_CXX_COMPILER=mpic++ -DCMAKE_Fortran_COMPILER=mpif90 - name: make run: | - make -j 4 + cd build && make -j 4 From 90524d79ccfe383b8e337d909dc6d873385ccf91 Mon Sep 17 00:00:00 2001 From: Kevin Chung Date: Thu, 26 Oct 2023 17:19:31 -0700 Subject: [PATCH 5/5] minor fix --- .github/workflows/docker_image.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker_image.yml b/.github/workflows/docker_image.yml index 6ef9c0e1..90a2447b 100644 --- a/.github/workflows/docker_image.yml +++ b/.github/workflows/docker_image.yml @@ -21,7 +21,7 @@ jobs: - name: DockerPATH configuration run: echo "DOCKERPATH=$DOCKERPATH" - name: DockerPATH - check if files in docker path changed - if: contains(steps.files.outputs.all,env.DOCKERPATH) || contains(steps.files.outputs.all,'docker_librom.yml') + if: contains(steps.files.outputs.all,env.DOCKERPATH) || contains(steps.files.outputs.all,'docker_image.yml') run: | echo "CI container needs rebuilding..." echo "CI_NEEDS_REBUILD=true" >> $GITHUB_ENV @@ -45,7 +45,7 @@ jobs: run: | echo "#!/bin/bash" > ${{env.DOCKERPATH}}/motd.sh echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh - echo "echo pylibrom_env/CI Development Container" >> ${{env.DOCKERPATH}}/motd.sh + echo "echo mgmol_env/CI Development Container" >> ${{env.DOCKERPATH}}/motd.sh echo "echo \"Revision: `echo ${GITHUB_SHA} | cut -c1-8`\"" >> ${{env.DOCKERPATH}}/motd.sh echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh chmod 755 ${{env.DOCKERPATH}}/motd.sh