From e365d8ca35d2da34e5ed4d1d306e3f980f8568bd Mon Sep 17 00:00:00 2001 From: Sergei Kliavinek Date: Mon, 25 Nov 2024 10:49:08 -0800 Subject: [PATCH] Script generator for Perturbo (#64) * add generation for script in the perturbopy functional * fix flake8 * organize input generation as a terminal command * remove comment in cyrillic * update description of variables in the code and add documenation on the input_generation command * fix flake8 * move scripts for the perturbo-docs to the perturbopy --- MANIFEST.in | 1 + docs/perturbo_docs/f90tools.py | 578 +++++++++++++++++ docs/perturbo_docs/files_description.yml | 225 +++++++ docs/perturbo_docs/htmltools.py | 396 ++++++++++++ docs/perturbo_docs/input_parameters.py | 95 +++ docs/perturbo_docs/interactive_workflow.py | 588 ++++++++++++++++++ docs/perturbo_docs/workflow.yml | 166 +++++ docs/source/index.rst | 1 + docs/source/input_generation.rst | 66 ++ setup.py | 7 +- src/perturbopy/generate_input/__init__.py | 1 + .../generate_input/generate_input.py | 340 ++++++++++ .../input_parameters_perturbo.yml | 381 ++++++++++++ .../input_parameters_qe2pert.yml | 177 ++++++ .../generate_input/input_template.yml | 164 +++++ 15 files changed, 3185 insertions(+), 1 deletion(-) create mode 100644 docs/perturbo_docs/f90tools.py create mode 100644 docs/perturbo_docs/files_description.yml create mode 100755 docs/perturbo_docs/htmltools.py create mode 100755 docs/perturbo_docs/input_parameters.py create mode 100755 docs/perturbo_docs/interactive_workflow.py create mode 100644 docs/perturbo_docs/workflow.yml create mode 100644 docs/source/input_generation.rst create mode 100644 src/perturbopy/generate_input/__init__.py create mode 100755 src/perturbopy/generate_input/generate_input.py create mode 100644 src/perturbopy/generate_input/input_parameters_perturbo.yml create mode 100644 src/perturbopy/generate_input/input_parameters_qe2pert.yml create mode 100644 src/perturbopy/generate_input/input_template.yml diff --git a/MANIFEST.in b/MANIFEST.in index a7447ce..5d0abe9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ recursive-include src/perturbopy *.cfg +recursive-include src/perturbopy/generate_input *.yml diff --git a/docs/perturbo_docs/f90tools.py b/docs/perturbo_docs/f90tools.py new file mode 100644 index 0000000..049e4c8 --- /dev/null +++ b/docs/perturbo_docs/f90tools.py @@ -0,0 +1,578 @@ +#!/usr/bin/env python3 +""" +Tools to generate the Fortran source code files +""" + +import os +import re +import datetime +import collections + +from yaml import load, dump +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + +def fortran_bcast_variable(param_name, fout, processid='meta_ionode_id', commid='world_comm'): + """ + Print a Fortran `mpi broadcast` statement. + + Parameters + ----- + param_name: str + Name of the parameter + + processid: str + ID of the process which broadcasts the data + + commid: + ID of the communicator + + fout: output file + Text file of the f90 source code + + + Returns + ----- + None + + """ + declare_indent = ' ' * 3 + fout.write( (f'{declare_indent}call mp_bcast({param_name},{processid},{commid})\n') ) + +def fortran_init_variable(param_name, param_type, param_default_value, fout, dim = ''): + """ + Print a Fortran `variable assignment` statement for automatically generating input variables from yaml file. + + Parameters + ----- + param_name: str + Name of the parameter + + param_type: str + Fortran type of the parameter + + param_default_value: formatted + Default value of the parameter + + fout: output file + Text file of the f90 source code + + dim: + Dimension of a vector + + description: + Description of the variable for doxygen + + Returns + ----- + None + + Raises + ----- + ValueError if parameter is unknown + + """ + + declare_indent = ' ' * 3 + + param_default_value_assign = param_default_value + if dim is not None and (not dim == ''): + # only one-dimensional array are implemented. + if type(param_default_value)== str and param_default_value[0] == '(': + if param_type == 'logical': + param_default_value_assign = param_default_value_assign.replace('(','').replace(')','').strip().split(',') + for iva in range(len(default_value)): + param_default_value_assign[iva] = fortran_bool(bool(default_value[iva])) + param_default_value_assign = '[' + ','.join(f'{ii}' for ii in default_value) + ']' + else: + param_default_value_assign = param_default_value_assign.replace('(','[').replace(')',']') + elif param_type == 'logical': + param_default_value_assign = fortran_bool(param_default_value_assign) + else: + if param_type == 'logical': + param_default_value_assign = fortran_bool(param_default_value_assign) + elif param_type == 'real': + param_default_value_assign = str(param_default_value_assign) + '_dp' + + fout.write( f"{declare_indent}{param_name} =" + f" {param_default_value_assign}\n" + ) + +def fortran_declare_variable(param_name, param_type, param_attr, param_len, fout, dim = '', description = ''): + """ + Print a Fortran `variable declaration` statement for automatically generating input variables from yaml file. + + Parameters + ----- + param_name: str + Name of the parameter + + param_type: str + Fortran type of the parameter + + param_attr: str + Fortran attributes for a new variable when declaration + + param_len: Int + Length of the string for Character datetype + + fout: output file + Text file of the f90 source code + + dim: + Dimension of a vector + + description: + Description of the variable for doxygen + + Returns + ----- + None + + Raises + ----- + ValueError if parameter is unknown + + """ + + declare_indent = ' ' * 3 + + if param_type == 'string': + declare_type = f'character(len={param_len})' + + elif param_type == 'logical': + declare_type = 'logical' + + elif param_type == 'integer': + declare_type = 'integer' + + elif param_type == 'real': + declare_type = 'real(dp)' + + else: + raise ValueError(f'Wrong param_type {param_type}') + + if param_attr is not None: + fout.write( f"{declare_indent}{declare_type}" + f", {param_attr}" + f" :: {param_name}{dim}" + f" !< {description}\n" + ) + else : + fout.write( f"{declare_indent}{declare_type}" + f" :: {param_name}{dim}" + f" !< {description}\n" + ) + +def fortran_write(param_name, param_type, unit, fout, + dim = None, bcast_name = None): + """ + Print a Fortran `write` statement + + Parameters + ----- + param_name: str + Name of the parameter + + param_type: str + Fortran type of the parameter + + unit: str + Fortran file unit where the write statement will output + + fout: output file + Text file of the f90 source code + + dim: + Dimension of a vector + + bcast_name: + Name of a variable in the code (if different from param_name) + + Returns + ----- + None + + Raises + ----- + ValueError if parameter is unknown + + """ + + print_indent = ' ' * 3 + write_indent = 6 + write_space = 10 + + write_value = param_name + + if param_type == 'string': + write_value = f'trim({param_name})' + write_format = 'a' + + elif param_type == 'logical': + write_value = f'python_bool({param_name})' + write_format = 'a' + + elif param_type == 'integer': + write_format = 'i10' + + elif param_type == 'real': + write_format = 'es23.16' + + else: + raise ValueError(f'Wrong param_type {param_type}') + + # In the case if the name in the code is different from the name in the + # input file, just substitue the param_name with bcast_name + if bcast_name is not None: + write_value = re.sub(param_name, bcast_name, write_value) + + if dim is not None: + # only one-dimensional array are implemented. + # otherwise, int(...) will raise an Error + dim_int = int(dim.replace('(','').replace(')','')) + + vec_format = '\"[\",' + + vec_format += f'{dim_int}({write_format},\",\"2x)' + + vec_format += ',\"]\"' + + write_format = vec_format + + fout.write( f"{print_indent}write(" + f"{unit},'({write_indent}x, a, {write_space}x, {write_format})')" + f" '{param_name}:', {write_value}\n" + ) + +def print_header(fout): + """ + Print header, information how to properly modify the file + + Parameters + ----- + fout : output file + file where to print the header + """ + + fout.write( (f'! This file was automatically generated by the' + f' {os.path.basename(__file__)} Python script\n' + f'! from the ./utils folder.\n' + f'! To do any modifications, please modify the' + f' YAML files in the ./docs folder or the script directly.\n' + f'! NOTE THAT the modifications will be erased when' + f' you run the Python script again.\n' + f'! Date: {datetime.datetime.now().strftime("%B %d, %Y %H:%M")}\n\n' + ) + ) + + +def fortran_bool(trueornot): + """ + convert python bool to fortran bool + + Parameters + ----- + trueornot: str + logically true or not in Python + + Returns + ----- + fortran_bool_type: str ['.true.', '.false.'] + logically true or not in Fortran + """ + + if trueornot: + return '.true.' + elif not trueornot: + return '.false.' + else: + raise ValueError(f'Wrong param_type {trueornot}') + +def write_param_to_yaml(folder, input_param_path, code_prefix): + """ + Generate an f90 file to print out all of the input parameters of Perturbo + + Parameters + ----- + input_param_path: str + path to a YAML files with the input parameters + code_prefix: str + name of the executable (without `.x`). `perturbo` or `qe2pert` + folder: str + A folder where the f90 file should be placed + + Returns + ----- + None + """ + + with open(input_param_path,'r') as stream: + input_param_dict = load(stream,Loader=Loader) + + # sort + input_param_dict = collections.OrderedDict(sorted(input_param_dict.items())) + + + f90filename = os.path.join(folder,f'param_to_yaml_{code_prefix}.f90') + + unit = 'ymlout' + + with open(f90filename, 'w') as f90file: + + print_header(f90file) + + f90file.write( (f'module {code_prefix}_autogen_output_yaml\n') ) + f90file.write( (f' use yaml_utils, only: ymlout, python_bool\n') ) + if code_prefix == 'perturbo': + f90file.write( (f' use pert_param\n') ) + elif code_prefix == 'qe2pert': + f90file.write( (f' use input_param\n') ) + else: + raise ValueError(f'{code_prefix} can not be recognised and you may need to add an elif branch here!') + f90file.write( (f' implicit none\n') ) + f90file.write( (f' private\n\n') ) + f90file.write( (f' public :: auto_output_beforeconv_to_yaml\n') ) + f90file.write( (f' public :: auto_output_afterconv_to_yaml\n') ) + + f90file.write( (f'\ncontains\n') ) + f90file.write( (f'subroutine auto_output_afterconv_to_yaml()\n') ) + f90file.write( (f' implicit none\n') ) + + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + + if 'output' in param_dict.keys() and not param_dict['output']: + continue + + # some names used in the code are not the same as the names read + # from input + if 'bcast_name' in param_dict.keys(): + bcast_name = param_dict['bcast_name'] + else: + bcast_name = None + + param_type = param_dict['type'] + + dim = param_dict.get('dimensions', None) + + fortran_write(param_name, param_type, unit, f90file, + dim = dim, bcast_name = bcast_name) + + f90file.write( (f'\nend subroutine auto_output_afterconv_to_yaml\n\n') ) + + # before unit conversion + f90file.write( (f'! the "before conversion" variabls has not been broadcast to other nodes, so it can just be used in master (io) node.\n') ) + f90file.write( (f'subroutine auto_output_beforeconv_to_yaml()\n') ) + f90file.write( (f' implicit none\n') ) + + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + + if 'output' in param_dict.keys() and not param_dict['output']: + continue + + # here is different with the "after conversion", we just keep the variables on the master node + # also here use a poor-man trick + bcast_name = param_name + '_beforeconv' + ## some names used in the code are not the same as the names read + ## from input + #if 'bcast_name' in param_dict.keys(): + # bcast_name = param_dict['bcast_name'] + #else: + # bcast_name = None + + param_type = param_dict['type'] + + dim = param_dict.get('dimensions', None) + + fortran_write(param_name, param_type, unit, f90file, + dim = dim, bcast_name = bcast_name) + + f90file.write( (f'\nend subroutine auto_output_beforeconv_to_yaml\n\n') ) + # normal keywords for module + f90file.write( (f'end module {code_prefix}_autogen_output_yaml\n') ) + + +def autogen_declare_init_bcast_inputvariables(folder, input_param_path, code_prefix): + """ + Generate an f90 file to declare all of the input parameters of Perturbo + + Parameters + ----- + folder: str + A folder where the f90 file should be placed + input_param_path: str + path to a YAML files with the input parameters + code_prefix: str + name of the executable (without `.x`). `perturbo` or `qe2pert` + + Returns + ----- + None + """ + + with open(input_param_path,'r') as stream: + input_param_dict = load(stream,Loader=Loader) + + # sort + input_param_dict = collections.OrderedDict(sorted(input_param_dict.items())) + + + f90filename = os.path.join(folder,f'autogen_param_{code_prefix}.f90') + + with open(f90filename, 'w') as f90file: + + print_header(f90file) + + # normal keywords for module + f90file.write( (f'module {code_prefix}_autogen_param\n') ) + if code_prefix == 'perturbo': + f90file.write( (f' use pert_const, only: dp\n') ) + elif code_prefix == 'qe2pert': + f90file.write( (f' use kinds, only: dp\n') ) + f90file.write( (f' use io_files, only: prefix\n') ) + else: + raise ValueError(f'{code_prefix} can not be recognised and you may need to add an elif branch here!') + f90file.write( (f' implicit none\n') ) + + cnt_param = 0 + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + cnt_param += 1 # do not shift this counting line below if-conditional line for "param_source" + + param_source = param_dict.get('source', None) + + if param_source is not None and param_source != f'{code_prefix}': + continue + + param_type = param_dict['type'] + + param_attr = param_dict.get('attributes', None) + + param_len = param_dict.get('len', None) + + dim = param_dict.get('dimensions', '') + + description = param_dict.get('description',' Not yet') + + fortran_declare_variable(param_name, param_type, param_attr, param_len, f90file, dim = dim, description=description) + + f90file.write('\n') + + # before conversion + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + + param_type = param_dict['type'] + + param_attr = param_dict.get('attributes', None) + + param_len = param_dict.get('len', None) + + dim = param_dict.get('dimensions', '') + + description = param_dict.get('description',' Not yet') + + param_name += '_beforeconv' + description += " (before conversion of the unit)" + + fortran_declare_variable(param_name, param_type, param_attr, param_len, f90file, dim = dim, description=description) + + + # namelist + f90file.write( (f'\n namelist / {code_prefix} / & \n') ) + cnt = 0 + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + cnt += 1 + if cnt < cnt_param : + f90file.write( (f' {param_name}, & \n') ) + else: + f90file.write( (f' {param_name}\n') ) + + + + + f90file.write( (f'\ncontains\n') ) + f90file.write( (f'subroutine autogen_init_input_param()\n') ) + f90file.write( (f' implicit none\n') ) + + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + + param_value_default = param_dict.get('default', None) + + if param_value_default is None: + continue + + param_type = param_dict['type'] + + dim = param_dict.get('dimensions', '') + + fortran_init_variable(param_name, param_type, param_value_default, f90file, dim = dim) + + f90file.write( (f'\nend subroutine autogen_init_input_param\n\n') ) + + # broadcast from the main process + f90file.write( (f'subroutine autogen_bcast_input_param()\n') ) + + + + + if code_prefix == 'perturbo': + f90file.write( (f' use qe_mpi_mod, only: meta_ionode_id, world_comm, mp_bcast\n') ) + elif code_prefix == 'qe2pert': + f90file.write( (f' use io_global, only: ionode_id\n' + f' use mp_world, only: world_comm\n' + f' use mp, only: mp_bcast\n') ) + else: + raise ValueError(f'{code_prefix} can not be recognised and you may need to add an elif branch here!') + f90file.write( (f' implicit none\n\n') ) + + if code_prefix == 'perturbo': + param_bcast_processid, param_bcast_comm = 'meta_ionode_id', 'world_comm' + elif code_prefix == 'qe2pert': + param_bcast_processid, param_bcast_comm = 'ionode_id', 'world_comm' + else: + raise ValueError(f'{code_prefix} can not be recognised and you may need to add an elif branch here!') + + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + + fortran_bcast_variable(param_name, f90file, processid=param_bcast_processid, commid=param_bcast_comm) + + f90file.write( (f'\nend subroutine autogen_bcast_input_param\n\n') ) + + # store the data before conversion of the unit. + f90file.write( (f'subroutine autogen_input_param_beforeconv()\n') ) + f90file.write( (f' implicit none\n') ) + + assign_indent = ' ' * 3 + for param_name, param_dict in input_param_dict.items(): + + if param_dict['type'] == 'family': + continue + + f90file.write( (f'{assign_indent}{param_name}_beforeconv = {param_name}\n') ) + + f90file.write( (f'\nend subroutine autogen_input_param_beforeconv\n\n') ) + + # normal keywords for module + f90file.write( (f'end module {code_prefix}_autogen_param\n') ) diff --git a/docs/perturbo_docs/files_description.yml b/docs/perturbo_docs/files_description.yml new file mode 100644 index 0000000..f82a8ad --- /dev/null +++ b/docs/perturbo_docs/files_description.yml @@ -0,0 +1,225 @@ +--- +# This is a yaml file that contains the description of files required for PERTURBO calcation modes. + +phdir: + type: directory + description: Directory where the phonon "save" directory is located. + obtained from: DFPT + +prefix_centres.xyz: + type: text + description: Atomic positions and Wannier centres. Please refer to Wannier90 documentation for more details. + obtained from: DFT (Wannier90) + +prefix_u.mat: + type: text + description: $$U(\mathbf{k})$$ matrix - a unitary matrix that mixes the Bloch states at each $$\mathbf{k}$$. Please refer to Wannier90 documentation for more details. + obtained from: DFT (Wannier90) + +prefix_u_dis.mat: + type: text + description: $$U^{dis}(\mathbf{k})$$ matrix. Please refer to Wannier90 documentation for more details. + obtained from: DFT (Wannier90) + +prefix_epr.h5: + type: HDF5 + description: Electron-phonon matrix elements on a coarse Brillouin zone grid as well as in the Wannier basis. + obtained from: qe2pert + format example: mydoc_qe2pert.html#eprh5-file-structure + +prefix_band.kpt: + type: text + description: $$\mathbf{k}$$ point list file. + format example: mydoc_interpolation.html#fklist_file + +prefix_phdisp.qpt: + type: text + description: $$\mathbf{q}$$ point list file. + format example: mydoc_interpolation.html#fklist_file + +prefix.temper: + type: text + description: List of temperatures, chemical potentials, and carrier concentrations. + format example: mydoc_scattering.html#ftemper_file + obtained from: setup + +prefix_tet.kpt: + type: text + description: Coordinates (in crystal units) of the irreducible $$\mathbf{k}$$ points in the energy window of interest. + obtained from: setup + +prefix_tet.h5: + type: HDF5 + description: Contains information on the $$\mathbf{k}$$ points (both in the irreducible wedge and full grid) and the associated $$\mathbf{k}$$ point tetrahedra in the energy window of interest. + obtained from: setup + +prefix.bands: + type: text + description: Interpolated band structure. + obtained from: bands + format example: mydoc_interpolation.html#bands_file + deprecated: True + +prefix.phdisp: + type: text + description: Interpolated phonon dispersion. + obtained from: phdisp + format example: mydoc_interpolation.html#phdisp_file + deprecated: True + +prefix.ephmat: + type: text + description: Absolute values of the electron-phonon matrix elements summed over bands from band_min to band_max. + obtained from: ephmat + format example: mydoc_interpolation.html#ephmat_file + deprecated: True + +prefix.doping: + type: text + description: Chemical potentials and carrier concentrations for each tempearture specified in the prefix.temper file. + obtained from: setup + deprecated: True + +prefix.dos: + type: text + description: Density of states (number of states per eV per unit cell) as a function of energy (eV). + obtained from: setup + deprecated: True + +prefix.imsigma: + type: text + description: Imaginary part of the electron-phonon self-energy. + obtained from: imsigma + format example: mydoc_scattering.html#imsigma_file + deprecated: True + +prefix.imsigma_mode: + type: text + description: Imaginary part of the electron-phonon self-energy (where phonon modes are numbered for increasing energy values). + obtained from: imsigma + format example: mydoc_scattering.html#imsigma_file + deprecated: True + +prefix.mfp: + type: text + description: Relaxation time and mean free path of each electronic state. + obtained from: meanfp + format example: mydoc_scattering.html#meanfp_file + deprecated: True + +prefix.vel: + type: text + description: Band velocity of each state. + obtained from: meanfp + format example: mydoc_scattering.html#meanfp_file + deprecated: True + +prefix.cond: + type: text + description: Conductivity and mobility tensors as a function of temperature. + obtained from: trans + format example: mydoc_trans.html#trans_file + deprecated: True + +prefix.tdf: + type: text + description: Transport distribution function (TDF) as a function of carrier energy and temperature. + obtained from: trans + format example: mydoc_trans.html#trans_file + deprecated: True + +prefix_tdf.h5: + type: HDF5 + description: Includes all information of the transport distribution function (TDF) for each temperature. + obtained from: trans + +prefix_cdyna.h5: + type: HDF5 + description: Contains all information about a real-time dynamics simulation. + obtained from: dynamics-run + format example: mydoc_dynamics.html#cdyna_h5_file + +prefix_cdyna.dat: + type: text + description: Number of carriers per unit cell as a function of time. + obtained from: dynamics-pp + deprecated: True + +prefix_popu.h5: + type: HDF5 + description: Contains the carrier population as a function of energy and time. + obtained from: dynamics-pp + format example: mydoc_dynamics.html#popu_h5_file + +prefix.trans_coef: + type: text + description: Seebeck coefficient. + obtained from: trans-pp + format example: mydoc_trans.html#trans-pp_file + deprecated: True + +input file: + type: text + description: File containing the input parameters. A typical input file for this calculation mode is given below. + +# YAML output files +qe2pert_output.yml: + type: YAML + description: Output of the qe2pert calculation. + obtained from: qe2pert + +prefix_bands.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: bands + format example: mydoc_interpolation.html#bands_output_yaml + +prefix_phdisp.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: phdisp + format example: mydoc_interpolation.html#phdisp_output_yaml + +prefix_ephmat.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: ephmat + format example: mydoc_interpolation.html#ephmat_output_yaml + +prefix_imsigma.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: imsigma + format example: mydoc_scattering.html#imsigma_output_yaml + +prefix_setup.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: setup + format example: mydoc_scattering.html#setup_output_yaml + +prefix_meanfp.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: meanfp + format example: mydoc_scattering.html#meanfp_output_yaml + +prefix_trans.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: trans + format example: mydoc_trans.html#trans_rta_output_yaml + +prefix_dynamics-run.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: dynamics-run + format example: mydoc_dynamics.html#dynamics-run_output_yaml + +prefix_dynamics-pp.yml: + type: YAML + description: Output data from the calculation, including the input parameters and the quantities of interest. The file can be processed by the Perturbopy Python suite. + obtained from: dynamics-pp + format example: mydoc_dynamics.html#dynamics-pp_output_yaml + +... diff --git a/docs/perturbo_docs/htmltools.py b/docs/perturbo_docs/htmltools.py new file mode 100755 index 0000000..c30b9ab --- /dev/null +++ b/docs/perturbo_docs/htmltools.py @@ -0,0 +1,396 @@ +#!/usr/bin/env python3 +""" +Tools for the HTML output +""" + +import os +import re +import datetime + +from yaml import load, dump +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + +def get_mandatory_optional(param,input_data,executable): + if param in ['prefix','calc_mode']: + return 'Mandatory for all calculation types.' + elif param in ['output_yaml','yaml_fname']: + return 'Optional for all calculation types.' + else: + #loop over the calculation types + mand_list = [] + opt_list = [] + for calc_mode in input_data.keys(): + if param in input_data[calc_mode]['mandatory'].keys(): + mand_list.append(calc_mode) + if 'optional' in input_data[calc_mode].keys(): + if param in input_data[calc_mode]['optional'].keys(): + opt_list.append(calc_mode) + + text = '' + prefix = '' + if executable == 'perturbo': + calc_mode_link = 'calc_mode' + prefix = ' '+calc_mode_link+':' + + if mand_list: + text = text + 'Mandatory for'+prefix+\ + ''+' '*2 + for i, tt in enumerate(mand_list): + text = text + '' + tt + '' + if i < len(mand_list)-1: + text = text + ', ' + if i == 6: + text = text + '
' + text = text + '\n' + + if opt_list: + text = text + 'Optional for'+prefix+\ + ''+' '*2 + for i, tt in enumerate(opt_list): + text = text + '' + tt + '' + if i < len(opt_list)-1: + text = text + ', ' + if i == 6: + text = text + '
' + text = text + '\n' + + return text + + +def write_parameter_info(fout,key,value,color,family_desc,input_data,executable): + """ + write the information about a parameter + """ + # For the link + fout.write('\n') + + # The parameter box starts here + fout.write('
\n') + fout.write('
'+family_desc.upper() +'
\n') + fout.write(''+key+' \n ') + + fout.write('
'*2+'\n') + fout.write('Variable type: '+value['type']+'
\n') + + if 'default' in value.keys(): + fout.write('Default value: '+print_value(value['default'])+'
\n') + + if 'typical' in value.keys() and key != 'prefix': + fout.write('Typical value: '+print_value(value['typical'])+'
\n') + + if 'dimensions' in value.keys(): + fout.write('Dimensions: '+print_value(value['dimensions'])+'
\n') + + if 'units' in value.keys(): + fout.write('Units: '+print_value(value['units'])+'
\n') + + if 'options' in value.keys(): + options = value['options'] + fout.write('Options:
\n') + for opt_key,opt_value in options.items(): + fout.write('
\n') + fout.write(print_value(opt_key)+'\n') + fout.write('
\n') + + fout.write('
\n') + fout.write(str(opt_value)) + fout.write('
\n') + + fout.write('
\n') + + fout.write('
'+'\n') + fout.write(value['description']) + + if key == 'calc_mode': + fout.write(' To see the typical input files for different calculation modes, click here.') + + fout.write('
'*2) + + # Mandatory/Optional box + fout.write('') + fout.write('
') + mand_opt_text = get_mandatory_optional(key,input_data,executable) + fout.write(mand_opt_text) + fout.write('
') + # End of mandatory/Optional box + + # End of box + fout.write('
\n') + fout.write('
\n') + + +def lightendarken(color_hsl,percentage): + h0 = color_hsl[0] + s0 = color_hsl[1] + l0 = color_hsl[2] + + p = percentage/100.0 + + if p <= 0.0: + s = s0 * (1+p) + l = l0 - p * (100-l0) + else: + s = s0 + p * (100-s0) + l = l0 * (1-p) + + return 'hsl('+str(h0)+','+str(s)+'%,'+str(l)+'%)' + + +def print_value(value): + if type(value) is bool: + if value is True: + return ''+'.true.'+'' + else: + return ''+'.false.'+'' + else: + return ''+str(value)+'' + + +def write_header(fout,fout_name,title): + """ + Print the markdown-style header + """ + fout.write('---'+'\n') + fout.write('title: '+title+'\n') + fout.write('sidebar: mydoc_sidebar'+'\n') + fout.write('last_updated: '+datetime.date.today().strftime("%B %d, %Y")+'\n') + fout.write('permalink: '+os.path.basename(fout_name)+'\n') + fout.write('folder: mydoc'+'\n') + fout.write('toc: false'+'\n') + fout.write('---'+'\n') + fout.write(''+'\n'*2) + + +def create_html_table(yaml_dict,input_data,html_path,fout_name,title,executable): + fout = open(html_path+fout_name,'w') + + # input_param is a python dictionary read from the yaml file + # it contains all the necessary information about the input parameters + with open(yaml_dict, 'r') as stream: + input_param = load(stream,Loader=Loader) + + write_header(fout,fout_name,title) + + fout.write('\n') + fout.write('\n') + # include the css styles file + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + + family_list = [] + for key,value in input_param.items(): + if value['type'] == 'family' and value['type'] not in family_list: + family_list.append(key) + + # + # loop over families + # + # List all the variables that belong to this family + for family in family_list: + + if len(family_list) > 1: + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + fout.write('\n') + + for key,value in input_param.items(): + if 'family' in value.keys() and value['family'] == family: + + fout.write('\n') + + fout.write('\n') + + fout.write('\n') + + fout.write('\n') + + fout.write('\n') + + fout.write('\n') + + fout.write('
'+input_param[family]['description']+'
NameTypeDescription
\n') + fout.write('\n') + fout.write(''+key+'\n') + fout.write(''+value['type']+'\n') + fout.write(value['description']+'
') + if 'default' in value.keys(): + fout.write('

Default: '+print_value(value['default'])+'

') + if 'typical' in value.keys() and key != 'calc_mode': + fout.write('

Typical: '+print_value(value['typical'])+'

') + if 'dimenstions' in value.keys(): + fout.write('

Dimenstions: '+print_value(value['dimenstions'])+'

') + if 'options' in value.keys(): + fout.write('

Options: '+str(list(map(print_value,list(value['options'].keys()))))+'

') + fout.write('
\n') + fout.write('\n') + fout.write('\n') + fout.close() + + +def create_html_file(yaml_dict,input_data,html_path,fout_name,title,executable): + fout = open(html_path+fout_name,'w') + + # input_param is a python dictionary read from the yaml file + # it contains all the necessary information about the input parameters + with open(yaml_dict, 'r') as stream: + input_param = load(stream,Loader=Loader) + + write_header(fout,fout_name,title) + + fout.write('\n') + fout.write('\n') + # include the css styles file + fout.write('') + fout.write('\n') + fout.write('\n') + + # + # List the fimilies + # + # Get the list of all families in the given yaml dictionary + family_list = [] + color_list = [] + for key,value in input_param.items(): + if value['type'] == 'family' and value['type'] not in family_list: + family_list.append(key) + color_list.append(value['color_hsl']) + + # + # FIRST loop over families + # + # List all the variables that belong to this family + for family in family_list: + color = input_param[family]['color_hsl'] + fout.write('

'+input_param[family]['description']+'

\n

\n') + + fout.write('| ') + for key,value in input_param.items(): + if 'family' in value.keys() and value['family'] == family: + fout.write(''+key+' | '+'\n') + + # + # SECOND loop over families + # + # + # Write the detailed description of each famility + # + fout.write('


\n') + + for family in family_list: + color = input_param[family]['color_hsl'] + family_desc = input_param[family]['description'] + + if len(family_list) > 1: + fout.write('  '+input_param[family]['description']+'\n
\n
\n') + + for key,value in input_param.items(): + if 'family' in value.keys() and value['family'] == family: + write_parameter_info(fout,key,value,color,family_desc,input_data,executable) + + fout.write('
'*2) + + fout.write('\n') + fout.write('\n') + fout.close() + + +def print_inputs_to_html(fout,id_prefix,calc_mode_list): + """ launch the generate_input.py script for all calc modes and print the output in a HTML file""" + for calc_mode in calc_mode_list: + os.system('input_generation -c '+calc_mode+' -i '+'tmp.in > /dev/null') + + fout.write(''+'\n'*2) + os.system('rm tmp.in') + #fout.write('\n') + #fout.write('\n') + +def print_select_button_header(fout_name, yaml_dict): + """ + Print the header of the select button for the input examples HTML page + """ + + with open('../../src/perturbopy/generate_input/input_parameters_perturbo.yml', 'r') as stream: + param_data_perturbo = load(stream,Loader=Loader) + + # For the code blocks,
 
could be also a solution. + + fex = open(fout_name,'w') + + list_calc_mode = ['qe2pert']+list(param_data_perturbo['calc_mode']['options'].keys()) + + # create the drop down box + fex.write('
\n') + fex.write('\n') + fex.write('

To get a typical input file without running the script, select the calculation type here: ') + fex.write('\n') + # copy to clipboard button + #fex.write('\n') + fex.write('

\n') + + #fex.write('
'*2+'\n'*2) + + id_prefix = 'modeblock' + print_inputs_to_html(fex,id_prefix,list_calc_mode) diff --git a/docs/perturbo_docs/input_parameters.py b/docs/perturbo_docs/input_parameters.py new file mode 100755 index 0000000..46ae459 --- /dev/null +++ b/docs/perturbo_docs/input_parameters.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# This Python script automatically generates the mydoc_param_qe2pert.html +# and mydoc_param_perturbo.html files. + +import os +import sys + +import htmltools +import f90tools + +from yaml import load, dump +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + + +def main(): + + # path to the directory where the html file should be placed + # copy manually the generated .html files to pages/mydoc/ directory of the + # perturbo site repository + + html_path = './' + + input_template = '../../src/perturbopy/generate_input/input_template.yml' + with open(input_template,'r') as stream: + input_data = load(stream,Loader=Loader) + + # + # Parameters for qe2pert.x + # + # name of the html page + fout_name = './mydoc_param_qe2pert.html' + # name of the yaml file that contains the info about the input parameters + yaml_dict = '../../src/perturbopy/generate_input/input_parameters_qe2pert.yml' + # title of the html page + title = 'Quantum Espresso to PERTURBO input parameters' + + print('Generating '+fout_name+' ...') + htmltools.create_html_file(yaml_dict,input_data,html_path,fout_name,title,'qe2pert') + + fout_name = './mydoc_table_input_parameters_qe2pert.html' + print('Generating '+fout_name+' ...') + htmltools.create_html_table(yaml_dict,input_data,html_path,fout_name,title,'qe2pert') + + # + # Parameters for perturbo.x + # + fout_name = './mydoc_param_perturbo.html' + yaml_dict = '../../src/perturbopy/generate_input/input_parameters_perturbo.yml' + title = 'PERTURBO input parameters' + + print('Generating '+fout_name+' ...') + htmltools.create_html_file(yaml_dict,input_data,html_path,fout_name,title,'perturbo') + + fout_name = './mydoc_table_input_parameters_perturbo.html' + print('Generating '+fout_name+' ...') + htmltools.create_html_table(yaml_dict,input_data,html_path,fout_name,title,'perturbo') + + # + # Generate the f90 files + # + print('Generating f90 files ...') + + # For perturo.x: output + print('param_to_yaml_perturbo.f90') + input_param_path = '../../src/perturbopy/generate_input/input_parameters_perturbo.yml' + f90tools.write_param_to_yaml('./', input_param_path, 'perturbo') + + print('autogen_param_perturbo.f90') + # For perturo.x: auto generation of vairable declaration + f90tools.autogen_declare_init_bcast_inputvariables('./', input_param_path, 'perturbo') + + # For qe2pert.x + print('param_to_yaml_qe2pert.f90') + input_param_path = '../../src/perturbopy/generate_input/input_parameters_qe2pert.yml' + f90tools.write_param_to_yaml('./', input_param_path, 'qe2pert') + + # For qe2pert.x: auto generation of vairable declaration + print('autogen_param_qe2pert.f90') + f90tools.autogen_declare_init_bcast_inputvariables('./', input_param_path, 'qe2pert') + # + # Input files HTML page generation + # + + # Move the generated input_examples.html file to _includes directory of the site. + # mv input_examples.html ~/github/perturbo-code.github.io/_includes + + fout_name = 'input_examples.html' + print('Generating '+fout_name+' ...') + htmltools.print_select_button_header(fout_name, yaml_dict) + +if __name__ == '__main__': + main() diff --git a/docs/perturbo_docs/interactive_workflow.py b/docs/perturbo_docs/interactive_workflow.py new file mode 100755 index 0000000..ef0afd0 --- /dev/null +++ b/docs/perturbo_docs/interactive_workflow.py @@ -0,0 +1,588 @@ +#!/usr/bin/env python3 +""" +This script reads the PERTURBO workflow information from the ../docs/workflow.yml file and +generates the interactive html page. +To run the script a user should first install Graphviz and then pygraphviz. +Installation for Mac: +brew install graphviz +pip install --install-option="--include-path=/usr/local/include/" --install-option="--library-path=/usr/local/lib/" pygraphviz + +: +brew install graphviz +brew info graphviz +export GRAPHVIZ_DIR="/usr/local/Cellar/graphviz/" +pip install pygraphviz --global-option=build_ext --global-option="-I$GRAPHVIZ_DIR/include" --global-option="-L$GRAPHVIZ_DIR/lib" + +To generate the Interactive Workflow webpage: +1. run the script +./interactive_workflow.py + +2. copy the .html page to the site repository +cp mydoc_interactive_workflow.html ~/github/perturbo-code.github.io/pages/mydoc + +3. copy the diagram to the site repository +cp graph.svg ~/github/perturbo-code.github.io/images + +""" + +import os, re, sys, datetime +import pygraphviz as pgv + +from htmltools import print_inputs_to_html + +from yaml import load, dump +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle + +############################################################################################ +def create_graph_dict(data_dict): + """ + Create a graph Python dictionary of dictionaries from the workflow YAML file + """ + graph_dict = {} + interactive_nodes = [] + non_interactive_nodes = [] + for calc_mode in data_dict.keys(): + dd = data_dict[calc_mode] + + # Find all parents + d_tmp = {} + if 'parents' in dd.keys(): + for par in dd['parents']: + d_tmp[par] = None + + if 'non-interactive' in dd.keys(): + if dd['non-interactive'] == True: + non_interactive_nodes.append(calc_mode) + else: + interactive_nodes.append(calc_mode) + else: + interactive_nodes.append(calc_mode) + + graph_dict[calc_mode] = d_tmp + + return graph_dict, interactive_nodes, non_interactive_nodes +############################################################################################ + + + +# +# Load the files description files +# +workflow_filename = 'files_description.yml' + +with open(workflow_filename,'r') as stream: + files_desc_dict = load(stream,Loader=Loader) + +# +# Load the workflow.yml file +# +workflow_filename = 'workflow.yml' + +with open(workflow_filename,'r') as stream: + workflow_dict = load(stream,Loader=Loader) + + +graph_dict, interactive_nodes, non_interactive_nodes = create_graph_dict(workflow_dict) + +print('Interactive nodes:', interactive_nodes) +print('Non-interactive nodes: ',non_interactive_nodes) + +A=pgv.AGraph(graph_dict,strict=False,directed=True).reverse() + + +A.node_attr['shape']='rectangle' +#A.edge_attr['color']='red' + +# Make non-interactive nodes elliptical +for node in non_interactive_nodes: + n = A.get_node(node) + n.attr['shape']='ellipse' + #n.attr['color']='gray' + +# Make the connections between the optional parents +for calc_mode in workflow_dict.keys(): + if 'optional parents' in workflow_dict[calc_mode].keys(): + optional_parents = workflow_dict[calc_mode]['optional parents'] + for opt_parent in optional_parents: + # constraint=false will not change the hierarchy for the nodes + A.add_edge(opt_parent,calc_mode,style='dashed', constraint='false') + +# parameters for the separation between nodes: pad="0.5", nodesep="1", ranksep="2" +A.graph_attr['nodesep'] = 0.5 + +A.graph_attr['rankdir']='LR' + +#A.graph_attr['size'] = "120,30" + +#A.graph_attr.update(size="6,6") + +#dpi = 150 +#A.graph_attr['dpi'] = dpi + +# Possible layouts: +# neato, dot, twopi, circo, fdp, nop, wc, acyclic, gvpr, gvcolor, ccomps, sccmap, tred, sfdp, unflatten +A.layout(prog='dot') + +#A.graph_attr.update(landscape='true',ranksep='0.1') + +rect_list=[] +for n in A.iternodes(): + w = float(n.attr['width']) #* dpi + h = float(n.attr['height']) #* dpi + x,y = list(map(float,n.attr['pos'].split(','))) + x1 = x - w/2 + x2 = x + w/2 + y1 = y - h/2 + y2 = y + h/2 + rect_list.append([x,y,w,h]) + #print(n.attr['pos'], n.attr['width'], n.attr['height']) + +#A.draw(path='graph.png') + +graph_filename = 'graph.svg' +A.draw(path=graph_filename) +A.draw(path='graph.png') + +# +# Parse the svg file to get coordinates of rectangles, get the coordinates from 'pos' is complicated +# because of complicated units. +# + +polygone_dict = {} + +with open(graph_filename,'r') as f: + lines = f.readlines() + for i,line in enumerate(lines): + #if 'width' in line: + # image_width = int(line.split('width=')[1].split()[0].strip('"pt')) + # image_height = int(line.split('height=')[1].split()[0].strip('"pt')) + if 'viewBox' in line: + image_width, image_height = list(map(float,line.split('viewBox=')[1].replace('"','').split()[2:4])) + if 'translate' in line: + x_offset, y_offset = list(map(float,re.sub(r'[()">]','',line.split('translate')[1]).split() )) + y_offset = image_height - y_offset + + # line example: + if '\n\n'.format(os.path.basename(__file__)) ) + +html.write('\n') +html.write('\n\n') + +html.write('') +html.write('\n\n') + +html.write('\n') +html.write('\n') +html.write('\n') +html.write('\n') +html.write('\n\n') + +html.write('\n') +html.write('\n\n') + +html.write('\n') +html.write('\n\n') + +html.write('\n\n') + + +html.write('\n\n') + +# +# Header text of the page +# +html.write('

To get the calculation mode requirements, outputs, and the input file, click on a calculation mode name in the graph below or select the calculation mode from the list (recommended for mobile devices): \n\n') +html.write('\n') +html.write('

\n') + +html.write('
\n'*2) +html.write('Workflow\n\n'.format(image_width,image_height)) + +html.write('\n') + +# +# Write the polygones coordinates for the HTML image map +# +for node,p in polygone_dict.items(): + left_bottom = p[1] + right_top = p[3] + xmin = left_bottom[0] + x_offset + xmax = right_top[0] + x_offset + + #ymin = -left_bottom[1] + y_offset + #ymax = -right_top[1] + y_offset + + ymin = left_bottom[1] - y_offset + image_height + ymax = right_top[1] - y_offset + image_height + + corner_dict[node] = '{},{},{},{}'.format(xmin,ymin,xmax,ymax) + + html.write(' {0:<15}\n'.format('"'+node+'"','"'+corner_dict[node]+'"')) + + # debug + #w = xmax - xmin + #h = ymax - ymin + #rect = Rectangle((xmin,ymin),w,h) + #ax.add_patch(rect) + +html.write('\n\n') + +html.write('
\n'*3) + +html.write('\n\n\n') +for node in interactive_nodes: + + # Title + html.write('\n\n') + + computes = workflow_dict[node]['computes'] + + tutorial_link = workflow_dict[node]['tutorial link'] + tutorial_link = f' See in tutorial.' + + # Replace $$...$$ with with Python re + computes = re.sub(r'\$\$(.+?)\$\$',r'',computes) + + computes = computes + tutorial_link + + html.write('\n'.format(node)) + html.write('\n\n') + + +html.write('
\n') + +# +# === Require and Output === +# + +html.write('\n\n\n') +for node in interactive_nodes: + + html.write('\n'.format(node)) + + html.write('\n\n') # End Require and Output div block + + +# +# === Files description === +# +html.write('
\n') + +html.write('\n\n\n') + +html.write('\n\n'.format(node)) # End hide_file_desc_block + +# +# ======================================================================================= +# + + +html.write('\n\n\n') +html.write('
\n') +print_inputs_to_html(html,id_prefix,interactive_nodes) + +html.write('\n\n') +html.write('\n') + +# debug +#ax.set_xlim(0,image_width) +#ax.set_ylim(0,image_height) +#plt.savefig('rectangles.svg') +#plt.show() + diff --git a/docs/perturbo_docs/workflow.yml b/docs/perturbo_docs/workflow.yml new file mode 100644 index 0000000..72cc546 --- /dev/null +++ b/docs/perturbo_docs/workflow.yml @@ -0,0 +1,166 @@ +--- +# This is a yaml file that contains the PERTURBO workflow information. +# It is used to generate the interactive workflow. + +DFT: + non-interactive: True + +DFPT: + non-interactive: True + +qe2pert: + computes: E-ph matrix elements on the coarse $$\mathbf{k}$$ point (determined by the nscf step) and $$\mathbf{q}$$ point (determined by the phonon step) Brillouin zone grids as well as in the Wannier basis. + parents: + - DFT + - DFPT + requirements: + - phdir + - prefix_centres.xyz + - prefix_u.mat + - prefix_u_dis.mat + outputs: + - qe2pert_output.yml + - prefix_epr.h5 + tutorial link: mydoc_qe2pert.html + +bands: + parents: + - qe2pert + computes: Interpolated electronic band structure given an electronic crystal momentum path. + requirements: + - prefix_epr.h5 + - prefix_band.kpt + outputs: + - prefix_bands.yml + - prefix.bands + tutorial link: mydoc_interpolation.html#calc_mode_bands + +phdisp: + parents: + - qe2pert + computes: Interpolated phonon dispersions along a given crystal momentum path. + requirements: + - prefix_epr.h5 + - prefix_phdisp.qpt + outputs: + - prefix_phdisp.yml + - prefix.phdisp + tutorial link: mydoc_interpolation.html#calc_mode_phdisp + +ephmat: + parents: + - qe2pert + computes: The absolute values of the e-ph matrix elements, summed over the number of electronic bands, given two lists of $$\mathbf{k}$$ and $$\mathbf{q}$$ points. In a typical scenario, one computes the e-ph matrix elements for a chosen $$\mathbf{k}$$ point as a function of $$\mathbf{q}$$ point. + requirements: + - prefix_epr.h5 + - prefix_band.kpt + - prefix_phdisp.qpt + outputs: + - prefix_ephmat.yml + - prefix.ephmat + tutorial link: mydoc_interpolation.html#calc_mode_ephmat + +imsigma: + parents: + - qe2pert + optional parents: + - setup + computes: The imaginary part of the lowest-order (so-called 'Fan') e-ph self-energy, $$\operatorname{Im}\Sigma$$, for states in a range of bands and with crystal momenta $$\mathbf{k}$$ read from a list (this list can be obtained from calc_mode='setup' or created manually). The scattering rates can also be obtained using $${2} \operatorname{Im}\Sigma /{\hbar}$$. + requirements: + - prefix_epr.h5 + - prefix_tet.kpt + - prefix.temper + outputs: + - prefix_imsigma.yml + - prefix.imsigma + - prefix.imsigma_mode + tutorial link: mydoc_scattering.html#calc_mode_imsigma + +setup: + parents: + - qe2pert + computes: Set up transport property calculations (i.e., electrical conductivity, carrier mobility and Seebeck) by providing $$\mathbf{k}$$ points, $$\mathbf{k}$$ point tetrahedra and (if needed) finding chemical potentials for given carrier concentrations. + requirements: + - prefix_epr.h5 + - prefix.temper + outputs: + - prefix_setup.yml + - prefix.doping + - prefix_tet.h5 + - prefix_tet.kpt + - prefix.dos + tutorial link: mydoc_scattering.html#calc_mode_setup + +meanfp: + parents: + - imsigma + computes: The e-ph mean free paths for electronic states in a user-defined $$\mathbf{k}$$ point list and range of bands. + requirements: + - prefix_epr.h5 + - prefix_tet.kpt + - prefix.temper + - prefix.imsigma + outputs: + - prefix_meanfp.yml + - prefix.mfp + - prefix.vel + tutorial link: mydoc_scattering.html#calc_mode_meanfp + +trans: + parents: + - setup + optional parents: + - imsigma + computes: The phonon-limited conductivity and carrier mobility. + requirements: + - prefix_epr.h5 + - prefix.temper + - prefix_tet.h5 + optional files: + - prefix.imsigma + outputs: + - prefix_trans.yml + - prefix.cond + - prefix.tdf + - prefix_tdf.h5 + tutorial link: mydoc_trans.html#calc_mode_trans + +trans-pp: + parents: + - trans + computes: Seebeck coefficient. Note that phonon drag effects are not included in this calculation. + requirements: + - prefix_epr.h5 + - prefix.temper + - prefix_tet.h5 + - prefix_tdf.h5 + outputs: + - prefix.trans_coef + tutorial link: mydoc_trans.html#calc_mode_trans-pp + +dynamics-run: + parents: + - setup + computes: "Ultrafast hot carrier dynamics via the time-dependent Boltzmann transport equation: set an initial carrier distribution and calculate its evolution in time." + requirements: + - prefix_epr.h5 + - prefix.temper + - prefix_tet.h5 + outputs: + - prefix_dynamics-run.yml + - prefix_cdyna.h5 + tutorial link: mydoc_dynamics.html#calc_mode_dynamics-run + +dynamics-pp: + parents: + - dynamics-run + computes: "Postprocessing of the ultrafast dynamics calculations: carrier population as a function of energy and time." + requirements: + - prefix_epr.h5 + - prefix_cdyna.h5 + outputs: + - prefix_dynamics-pp.yml + - prefix_cdyna.dat + - prefix_popu.h5 + tutorial link: mydoc_dynamics.html#calc_mode_dynamics-pp +... diff --git a/docs/source/index.rst b/docs/source/index.rst index 5903680..2fb36b8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -31,4 +31,5 @@ Contents Usage Postprocessing Testsuite + Input generation API reference diff --git a/docs/source/input_generation.rst b/docs/source/input_generation.rst new file mode 100644 index 0000000..8b21289 --- /dev/null +++ b/docs/source/input_generation.rst @@ -0,0 +1,66 @@ +Automatic Generation of Input Files for Perturbo +================================================ + +The PERTURBO code has many calculation modes (specified by the `calc_mode `_ variable). Each calculation mode implies different mandatory and optional input parameters. In order to simplify and systematize the input files for the user, Perturbopy package conatin command ``input_generation``, which generates the PERTURBO input files for different calculation modes. + +To use the script, just go to the folder, where you want to generate the file, and run the command (suppose, that we generate the input file for the calculation mode `ephmat`): + +.. code-block:: console + + $ input_generation --calc_mode ephmat + +For a shorter version, one can specify ``-c`` instead of ``--calc_mode``. + +Then, the input file (called by default *pert.in*) is generated: + +.. code-block:: console + + ! This input file for PERTURBO was generated by Perturbopy + ! Date: November 20, 2024 14:42 + + &perturbo + ! ***Mandatory parameters*** + calc_mode = 'ephmat' + prefix = 'prefix' + fklist = 'prefix.kpt' + fqlist = 'prefix.qpt' + + + ! ***Optional parameters*** + ! band_min = 1 + ! band_max = 9999999 + ! phfreq_cutoff = 1.0 + / + + +.. code-block:: python + ! This input file for PERTURBO was generated by Perturbopy + ! Date: November 20, 2024 14:42 + + &perturbo + ! ***Mandatory parameters*** + calc_mode = 'ephmat' + prefix = 'prefix' + fklist = 'prefix.kpt' + fqlist = 'prefix.qpt' + + + ! ***Optional parameters*** + ! band_min = 1 + ! band_max = 9999999 + ! phfreq_cutoff = 1.0 + / + +It contains a block of mandatory parameters for this calculation mode and a block of optional ones, which is commented. As one can see, this input file containes some *typical* values for the input parameters. The user should modify them for a given calculation. + +Setting the variables is also possible using the scipt. For example, to set ``prefix`` to `'si'` and ``band_min`` to `'10'`, run: + +.. code-block:: console + + $ input_generation -c ephmat --prefix si --band_min 10 + +The values of these parameters were changed in the *pert.in* file. Note, that since we specified an optional parameter ``band_min``, it was uncommented in the input file. + +To change the name of the input file, run the script with ``-i your_name.in`` option. Setting the input parameter values from the scipt could be usefull in the case, when one needs to create automatically many different input files. + +In order to generate the input files for the ``qe2pert.x`` calcuation, select ``-c qe2pert``. Run the script with ``-h`` to get the whole list of possible options. diff --git a/setup.py b/setup.py index 8e78142..afd9ab0 100644 --- a/setup.py +++ b/setup.py @@ -27,5 +27,10 @@ packages=find_packages( where='./src' ), - package_dir={"": "src"} + package_dir={"": "src"}, + entry_points={ + 'console_scripts': [ + 'input_generation=perturbopy.generate_input:input_generation', + ], + }, ) diff --git a/src/perturbopy/generate_input/__init__.py b/src/perturbopy/generate_input/__init__.py new file mode 100644 index 0000000..f43e4b9 --- /dev/null +++ b/src/perturbopy/generate_input/__init__.py @@ -0,0 +1 @@ +from .generate_input import input_generation diff --git a/src/perturbopy/generate_input/generate_input.py b/src/perturbopy/generate_input/generate_input.py new file mode 100755 index 0000000..2c768a4 --- /dev/null +++ b/src/perturbopy/generate_input/generate_input.py @@ -0,0 +1,340 @@ +import datetime +import os +import sys +import numpy as np +import argparse +import re +from ast import literal_eval + +from yaml import load, dump +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + + +def set_default(param_name, param_data, executable): + """ + Define the default value for the provided calculation + parameter + + Parameters + ---------- + param_name : str + name of the considering parameter + executable : str + name of the executable module ('perturbo' or 'qe2pert') + param_data : dict + + + Returns + ------- + default or typical value of the corresponding parameter + + """ + if 'default' in param_data[executable][param_name].keys(): + return param_data[executable][param_name]['default'] + + elif 'typical' in param_data[executable][param_name].keys(): + return param_data[executable][param_name]['typical'] + + else: + sys.exit('Each variable must contain \'default\' or \'typical field\' in yaml file') + + +def get_description(description): + """ + Return description without the formating symbols + Parameters + ---------- + description : str + description of the calculation parameter + + + Returns + ------- + desc : str + description without the formating symbols + + """ + desc = re.sub(r'', '', description, flags=re.DOTALL) + desc = re.sub(r'<.*?code>', '', desc, flags=re.DOTALL) + desc = re.sub(r']+>', '', desc, flags=re.DOTALL) + return desc + + +def create_arg_namespace(param_data, input_data): + """ + Function that returns a dictionary with all the calculation parameters. + + Parameters + ---------- + param_data : dict + dictionary with all arguments, their description and type + input_data : dict + dictionary with all calculation modes and corresponding arguments + + + Returns + ------- + parser.parse_args() : argparse.Namespace + dictionary with the calculation parameters as keys. + if value was passed to the program, it's assigned to + the corresponding key. Otherwise, value is None + + """ + list_calc_mode = input_data.keys() + + help_description = ( + "Generate an exemplified input file for the PERTURBO code. You can find " + "description of all calculated parameters at the PERTURBO official webpage " + "https://perturbo-code.github.io/" + ) + + parser = argparse.ArgumentParser(description=help_description) + parser.add_argument( + '-c', '--calc_mode', metavar='Mode', help=f'Calculation mode. Options: {", ".join(list_calc_mode)}.', + choices=list_calc_mode, required=True) + + parser.add_argument('-i', '--file_name', metavar='file name', help='Name of the input file.') + + # add all perturbo parameters as arguments, expcept calc_mode + for key, value in param_data['perturbo'].items(): + if key == 'calc_mode': + continue + if value['type'] == 'family': + continue + + # description for the help. remove , , * + description = get_description(value['description']) + if 'default' in value: + description = f'{description} Default value is {value["default"]}.' + if 'typical' in value: + description = f'{description} Typical value is {value["typical"]}.' + parser.add_argument('--' + key, metavar=f'type={value["type"]}', help=description) + + # add all qe2pert parameters as arguments, except repeated_parameters + for key, value in param_data['qe2pert'].items(): + repeated_parameters = ['prefix', 'debug', 'output_yaml', 'yaml_fname'] + if key in repeated_parameters: + continue + if value['type'] == 'family': + continue + + # description for the help. remove , , * + description = get_description(value['description']) + if 'default' in value: + description = f'{description} Default value is {value["default"]}.' + if 'typical' in value: + description = f'{description} Typical value is {value["typical"]}.' + parser.add_argument('--' + key, metavar=f'type={value["type"]}', help=description) + + return parser.parse_args() + + +def write_parameter_to_input(finput, param, executable, args, param_data, optional=False): + """ + Function that write the calculation to the input file + + Parameters + ---------- + finput : _io.TextIOWrapper + variable, which corresponds to the input file + param : str + name of the input parameter + executable : str + name of the executable module ('perturbo' or 'qe2pert') + args : argparse.Namespace + in dictionary of this variable saved all names of + calculation parameters and provided values + param_data : dict + dictionary with all arguments, their description and type + optional : bool + optional of mandatory parameter for the calculation + + + + Returns + ------- + None + + """ + + if optional: + if args.__dict__[param] is None: + str_key = '! ' + str(param) + param_value = set_default(param, param_data, executable) + else: + str_key = ' ' + str(param) + param_value = args.__dict__[param] + else: + str_key = ' ' + str(param) + if args.__dict__[param] is None: + param_value = set_default(param, param_data, executable) + else: + param_value = args.__dict__[param] + + param_type = param_data[executable][param]['type'] + + # Dimensions + if 'dimensions' in param_data[executable][param].keys(): + try: + dimensions = int(param_data[executable][param]['dimensions'].replace('(', '').replace(')', '')) + except ValueError: + dimensions = 1 + else: + dimensions = 1 + + # Units + if 'units' in param_data[executable][param].keys(): + units = param_data[executable][param]['units'] + else: + units = None + + if param_type == 'string': + if param_value == "''": + finput.write('{:20} = \'\'\n'.format(str_key)) + else: + # Replace prefix if it was specified + if args.__dict__['prefix'] is not None: + param_value = re.sub('prefix', args.__dict__['prefix'], param_value) + # finput.write('{:20} = \'{}\'\n'.format(str_key,param_value)) + finput.write('{:20} = {}\n'.format(str_key, param_value)) + + elif param_type == 'logical': + true_false = param_value + if type(true_false) is not bool: + if 'true' in true_false.lower(): + true_false = True + else: + true_false = False + + if true_false: + finput.write('{:20} = .true.\n'.format(str_key)) + else: + finput.write('{:20} = .false.\n'.format(str_key)) + + elif dimensions != 1: + default_tuple = literal_eval(param_value) + for dim in range(dimensions): + finput.write('{:20} = {}\n'.format(str_key + '(' + str(dim + 1) + ')', default_tuple[dim])) + else: + if units: + finput.write('{:20} = {:<15} ! {}\n'.format(str_key, param_value, units)) + else: + finput.write('{:20} = {:}\n'.format(str_key, param_value)) + + +def input_generation(): + """ + Function that write the calculation to the input file + + Parameters + ---------- + finput : _io.TextIOWrapper + variable, which corresponds to the input file + param : str + name of the input parameter + executable : str + name of the executable module ('perturbo' or 'qe2pert') + args : argparse.Namespace + in dictionary of this variable saved all names of + calculation parameters and provided values + param_data : dict + dictionary with all arguments, their description and type + optional : bool + optional of mandatory parameter for the calculation + + + + Returns + ------- + None + + """ + module_dir = os.path.dirname(__file__) + param_qe2pert = os.path.join(module_dir, 'input_parameters_qe2pert.yml') + param_perturbo = os.path.join(module_dir, 'input_parameters_perturbo.yml') + input_template = os.path.join(module_dir, 'input_template.yml') + + param_data = {} + + # Read the yaml files + with open(param_qe2pert, 'r') as stream: + param_data['qe2pert'] = load(stream, Loader=Loader) + + with open(param_perturbo, 'r') as stream: + param_data['perturbo'] = load(stream, Loader=Loader) + + with open(input_template, 'r') as stream: + input_data = load(stream, Loader=Loader) + + # Parse the command line + args = create_arg_namespace(param_data, input_data) + + # Check if the user did not specify a variabe which is not used in a given calc_mode + list_used_param = [] + + # Parameters that should not be checked + general_arg_list = ['calc_mode', 'file_name', 'prefix'] + + if 'mandatory' in input_data[args.calc_mode].keys(): + list_used_param += list(input_data[args.calc_mode]['mandatory'].keys()) + + if 'optional' in input_data[args.calc_mode].keys(): + list_used_param += list(input_data[args.calc_mode]['optional'].keys()) + + for arg in vars(args): + if arg in general_arg_list: + continue + if args.__dict__[arg] is not None: + if arg not in list_used_param: + print('WARNING: ' + arg + ' input parameter is not used in ' + args.calc_mode + ' calculation mode.') + + # Write the input + if not args.file_name: + if args.calc_mode == 'qe2pert': + file_name = 'qe2pert.in' + else: + file_name = 'pert.in' + else: + file_name = args.file_name + + finput = open(file_name, 'w') + + finput.write('! This input file for PERTURBO was generated by Perturbopy \n') + finput.write('! Date: {} '.format(datetime.datetime.now().strftime("%B %d, %Y %H:%M")) + '\n' * 2) + + if args.calc_mode == 'qe2pert': + finput.write('&qe2pert' + '\n') + else: + finput.write('&perturbo' + '\n') + + # ===========MANDATORY================= + finput.write('! ***Mandatory parameters***' + '\n') + + if args.calc_mode == 'qe2pert': + executable = 'qe2pert' + else: + executable = 'perturbo' + finput.write('{:20} = \'{}\'\n'.format(' calc_mode', args.calc_mode)) + + write_parameter_to_input(finput, 'prefix', executable, args, param_data) + + for key, value in input_data[args.calc_mode]['mandatory'].items(): + if value: + finput.write('! ' + value + '\n') + + write_parameter_to_input(finput, key, executable, args, param_data) + + # ===========OPTIONAL================= + if 'optional' in input_data[args.calc_mode].keys(): + finput.write('\n' * 2 + '! ***Optional parameters***' + '\n') + for param, value in input_data[args.calc_mode]['optional'].items(): + write_parameter_to_input(finput, param, executable, args, param_data, optional=True) + + finput.write('/\n') + + finput.close() + + print('File ' + file_name + ' is generated.') diff --git a/src/perturbopy/generate_input/input_parameters_perturbo.yml b/src/perturbopy/generate_input/input_parameters_perturbo.yml new file mode 100644 index 0000000..1a2c0de --- /dev/null +++ b/src/perturbopy/generate_input/input_parameters_perturbo.yml @@ -0,0 +1,381 @@ +--- +# This is a yaml file that contains the information about the input parameters for the perturbo.x code. +# From this file, the mydoc_input_parameters_perturbo.html file is automatically generated + +# +# Description of the input parameters families +# +job_control: + type: family + description: Job control + color_hsl: [9, 100, 64] + +bte: + type: family + description: Boltzmann Transport Equation + color_hsl: [39, 100, 50] + +polar_correction: + type: family + description: Polar correction + #(required only for calc_mode='imsigma') + color_hsl: [147, 50, 47] + +dynamics: + type: family + description: Ultra-fast dynamics + #(via the time-dependent BTE) + color_hsl: [210, 100, 56] + +# +# Input parameters +# +prefix: + family: job_control + type: string + typical: "'prefix'" + default: "''" + len: 80 + attributes: save + description: Job name prefix. It should be the same as the prefix used in QE. + +calc_mode: + family: job_control + type: string + options: + "'bands'": interpolated electronic band structure (see in the section) + "'phdisp'": interpolated phonon dispersions along a given crystal momentum path (see in the section) + "'ephmat'": absolute values of the e-ph matrix elements (see in the section) + "'setup'": set up transport property calculations (see in the section) + "'imsigma'": imaginary part of the lowest-order e-ph self-energy (see in the section) + "'meanfp'": e-ph mean free paths for electronic states (see in the section) + "'trans'": electrical conductivity and carrier mobility tensors (see in the section) + "'trans-pp'": computes Seebeck coefficient (see in the section) + "'dynamics-run'": ultrafast hot carrier dynamics (see in the section) + "'dynamics-pp'": computes the energy-dependent carrier population as a function of time (see in the section) + default: "''" + len: 80 + attributes: save + description: Calculation mode. + +fklist: + family: job_control + type: string + typical: "'prefix_tet.kpt'" + default: "''" + len: 80 + attributes: save + description: Name of the file containing the k-point list (in crystal coordiates). + +fqlist: + family: job_control + type: string + typical: "'prefix_phdisp.qpt'" + default: "''" + len: 80 + attributes: save + description: Name of the file containing the q-point list (in crystal coordiates). + +ftemper: + family: job_control + type: string + typical: "'prefix.temper'" + default: "''" + len: 80 + attributes: save + description: Name of the file containing values for the temperature (K), chemical potential (eV), and carrier concentration (cm-2 or cm-3). + +debug: + family: job_control + type: logical + default: False + attributes: save + description: Debug mode. + +yaml_fname: + family: job_control + type: string + default: "'.yml'" + len: 80 + attributes: save + description: Name of the YAML output file. If the parameter (yaml_fname) is not changed by the user, the output name of the YAML file will be {prefix}_{calc_mode}.yml. For example, for Si bands calculation, the YAML file would be called si_bands.yml. + +hole: + family: job_control + type: logical + default: False + attributes: save + description: Set to .true. for calculations on hole carriers. + +tmp_dir: + family: job_control + type: string + typical: "'./tmp'" + default: "'.'" + len: 80 + attributes: save + description: The directory where the e-ph matrix elements are stored when calc_mode='trans'. + +load_scatter_eph: + family: job_control + type: logical + default: False + len: 80 + attributes: save + description: Read the e-ph matrix elements from the files in tmp_dir. Used for calc_mode='trans'. + +find_efermi: + family: job_control + type: logical + default: False + description: Find chemical potential (Fermi energy) given the concentration (if set to .true.). Find concentration given the chemical potential (if .false.). + +boltz_kdim: + family: bte + type: integer + dimensions: (3) + default: (1,1,1) + attributes: save + description: Number of k points along each dimension for the Boltzmann equation. + +boltz_qdim: + family: bte + type: integer + dimensions: (3) + default: (0,0,0) + attributes: save +# default: ('boltz_kdim(1)','boltz_kdim(2)','boltz_kdim(3)') + description: Number of q points along each dimension for the Boltzmann equation. It should be same with boltz_kdim. + +band_min: + family: bte + type: integer + default: 1 + attributes: save + description: Lowest band included. + +band_max: + family: bte + type: integer + default: 9999999 + attributes: save + description: Highest band included. + +boltz_emin: + family: bte + type: real + default: -9999.0 + units: eV + attributes: save + description: Bottom of the energy window for the Boltzmann equation. + +boltz_emax: + family: bte + type: real + default: 9999.0 + units: eV + attributes: save + description: Top of the energy window for the Boltzmann equation. + +boltz_nstep: + family: bte + type: integer + default: 0 + typical: 50 + attributes: save + description: Number of iterations for solving the Boltzmann transport equation. + +boltz_de: + family: bte + type: real + default: 1.0 + units: meV + attributes: save + description: Energy step for the integrals in the Boltzmann equation. + +delta_smear: + family: bte + type: real + default: 10.0 + units: meV + attributes: save + description: Smearing for the Dirac delta function. + +full_ite: + family: bte + type: logical + default: True + attributes: save + description: Solve BTE with both E- and T-fields iteratively. + +phfreq_cutoff: + family: bte + type: real + typical: 1.0 + default: 1.0 + units: meV + attributes: save + description: Phonon energy threshold. Phonons with energy smaller than phfreq_cutoff will be excluded. + +trans_thr: + family: bte + type: real + default: 0.002 + attributes: save + description: Threshold for the iterative procedure. + +polar_split: + family: polar_correction + type: string + default: "''" + options: + "''": (leave blank) both the polar and nonpolar parts, no split + "'polar'": polar part only + "'rmpol'": remainder part + len: 80 + attributes: save + description: Polar correction mode. + +sampling: + family: job_control + type: string + default: "'uniform'" + options: + "'uniform'": random sampling from an uniform distribution. + "'cauchy'": random sampling from a Cauchy disrtibution. + len: 80 + attributes: save + description: Random q points sampling method. + +cauchy_scale: + family: job_control + type: real + typical: 1.0 + default: 0.05 + attributes: save + description: Scale parameter gamma for the Cauchy distribution; used when sampling='cauchy'. + +nsamples: + family: job_control + type: integer + default: 100000 + attributes: save + description: Number of q-points for the summation over the q-points in imsigma calculation. + +time_step: + family: dynamics + type: real + typical: 1.0 + default: 1.0 + units: fs + attributes: save + description: Time step for the carrier dynamics. + +output_nstep: + family: dynamics + type: integer + default: 1 + attributes: save + description: Print out the results every output_nstep time steps. + +boltz_init_dist: + family: dynamics + type: string + options: + "'restart'": restart from the previous calculations. + "'lorentz'": Loretnzian distribution + "'fermi'": Fermi-Dirac distribution + "'gaussian'": Gaussian distribution + typical: "'gaussian'" + default: "''" + len: 80 + attributes: save + description: Initial electron distribution at time zero. + +boltz_init_e0: + family: dynamics + type: real + typical: 1.0 + units: eV + default: -9999.0 + attributes: save + description: Energy parameter used to generate initial distribution. Needs to be specified for boltz_init_dist='lorentz' (center), 'gaussian' (center), or 'fermi' (chemical potential). + +boltz_init_smear: + family: dynamics + type: real + typical: 1.0 + units: meV + default: 20.0 + attributes: save + description: The broadening or width of the initial distribution for boltz_init_dist='lorentz' or 'gaussian', or temperature (in meV) for 'fermi'. + +solver: + family: dynamics + type: string + default: "'rk4'" + options: + "'euler'": Euler method (first-order) + "'rk4'": fourth-order Runge-Kutta method + len: 80 + attributes: save + description: Solver type for the Boltzmann transport equation. + +boltz_efield: + family: dynamics + type: real + dimensions: (3) + default: (0.0, 0.0, 0.0) + units: V/cm + attributes: save + description: External electric field for the ultrafast real-time dynamics. + +boltz_norm_dist: + family: dynamics + type: logical + default: False + attributes: save + description: Normalize the distribution function at each step of the real-time Boltzmann Transport Equation simulation. + +boltz_acc_thr: + family: dynamics + type: real + typical: 1.0 + default: 0.0 + units: cm/s2 + attributes: save + description: Drift acceleration threshold. If specified, the real-time simulation will stop when at least 10 last iterations had a drift acceleration lower than the threshold. + +boltz_nstep_min: + family: dynamics + type: integer + default: 1 + typical: 100 + attributes: save + description: Minimum number of iterations of real-time dynamics. Used with boltz_acc_thr. Will not be applied if boltz_acc_thr is not specified, in this case, use boltz_nstep instead. + +ph_mode_exclude_ranges: + family: dynamics + output: False + type: integer + dimensions: (30, 2) + default: -1 + attributes: save + description: "Specify the phonon modes to exclude in rt-BTE: the g2 factor will be set to zero for these modes. The modes to exclude are specified with ranges, e.g. to exclude modes from 2 to 5, write in the input file: ph_mode_exclude_ranges(1,:)=2,5 . To add another range to exclude, specify ph_mode_exclude_ranges(2,:)=7,10 . One can use up to 30 ranges. To exclude one mode, set first and second number to the phonon mode index. The indices of the phonon modes to exclude must be smaller than the total number of modes in a system." + +use_mem: + family: job_control + type: logical + default: True + typical: True + attributes: save + description: Flag for using memory or not and only used in boltz_scatter + +find_efermi: + family: job_control + type: logical + default: False + typical: False + attributes: save + description: Flag to indicate whether to find the Fermi energy, which means fix the Fermi energy or occupancy. +... diff --git a/src/perturbopy/generate_input/input_parameters_qe2pert.yml b/src/perturbopy/generate_input/input_parameters_qe2pert.yml new file mode 100644 index 0000000..4b97eb4 --- /dev/null +++ b/src/perturbopy/generate_input/input_parameters_qe2pert.yml @@ -0,0 +1,177 @@ +--- +# This is a yaml file that contains the information about the input parameters for the qe2pert.x code. +# From this file, the mydoc_input_parameters_qe2pert.html file is automatically generated + +# +# Description of the input parameters families +# +general: + type: family + description: General input parameters + color_hsl: [0, 0, 50] + +# +# Input parameters +# +prefix: + family: general + type: string + typical: "'prefix'" + len: 256 + description: Job name prefix. It should be the same as the prefix used in QE. + source: qe + +outdir: + family: general + type: string + typical: "'./tmp'" + len: 256 + description: Name of the directory where the QE nscf output directory prefix.save is located, and where the e-ph matrix elements prefix_elph.h5 will be stored. + bcast_name: tmp_dir + +phdir: + family: general + type: string + typical: "'phdir'" + len: 256 + attributes: save + description: Name of the directory where the phonon "save" directory is located. + +dft_band_min: + family: general + type: integer + default: 1 + attributes: save + description: Lowest band index used in Wannier90. + +dft_band_max: + family: general + type: integer + default: 10000 + attributes: save + description: Highest band index used in Wannier90. Be default, it will be reset to the highest band index in the DFT results. + +dis_win_min: + family: general + type: real + default: -9999.0 + attributes: save + description: The 'dis_win_min' used in Wannier90, the lower boundary of the outer windows. + +num_wann: + family: general + type: integer + default: 1 + attributes: save + description: Number of Wannier functions. + +system_2d: + family: general + type: logical + default: False + attributes: save + description: Set it to .true. if the system is 2D. + +nk1: + family: general + type: integer + typical: 8 + description: Number of k points along x-axis used in the Wannierization. + bcast_name: kdim(1) + +nk2: + family: general + type: integer + typical: 8 + description: Number of k points along y-axis used in the Wannierization. + bcast_name: kdim(2) + +nk3: + family: general + type: integer + typical: 8 + description: Number of k points along z-axis used in the Wannierization. + bcast_name: kdim(3) + +debug: + family: general + type: logical + default: False + attributes: save + description: Set to .true. to turn on the debug mode, in which the code stop after g(k,q) (does not compute g in wannier basis) + +yaml_fname: + family: general + type: string + default: "'qe2pert_output.yml'" + len: 80 + description: Name of the YAML output file. + +lwannier: + family: general + type: logical + default: True + attributes: save + description: Set to .true. to rotate the wavefunctions using Wannier unitary matrix before computing e-ph matrix elements. + +load_ephmat: + family: general + type: logical + default: False + attributes: save + description: Set to .true. to load prefix_elph.h5 from the directory specified by the variable outdir. + +eig_corr: + family: general + type: string + typical: "'eig_corr'" + len: 256 + default: "''" + attributes: save + description: File containing the electron eigenvalues on the (nk1, nk2, nk3) grid. The format of this file is the same as the file prefix.eig generated in Wannier90. if present, qe2pert.x will read the eigenvalues from this file, rather than Kohn-Sham eigenvalues from QE-nscf calculation. This is usually used when one wants to use modified eigenvalues (e.g., from GW). + +polar_alpha: + family: general + type: real + default: 1.0 + attributes: save + description: Convergence parameter used in the Ewald sum when computing the polar correction in polar materials. The default value is 1.0. + +asr: + family: general + type: string + default: "'crystal'" + len: 10 + attributes: save + options: + "'no'": no Acoustic Sum Rules imposed + "'simple'": 3 translational asr imposed by correction of the diagonal elements of the force constants matrix + "'crystal'": 3 translational asr imposed by optimized correction of the force constants (projection) + description: Indicates the type of Acoustic Sum Rule imposed. + +thickness_2d: + family: general + type: real + default: 6.0 + units: Å + attributes: save + description: Thickness of the 2d system, used in the 2D polar e-ph correction. Only needed when system_2d=.true. + +spin_component: + family: general + type: string + default: "'none'" + len: 4 + attributes: save + options: + "'none'": on spin or non-collinear channel. + "'up'": LSDA-up channel. + description: Flag for LSDA spin polarized calculation. + +tdep: + family: general + type: logical + default: False + attributes: save + description: Flag for TDEP support. +... diff --git a/src/perturbopy/generate_input/input_template.yml b/src/perturbopy/generate_input/input_template.yml new file mode 100644 index 0000000..d13b1dc --- /dev/null +++ b/src/perturbopy/generate_input/input_template.yml @@ -0,0 +1,164 @@ +--- +# This is a yaml file that contains the information about the request +# input parameters for different tasks. used for automatically generating input files +# NOTE: "prefix" is mandatory for all, thus not listed. +# "calc_mode" is mandatory for all tasks except qe2pert. + +qe2pert: + mandatory: + outdir: + phdir: + nk1: coarse k grid (used to construct Wannier functions) + nk2: + nk3: + num_wann: number of wannier functions + + optional: + dft_band_min: lowest band index used in Wannier90. + dft_band_max: highest band index used in Wannier90. + dis_win_min: the same as 'dis_win_min' used in Wannier90. + system_2d: set it to .true. for 2D systems + lwannier: compute g(k,q) using wavefunctions in wannier gauge directly. + debug: debug mode, stop after g(k,q) (does not compute g in wannier basis) + load_ephmat: load prefix_elph.h5 + asr: acoustic sum rules + polar_alpha: convergence parameter used in the Ewald sum, only used for polar correction. + thickness_2d: for 2D polar e-ph correction. Only needed when system_2d=.true. + eig_corr: usually used when one wants to use modified eigenvalues (e.g., from GW) + + +bands: + mandatory: + fklist: + +phdisp: + mandatory: + fqlist: + +ephmat: + mandatory: + fklist: + fqlist: + + optional: + band_min: + band_max: + phfreq_cutoff: Phonons with energy smaller than phfreq_cutoff will be excluded. + +setup: + mandatory: + boltz_kdim: + ftemper: + + optional: + band_min: + band_max: + boltz_emin: + boltz_emax: + find_efermi: + hole: Set to .true. for calculations on hole carriers of semiconductors. + + +imsigma: + mandatory: + ftemper: + fklist: + + optional: + band_min: + band_max: + delta_smear: + phfreq_cutoff: + polar_split: + fqlist: + sampling: + cauchy_scale: + nsamples: + + +meanfp: + mandatory: + fklist: + ftemper: + + optional: + band_min: + band_max: + +trans: + mandatory: + boltz_kdim: + ftemper: + + optional: + boltz_qdim: + band_min: + band_max: + boltz_emin: + boltz_emax: + delta_smear: + phfreq_cutoff: + boltz_nstep: + boltz_de: + trans_thr: + hole: + load_scatter_eph: + tmp_dir: + full_ite: + +trans-pp: + mandatory: + boltz_kdim: + ftemper: + + optional: + band_min: + band_max: + boltz_emin: + boltz_emax: + boltz_de: + hole: + +dynamics-run: + mandatory: + boltz_kdim: + ftemper: + boltz_nstep: + output_nstep: + time_step: + boltz_init_dist: + + optional: + solver: + boltz_init_e0: + boltz_init_smear: + delta_smear: + phfreq_cutoff: + boltz_qdim: + hole: + band_min: + band_max: + boltz_emin: + boltz_emax: + load_scatter_eph: + tmp_dir: + boltz_efield: + boltz_norm_dist: + boltz_acc_thr: + boltz_nstep_min: + ph_mode_exclude_ranges: + +dynamics-pp: + mandatory: + boltz_kdim: + ftemper: + + optional: + hole: + boltz_de: + band_min: + band_max: + boltz_emin: + boltz_emax: + boltz_efield: +...