Package: cp2k-input-tools
cp2k-input-toolsFully validating pure-python CP2K input file parsers including preprocessing capabilitiesAvailable commands (also available through an API, see below):cp2klint.. a CP2K input file linterfromcp2k.. create a JSON/YAML configuration file or anAiiDArun script from a CP2K input file (includes validation)tocp2k.. convert a JSON or YAML configuration back to CP2K's input file format (includes validation)cp2kgen.. generate new input files based on a given input file and expressions to change parameters programmaticallycp2kget.. get values from a CP2K input file (most likely a restart file) given a path of sections and attributecp2k-language-server.. aLanguage Server Protocolimplementation for the CP2K input file formatcp2k-datafile-lint.. linters for other CP2K-related data file formats (like pseudos and basissets)For a description of the JSON/YAML formats used, see below.RequirementsPython 3.6+https://pypi.org/project/transitions/https://pypi.org/project/pint/optional:https://pypi.org/project/ruamel.yaml/for YAML supportoptional:https://github.com/openlawlibrary/pyglsfor the cp2k-language-serverFor development:https://poetry.eustace.io/https://pytest.org/Ideahave a pure-python CP2K input file linter with proper syntax error reporting (context, etc.)a final & complete restart file parserbasis for an AiiDA CP2K project importertestbed for alternative import formats (YAML, JSON) for CP2Kpossible testbed for a re-implementation of the CP2K input parser itselfTODOsparser: improve error reporting with contextpreprocessor: don't lose original context when interpolating variablesparser: parsing the XML is slow (easily 70% of the time), pickle or generate Python code directly instead and keep XML parsing as fallbackparser: preserve comments when going to/from YAMLUsageInstallationYou will get most tools using simply:$pipinstallcp2k-input-toolsFor YAML support you should use$pipinstallcp2k-input-tools[yaml]and for the Language Server:$pipinstallcp2k-input-tools[lsp]Command Line InterfaceGenerate JSON, YAML or aiida-cp2k run script from a CP2K input file:$fromcp2k--helpusage: fromcp2k [-h] [-y] [-c] [-b BASE_DIR] [-t TRAFO] <file>Convert CP2K input to JSON (default) or YAMLpositional arguments:<file>                CP2K input fileoptional arguments:-h, --help            show this help message and exit-y, --yaml            output yaml instead of json-c, --canonical       use the canonical output format-b BASE_DIR, --base-dir BASE_DIRsearch path used for relative @include's-t TRAFO, --trafo TRAFOtransformation applied to key and section names (auto,upper, lower)Generate anaiida-cp2ktemplate run script:$fromcp2k--formataiida-cp2k-calctests/inputs/test01.inpAny key transformation function other than 'auto' is ignored when generating an aiida-cp2k run script templatefrom aiida.engine import runfrom aiida.orm import (load_code, Dict, StructureData)cp2k_code = load_code('...')#Structurestructure = StructureData(...)#Parametersparameters = Dict(dict={"FORCE_EVAL": {"DFT": {"KPOINTS": {"FULL_GRID": False,"PARALLEL_GROUP_SIZE": -1,"SCHEME": "MONKHORST-PACK 3 3 3","SYMMETRY": False,},"MGRID": {"CUTOFF": 1000.0,"REL_CUTOFF": 100.0,},"POISSON": {"PERIODIC": "XYZ",},"PRINT": {"OVERLAP_CONDITION": {"_": "ON","1-NORM": True,"DIAGONALIZATION": True,},},"QS": {"EPS_DEFAULT": 1e-16,"EXTRAPOLATION": "USE_GUESS","METHOD": "GAPW",},"SCF": {"SMEAR": {"_": True,"ELECTRONIC_TEMPERATURE": 300.0,"METHOD": "FERMI_DIRAC",},"ADDED_MOS": 40,"EPS_SCF": 1e-08,"MAX_SCF": 50,},"XC": {"XC_FUNCTIONAL": {"_": "PBE",},},"BASIS_SET_FILE_NAME": "./BASIS_SETS","POTENTIAL_FILE_NAME": "./POTENTIALS",},"SUBSYS": {"CELL": {"CELL_REF": {"A": "4.32947291598 0.0 0.0","B": "2.16473645799 3.7494335304 0.0","C": "2.16473645799 1.24981118034 3.53499983838","PERIODIC": "XYZ",},"A": "4.07419 0.0 0.0","B": "2.037095 3.52835204 0.0","C": "2.037095 1.17611735 3.32656221","PERIODIC": "XYZ",},"KIND": [{"_": "Ge","ELEMENT": "Ge","POTENTIAL": "ALL-q32","BASIS_SET": "ORB pob-TZVP",},],"TOPOLOGY": {"COORD_FILE_NAME": "./struct.xyz","COORD_FILE_FORMAT": "XYZ",},},"METHOD": "QUICKSTEP",},"GLOBAL": {"PRINT_LEVEL": "MEDIUM","PROJECT_NAME": "fatman.calc","RUN_TYPE": "ENERGY",},})#Constructprocessbuilder.builder = cp2k_code.get_builder()builder.structure = structurebuilder.parameters = parametersbuilder.code = cp2k_codebuilder.metadata.options.resources = {"num_machines": 1,"num_mpiprocs_per_machine": 1,}builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60run(builder)Generate a CP2K input file from a JSON or YAML:$tocp2k--helpusage: tocp2k [-h] [-y] <file>Convert JSON or YAML input to CP2Kpositional arguments:<file>      JSON or YAML input fileoptional arguments:-h, --help  show this help message and exit-y, --yamlLint a CP2K input file:$cp2klinttests/inputs/unterminated_var.inpSyntax error: unterminated variable, in tests/inputs/unterminated_var.inp:line   36: @IF ${HP~~~~^Generate input files for aCUTOFFconvergence study (multiple expressions will be combined as a cartesian product):$cp2kgentests/inputs/NaCl.inp"force_eval/dft/mgrid/cutoff=[800,900,1000]"Writing 'NaCl-cutoff_800.inp'...Writing 'NaCl-cutoff_900.inp'...Writing 'NaCl-cutoff_1000.inp'...$diff-NaurbNaCl-cutoff_800.inpNaCl-cutoff_900.inp--- NaCl-cutoff_800.inp	2019-10-21 18:52:09.994323474 +0200+++ NaCl-cutoff_900.inp	2019-10-21 18:52:10.680996641 +0200@@ -69,7 +69,7 @@POTENTIAL_FILE_NAME ALL_POTENTIALS&MGRIDREL_CUTOFF 80.0-         CUTOFF 800+         CUTOFF 900NGRIDS 6&END MGRID&XCGet a value from a CP2K input file, for example aRESTARTfile generated in a cell optimization:$cp2kgettests/inputs/NaCl.inp"force_eval/subsys/cell/a/0"force_eval/subsys/cell/a/0: 5.64123539364476APIConvert a CP2K input file to a nested Python dictionary:fromcp2k_input_tools.parserimportCP2KInputParser,CP2KInputParserSimplifiedcanonical=Falseifcanonical:parser=CP2KInputParser()else:parser=CP2KInputParserSimplified()withopen("project.inp")asfhandle:tree=parser.parse(fhandle)Convert a nested Python dictionary back to a CP2K input file:fromcp2k_input_tools.generatorimportCP2KInputGeneratorgenerator=CP2KInputGenerator()tree={"global":{}}# ... the input treewithopen("project.inp","w")asfhandle:forlineingenerator.line_iter(tree):fhandle.write(f"{line}\n")Language Server ProtocolThe executable providing the language server is:cp2k-language-serverForvimyou need a plugin to be able to use language servers. One such plugin isALEfor which you can create in its directory the fileale_linters/cp2k/language_server.vimwith the contentcallale#Set('cp2k_lsp_executable','cp2k-language-server')function!ale_linters#cp2k#language_server#GetProjectRoot(buffer)abortletl:git_path=ale#path#FindNearestDirectory(a:buffer,'.git')return!empty(l:git_path)? fnamemodify(l:git_path,':h:h'):''endfunctioncallale#linter#Define('cp2k',{
\'name':'language_server',\'lsp':'stdio',\'executable': {b->ale#Var(b,'cp2k_lsp_executable')},\'project_root':function('ale_linters#cp2k#language_server#GetProjectRoot'),\'command':'%e',\})Afterwards you must set the filetype when editing a CP2K input file tocp2kto get it running. This can be done explicitly using:set filetype=cp2k.The CP2K JSON and YAML formatsA reference to the CP2K input format can be found here:https://manual.cp2k.org/Canonical formatFor everything except the pre-processor capabilities (@IF/@ENDIF/$var/@SET) there is a canonical one-to-one mapping of the CP2K input format to either JSON or YAML:repeatable sections are mapped to dictionarieskeywords or subsections are key/value entries in sectionsall repeatable elements (sections and keywords) are mapped to lists of their respective mapped datatypesection parameters are mapped to a special key named_default section keywords are mapped to a special key name*sections in JSON or YAML must be prefixed to avoid double definition of a key in case of same name for a section and a keyword (like thePOTENTIALinKIND), to avoid quotation marks, instead of CP2K's&we are using the+keyword values are mapped based on their datatypes: a list of values is always mapped to a list of their respective datatypesThe following example input:&GLOBAL
   PRINT_LEVEL MEDIUM
   PROJECT test
   RUN_TYPE ENERGY
&END GLOBAL
&FORCE_EVAL
   METHOD Quickstep
   &DFT
      BASIS_SET_FILE_NAME "./BASIS_SETS"
      POTENTIAL_FILE_NAME ./POTENTIALS
      &XC
         &XC_FUNCTIONAL PBE
         &END XC_FUNCTIONAL
      &END XC
   &END DFT
   &SUBSYS
      &CELL
         A [angstrom] 4.07419 0.0 0.0
         B [angstrom] 2.037095 3.52835204 0.0
         C [angstrom] 2.037095 1.17611735 3.32656221
         PERIODIC XYZ
      &END CELL
      &KIND Ge
         ELEMENT Ge
         POTENTIAL ALL-q32
         BASIS_SET ORB pob-TZVP
      &END KIND
      &TOPOLOGY
         COORD_FILE ./struct.xyz
         COORD_FILE_FORMAT XYZ
      &END TOPOLOGY
   &END SUBSYS
&END FORCE_EVALwould generate the (canonical) JSON:{"+global":{"print_level":"medium","project_name":"test","run_type":"energy"},"+force_eval":[{"method":"quickstep","+DFT":{"basis_set_file_name":["./BASIS_SETS"],"potential_file_name":"./POTENTIALS"},"+XC":{"+xc_functional":{"_":"PBE"}},"+subsys":{"cell":{"A":[4.07419,0,0],"B":[2.037095,3.52835204,0],"C":[2.037095,1.17611735,3.32656221],"periodic":"XYZ"},"+kind":[{"_":"Ge","element":"Ge","potential":"ALL-q32","basis_set":[["ORB","pob-TZVP"]]}],"+topology":{"coord_file_name":"./struct.xyz","coord_file_format":"XYZ"}}}]}Caveats:the full input format needs be known and is being loaded from a bundledcp2k_input.xmlthe YAML/JSON is quiet verbose and one has to know exactly which keywords can be repeatedWhile there is no solution to remedy the first caveat, the second can be solved with the simplified output formatSimplified formatStill based on the canonical format the simplified format relaxes some of the rulesa section must only be prefixed with a+if a keyword with the same name is present at the same time in the same section (since we can figure out whether the user wanted to specify the section or the keyword by inspecting the value for the key:dictfor a section)if a repeated keyword or section contains only one entry, the list can be omitted (in case of ambiguity priority is given to multiple values per keyword rather than keyword repetition)sections with default parameters can be formulated as dictionaries, as long as the default parameter values are unique and do not match section keyword or subsection namesthe example from before in the simplified format:{"global":{"print_level":"medium","project_name":"test","run_type":"energy"},"force_eval":{"method":"quickstep","DFT":{"basis_set_file_name":"./BASIS_SETS","potential_file_name":"./POTENTIALS"},"xc":{"xc_functional":{"_":"PBE"}},"subsys":{"cell":{"A":[4.07419,0,0],"B":[2.037095,3.52835204,0],"C":[2.037095,1.17611735,3.32656221],"periodic":"XYZ"},"kind":{"_":"Ge","element":"Ge","potential":"ALL-q32","basis_set":["ORB","pob-TZVP"]},"topology":{"coord_file_name":"./struct.xyz","coord_file_format":"XYZ"}}}}or in YAML (with simplification rule #3 applied):global:print_level:mediumproject_name:testrun_type:energyforce_eval:DFT:basis_set_file_name:./BASIS_SETSpotential_file_name:./POTENTIALSXC:xc_functional:_:PBE# this can NOT be simplified since PBE could also be a subsection of xc_functionalmethod:quickstepsubsys:cell:A:[4.07419,0.0,0.0]B:[2.037095,3.52835204,0.0]C:[2.037095,1.17611735,3.32656221]periodic:XYZkind:Ge:basis_set:[ORB,pob-TZVP]element:Gepotential:ALL-q32topology:coord_file_format:XYZcoord_file_name:./struct.xyz