diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1cc6f884..3d9f8110 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-added-large-files - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.4 + rev: v0.5.6 hooks: - id: ruff args: [ "--fix", "--show-fixes" ] diff --git a/doc/changelog.md b/doc/changelog.md index 480a9b91..6f6212fe 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,14 @@ # Change Log +## Jul-22-2024: Version 3.3.3 + +- Provide functionality by `--cf3` and `--cf2` command options to create force + constants from displacement-force dataset of random displacements when + an external force constants calculator is specified. +- New command line options `--rd`, `--rd-fc2`, `--fc-calc`, `--fc-calc-opt` and + `--sp` to support random displacements. + ## Jul-22-2024: Version 3.3.2 - Minor fix of `phono3py.load` function for reading displacements from diff --git a/doc/command-options.md b/doc/command-options.md index 9851d73e..8979cc06 100644 --- a/doc/command-options.md +++ b/doc/command-options.md @@ -27,13 +27,13 @@ CELL_FILENAME = POSCAR-unitcell where the setting tag names are case insensitive. This is run by ```bash -% phono3py setting.conf [comannd options] +% phono3py setting.conf [command options] ``` or ```bash -% phono3py [comannd options] -- setting.conf +% phono3py [command options] -- setting.conf ``` ```{contents} @@ -48,7 +48,7 @@ or This specifies input unit cell filename. ```bash -% phono3py -c POSCAR-unitcell ... (many options) +% phono3py -c POSCAR-unitcell ... (options) ``` ## Calculator interface @@ -174,6 +174,27 @@ created from `FORCES_FC2` and `phono3py_disp.yaml` instead of `FORCES_FC3` and % phono3py --cfs --dim-fc2="x x x" ``` +(sp_option)= + +### `--sp` or `--save-params` + +Instead of `FORCES_FC3`, `phono3py_params.yaml` is generated. This option must +be used with `--cf3`, and optionally with `--cf2`. If the force calculator +supports reading energy of supercell, those are written into +`phono3y_params.yaml`. These energies are necessary for using `--pypolymlp` +option. + +```bash +% phono3py --cf3 disp-{00001..00755}/vasprun.xml --sp +``` + +When using with `--cf2`, `--cf3` has to be specified simultaneously as below, + +```bash +% phono3py --cf3 disp-{00001..00755}/vasprun.xml --cf2 disp_fc2-{00001..00002}/vasprun.xml --sp +``` + + ## Supercell, primitive cell, masses, magnetic moments (dim_option)= @@ -250,7 +271,6 @@ web page](https://phonopy.github.io/phonopy/setting-tags.html#magmom). ## Displacement creation (create_displacements_option)= - ### `-d` (`CREATE_DISPLACEMENTS = .TRUE.`) Supercell with displacements are created. Using with `--amplitude` option, @@ -259,8 +279,8 @@ supercells with displacements and `phono3py_disp.yaml` file are created. `--pa` should be specified if the input unit cell structure is not a primitive cell, e.g., `--pa="F"` if the input unit cell has F-centring. -(amplitude_option)= +(random_displacements_option)= ### `--rd` (`RANDOM_DISPLACEMENTS`), `--rd-fc2` (`RANDOM_DISPLACEMENTS_FC2`) and `--random-seed` (`RANDOM_SEED`) Random directional displacements are generated for fc3 and fc2 supercells by @@ -268,6 +288,7 @@ Random directional displacements are generated for fc3 and fc2 supercells by may be used together. These are used in the equivalent way to [`--rd` of phonopy](https://phonopy.github.io/phonopy/setting-tags.html#random-displacements). +(amplitude_option)= ### `--amplitude` (`DISPLACEMENT_DISTANCE`) Atomic displacement distance is specified. This value may be increased for the @@ -277,6 +298,44 @@ very accurate. The default value depends on calculator. See {ref}`default_displacement_distance_for_calculator`. +(fc_calculator_option)= +### `--fc-calc`, `--fc-calculator` (`FC_CALCULATOR`) + +Choice of force constants calculator. + +``` +% phono3py --fc-calc symfc ... +``` + +To use different force constants calculators for fc2 and fc3 +``` +% phono3py --fc-calc "symfc|" ... +``` +Those for fc2 and fc3 are seprated by `|` such as `symfc|` . Blank means to +employ the finite difference method for systematic displacements generated by +the option `-d`. + +(fc_calculator_options_option)= +### `--fc-calc-opt`, `--fc-calculator-options` (`FC_CALCULATOR_OPTIONS`) + +Special options for force constants calculators. + +``` +% phono3py --fc-calc-opt "cutoff=8" ... +``` + +Similarly to `--fc-calc`, `|` can be used to separated those for fc2 and fc3. + +#### Options for symfc + +* cutoff : cutoff pair distance beyond that third-order force constants are zero + (fc3 only). +* use_mkl : sparse_dot_mkl is employed when it is available. + +### `--symfc` and `--alm` + +These are shortcuts of `--fc-calc symfc` and `--fc-calc alm`, respectively. + ## Force constants (compact_fc_option)= @@ -331,14 +390,16 @@ supercell size and the second choice is using `--cutoff-pair` option. ### `--cutoff-pair` or `--cutoff-pair-distance` (`CUTOFF_PAIR_DISTANCE`) -This option is only used together with `-d` option. +This option works differently for the `-d` and `--rd` options. -A cutoff pair-distance in a supercell is used to reduce the number of necessary -supercells with displacements to obtain third order force constants. As the -drawback, a certain number of third-order-force-constants elements are abandoned -or computed with less numerical accuracy. More details are found at +For `-d`, A cutoff pair-distance in a supercell is used to reduce the number of +necessary supercells with displacements to obtain third order force constants. +As the drawback, a certain number of third-order-force-constants elements are +abandoned or computed with less numerical accuracy. More details are found at {ref}`command_cutoff_pair`. +For `--rd`, `--cutoff-pair VAL` is equivalent to `--fc-calc-opt "cutoff=VAL"`. + ### `--alm` This invokes ALM as the force constants calculator for fc2 and fc3. See the diff --git a/doc/conf.py b/doc/conf.py index bf1a79a5..da5cb499 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -60,7 +60,7 @@ # The short X.Y version. version = "3.3" # The full version, including alpha/beta/rc tags. -release = "3.3.2" +release = "3.3.3" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/cutoff-pair.md b/doc/cutoff-pair.md index 03228c21..a07b1332 100644 --- a/doc/cutoff-pair.md +++ b/doc/cutoff-pair.md @@ -2,7 +2,11 @@ # Force constants calculation with cutoff pair-distance -Here the detail of the command option {ref}`--cutoff_pair ` +Since this calculation is a little bit tricky. It may be recommended to try +{ref}`random-displacements` with `--fc-calc-opt "cutoff = VAL"` before trying +this option. + +Here the detail of the command option {ref}`--cutoff-pair ` is explained. diff --git a/doc/index.md b/doc/index.md index 961ad249..1e077455 100644 --- a/doc/index.md +++ b/doc/index.md @@ -58,6 +58,7 @@ auxiliary-tools direct-solution wigner-solution workload-distribution +random-displacements cutoff-pair external-tools phono3py-api diff --git a/doc/random-displacements.md b/doc/random-displacements.md new file mode 100644 index 00000000..4c4b1185 --- /dev/null +++ b/doc/random-displacements.md @@ -0,0 +1,125 @@ +(random-displacements)= +# Force constants calculation with randan displacements of atoms + +Random displacements and corresponding forces in supercells can be employed as a +displacement-force dataset for computing force constants. This requires an +external force constants calculator, e.g., symfc or ALM. Here, examples are +presented with using symfc that can be installed via pip or conda easily. + +## Related setting tags + +- {ref}`random_displacements_option` (`--rd`, `--random-seed`) +- {ref}`fc_calculator_option` (`--fc-calc`) +- {ref}`fc_calculator_options_option` (`--fc-calc-opt`) + +## Generation of random directional displacements + +The option `--rd NUM` is used instead of `-d` in generating displacements as follows: + +```bash +% phono3py --rd 100 --dim 2 2 2 --pa auto -c POSCAR-unitcell +``` + +`NUM` means the number of supercells with random directional displacements. This +must be specified, and the initial guess may be from around the number of +supecells generated for the systematic displacements by `-d`. In the case of the +`NaCl-rd` example, 146 supercells are generated with `-d`, so similar +number `--rd 100` was chosen here. + +If random directional displacements for fc2 are expected, `--rd-fc2` and +`--dim-fc2` have to be specified: + +```bash +% phono3py --rd 100 --dim 2 2 2 --rd-fc2 2 --dim-fc2 4 4 4 --pa auto -c POSCAR-unitcell +``` + +where `--dim` is necessary but `--rd` is not. + +## Create `FORCES_FC3` and `FORCES_FC2` + +`FORCES_FC3` and optionally `FORCES_FC2`, which contains forces corresponding to +displacements, can be created by + +```bash +% phono3py --cf3 vasprun_xmls/vasprun-00{001..100}.xml +``` + +Here it is assumed that the forces were calculated by VASP, and the output files +(`vasprun.xml`) are stored in `vasprun_xmls` directory after renaming. When +running this command, `phono3py_disp.yaml` is automatically read. For the +different file name, e.g. `phono3py_disp_rd.yaml`, it is specified with `-c` +option: + +```bash +% phono3py -c phono3py_disp_rd.yaml --cf3 vasprun_xmls/vasprun-00{001..100}.xml +``` + +`FORCES_FC2` is created similarly, e.g., from the VASP output stored as +`vasprun_xmls/vasprun-ph000{1,2}.xml`, + +```bash +% phono3py --cf2 vasprun_xmls/vasprun-ph000{1,2}.xml +``` + +## Create `phono3py_params.yaml` + +Instead of creating `FORCES_FC3` and `FORCES_FC2`, more convenient data file to +store displacement-force dataset is created by `--sp` option: + +```bash +% phono3py --cf3 vasprun_xmls/vasprun-00{001..100}.xml --cf2 vasprun_xmls/vasprun-ph0000{1,2}.xml --sp +``` + +The advantage to employ `phono3py_params.yaml` is that this file can contain all +the information required to run phono3py such as crystal structure, supercell +information, displacements, forces, and parameters for non-analytical term +correction. This file is immediately usable for `phono3py-load` command ({ref}`phono3py_load_command`). + +## Calculation of force constants + +If `phono3py_disp.yaml` is located in current directory, force constants are +calculated from `FORCES_FC3` (and optionally `FORCES_FC2`) and +`phono3py_disp.yaml` by + +```bash +% phono3py --symfc -v +``` + +or with `phono3py_params.yaml` + +```bash +% phono3py -c phono3py_params.yaml --symfc -v +``` + +Similarly, it is performed by also using `phono3py-load` command, + +```bash +% phono3py-load --symfc -v +``` + +or + +```bash +% phono3py-load phono3py_params.yaml --symfc -v +``` + +## Cutoff pair-distance for fc3 calculation + +The number of supercells required for calculating fc3 depends on crystal +structure, crystal symmetry, and supercell size. For larger supercells, the +number can be very large. In addition, the required computational time and +memory space can also become large. In such case, it may be good to consider +introducing cutoff distance for pairs of atoms. It is performed by +`--fc-calc-opt` option as + +```bash +% phono3py --symfc -v --fc-calc-opt "cutoff=8" +``` + +The shortcut of `--fc-calc-opt "cutoff=8"` is `--cutoff-pair 8`. + +The convergence of fc3 has to be checked. With the same input of +displacement-force dataset, calculated force constants gradually converge by +increasing cutoff pair-distance. The convergence may be checked by lattice +thermal conductivity, but it may depend on quantity that is expected to be +calculated. diff --git a/example/NaCl-rd/README.md b/example/NaCl-rd/README.md new file mode 100644 index 00000000..761570c0 --- /dev/null +++ b/example/NaCl-rd/README.md @@ -0,0 +1,80 @@ +# Example of using random directional displacements + +## How to use symfc + +This example utilizes an NaCl calculation result from A. Togo and A. Seko, J. +Chem. Phys. 160, 211001 (2024). Supercells of 2x2x2 and 4x4x4 conventional unit +cells are chosen for the third-order force constants (fc3) and second-order +force constants (fc2), respectively. Displacement-force datasets consisting of +100 supercells for fc3 and 2 supercells for fc2 are extracted and stored in +`phono3py_params_NaCl.yaml.xz`. Random directional displacements of a constant +0.03 Angstrom are used. + +To calculate force constants, an external force constants calculator is +necessary. Here, the symfc tool (available at https://github.com/symfc/symfc) is +used, which can be easily installed via pip or conda. + +The `fc3.hdf5` and `fc2.hdf5` are computed using the command: + +``` +% phono3py-load phono3py_params_NaCl.yaml.xz --symfc -v +``` + +Lattice thermal conductivity (LTC) is calculated with the following command: + +``` +% phono3py-load phono3py_params_NaCl.yaml.xz --br --ts 300 --mesh 50 +``` + +By this, LTC is obtained around 8.3 W/m-k. + + +## How to use pypolymlp + +When supercell energies are included in `phono3py_params.yaml` like file, the +polynomial machine learning potential (poly-MLP) by pypolymlp can be used to +calculate fc3 by the following command: + +```bash +% phono3py-load phono3py_params_NaCl.yaml.xz --pypolymlp --symfc --rd 400 -v +``` + +the procedure below is performed: + +1. Poly-MLPs are computed from the displacement-force dataset for fc3. This is + activated by `--pypolymlp` option. +2. 800=400+400 supercells for random directional displacements are generated, + where 400+400 means 400 supercells with random displacements (u) and 400 + supercells with opposite displacement vectors (-u). This is activated by + `--rd 400` option. The default displacement distance is 0.001 Angstrom in + `--pypolymlp` mode. Since random displacements are generated `--symfc` has to + be specified for fc3. In this example, random displacements are used for fc2, + too, `--symfc` is applied to both of fc3 and fc2. Without `--rd` option, + systematic displacements are generated, for which the option `--fc-calc "symfc|"` + has to be specified instead of `--symfc` (equivalent to `--fc-calc "symfc|symfc")`). +3. Forces on atoms in these 800 supercells are calculated using poly-MLP. +4. Force constants are calculated. + + +The `fc3.hdf5` and `fc2.hdf5` are obtained. Using these force constants, LTC is +calculated by + +```bash +% phono3py-load phono3py_params_NaCl.yaml.xz --br --ts 300 --mesh 50 +``` + +and the LTC value of around 8.2 W/m-k is obtained. + +## Generating phono3py_params.yaml from vasprun.xml's + +`phono3py_params.yaml` is generated from + +```bash +% phono3py phono3py_disp.yaml --cf3 NaCl-vasprun/vasprun-{00001..00100}.xml --cf2 NaCl-vasprun/vasprun-ph0000{1,2}.xml --sp +``` + +This command reads electronic energies of supercells from `vasprun.xml`s and +writes them into `phono3py_params.yaml`, too. Here, `phono3py_disp.yaml` is not +included in this example, but `phono3py_params_NaCl.yaml.xz` can be used to run +this example since corresponding information of displacements is included in +this file, too. diff --git a/example/NaCl-rd/phono3py_params_NaCl.yaml.xz b/example/NaCl-rd/phono3py_params_NaCl.yaml.xz new file mode 100644 index 00000000..105413ca Binary files /dev/null and b/example/NaCl-rd/phono3py_params_NaCl.yaml.xz differ diff --git a/example/NaCl-rd/vasprun_xmls.tar.xz b/example/NaCl-rd/vasprun_xmls.tar.xz new file mode 100644 index 00000000..2bb74deb Binary files /dev/null and b/example/NaCl-rd/vasprun_xmls.tar.xz differ diff --git a/phono3py/cui/create_force_constants.py b/phono3py/cui/create_force_constants.py index fbe9a5e3..740455f0 100644 --- a/phono3py/cui/create_force_constants.py +++ b/phono3py/cui/create_force_constants.py @@ -168,14 +168,9 @@ def create_phono3py_force_constants( if settings.read_fc2: _read_phono3py_fc2(phono3py, symmetrize_fc2, input_filename, log_level) else: - if phono3py.phonon_supercell_matrix is None: - force_filename = "FORCES_FC3" - else: - force_filename = "FORCES_FC2" _create_phono3py_fc2( phono3py, ph3py_yaml, - force_filename, symmetrize_fc2, settings.is_compact_fc, fc_calculator, @@ -219,20 +214,22 @@ def parse_forces( """ filename_read_from: Optional[str] = None - + dataset = None calculator = phono3py.calculator + # Get dataset from ph3py_yaml. dataset can be None. # physical_units can be overwritten if calculator is found in ph3py_yaml. - dataset = _extract_dataset_from_ph3py_yaml(ph3py_yaml, fc_type) + if ph3py_yaml: + dataset = _extract_dataset_from_ph3py_yaml(ph3py_yaml, fc_type) if dataset and ph3py_yaml.calculator: calculator = ph3py_yaml.calculator physical_units = get_default_physical_units(calculator) - if fc_type == "phonon_fc2": - natom = len(phono3py.phonon_supercell) - else: + if phono3py.phonon_supercell is None or fc_type == "fc3": natom = len(phono3py.supercell) + else: + natom = len(phono3py.phonon_supercell) if dataset: filename_read_from = phono3py_yaml_filename @@ -269,20 +266,18 @@ def parse_forces( assert dataset is not None if "natom" in dataset and dataset["natom"] != natom: - msg = ( + raise RuntimeError( "Number of atoms in supercell is not consistent with " - '"%s".' % filename_read_from + f'"{filename_read_from}".' ) - raise RuntimeError(msg) if log_level and filename_read_from is not None: print( - 'Displacement dataset for %s was read from "%s".' - % (fc_type, filename_read_from) + f'Displacement dataset for {fc_type} was read from "{filename_read_from}".' ) # Overwrite dataset['cutoff_distance'] when necessary. - if cutoff_pair_distance: + if fc_type == "fc3" and cutoff_pair_distance: if "cutoff_distance" not in dataset or ( "cutoff_distance" in dataset and cutoff_pair_distance < dataset["cutoff_distance"] @@ -295,10 +290,10 @@ def parse_forces( # dataset comes either from disp_fc*.yaml or phono3py*.yaml. if not forces_in_dataset(dataset): if force_filename is not None: - if fc_type == "phonon_fc2": - parse_FORCES_FC2(dataset, filename=force_filename) - else: + if fc_type == "fc3": parse_FORCES_FC3(dataset, filename=force_filename) + else: + parse_FORCES_FC2(dataset, filename=force_filename) if log_level: print( @@ -452,10 +447,8 @@ def read_type2_dataset(natom, filename="FORCES_FC3", log_level=0) -> Optional[di if len_first_line == 6: dataset = get_dataset_type2(f, natom) if log_level: - print( - "%d snapshots were found in %s." - % (len(dataset["displacements"]), "FORCES_FC3") - ) + n_disp = len(dataset["displacements"]) + print(f'{n_disp} snapshots were found in "{filename}".') else: dataset = None return dataset @@ -663,7 +656,6 @@ def run_pypolymlp_to_compute_phonon_forces( def _create_phono3py_fc2( phono3py: Phono3py, ph3py_yaml: Optional[Phono3pyYaml], - force_filename, symmetrize_fc2, is_compact_fc, fc_calculator, @@ -675,6 +667,11 @@ def _create_phono3py_fc2( force_filename is either "FORCES_FC2" or "FORCES_FC3". """ + if phono3py.phonon_supercell_matrix is None: + force_filename = "FORCES_FC3" + else: + force_filename = "FORCES_FC2" + _ph3py_yaml = _get_default_ph3py_yaml(ph3py_yaml) try: @@ -682,7 +679,7 @@ def _create_phono3py_fc2( phono3py, ph3py_yaml=_ph3py_yaml, force_filename=force_filename, - fc_type="fc2", + fc_type="phonon_fc2", log_level=log_level, ) except RuntimeError as e: @@ -752,12 +749,13 @@ def _to_ndarray(array, dtype="double"): return array -def _extract_dataset_from_ph3py_yaml(ph3py_yaml: Optional[Phono3pyYaml], fc_type): - dataset = None - if fc_type == "phonon_fc2": - if ph3py_yaml and ph3py_yaml.phonon_dataset is not None: - dataset = copy.deepcopy(ph3py_yaml.phonon_dataset) +def _extract_dataset_from_ph3py_yaml( + ph3py_yaml: Optional[Phono3pyYaml], fc_type +) -> Optional[dict]: + if ph3py_yaml.phonon_supercell is None or fc_type == "fc3": + if ph3py_yaml.dataset is not None: + return copy.deepcopy(ph3py_yaml.dataset) else: - if ph3py_yaml and ph3py_yaml.dataset is not None: - dataset = copy.deepcopy(ph3py_yaml.dataset) - return dataset + if ph3py_yaml.phonon_dataset is not None: + return copy.deepcopy(ph3py_yaml.phonon_dataset) + return None diff --git a/phono3py/cui/create_supercells.py b/phono3py/cui/create_supercells.py index a09f3dcf..9c1e5a57 100644 --- a/phono3py/cui/create_supercells.py +++ b/phono3py/cui/create_supercells.py @@ -35,8 +35,10 @@ # POSSIBILITY OF SUCH DAMAGE. from phonopy.interface.calculator import write_supercells_with_displacements +from phonopy.structure.cells import print_cell from phono3py import Phono3py +from phono3py.cui.show_log import print_supercell_matrix from phono3py.interface.calculator import ( get_additional_info_to_write_fc2_supercells, get_additional_info_to_write_supercells, @@ -92,6 +94,16 @@ def create_phono3py_supercells( if log_level: print("") print('Unit cell was read from "%s".' % optional_structure_info[0]) + print("-" * 32 + " unit cell " + "-" * 33) # 32 + 11 + 33 = 76 + print_cell(phono3py.unitcell) + print("-" * 76) + print_supercell_matrix( + phono3py.supercell_matrix, phono3py.phonon_supercell_matrix + ) + if phono3py.primitive_matrix is not None: + print("Primitive matrix:") + for v in phono3py.primitive_matrix: + print(" %s" % v) print("Displacement distance: %s" % distance) ids = [] @@ -125,6 +137,7 @@ def create_phono3py_supercells( print("Number of displacement supercell files created: %d" % num_disp_files) if phono3py.phonon_supercell_matrix is not None: + num_disps = len(phono3py.phonon_supercells_with_displacements) additional_info = get_additional_info_to_write_fc2_supercells( interface_mode, phono3py.phonon_supercell_matrix ) diff --git a/phono3py/cui/load.py b/phono3py/cui/load.py index a5acd263..d100afdb 100644 --- a/phono3py/cui/load.py +++ b/phono3py/cui/load.py @@ -588,9 +588,9 @@ def _get_dataset_phonon_dataset_or_fc2( ) elif ( forces_fc2_filename is not None or pathlib.Path("FORCES_FC2").exists() - ) and ph3py.phonon_supercell_matrix: + ) and ph3py.phonon_supercell_matrix is not None: if forces_fc2_filename is None: - force_filename = forces_fc2_filename + force_filename = "FORCES_FC2" else: force_filename = forces_fc2_filename phonon_dataset = _get_dataset_for_fc2( diff --git a/phono3py/cui/phono3py_script.py b/phono3py/cui/phono3py_script.py index 3bf870bf..0b0c6c2c 100644 --- a/phono3py/cui/phono3py_script.py +++ b/phono3py/cui/phono3py_script.py @@ -36,8 +36,10 @@ from __future__ import annotations +import argparse import datetime import sys +from typing import Optional import numpy as np from phonopy.cui.collect_cell_info import collect_cell_info @@ -75,7 +77,7 @@ set_dataset_and_force_constants, ) from phono3py.cui.phono3py_argparse import get_parser -from phono3py.cui.settings import Phono3pyConfParser +from phono3py.cui.settings import Phono3pyConfParser, Phono3pySettings from phono3py.cui.show_log import ( show_general_settings, show_phono3py_cells, @@ -212,7 +214,7 @@ def get_run_mode(settings): return run_mode -def start_phono3py(**argparse_control): +def start_phono3py(**argparse_control) -> tuple[argparse.Namespace, int]: """Parse arguments and set some basic parameters.""" parser, deprecated = get_parser(**argparse_control) args = parser.parse_args() @@ -310,7 +312,9 @@ def get_input_output_filenames_from_args(args): return input_filename, output_filename -def get_cell_info(settings, cell_filename, log_level): +def get_cell_info( + settings: Phono3pySettings, cell_filename: str, log_level: int +) -> dict: """Return calculator interface and crystal structure information.""" cell_info = collect_cell_info( supercell_matrix=settings.supercell_matrix, @@ -513,6 +517,58 @@ def grid_addresses_to_grid_points(grid_addresses, bz_grid): return bz_grid.grg2bzg[grid_points] +def create_supercells_with_displacements( + settings: Phono3pySettings, + cell_info: dict, + confs_dict: dict, + unitcell_filename: str, + interface_mode: Optional[str], + load_phono3py_yaml: bool, + symprec: float, + log_level: int, +): + """Create supercells and write displacements.""" + if ( + settings.create_displacements + or settings.random_displacements + or settings.random_displacements_fc2 + ): + phono3py = create_phono3py_supercells( + cell_info, + settings, + symprec, + interface_mode=interface_mode, + log_level=log_level, + ) + + store_nac_params( + phono3py, + settings, + cell_info["phonopy_yaml"], + unitcell_filename, + log_level, + nac_factor=Hartree * Bohr, + load_phonopy_yaml=load_phono3py_yaml, + ) + + if log_level: + if phono3py.supercell.magnetic_moments is None: + print("Spacegroup: %s" % phono3py.symmetry.get_international_table()) + else: + print( + "Number of symmetry operations in supercell: %d" + % len(phono3py.symmetry.symmetry_operations["rotations"]) + ) + + finalize_phono3py( + phono3py, + confs_dict, + log_level, + write_displacements=True, + filename="phono3py_disp.yaml", + ) + + def store_force_constants( phono3py: Phono3py, settings, @@ -853,7 +909,7 @@ def main(**argparse_control): # warnings.simplefilter("error") load_phono3py_yaml = argparse_control.get("load_phono3py_yaml", False) - if "args" in argparse_control: # For pytest + if "args" in argparse_control: # This is for pytest. args = argparse_control["args"] log_level = args.log_level else: @@ -926,29 +982,16 @@ def main(**argparse_control): ###################################################### # Create supercells with displacements and then exit # ###################################################### - if settings.create_displacements: - phono3py = create_phono3py_supercells( - cell_info, + if not settings.use_pypolymlp: + create_supercells_with_displacements( settings, - symprec, - interface_mode=interface_mode, - log_level=log_level, - ) - - if phono3py.supercell.magnetic_moments is None: - print("Spacegroup: %s" % phono3py.symmetry.get_international_table()) - else: - print( - "Number of symmetry operations in supercell: %d" - % len(phono3py.symmetry.symmetry_operations["rotations"]) - ) - - finalize_phono3py( - phono3py, + cell_info, confs_dict, + unitcell_filename, + interface_mode, + load_phono3py_yaml, + symprec, log_level, - write_displacements=True, - filename="phono3py_disp.yaml", ) ####################### @@ -1067,15 +1110,16 @@ def main(**argparse_control): ################################## # Non-analytical term correction # ################################## - store_nac_params( - phono3py, - settings, - cell_info["phonopy_yaml"], - unitcell_filename, - log_level, - nac_factor=Hartree * Bohr, - load_phonopy_yaml=load_phono3py_yaml, - ) + if settings.is_nac: + store_nac_params( + phono3py, + settings, + cell_info["phonopy_yaml"], + unitcell_filename, + log_level, + nac_factor=Hartree * Bohr, + load_phonopy_yaml=load_phono3py_yaml, + ) ################### # Force constants # diff --git a/phono3py/cui/settings.py b/phono3py/cui/settings.py index 9e5ebe40..45f71814 100644 --- a/phono3py/cui/settings.py +++ b/phono3py/cui/settings.py @@ -715,6 +715,7 @@ def _parse_conf(self): "conductivity_type", "create_forces_fc3_file", "output_yaml_filename", + "subtract_forces", ): self.set_parameter(conf_key, confs[conf_key]) diff --git a/phono3py/cui/show_log.py b/phono3py/cui/show_log.py index bc731832..650a5657 100644 --- a/phono3py/cui/show_log.py +++ b/phono3py/cui/show_log.py @@ -35,6 +35,8 @@ # POSSIBILITY OF SUCH DAMAGE. import sys +from collections.abc import Sequence +from typing import Optional, Union import numpy as np from phonopy.structure.cells import print_cell @@ -68,6 +70,23 @@ def show_general_settings( print("Calculator interface: %s" % phono3py.calculator) print('Crystal structure was read from "%s".' % cell_filename) + print_supercell_matrix(supercell_matrix, phonon_supercell_matrix) + + if is_primitive_axes_auto: + print("Primitive matrix (Auto):") + for v in primitive_matrix: + print(" %s" % v) + elif primitive_matrix is not None: + print("Primitive matrix:") + for v in primitive_matrix: + print(" %s" % v) + + +def print_supercell_matrix( + supercell_matrix: Union[Sequence, np.ndarray], + phonon_supercell_matrix: Optional[Union[Sequence, np.ndarray]] = None, +): + """Print supercell matrix.""" if (np.diag(np.diag(supercell_matrix)) - supercell_matrix).any(): print("Supercell matrix (dim):") for v in supercell_matrix: @@ -81,14 +100,6 @@ def show_general_settings( print(" %s" % v) else: print("Phonon supercell (dim-fc2): %s" % np.diag(phonon_supercell_matrix)) - if is_primitive_axes_auto: - print("Primitive matrix (Auto):") - for v in primitive_matrix: - print(" %s" % v) - elif primitive_matrix is not None: - print("Primitive matrix:") - for v in primitive_matrix: - print(" %s" % v) def show_phono3py_cells(phono3py: Phono3py): diff --git a/phono3py/file_IO.py b/phono3py/file_IO.py index 58a94ffc..0b9066b7 100644 --- a/phono3py/file_IO.py +++ b/phono3py/file_IO.py @@ -200,16 +200,26 @@ def write_FORCES_FC2(disp_dataset, forces_fc2=None, fp=None, filename="FORCES_FC else: w = fp - for i, disp1 in enumerate(disp_dataset["first_atoms"]): - w.write("# File: %-5d\n" % (i + 1)) - w.write("# %-5d " % (disp1["number"] + 1)) - w.write("%20.16f %20.16f %20.16f\n" % tuple(disp1["displacement"])) - if "forces" in disp1 and forces_fc2 is None: - force_set = disp1["forces"] + if "first_atoms" in disp_dataset: + for i, disp1 in enumerate(disp_dataset["first_atoms"]): + w.write("# File: %-5d\n" % (i + 1)) + w.write("# %-5d " % (disp1["number"] + 1)) + w.write("%20.16f %20.16f %20.16f\n" % tuple(disp1["displacement"])) + if "forces" in disp1 and forces_fc2 is None: + force_set = disp1["forces"] + else: + force_set = forces_fc2[i] + for forces in force_set: + w.write("%15.10f %15.10f %15.10f\n" % tuple(forces)) + else: + if "forces" in disp_dataset: + write_FORCE_SETS(disp_dataset, filename="FORCES_FC2") else: - force_set = forces_fc2[i] - for forces in force_set: - w.write("%15.10f %15.10f %15.10f\n" % tuple(forces)) + if forces_fc2 is None: + raise RuntimeError("No forces are found.") + dataset = disp_dataset.copy() + dataset["forces"] = forces_fc2 + write_FORCE_SETS(dataset, filename="FORCES_FC2") if fp is None: w.close() diff --git a/phono3py/version.py b/phono3py/version.py index a30ed251..00dbceca 100644 --- a/phono3py/version.py +++ b/phono3py/version.py @@ -34,4 +34,4 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -__version__ = "3.3.2" +__version__ = "3.3.3"