diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 2f1e31a4f6..4a1839acbb 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -71,6 +71,9 @@ jobs: if: github.event_name == 'repository_dispatch' && github.event.action == 'pymatgen-ci-trigger' run: pip install --upgrade 'git+https://github.com/materialsproject/pymatgen@${{ github.event.client_payload.pymatgen_ref }}' + - name: Test Notebooks + run: pytest --nbmake ./tutorials + - name: Test env: MP_API_KEY: ${{ secrets.MP_API_KEY }} diff --git a/.gitignore b/.gitignore index 84772c27cc..6cdafcdcea 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,5 @@ docs/reference/atomate2.* # see https://github.com/materialsproject/atomate2/issues/345 *.doctrees* + +.ipynb_checkpoints diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 32aeb5438e..e84a23f915 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,3 +44,12 @@ repos: stages: [commit, commit-msg] args: [--ignore-words-list, 'titel,statics,ba,nd,te,atomate'] types_or: [python, rst, markdown] +- repo: https://github.com/kynan/nbstripout + rev: 0.7.1 + hooks: + - id: nbstripout + args: [ + --drop-empty-cells, + --strip-init-cells, + --extra-keys=metadata.kernelspec, + ] diff --git a/docs/_static/docs_store_Si_relax.json b/docs/_static/docs_store_Si_relax.json new file mode 100644 index 0000000000..8f54f2f0bb --- /dev/null +++ b/docs/_static/docs_store_Si_relax.json @@ -0,0 +1 @@ +[{"uuid":"c2b5eb7d-838b-4dee-896f-95f21867b62b","index":1,"output":{"builder_meta":{"emmet_version":"0.83.0","pymatgen_version":"2024.4.13","pull_request":null,"database_version":null,"build_date":"2024-05-19T21:13:45.541000","license":null},"nsites":2,"elements":["Si"],"nelements":1,"composition":{"Si":2.0},"composition_reduced":{"Si":1.0},"formula_pretty":"Si","formula_anonymous":"A","chemsys":"Si","volume":40.163300666862035,"density":2.3223723738160613,"density_atomic":20.081650333431018,"symmetry":{"crystal_system":"Cubic","symbol":"Fd-3m","number":227,"point_group":"m-3m","symprec":0.1,"version":"2.4.0"},"tags":null,"dir_name":"della-r3c1n3:/scratch/gpfs/ab6989/MPScanRelaxSet/atomate2/Ca_Mg_runs/job_2024-05-19-21-13-15-058677-64911","state":"successful","calcs_reversed":[{"dir_name":"/scratch/gpfs/ab6989/MPScanRelaxSet/atomate2/Ca_Mg_runs/job_2024-05-19-21-13-15-058677-64911","vasp_version":"6.4.2","has_vasp_completed":"successful","input":{"incar":{"PREC":"Accurate","ALGO":"Fast","ISPIN":2,"NELM":200,"IBRION":2,"EDIFF":0.00001,"EDIFFG":-0.02,"NSW":99,"ISIF":3,"ENCUT":680.0,"ENAUG":1360.0,"MAGMOM":[0.6,0.6],"LREAL":false,"ISMEAR":0,"SIGMA":0.2,"LWAVE":false,"LCHARG":false,"LVTOT":false,"LORBIT":11,"LELF":false,"LASPH":true,"LAECHG":true,"GGA":"Ps","LMIXTAU":true},"kpoints":{"comment":"Kpoints from vasprun.xml","nkpoints":0,"generation_style":"Gamma","kpoints":[[7,7,7]],"usershift":[0.0,0.0,0.0],"kpts_weights":null,"coord_type":null,"labels":null,"tet_number":0,"tet_weight":0,"tet_connections":null,"@module":"pymatgen.io.vasp.inputs","@class":"Kpoints"},"nkpoints":20,"potcar":["PAW_PBE"],"potcar_spec":[{"titel":"PAW_PBE Si 05Jan2001","hash":"c27340a9c98542122fbad458bbb5d441","summary_stats":{"keywords":{"header":["dexc","eatom","eaug","enmax","enmin","icore","iunscr","lcor","lexch","lpaw","lultra","ndata","orbitaldescriptions","orbitals","pomass","raug","rcore","rdep","rdept","rmax","rpacor","rrkj","rwigs","step","titel","vrhfin","zval","nentries"],"data":["localpart","gradientcorrectionsusedforxc","corecharge-density(partial)","kineticenergydensity(partial)","atomicpseudocharge-density","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","pawradialsets","(5e20.12)","augmentationcharges(nonsperical)","uccopanciesinatom","grid","aepotential","corecharge-density","kineticenergy-density","mkineticenergy-densitypseudized","localpseudopotentialcore","pspotentialvalenceonly","corecharge-density(pseudized)","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","endofdataset"]},"stats":{"header":{"MEAN":9.198469218699186,"ABSMEAN":9.198469218699186,"VAR":1790.7147656424072,"MIN":0.0,"MAX":322.069},"data":{"MEAN":215.16613596661992,"ABSMEAN":237.9507629282115,"VAR":3381771.445249609,"MIN":-872.57185,"MAX":24929.6947974}}}}],"potcar_type":["PAW_PBE"],"parameters":{"SYSTEM":"unknown system","LCOMPAT":false,"PREC":"accura","ENMAX":680.0,"ENAUG":1360.0,"EDIFF":0.00001,"IALGO":68,"IWAVPR":11,"NBANDS":40,"NBANDSLOW":-1,"NBANDSHIGH":-1,"NELECT":8.0,"TURBO":0,"IRESTART":0,"NREBOOT":0,"NMIN":0,"EREF":0.0,"ISMEAR":0,"SIGMA":0.2,"KSPACING":0.5,"KGAMMA":true,"KBLOWUP":true,"LREAL":false,"ROPT":[0.0],"LMAXPAW":-100,"LMAXMIX":2,"NLSPLINE":false,"ISTART":0,"ICHARG":2,"INIWAV":1,"ISPIN":2,"LNONCOLLINEAR":false,"MAGMOM":[0.6,0.6],"NUPDOWN":-1.0,"LSORBIT":false,"SAXIS":[0.0,0.0,1.0],"LSPIRAL":false,"QSPIRAL":[0.0,0.0,0.0],"LZEROZ":false,"LASPH":true,"LMETAGGA":false,"NELM":200,"NELMDL":-5,"NELMIN":2,"ENINI":680.0,"LDIAG":true,"LSUBROT":false,"WEIMIN":0.001,"EBREAK":6e-8,"DEPER":0.3,"NRMM":4,"TIME":0.4,"AMIX":0.4,"BMIX":1.0,"AMIN":0.1,"AMIX_MAG":1.6,"BMIX_MAG":1.0,"IMIX":4,"MIXFIRST":false,"MAXMIX":-45,"WC":100.0,"INIMIX":1,"MIXPRE":1,"MREMOVE":5,"LDIPOL":false,"LMONO":false,"IDIPOL":0,"EPSILON":1.0,"DIPOL":[-100.0,-100.0,-100.0],"EFIELD":0.0,"NGX":36,"NGY":36,"NGZ":36,"NGXF":72,"NGYF":72,"NGZF":72,"ADDGRID":false,"NSW":99,"IBRION":2,"MDALGO":0,"ISIF":3,"PSTRESS":0.0,"EDIFFG":-0.02,"NFREE":1,"POTIM":0.5,"SMASS":-3.0,"SCALEE":1.0,"TEBEG":0.0001,"TEEND":0.0001,"NBLOCK":1,"KBLOCK":99,"NPACO":256,"APACO":10.0,"ISYM":2,"SYMPREC":0.00001,"LORBIT":11,"RWIGS":[-1.0],"NEDOS":301,"EMIN":10.0,"EMAX":-10.0,"EFERMI":0.0,"NWRITE":2,"LWAVE":false,"LDOWNSAMPLE":false,"LCHARG":false,"LPARD":false,"LVTOT":false,"LVHAR":false,"LELF":false,"LOPTICS":false,"STM":[0.0,0.0,0.0,0.0,0.0,0.0,0.0],"NPAR":40,"NSIM":4,"NBLK":-1,"LPLANE":true,"LSCALAPACK":true,"LSCAAWARE":false,"LSCALU":false,"LASYNC":false,"LORBITALREAL":false,"IDIOT":3,"PHON_NSTRUCT":-1,"LMUSIC":false,"POMASS":[28.085],"DARWINR":[0.0],"DARWINV":[1.0],"LCORR":true,"GGA_COMPAT":true,"LBERRY":false,"ICORELEVEL":0,"LDAU":false,"I_CONSTRAINED_M":0,"GGA":"PS","VOSKOWN":0,"LHFCALC":false,"PRECFOCK":"","LSYMGRAD":false,"LHFONE":false,"LRHFCALC":false,"LTHOMAS":false,"LMODELHF":false,"LFOCKACE":false,"ENCUT4O":-1.0,"EXXOEP":0,"FOURORBIT":0,"AEXX":0.0,"HFALPHA":0.0,"MCALPHA":0.0,"ALDAX":1.0,"AGGAX":1.0,"ALDAC":1.0,"AGGAC":1.0,"NKREDX":1,"NKREDY":1,"NKREDZ":1,"SHIFTRED":false,"ODDONLY":false,"EVENONLY":false,"LMAXFOCK":0,"NMAXFOCKAE":0,"LFOCKAEDFT":false,"HFSCREEN":0.0,"HFSCREENC":0.0,"NBANDSGWLOW":0,"LUSE_VDW":false,"IVDW_NL":1,"LSPIN_VDW":false,"Zab_VDW":-0.8491,"PARAM1":0.1234,"PARAM2":1.0,"PARAM3":0.0,"MODEL_GW":0,"MODEL_EPS0":12.2078502,"MODEL_ALPHA":1.0,"LEPSILON":false,"LRPA":false,"LNABLA":false,"LVEL":false,"CSHIFT":0.1,"OMEGAMAX":-1.0,"DEG_THRESHOLD":0.002,"RTIME":-0.1,"WPLASMAI":0.0,"DFIELD":[0.0,0.0,0.0],"WPLASMA":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],"NUCIND":false,"MAGPOS":[0.0,0.0,0.0],"LNICSALL":true,"ORBITALMAG":false,"LMAGBLOCH":false,"LCHIMAG":false,"LGAUGE":true,"MAGATOM":0,"MAGDIPOL":[0.0,0.0,0.0],"AVECCONST":[0.0,0.0,0.0],"LALL_IN_ONE":false,"IALL_IN_ONE":-1,"NBANDS_WAVE":-1,"LFINITE_TEMPERATURE":false,"LADDER":false,"LRPAFORCE":false,"LFXC":false,"LHARTREE":true,"IBSE":0,"KPOINT":[-1,0,0,0],"LTCTC":false,"LTCTE":false,"LTETE":false,"LTRIPLET":false,"LFXCEPS":false,"LFXHEG":false,"NATURALO":2,"LHOLEGF":false,"L2ORDER":false,"LDMP1":false,"LMP2LT":false,"LSMP2LT":false,"LGWLF":false,"ENCUTGW":-1.60000002,"ENCUTGWSOFT":-1.60000002,"ENCUTLF":-1.0,"LESF_SPLINES":false,"LMAXMP2":-1,"SCISSOR":0.0,"NOMEGA":0,"NOMEGAR":0,"NBANDSGW":-1,"NBANDSO":-1,"NBANDSV":-1,"NELMGW":1,"NELMHF":1,"DIM":3,"IESPILON":4,"ANTIRES":0,"OMEGAMIN":-30.0,"OMEGATL":-200.0,"OMEGAGRID":0,"LSELFENERGY":false,"LSPECTRAL":false,"LSPECTRALGW":false,"LSINGLES":false,"LFERMIGW":false,"ODDONLYGW":false,"EVENONLYGW":false,"NKREDLFX":1,"NKREDLFY":1,"NKREDLFZ":1,"MAXMEM":2800,"TELESCOPE":0,"NTAUPAR":-1,"NOMEGAPAR":-1,"DAMP_NEWTON":0.80000001,"LAMBDA":1.0,"OFIELD_KAPPA":0.0,"OFIELD_K":[0.0,0.0,0.0],"OFIELD_Q6_NEAR":0.0,"OFIELD_Q6_FAR":0.0,"OFIELD_A":0.0,"KPOINTS_OPT_MODE":1,"LKPOINTS_OPT":false},"lattice_rec":{"@module":"pymatgen.core.lattice","@class":"Lattice","matrix":[[-1.150766539776481,1.150766539776481,1.150766539776481],[1.150766539776481,-1.150766539776481,1.150766539776481],[1.150766539776481,1.150766539776481,-1.1507665397764812]],"pbc":[true,true,true]},"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[0.0,2.73,2.73],[2.73,0.0,2.73],[2.73,2.73,0.0]],"pbc":[true,true,true],"a":3.8608030252785492,"b":3.8608030252785492,"c":3.8608030252785492,"alpha":59.99999999999999,"beta":59.99999999999999,"gamma":59.99999999999999,"volume":40.692834},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[0.0,0.0,0.0],"xyz":[0.0,0.0,0.0],"properties":{},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.365,1.365,1.365],"properties":{},"label":"Si"}]},"is_hubbard":false,"hubbards":{}},"output":{"energy":-11.48288783,"energy_per_atom":-5.741443915,"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[-0.0,2.7181064862403606,2.7181064862403606],[2.7181064862403606,0.0,2.7181064862403606],[2.7181064862403606,2.7181064862403606,0.0]],"pbc":[true,true,true],"a":3.8439830568153965,"b":3.8439830568153965,"c":3.8439830568153965,"alpha":60.00000000000001,"beta":60.00000000000001,"gamma":60.00000000000001,"volume":40.163300666862035},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[-0.0,-0.0,-0.0],"xyz":[0.0,0.0,0.0],"properties":{"magmom":-0.0},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.3590532431201803,1.3590532431201803,1.3590532431201803],"properties":{"magmom":-0.0},"label":"Si"}]},"efermi":5.96853235,"is_metal":false,"bandgap":0.45999999999999996,"cbm":6.2225,"vbm":5.7625,"is_gap_direct":false,"direct_gap":2.5146000000000006,"transition":"(0.000,0.000,0.000)-(0.429,0.429,-0.000)","mag_density":-1.2698159551931228e-7,"epsilon_static":null,"epsilon_static_wolfe":null,"epsilon_ionic":null,"frequency_dependent_dielectric":{"real":null,"imaginary":null,"energy":null},"ionic_steps":[{"e_fr_energy":-11.48123683,"e_wo_entrp":-11.48059295,"e_0_energy":-11.48091489,"forces":[[-0.0,-0.0,-0.0],[0.0,0.0,0.0]],"stress":[[-11.94991105,-0.0,0.0],[-0.0,-11.94991105,-0.0],[0.0,0.0,-11.94991105]],"electronic_steps":[{"alphaZ":3.30899841,"ewald":-227.30768138,"hartreedc":-11.25054504,"XCdc":-17.44029463,"pawpsdc":174.89845602,"pawaedc":-140.31916047,"eentropy":-0.00576862,"bandstr":7.4477054,"atom":205.15160006,"e_fr_energy":-5.51669025,"e_wo_entrp":-5.51092163,"e_0_energy":-5.51380594},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.5030273,"e_wo_entrp":-11.50196668,"e_0_energy":-11.50249699},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.50956333,"e_wo_entrp":-11.50850279,"e_0_energy":-11.50903306},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.50956706,"e_wo_entrp":-11.50850652,"e_0_energy":-11.50903679},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.50956706,"e_wo_entrp":-11.50850652,"e_0_energy":-11.50903679},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.53611896,"e_wo_entrp":-11.53582946,"e_0_energy":-11.53597421},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.45975595,"e_wo_entrp":-11.45885776,"e_0_energy":-11.45930686},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48088697,"e_wo_entrp":-11.48018417,"e_0_energy":-11.48053557},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48108984,"e_wo_entrp":-11.48040567,"e_0_energy":-11.48074775},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48120487,"e_wo_entrp":-11.48055795,"e_0_energy":-11.48088141},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48124463,"e_wo_entrp":-11.48060003,"e_0_energy":-11.48092233},{"alphaZ":3.30899841,"ewald":-227.30768138,"hartreedc":-14.82023784,"XCdc":-16.9157322,"pawpsdc":843.38594458,"pawaedc":-809.01255792,"eentropy":-0.00064389,"bandstr":4.72907334,"atom":205.15160006,"e_fr_energy":-11.48123683,"e_wo_entrp":-11.48059295,"e_0_energy":-11.48091489}],"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[0.0,2.73,2.73],[2.73,0.0,2.73],[2.73,2.73,0.0]],"pbc":[true,true,true],"a":3.8608030252785492,"b":3.8608030252785492,"c":3.8608030252785492,"alpha":59.99999999999999,"beta":59.99999999999999,"gamma":59.99999999999999,"volume":40.692834},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[0.0,0.0,0.0],"xyz":[0.0,0.0,0.0],"properties":{},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.365,1.365,1.365],"properties":{},"label":"Si"}]}},{"e_fr_energy":-11.48232167,"e_wo_entrp":-11.48151129,"e_0_energy":-11.48191648,"forces":[[-0.0,0.0,-0.0],[0.0,-0.0,0.0]],"stress":[[8.312558,0.0,0.0],[0.0,8.312558,0.0],[0.0,-0.0,8.312558]],"electronic_steps":[{"alphaZ":3.38275168,"ewald":-228.98408474,"hartreedc":-14.93040698,"XCdc":-16.81647568,"pawpsdc":840.23106792,"pawaedc":-805.85763374,"eentropy":-0.00099223,"bandstr":6.33884318,"atom":205.15160006,"e_fr_energy":-11.48533053,"e_wo_entrp":-11.4843383,"e_0_energy":-11.48483442},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48327646,"e_wo_entrp":-11.48237268,"e_0_energy":-11.48282457},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48232378,"e_wo_entrp":-11.48151821,"e_0_energy":-11.481921},{"alphaZ":3.38275168,"ewald":-228.98408474,"hartreedc":-14.56699686,"XCdc":-16.8223405,"pawpsdc":886.45497495,"pawaedc":-852.09684853,"eentropy":-0.00081037,"bandstr":5.99943265,"atom":205.15160006,"e_fr_energy":-11.48232167,"e_wo_entrp":-11.48151129,"e_0_energy":-11.48191648}],"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[-0.0,2.71001354,2.71001354],[2.71001354,0.0,2.71001354],[2.71001354,2.71001354,0.0]],"pbc":[true,true,true],"a":3.8325379024827217,"b":3.8325379024827217,"c":3.8325379024827217,"alpha":59.99999999999999,"beta":59.99999999999999,"gamma":59.99999999999999,"volume":39.80561863766497},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[-0.0,-0.0,-0.0],"xyz":[0.0,0.0,0.0],"properties":{},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.35500677,1.35500677,1.35500677],"properties":{},"label":"Si"}]}},{"e_fr_energy":-11.48325744,"e_wo_entrp":-11.48251822,"e_0_energy":-11.48288783,"forces":[[0.0,0.0,0.0],[-0.0,-0.0,-0.0]],"stress":[[0.04088458,0.0,-0.0],[0.0,0.04088458,0.0],[0.0,-0.0,0.04088458]],"electronic_steps":[{"alphaZ":3.35262593,"ewald":-228.30230284,"hartreedc":-14.52175313,"XCdc":-16.86205909,"pawpsdc":881.66215819,"pawaedc":-847.30559099,"eentropy":-0.00067543,"bandstr":5.34224671,"atom":205.15160006,"e_fr_energy":-11.4837506,"e_wo_entrp":-11.48307517,"e_0_energy":-11.48341288},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48341833,"e_wo_entrp":-11.48271382,"e_0_energy":-11.48306607},{"alphaZ":null,"ewald":null,"hartreedc":null,"XCdc":null,"pawpsdc":null,"pawaedc":null,"eentropy":null,"bandstr":null,"atom":null,"e_fr_energy":-11.48325844,"e_wo_entrp":-11.4825187,"e_0_energy":-11.48288857},{"alphaZ":3.35262593,"ewald":-228.30230284,"hartreedc":-14.66693957,"XCdc":-16.85933152,"pawpsdc":859.83950703,"pawaedc":-825.47718253,"eentropy":-0.00073922,"bandstr":5.47950522,"atom":205.15160006,"e_fr_energy":-11.48325744,"e_wo_entrp":-11.48251822,"e_0_energy":-11.48288783}],"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[-0.0,2.71810649,2.71810649],[2.71810649,0.0,2.71810649],[2.71810649,2.71810649,0.0]],"pbc":[true,true,true],"a":3.843983062132329,"b":3.843983062132329,"c":3.843983062132329,"alpha":59.99999999999999,"beta":59.99999999999999,"gamma":59.99999999999999,"volume":40.163300833521646},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[-0.0,-0.0,-0.0],"xyz":[0.0,0.0,0.0],"properties":{},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.359053245,1.359053245,1.359053245],"properties":{},"label":"Si"}]}}],"locpot":null,"outcar":{"@module":"pymatgen.io.vasp.outputs","@class":"Outcar","efermi":5.9685,"magnetization":[{"s":-0.0,"p":0.0,"d":0.0,"tot":-0.0},{"s":-0.0,"p":0.0,"d":0.0,"tot":-0.0}],"charge":[{"s":0.751,"p":0.938,"d":0.0,"tot":1.689},{"s":0.751,"p":0.938,"d":0.0,"tot":1.689}],"total_magnetization":-5.1e-6,"nelect":8.0,"is_stopped":false,"drift":[[0.0,0.0,-0.0],[0.0,0.0,-0.0],[0.0,0.0,-0.0]],"ngf":[72,72,72],"sampling_radii":[0.9892],"electrostatic_potential":[-83.0676,-83.0676]},"force_constants":null,"normalmode_frequencies":null,"normalmode_eigenvals":null,"normalmode_eigenvecs":null,"elph_displaced_structures":{"temperatures":null,"structures":null},"dos_properties":{"Si":{"s":{"filling":0.4427601717036412,"center":6.0420383388504755,"bandwidth":15.846281139043978,"skewness":0.7981832261655295,"kurtosis":2.486314542519376,"upper_edge":-6.39203235},"p":{"filling":0.2091359960478043,"center":14.073327227948507,"bandwidth":13.877364959477802,"skewness":0.4111522709467528,"kurtosis":2.1841902117142857,"upper_edge":6.713967649999999}}},"run_stats":{"average_memory":0.0,"max_memory":241584.0,"elapsed_time":18.833,"system_time":1.114,"user_time":16.166,"total_time":17.28,"cores":40}},"completed_at":"2024-05-19 17:13:34.897366","task_name":"standard","output_file_paths":{"chgcar":"CHGCAR","aeccar0":"AECCAR0","aeccar1":"AECCAR1","aeccar2":"AECCAR2"},"bader":null,"ddec6":null,"run_type":"PBESol","task_type":"Structure Optimization","calc_type":"PBESol Structure Optimization"}],"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[-0.0,2.7181064862403606,2.7181064862403606],[2.7181064862403606,0.0,2.7181064862403606],[2.7181064862403606,2.7181064862403606,0.0]],"pbc":[true,true,true],"a":3.8439830568153965,"b":3.8439830568153965,"c":3.8439830568153965,"alpha":60.00000000000001,"beta":60.00000000000001,"gamma":60.00000000000001,"volume":40.163300666862035},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[-0.0,-0.0,-0.0],"xyz":[0.0,0.0,0.0],"properties":{"magmom":-0.0},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.3590532431201803,1.3590532431201803,1.3590532431201803],"properties":{"magmom":-0.0},"label":"Si"}]},"task_type":"Structure Optimization","task_id":null,"orig_inputs":{"incar":{"ALGO":"Fast","EDIFF":0.00001,"EDIFFG":-0.02,"ENAUG":1360,"ENCUT":680,"GGA":"Ps","IBRION":2,"ISIF":3,"ISMEAR":0,"ISPIN":2,"LAECHG":true,"LASPH":true,"LCHARG":false,"LELF":false,"LMIXTAU":true,"LORBIT":11,"LREAL":false,"LVTOT":false,"LWAVE":false,"MAGMOM":[0.6,0.6],"NELM":200,"NSW":99,"PREC":"Accurate","SIGMA":0.2},"poscar":{"@module":"pymatgen.io.vasp.inputs","@class":"Poscar","structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0,"lattice":{"matrix":[[0.0,2.73,2.73],[2.73,0.0,2.73],[2.73,2.73,0.0]],"pbc":[true,true,true],"a":3.8608030252785492,"b":3.8608030252785492,"c":3.8608030252785492,"alpha":59.99999999999999,"beta":59.99999999999999,"gamma":59.99999999999999,"volume":40.692834},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[0.0,0.0,0.0],"xyz":[0.0,0.0,0.0],"properties":{},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.365,1.365,1.365],"properties":{},"label":"Si"}]},"true_names":true,"selective_dynamics":null,"velocities":null,"predictor_corrector":null,"comment":"Si2"},"kpoints":{"comment":"Automatic kpoint scheme","nkpoints":0,"generation_style":"Gamma","kpoints":[[7,7,7]],"usershift":[0,0,0],"kpts_weights":null,"coord_type":null,"labels":null,"tet_number":0,"tet_weight":0,"tet_connections":null,"@module":"pymatgen.io.vasp.inputs","@class":"Kpoints"},"potcar":[{"titel":"Si","hash":"c27340a9c98542122fbad458bbb5d441","summary_stats":{"keywords":{"header":["dexc","eatom","eaug","enmax","enmin","icore","iunscr","lcor","lexch","lpaw","lultra","ndata","orbitaldescriptions","orbitals","pomass","raug","rcore","rdep","rdept","rmax","rpacor","rrkj","rwigs","step","titel","vrhfin","zval","nentries"],"data":["localpart","gradientcorrectionsusedforxc","corecharge-density(partial)","kineticenergydensity(partial)","atomicpseudocharge-density","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","pawradialsets","(5e20.12)","augmentationcharges(nonsperical)","uccopanciesinatom","grid","aepotential","corecharge-density","kineticenergy-density","mkineticenergy-densitypseudized","localpseudopotentialcore","pspotentialvalenceonly","corecharge-density(pseudized)","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","endofdataset"]},"stats":{"header":{"MEAN":9.198469218699186,"ABSMEAN":9.198469218699186,"VAR":1790.7147656424072,"MIN":0.0,"MAX":322.069},"data":{"MEAN":215.16613596661992,"ABSMEAN":237.9507629282115,"VAR":3381771.445249609,"MIN":-872.57185,"MAX":24929.6947974}}}}]},"input":{"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[0.0,2.73,2.73],[2.73,0.0,2.73],[2.73,2.73,0.0]],"pbc":[true,true,true],"a":3.8608030252785492,"b":3.8608030252785492,"c":3.8608030252785492,"alpha":59.99999999999999,"beta":59.99999999999999,"gamma":59.99999999999999,"volume":40.692834},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[0.0,0.0,0.0],"xyz":[0.0,0.0,0.0],"properties":{},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.365,1.365,1.365],"properties":{},"label":"Si"}]},"parameters":{"SYSTEM":"unknown system","LCOMPAT":false,"PREC":"accura","ENMAX":680.0,"ENAUG":1360.0,"EDIFF":0.00001,"IALGO":68,"IWAVPR":11,"NBANDS":40,"NBANDSLOW":-1,"NBANDSHIGH":-1,"NELECT":8.0,"TURBO":0,"IRESTART":0,"NREBOOT":0,"NMIN":0,"EREF":0.0,"ISMEAR":0,"SIGMA":0.2,"KSPACING":0.5,"KGAMMA":true,"KBLOWUP":true,"LREAL":false,"ROPT":[0.0],"LMAXPAW":-100,"LMAXMIX":2,"NLSPLINE":false,"ISTART":0,"ICHARG":2,"INIWAV":1,"ISPIN":2,"LNONCOLLINEAR":false,"MAGMOM":[0.6,0.6],"NUPDOWN":-1.0,"LSORBIT":false,"SAXIS":[0.0,0.0,1.0],"LSPIRAL":false,"QSPIRAL":[0.0,0.0,0.0],"LZEROZ":false,"LASPH":true,"LMETAGGA":false,"NELM":200,"NELMDL":-5,"NELMIN":2,"ENINI":680.0,"LDIAG":true,"LSUBROT":false,"WEIMIN":0.001,"EBREAK":6e-8,"DEPER":0.3,"NRMM":4,"TIME":0.4,"AMIX":0.4,"BMIX":1.0,"AMIN":0.1,"AMIX_MAG":1.6,"BMIX_MAG":1.0,"IMIX":4,"MIXFIRST":false,"MAXMIX":-45,"WC":100.0,"INIMIX":1,"MIXPRE":1,"MREMOVE":5,"LDIPOL":false,"LMONO":false,"IDIPOL":0,"EPSILON":1.0,"DIPOL":[-100.0,-100.0,-100.0],"EFIELD":0.0,"NGX":36,"NGY":36,"NGZ":36,"NGXF":72,"NGYF":72,"NGZF":72,"ADDGRID":false,"NSW":99,"IBRION":2,"MDALGO":0,"ISIF":3,"PSTRESS":0.0,"EDIFFG":-0.02,"NFREE":1,"POTIM":0.5,"SMASS":-3.0,"SCALEE":1.0,"TEBEG":0.0001,"TEEND":0.0001,"NBLOCK":1,"KBLOCK":99,"NPACO":256,"APACO":10.0,"ISYM":2,"SYMPREC":0.00001,"LORBIT":11,"RWIGS":[-1.0],"NEDOS":301,"EMIN":10.0,"EMAX":-10.0,"EFERMI":0.0,"NWRITE":2,"LWAVE":false,"LDOWNSAMPLE":false,"LCHARG":false,"LPARD":false,"LVTOT":false,"LVHAR":false,"LELF":false,"LOPTICS":false,"STM":[0.0,0.0,0.0,0.0,0.0,0.0,0.0],"NPAR":40,"NSIM":4,"NBLK":-1,"LPLANE":true,"LSCALAPACK":true,"LSCAAWARE":false,"LSCALU":false,"LASYNC":false,"LORBITALREAL":false,"IDIOT":3,"PHON_NSTRUCT":-1,"LMUSIC":false,"POMASS":[28.085],"DARWINR":[0.0],"DARWINV":[1.0],"LCORR":true,"GGA_COMPAT":true,"LBERRY":false,"ICORELEVEL":0,"LDAU":false,"I_CONSTRAINED_M":0,"GGA":"PS","VOSKOWN":0,"LHFCALC":false,"PRECFOCK":"","LSYMGRAD":false,"LHFONE":false,"LRHFCALC":false,"LTHOMAS":false,"LMODELHF":false,"LFOCKACE":false,"ENCUT4O":-1.0,"EXXOEP":0,"FOURORBIT":0,"AEXX":0.0,"HFALPHA":0.0,"MCALPHA":0.0,"ALDAX":1.0,"AGGAX":1.0,"ALDAC":1.0,"AGGAC":1.0,"NKREDX":1,"NKREDY":1,"NKREDZ":1,"SHIFTRED":false,"ODDONLY":false,"EVENONLY":false,"LMAXFOCK":0,"NMAXFOCKAE":0,"LFOCKAEDFT":false,"HFSCREEN":0.0,"HFSCREENC":0.0,"NBANDSGWLOW":0,"LUSE_VDW":false,"IVDW_NL":1,"LSPIN_VDW":false,"Zab_VDW":-0.8491,"PARAM1":0.1234,"PARAM2":1.0,"PARAM3":0.0,"MODEL_GW":0,"MODEL_EPS0":12.2078502,"MODEL_ALPHA":1.0,"LEPSILON":false,"LRPA":false,"LNABLA":false,"LVEL":false,"CSHIFT":0.1,"OMEGAMAX":-1.0,"DEG_THRESHOLD":0.002,"RTIME":-0.1,"WPLASMAI":0.0,"DFIELD":[0.0,0.0,0.0],"WPLASMA":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],"NUCIND":false,"MAGPOS":[0.0,0.0,0.0],"LNICSALL":true,"ORBITALMAG":false,"LMAGBLOCH":false,"LCHIMAG":false,"LGAUGE":true,"MAGATOM":0,"MAGDIPOL":[0.0,0.0,0.0],"AVECCONST":[0.0,0.0,0.0],"LALL_IN_ONE":false,"IALL_IN_ONE":-1,"NBANDS_WAVE":-1,"LFINITE_TEMPERATURE":false,"LADDER":false,"LRPAFORCE":false,"LFXC":false,"LHARTREE":true,"IBSE":0,"KPOINT":[-1,0,0,0],"LTCTC":false,"LTCTE":false,"LTETE":false,"LTRIPLET":false,"LFXCEPS":false,"LFXHEG":false,"NATURALO":2,"LHOLEGF":false,"L2ORDER":false,"LDMP1":false,"LMP2LT":false,"LSMP2LT":false,"LGWLF":false,"ENCUTGW":-1.60000002,"ENCUTGWSOFT":-1.60000002,"ENCUTLF":-1.0,"LESF_SPLINES":false,"LMAXMP2":-1,"SCISSOR":0.0,"NOMEGA":0,"NOMEGAR":0,"NBANDSGW":-1,"NBANDSO":-1,"NBANDSV":-1,"NELMGW":1,"NELMHF":1,"DIM":3,"IESPILON":4,"ANTIRES":0,"OMEGAMIN":-30.0,"OMEGATL":-200.0,"OMEGAGRID":0,"LSELFENERGY":false,"LSPECTRAL":false,"LSPECTRALGW":false,"LSINGLES":false,"LFERMIGW":false,"ODDONLYGW":false,"EVENONLYGW":false,"NKREDLFX":1,"NKREDLFY":1,"NKREDLFZ":1,"MAXMEM":2800,"TELESCOPE":0,"NTAUPAR":-1,"NOMEGAPAR":-1,"DAMP_NEWTON":0.80000001,"LAMBDA":1.0,"OFIELD_KAPPA":0.0,"OFIELD_K":[0.0,0.0,0.0],"OFIELD_Q6_NEAR":0.0,"OFIELD_Q6_FAR":0.0,"OFIELD_A":0.0,"KPOINTS_OPT_MODE":1,"LKPOINTS_OPT":false},"pseudo_potentials":{"pot_type":"PAW","functional":"P_B_E","symbols":["PAW_PBE"]},"potcar_spec":[{"titel":"PAW_PBE Si 05Jan2001","hash":"c27340a9c98542122fbad458bbb5d441","summary_stats":{"keywords":{"header":["dexc","eatom","eaug","enmax","enmin","icore","iunscr","lcor","lexch","lpaw","lultra","ndata","orbitaldescriptions","orbitals","pomass","raug","rcore","rdep","rdept","rmax","rpacor","rrkj","rwigs","step","titel","vrhfin","zval","nentries"],"data":["localpart","gradientcorrectionsusedforxc","corecharge-density(partial)","kineticenergydensity(partial)","atomicpseudocharge-density","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","pawradialsets","(5e20.12)","augmentationcharges(nonsperical)","uccopanciesinatom","grid","aepotential","corecharge-density","kineticenergy-density","mkineticenergy-densitypseudized","localpseudopotentialcore","pspotentialvalenceonly","corecharge-density(pseudized)","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","endofdataset"]},"stats":{"header":{"MEAN":9.198469218699186,"ABSMEAN":9.198469218699186,"VAR":1790.7147656424072,"MIN":0.0,"MAX":322.069},"data":{"MEAN":215.16613596661992,"ABSMEAN":237.9507629282115,"VAR":3381771.445249609,"MIN":-872.57185,"MAX":24929.6947974}}}}],"xc_override":"PS","is_lasph":true,"is_hubbard":false,"hubbards":{},"magnetic_moments":[0.6,0.6]},"output":{"structure":{"@module":"pymatgen.core.structure","@class":"Structure","charge":0.0,"lattice":{"matrix":[[-0.0,2.7181064862403606,2.7181064862403606],[2.7181064862403606,0.0,2.7181064862403606],[2.7181064862403606,2.7181064862403606,0.0]],"pbc":[true,true,true],"a":3.8439830568153965,"b":3.8439830568153965,"c":3.8439830568153965,"alpha":60.00000000000001,"beta":60.00000000000001,"gamma":60.00000000000001,"volume":40.163300666862035},"properties":{},"sites":[{"species":[{"element":"Si","occu":1}],"abc":[-0.0,-0.0,-0.0],"xyz":[0.0,0.0,0.0],"properties":{"magmom":-0.0},"label":"Si"},{"species":[{"element":"Si","occu":1}],"abc":[0.25,0.25,0.25],"xyz":[1.3590532431201803,1.3590532431201803,1.3590532431201803],"properties":{"magmom":-0.0},"label":"Si"}]},"density":2.3223723738160613,"energy":-11.48288783,"forces":[[0.0,0.0,0.0],[-0.0,-0.0,-0.0]],"stress":[[0.04088458,0.0,-0.0],[0.0,0.04088458,0.0],[0.0,-0.0,0.04088458]],"energy_per_atom":-5.741443915,"bandgap":0.45999999999999996},"included_objects":null,"vasp_objects":{},"entry":{"@module":"pymatgen.entries.computed_entries","@class":"ComputedEntry","energy":-11.48288783,"composition":{"Si":2.0},"entry_id":null,"correction":0.0,"energy_adjustments":[],"parameters":{"potcar_spec":[{"titel":"PAW_PBE Si 05Jan2001","hash":"c27340a9c98542122fbad458bbb5d441","summary_stats":{"keywords":{"header":["dexc","eatom","eaug","enmax","enmin","icore","iunscr","lcor","lexch","lpaw","lultra","ndata","orbitaldescriptions","orbitals","pomass","raug","rcore","rdep","rdept","rmax","rpacor","rrkj","rwigs","step","titel","vrhfin","zval","nentries"],"data":["localpart","gradientcorrectionsusedforxc","corecharge-density(partial)","kineticenergydensity(partial)","atomicpseudocharge-density","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","nonlocalpart","reciprocalspacepart","realspacepart","reciprocalspacepart","realspacepart","pawradialsets","(5e20.12)","augmentationcharges(nonsperical)","uccopanciesinatom","grid","aepotential","corecharge-density","kineticenergy-density","mkineticenergy-densitypseudized","localpseudopotentialcore","pspotentialvalenceonly","corecharge-density(pseudized)","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","pseudowavefunction","aewavefunction","endofdataset"]},"stats":{"header":{"MEAN":9.198469218699186,"ABSMEAN":9.198469218699186,"VAR":1790.7147656424072,"MIN":0.0,"MAX":322.069},"data":{"MEAN":215.16613596661992,"ABSMEAN":237.9507629282115,"VAR":3381771.445249609,"MIN":-872.57185,"MAX":24929.6947974}}}}],"run_type":"PBESol","is_hubbard":false,"hubbards":{}},"data":{"oxide_type":"None","aspherical":true,"last_updated":"2024-05-19 21:13:45.541962"}},"task_label":"relax","author":null,"icsd_id":null,"transformations":{},"additional_json":{},"custodian":[{"corrections":[],"job":{"@module":"custodian.vasp.jobs","@class":"VaspJob","@version":"2024.4.18","vasp_cmd":["srun","/scratch/gpfs/ab6989/MPScanRelaxSet/atomate2/vasp_std"],"output_file":"vasp.out","stderr_file":"std_err.txt","suffix":"","final":true,"backup":true,"auto_npar":false,"auto_gamma":true,"settings_override":null,"gamma_vasp_cmd":["vasp_gam"],"copy_magmom":false,"auto_continue":false}}],"analysis":{"delta_volume":-0.5295333331379624,"delta_volume_percent":-1.3012938178205096,"max_force":0.0,"warnings":[],"errors":[]},"last_updated":null,"include_structure":true,"completed_at":"2024-05-19 17:13:34.897366","run_stats":{"standard":{"average_memory":0.0,"max_memory":241584.0,"elapsed_time":18.833,"system_time":1.114,"user_time":16.166,"total_time":17.28,"cores":40},"overall":{"average_memory":0.0,"max_memory":241584.0,"elapsed_time":18.833,"system_time":1.114,"user_time":16.166,"total_time":17.28,"cores":40}},"@module":"emmet.core.tasks","@class":"TaskDoc","@version":null},"completed_at":"2024-05-19T17:13:46.400349","metadata":{},"hosts":["dbaebabf-134d-426a-b91c-15abf799da65"],"name":"relax","@module":"jobflow.core.schemas","@class":"JobStoreDocument","@version":"0.1.17"}] diff --git a/docs/_static/example_flow.png b/docs/_static/example_flow.png new file mode 100644 index 0000000000..4b1ec0f76b Binary files /dev/null and b/docs/_static/example_flow.png differ diff --git a/docs/index.md b/docs/index.md index 32f20ccbb8..a8a0382698 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,6 +4,7 @@ user/index user/install user/running-workflows +user/docs-schemas-emmet user/fireworks user/atomate-1-vs-2 user/codes/index diff --git a/docs/user/docs_schemas_emmet.md b/docs/user/docs_schemas_emmet.md new file mode 100644 index 0000000000..70004263b7 --- /dev/null +++ b/docs/user/docs_schemas_emmet.md @@ -0,0 +1,506 @@ +(docs_schemas_emmet)= + +# An introduction to task documents, schemas, and emmet + +## Introduction + +If you have been [running-workflows](running_workflows), you are now starting +to generate data. `atomate2` stores both input and output data for every step of +its workflows in Task Documents. Task Documents define a *schema* or structure for +organizing information from different types of calculations, which then facilitates +automatic processing with tools like `emmet` or `maggma`. This tutorial will familiarize you with +these basic concepts. + +### Objectives + +* Understand how `atomate2` stores and organizes calculation data +* Explain the meaning of a "Document Model" or schema +* Inspect a `TaskDoc` generated by `atomate2` + +### Prerequisites + +To complete this tutorial, you need + +* A working installation of `atomate2` +* (optional) to complete the [running workflows](running-workflows.md) tutorial. + +## How `atomate2` stores and organizes data. + +As explained in [Configure calculation output database](install.md#configure-calculation-output-database), `atomate2` +stores the results of every `Job` in a database. More specifically, `atomate2` uses a +[`maggma.Store`](https://materialsproject.github.io/maggma/getting_started/stores/) to interface with a data storage backend +(usually MongoDB). Data is stored in a `JSON`-like or python `dict`-like format, which you can think of as a list of +dictionaries, where each dictionary represents one `Job`. Each dictionary in the list is called a "document", +so "document" refers to the output data from a single `Job `. + +To facilitate automated processing and analysis, it's important that every document follows a +consistent format. That's where schemas (also called "Document Models") come in. + +## Document Models + +### Schema for `Job` + +Document models define a specific format (i.e., structure and data types) for a given `Job` or calculation. +`atomate2` uses [pydantic](https://docs.pydantic.dev/latest/) to define these schemas. If you'd like +to learn more about `pydantic`, we suggest reading [this introduction]( +https://realpython.com/python-pydantic/#getting-familiar-with-pydantic). In brief, every Document Model in `atomate2` +is an instance of `pydantic.BaseModel`. The `BaseModel` is then turned into a `dict` (serialized) before being +inserted into the store. + +To understand how this works, we are going to look at the output data from a structural relaxation for Si. If we +examine the `docs` store after running this `Job`, we will see something similar to the following: + +```json +[ + {"uuid":"c2b5eb7d-838b-4dee-896f-95f21867b62b", + "index":1, + "output":{...}, + "completed_at":"2024-05-19T17:13:46.400349", + "metadata":{}, + "hosts":["dbaebabf-134d-426a-b91c-15abf799da65"], + "name":"relax", + "@module":"jobflow.core.schemas", + "@class":"JobStoreDocument", + "@version":"0.1.17" + }, +] +``` + + +This document follows a schema (`JobStoreDocument`, defined [here](https://github.com/materialsproject/jobflow/blob/main/src/jobflow/core/schemas.py)) +that contains information about the `Job`, such as: + - `uuid`: a unique identifier for the `Job` + - `output`: The actual job output (e.g., calculation results). We'll examine this in the next section. + - `completed_at`: The time the job was completed. + - `name`: The name of the job (in this case "relax" because we did a structure relaxation) + - `@module`, `@class`, `@version`: These keys store the specific origin and version of the document model so that it can + be easily re-created from the `dict`. + +Because every `atomate2` document is first created as a `JobStoreDocument` before being inserted into the database, +you can be assured that every `Job` you run will contain these keys. Document Models have the additional benefit +of validating the data types, so for example, `name` is guaranteed to a `str`, whereas `index` is guaranteed to be a `int`. + +```{warning} +In this tutorial, we show only **excerpts** of the output data to highlight key points. For example, +in the box above we have collapsed the `outputs` key. You are encouraged to open the +[complete output data (`.json` format)](../_static/docs_store_Si_relax.json) in a separate tab of your web browser +and refer to it as you read through this tutorial. +``` + +### Schema for `output` + +The output data for the calculation itself (the contents of the `Job`) are stored in the `output` key. **The schema +of `output` will vary depending on the type of calculation (e.g., VASP relaxation, Q-Chem static, etc.), but will +always be consistent for a particular `Job` type**. In the case of a VASP calculation, the schema is called +a `TaskDoc`. + +That being said, most `Job` types have a few features in common, which we will highlight in our example. If we look +at the top-level keys of `output` from the `JobStoreDocument` in the previous section, we see: + +```json +{ + "builder_meta": {...} + "nsites": 2, + "elements": ["Si"], + "nelements": 1, + "composition": {"Si": 2}, + "composition_reduced": {"Si": 1}, + "formula_pretty": "Si", + "formula_anonymous": "A", + "chemsys": "Si", + "volume": 40.163300666862035, + "density": 2.3223723738160613, + "density_atomic": 20.081650333431018, + "symmetry": {...}, + "tags": null, + "dir_name": "/scratch/gpfs/.../job_2024-05-19-21-13-15-058677-64911", + "state": "successful", + "calcs_reversed": [...], + "structure": {...}, + "task_type": "Structure Optimization", + "task_id": null, + "orig_inputs": {...}, + "input": {...}, + "output": {...}, + "@module": "emmet.core.tasks", + "@class": "TaskDoc", + "@version": null +} +``` + +Even though we are looking at an example for a VASP calculations, **`atomate2` uses hierarchical or modular Document +Models wherever possible**. Therefore, the Task Documents generated for other calculation types have the same +general structure (e.g., `inputs`, `outputs`, structure metadata, `custodian`, `orig_inputs`, `calcs_reversed`, etc.) + +We describe many of these top-level keys in more detail in the following subsections. + +```{note} +You can also generate `TaskDoc` from VASP calculations that you have run manually. To do + so, use the `from_directory` class method: + ```python + from emmet.core.tasks import TaskDoc + doc = TaskDoc.from_directory("") +``` + +#### Structure Metadata + +The root level of the `TaskDoc` has keys containing basic structural information including: + - `nsites`: The number of sites + - `composition`: Full composition for the material. + - `elements`: List of elements in the material. + - `formula_pretty`: Cleaned representation of the formula. + - `chemsys`: dash-delimited string of elements in the material. + +And more. These keys illustrate another principle of Document Models -- they are +**hierarchical**. Specifically, the structure metadata keys are populated by _another_ `pydantic` schema called +[StructureMetadata](https://github.com/materialsproject/emmet/blob/efc0b22ff835b11b1c825cbc93d4bbebf84a0d91/emmet-core/emmet/core/structure.py#L18) +defined in `emmet`. So the `TaskDoc` schema comprises several subsidiary models that organize different types of +information, as discussed further below. + +#### `structure` + +The `structure` key contains the **final output structure** of the calculation as a serialized `pymatgen.Structure` object. + +```json +"structure": { + "@module": "pymatgen.core.structure", + "@class": "Structure", + "charge": 0, + "lattice": {...}, + "properties": {}, + "sites": [...] + } +``` + +#### `builder_meta` + +The `builder_meta` key contains information about the software used to generate the data in the `TaskDoc`. Here is the +example from our structure relaxation: + +```json +"builder_meta": { + "emmet_version": "0.83.0", + "pymatgen_version": "2024.4.13", + "pull_request": null, + "database_version": null, + "build_date": "2024-05-19T21:13:45.541000", + "license": null + } +``` + +#### Calculation metadata: `dir_name`, `run_stats`, `task_label`, and `task_type` + +- `task_label`: A user-definable label for the specific calculation +- `task_type`: A standardized label specifying the specific type of calculation being performed. +- `dir_name`: The path of the directory in which input/output files were written +- `run_stats`: Information about the walltime, cpu time, and computational resources utilized. + +```json +"task_type": "Structure Optimization", +"task_label": "relax", +"dir_name": "della-r3c1n3:/scratch/gpfs/ab6989/MPScanRelaxSet/atomate2/Ca_Mg_runs/job_2024-05-19-21-13-15-058677-64911", +"run_stats": { + "average_memory": 0, + "max_memory": 241584, + "elapsed_time": 18.833, + "system_time": 1.114, + "user_time": 16.166, + "total_time": 17.28, + "cores": 40 + } +``` + +#### Calculation Inputs + +`atomate2` stores a record of not just the outputs of a calculation, but also the inputs, and any modifications that +were made to those inputs. + +The `input` key contains the **summarized final input data for the calculation**. It's schema is defined by +[InputDoc](https://github.com/materialsproject/emmet/blob/efc0b22ff835b11b1c825cbc93d4bbebf84a0d91/emmet-core/emmet/core/tasks.py#L175) +and includes everything one needs to specify a VASP calculation: a `Structure` object, INCAR settings, +Pseudopotential specifications, etc. Let's just look at the top-level keys of our `input` section: + +```json +"input": { + "structure": {...}, + "parameters": {...}, + "pseudo_potentials": {...}, + "potcar_spec": [ ... ], + "xc_override": "PS", + "is_lasph": true, + "is_hubbard": false, + "hubbards": {}, + "magnetic_moments": [ + 0.6, + 0.6 + ] + }, +``` + +#### Calculation Outputs + +Much like `input`, the `output` key is populated by a nested schema called [`OutputDoc`](https://github.com/materialsproject/emmet/blob/efc0b22ff835b11b1c825cbc93d4bbebf84a0d91/emmet-core/emmet/core/tasks.py#L97). +`OutputDoc` captures key summary information about the final result of a VASP calculation, including the `Structure`, final energy, `energy_per_atom`, and `bandgap`. In our example: + +```json +"output": { + "structure": {...}, + "density": 2.3223723738160613, + "energy": -11.48288783, + "forces": [ + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ] + ], + "stress": [ + [ + 0.04088458, + 0, + 0 + ], + [ + 0, + 0.04088458, + 0 + ], + [ + 0, + 0, + 0.04088458 + ] + ], + "energy_per_atom": -5.741443915, + "bandgap": 0.45999999999999996 + }, + +``` + + + + +#### `custodian` and `orig_inputs` + +There is also a key called `orig_inputs` that contains the **original inputs given by the user** when the calculation +was launched. It is possible for `input` and `orig_inputs` to differ if `custodian` is invoked to apply some adjustment +to the calculation settings. `orig_inputs` is retained to provide 100% transparent provenance in such cases. + +In addition, there is a `custodian` key that will capture and list any corrections or changes made by `custodian` +during the calculation, as well as additional metadata. In our case, the `custodian.corrections` list is empty, +which means that no modifications or restarts were made. + +```json +"custodian": [ + { + "corrections": [], + "job": { + "@module": "custodian.vasp.jobs", + "@class": "VaspJob", + "@version": "2024.4.18", + "vasp_cmd": [ + "srun", + "/scratch/gpfs/ab6989/MPScanRelaxSet/atomate2/vasp_std" + ], + "output_file": "vasp.out", + "stderr_file": "std_err.txt", + "suffix": "", + "final": true, + "backup": true, + "auto_npar": false, + "auto_gamma": true, + "settings_override": null, + "gamma_vasp_cmd": [ + "vasp_gam" + ], + "copy_magmom": false, + "auto_continue": false + } + } + ], +``` + +#### `calcs_reversed` + +Most Task Documents also contain a key called `calcs_reversed` which, as the name implies, contains calculation inputs +and outputs **in reverse order**. These are stored as a `list`, so index `[0]` corresponds to the last (most recent) +calculation, whereas index `[-1]` is the first calculation. Each element in the list contains `input`, `output`, `dir_name`, +and other keys that give a complete specification of that calculation step. + +In this example, there is only one element in `calcs_reversed`, because we just did a one-step `Job`. However, more +complex workflows that contain multiple individual calculations would have an entry for each step. + +```json +"calcs_reversed": [ + { "dir_name": "/scratch/gpfs/.../job_2024-05-19-21-13-15-058677-64911", + "vasp_version": "6.4.2", + "has_vasp_completed": "successful", + "input": { + "incar": {...}, + "kpoints": {...}, + "nkpoints": 20, + "potcar": ["PAW_PBE"], + "potcar_spec": [ ... ], + "potcar_type": ["PAW_PBE"], + "parameters": {...}, + "lattice_rec": {...}, + "structure": {...}, + "is_hubbard": false, + "hubbards": {} + }, + "output": { + "energy": -11.48288783, + "energy_per_atom": -5.741443915, + "structure": { .... }, + "efermi": 5.96853235, + "is_metal": false, + "bandgap": 0.45999999999999996, + "cbm": 6.2225, + "vbm": 5.7625, + "is_gap_direct": false, + "direct_gap": 2.5146000000000006, + "transition": "(0.000,0.000,0.000)-(0.429,0.429,-0.000)", + "mag_density": -1.2698159551931228e-7, + "epsilon_static": null, + "epsilon_static_wolfe": null, + "epsilon_ionic": null, + "frequency_dependent_dielectric": { + "real": null, + "imaginary": null, + "energy": null + }, + "ionic_steps": [ ... ], + "force_constants": null, + "normalmode_frequencies": null, + "normalmode_eigenvals": null, + "normalmode_eigenvecs": null, + "elph_displaced_structures": { + "temperatures": null, + "structures": null + }, + "dos_properties": {...}, + "run_stats": { + "average_memory": 0, + "max_memory": 241584, + "elapsed_time": 18.833, + "system_time": 1.114, + "user_time": 16.166, + "total_time": 17.28, + "cores": 40 + } + }, + "completed_at": "2024-05-19 17:13:34.897366", + "task_name": "standard", + "output_file_paths": { + "chgcar": "CHGCAR", + "aeccar0": "AECCAR0", + "aeccar1": "AECCAR1", + "aeccar2": "AECCAR2" + }, + "bader": null, + "ddec6": null, + "run_type": "PBESol", + "task_type": "Structure Optimization", + "calc_type": "PBESol Structure Optimization" + }, + ] +``` + +There is some redundancy in the information stored in `input`, `output`, and `calcs_reversed`, but this is by design. +`input` and `output` capture summary information about the first and last steps of the `Job`, whereas +`calcs_reversed` records practically every detail of all the intermediate steps. + + +```{note} +The `TaskDoc` `calcs_reversed` section is designed to capture **all the information that can be obtained from a VASP OUTCAR** +(or `vasprun.xml`). Therefore, if you query your output data from the `atomate2` database, you should not need to +manually look up anything from the OUTCAR. Chances are very good that the information is available somewhere in the +`TaskDoc`. For example: + - you can get the electronic energy of the last SCF iteration (index `[-1]`) of the first +ionic step (index `[0]`) in `calcs_reversed[0].output.ionic_steps[0].electronic_steps[0].e_fr_energy`. + - you can retrieve any INCAR parameter, such as ENCUT, from `calcs_reversed[0].input.incar["ENCUT"]` +``` + +## `emmet` + +### Materials Project and Community document models + +Most document models used by `atomate2` "live" in a separate package called [`emmet`](https://github.com/materialsproject/emmet) +(or more specifically, `emmet-core`), which is installed by default as a dependency of `atomate2`. In general, +mature document models that are used in the Materials Project website or database are developed in `emmet`, +whereas some document models that are more niche or are in earlier stages of development may exist +in `atomate2` itself. + +Here is a partial listing of the codes and calculation types currently supported in `emmet-core`: + +Software: + - VASP + - Q-Chem + - FEFF + - OpenMM + +Calculation Types: + - Structure optimization + - Static / single point energy + - Frequency + - Band structure + - Elastic tensor + +### Code-agnostic document models for analysis + +So far, we have introduced Document Models as a way of parsing input and output data from a specific +calculation software (VASP). However, document models are also useful for capturing data from +"downstream" analysis that is not dependent on the specific code used to generate the data. +Hence, **many document models in `emmet-core` are agnostic or independent of the specific software +used in the initial calculation**. + +To take a simple example, `emmet-core` contains a schema called [`ElectronicStructureSummaryData`](https://github.com/materialsproject/emmet/blob/main/emmet-core/emmet/core/electronic_structure.py#L86) that stores +the `band_gap`, conduction band minimum (`cbm`), valence band maximum (`vbm`), and Fermi level (`e_fermi`): + +```python +class ElectronicStructureBaseData(BaseModel): + task_id: MPID = Field( + ..., + description="The source calculation (task) ID for the electronic structure data. " + "This has the same form as a Materials Project ID.", + ) + + band_gap: float = Field(..., description="Band gap energy in eV.") + + cbm: Optional[Union[float, Dict]] = Field( + None, description="Conduction band minimum data." + ) + + vbm: Optional[Union[float, Dict]] = Field( + None, description="Valence band maximum data." + ) + + efermi: Optional[float] = Field(None, description="Fermi energy in eV.") +``` + +Clearly, this simple document model could be used to store output from any periodic DFT code. + +### Builders + +`emmet-core` also defines `Builder` classes, which take raw calculation results (e.g., the `TaskDoc`) +from our example, perform some analysis or transformation, and then create new document models +in additional `Store`. This paradigm makes it possible to construct automated data processing +pipelines, and is the basis for how the Materials Project database. For more about how builders and +stores work together, see the [`maggma` documentation](https://materialsproject.github.io/maggma/concepts/). + +## Conclusion + +In this tutorial, you learned that `atomate2` uses schema or "Document Models" (based on `pydantic.BaseModel`) +to structure and validate output data. You examined the typical structure of a calculation output by +looking at the schema for a VASP structure optimization (`TaskDoc`). You also learned that `emmet` serves as +a "library" of mature document models used by the Materials Project. + +At this point, you might: + +* Explore how to query results from the docs store: [maggma tutorial](https://materialsproject.github.io/maggma/getting_started/query_101/) +* Learn how to create automatic processing pipelines with `Builder` [maggma tutorial](https://materialsproject.github.io/maggma/getting_started/simple_builder/). diff --git a/docs/user/install.md b/docs/user/install.md index 9a209fcac3..f569ef3241 100644 --- a/docs/user/install.md +++ b/docs/user/install.md @@ -456,6 +456,8 @@ See the following pages for more information on the topics we covered here: - To see how to run and customize the existing Workflows in atomate2, try the [](running_workflows) tutorial (suggested next step). +- To learn more about `TaskDocument` and how `atomate2` organizes output data, review + the [Introduction to task documents, schemas, and emmet](docs_schemas_emmet.md) tutorial. - To see how to manage and execute many workflows at once, try the [](atomate2_fireWorks) tutorial. diff --git a/docs/user/key_concepts_overview.md b/docs/user/key_concepts_overview.md new file mode 100644 index 0000000000..100cef25fc --- /dev/null +++ b/docs/user/key_concepts_overview.md @@ -0,0 +1,335 @@ +(key_concepts_overview)= + +# Key concepts in atomate2: `Job` & `Flow` `Makers`, `InputSet`, `TaskDocument`, and `Builder` + +# Introduction +This tutorial will give you a comprehensive high-level overview of the key concepts in atomate2, diving into the important features of `Job` and `Flow` makers, as well as `InputSets`, `TaskDocuments`, and `Builders`. + +## `Job` and `Flow` makers + +`Job` and `Flow` makers are the workhorses of the atomate2 code framework. Their key role is to enable the user to orchestrate and execute a sequence of usually repetitive tasks, processes and manage computational workflows. +To streamline the management of such processes, tools like [jobflow](https://github.com/materialsproject/jobflow) can be used. The two essential building blocks of the jobflow-based workflows in atomate2 are `Jobs` and `Flows`. + +### Basics + +A `Job` is a single computing job, and potentially can take any python function form, given that their inputs and outputs (return values) can be serialized in a JSON format. Jobs are defined using the `@job` decorator. + +A `Flow` is a sequential collection of job or other flow objects. The connectivity and also execution order and dependencies of the different jobs and flow is decided automatically from the job inputs. The output from one job (`job.output`) can be used as the input for the next one. This will therefore establish a connectivity between these two jobs. +The connectivity between several jobs and flows can be arbitrary, depending on the purpose of the workflow. + +The diagram below illustrates a very general example of a flow (Total flow) comprised of several other flows. Each flow integrates several individual jobs or tasks, connected by the respective `job.output`. + +![Flow example](../_static/example_flow.png) + +`Job` and `Flow` makers come in handy by providing a template schema to set up diverse electronic structure calculation and computational chemistry tasks (e.g. chemical bonding analysis, elastic constant calculations, force field applications and many more) and to make it easier to handle and unify output from the various supported software packages (like VASP, phonopy and more). +Given that the job output data is stored in a JSON serializable dict format, it makes it possible to conveniently handle the final output with so-called [`TaskDocuments`](#taskdocument). + +### Technical Aspects + +The atomate2 `Job` and `Flow` makers are both dataclasses that inherit from the `Maker` [jobflow](https://github.com/materialsproject/jobflow/blob/main/src/jobflow/core/maker.py) dataclass. +The `Maker` class from jobflow is a base class for constructing the aforementioned `Job` and `Flow` objects. It has two main functionalities, that are vital for any inheriting job or flow maker: the `make` function and the functionality to update keyword arguments (kwargs). + +``` +@dataclass +class Maker(MSONable): + """ + Base maker (factory) class for constructing :obj:`Job` and :obj:`Flow` objects. + [...] + """ + def make(...) -> jobflow.Flow | jobflow.Job: + """Make a job or a flow - must be overridden with a concrete implementation.""" + raise NotImplementedError + [...] + def update_kwargs(...): +``` + +When implementing a new job or flow maker, it's crucial to take care of the functions that raise an `NotImplementedError`. Functions like the `make` function have to be overridden for each specific job or flow maker with its own specific functionalities. + +### Examples + +Let's have a closer look at the `LobsterMaker` as an example for a `Job Maker`: + +``` +@dataclass +class LobsterMaker(Maker): + """ + LOBSTER job maker. + [...] + """ + name: str = "lobster" + [...] + + @job(output_schema=LobsterTaskDocument, data=[CompleteCohp, LobsterCompleteDos]) + def make( + self, + wavefunction_dir: str | Path = None, + basis_dict: dict | None = None, + ) -> LobsterTaskDocument: + """ + Run a LOBSTER calculation. + [...] + """ +``` +This class incorporates [LOBSTER](http://cohp.de/) specific input and output data, i.e. the `wavefunction_dir` and `basis_dict` as input in `make` that returns the `LobsterMaker`-class specific output as a `TaskDocument`. Also, note how the `make` functions is annotated by the `@job` decorator. This small addition to `make` turns the maker into a job maker. +As the name "job maker" implies, this maker will then create jobs to execute the LOBSTER runs and store the output in the `LobsterTaskDocument` format. + +What changes need to be made to turn a maker into a `Flow Maker`? In that case, the `make` function needs to be adjusted to return a `Flow` object instead of a task document. +As an example we take the `BasePhononMaker` (that can be used in combination with VASP or the various (machine-learned) force fields): +``` +@dataclass +class BasePhononMaker(Maker, ABC): + """ + Maker to calculate harmonic phonons with a DFT/force field code and Phonopy. + + [...] + """ + + name: str = "phonon" + [...] + + def make(...) -> Flow: +``` +This maker will return a flow that provides all the necessary steps and subroutines that are needed to complete the phonon calculations. +Oftentimes, such flows then involve dynamic jobs. For the phonon calculations this means that the number of supercells with individual atomic displacements will be decided upon runtime. +In this particular case, the flow maker `BasePhononMaker` is also inheriting from `ABC` (Abstract Base Classes). + + +# InputSet + +An `InputSet` is a convenient way to provide a collection of input data for one or more input files as dict-like container. They set the backbone framework to handle the input settings for a variety of computational codes, like e.g. VASP, Q-Chem, LAMMPS, CP2K and ABINIT. + +## Basics + +The [pymatgen](https://github.com/materialsproject/pymatgen) class `InputSet` is a core class to manage and write the input files for the several computational codes to a file location the user specifies. +There are predefined "recipes" for generating `InputSets` tailored to specific tasks like structural relaxation or the band structure calculation and more, that are provided as `InputGenerator` classes. + +## Technical Aspects + +The `InputSet` objects posses the `write_input()` method that is used to write all the necessary files. + +``` +class InputSet(MSONable, MutableMapping): + """ + Abstract base class for all InputSet classes. InputSet are dict-like + containers for all calculation input data. + [...] + """ + def write_input( + self, + directory: str | Path, + make_dir: bool = True, + overwrite: bool = True, + zip_inputs: bool = False, + ): + """ + Write Inputs to one or more files. + [...] + """ + + @classmethod + def from_directory(cls, directory: str | Path): + """ + Construct an InputSet from a directory of one or more files. + [...] + """ + raise NotImplementedError(f"from_directory has not been implemented in {cls.__name__}") +``` + +It is essential to emphasize that all `InputSet` must implement the `from_directory` classmethod. + +## Examples + +Diving into the specifics for the `VaspInputSet` will demonstrate you some important features of an input set. + +``` +class VaspInputSet(InputSet): + """ + A class to represent a set of VASP inputs. + [...] + """ + + def write_input(self,..., potcar_spec: bool = False) -> None: + """ + Write VASP input files to a directory. + [...] + """ + + @staticmethod + def from_directory(...) -> VaspInputSet: + """ + Load a set of VASP inputs from a directory. + [...] + """ + + @property + def is_valid(self) -> bool: + """ + Whether the input set is valid. + [...] + """ +``` +VASP needs several inputs files (INCAR, POSCAR, POTCAR and KPOINTS) in order to run. The files can be written to any directory using the `write_input` method. If needed, only POTCAR.spec instead of the full POTCAR can be written out. It will then only contain the [pseudopotential names](https://www.vasp.at/wiki/index.php/Available_PAW_potentials) (e.g. Li_sv). +If necessary, it is also possible to specify optional files. The `VaspInputSet` also provides the possibility to check if the constructed input set is valid, to avoid conflicting input setup (e.g. concerning the ISMEAR and KPOINTS settings). + +The corresponding input generator is the `VaspInputGenerator`. + +# TaskDocument +A `TaskDocument` (often shorted to TaskDoc) is a dictionary object that makes it feasible to collect all the information of the respective computational chemistry calculation run. + +## Basics + +`TaskDocuments` are schemas that contain and store all the information of a calculation run, like the (resulting) structure, input data (`InputDoc`), output data (`OutputDoc`), task directory name (`dir_name`) and many more items depending on the respective prerequisites of the computational software that is used. +Task documents are a very practical way to transfer (input and output) data between two different jobs. For instance, when you need the structure or path to the (current) job directory in the subsequent step, you can pass it in form of `taskdoc.structure` and `taskdoc.dir_name`, with `taskdoc` as an example instance of the task document class in question. + +## Technical Aspects + +In atomate2, the `TaskDocument` objects inherit from the [emmet](https://github.com/materialsproject/emmet/) classes `StructureMetadata` or `MoleculeMetadata`. + +``` +class StructureMetadata(EmmetBaseModel): + """Mix-in class for structure metadata.""" +``` +They contain the structure or molecule metadata, tailored to the variety of computational software. + +## Examples + +Let's take the `ForceFieldTaskDocument` as an illustrative example for task documents, inheriting from the `StructureMetadata` class. + +``` +class ForceFieldTaskDocument(StructureMetadata): + """Document containing information on structure relaxation using a force field.""" + + structure: Structure = Field( + None, description="Final output structure from the task" + ) + + input: InputDoc = Field( + None, description="The inputted information used to run this job." + ) + + output: OutputDoc = Field( + None, description="The outputted information from this relaxation job." + ) + + forcefield_name: str = Field( + None, + description="name of the interatomic potential used for relaxation.", + ) + + forcefield_version: str = Field( + None, + description="version of the interatomic potential used for relaxation.", + ) + + dir_name: Optional[str] = Field( + None, description="Directory where the force field calculations are performed." + ) +``` +This task document provides the user with all information concerning a force field-based structure relaxation calculation. This includes the resulting relaxed structure, and force field-specific metadata like the force field name or version among other things. + + +Next, we will have a look at the CP2K TaskDoc that is also inheriting from `MoleculeMetadata`. +``` +class TaskDocument(StructureMetadata, MoleculeMetadata): + """Definition of CP2K task document.""" + + dir_name: Optional[str] = Field( + None, description="The directory for this CP2K task" + ) + last_updated: str = Field( + default_factory=datetime_str, + description="Timestamp for this task document was last updated", + ) + completed_at: Optional[str] = Field( + None, description="Timestamp for when this task was completed" + ) + input: Optional[InputSummary] = Field( + None, description="The input to the first calculation" + ) + output: Optional[OutputSummary] = Field( + None, description="The output of the final calculation" + ) + structure: Union[Structure, Molecule] = Field( + None, description="Final output structure from the task" + ) + state: Optional[Status] = Field(None, description="State of this task") + included_objects: Optional[list[Cp2kObject]] = Field( + None, description="list of CP2K objects included with this task document" + ) + cp2k_objects: Optional[dict[Cp2kObject, Any]] = Field( + None, description="CP2K objects associated with this task" + ) + [...] +``` +Now, the TaskDoc stores structure or molecule metadata like `structure`, CP2K-specific items like `included_objects` or `cp2k_objects` and more items. + +# Builder + +The `Builder` object is provided by the [maggma](https://github.com/materialsproject/maggma/) toolkit and serves as a data processing step. + +## Basics + +`Builders` offer an interface for writing data transformations: you can get items from a `Store`, process and manipulate the input data and prepare an output document, as well as update and add the processed items to the target store(s). + + +## Technical Aspects + +The `Builder` and `Store` are the core classes of maggma and give the user tools to build data pipelines from different types of data sources. + +``` +class Builder(MSONable, metaclass=ABCMeta): + """ + Base Builder class + At minimum this class should implement: + get_items - Get items from the sources + update_targets - Updates the sources with results + + Multiprocessing and MPI processing can be used if all + the data processing is limited to process_items + """ + [...] + + @abstractmethod + def get_items(self) -> Iterable: + + def process_item(self, item: Any) -> Any: + + @abstractmethod + def update_targets(self, items: List): +``` +The `Builder` class has three main functionalities that are `get_items` to retrieve data from the source store(s), `process_item` to handle the input items and create an output document to be then added to the target store(s) by `update_target`. + +## Examples + +Atomate2 supplies us with the `ElasticBuilder` that is a handy example for a `Builder`: +``` +class ElasticBuilder(Builder): + """ + The elastic builder compiles deformation tasks into an elastic document. + [...] + """ + def get_items(self) -> Generator: + """ + Get all items to process into elastic documents. + [...] + """ + def process_item(self, tasks: list[dict]) -> list[ElasticDocument]: + """ + Process deformation tasks into elasticity documents. + [...] + """ + def update_targets(self, items: list[ElasticDocument]) -> None: + """ + Insert new elastic documents into the elasticity store. + [...] + """ +``` + +For the `ElasticBuilder`, the initial step of getting all the items awaiting processing involves finding all deformation documents with the same formula. +Then during the data and item processing stage, the deformations will be grouped by their parent structures. +Finally, the builder compiles the processed items into an ElasticDocument from the group of tasks, and adds the new elastic documents to the elasticity store. + + +# Exercises + +Construct a flow for a `DoubleRelaxMaker` (a workflow consisting of two relax jobs) based on the `CHGNetRelaxMaker`. Then add a final non-SCF static job using the `CHGNetStaticMaker`. Compare your result with the [DoubleRelaxMaker for VASP](https://materialsproject.github.io/atomate2/reference/atomate2.vasp.flows.core.DoubleRelaxMaker.html#atomate2.vasp.flows.core.DoubleRelaxMaker). Try to replicate one of the other [VASP workflows](https://materialsproject.github.io/atomate2/user/codes/vasp.html#list-of-vasp-workflows) as well! diff --git a/docs/user/running-workflows.md b/docs/user/running-workflows.md index 28322571af..149b74ea7a 100644 --- a/docs/user/running-workflows.md +++ b/docs/user/running-workflows.md @@ -170,5 +170,6 @@ At this point, you might: * Learn how to chain workflows together: [](connecting_vasp_jobs). * Learn how to customise VASP input settings: [](modifying_input_sets). +* Learn more about [Document Models and Schemas](docs_schemas_emmet) * Configure atomate2 with FireWorks to manage and execute many workflows at once: [](atomate2_fireWorks). diff --git a/pyproject.toml b/pyproject.toml index 7182b8368f..32f73bfb0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,6 +75,7 @@ tests = [ "pytest-cov==5.0.0", "pytest-mock==3.14.0", "pytest==8.0.2", + "nbmake==1.5.3" ] strict = [ "PyYAML==6.0.1", diff --git a/src/atomate2/aims/flows/elastic.py b/src/atomate2/aims/flows/elastic.py new file mode 100644 index 0000000000..7a0300f9e3 --- /dev/null +++ b/src/atomate2/aims/flows/elastic.py @@ -0,0 +1,93 @@ +"""Flows for calculating elastic constants.""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING + +from atomate2 import SETTINGS +from atomate2.aims.jobs.core import RelaxMaker +from atomate2.common.flows.elastic import BaseElasticMaker + +if TYPE_CHECKING: + from atomate2.aims.jobs.base import BaseAimsMaker + + +@dataclass +class ElasticMaker(BaseElasticMaker): + """ + Maker to calculate elastic constants. + + Calculate the elastic constant of a material. Initially, a tight structural + relaxation is performed to obtain the structure in a state of approximately zero + stress. Subsequently, perturbations are applied to the lattice vectors and the + resulting stress tensor is calculated from DFT, while allowing for relaxation of the + ionic degrees of freedom. Finally, constitutive relations from linear elasticity, + relating stress and strain, are employed to fit the full 6x6 elastic tensor. From + this, aggregate properties such as Voigt and Reuss bounds on the bulk and shear + moduli are derived. + + .. Note:: + It is heavily recommended to symmetrize the structure before passing it to + this flow. Otherwise, the symmetry reduction routines will not be as + effective at reducing the total number of deformations needed. + + Parameters + ---------- + name : str + Name of the flows produced by this maker. + order : int + Order of the tensor expansion to be determined. Can be either 2 or 3. + sym_reduce : bool + Whether to reduce the number of deformations using symmetry. + symprec : float + Symmetry precision to use in the reduction of symmetry. + bulk_relax_maker : .BaseAimsMaker or None + A maker to perform a tight relaxation on the bulk. Set to ``None`` to skip the + bulk relaxation. + elastic_relax_maker : .BaseAimsMaker + Maker used to generate elastic relaxations. + generate_elastic_deformations_kwargs : dict + Keyword arguments passed to :obj:`generate_elastic_deformations`. + fit_elastic_tensor_kwargs : dict + Keyword arguments passed to :obj:`fit_elastic_tensor`. + task_document_kwargs : dict + Additional keyword args passed to :obj:`.ElasticDocument.from_stresses()`. + """ + + name: str = "elastic" + order: int = 2 + sym_reduce: bool = True + symprec: float = SETTINGS.SYMPREC + bulk_relax_maker: BaseAimsMaker | None = field( + default_factory=RelaxMaker.full_relaxation + ) + elastic_relax_maker: BaseAimsMaker = field( + default_factory=RelaxMaker.fixed_cell_relaxation + ) + generate_elastic_deformations_kwargs: dict = field(default_factory=dict) + fit_elastic_tensor_kwargs: dict = field(default_factory=dict) + task_document_kwargs: dict = field(default_factory=dict) + + @property + def prev_calc_dir_argname(self) -> str: + """Name of argument informing static maker of previous calculation directory. + + As this differs between different DFT codes (e.g., VASP, CP2K), it + has been left as a property to be implemented by the inheriting class. + + Note: this is only applicable if a relax_maker is specified; i.e., two + calculations are performed for each ordering (relax -> static) + """ + return "prev_dir" + + @property + def stress_sign_correction(self) -> float: + r"""Correct the sign of the stress tensor. + + This is done because VASP defines the stress tensor to be + \sigma_ij = -\partial E / \partial n_ij + and FHI-aims defines it to be + \sigma_ij = \partial E / \partial n_ij + """ + return -1.0 diff --git a/src/atomate2/common/flows/elastic.py b/src/atomate2/common/flows/elastic.py index 256e0753e9..c0e04fa19f 100644 --- a/src/atomate2/common/flows/elastic.py +++ b/src/atomate2/common/flows/elastic.py @@ -22,6 +22,7 @@ from emmet.core.math import Matrix3D from pymatgen.core.structure import Structure + from atomate2.aims.jobs.base import BaseAimsMaker from atomate2.forcefields.jobs import ForceFieldRelaxMaker from atomate2.vasp.jobs.base import BaseVaspMaker @@ -77,8 +78,8 @@ class BaseElasticMaker(Maker, ABC): order: int = 2 sym_reduce: bool = True symprec: float = SETTINGS.SYMPREC - bulk_relax_maker: BaseVaspMaker | ForceFieldRelaxMaker | None = None - elastic_relax_maker: BaseVaspMaker | ForceFieldRelaxMaker = ( + bulk_relax_maker: BaseAimsMaker | BaseVaspMaker | ForceFieldRelaxMaker | None = None + elastic_relax_maker: BaseAimsMaker | BaseVaspMaker | ForceFieldRelaxMaker = ( None # constant volume optimization ) max_failed_deformations: int | float | None = None @@ -93,7 +94,8 @@ def make( equilibrium_stress: Matrix3D = None, conventional: bool = False, ) -> Flow: - """Make flow to calculate the elastic constant. + """ + Make flow to calculate the elastic constant. Parameters ---------- @@ -145,6 +147,7 @@ def make( equilibrium_stress=equilibrium_stress, order=self.order, symprec=self.symprec if self.sym_reduce else None, + stress_sign_factor=self.stress_sign_correction, max_failed_deformations=self.max_failed_deformations, **self.fit_elastic_tensor_kwargs, **self.task_document_kwargs, @@ -161,6 +164,17 @@ def make( name=self.name, ) + @property + def stress_sign_correction(self) -> float: + r"""Correct the sign of the stress tensor. + + This is done because VASP defines the stress tensor to be + \sigma_ij = -\partial E / \partial n_ij + and FHI-aims defines it to be + \sigma_ij = \partial E / \partial n_ij + """ + return 1.0 + @property @abstractmethod def prev_calc_dir_argname(self) -> str: diff --git a/src/atomate2/common/jobs/elastic.py b/src/atomate2/common/jobs/elastic.py index 253977f99a..cd25367cf6 100644 --- a/src/atomate2/common/jobs/elastic.py +++ b/src/atomate2/common/jobs/elastic.py @@ -172,9 +172,10 @@ def fit_elastic_tensor( fitting_method: str = SETTINGS.ELASTIC_FITTING_METHOD, symprec: float = SETTINGS.SYMPREC, allow_elastically_unstable_structs: bool = True, + stress_sign_factor: float = 1.0, max_failed_deformations: float | None = None, ) -> ElasticDocument: - """ + r""" Analyze stress/strain data to fit the elastic tensor and related properties. Parameters @@ -201,6 +202,8 @@ def fit_elastic_tensor( allow_elastically_unstable_structs : bool Whether to allow the ElasticDocument to still complete in the event that the structure is elastically unstable. + stress_sign_factor: float + Corrections for codes that define stress to be \partial E / \partial n_ij max_failed_deformations: int or float Maximum number of deformations allowed to fail to proceed with the fitting of the elastic tensor. If an int the absolute number of deformations. If @@ -218,7 +221,7 @@ def fit_elastic_tensor( failed_uuids.append(data["uuid"]) continue - stresses.append(Stress(data["stress"])) + stresses.append(Stress(stress_sign_factor * np.array(data["stress"]))) deformations.append(Deformation(data["deformation"])) uuids.append(data["uuid"]) job_dirs.append(data["job_dir"]) diff --git a/tests/aims/test_flows/test_elastic.py b/tests/aims/test_flows/test_elastic.py new file mode 100644 index 0000000000..edcb7b51a5 --- /dev/null +++ b/tests/aims/test_flows/test_elastic.py @@ -0,0 +1,73 @@ +import os + +import pytest +from jobflow import run_locally +from numpy.testing import assert_allclose +from pymatgen.symmetry.analyzer import SpacegroupAnalyzer + +from atomate2.aims.flows.elastic import ElasticMaker +from atomate2.aims.jobs.core import RelaxMaker +from atomate2.common.schemas.elastic import ElasticDocument + +cwd = os.getcwd() + + +@pytest.mark.parametrize("conventional", [False, True]) +def test_elastic(si, tmp_path, mock_aims, species_dir, conventional): + ref_paths = { + "Relaxation calculation (fixed cell) 1/6": "elastic-si-rel-1", + "Relaxation calculation (fixed cell) 2/6": "elastic-si-rel-2", + "Relaxation calculation (fixed cell) 3/6": "elastic-si-rel-3", + "Relaxation calculation (fixed cell) 4/6": "elastic-si-rel-4", + "Relaxation calculation (fixed cell) 5/6": "elastic-si-rel-5", + "Relaxation calculation (fixed cell) 6/6": "elastic-si-rel-6", + "Relaxation calculation": "elastic-si-bulk-relax", + } + + # settings passed to fake_run_aims; adjust these to check for certain input settings + fake_run_aims_kwargs = {} + + # automatically use fake FHI-aims + mock_aims(ref_paths, fake_run_aims_kwargs) + + parameters = { + "k_grid": [2, 2, 2], + "species_dir": (species_dir / "light").as_posix(), + } + + # generate flow + si_sga = SpacegroupAnalyzer(si).get_conventional_standard_structure() + maker = ElasticMaker( + bulk_relax_maker=RelaxMaker.full_relaxation( + user_params=dict(**parameters, rlsy_symmetry="all") + ), + elastic_relax_maker=RelaxMaker.fixed_cell_relaxation( + user_params=dict( + **parameters, compute_analytical_stress=True, rlsy_symmetry=None + ) + ), + ) + flow = maker.make(si_sga, conventional=conventional) + + # Run the flow or job and ensure that it finished running successfully + os.chdir(tmp_path) + responses = run_locally(flow, create_folders=True, ensure_success=True) + os.chdir(cwd) + + # validation on the outputs + elastic_output = responses[flow.jobs[-1].uuid][1].output + assert isinstance(elastic_output, ElasticDocument) + + assert_allclose( + elastic_output.elastic_tensor.ieee_format, + [ + [147.279167, 56.2746603, 56.2746603, 0.0, 0.0, 0.0], + [56.2746603, 147.279167, 56.2746603, 0.0, 0.0, 0.0], + [56.2746603, 56.2746603, 147.279167, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 75.9240547, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 75.9240547, 0.0], + [0.0, 0.0, 0.0, 0.0, 0.0, 75.9240547], + ], + atol=1e-6, + ) + assert elastic_output.chemsys == "Si" diff --git a/tests/test_data/aims/elastic-si-bulk-relax/inputs/control.in.gz b/tests/test_data/aims/elastic-si-bulk-relax/inputs/control.in.gz new file mode 100644 index 0000000000..88070b9cf4 Binary files /dev/null and b/tests/test_data/aims/elastic-si-bulk-relax/inputs/control.in.gz differ diff --git a/tests/test_data/aims/elastic-si-bulk-relax/inputs/geometry.in.gz b/tests/test_data/aims/elastic-si-bulk-relax/inputs/geometry.in.gz new file mode 100644 index 0000000000..44d1d1c680 Binary files /dev/null and b/tests/test_data/aims/elastic-si-bulk-relax/inputs/geometry.in.gz differ diff --git a/tests/test_data/aims/elastic-si-bulk-relax/inputs/parameters.json b/tests/test_data/aims/elastic-si-bulk-relax/inputs/parameters.json new file mode 100644 index 0000000000..97cc6216fd --- /dev/null +++ b/tests/test_data/aims/elastic-si-bulk-relax/inputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "full", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "rlsy_symmetry": "all"} diff --git a/tests/test_data/aims/elastic-si-bulk-relax/outputs/aims.out.gz b/tests/test_data/aims/elastic-si-bulk-relax/outputs/aims.out.gz new file mode 100644 index 0000000000..57c6931744 Binary files /dev/null and b/tests/test_data/aims/elastic-si-bulk-relax/outputs/aims.out.gz differ diff --git a/tests/test_data/aims/elastic-si-bulk-relax/outputs/geometry.in.next_step.gz b/tests/test_data/aims/elastic-si-bulk-relax/outputs/geometry.in.next_step.gz new file mode 100644 index 0000000000..e20f3b05b3 Binary files /dev/null and b/tests/test_data/aims/elastic-si-bulk-relax/outputs/geometry.in.next_step.gz differ diff --git a/tests/test_data/aims/elastic-si-bulk-relax/outputs/hessian.aims.gz b/tests/test_data/aims/elastic-si-bulk-relax/outputs/hessian.aims.gz new file mode 100644 index 0000000000..3efb87fbeb Binary files /dev/null and b/tests/test_data/aims/elastic-si-bulk-relax/outputs/hessian.aims.gz differ diff --git a/tests/test_data/aims/elastic-si-bulk-relax/outputs/parameters.json b/tests/test_data/aims/elastic-si-bulk-relax/outputs/parameters.json new file mode 100644 index 0000000000..97cc6216fd --- /dev/null +++ b/tests/test_data/aims/elastic-si-bulk-relax/outputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "full", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "rlsy_symmetry": "all"} diff --git a/tests/test_data/aims/elastic-si-rel-1/inputs/control.in.gz b/tests/test_data/aims/elastic-si-rel-1/inputs/control.in.gz new file mode 100644 index 0000000000..e559b33015 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-1/inputs/control.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-1/inputs/geometry.in.gz b/tests/test_data/aims/elastic-si-rel-1/inputs/geometry.in.gz new file mode 100644 index 0000000000..ce173a2216 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-1/inputs/geometry.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-1/inputs/parameters.json b/tests/test_data/aims/elastic-si-rel-1/inputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-1/inputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-1/outputs/aims.out.gz b/tests/test_data/aims/elastic-si-rel-1/outputs/aims.out.gz new file mode 100644 index 0000000000..2eff949464 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-1/outputs/aims.out.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-1/outputs/parameters.json b/tests/test_data/aims/elastic-si-rel-1/outputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-1/outputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-1/outputs/transformations.json b/tests/test_data/aims/elastic-si-rel-1/outputs/transformations.json new file mode 100644 index 0000000000..7fe1c1ad5e --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-1/outputs/transformations.json @@ -0,0 +1 @@ +{"@module": "pymatgen.alchemy.materials", "@class": "TransformedStructure", "charge": 0, "lattice": {"matrix": [[5.438033809472898, 0.0, 3.3636416509474475e-16], [8.74502533872069e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.438033809472898, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 164.09661950614597}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3595084523682248, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.372512669360345e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3595084523682253, 4.1199327675, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.719016904736449, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.078525357104674, 1.3733109225, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7190169047364496, 2.746621845, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.078525357104675, 4.1199327675, 4.1199327675], "properties": {}, "label": "Si"}], "history": [{"@module": "pymatgen.transformations.standard_transformations", "@class": "DeformStructureTransformation", "@version": null, "deformation": [[0.9899494936611666, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], "input_structure": {"@module": "pymatgen.core.structure", "@class": "Structure", "charge": 0, "lattice": {"matrix": [[5.49324369, 0.0, 3.3636416509474475e-16], [8.833809598082263e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 165.7626177465493}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.1199327675, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.3733109225, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.746621845, 2.7466218450000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.1199327675, 4.119932767500001], "properties": {}, "label": "Si"}]}, "output_parameters": {}}], "last_modified": "2024-06-03 21:21:32.385740+00:00", "other_parameters": {}, "@version": null} diff --git a/tests/test_data/aims/elastic-si-rel-2/inputs/control.in.gz b/tests/test_data/aims/elastic-si-rel-2/inputs/control.in.gz new file mode 100644 index 0000000000..a71579b08f Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-2/inputs/control.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-2/inputs/geometry.in.gz b/tests/test_data/aims/elastic-si-rel-2/inputs/geometry.in.gz new file mode 100644 index 0000000000..ddfe4b2736 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-2/inputs/geometry.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-2/inputs/parameters.json b/tests/test_data/aims/elastic-si-rel-2/inputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-2/inputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-2/outputs/aims.out.gz b/tests/test_data/aims/elastic-si-rel-2/outputs/aims.out.gz new file mode 100644 index 0000000000..f6944312ea Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-2/outputs/aims.out.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-2/outputs/parameters.json b/tests/test_data/aims/elastic-si-rel-2/outputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-2/outputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-2/outputs/transformations.json b/tests/test_data/aims/elastic-si-rel-2/outputs/transformations.json new file mode 100644 index 0000000000..59734e1dcb --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-2/outputs/transformations.json @@ -0,0 +1 @@ +{"@module": "pymatgen.alchemy.materials", "@class": "TransformedStructure", "charge": 0, "lattice": {"matrix": [[5.465708460515212, 0.0, 3.3636416509474475e-16], [8.789529571883732e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.465708460515212, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 164.93172219972337}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3664271151288032, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.394764785941866e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3664271151288037, 4.1199327675, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.732854230257606, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.099281345386409, 1.3733109225, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7328542302576064, 2.746621845, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.09928134538641, 4.1199327675, 4.1199327675], "properties": {}, "label": "Si"}], "history": [{"@module": "pymatgen.transformations.standard_transformations", "@class": "DeformStructureTransformation", "@version": null, "deformation": [[0.99498743710662, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], "input_structure": {"@module": "pymatgen.core.structure", "@class": "Structure", "charge": 0, "lattice": {"matrix": [[5.49324369, 0.0, 3.3636416509474475e-16], [8.833809598082263e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 165.7626177465493}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.1199327675, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.3733109225, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.746621845, 2.7466218450000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.1199327675, 4.119932767500001], "properties": {}, "label": "Si"}]}, "output_parameters": {}}], "last_modified": "2024-06-03 21:23:01.980849+00:00", "other_parameters": {}, "@version": null} diff --git a/tests/test_data/aims/elastic-si-rel-3/inputs/control.in.gz b/tests/test_data/aims/elastic-si-rel-3/inputs/control.in.gz new file mode 100644 index 0000000000..13ba14cce4 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-3/inputs/control.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-3/inputs/geometry.in.gz b/tests/test_data/aims/elastic-si-rel-3/inputs/geometry.in.gz new file mode 100644 index 0000000000..d1480c369e Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-3/inputs/geometry.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-3/inputs/parameters.json b/tests/test_data/aims/elastic-si-rel-3/inputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-3/inputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-3/outputs/aims.out.gz b/tests/test_data/aims/elastic-si-rel-3/outputs/aims.out.gz new file mode 100644 index 0000000000..ffbf228777 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-3/outputs/aims.out.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-3/outputs/parameters.json b/tests/test_data/aims/elastic-si-rel-3/outputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-3/outputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-3/outputs/transformations.json b/tests/test_data/aims/elastic-si-rel-3/outputs/transformations.json new file mode 100644 index 0000000000..1fcbc6925e --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-3/outputs/transformations.json @@ -0,0 +1 @@ +{"@module": "pymatgen.alchemy.materials", "@class": "TransformedStructure", "charge": 0, "lattice": {"matrix": [[5.520641584100716, 0.0, 3.3636416509474475e-16], [8.877868772139066e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.520641584100716, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 166.58936909842265}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3801603960251791, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.438934386069533e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3801603960251796, 4.1199327675, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.760320792050358, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.140481188075537, 1.3733109225, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7603207920503583, 2.746621845, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.140481188075538, 4.1199327675, 4.1199327675], "properties": {}, "label": "Si"}], "history": [{"@module": "pymatgen.transformations.standard_transformations", "@class": "DeformStructureTransformation", "@version": null, "deformation": [[1.004987562112089, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], "input_structure": {"@module": "pymatgen.core.structure", "@class": "Structure", "charge": 0, "lattice": {"matrix": [[5.49324369, 0.0, 3.3636416509474475e-16], [8.833809598082263e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 165.7626177465493}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.1199327675, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.3733109225, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.746621845, 2.7466218450000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.1199327675, 4.119932767500001], "properties": {}, "label": "Si"}]}, "output_parameters": {}}], "last_modified": "2024-06-03 21:24:30.661017+00:00", "other_parameters": {}, "@version": null} diff --git a/tests/test_data/aims/elastic-si-rel-4/inputs/control.in.gz b/tests/test_data/aims/elastic-si-rel-4/inputs/control.in.gz new file mode 100644 index 0000000000..4e75df4442 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-4/inputs/control.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-4/inputs/geometry.in.gz b/tests/test_data/aims/elastic-si-rel-4/inputs/geometry.in.gz new file mode 100644 index 0000000000..e09ee4de0c Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-4/inputs/geometry.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-4/inputs/parameters.json b/tests/test_data/aims/elastic-si-rel-4/inputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-4/inputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-4/outputs/aims.out.gz b/tests/test_data/aims/elastic-si-rel-4/outputs/aims.out.gz new file mode 100644 index 0000000000..9c59cbb617 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-4/outputs/aims.out.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-4/outputs/parameters.json b/tests/test_data/aims/elastic-si-rel-4/outputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-4/outputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-4/outputs/transformations.json b/tests/test_data/aims/elastic-si-rel-4/outputs/transformations.json new file mode 100644 index 0000000000..fa013f4d96 --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-4/outputs/transformations.json @@ -0,0 +1 @@ +{"@module": "pymatgen.alchemy.materials", "@class": "TransformedStructure", "charge": 0, "lattice": {"matrix": [[5.547904177478133, 0.0, 3.3636416509474475e-16], [8.921710366038215e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.547904177478133, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 167.41203765270998}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3869760443695334, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.460855183019108e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3869760443695338, 4.1199327675, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.7739520887390663, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1609281331086, 1.3733109225, 1.3733109225000002], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7739520887390667, 2.746621845, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.160928133108601, 4.1199327675, 4.1199327675], "properties": {}, "label": "Si"}], "history": [{"@module": "pymatgen.transformations.standard_transformations", "@class": "DeformStructureTransformation", "@version": null, "deformation": [[1.0099504938362078, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], "input_structure": {"@module": "pymatgen.core.structure", "@class": "Structure", "charge": 0, "lattice": {"matrix": [[5.49324369, 0.0, 3.3636416509474475e-16], [8.833809598082263e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 165.7626177465493}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.1199327675, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.3733109225, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.746621845, 2.7466218450000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.1199327675, 4.119932767500001], "properties": {}, "label": "Si"}]}, "output_parameters": {}}], "last_modified": "2024-06-03 21:25:58.698697+00:00", "other_parameters": {}, "@version": null} diff --git a/tests/test_data/aims/elastic-si-rel-5/inputs/control.in.gz b/tests/test_data/aims/elastic-si-rel-5/inputs/control.in.gz new file mode 100644 index 0000000000..d65d99e63c Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-5/inputs/control.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-5/inputs/geometry.in.gz b/tests/test_data/aims/elastic-si-rel-5/inputs/geometry.in.gz new file mode 100644 index 0000000000..f9cf9679c3 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-5/inputs/geometry.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-5/inputs/parameters.json b/tests/test_data/aims/elastic-si-rel-5/inputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-5/inputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-5/outputs/aims.out.gz b/tests/test_data/aims/elastic-si-rel-5/outputs/aims.out.gz new file mode 100644 index 0000000000..95c1fcb4f0 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-5/outputs/aims.out.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-5/outputs/geometry.in.next_step.gz b/tests/test_data/aims/elastic-si-rel-5/outputs/geometry.in.next_step.gz new file mode 100644 index 0000000000..ac38b60ee6 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-5/outputs/geometry.in.next_step.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-5/outputs/hessian.aims.gz b/tests/test_data/aims/elastic-si-rel-5/outputs/hessian.aims.gz new file mode 100644 index 0000000000..c6bd81078b Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-5/outputs/hessian.aims.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-5/outputs/parameters.json b/tests/test_data/aims/elastic-si-rel-5/outputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-5/outputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-5/outputs/transformations.json b/tests/test_data/aims/elastic-si-rel-5/outputs/transformations.json new file mode 100644 index 0000000000..a238a0f850 --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-5/outputs/transformations.json @@ -0,0 +1 @@ +{"@module": "pymatgen.alchemy.materials", "@class": "TransformedStructure", "charge": 0, "lattice": {"matrix": [[5.49324369, -6.7272833018948954e-18, 3.362968855330967e-16], [8.833809598082263e-16, 5.49324369, 3.362968855330967e-16], [0.0, -0.1098648738, 5.492144931375147]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.493243689999999, "alpha": 91.14599199838858, "beta": 90.0, "gamma": 90.0, "volume": 165.72946190708439}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, -0.0549324369, 2.7460724656875737], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.29091226715, 4.1191086985313605], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.6814844276654835e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.09246654905, 1.373036232843787], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, -3.3636416509474477e-18, 1.6814844276654835e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.34584470405, 1.373036232843787], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.6916894081, 2.7460724656875737], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.03753411215, 4.1191086985313605], "properties": {}, "label": "Si"}], "history": [{"@module": "pymatgen.transformations.standard_transformations", "@class": "DeformStructureTransformation", "@version": null, "deformation": [[1.0, 0.0, 0.0], [0.0, 1.0, -0.02], [0.0, 0.0, 0.999799979995999]], "input_structure": {"@module": "pymatgen.core.structure", "@class": "Structure", "charge": 0, "lattice": {"matrix": [[5.49324369, 0.0, 3.3636416509474475e-16], [8.833809598082263e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 165.7626177465493}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.1199327675, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.3733109225, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.746621845, 2.7466218450000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.1199327675, 4.119932767500001], "properties": {}, "label": "Si"}]}, "output_parameters": {}}], "last_modified": "2024-06-03 21:27:26.107315+00:00", "other_parameters": {}, "@version": null} diff --git a/tests/test_data/aims/elastic-si-rel-6/inputs/control.in.gz b/tests/test_data/aims/elastic-si-rel-6/inputs/control.in.gz new file mode 100644 index 0000000000..b062078a31 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-6/inputs/control.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-6/inputs/geometry.in.gz b/tests/test_data/aims/elastic-si-rel-6/inputs/geometry.in.gz new file mode 100644 index 0000000000..403575cfc6 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-6/inputs/geometry.in.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-6/inputs/parameters.json b/tests/test_data/aims/elastic-si-rel-6/inputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-6/inputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-6/outputs/aims.out.gz b/tests/test_data/aims/elastic-si-rel-6/outputs/aims.out.gz new file mode 100644 index 0000000000..98ad5af637 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-6/outputs/aims.out.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-6/outputs/geometry.in.next_step.gz b/tests/test_data/aims/elastic-si-rel-6/outputs/geometry.in.next_step.gz new file mode 100644 index 0000000000..4d56688245 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-6/outputs/geometry.in.next_step.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-6/outputs/hessian.aims.gz b/tests/test_data/aims/elastic-si-rel-6/outputs/hessian.aims.gz new file mode 100644 index 0000000000..dc7f3919e9 Binary files /dev/null and b/tests/test_data/aims/elastic-si-rel-6/outputs/hessian.aims.gz differ diff --git a/tests/test_data/aims/elastic-si-rel-6/outputs/parameters.json b/tests/test_data/aims/elastic-si-rel-6/outputs/parameters.json new file mode 100644 index 0000000000..7fbabcd09f --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-6/outputs/parameters.json @@ -0,0 +1 @@ +{"xc": "pbe", "relativistic": "atomic_zora scalar", "relax_geometry": "trm 1.000000e-03", "relax_unit_cell": "none", "k_grid": [2, 2, 2], "species_dir": "/home/purcellt/git/atomate2_test/test_private/tests/aims/species_dir/light", "compute_analytical_stress": true, "rlsy_symmetry": null} diff --git a/tests/test_data/aims/elastic-si-rel-6/outputs/transformations.json b/tests/test_data/aims/elastic-si-rel-6/outputs/transformations.json new file mode 100644 index 0000000000..df4699872c --- /dev/null +++ b/tests/test_data/aims/elastic-si-rel-6/outputs/transformations.json @@ -0,0 +1 @@ +{"@module": "pymatgen.alchemy.materials", "@class": "TransformedStructure", "charge": 0, "lattice": {"matrix": [[5.49324369, -3.3636416509474477e-18, 3.363473464660138e-16], [8.833809598082263e-16, 5.49324369, 3.363473464660138e-16], [0.0, -0.0549324369, 5.492969020948602]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.493243690000001, "alpha": 90.57296734485716, "beta": 90.0, "gamma": 90.0, "volume": 165.75432940844834}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, -0.02746621845, 2.746484510474301], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.332111594825, 4.119726765711452], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.681736732330069e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.106199658275, 1.3732422552371508], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, -1.6818208254737239e-18, 1.681736732330069e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.359577813275, 1.3732422552371508], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.71915562655, 2.746484510474301], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.078733439825, 4.119726765711452], "properties": {}, "label": "Si"}], "history": [{"@module": "pymatgen.transformations.standard_transformations", "@class": "DeformStructureTransformation", "@version": null, "deformation": [[1.0, 0.0, 0.0], [0.0, 1.0, -0.01], [0.0, 0.0, 0.9999499987499375]], "input_structure": {"@module": "pymatgen.core.structure", "@class": "Structure", "charge": 0, "lattice": {"matrix": [[5.49324369, 0.0, 3.3636416509474475e-16], [8.833809598082263e-16, 5.49324369, 3.3636416509474475e-16], [0.0, 0.0, 5.49324369]], "pbc": [true, true, true], "a": 5.49324369, "b": 5.49324369, "c": 5.49324369, "alpha": 90.0, "beta": 90.0, "gamma": 90.0, "volume": 165.7626177465493}, "properties": {}, "sites": [{"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.0, 0.5], "xyz": [0.0, 0.0, 2.746621845], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.25, 0.75], "xyz": [1.3733109225000002, 1.3733109225, 4.1199327675], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.0, 0.5, 0.0], "xyz": [4.4169047990411317e-16, 2.746621845, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.25, 0.75, 0.25], "xyz": [1.3733109225000006, 4.1199327675, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.0, 0.0], "xyz": [2.746621845, 0.0, 1.6818208254737238e-16], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.25, 0.25], "xyz": [4.1199327675, 1.3733109225, 1.3733109225000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.5, 0.5, 0.5], "xyz": [2.7466218450000004, 2.746621845, 2.7466218450000004], "properties": {}, "label": "Si"}, {"species": [{"element": "Si", "occu": 1}], "abc": [0.75, 0.75, 0.75], "xyz": [4.119932767500001, 4.1199327675, 4.119932767500001], "properties": {}, "label": "Si"}]}, "output_parameters": {}}], "last_modified": "2024-06-03 21:31:32.637130+00:00", "other_parameters": {}, "@version": null} diff --git a/tests/vasp/conftest.py b/tests/vasp/conftest.py index b8e665c640..81a41661c2 100644 --- a/tests/vasp/conftest.py +++ b/tests/vasp/conftest.py @@ -84,6 +84,15 @@ def mock_vasp( For examples, see the tests in tests/vasp/makers/core.py. """ + yield from _mock_vasp(monkeypatch, vasp_test_dir) + + +def _mock_vasp( + monkeypatch: MonkeyPatch, vasp_test_dir: Path +) -> Generator[Callable[[Any, Any], Any], None, None]: + """ + Isolated version of the mock_vasp fixture that can be used in other contexts. + """ def mock_run_vasp(*args, **kwargs): name = CURRENT_JOB.job.name @@ -94,7 +103,6 @@ def mock_run_vasp(*args, **kwargs): f"no reference directory found for job {name!r}; " f"reference paths received={_REF_PATHS}" ) from None - fake_run_vasp(ref_path, **_FAKE_RUN_VASP_KWARGS.get(name, {})) get_input_set_orig = VaspInputGenerator.get_input_set diff --git a/tutorials/__init__.py b/tutorials/__init__.py new file mode 100644 index 0000000000..c4feb74fef --- /dev/null +++ b/tutorials/__init__.py @@ -0,0 +1 @@ +"""Tutorials.""" diff --git a/tutorials/blob_storage.ipynb b/tutorials/blob_storage.ipynb new file mode 100644 index 0000000000..5fea8b446d --- /dev/null +++ b/tutorials/blob_storage.ipynb @@ -0,0 +1,218 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from atomate2.vasp.flows.core import StaticMaker\n", + "from jobflow import JobStore, run_locally\n", + "from maggma.stores import MemoryStore\n", + "from pymatgen.core import Structure\n", + "from mock_vasp import mock_vasp, TEST_DIR\n", + "from monty.json import MontyDecoder\n", + "from pymatgen.io.vasp import Chgcar\n", + "import numpy as np\n", + "\n", + "def decode(d):\n", + " return MontyDecoder().process_decoded(d)\n", + "\n", + "jobstore = JobStore(MemoryStore(), additional_stores={\"data\": MemoryStore()})\n", + "si_structure = Structure.from_file(TEST_DIR / \"structures\" / \"Si.cif\")\n", + "ref_paths = {\"static\": \"Si_band_structure/static\"}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Blob Storage\n", + "\n", + "While most of the output data from `atomate2` is serialized and stored in a MongoDB database, some objects exceed the 16MB limit for MongoDB documents and must be placed into blob storage. Objects like the electronic charge density (`Chgcar`) are routinely larger than this file size and requires special treatment. `jobflows` method of dealing with these objects this shown below:\n", + "\n", + "```python\n", + "@job(data=Chgcar)\n", + "def some_job():\n", + " # return a document/dictionary that contains a Chgcar\n", + " return dictionary\n", + "```\n", + "\n", + "where the argument to the `@job` decorator indicates that all `Chgcar` objects will be automaically dispatched to \n", + "\n", + "```python\n", + "JOB_STORE.additional_stores[\"data\"]\n", + "```\n", + "\n", + "Which should already be configured in your `jobflow.yaml` file.\n", + "\n", + "For more details on how `additional_store` works please check out this [example](https://github.com/materialsproject/jobflow/blob/main/examples/data_store.py).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "`atomate2` will automatically dispatch some well-known large objects to the `data` blob storage.\n", + "\n", + "A full list of the the objects that will automatically dispatched to blob storage can be found [here](https://github.com/materialsproject/atomate2/blob/22b2fa0f7152aa7716906da4cf08672b8960d45d/src/atomate2/vasp/jobs/base.py#L39-L52):\n", + "\n", + "\n", + "\n", + "A common usage case of object storage is in storing volumetric data from VASP outputs. The storage of volumetric data is turned off by default, but specific files can be turned on by setting the `task_document_kwargs` for any child class of `BaseVaspMaker`.\n", + "For example, to store the `CHGCAR` file, you would set the `task_document_kwargs` in StaticMaker as follows:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "static_maker = StaticMaker(task_document_kwargs={\"store_volumetric_data\": (\"chgcar\",)})\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that a valid list of object `Enum` values must be provided to `store_volumetric_data` in order to store the data. The list of valid objects can be found [here](https://github.com/materialsproject/emmet/blob/183d74c8ed640b64ba596eedbebba7072bc4f1af/emmet-core/emmet/core/vasp/calculation.py#L48)\n", + "\n", + "```python\n", + "class VaspObject(ValueEnum):\n", + " \"\"\"Types of VASP data objects.\"\"\"\n", + "\n", + " BANDSTRUCTURE = \"bandstructure\"\n", + " DOS = \"dos\"\n", + " CHGCAR = \"chgcar\"\n", + " AECCAR0 = \"aeccar0\"\n", + " AECCAR1 = \"aeccar1\"\n", + " AECCAR2 = \"aeccar2\"\n", + " TRAJECTORY = \"trajectory\"\n", + " ELFCAR = \"elfcar\"\n", + " WAVECAR = \"wavecar\"\n", + " LOCPOT = \"locpot\"\n", + " OPTIC = \"optic\"\n", + " PROCAR = \"procar\"\n", + "```\n", + "\n", + "\n", + "Using the `static_maker` we can create a job and execute it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# create the job\n", + "job = static_maker.make(si_structure)\n", + "# run the job in a mock vasp environment\n", + "# make sure to send the results to the temporary jobstore\n", + "with mock_vasp(ref_paths=ref_paths) as mf:\n", + " responses = run_locally(\n", + " job,\n", + " create_folders=True,\n", + " ensure_success=True,\n", + " store=jobstore,\n", + " raise_immediately=True,\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once the job completes, you can retrieve the full task document along with the serialized `Chgcar` object from the blob storage and reconstruct the `Chgcar` object using the `load=True` flag as shown below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "with jobstore as s:\n", + " result = s.get_output(job.uuid, load=True)\n", + "\n", + "chgcar = decode(result[\"vasp_objects\"][\"chgcar\"])\n", + "assert isinstance(chgcar, Chgcar)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, if the objects is too big to keep around while you are exploring the data structure, you can use the default `load=False` flag and only load the reference to the object. This will allow you to explore the data structure without loading the object into memory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with jobstore as s:\n", + " result_no_obj = s.get_output(job.uuid)\n", + "result_no_obj[\"vasp_objects\"]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then you can query for the object at any time using the `blob_uuid`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "seach_data = result_no_obj[\"vasp_objects\"][\"chgcar\"]\n", + "with jobstore.additional_stores[\"data\"] as s:\n", + " blob_data = s.query_one(criteria={\"blob_uuid\": seach_data[\"blob_uuid\"]})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we can deserialize the object again from the `data` subfield of the blob query result." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "chgcar2 = decode(blob_data[\"data\"])" + ] + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tutorials/mock_vasp.py b/tutorials/mock_vasp.py new file mode 100644 index 0000000000..adeb06dbca --- /dev/null +++ b/tutorials/mock_vasp.py @@ -0,0 +1,42 @@ +"""Mock VASP functions for executing tutorials.""" + +import contextlib +import os +import shutil +import sys +import tempfile +from collections.abc import Generator +from pathlib import Path + +from pytest import MonkeyPatch + +# load the vasp conftest +TEST_ROOT = Path(__file__).parent.parent / "tests" +TEST_DIR = TEST_ROOT / "test_data" +VASP_TEST_DATA = TEST_ROOT / "test_data/vasp" +sys.path.insert(0, str(TEST_ROOT / "vasp")) +from conftest import _mock_vasp # noqa: E402 + + +@contextlib.contextmanager +def mock_vasp(ref_paths: dict) -> Generator: + """Mock VASP functions. + + Parameters + ---------- + ref_paths (dict): A dictionary of reference paths to the test data. + + Yields + ------ + function: A function that mocks calls to VASP. + """ + for mf in _mock_vasp(MonkeyPatch(), TEST_ROOT / "test_data/vasp"): + fake_run_vasp_kwargs = {k: {"check_inputs": tuple()} for k in ref_paths} + old_cwd = os.getcwd() + new_path = tempfile.mkdtemp() + os.chdir(new_path) + try: + yield mf(ref_paths, fake_run_vasp_kwargs) + finally: + os.chdir(old_cwd) + shutil.rmtree(new_path)