Example #1
0
    def testDFTB(self):
        try:
            yaml_file = os.path.join(_TESTDATA_DIR, "Si2-muairss-dftb.yaml")
            cell_file = os.path.join(_TESTDATA_DIR, "Si2.cell")
            input_params = load_input_file(yaml_file, MuAirssSchema)
            with silence_stdio(True, True):
                input_atoms = io.read(cell_file)

            # Run Muairss write:
            sys.argv[1:] = ["-tw", cell_file, yaml_file]
            os.chdir(_TESTDATA_DIR)
            run_muairss()
            # Check all folders contain a dftb_in.hsd and geo_end.gen
            for rootDir, subDirs, files in os.walk(
                os.path.abspath("muon-airss-out-dftb/dftb+")
            ):
                expected_files = ["geo_end.gen", "dftb_in.hsd"]

                for s in subDirs:
                    count = 0
                    for f in expected_files:
                        f = os.path.join("muon-airss-out-dftb/dftb+/" + s, f)
                        self.assertTrue(os.path.exists(f))
                        if count == 0:
                            with silence_stdio(True, True):
                                atoms = io.read(f)
                            equal = atoms.cell == input_atoms.cell
                            self.assertTrue(equal.all())
                        count += 1

            # Run DFTB
            if _RUN_DFTB:
                subprocess.call(os.path.join(_TESTDATA_DIR, "script-dftb"))
            else:
                yaml_file = os.path.join(_TESTDATA_DIR, "Si2-muairss-dftb-read.yaml")

            input_params = load_input_file(yaml_file, MuAirssSchema)

            sys.argv[1:] = [cell_file, yaml_file]
            run_muairss()
            clust_folder = "Si2_clusters/dftb+"
            self.assertTrue(os.path.exists(clust_folder))
            self.assertTrue(
                len(
                    glob.glob(
                        os.path.join(
                            clust_folder,
                            "*.{0}".format(input_params["clustering_save_format"]),
                        )
                    )
                )
                > 0
            )

            self.assertTrue(os.path.exists("Si2_clusters.txt"))
            self.assertTrue(os.path.exists("Si2_Si2_dftb+_clusters.dat"))
        finally:
            #  Remove all created files and folders
            _clean_testdata_dir()
Example #2
0
def save_muairss_batch(args, global_params):
    structures_path = args.structures

    all_files = glob.glob(os.path.join(structures_path, "*"))
    structure_files = [
        path for path in all_files if not os.path.splitext(path)[1] == '.yaml'
    ]

    global_params['out_folder'] = safe_create_folder(
        global_params['out_folder'])

    print("Beginning creation of {} structures".format(len(structure_files)))

    for path in structure_files:
        name = parse_structure_name(path)
        parameter_file = os.path.join(structures_path, "{}.yaml".format(name))
        if not os.path.isfile(parameter_file):
            parameter_file = None

        struct = io.read(path)
        params = dict(global_params)  # Copy
        params['name'] = name
        if parameter_file is not None:
            params = load_input_file(parameter_file,
                                     MuAirssSchema,
                                     merge=params)
        params['out_folder'] = params['name']

        print("Making {} ---------------------".format(name))
        save_muairss_collection(struct,
                                params,
                                batch_path=global_params['out_folder'])

    print("Done!")
Example #3
0
def main():
    parser = ap.ArgumentParser()
    parser.add_argument('structures',
                        type=str,
                        default=None,
                        help="A structure file or a folder of files in an ASE "
                        "readable format")
    parser.add_argument('parameter_file',
                        type=str,
                        default=None,
                        help="""YAML
                        formatted file with generation parameters. The 
                        arguments can be overridden by structure-specific YAML
                        files if a folder is passed as the first argument.""")

    args = parser.parse_args()
    params = load_input_file(args.parameter_file, MuAirssSchema)

    if os.path.isdir(args.structures):
        save_muairss_batch(args, params)
    elif os.path.isfile(args.structures):
        struct = io.read(args.structures)
        save_muairss_collection(struct, params)
    else:
        raise RuntimeError("{} is neither a file or a directory".format(
            args.structures))
Example #4
0
def nq_entry():
    parser = ap.ArgumentParser()
    parser.add_argument('parameter_file',
                        type=str,
                        help="YAML file containing relevant input parameters")
    parser.add_argument(
        '-w',
        action='store_true',
        default=False,
        help="Create and write input files instead of parsing the results")

    args = parser.parse_args()

    # Load parameters
    params = load_input_file(args.parameter_file, MuonHarmonicSchema)

    # Temperature
    if params['average_T'] is None:
        params['average_T'] = params['displace_T']

    if args.w:
        muon_vibrational_average_write(**params)
    else:
        try:
            muon_vibrational_average_read(**params)
        except IOError as e:
            print('Read/write error: {0}'.format(e))
            print('\nThis could mean it was impossible to find the displaced '
                  'structure folder: maybe you wanted to run with the '
                  '-w option to write it?\n')
    def test_write(self):
        # read in cell file to get atom
        try:
            input_folder = _TESTDATA_DIR + "/Si2"
            os.chdir(input_folder)

            output_folder = "test_save"
            os.mkdir(output_folder)

            with silence_stdio():
                atoms = io.read("Si2.cell")

            # test writing geom_opt output
            param_file = "Si2-muairss-uep.yaml"
            params = load_input_file(param_file, MuAirssSchema)

            reader = ReadWriteUEP(params=params)

            reader.write(atoms, output_folder)

            self.assertTrue(
                os.path.exists(os.path.join(output_folder, "test_save.yaml")))

            params["charged"] = False

            reader = ReadWriteUEP(params=params)

            reader.write(atoms, output_folder)

        except Exception as e:
            print(e)
        finally:
            shutil.rmtree("test_save")
Example #6
0
def geomopt_entry():
    parser = ap.ArgumentParser()
    parser.add_argument('input',
                        type=str,
                        help="Input YAML file for the calculation")
    args = parser.parse_args()

    params = load_input_file(args.input, UEPOptSchema)

    seedpath = os.path.splitext(args.input)[0]
    seedname = os.path.split(seedpath)[1]

    if params['chden_seed'] is None:
        params['chden_seed'] = seedname  # Default is the same

    with open(seedpath + '.uep', 'w') as outf:
        try:
            results = geomopt(params, outf)
        except Exception as e:
            print("Error: ", e)
            return

    # Now dump results
    if params['save_pickle']:
        pickle.dump(results, open(seedpath + '.uep.pkl', 'wb'))
        muon = Atoms('H', positions=[results['x']])
    if params['save_structs']:
        io.write(seedpath + '.xyz', results['struct'] + muon)
Example #7
0
def main(task=None):
    parser = ap.ArgumentParser()
    parser.add_argument('structures',
                        type=str,
                        default=None,
                        help="A structure file or a folder of files in an ASE "
                        "readable format")
    parser.add_argument('parameter_file',
                        type=str,
                        default=None,
                        help="""YAML
                        formatted file with generation parameters. The
                        arguments can be overridden by structure-specific YAML
                        files if a folder is passed as the first argument.""")
    parser.add_argument('-t',
                        type=str,
                        default='r',
                        choices=['r', 'w'],
                        dest='task',
                        help="""Task to be run by muairss. Can be either 'w'
                        (=generate and WRITE structures) or 'r' (=READ and
                        cluster results). Default is READ.""")

    args = parser.parse_args()
    params = load_input_file(args.parameter_file, MuAirssSchema)

    if task is None:
        task = args.task

    if task == 'w':
        if os.path.isdir(args.structures):
            muairss_batch_io(args, params, True)
        elif os.path.isfile(args.structures):
            with silence_stdio():
                struct = io.read(args.structures)
            save_muairss_collection(struct, params)
        else:
            raise RuntimeError("{} is neither a file or a directory".format(
                args.structures))
    elif task == 'r':
        if os.path.isdir(args.structures):
            all_coll = muairss_batch_io(args, params)
            clusters = {}
            for name, data in all_coll.items():
                clusters[name] = muairss_cluster(data['struct'],
                                                 data['collection'], params)
        elif os.path.isfile(args.structures):
            with silence_stdio():
                struct = io.read(args.structures)
            collection = load_muairss_collection(struct, params)
            clusters = {
                params['name']: muairss_cluster(struct, collection, params)
            }
        else:
            raise RuntimeError("{} is neither a file or a directory".format(
                args.structures))
        write_cluster_report(args, params, clusters)
Example #8
0
def asephonons_entry():

    from ase import io
    from ase.calculators.dftb import Dftb
    from pymuonsuite.data.dftb_pars import DFTBArgs

    parser = ap.ArgumentParser(description="Compute phonon modes with ASE and"
                               " DFTB+ for reuse in quantum effects "
                               "calculations.")
    parser.add_argument('structure_file',
                        type=str,
                        help="Structure for which to compute the phonons")
    parser.add_argument('parameter_file',
                        type=str,
                        help="YAML file containing relevant input parameters")

    args = parser.parse_args()

    # Load parameters
    params = load_input_file(args.parameter_file, AsePhononsSchema)

    fname, fext = os.path.splitext(args.structure_file)
    if params['name'] is None:
        params['name'] = fname

    # Load structure
    a = io.read(args.structure_file)
    # Create a Dftb calculator
    dargs = DFTBArgs(params['dftb_set'])
    # Is it periodic?
    if params['pbc']:
        a.set_pbc(True)
        calc = Dftb(atoms=a,
                    label='asephonons',
                    kpts=params['kpoint_grid'],
                    **dargs.args)
        ph_kpts = params['phonon_kpoint_grid']
    else:
        a.set_pbc(False)
        calc = Dftb(atoms=a, label='asephonons', **dargs.args)
        ph_kpts = None
    a.set_calculator(calc)
    phdata = ase_phonon_calc(a,
                             kpoints=ph_kpts,
                             ftol=params['force_tol'],
                             force_clean=params['force_clean'],
                             name=params['name'])

    # Save optimised structure
    io.write(params['name'] + '_opt' + fext, phdata.structure)

    # And write out the phonons
    outf = params['name'] + '_opt.phonons.pkl'
    pickle.dump(phdata, open(outf, 'wb'))
    write_phonon_report(args, params, phdata)
Example #9
0
    def testUEP(self):
        try:
            yaml_file = os.path.join(_TESTDATA_DIR, "Si2-muairss-uep.yaml")
            cell_file = os.path.join(_TESTDATA_DIR, "Si2.cell")
            input_params = load_input_file(yaml_file, MuAirssSchema)

            # Run Muairss write:
            sys.argv[1:] = ["-tw", cell_file, yaml_file]
            os.chdir(_TESTDATA_DIR)
            run_muairss()
            # Check all folders contain a yaml file
            for (rootDir, subDirs, files) in os.walk("muon-airss-out-uep/uep/"):
                for s in subDirs:
                    expected_file = os.path.join(
                        "muon-airss-out-uep/uep/" + s, s + ".yaml"
                    )
                    self.assertTrue(os.path.exists(expected_file))
                    params = load_input_file(expected_file, UEPOptSchema)
                    self.assertEqual(params["geom_steps"], input_params["geom_steps"])
                    self.assertEqual(params["opt_tol"], input_params["geom_force_tol"])
                    self.assertEqual(params["gw_factor"], input_params["uep_gw_factor"])

            # Run UEP
            subprocess.call(os.path.join(_TESTDATA_DIR, "script-uep"))

            # Check all folders contain UEP file
            for (rootDir, subDirs, files) in os.walk("muon-airss-out-uep/uep/"):
                for s in subDirs:
                    expected_file = os.path.join(
                        "muon-airss-out-uep/uep/" + s, s + ".uep"
                    )
                    self.assertTrue(os.path.exists(expected_file))

            sys.argv[1:] = [cell_file, yaml_file]
            run_muairss()

            self.assertTrue(os.path.exists("Si2_clusters.txt"))
            self.assertTrue(os.path.exists("Si2_Si2_uep_clusters.dat"))
        finally:
            #  Remove all created files and folders
            _clean_testdata_dir()
def nq_entry():
    parser = ap.ArgumentParser()
    parser.add_argument(
        "structure",
        type=str,
        default=None,
        help="A structure file in an ASE readable format",
    )
    parser.add_argument(
        "parameter_file",
        type=str,
        help="YAML file containing relevant input parameters",
    )
    parser.add_argument(
        "-t",
        type=str,
        default="r",
        choices=["r", "w"],
        dest="task",
        help="""Task to be run by pm-nq. Can be either 'w'
                        (=generate and WRITE structures) or 'r' (=READ and
                        analyse results). Default is READ.""",
    )

    args = parser.parse_args()

    # Load parameters
    params = load_input_file(args.parameter_file, MuonHarmonicSchema)

    # Temperature
    if params["average_T"] is None:
        params["average_T"] = params["displace_T"]

    if args.task == "w":
        try:
            muon_vibrational_average_write(args.structure, **params)
        except IOError as e:
            print(e)
    else:
        try:
            muon_vibrational_average_read(args.structure, **params)
        except IOError as e:
            print("Read/write error: {0}".format(e))
            print(
                "\nThis could mean it was impossible to find the displaced "
                "structure folder: maybe you wanted to run with the "
                "-t w option to write it?\n"
            )
Example #11
0
def plot_entry():
    parser = ap.ArgumentParser()
    parser.add_argument('input',
                        type=str,
                        help="Input YAML file for the calculation")
    args = parser.parse_args()

    params = load_input_file(args.input, UEPPlotSchema)

    seedpath = os.path.splitext(args.input)[0]
    seedname = os.path.split(seedpath)[1]

    if params['chden_seed'] is None:
        params['chden_seed'] = seedname  # Default is the same

    plot(params, seedname)
Example #12
0
def muairss_batch_io(args, global_params, save=False):
    structures_path = args.structures

    all_files = glob.glob(os.path.join(structures_path, "*"))
    structure_files = [
        path for path in all_files if not os.path.splitext(path)[1] == ".yaml"
    ]

    if save:
        global_params["out_folder"] = safe_create_folder(global_params["out_folder"])

    print(
        "Beginning {0} of {1} structures".format(
            "creation" if save else "loading", len(structure_files)
        )
    )

    bpath = global_params["out_folder"]

    loaded = {}

    for path in structure_files:
        name = parse_structure_name(path)
        parameter_file = os.path.join(structures_path, "{}.yaml".format(name))
        if not os.path.isfile(parameter_file):
            parameter_file = None
        with silence_stdio():
            struct = io.read(path)
        params = dict(global_params)  # Copy
        params["name"] = name
        if parameter_file is not None:
            params = load_input_file(parameter_file, MuAirssSchema, merge=params)
        params["out_folder"] = params["name"]

        if save:
            print("Making {} ---------------------".format(name))
            save_muairss_collection(struct, params, batch_path=bpath)
        else:
            print("Loading {} ---------------------".format(name))
            coll = load_muairss_collection(struct, params, batch_path=bpath)
            loaded[name] = {"struct": struct, "collection": coll}

    print("Done!")

    if not save:
        return loaded
Example #13
0
def geomopt_entry():
    parser = ap.ArgumentParser()
    parser.add_argument('input',
                        type=str,
                        help="Input YAML file for the calculation")
    args = parser.parse_args()

    params = load_input_file(args.input, UEPSchema)

    seedpath = os.path.splitext(args.input)[0]
    seedname = os.path.split(seedpath)[1]

    if params['chden_seed'] is None:
        params['chden_seed'] = seedname  # Default is the same

    with open(seedpath + '.uep', 'w') as outf:
        results = geomopt(params, outf)

    # Now dump results
    if params['save_pickle']:
        pickle.dump(results, open(seedpath + '.uep.pkl', 'wb'))
Example #14
0
def nq_entry():
    parser = ap.ArgumentParser()
    parser.add_argument('parameter_file', type=str,
                        help="YAML file containing relevant input parameters")
    parser.add_argument('-w',   action='store_true', default=False,
                        help="Create and write input files instead of parsing the results")

    args = parser.parse_args()

    # Load parameters
    params = load_input_file(args.parameter_file, MuonHarmonicSchema)

    if args.w:
        muon_vibrational_average_write(**params)
    else:
        try:
            muon_vibrational_average_read(**params)
        except IOError:
            print('\nCould not find displaced structure folder: '
                  'maybe you wanted to run with the -w option'
                  ' to write it?\n')
Example #15
0
    def testCASTEP(self):
        try:
            yaml_file = os.path.join(_TESTDATA_DIR, "Si2-muairss-castep.yaml")
            cell_file = os.path.join(_TESTDATA_DIR, "Si2.cell")
            param_file = os.path.join(_TESTDATA_DIR, "Si2.param")
            input_params = load_input_file(yaml_file, MuAirssSchema)
            with silence_stdio(True, True):
                castep_param = read_param(param_file).param

            # Run Muairss write:
            sys.argv[1:] = ["-tw", cell_file, yaml_file]
            os.chdir(_TESTDATA_DIR)
            run_muairss()
            # Check all folders contain a yaml file
            for (rootDir, subDirs, files) in os.walk("muon-airss-out-castep/castep/"):
                for s in subDirs:
                    expected_file = os.path.join(
                        "muon-airss-out-castep/castep/" + s, s + ".cell"
                    )
                    script_file = input_params["script_file"]
                    if script_file is not None:
                        expected_script = os.path.join(
                            "muon-airss-out-castep/castep/" + s, "script.sh"
                        )
                        self.assertTrue(os.path.exists(expected_script))

                    self.assertTrue(os.path.exists(expected_file))
                    with silence_stdio():
                        atoms = io.read(expected_file)
                    self.assertEqual(
                        atoms.calc.cell.kpoint_mp_grid.value,
                        list_to_string(input_params["k_points_grid"]),
                    )
                    expected_param_file = os.path.join(
                        "muon-airss-out-castep/castep/" + s, s + ".param"
                    )
                    self.assertTrue(os.path.exists(expected_param_file))
                    with silence_stdio():
                        output_castep_param = read_param(expected_param_file).param
                    self.assertEqual(
                        output_castep_param.cut_off_energy,
                        castep_param.cut_off_energy,
                    )
                    self.assertEqual(
                        output_castep_param.elec_energy_tol,
                        castep_param.elec_energy_tol,
                    )
                    # below test didn't work as cell positions get rounded...
                    # equal = atoms.cell == input_atoms.cell
                    # self.assertTrue(equal.all())

            yaml_file = os.path.join(_TESTDATA_DIR, "Si2-muairss-castep-read.yaml")
            sys.argv[1:] = [cell_file, yaml_file]
            run_muairss()

            self.assertTrue(os.path.exists("Si2_clusters.txt"))
            self.assertTrue(os.path.exists("Si2_Si2_castep_clusters.dat"))

            # Test clustering_write_input has produced files we expect:
            self.assertTrue(os.path.exists("Si2_clusters"))
            calc_folder = "Si2_clusters/castep/"
            for (rootDir, subDirs, files) in os.walk(calc_folder):
                for s in subDirs:
                    expected_file = os.path.join(calc_folder + s, s + ".cell")
                    self.assertTrue(os.path.exists(expected_file))
                    with silence_stdio():
                        atoms = io.read(expected_file)
                    self.assertEqual(
                        atoms.calc.cell.kpoint_mp_grid.value,
                        list_to_string(input_params["k_points_grid"]),
                    )
                    expected_param_file = os.path.join(calc_folder + s, s + ".param")
                    self.assertTrue(os.path.exists(expected_param_file))
                    with silence_stdio():
                        output_castep_param = read_param(expected_param_file).param
                    self.assertEqual(
                        output_castep_param.cut_off_energy,
                        castep_param.cut_off_energy,
                    )
                    self.assertEqual(
                        output_castep_param.elec_energy_tol,
                        castep_param.elec_energy_tol,
                    )
        finally:
            # Remove all created files and folders
            _clean_testdata_dir()
import sys
import glob
from ase import io, Atoms
from ase.build import make_supercell

from pymuonsuite.utils import make_3x3
from pymuonsuite.schemas import load_input_file, MuAirssSchema

atoms = io.read(sys.argv[1])
if len(sys.argv) > 2:
    params = load_input_file(sys.argv[2], MuAirssSchema)
    scell = make_3x3(params["supercell"])
    atoms = make_supercell(atoms, scell)

for f in glob.glob("muon-airss-out/dftb+/*/geo_end.xyz"):
    a = io.read(f)
    atoms += Atoms("H", positions=a.get_positions()[-1, None, :])

io.write("merged.cif", atoms)
Example #17
0
    def test_write(self):
        # read in cell file to get atom
        try:
            input_folder = _TESTDATA_DIR + "/Si2"
            output_folder = os.path.join(_TESTDATA_DIR, "test_save")
            os.mkdir(output_folder)

            os.chdir(input_folder)

            yaml_file = os.path.join(input_folder, "Si2-muairss-castep.yaml")
            cell_file = os.path.join(input_folder, "Si2.cell")
            param_file = os.path.join(input_folder, "Si2.param")
            input_params = load_input_file(yaml_file, MuAirssSchema)

            with silence_stdio():
                castep_param = read_param(param_file).param
                atoms = io.read(cell_file)

            # test writing geom_opt output
            reader = ReadWriteCastep(params=input_params)
            reader.write(
                atoms,
                output_folder,
                sname="Si2_geom_opt",
                calc_type="GEOM_OPT",
            )

            reader.write(atoms, output_folder, sname="Si2_magres", calc_type="MAGRES")

            # # read back in and check that atom locations are preserved
            with silence_stdio():
                geom_opt_atoms = io.read(
                    os.path.join(output_folder, "Si2_geom_opt.cell")
                )
                magres_atoms = io.read(os.path.join(output_folder, "Si2_magres.cell"))
            equal = atoms.positions == geom_opt_atoms.positions
            # self.assertTrue(equal.all()) # is not true due to to rounding
            equal = geom_opt_atoms.positions == magres_atoms.positions
            self.assertTrue(equal.all())
            self.assertEqual(
                geom_opt_atoms.calc.cell.kpoint_mp_grid.value,
                list_to_string(input_params["k_points_grid"]),
            )
            self.assertEqual(
                magres_atoms.calc.cell.kpoint_mp_grid.value,
                list_to_string(input_params["k_points_grid"]),
            )

            # Test if parameters file have correct tasks:
            with silence_stdio():
                geom_params = read_param(
                    os.path.join(output_folder, "Si2_geom_opt.param")
                ).param
                magres_params = read_param(
                    os.path.join(output_folder, "Si2_magres.param")
                ).param
            self.assertEqual(geom_params.task.value, "GeometryOptimization")
            self.assertEqual(magres_params.task.value, "Magres")
            self.assertEqual(magres_params.magres_task.value, "Hyperfine")
            # These are only set in the param file only so should equal
            # the value in the param file:
            self.assertEqual(geom_params.geom_max_iter, castep_param.geom_max_iter)
            self.assertEqual(geom_params.cut_off_energy, castep_param.cut_off_energy)
            self.assertEqual(geom_params.elec_energy_tol, castep_param.elec_energy_tol)
            # This is set in the input yaml and param file so should equal
            # the value in the yaml file:
            self.assertEqual(
                geom_params.geom_force_tol.value,
                str(input_params["geom_force_tol"]),
            )

            self.assertEqual(magres_params.cut_off_energy, castep_param.cut_off_energy)
            self.assertEqual(
                magres_params.elec_energy_tol, castep_param.elec_energy_tol
            )

        finally:
            shutil.rmtree(output_folder)
def asephonons_entry():

    from ase import io
    from ase.calculators.dftb import Dftb
    from pymuonsuite.data.dftb_pars import DFTBArgs

    parser = ap.ArgumentParser(
        description="Compute phonon modes with ASE and"
        " DFTB+ for reuse in quantum effects "
        "calculations."
    )
    parser.add_argument(
        "structure_file",
        type=str,
        help="Structure for which to compute the phonons",
    )
    parser.add_argument(
        "parameter_file",
        type=str,
        help="YAML file containing relevant input parameters",
    )

    args = parser.parse_args()

    # Load parameters
    params = load_input_file(args.parameter_file, AsePhononsSchema)

    fname, fext = os.path.splitext(args.structure_file)
    if params["name"] is None:
        params["name"] = fname

    # Load structure
    with silence_stdio():
        a = io.read(args.structure_file)

    # Create a Dftb calculator
    dargs = DFTBArgs(params["dftb_set"])
    # Is it periodic?
    if params["pbc"]:
        a.set_pbc(True)
        calc = Dftb(
            atoms=a, label="asephonons", kpts=params["kpoint_grid"], **dargs.args
        )
        ph_kpts = params["phonon_kpoint_grid"]
    else:
        a.set_pbc(False)
        calc = Dftb(atoms=a, label="asephonons", **dargs.args)
        ph_kpts = None
    a.calc = calc
    try:
        phdata = ase_phonon_calc(
            a,
            kpoints=ph_kpts,
            ftol=params["force_tol"],
            force_clean=params["force_clean"],
            name=params["name"],
        )
    except Exception as e:
        print(e)
        print("Error: Could not write phonons file, see asephonons.out for" " details.")
        sys.exit(1)

    # Save optimised structure
    with silence_stdio():
        io.write(params["name"] + "_opt" + fext, phdata.structure)

    # And write out the phonons
    outf = params["name"] + "_opt.phonons.pkl"
    pickle.dump(phdata, open(outf, "wb"))
    write_phonon_report(args, params, phdata)