1# Copyright (C) 2018 Atsushi Togo 2# All rights reserved. 3# 4# This file is part of phonopy. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 10# * Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 13# * Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in 15# the documentation and/or other materials provided with the 16# distribution. 17# 18# * Neither the name of the phonopy project nor the names of its 19# contributors may be used to endorse or promote products derived 20# from this software without specific prior written permission. 21# 22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33# POSSIBILITY OF SUCH DAMAGE. 34 35import numpy as np 36from phonopy.interface.calculator import ( 37 read_crystal_structure, get_default_cell_filename) 38from phonopy.interface.vasp import read_vasp 39from phonopy.interface.phonopy_yaml import PhonopyYaml 40 41 42def collect_cell_info(supercell_matrix=None, 43 primitive_matrix=None, 44 interface_mode=None, 45 cell_filename=None, 46 chemical_symbols=None, 47 enforce_primitive_matrix_auto=False, 48 phonopy_yaml_cls=None, 49 symprec=1e-5, 50 return_dict=False): 51 # In some cases, interface mode falls back to phonopy_yaml mode. 52 fallback_reason = _fallback_to_phonopy_yaml( 53 supercell_matrix, 54 interface_mode, 55 cell_filename) 56 57 if fallback_reason: 58 _interface_mode = 'phonopy_yaml' 59 elif interface_mode is None: 60 _interface_mode = None 61 else: 62 _interface_mode = interface_mode.lower() 63 64 unitcell, optional_structure_info = read_crystal_structure( 65 filename=cell_filename, 66 interface_mode=_interface_mode, 67 chemical_symbols=chemical_symbols, 68 phonopy_yaml_cls=phonopy_yaml_cls) 69 70 # Error check 71 if unitcell is None: 72 err_msg = _get_error_message(optional_structure_info, 73 interface_mode, 74 fallback_reason, 75 cell_filename, 76 phonopy_yaml_cls) 77 return err_msg 78 79 # Retrieve more information on cells 80 (interface_mode_out, 81 supercell_matrix_out, 82 primitive_matrix_out) = _collect_cells_info( 83 _interface_mode, 84 optional_structure_info, 85 interface_mode, 86 supercell_matrix, 87 primitive_matrix, 88 enforce_primitive_matrix_auto) 89 90 # Another error check 91 msg_list = ["Crystal structure was read from \"%s\"." 92 % optional_structure_info[0], ] 93 if supercell_matrix_out is None: 94 msg_list.append( 95 "Supercell matrix (DIM or --dim) information was not found.") 96 return "\n".join(msg_list) 97 98 if np.linalg.det(unitcell.get_cell()) < 0.0: 99 msg_list.append("Lattice vectors have to follow the right-hand rule.") 100 return "\n".join(msg_list) 101 102 # Succeeded! 103 if _interface_mode == 'phonopy_yaml': 104 phpy_yaml = optional_structure_info[1] 105 else: 106 phpy_yaml = None 107 108 if return_dict: 109 return {'unitcell': unitcell, 110 'supercell_matrix': supercell_matrix_out, 111 'primitive_matrix': primitive_matrix_out, 112 'optional_structure_info': optional_structure_info, 113 'interface_mode': interface_mode_out, 114 'phonopy_yaml': phpy_yaml} 115 else: 116 return (unitcell, supercell_matrix_out, primitive_matrix_out, 117 optional_structure_info, interface_mode_out, phpy_yaml) 118 119 120def _fallback_to_phonopy_yaml(supercell_matrix, 121 interface_mode, 122 cell_filename): 123 """Find possibility to fallback to phonopy.yaml mode 124 125 Fallback happens in any of the following cases. 126 127 1. Parsing crystal structure file in the VASP POSCAR-style failed 128 2. Default VASP POSCAR-style file is not found. 129 3. supercell_matrix is not given along with (1) or (2). 130 131 Parameters 132 ---------- 133 supercell_matrix : array_like or None 134 None is given when phonopy.yaml mode is expected. 135 interface_mode : str or None 136 None is the default mode, i.e., VASP like. 137 cell_filename : str or None 138 File name of VASP style crystal structure. None means the default 139 file name, "POSCAR". 140 141 Returns 142 ------- 143 fallback_reason : str or None 144 This provides information how to handle after the fallback. 145 None means fallback to phonopy.yaml mode will not happen. 146 147 """ 148 149 fallback_reason = None 150 151 if interface_mode is None: 152 fallback_reason = _poscar_failed(cell_filename) 153 154 if fallback_reason is not None: 155 if supercell_matrix is None: 156 fallback_reason = "no supercell matrix given" 157 158 return fallback_reason 159 160 161def _poscar_failed(cell_filename): 162 """Determine if fall back happens 163 164 1) read_vasp (parsing POSCAR-style file) is failed. --> fallback 165 166 ValueError is raised by read_vasp when the POSCAR-style format 167 is broken. By this way, we assume the input crystal structure 168 is not in the POSCAR-style format and is in the phonopy.yaml 169 type. 170 171 2) The file given by get_default_cell_filename('vasp') is not 172 found at the current directory. --> fallback 173 174 This is the trigger to look for the phonopy.yaml type file. 175 176 3) The given file with cell_filename is not found. --> not fallback 177 178 This case will not invoke phonopy.yaml mode and here nothing 179 is done, i.e., fallback_reason = None. 180 This error will be caught in the following part again be 181 handled properly (read_crystal_structure). 182 183 """ 184 185 fallback_reason = None 186 try: 187 if cell_filename is None: 188 read_vasp(get_default_cell_filename('vasp')) 189 else: 190 read_vasp(cell_filename) 191 except ValueError: 192 # (1) see above 193 fallback_reason = "read_vasp parsing failed" 194 except FileNotFoundError: 195 if cell_filename is None: 196 # (2) see above 197 fallback_reason = "default file not found" 198 else: 199 # (3) see above 200 pass 201 return fallback_reason 202 203 204def _collect_cells_info(_interface_mode, 205 optional_structure_info, 206 interface_mode, 207 supercell_matrix, 208 primitive_matrix, 209 enforce_primitive_matrix_auto): 210 """This is a method just to wrap up and exclude dirty stuffs.""" 211 212 if (_interface_mode == 'phonopy_yaml' and 213 optional_structure_info[1] is not None): 214 phpy = optional_structure_info[1] 215 if phpy.calculator is None: 216 interface_mode_out = interface_mode 217 else: 218 interface_mode_out = phpy.calculator 219 if phpy.supercell_matrix is None: 220 _supercell_matrix = supercell_matrix 221 else: 222 _supercell_matrix = phpy.supercell_matrix 223 if primitive_matrix is not None: 224 _primitive_matrix = primitive_matrix 225 elif phpy.primitive_matrix is not None: 226 _primitive_matrix = phpy.primitive_matrix 227 else: 228 _primitive_matrix = 'auto' 229 else: 230 interface_mode_out = _interface_mode 231 _supercell_matrix = supercell_matrix 232 _primitive_matrix = primitive_matrix 233 234 if enforce_primitive_matrix_auto: 235 _primitive_matrix = 'auto' 236 237 if _supercell_matrix is None and _primitive_matrix == 'auto': 238 supercell_matrix_out = np.eye(3, dtype='intc') 239 else: 240 supercell_matrix_out = _supercell_matrix 241 242 primitive_matrix_out = _primitive_matrix 243 244 return interface_mode_out, supercell_matrix_out, primitive_matrix_out 245 246 247def _get_error_message(optional_structure_info, 248 interface_mode, 249 fallback_reason, 250 cell_filename, 251 phonopy_yaml_cls): 252 final_cell_filename = optional_structure_info[0] 253 if phonopy_yaml_cls is None: 254 _phonopy_yaml_cls = PhonopyYaml 255 else: 256 _phonopy_yaml_cls = phonopy_yaml_cls 257 258 if fallback_reason is None: 259 msg_list = [] 260 if cell_filename != final_cell_filename: 261 msg_list.append("Crystal structure file \"%s\" was not found." 262 % cell_filename) 263 msg_list.append("Crystal structure file \"%s\" was not found." 264 % final_cell_filename) 265 return "\n".join(msg_list) 266 267 #################################### 268 # Must be phonopy_yaml mode below. # 269 #################################### 270 271 msg_list = [] 272 if fallback_reason in ["default file not found", 273 "read_vasp parsing failed"]: 274 if cell_filename: 275 vasp_filename = cell_filename 276 else: 277 vasp_filename = get_default_cell_filename('vasp') 278 279 if fallback_reason == "read_vasp parsing failed": 280 msg_list.append( 281 "Parsing crystal structure file of \"%s\" failed." 282 % vasp_filename) 283 else: 284 msg_list.append( 285 "Crystal structure file of \"%s\" was not found." 286 % vasp_filename) 287 288 elif fallback_reason == "no supercell matrix given": 289 msg_list.append("Supercell matrix (DIM or --dim) was not explicitly " 290 "specified.") 291 292 msg_list.append("By this reason, %s_yaml mode was invoked." 293 % _phonopy_yaml_cls.command_name) 294 295 if final_cell_filename is None: # No phonopy*.yaml file was found. 296 filenames = ["\"%s\"" % name 297 for name in _phonopy_yaml_cls.default_filenames] 298 if len(filenames) == 1: 299 text = filenames[0] 300 elif len(filenames) == 2: 301 text = " and ".join(filenames) 302 else: 303 tail = " and ".join(filenames[-2:]) 304 head = ", ".join(filenames[:-2]) 305 text = head + ", " + tail 306 msg_list.append("But %s could not be found." % text) 307 return "\n".join(msg_list) 308 309 phpy = optional_structure_info[1] 310 if phpy is None: # Failed to parse phonopy*.yaml. 311 msg_list.append("But parsing \"%s\" failed." % final_cell_filename) 312 313 return "\n".join(msg_list) 314