diff --git a/.github/workflows/phono3py-pytest-conda-mkl-phphmtblas.yml b/.github/workflows/phono3py-pytest-conda-mkl-phphmtblas.yml index f32a9b58..a262cdf6 100644 --- a/.github/workflows/phono3py-pytest-conda-mkl-phphmtblas.yml +++ b/.github/workflows/phono3py-pytest-conda-mkl-phphmtblas.yml @@ -35,7 +35,7 @@ jobs: - name: Install phonopy develop branch run: | conda activate test - git clone --depth 1 https://github.com/phonopy/phonopy.git + git clone https://github.com/phonopy/phonopy.git cd phonopy pip install -e . -vvv cd .. diff --git a/.github/workflows/phono3py-pytest-conda-mkl-v2.yml b/.github/workflows/phono3py-pytest-conda-mkl-v2.yml index 7a285923..a6d5c8d5 100644 --- a/.github/workflows/phono3py-pytest-conda-mkl-v2.yml +++ b/.github/workflows/phono3py-pytest-conda-mkl-v2.yml @@ -35,7 +35,7 @@ jobs: - name: Install phonopy develop branch run: | conda activate test - git clone --depth 1 https://github.com/phonopy/phonopy.git + git clone https://github.com/phonopy/phonopy.git cd phonopy pip install -e . -vvv cd .. diff --git a/.github/workflows/phono3py-pytest-conda-mkl.yml b/.github/workflows/phono3py-pytest-conda-mkl.yml index a9be299a..f42b8264 100644 --- a/.github/workflows/phono3py-pytest-conda-mkl.yml +++ b/.github/workflows/phono3py-pytest-conda-mkl.yml @@ -35,7 +35,7 @@ jobs: - name: Install phonopy develop branch run: | conda activate test - git clone --depth 1 https://github.com/phonopy/phonopy.git + git clone https://github.com/phonopy/phonopy.git cd phonopy pip install -e . -vvv cd .. diff --git a/.github/workflows/phono3py-pytest-conda-numpy2.yml b/.github/workflows/phono3py-pytest-conda-numpy2.yml index fdb106b2..85aee8be 100644 --- a/.github/workflows/phono3py-pytest-conda-numpy2.yml +++ b/.github/workflows/phono3py-pytest-conda-numpy2.yml @@ -35,14 +35,14 @@ jobs: - name: Install symfc develop branch run: | conda activate test - git clone --depth 1 https://github.com/symfc/symfc.git + git clone https://github.com/symfc/symfc.git cd symfc pip install -e . -vvv cd .. - name: Install phonopy develop branch run: | conda activate test - git clone --depth 1 https://github.com/phonopy/phonopy.git + git clone https://github.com/phonopy/phonopy.git cd phonopy pip install -e . -vvv cd .. diff --git a/.github/workflows/phono3py-pytest-conda-phphmtblas.yml b/.github/workflows/phono3py-pytest-conda-phphmtblas.yml index 59f41d31..5771b33b 100644 --- a/.github/workflows/phono3py-pytest-conda-phphmtblas.yml +++ b/.github/workflows/phono3py-pytest-conda-phphmtblas.yml @@ -28,14 +28,14 @@ jobs: - name: Install symfc develop branch run: | conda activate test - git clone --depth 1 https://github.com/symfc/symfc.git + git clone https://github.com/symfc/symfc.git cd symfc pip install -e . -vvv cd .. - name: Install phonopy develop branch run: | conda activate test - git clone --depth 1 https://github.com/phonopy/phonopy.git + git clone https://github.com/phonopy/phonopy.git cd phonopy pip install -e . -vvv cd .. diff --git a/.github/workflows/phono3py-pytest-conda.yml b/.github/workflows/phono3py-pytest-conda.yml index ad620453..1df4515a 100644 --- a/.github/workflows/phono3py-pytest-conda.yml +++ b/.github/workflows/phono3py-pytest-conda.yml @@ -28,7 +28,7 @@ jobs: - name: Install phonopy develop branch run: | conda activate test - git clone --depth 1 https://github.com/phonopy/phonopy.git + git clone https://github.com/phonopy/phonopy.git cd phonopy pip install -e . -vvv cd .. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 84862979..b76dcf07 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: exclude: ^example/AlN-LDA/ - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.1 + rev: v0.6.4 hooks: - id: ruff args: [ "--fix", "--show-fixes" ] diff --git a/doc/changelog.md b/doc/changelog.md index b703de32..25cf858f 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,6 +2,10 @@ # Change Log +## Sep-13-2024: Version 3.5 + +- Maintenance release. + ## Aug-23-2024: Version 3.4 - Update for spglib v2.5 and for following the change in phonopy. diff --git a/doc/command-options.md b/doc/command-options.md index 635150fb..b4957714 100644 --- a/doc/command-options.md +++ b/doc/command-options.md @@ -86,8 +86,7 @@ These options have no respective configuration file tags. This is used to create `FORCES_FC3` from `phono3py_disp.yaml` and force calculator outputs containing forces in supercells. `phono3py_disp.yaml` has to -be located at the current directory. Calculator interface has to be specified -except for VASP (default) case. +be located at the current directory. ```bash % phono3py --cf3 disp-{00001..00755}/vasprun.xml @@ -97,14 +96,26 @@ except for VASP (default) case. % phono3py --cf3 supercell_out/disp-{00001..00111}/Si.out ``` +````{note} +The calculator interface should be stored in `phono3py_disp.yaml`, so it is not +needed to set it manually. Command-line-options like `--qe` will be ignored. If +the calculator interface is missing from `phono3py_disp.yaml` but needed, please +update the `phono3py` section in the file as follows: + +```yaml +phono3py: + calculator: qe +``` +```` + (cf3_file_option)= ### `--cf3-file` (command option only) This is used to create `FORCES_FC3` from a text file containing a list of calculator output file names. `phono3py_disp.yaml` has to be located at the -current directory. Calculator interface has to be specified except for VASP -(default) case. +current directory. The calculator interface is unnecessary to specify, see the +note at {ref}`--cf3 `. ```bash % phono3py --cf3-file file_list.dat @@ -130,8 +141,9 @@ together with `--cutoff-pair` option. This is used to create `FORCES_FC2` similarly to `--cf3` option. `phono3py_disp.yaml` has to be located at the current directory. This is -optional. Calculator interface has to be specified except for VASP (default) -case. `FORCES_FC2` is necessary to run with `--dim-fc2` option. +optional. `FORCES_FC2` is necessary to run with `--dim-fc2` option. The +calculator interface is unnecessary to specify, see the note at {ref}`--cf3 +`. ```bash % phono3py --cf2 disp_fc2-{00001..00002}/vasprun.xml @@ -142,8 +154,8 @@ case. `FORCES_FC2` is necessary to run with `--dim-fc2` option. ### `--cfz` (command option only) This is used to create `FORCES_FC3` and `FORCES_FC2` subtracting residual forces -combined with `--cf3` and `--cf2`, respectively. Calculator interface has to be -specified except for VASP (default) case. +combined with `--cf3` and `--cf2`, respectively. The calculator interface is +unnecessary to specify, see the note at {ref}`--cf3 `. In the following example, it is supposed that `disp3-00000/vasprun.xml` and `disp2-00000/vasprun.xml` contain the forces of the perfect supercells. In ideal @@ -204,7 +216,6 @@ When using with `--cf2`, `--cf3` has to be specified simultaneously as below, % phono3py --cf3 disp-{00001..00755}/vasprun.xml --cf2 disp_fc2-{00001..00002}/vasprun.xml --sp ``` - ## Supercell, primitive cell, masses, magnetic moments (dim_option)= @@ -299,6 +310,7 @@ web page](https://phonopy.github.io/phonopy/setting-tags.html#magmom). ## Displacement creation (create_displacements_option)= + ### `-d` (`CREATE_DISPLACEMENTS = .TRUE.`) **`phono3py-load` doesn't have this option.** @@ -317,6 +329,7 @@ information about primitive cell (`primitive_matrix` key) in ``` (random_displacements_option)= + ### `--rd` (`RANDOM_DISPLACEMENTS`), `--rd-fc2` (`RANDOM_DISPLACEMENTS_FC2`) and `--random-seed` (`RANDOM_SEED`) **`phono3py-load` doesn't have this option.** @@ -336,6 +349,7 @@ and/or `--rd-fc2`, ``` (amplitude_option)= + ### `--amplitude` (`DISPLACEMENT_DISTANCE`) **`phono3py-load` doesn't have this option.** @@ -348,6 +362,7 @@ 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. @@ -357,14 +372,17 @@ Choice of force constants calculator. ``` To use different force constants calculators for fc2 and fc3 + ```bash % phono3py-load --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. @@ -608,9 +626,9 @@ $$ \bigl|\Phi_{-\lambda\lambda'\lambda''}\bigl|^2 \left\{(n_{\lambda'}+ n_{\lambda''}+1) \delta(\omega-\omega_{\lambda'}-\omega_{\lambda''}) \right. - + (n_{\lambda'}-n_{\lambda''}) + * (n_{\lambda'}-n_{\lambda''}) \left[\delta(\omega+\omega_{\lambda'}-\omega_{\lambda''}) -+ \left. \delta(\omega-\omega_{\lambda'}+\omega_{\lambda''}) +* \left. \delta(\omega-\omega_{\lambda'}+\omega_{\lambda''}) \right]\right\}. $$ @@ -840,7 +858,7 @@ $$ \bigl|\Phi_{-\lambda\lambda_1\lambda_2}\bigl|^2 (n_{\lambda_1}-n_{\lambda_2}) \left[\delta(\omega+\omega_{\lambda_1}-\omega_{\lambda_2}) - + \delta(\omega-\omega_{\lambda_1}+\omega_{\lambda_2}) + * \delta(\omega-\omega_{\lambda_1}+\omega_{\lambda_2}) \right] \end{align*} $$ @@ -854,7 +872,7 @@ $$ \bigl|\Phi_{-\lambda\lambda_1\lambda_2}\bigl|^2 (n_{\lambda_1}+ n_{\lambda_2}+1) \left[ \delta(\omega-\omega_{\lambda_1}-\omega_{\lambda_2}) - + \delta(\omega + \omega_{\lambda_1} + \omega_{\lambda_2}) \right] + * \delta(\omega + \omega_{\lambda_1} + \omega_{\lambda_2}) \right] \end{align*}, $$ @@ -922,11 +940,11 @@ $$ \bigl|\Phi_{-\lambda\lambda_1\lambda_2}\bigl|^2 & \left\{(n_{\lambda_1}+ n_{\lambda_2}+1) \left[ \delta(\omega-\omega_{\lambda_1}-\omega_{\lambda_2}) - + \delta(\omega+\omega_{\lambda_1}+\omega_{\lambda_2}) \right] \right. + * \delta(\omega+\omega_{\lambda_1}+\omega_{\lambda_2}) \right] \right. \\ & + (n_{\lambda_1}-n_{\lambda_2}) \left[\delta(\omega+\omega_{\lambda_1}-\omega_{\lambda_2}) - + \left. \delta(\omega-\omega_{\lambda_1}+\omega_{\lambda_2}) + * \left. \delta(\omega-\omega_{\lambda_1}+\omega_{\lambda_2}) \right]\right\}, \end{align*} $$ @@ -941,14 +959,14 @@ $$ \left\{ \left[ \frac{(n_{\lambda_1}+ n_{\lambda_2}+1)}{ (\omega-\omega_{\lambda_1}-\omega_{\lambda_2})_\mathrm{p}} - + \frac{(n_{\lambda_1}+ n_{\lambda_2}+1)}{ + * \frac{(n_{\lambda_1}+ n_{\lambda_2}+1)}{ (\omega+\omega_{\lambda_1}+\omega_{\lambda_2})_\mathrm{p}} \right] \right. \\ & + \left[ \frac{(n_{\lambda_1}-n_{\lambda_2})}{(\omega + \omega_{\lambda_1} - \omega_{\lambda_2})_\mathrm{p}} - + \left. \frac{(n_{\lambda_1}-n_{\lambda_2})}{(\omega - + * \left. \frac{(n_{\lambda_1}-n_{\lambda_2})}{(\omega - \omega_{\lambda_1} + \omega_{\lambda_2})_\mathrm{p}} \right]\right\}, \end{align*} @@ -1012,7 +1030,7 @@ A_\lambda(\omega) = \frac{1}{\pi} \frac{4\Omega^2_\lambda \Gamma_\lambda(\omega)} {\left[\omega^2 - \Omega^2_\lambda - 2\Omega_\lambda \Delta_\lambda(\omega) \right]^2 - + \left[ 2\Omega_\lambda + * \left[ 2\Omega_\lambda \Gamma_\lambda(\omega) \right]^2}, $$ @@ -1348,12 +1366,12 @@ Using this option, output file names are slightly modified. For example, with This rule is applied to -+ `fc3.hdf5` -+ `fc2.hdf5` -+ `kappa-xxx.hdf5` -+ `phonon-xxx.hdf5` -+ `pp-xxx.hdf5` -+ `gamma_detail-xxx.hdf5` (write only) +* `fc3.hdf5` +* `fc2.hdf5` +* `kappa-xxx.hdf5` +* `phonon-xxx.hdf5` +* `pp-xxx.hdf5` +* `gamma_detail-xxx.hdf5` (write only) (input_filename_option)= @@ -1367,11 +1385,11 @@ specifying `-i iso --fc3`, a file name `fc3.iso.hdf5` is read instead of This rule is applied to -+ `fc3.hdf5` -+ `fc2.hdf5` -+ `kappa-xxx.hdf5` -+ `phonon-xxx.hdf5` -+ `pp-xxx.hdf5` +* `fc3.hdf5` +* `fc2.hdf5` +* `kappa-xxx.hdf5` +* `phonon-xxx.hdf5` +* `pp-xxx.hdf5` ### `--io` (command option only) diff --git a/doc/conf.py b/doc/conf.py index 19a19a0b..cb1804de 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -58,9 +58,9 @@ # built documents. # # The short X.Y version. -version = "3.3" +version = "3.5" # The full version, including alpha/beta/rc tags. -release = "3.3.4" +release = "3.5.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/index.md b/doc/index.md index 0ec63523..d7272258 100644 --- a/doc/index.md +++ b/doc/index.md @@ -30,11 +30,8 @@ Papers that may introduce phono3py: [JPCM.35.353001](https://iopscience.iop.org/article/10.1088/1361-648X/acd831) (open access) - -## Documentation - ```{toctree} -:maxdepth: 1 +:hidden: install workflow examples diff --git a/phono3py/api_phono3py.py b/phono3py/api_phono3py.py index 00d54efe..c1d8da07 100644 --- a/phono3py/api_phono3py.py +++ b/phono3py/api_phono3py.py @@ -58,8 +58,10 @@ from phonopy.interface.pypolymlp import ( PypolymlpData, PypolymlpParams, + develop_mlp_by_pypolymlp, develop_polymlp, evalulate_polymlp, + load_polymlp, parse_mlp_params, ) from phonopy.structure.atoms import PhonopyAtoms @@ -2203,31 +2205,20 @@ def develop_mlp( if self._mlp_dataset is None: raise RuntimeError("MLP dataset is not set.") - if params is not None: - _params = parse_mlp_params(params) - else: - _params = params - - disps = self._mlp_dataset["displacements"] - forces = self._mlp_dataset["forces"] - energies = self._mlp_dataset["supercell_energies"] - n = int(len(disps) * (1 - test_size)) - train_data = PypolymlpData( - displacements=disps[:n], forces=forces[:n], supercell_energies=energies[:n] - ) - test_data = PypolymlpData( - displacements=disps[n:], forces=forces[n:], supercell_energies=energies[n:] - ) - self._mlp = develop_polymlp( + self._mlp = develop_mlp_by_pypolymlp( + self._mlp_dataset, self._supercell, - train_data, - test_data, - params=_params, - verbose=self._log_level - 1 > 0, + params=params, + test_size=test_size, + log_level=self._log_level, ) + def load_mlp(self, filename: str = "phono3py.pmlp"): + """Load machine learning potential of pypolymlp.""" + self._mlp = load_polymlp(filename=filename) + def evaluate_mlp(self): - """Evaluate the machine learning potential of pypolymlp. + """Evaluate machine learning potential of pypolymlp. This method calculates the supercell energies and forces from the MLP for the displacements in self._dataset of type 2. The results are stored diff --git a/phono3py/cui/create_force_constants.py b/phono3py/cui/create_force_constants.py index c4a41cd3..94c82b46 100644 --- a/phono3py/cui/create_force_constants.py +++ b/phono3py/cui/create_force_constants.py @@ -118,19 +118,28 @@ def create_phono3py_force_constants( if settings.read_fc3: _read_phono3py_fc3(phono3py, symmetrize_fc3r, input_filename, log_level) else: # fc3 from FORCES_FC3 or ph3py_yaml - _read_dataset_fc3( + dataset = _read_dataset_fc3( phono3py, ph3py_yaml, phono3py_yaml_filename, settings.cutoff_pair_distance, calculator, - settings.use_pypolymlp, - settings.mlp_params, - settings.displacement_distance, - settings.random_displacements, - settings.random_seed, log_level, ) + + if settings.use_pypolymlp: + phono3py.mlp_dataset = dataset + run_pypolymlp_to_compute_forces( + phono3py, + settings.mlp_params, + displacement_distance=settings.displacement_distance, + number_of_snapshots=settings.random_displacements, + random_seed=settings.random_seed, + log_level=log_level, + ) + else: + phono3py.dataset = dataset + phono3py.produce_fc3( symmetrize_fc3r=symmetrize_fc3r, is_compact_fc=settings.is_compact_fc, @@ -214,7 +223,7 @@ def parse_forces( fc_type: Literal["fc3", "phonon_fc2"] = "fc3", calculator: Optional[str] = None, log_level=0, -): +) -> dict: """Read displacements and forces. Physical units of displacements and forces are converted following the @@ -259,7 +268,6 @@ def parse_forces( distance_to_A=physical_units["distance_to_A"], force_to_eVperA=physical_units["force_to_eVperA"], ) - assert dataset is not None if "natom" in dataset and dataset["natom"] != natom: @@ -273,6 +281,12 @@ def parse_forces( f'Displacement dataset for {fc_type} was read from "{filename_read_from}".' ) + if calculator is not None and log_level: + print( + f"Displacements and forces were converted from {calculator} " + "unit to A and eV/A." + ) + # Overwrite dataset['cutoff_distance'] when necessary. if fc_type == "fc3" and cutoff_pair_distance: if "cutoff_distance" not in dataset or ( @@ -454,13 +468,8 @@ def _read_dataset_fc3( phono3py_yaml_filename: Optional[str], cutoff_pair_distance: Optional[float], calculator: Optional[str], - use_pypolymlp: bool, - mlp_params: Union[str, dict, PypolymlpParams], - displacement_distance: Optional[float], - number_of_snapshots: Optional[int], - random_seed: Optional[int], log_level: int, -): +) -> dict: """Read or calculate fc3. Note @@ -496,18 +505,7 @@ def _read_dataset_fc3( # from _get_type2_dataset file_exists(e.filename, log_level=log_level) - if use_pypolymlp: - phono3py.mlp_dataset = dataset - run_pypolymlp_to_compute_forces( - phono3py, - mlp_params, - displacement_distance=displacement_distance, - number_of_snapshots=number_of_snapshots, - random_seed=random_seed, - log_level=log_level, - ) - else: - phono3py.dataset = dataset + return dataset def run_pypolymlp_to_compute_forces( @@ -516,6 +514,7 @@ def run_pypolymlp_to_compute_forces( displacement_distance: Optional[float] = None, number_of_snapshots: Optional[int] = None, random_seed: Optional[int] = None, + mlp_filename: str = "phono3py.pmlp", log_level: int = 0, ): """Run pypolymlp to compute forces.""" @@ -529,12 +528,21 @@ def run_pypolymlp_to_compute_forces( for k, v in asdict(parse_mlp_params(mlp_params)).items(): if v is not None: print(f" {k}: {v}") - if log_level > 1: - print("") - if log_level: - print("Developing MLPs by pypolymlp...", flush=True) - ph3py.develop_mlp(params=mlp_params) + if forces_in_dataset(ph3py.mlp_dataset): + if log_level: + print("Developing MLPs by pypolymlp...", flush=True) + ph3py.develop_mlp(params=mlp_params) + ph3py.mlp.save_mlp(filename=mlp_filename) + if log_level: + print(f'MLPs were written into "{mlp_filename}"', flush=True) + else: + if pathlib.Path(mlp_filename).exists(): + if log_level: + print(f'Load MLPs from "{mlp_filename}".') + ph3py.load_mlp(mlp_filename) + else: + raise RuntimeError(f'"{mlp_filename}" is not found.') if log_level: print("-" * 30 + " pypolymlp end " + "-" * 31, flush=True) @@ -572,9 +580,6 @@ def run_pypolymlp_to_compute_forces( flush=True, ) - if ph3py.mlp_dataset is None: - msg = "mlp_dataset has to be set before calling this method." - raise RuntimeError(msg) if ph3py.supercells_with_displacements is None: raise RuntimeError("Displacements are not set. Run generate_displacements.") @@ -601,8 +606,6 @@ def run_pypolymlp_to_compute_phonon_forces( for k, v in asdict(parse_mlp_params(mlp_params)).items(): if v is not None: print(f" {k}: {v}") - if log_level > 1: - print("") if log_level: print("Developing MLPs by pypolymlp...", flush=True) diff --git a/phono3py/cui/create_force_sets.py b/phono3py/cui/create_force_sets.py index 57c69570..84bec1ff 100644 --- a/phono3py/cui/create_force_sets.py +++ b/phono3py/cui/create_force_sets.py @@ -44,7 +44,7 @@ from phonopy.cui.create_force_sets import check_number_of_force_files from phonopy.cui.load_helper import get_nac_params from phonopy.cui.phonopy_script import file_exists, files_exist, print_error -from phonopy.file_IO import parse_FORCE_SETS, write_FORCE_SETS +from phonopy.file_IO import is_file_phonopy_yaml, parse_FORCE_SETS, write_FORCE_SETS from phonopy.interface.calculator import get_calc_dataset from phono3py.file_IO import ( @@ -72,10 +72,24 @@ def create_FORCES_FC3_and_FORCES_FC2( """ interface_mode = settings.calculator + disp_filename_candidates = [ "phono3py_disp.yaml", ] - if cell_filename is not None: + + if log_level: + print("") + + if ( + log_level + and cell_filename is not None + and not is_file_phonopy_yaml(cell_filename, keyword="phono3py") + ): + print(f'*Unnecessary to specify "{cell_filename}".') + + if cell_filename is not None and is_file_phonopy_yaml( + cell_filename, keyword="phono3py" + ): disp_filename_candidates.insert(0, cell_filename) disp_filenames = files_exist( disp_filename_candidates, log_level=log_level, is_any=True @@ -86,6 +100,10 @@ def create_FORCES_FC3_and_FORCES_FC2( if ph3py_yaml.calculator is not None: interface_mode = ph3py_yaml.calculator # overwrite + if interface_mode is not None: + if log_level: + print(f"Calculator interface: {interface_mode}") + if settings.create_forces_fc3 or settings.create_forces_fc3_file: calc_dataset_fc3 = _get_force_sets_fc3( settings, ph3py_yaml.dataset, disp_filename, interface_mode, log_level @@ -172,7 +190,9 @@ def create_FORCE_SETS_from_FORCES_FCx( phonon_smat, input_filename: Optional[str], cell_filename: Optional[str], log_level ): """Convert FORCES_FC3 or FORCES_FC2 to FORCE_SETS.""" - if cell_filename is not None: + if cell_filename is not None and is_file_phonopy_yaml( + cell_filename, keyword="phono3py" + ): disp_filename = cell_filename elif input_filename is None: disp_filename = "phono3py_disp.yaml" @@ -286,7 +306,6 @@ def _get_force_sets_fc3( settings, disp_dataset, disp_filename, interface_mode, log_level ) -> dict: if log_level: - print("") print(f'FC3 Displacement dataset was read from "{disp_filename}".') if "first_atoms" in disp_dataset: # type-1 diff --git a/phono3py/cui/load.py b/phono3py/cui/load.py index f87d6e2c..e4dda9d0 100644 --- a/phono3py/cui/load.py +++ b/phono3py/cui/load.py @@ -416,7 +416,8 @@ def set_dataset_and_force_constants( ) if not read_fc["fc3"]: if use_pypolymlp: - ph3py.mlp_dataset = dataset + if forces_in_dataset(dataset): + ph3py.mlp_dataset = dataset else: ph3py.dataset = dataset read_fc["fc2"], phonon_dataset = _get_dataset_phonon_dataset_or_fc2( @@ -461,8 +462,8 @@ def compute_force_constants_from_datasets( """ fc3_calculator = extract_fc2_fc3_calculators(fc_calculator, 3) fc2_calculator = extract_fc2_fc3_calculators(fc_calculator, 2) - if not read_fc["fc3"] and (ph3py.dataset or ph3py.mlp_dataset): - if use_pypolymlp and forces_in_dataset(ph3py.mlp_dataset): + if not read_fc["fc3"]: + if use_pypolymlp: run_pypolymlp_to_compute_forces( ph3py, mlp_params=mlp_params, diff --git a/phono3py/cui/phono3py_script.py b/phono3py/cui/phono3py_script.py index 943b9311..2f699db2 100644 --- a/phono3py/cui/phono3py_script.py +++ b/phono3py/cui/phono3py_script.py @@ -163,18 +163,23 @@ def finalize_phono3py( else: yaml_filename = filename - _physical_units = get_default_physical_units(phono3py.calculator) + if phono3py.mlp_dataset is not None: + mlp_eval_filename = "phono3py_mlp_eval_dataset.yaml" + if log_level: + print( + f'Dataset generated using MMLPs was written in "{mlp_eval_filename}".' + ) + phono3py.save(mlp_eval_filename) - write_force_sets = phono3py.mlp is not None - _write_displacements = write_displacements or phono3py.mlp is not None + _physical_units = get_default_physical_units(phono3py.calculator) ph3py_yaml = Phono3pyYaml( configuration=confs_dict, calculator=phono3py.calculator, physical_units=_physical_units, settings={ - "force_sets": write_force_sets, - "displacements": _write_displacements, + "force_sets": False, + "displacements": write_displacements, }, ) ph3py_yaml.set_phonon_info(phono3py) @@ -281,7 +286,7 @@ def read_phono3py_settings(args, argparse_control, log_level): args=args, default_settings=argparse_control ) cell_filename = args.filename[0] - else: + else: # args.filename[0] is assumed to be phono3py-conf file. phono3py_conf_parser = Phono3pyConfParser( filename=args.filename[0], args=args, @@ -1033,6 +1038,7 @@ def main(**argparse_control): unitcell_filename, input_filename, output_filename, + interface_mode, ) if phono3py.supercell.magnetic_moments is None: diff --git a/phono3py/cui/show_log.py b/phono3py/cui/show_log.py index 650a5657..c03f90b6 100644 --- a/phono3py/cui/show_log.py +++ b/phono3py/cui/show_log.py @@ -46,7 +46,13 @@ def show_general_settings( - settings, run_mode, phono3py, cell_filename, input_filename, output_filename + settings, + run_mode, + phono3py, + cell_filename, + input_filename, + output_filename, + interface_mode, ): """Show general setting information.""" is_primitive_axes_auto = ( @@ -58,28 +64,32 @@ def show_general_settings( phonon_supercell_matrix = phono3py.phonon_supercell_matrix print("-" * 29 + " General settings " + "-" * 29) - print("Run mode: %s" % run_mode) + if run_mode: + print("Run mode: {run_mode}") if output_filename: - print("Output filename is modified by %s." % output_filename) + print(f"Output filename is modified by {output_filename}.") if input_filename: - print("Input filename is modified by %s." % input_filename) + print(f"Input filename is modified by {input_filename}.") if settings.hdf5_compression: - print("HDF5 data compression filter: %s" % settings.hdf5_compression) - - if phono3py.calculator: - print("Calculator interface: %s" % phono3py.calculator) - print('Crystal structure was read from "%s".' % cell_filename) + print(f"HDF5 data compression filter: {settings.hdf5_compression}") + if interface_mode: + print( + f'Crystal structure was read from "{cell_filename}" ' + f"in {interface_mode} unit." + ) + else: + print(f'Crystal structure was read from "{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) + print(f" {v}") elif primitive_matrix is not None: print("Primitive matrix:") for v in primitive_matrix: - print(" %s" % v) + print(f" {v}") def print_supercell_matrix( diff --git a/phono3py/phonon3/displacement_fc3.py b/phono3py/phonon3/displacement_fc3.py index f769c900..9afd6eac 100644 --- a/phono3py/phonon3/displacement_fc3.py +++ b/phono3py/phonon3/displacement_fc3.py @@ -272,7 +272,7 @@ def get_bond_symmetry( def get_least_orbits(atom_index, cell, site_symmetry, symprec=1e-5): """Find least orbits for a centering atom.""" orbits = _get_orbits(atom_index, cell, site_symmetry, symprec) - mapping = np.arange(cell.get_number_of_atoms()) + mapping = np.arange(len(cell)) for i, orb in enumerate(orbits): for num in np.unique(orb): diff --git a/phono3py/phonon3/reciprocal_to_normal.py b/phono3py/phonon3/reciprocal_to_normal.py index 9cf2970e..4db52090 100644 --- a/phono3py/phonon3/reciprocal_to_normal.py +++ b/phono3py/phonon3/reciprocal_to_normal.py @@ -88,7 +88,7 @@ def _reciprocal_to_normal(self, grid_triplet): self._fc3_normal[i, j, k] = fc3_elem / fff def _sum_in_atoms(self, band_indices, eigvecs): - num_atom = self._primitive.get_number_of_atoms() + num_atom = len(self._primitive) (e1, e2, e3) = eigvecs (b1, b2, b3) = band_indices diff --git a/phono3py/version.py b/phono3py/version.py index cb1c9419..d6368a53 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.4.0" +__version__ = "3.5.0" diff --git a/pyproject.toml b/pyproject.toml index c9709b36..af837355 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [ "matplotlib>=2.2.2", "h5py>=3.0", "spglib>=2.3", - "phonopy>=2.27,<2.28", + "phonopy>=2.28,<2.29", ] license = { file = "LICENSE" } diff --git a/setup-legacy.cfg b/setup-legacy.cfg deleted file mode 100644 index 01d3497b..00000000 --- a/setup-legacy.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[options] -package_dir= - =. -packages=find: - -[options.packages.find] -where=. diff --git a/setup-legacy.py b/setup-legacy.py deleted file mode 100644 index 1784f761..00000000 --- a/setup-legacy.py +++ /dev/null @@ -1,340 +0,0 @@ -"""Phono3py setup.py. - -Cmake handles automatic finding of library. -Custom settings should be written in site.cfg. - -To fully customize using site.cfg, -set PHONO3PY_USE_CMAKE=false to avoid running cmake. - -""" - -import os -import pathlib -import shutil -import subprocess - -import numpy -import setuptools - -if ( - "PHONO3PY_USE_CMAKE" in os.environ - and os.environ["PHONO3PY_USE_CMAKE"].lower() == "false" -): - use_cmake = False -else: - use_cmake = True - - -def _run_cmake(build_dir): - build_dir.mkdir() - args = [ - "cmake", - "-S", - ".", - "-B", - "_build", - "-DPHONONCALC=on", - "-DPHPHCALC=on", - "-DCMAKE_INSTALL_PREFIX=.", - ] - if ( - "PHPHCALC_USE_MTBLAS" in os.environ - and os.environ["PHPHCALC_USE_MTBLAS"].lower() == "true" - ): - args.append("-DPHPHCALC_USE_MTBLAS=on") - - # if "CONDA_PREFIX" in os.environ: - # args.append("-DUSE_CONDA_PATH=on") - # if "CC" in os.environ: - # args.append(f'-DCMAKE_C_COMPILER={os.environ["CC"]}') - - cmake_output = subprocess.check_output(args) - print(cmake_output.decode("utf-8")) - subprocess.check_call(["cmake", "--build", "_build", "-v"]) - return cmake_output - - -def _clean_cmake(build_dir): - if build_dir.exists(): - shutil.rmtree(build_dir) - - -def _get_params_from_site_cfg(): - """Read extra_compile_args and extra_link_args. - - Examples - -------- - # For macOS - extra_compile_args = -fopenmp=libomp - extra_link_args = -lomp -lopenblas - - # For linux - extra_compile_args = -fopenmp - extra_link_args = -lgomp -lopenblas -lpthread - - """ - params = { - "define_macros": [], - "extra_link_args": [], - "extra_compile_args": [], - "extra_objects": [], - "include_dirs": [], - } - use_mkl_lapacke = False - use_threaded_blas = False - - site_cfg_file = pathlib.Path.cwd() / "site.cfg" - if not site_cfg_file.exists(): - return params - - with open(site_cfg_file) as f: - lines = [line.strip().split("=", maxsplit=1) for line in f] - - for line in lines: - if len(line) < 2: - continue - key = line[0].strip() - val = line[1].strip() - if key not in params: - continue - if key == "define_macros": - pair = val.split(maxsplit=1) - if pair[1].lower() == "none": - pair[1] = None - params[key].append(tuple(pair)) - else: - if "mkl" in val: - use_mkl_lapacke = True - if "openblas" in val: - use_threaded_blas = True - params[key] += val.split() - - if use_mkl_lapacke: - params["define_macros"].append(("MKL_LAPACKE", None)) - if use_threaded_blas: - params["define_macros"].append(("MULTITHREADED_BLAS", None)) - if "THM_EPSILON" not in [macro[0] for macro in params["define_macros"]]: - params["define_macros"].append(("THM_EPSILON", "1e-10")) - - print("=============================================") - print("Parameters found in site.cfg") - for key, val in params.items(): - print(f"{key}: {val}") - print("=============================================") - return params - - -def _get_extensions(build_dir): - """Return python extension setting. - - User customization by site.cfg file - ----------------------------------- - See _get_params_from_site_cfg(). - - Automatic search using cmake - ---------------------------- - Invoked by environment variable unless PHONO3PY_USE_CMAKE=false. - - """ - params = _get_params_from_site_cfg() - extra_objects_ph3py = [] - extra_objects_phcalc = [] - - if not use_cmake or not shutil.which("cmake"): - print("** Setup without using cmake **") - sources_ph3py = [ - "c/_phono3py.c", - "c/bzgrid.c", - "c/collision_matrix.c", - "c/fc3.c", - "c/grgrid.c", - "c/imag_self_energy_with_g.c", - "c/interaction.c", - "c/isotope.c", - "c/lagrid.c", - "c/lapack_wrapper.c", - "c/phono3py.c", - "c/phonoc_utils.c", - "c/pp_collision.c", - "c/real_self_energy.c", - "c/real_to_reciprocal.c", - "c/reciprocal_to_normal.c", - "c/snf3x3.c", - "c/tetrahedron_method.c", - "c/triplet.c", - "c/triplet_grid.c", - "c/triplet_iw.c", - ] - sources_phcalc = [ - "c/_phononcalc.c", - "c/dynmat.c", - "c/lapack_wrapper.c", - "c/phonon.c", - "c/phononcalc.c", - ] - else: - print("** Setup using cmake **") - use_mkl_lapacke = False - found_extra_link_args = [] - found_extra_compile_args = [] - sources_ph3py = ["c/_phono3py.c"] - sources_phcalc = ["c/_phononcalc.c"] - cmake_output = _run_cmake(build_dir) - found_flags = {} - found_libs = {} - for line in cmake_output.decode("utf-8").split("\n"): - for key in ["BLAS", "LAPACK", "OpenMP"]: - if f"{key} libs" in line and len(line.split()) > 3: - found_libs[key] = line.split()[3].split(";") - if f"{key} flags" in line and len(line.split()) > 3: - found_flags[key] = line.split()[3].split(";") - for _, value in found_libs.items(): - found_extra_link_args += value - for element in value: - if "libmkl" in element: - use_mkl_lapacke = True - for _, value in found_flags.items(): - found_extra_compile_args += value - if use_mkl_lapacke: - params["define_macros"].append(("MKL_LAPACKE", None)) - - libph3py = list((pathlib.Path.cwd() / "_build").glob("*ph3py.*")) - if libph3py: - print("=============================================") - print(f"Phono3py library: {libph3py[0]}") - print("=============================================") - extra_objects_ph3py += [str(libph3py[0])] - - libphcalc = list((pathlib.Path.cwd() / "_build").glob("*phcalc.*")) - if libphcalc: - print("=============================================") - print(f"Phonon library: {libphcalc[0]}") - print("=============================================") - extra_objects_phcalc += [str(libphcalc[0])] - - params["extra_link_args"] += found_extra_link_args - params["extra_compile_args"] += found_extra_compile_args - - print("=============================================") - print("Parameters found by cmake") - print("extra_compile_args: ", found_extra_compile_args) - print("extra_link_args: ", found_extra_link_args) - print("define_macros: ", params["define_macros"]) - print("=============================================") - print() - - extensions = [] - params["define_macros"].append(("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")) - params["include_dirs"] += ["c", numpy.get_include()] - - extensions.append( - setuptools.Extension( - "phono3py._phono3py", - sources=sources_ph3py, - extra_link_args=params["extra_link_args"], - include_dirs=params["include_dirs"], - extra_compile_args=params["extra_compile_args"], - extra_objects=params["extra_objects"] + extra_objects_ph3py, - define_macros=params["define_macros"], - ) - ) - - extensions.append( - setuptools.Extension( - "phono3py._phononcalc", - sources=sources_phcalc, - extra_link_args=params["extra_link_args"], - include_dirs=params["include_dirs"], - extra_compile_args=params["extra_compile_args"], - extra_objects=params["extra_objects"] + extra_objects_phcalc, - define_macros=params["define_macros"], - ) - ) - return extensions - - -def _get_version() -> str: - git_num = None - version_nums = [None, None, None] - with open("phono3py/version.py") as w: - for line in w: - if "__version__" in line: - for i, num in enumerate(line.split()[2].strip('"').split(".")): - version_nums[i] = num - break - - # To deploy to pypi by travis-CI - if os.path.isfile("__nanoversion__.txt"): - nanoversion = 0 - with open("__nanoversion__.txt") as nv: - try: - for line in nv: - nanoversion = int(line.strip()) - break - except ValueError: - nanoversion = 0 - if nanoversion != 0: - version_nums.append(nanoversion) - elif git_num: - version_nums.append(git_num) - - if None in version_nums: - print("Failed to get version number in setup.py.") - raise - - version = ".".join(["%s" % n for n in version_nums[:3]]) - if len(version_nums) > 3: - version += "-%s" % version_nums[3] - return version - - -def main(build_dir): - """Run setuptools.""" - version = _get_version() - - packages_phono3py = [ - "phono3py", - "phono3py.conductivity", - "phono3py.cui", - "phono3py.interface", - "phono3py.other", - "phono3py.phonon", - "phono3py.phonon3", - "phono3py.sscha", - ] - scripts_phono3py = [ - "scripts/phono3py", - "scripts/phono3py-load", - "scripts/phono3py-kaccum", - "scripts/phono3py-kdeplot", - "scripts/phono3py-coleigplot", - ] - - setuptools.setup( - name="phono3py", - version=version, - description="This is the phono3py module.", - author="Atsushi Togo", - author_email="atz.togo@gmail.com", - url="http://phonopy.github.io/phono3py/", - packages=packages_phono3py, - python_requires=">=3.8", - install_requires=[ - "numpy>=1.17.0", - "scipy", - "PyYAML>=5.3", - "matplotlib>=2.2.2", - "h5py>=3.0", - "spglib>=2.0", - "phonopy>=2.25,<2.26", - ], - provides=["phono3py"], - scripts=scripts_phono3py, - ext_modules=_get_extensions(build_dir), - ) - _clean_cmake(build_dir) - - -if __name__ == "__main__": - build_dir = pathlib.Path.cwd() / "_build" - main(build_dir) diff --git a/test/api/test_api_phono3py.py b/test/api/test_api_phono3py.py index beb63677..98fb2bfa 100644 --- a/test/api/test_api_phono3py.py +++ b/test/api/test_api_phono3py.py @@ -173,6 +173,7 @@ def test_type2_forces_energies_setter_Si(si_111_222_rd: Phono3py): def test_use_pypolymlp_mgo(mgo_222rd_444rd: Phono3py): """Test use_pypolymlp in produce_fc3.""" pytest.importorskip("pypolymlp") + pytest.importorskip("symfc") ph3_in = mgo_222rd_444rd ph3 = Phono3py( diff --git a/test/cui/test_phono3py_load_script.py b/test/cui/test_phono3py_load_script.py index 4437e06d..c3b751b1 100644 --- a/test/cui/test_phono3py_load_script.py +++ b/test/cui/test_phono3py_load_script.py @@ -36,6 +36,7 @@ class MockArgs: is_bterta: Optional[bool] = None mesh_numbers: Optional[Sequence] = None temperatures: Optional[Sequence] = None + use_pypolymlp: bool = False input_filename = None output_filename = None input_output_filename = None @@ -114,6 +115,54 @@ def test_phono3py_with_QE_calculator(load_phono3py_yaml): file_path.unlink() +def test_phono3py_load_with_pypolymlp_si(): + """Test phono3py-load script with pypolymlp. + + First run generates phono3py.pmlp. + Second run uses phono3py.pmlp. + + """ + pytest.importorskip("pypolymlp") + pytest.importorskip("symfc") + + argparse_control = _get_phono3py_load_args( + cwd / ".." / "phono3py_params_Si-111-222-rd.yaml.xz", + fc_calculator="symfc", + use_pypolymlp=True, + ) + + with pytest.raises(SystemExit) as excinfo: + main(**argparse_control) + assert excinfo.value.code == 0 + + # phono3py.yaml and fc2.hd5 are used in the next run. So they are not deleted. + for created_filename in ("fc3.hdf5", "phono3py_mlp_eval_dataset.yaml"): + file_path = pathlib.Path(cwd_called / created_filename) + if file_path.exists(): + file_path.unlink() + + argparse_control = _get_phono3py_load_args( + cwd_called / "phono3py.yaml", + fc_calculator="symfc", + use_pypolymlp=True, + ) + + with pytest.raises(SystemExit) as excinfo: + main(**argparse_control) + assert excinfo.value.code == 0 + + for created_filename in ( + "phono3py.yaml", + "fc2.hdf5", + "fc3.hdf5", + "phono3py.pmlp", + "phono3py_mlp_eval_dataset.yaml", + ): + file_path = pathlib.Path(cwd_called / created_filename) + if file_path.exists(): + file_path.unlink() + + def _get_phono3py_load_args( phono3py_yaml_filepath: Union[str, pathlib.Path], fc_calculator: Optional[str] = None, @@ -121,6 +170,7 @@ def _get_phono3py_load_args( is_bterta: bool = False, temperatures: Optional[Sequence] = None, mesh_numbers: Optional[Sequence] = None, + use_pypolymlp: bool = False, ): # Mock of ArgumentParser.args. if load_phono3py_yaml: @@ -130,6 +180,7 @@ def _get_phono3py_load_args( is_bterta=is_bterta, temperatures=temperatures, mesh_numbers=mesh_numbers, + use_pypolymlp=use_pypolymlp, log_level=1, ) else: @@ -141,6 +192,7 @@ def _get_phono3py_load_args( is_bterta=is_bterta, temperatures=temperatures, mesh_numbers=mesh_numbers, + use_pypolymlp=use_pypolymlp, ) # See phono3py-load script. diff --git a/test/interface/test_phono3py_yaml.py b/test/interface/test_phono3py_yaml.py index 6702c50f..4972544c 100644 --- a/test/interface/test_phono3py_yaml.py +++ b/test/interface/test_phono3py_yaml.py @@ -31,7 +31,7 @@ def test_read_phono3py_yaml(): [0.0, 0.5, 0.0], [0.0, 0.0, 0.5], ], - numbers=[11, 11, 11, 11, 17, 17, 17, 17], + symbols=["Na", "Na", "Na", "Na", "Cl", "Cl", "Cl", "Cl"], ) assert isclose(cell, cell_ref)