diff --git a/andrewsalij/Convergence-Tracker.md b/andrewsalij/Convergence-Tracker.md new file mode 100644 index 00000000..3d4f1a4d --- /dev/null +++ b/andrewsalij/Convergence-Tracker.md @@ -0,0 +1,86 @@ +# K-point convergence tracker (Materials) + +Dependencies for this project may be installed by running in the following install script. + +```bash +pip install numpy matplotlib +pip install pymatgen +pip install pydantic +``` + +Tests (see Scripts folder) have been run on a variety of materials, whose provenance is below: + +Materials Project +link: https://legacy.materialsproject.org/ +(DOI: 10.1063/1.4812323) +(CC-BY 4.0, https://creativecommons.org/licenses/by/4.0/legalcode), see https://legacy.materialsproject.org/terms + +Si2 (mp-149) (DOI 10.17188/1190959) (https://legacy.materialsproject.org/materials/mp-149/) + +Materials Cloud three-dimensional crystals database (MC3D) +link: https://archive.materialscloud.org/record/2022.38 +(DOI: 10.24435/materialscloud:rw-t0) +(CC-BY 4.0, https://creativecommons.org/licenses/by/4.0/legalcode) + + +GaN (mc3d-3763/pbe) +BN (mc3d-13290/pbe) +O4Ru2 (mc3d-1930/pbe) +Br4Ca2 (mc3d-30836/pbe) +Cs2La2Te6Zn2 (mc3d-11071/pbe) +F2Fe2O8S2 (mc3d-14425/pbe) + +Materials Cloud two-dimensional crystals database (MC2D) +link: https://archive.materialscloud.org/record/2020.158 +DOI:10.24435/materialscloud:az-b2 +DOI:10.24435/materialscloud:36-nd (expansion) +(CC-BY 4.0, https://creativecommons.org/licenses/by/4.0/legalcode) + +C (graphene, from graphite exfoliation) (https://www.materialscloud.org/discover/mc2d/details/C, graphite (2H) initial) +MoS2 (https://www.materialscloud.org/discover/mc2d/details/MoS2-MoS2) +AgCO2 (https://www.materialscloud.org/discover/mc2d/details/AgCO2) + + +Pseudopotentials Tested: +PBEsol (standard accuracy) NC SR ONCVPSP 0.4.1 from Pseudo Dojo + Paper: 10.1016/j.cpc.2018.01.012 arxiv preprint + Method Paper: 10.1103/PhysRevB.88.085117 + License: (CC-BY 4.0, https://creativecommons.org/licenses/by/4.0/legalcode) + (see https://github.com/PseudoDojo/pseudodojo) + + +> Ideal candidate: scientists skilled in Density Functional Theory and proficient in python. + +# Overview + +The aim of this task is to create a python package that implements automatic convergence tracking mechanism for a materials simulations engine. The convergence is tracked with respect to the k-point sampling inside a reciprocal cell of a crystalline compound. + +# Requirements + +1. automatically find the dimensions of a k-point mesh that satisfy a certain criteria for total energy (eg. total energy is converged within dE = 0.01meV) +1. the code shall be written in a way that can facilitate easy addition of convergence wrt other characteristics extracted from simulations (forces, pressures, phonon frequencies etc) +1. the code shall support VASP or Quantum ESPRESSO + +# Expectations + +- correctly find k-point mesh that satisfies total energy convergence parameters for a set of 10 materials, starting from Si2, as simplest, to a 10-20-atom supercell of your choice +- modular and object-oriented implementation +- commit early and often - at least once per 24 hours + +# Timeline + +We leave exact timing to the candidate. Must fit Within 5 days total. + +# User story + +As a user of this software I can start it passing: + +- path to input data (eg. pw.in / POSCAR, INCAR, KPOINTS) and +- kinetic energy cutoff + +as parameters and get the k-point dimensions (eg. 5 5 5). + +# Notes + +- create an account at exabyte.io and use it for the calculation purposes +- suggested modeling engine: Quantum ESPRESSO diff --git a/andrewsalij/Licenses/matplotlib_LICENSE b/andrewsalij/Licenses/matplotlib_LICENSE new file mode 100644 index 00000000..ec51537d --- /dev/null +++ b/andrewsalij/Licenses/matplotlib_LICENSE @@ -0,0 +1,99 @@ +License agreement for matplotlib versions 1.3.0 and later +========================================================= + +1. This LICENSE AGREEMENT is between the Matplotlib Development Team +("MDT"), and the Individual or Organization ("Licensee") accessing and +otherwise using matplotlib software in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, MDT +hereby grants Licensee a nonexclusive, royalty-free, world-wide license +to reproduce, analyze, test, perform and/or display publicly, prepare +derivative works, distribute, and otherwise use matplotlib +alone or in any derivative version, provided, however, that MDT's +License Agreement and MDT's notice of copyright, i.e., "Copyright (c) +2012- Matplotlib Development Team; All Rights Reserved" are retained in +matplotlib alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on or +incorporates matplotlib or any part thereof, and wants to +make the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to matplotlib . + +4. MDT is making matplotlib available to Licensee on an "AS +IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB +WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between MDT and +Licensee. This License Agreement does not grant permission to use MDT +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib , +Licensee agrees to be bound by the terms and conditions of this License +Agreement. + +License agreement for matplotlib versions prior to 1.3.0 +======================================================== + +1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the +Individual or Organization ("Licensee") accessing and otherwise using +matplotlib software in source or binary form and its associated +documentation. + +2. Subject to the terms and conditions of this License Agreement, JDH +hereby grants Licensee a nonexclusive, royalty-free, world-wide license +to reproduce, analyze, test, perform and/or display publicly, prepare +derivative works, distribute, and otherwise use matplotlib +alone or in any derivative version, provided, however, that JDH's +License Agreement and JDH's notice of copyright, i.e., "Copyright (c) +2002-2011 John D. Hunter; All Rights Reserved" are retained in +matplotlib alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on or +incorporates matplotlib or any part thereof, and wants to +make the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to matplotlib. + +4. JDH is making matplotlib available to Licensee on an "AS +IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB +WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between JDH and +Licensee. This License Agreement does not grant permission to use JDH +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib, +Licensee agrees to be bound by the terms and conditions of this License +Agreement. \ No newline at end of file diff --git a/andrewsalij/Licenses/numpy_LICENSE.txt b/andrewsalij/Licenses/numpy_LICENSE.txt new file mode 100644 index 00000000..014d51c9 --- /dev/null +++ b/andrewsalij/Licenses/numpy_LICENSE.txt @@ -0,0 +1,30 @@ +Copyright (c) 2005-2023, NumPy Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/andrewsalij/Licenses/pydantic_LICENSE b/andrewsalij/Licenses/pydantic_LICENSE new file mode 100644 index 00000000..488c6260 --- /dev/null +++ b/andrewsalij/Licenses/pydantic_LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 to present Pydantic Services Inc. and individual contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/andrewsalij/Licenses/pymatgen_LICENSE b/andrewsalij/Licenses/pymatgen_LICENSE new file mode 100644 index 00000000..5533d21a --- /dev/null +++ b/andrewsalij/Licenses/pymatgen_LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright (c) 2011-2012 MIT & The Regents of the University of California, +through Lawrence Berkeley National Laboratory + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/andrewsalij/Scripts/AgCO2_2D/agco2_2d_k_converged.png b/andrewsalij/Scripts/AgCO2_2D/agco2_2d_k_converged.png new file mode 100644 index 00000000..ed1919d4 Binary files /dev/null and b/andrewsalij/Scripts/AgCO2_2D/agco2_2d_k_converged.png differ diff --git a/andrewsalij/Scripts/AgCO2_2D/run_sweep_agco2.py b/andrewsalij/Scripts/AgCO2_2D/run_sweep_agco2.py new file mode 100644 index 00000000..6c29e682 --- /dev/null +++ b/andrewsalij/Scripts/AgCO2_2D/run_sweep_agco2.py @@ -0,0 +1,21 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for 2D material AgCo2.''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "agco2_2d" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.03,run_prefix_str="mpirun -np 4") + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/BN/bn_k_converged.png b/andrewsalij/Scripts/BN/bn_k_converged.png new file mode 100644 index 00000000..0a8d91dc Binary files /dev/null and b/andrewsalij/Scripts/BN/bn_k_converged.png differ diff --git a/andrewsalij/Scripts/BN/run_sweep_bn.py b/andrewsalij/Scripts/BN/run_sweep_bn.py new file mode 100644 index 00000000..37777930 --- /dev/null +++ b/andrewsalij/Scripts/BN/run_sweep_bn.py @@ -0,0 +1,22 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for boron nitride.''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "bn" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.001,run_prefix_str="mpirun -np 4", + k_index=2,k_step=1,k_iterator_init=3) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/Br4Ca2/br4ca2_k_converged.png b/andrewsalij/Scripts/Br4Ca2/br4ca2_k_converged.png new file mode 100644 index 00000000..381e01b7 Binary files /dev/null and b/andrewsalij/Scripts/Br4Ca2/br4ca2_k_converged.png differ diff --git a/andrewsalij/Scripts/Br4Ca2/run_sweep_br4ca2.py b/andrewsalij/Scripts/Br4Ca2/run_sweep_br4ca2.py new file mode 100644 index 00000000..df1ca678 --- /dev/null +++ b/andrewsalij/Scripts/Br4Ca2/run_sweep_br4ca2.py @@ -0,0 +1,22 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for Br4Ca2. Also tests that lattice weighting is working +and that k iteration varies well ''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "br4ca2" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.005,run_prefix_str="mpirun -np 4",weight_type = "lattice",k_index=1,k_step=1,k_iterator_init=1) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/CsLaZnTe/cslaznte_k_converged.png b/andrewsalij/Scripts/CsLaZnTe/cslaznte_k_converged.png new file mode 100644 index 00000000..0b470a43 Binary files /dev/null and b/andrewsalij/Scripts/CsLaZnTe/cslaznte_k_converged.png differ diff --git a/andrewsalij/Scripts/CsLaZnTe/run_sweep_cslaznte.py b/andrewsalij/Scripts/CsLaZnTe/run_sweep_cslaznte.py new file mode 100644 index 00000000..ac79dcdb --- /dev/null +++ b/andrewsalij/Scripts/CsLaZnTe/run_sweep_cslaznte.py @@ -0,0 +1,21 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for rare-earth complex (Cs2La2Te6Zn2). Also tests parallelism of run command''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "cslaznte" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.1,run_prefix_str="mpirun -np 4",max_iterations=10) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/F2Fe2O8S2/ffeos_simple_k_converged.png b/andrewsalij/Scripts/F2Fe2O8S2/ffeos_simple_k_converged.png new file mode 100644 index 00000000..410e9ccf Binary files /dev/null and b/andrewsalij/Scripts/F2Fe2O8S2/ffeos_simple_k_converged.png differ diff --git a/andrewsalij/Scripts/F2Fe2O8S2/run_sweep_ffeos.py b/andrewsalij/Scripts/F2Fe2O8S2/run_sweep_ffeos.py new file mode 100644 index 00000000..cfb51f36 --- /dev/null +++ b/andrewsalij/Scripts/F2Fe2O8S2/run_sweep_ffeos.py @@ -0,0 +1,23 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for rare-earth complex (C2Ce2Os4P2). Also tests that lattice weighting is working''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "ffeos_simple" +#TODO add parser support for magnetization +#there is a bug in the pymatgen parser that prevents 'scf' calculations running w/ magnetization + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.1,run_prefix_str="mpirun -np 4",weight_type = "uniform",max_iterations=10) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/GaN/gan_k_converged.png b/andrewsalij/Scripts/GaN/gan_k_converged.png new file mode 100644 index 00000000..acc20b8c Binary files /dev/null and b/andrewsalij/Scripts/GaN/gan_k_converged.png differ diff --git a/andrewsalij/Scripts/GaN/run_sweep_gan.py b/andrewsalij/Scripts/GaN/run_sweep_gan.py new file mode 100644 index 00000000..b656cf30 --- /dev/null +++ b/andrewsalij/Scripts/GaN/run_sweep_gan.py @@ -0,0 +1,21 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for GaN''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "gan" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.002) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/Graphene_2D/graphene_2d_k_converged.png b/andrewsalij/Scripts/Graphene_2D/graphene_2d_k_converged.png new file mode 100644 index 00000000..3aac9874 Binary files /dev/null and b/andrewsalij/Scripts/Graphene_2D/graphene_2d_k_converged.png differ diff --git a/andrewsalij/Scripts/Graphene_2D/run_sweep_graphene.py b/andrewsalij/Scripts/Graphene_2D/run_sweep_graphene.py new file mode 100644 index 00000000..81a06c26 --- /dev/null +++ b/andrewsalij/Scripts/Graphene_2D/run_sweep_graphene.py @@ -0,0 +1,21 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for 2D material (graphene)''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "graphene_2d" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.002,fixed_k_points=[None,None,2]) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/MoS2_2D/mos2_2d_k_converged.png b/andrewsalij/Scripts/MoS2_2D/mos2_2d_k_converged.png new file mode 100644 index 00000000..a4a6c9f4 Binary files /dev/null and b/andrewsalij/Scripts/MoS2_2D/mos2_2d_k_converged.png differ diff --git a/andrewsalij/Scripts/MoS2_2D/run_sweep.py b/andrewsalij/Scripts/MoS2_2D/run_sweep.py new file mode 100644 index 00000000..35796310 --- /dev/null +++ b/andrewsalij/Scripts/MoS2_2D/run_sweep.py @@ -0,0 +1,21 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working for 2D material (MoS2)''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "mos2_2d" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.002,fixed_k_points=[None,None,2]) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/Os4Ru/os4ru_k_converged.png b/andrewsalij/Scripts/Os4Ru/os4ru_k_converged.png new file mode 100644 index 00000000..7f23392e Binary files /dev/null and b/andrewsalij/Scripts/Os4Ru/os4ru_k_converged.png differ diff --git a/andrewsalij/Scripts/Os4Ru/run_sweep.py b/andrewsalij/Scripts/Os4Ru/run_sweep.py new file mode 100644 index 00000000..e10070ce --- /dev/null +++ b/andrewsalij/Scripts/Os4Ru/run_sweep.py @@ -0,0 +1,21 @@ +import os +import andrewsalij.convergence_tracker as convergence_tracker + +'''Script for testing that k sweeping is working''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +compound_str = "os4ru" + +input = compound_str+".in" +filepath = os.sep.join((INPUT_BASE_FOLDER,input)) + +run_sub_dir = compound_str+"_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +k_array_conv = convergence_tester.find_convergence(-.005) + +convergence_tester.make_report_figure(compound_str+"_k_converged.png",x_axis_type="convergence_parameter") \ No newline at end of file diff --git a/andrewsalij/Scripts/Si2/run_si2_sweep.py b/andrewsalij/Scripts/Si2/run_si2_sweep.py new file mode 100644 index 00000000..1d9a3872 --- /dev/null +++ b/andrewsalij/Scripts/Si2/run_si2_sweep.py @@ -0,0 +1,33 @@ +import andrewsalij.io +import os +import copy +import andrewsalij.convergence_tracker as convergence_tracker + + +'''Script for testing that Si2 k sweeping is working''' + +INPUT_BASE_FOLDER = "/home/andrew/Documents/MaterialsDB/pwscf_files/" +RUN_BASE_FOLDER = "/home/andrew/Documents/QE_Runs" +os.makedirs(RUN_BASE_FOLDER,exist_ok=True) + +si2_input = "si2.in" + + +filepath = os.sep.join((INPUT_BASE_FOLDER,si2_input)) + +run_sub_dir = "Si2_k_sweep" +run_directory = os.sep.join((RUN_BASE_FOLDER,run_sub_dir)) +convergence_tester = convergence_tracker.KPointConvergenceTester(filepath,output_dir = run_directory) + +base_job = convergence_tester.base_job +update_job = copy.deepcopy(base_job) +sections = update_job.input.sections + + +convergence_tester.find_convergence(-.005) + +convergence_list = convergence_tester.convergence_parameter_list +convergence_energy_list = convergence_tester.convergence_energy_list + +convergence_tester.make_report_figure("si2_k_converged.png",x_axis_type="convergence_parameter") + diff --git a/andrewsalij/Scripts/Si2/si2_k_converged.png b/andrewsalij/Scripts/Si2/si2_k_converged.png new file mode 100644 index 00000000..111eb068 Binary files /dev/null and b/andrewsalij/Scripts/Si2/si2_k_converged.png differ diff --git a/andrewsalij/Tests/__pycache__/createConvergenceTester.cpython-310.pyc b/andrewsalij/Tests/__pycache__/createConvergenceTester.cpython-310.pyc new file mode 100644 index 00000000..3255663f Binary files /dev/null and b/andrewsalij/Tests/__pycache__/createConvergenceTester.cpython-310.pyc differ diff --git a/andrewsalij/Tests/__pycache__/createConvergenceTester.cpython-38.pyc b/andrewsalij/Tests/__pycache__/createConvergenceTester.cpython-38.pyc new file mode 100644 index 00000000..c70020c6 Binary files /dev/null and b/andrewsalij/Tests/__pycache__/createConvergenceTester.cpython-38.pyc differ diff --git a/andrewsalij/Tests/__pycache__/create_k_points.cpython-310.pyc b/andrewsalij/Tests/__pycache__/create_k_points.cpython-310.pyc new file mode 100644 index 00000000..a84ed682 Binary files /dev/null and b/andrewsalij/Tests/__pycache__/create_k_points.cpython-310.pyc differ diff --git a/andrewsalij/Tests/__pycache__/create_k_points.cpython-38.pyc b/andrewsalij/Tests/__pycache__/create_k_points.cpython-38.pyc new file mode 100644 index 00000000..30832e81 Binary files /dev/null and b/andrewsalij/Tests/__pycache__/create_k_points.cpython-38.pyc differ diff --git a/andrewsalij/Tests/__pycache__/qe_job_updating.cpython-310.pyc b/andrewsalij/Tests/__pycache__/qe_job_updating.cpython-310.pyc new file mode 100644 index 00000000..87ef3ecc Binary files /dev/null and b/andrewsalij/Tests/__pycache__/qe_job_updating.cpython-310.pyc differ diff --git a/andrewsalij/Tests/__pycache__/test_params.cpython-310.pyc b/andrewsalij/Tests/__pycache__/test_params.cpython-310.pyc new file mode 100644 index 00000000..8702aa1d Binary files /dev/null and b/andrewsalij/Tests/__pycache__/test_params.cpython-310.pyc differ diff --git a/andrewsalij/Tests/__pycache__/test_pwscf_io.cpython-310.pyc b/andrewsalij/Tests/__pycache__/test_pwscf_io.cpython-310.pyc new file mode 100644 index 00000000..7941d012 Binary files /dev/null and b/andrewsalij/Tests/__pycache__/test_pwscf_io.cpython-310.pyc differ diff --git a/andrewsalij/Tests/__pycache__/test_pwscf_io.cpython-38.pyc b/andrewsalij/Tests/__pycache__/test_pwscf_io.cpython-38.pyc new file mode 100644 index 00000000..fb3cdc14 Binary files /dev/null and b/andrewsalij/Tests/__pycache__/test_pwscf_io.cpython-38.pyc differ diff --git a/andrewsalij/Tests/createConvergenceTester.py b/andrewsalij/Tests/createConvergenceTester.py new file mode 100644 index 00000000..5f7453c6 --- /dev/null +++ b/andrewsalij/Tests/createConvergenceTester.py @@ -0,0 +1,18 @@ +import unittest +import andrewsalij.convergence_tracker as convergence_tracker +import andrewsalij.io +import andrewsalij.Tests.test_params as test_params + +class CreateConvergenceTester(unittest.TestCase): + def test_base_creation(self): + convergence_tester = convergence_tracker.ConvergenceTester(path="") + assert isinstance(convergence_tester,convergence_tracker.ConvergenceTester) + def test_k_pt_creation(self): + k_point_convergence_tester = convergence_tracker.KPointConvergenceTester(path="") + assert isinstance(k_point_convergence_tester,convergence_tracker.KPointConvergenceTester) + def test_convergence_loaded(self): + k_point_convergence_tester = convergence_tracker.KPointConvergenceTester(test_params.FILE_PATH) + assert isinstance(k_point_convergence_tester.base_job,andrewsalij.io.Job) + +if __name__ == '__main__': + unittest.main() diff --git a/andrewsalij/Tests/create_k_points.py b/andrewsalij/Tests/create_k_points.py new file mode 100644 index 00000000..5d4bf81c --- /dev/null +++ b/andrewsalij/Tests/create_k_points.py @@ -0,0 +1,35 @@ +import unittest +import numpy as np +from andrewsalij.convergence_tracker import KPointConvergenceTester + +class KPointArrayCreation(unittest.TestCase): + def test_basic(self): + k_array = KPointConvergenceTester.create_k_point_array(k_iterator=1) + assert np.array_equal(k_array,np.array([1,1,1],dtype=int)) + def test_k_indices(self): + for i in np.arange(3): + k_array = KPointConvergenceTester.create_k_point_array(k_iterator=2,k_index=i) + assert np.array_equal(k_array,np.array([2,2,2],dtype=int)) + def test_weight(self): + weight = np.array([1,2.4,3.1]) + k_array = KPointConvergenceTester.create_k_point_array(k_iterator=10,k_index = 0,effective_weight_array=weight) + assert np.array_equal(k_array,np.array([10,24,31])) + def test_k_force(self): + weight = np.array([3,2.4,2]) + k_force_array = np.array([None,None,1]) #for 2D (xy) materials + k_array = KPointConvergenceTester.create_k_point_array(k_iterator=5,k_index =1,effective_weight_array=weight, + fixed_k_points=k_force_array) + assert np.array_equal(k_array, np.array([6, 5, 1])) + def test_k_force_invalid_warn(self): + k_force= 1 #should warn--scalar does not work + self.assertWarns(Warning,KPointConvergenceTester.create_k_point_array,5, + k_index =1,effective_weight_array = np.array([3.6,3.1,6.3]),fixed_k_points = k_force) + def test_k_force_invalid_pass(self): + weight = np.array([3,2.4,2]) + k_force_array = 1 #should pass with warning + k_array = KPointConvergenceTester.create_k_point_array(k_iterator=5,k_index =1,effective_weight_array=weight, + fixed_k_points=k_force_array) + assert np.array_equal(k_array, np.array([6, 5, 4])) + +if __name__ == '__main__': + unittest.main() diff --git a/andrewsalij/Tests/qe_job_updating.py b/andrewsalij/Tests/qe_job_updating.py new file mode 100644 index 00000000..df476597 --- /dev/null +++ b/andrewsalij/Tests/qe_job_updating.py @@ -0,0 +1,21 @@ +import copy +import unittest +import test_params +import andrewsalij.io +import numpy as np +import numpy.testing as np_test +QE_JOB = andrewsalij.io.QEJob(test_params.FILE_PATH) +class QEJobUpdateTester(unittest.TestCase): + def test_k_array_update(self): + new_k_points = np.array([1,7,4]) + QE_JOB.update_k_points(new_k_points) + np_test.assert_array_equal(new_k_points,np.array(QE_JOB.input.kpoints_grid)) + def test_section_update(self): + new_directory = "/home/new_directory" + section_dict_update = {'control':{'outdir':new_directory}} + QE_JOB_copy = copy.deepcopy(QE_JOB) + QE_JOB_copy.update_input_sections(section_dict_update) + new_outdir = QE_JOB_copy.input.sections['control']['outdir'] + assert new_outdir == new_directory +if __name__ == '__main__': + unittest.main() diff --git a/andrewsalij/Tests/test_params.py b/andrewsalij/Tests/test_params.py new file mode 100644 index 00000000..2729dc8f --- /dev/null +++ b/andrewsalij/Tests/test_params.py @@ -0,0 +1,4 @@ +import os +TEST_DIR = "/home/andrew/Documents/RewoteTests" +FILE_STR = "si2.in" +FILE_PATH = os.sep.join((TEST_DIR,FILE_STR)) \ No newline at end of file diff --git a/andrewsalij/Tests/test_pwscf_io.py b/andrewsalij/Tests/test_pwscf_io.py new file mode 100644 index 00000000..0b4b2acf --- /dev/null +++ b/andrewsalij/Tests/test_pwscf_io.py @@ -0,0 +1,32 @@ +import unittest +import andrewsalij.io as io +import os +from pymatgen.io import pwscf +import andrewsalij.Tests.test_params as test_params +QE_JOB = io.QEJob(test_params.FILE_PATH) +class test_qcinput_io(unittest.TestCase): + def test_k_points(self): + k_points = [1,2,3] + QE_JOB.update_k_points(k_points) + self.assertTupleEqual(tuple(k_points),QE_JOB.input.kpoints_grid) + def test_write(self): + try: + os.makedirs(os.sep.join((test_params.TEST_DIR,"save")),exist_ok=True) + QE_JOB.save(os.sep.join((test_params.TEST_DIR,"save/si2.in"))) + except: + self.fail("Exception raised in saving QEJob") + def test_run(self): + try: + QE_JOB.run() + except: + self.fail("Exception raised in running QEJob") + def test_load_qejob(self): + try: + io.load_job(test_params.FILE_PATH,job_type="pwscf") + except: + self.fail("Exception raised in loading QEJob") + def test_output(self): + QE_JOB.run() + assert isinstance(QE_JOB.output,pwscf.PWOutput) +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/andrewsalij/__pycache__/convergence_tracker.cpython-310.pyc b/andrewsalij/__pycache__/convergence_tracker.cpython-310.pyc new file mode 100644 index 00000000..afe34609 Binary files /dev/null and b/andrewsalij/__pycache__/convergence_tracker.cpython-310.pyc differ diff --git a/andrewsalij/__pycache__/convergence_tracker.cpython-38.pyc b/andrewsalij/__pycache__/convergence_tracker.cpython-38.pyc new file mode 100644 index 00000000..e4ac6310 Binary files /dev/null and b/andrewsalij/__pycache__/convergence_tracker.cpython-38.pyc differ diff --git a/andrewsalij/__pycache__/io.cpython-310.pyc b/andrewsalij/__pycache__/io.cpython-310.pyc new file mode 100644 index 00000000..e3fafacf Binary files /dev/null and b/andrewsalij/__pycache__/io.cpython-310.pyc differ diff --git a/andrewsalij/__pycache__/io.cpython-38.pyc b/andrewsalij/__pycache__/io.cpython-38.pyc new file mode 100644 index 00000000..7277e771 Binary files /dev/null and b/andrewsalij/__pycache__/io.cpython-38.pyc differ diff --git a/andrewsalij/convergence_tracker.py b/andrewsalij/convergence_tracker.py new file mode 100644 index 00000000..699c3d6a --- /dev/null +++ b/andrewsalij/convergence_tracker.py @@ -0,0 +1,260 @@ +import copy +import matplotlib.pyplot as plt +import numpy as np +import warnings +import os +import andrewsalij.io +'''Convergence tracking of parameters, particularly testing for k point convergence.''' +class ConvergenceTester: + '''Base class for convergence testing some system''' + def __init__(self,path,output_dir = None,job_type = "pwscf"): + ''' + Initializes general convergence tester + :param path: str + :param output_dir: str or None + :param job_type : str + Path to file containing system for convergence testing + ''' + self.path = path + self.convergence_energy_list = [] + self.convergence_parameter_list = [] + self.output_list = [] + self.converged_energy = None + self.converged_parameter = None + if (path): + self.init_directory, self.filename = os.path.split(self.path) + self.base_output_directory = self._initialize_convergence_output_dir(output_dir=output_dir) + self.base_job= andrewsalij.io.load_job(self.path,job_type=job_type) + def find_convergence(self,convergence_delta): + ''' + Convergence parameter tolerance in units of parameter + :param convergence_delta: float + :return: + ''' + #TODO write general convergence handling + return None + def _initialize_convergence_output_dir(self,output_dir = None): + '''Initializes the convergence testing by creating output directory. If output_dir = None, makes directory 'conv' in self.path''' + if output_dir is None: + output_dir = os.sep.join((self.init_directory,"conv")) + os.makedirs(output_dir,exist_ok=True) + return output_dir + +class KPointConvergenceTester(ConvergenceTester): + '''Subclass for k-point convergence testing''' + def __init__(self,path,output_dir = None,job_type = "pwscf"): + '''Initializes KPointConvergenceTester as an instance of ConvergenceTester + :param path: str + :param output_dir: str or None + :param job_type: str + "pwscf": Quantum Espresso calculation (pw.x) + ''' + super().__init__(path,output_dir=output_dir,job_type=job_type) + + @staticmethod + def create_k_point_array(k_iterator,k_index = 0,effective_weight_array = np.array([1,1,1]),fixed_k_points = None): + ''' + Static method for the creation of a np.ndarray (size 3). See find_convergence() for details + :param k_iterator: int + :param k_index: int + :param effective_weight_array: np.ndarray (size 3) (default: np.array([1,1,1])) + Array for weighting of k indices. Defaults to uniform weighting. + :param fixed_k_points: (value, value, value) where value is int or None + :return: np.ndarray (size 3, type int) + ''' + k_index,k_iterator = int(k_index), float(k_iterator) + normalized_weight_array = np.array((effective_weight_array.astype(float))/float(effective_weight_array[k_index])) #normalized to iterator + k_point_array = (normalized_weight_array*k_iterator).astype(int) + k_point_array = np.where(k_point_array<1,1,k_point_array) #removing 0 indices-->imposing 1 minimum + if fixed_k_points is not None: #for fixed k points, overrides calculated k point array + try: + for i in np.arange(3): + k_point_force = fixed_k_points[i] + if (k_point_force is not None): k_point_array[i] = int(k_point_force) + except: + warnings.warn("Manually overriding k points failed: defaulting to initial values") + pass + return k_point_array + def _get_effective_k_point_weight(self,weight_type = "uniform"): + ''' + See find_convergence() for weight_type descriptions + :param weight_type: str + :return: np.ndarray (size 3, type int) + ''' + if weight_type=="uniform": + effective_weight_array = np.array([1,1,1]) #no special weighting + if weight_type=="lattice": + lattice_array = self.base_job.get_lattice_vectors() #a,b,c (in real space) + effective_weight_array = 1/lattice_array #now in reciprocal space + return effective_weight_array + def find_convergence(self,convergence_delta,k_iterator_init = int(1),k_step = int(1),k_index = 0, + fixed_k_points = None,weight_type = "uniform",run_prefix_str = "",max_iterations = 20,talk = True, + force_energy_decrease = False,allow_convergence_pos_delta= True): + ''' + Finds the converged energy for a given convergence delta for the input from the initialization. + Creates and runs in subdirectories within self.output_dir scf calculations for target system. + Convergence defined where the latest change in energy is less than the provided convergence_delta (to compel convergence to be negative + in final iteration, set allow_covergence_pos_delta to False. + Convergence iterates over a single k point index (default: first lattice dimension) from k_iterator_init (default: 1) + in increments of k_step (default: 1). Terminates after set max_iterations (default: 20). + :param convergence_delta : float (in units of method energy) + Tolerance for convergence + :param k_iterator_init : int (default: 1) + Initial value to begin the iterated k_index + :param k_step: int (default: 1) + Value to increase the k_iterator by each iteration + :param k_index: int (default: 0) + Scalar index of k points to iterate over + :param fixed_k_points: (value, value, value) where value is int or None + Optional parameter to fix certain k point values to arbitrary integers. + None either as a whole parameter or in the given tuple index implies that k point + value increases with iteration. + :param weight_type: str (default: "uniform") + Scaling type for k point iteration: + "uniform": + All free (not in fixed_k_points) indices are identical + "lattice": + K points scaled according to integers closed to reciprocal lattice vectors + :param run_prefix_str (default: "") + String to inset (e.g. "mpirun -np 4", before method call (e.g., "pw.x")). + Enables support for method parallelism + :param max_iterations: int (default: 20) + Number of iterations to run before killing convergence + :param talk: bool (default: True) + If True, outputs progress to console + :param force_energy_decrease: bool (default: False) + If True, kills convergence if energy ever increases + :param allow_convergence_pos_delta: bool (default: True) + If True, final convergence step can have a positive increase in energy less than convergence_delta and + force_energy_decrease is False. + If False, requires that final step is a negative change in energy + :return: np.ndarray (size 3, type int) or None + returns None if run failed to converge + ''' + k_iterator_init,k_step = int(k_iterator_init),int(k_step) + if (convergence_delta > 0): + warnings.warn("convergence_delta must be negative. Negativity imposed") + convergence_delta = -1*np.abs(convergence_delta) + cur_convergence_delta = convergence_delta-1 # initial value that must be lower that converged value + cur_k_iterator = k_iterator_init #index for k array construction + effective_weight_array = self._get_effective_k_point_weight(weight_type = weight_type) + run_counter = 0 #index for convergence lists + convergence_flag = False + while (not convergence_flag): #absolutes taken in case convergence + if run_counter >= max_iterations: + print("Max iterations "+str(max_iterations)+" reached. Terminating convergence run") + break + self._run_convergence_iteration(cur_k_iterator, + prefix_str=run_prefix_str,k_index = k_index, + effective_weight_array=effective_weight_array,fixed_k_points=fixed_k_points,talk = talk) + if (run_counter>=int(1)): + cur_convergence_delta = self.convergence_energy_list[run_counter]-self.convergence_energy_list[int(run_counter-1)] + + if cur_convergence_delta>0 and force_energy_decrease: + print("Energy increased in final convergence step. Terminating convergence run") + break + if (np.abs(cur_convergence_delta) "+output_path + subprocess.run(qe_process_str,shell=True) + self.output = pwscf.PWOutput(output_path) + def get_output_filename(self): + '''Returns pwscf filename corresponding to input '.in' given in self.path''' + base_dir, input_filename = os.path.split(self.path) + input_filename_base, ext = os.path.splitext(input_filename) + return input_filename_base+".out" + def get_lattice_vectors(self): + '''Returns lattice vectors a np.ndarray from PWInput''' + return np.array(self.input.structure.lattice.abc) +