Ejemplo n.º 1
0
def test_parameteric_constr():
    import numpy as np

    from ase.build import bulk
    from ase.constraints import (
        dict2constraint,
        FixScaledParametricRelations,
        FixCartesianParametricRelations,
    )
    from ase.calculators.emt import EMT

    # Build the atoms object and attach a calculator
    a = bulk("Ni", cubic=True)
    a.calc = EMT()

    # Get adjusted cell
    cell = a.cell + 0.01

    # Generate lattice constraint
    param_lat = ["a"]
    expr_lat = [
        "a",
        "0",
        "0",
        "0",
        "a",
        "0",
        "0",
        "0",
        "a",
    ]
    constr_lat = FixCartesianParametricRelations.from_expressions(
        indices=[0, 1, 2],
        params=param_lat,
        expressions=expr_lat,
        use_cell=True,
    )

    # Check expression generator
    for const_expr, passed_expr in zip(constr_lat.expressions.flatten(),
                                       expr_lat):
        assert const_expr == passed_expr

    # Check adjust_cell
    constr_lat.adjust_cell(a, cell)

    # Check serialization and construction from dict
    constr_lat_dict = constr_lat.todict()
    dict2constraint(constr_lat_dict)

    cell_diff = (cell - a.cell).flatten()
    expected_cell_diff = np.array(
        [0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01])
    assert np.max(np.abs(cell_diff - expected_cell_diff)) < 1e-12

    # Check adjust_stress
    a.cell += 0.01
    stress = a.get_stress().copy()
    constr_lat.adjust_stress(a, stress)
    stress_rat = stress / a.get_stress()

    assert np.max(
        np.abs(stress_rat - np.array([1., 1., 1., 0., 0., 0.]))) < 1e-12

    # Reset cell
    a.cell -= 0.01

    # Get adjusted cell/positions for the system
    pos = a.get_positions().copy() + 0.01

    # Generate proper atomic constraints
    constr_atom = FixScaledParametricRelations(
        [0, 1, 2, 3],
        np.ndarray((12, 0)),
        a.get_scaled_positions().flatten(),
    )

    # Check serialization and construction from dict
    constr_atom_dict = constr_atom.todict()
    dict2constraint(constr_atom_dict)

    # Check adjust_positions
    constr_atom.adjust_positions(a, pos)
    assert np.max(np.abs(a.get_positions() - pos)) < 1e-12

    # Check adjust_forces
    assert np.max(np.abs(a.get_forces())) < 1e-12

    # Check non-empty constraint
    param_atom = ["dis"]
    expr_atom = [
        "dis",
        "dis",
        "dis",
        "dis",
        "-0.5",
        "0.5",
        "0.5",
        "dis",
        "0.5",
        "0.5",
        "0.5",
        "dis",
    ]

    constr_atom = FixScaledParametricRelations.from_expressions(
        indices=[0, 1, 2, 3],
        params=param_atom,
        expressions=expr_atom,
    )

    # Restart position adjustment
    pos += 0.01 * a.cell[0, 0]

    # Check adjust_positions
    constr_atom.adjust_positions(a, pos)
    scaled_pos = a.cell.scaled_positions(pos)
    pos_diff = (scaled_pos - a.get_scaled_positions()).flatten()
    expected_pos_diff = np.array(
        [0.01, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01])
    assert np.max(np.abs(pos_diff - expected_pos_diff)) < 1e-12

    # Check adjust_forces
    a.set_positions(pos + 0.3)
    forces = a.get_forces()
    constr_atom.adjust_forces(a, forces)
    forces_rat = forces / a.get_forces()

    assert np.max(
        np.abs(forces_rat.flatten() / 100.0 - expected_pos_diff)) < 1e-12

    # Check auto-remapping/expression generation, the -0.5 should now be 0.5
    expr_atom[4] = "0.5"
    current_expression = constr_atom.expressions.flatten()
    for const_expr, passed_expr in zip(current_expression, expr_atom):
        assert const_expr == passed_expr

    # Check with Cartesian parametric constraints now
    expr_atom = [
        "dis",
        "dis",
        "dis",
        "dis",
        "1.76",
        "1.76",
        "1.76",
        "dis",
        "1.76",
        "1.76",
        "1.76",
        "dis",
    ]
    constr_atom = FixCartesianParametricRelations.from_expressions(
        indices=[0, 1, 2, 3],
        params=param_atom,
        expressions=expr_atom,
    )

    # Restart position adjustment
    a.set_positions(pos)
    pos += 0.01
    # Check adjust_positions
    constr_atom.adjust_positions(a, pos)
    pos_diff = (pos - a.get_positions()).flatten()
    expected_pos_diff = np.array(
        [0.01, 0.01, 0.01, 0.01, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.01])
    assert np.max(np.abs(pos_diff - expected_pos_diff)) < 1e-12

    # Check adjust_forces
    a.set_positions(pos + 0.3)
    forces = a.get_forces()
    constr_atom.adjust_forces(a, forces)
    forces_rat = forces / a.get_forces()

    assert np.max(
        np.abs(forces_rat.flatten() / 100.0 - expected_pos_diff)) < 1e-12
Ejemplo n.º 2
0
def read_aims(filename, apply_constraints=True):
    """Import FHI-aims geometry type files.

    Reads unitcell, atom positions and constraints from
    a geometry.in file.

    If geometric constraint (symmetry parameters) are in the file
    include that information in atoms.info["symmetry_block"]
    """

    from ase import Atoms
    from ase.constraints import (
        FixAtoms,
        FixCartesian,
        FixScaledParametricRelations,
        FixCartesianParametricRelations,
    )
    import numpy as np

    atoms = Atoms()
    with open(filename, "r") as fd:
        lines = fd.readlines()

    positions = []
    cell = []
    symbols = []
    velocities = []
    magmoms = []
    symmetry_block = []
    charges = []
    fix = []
    fix_cart = []
    xyz = np.array([0, 0, 0])
    i = -1
    n_periodic = -1
    periodic = np.array([False, False, False])
    cart_positions, scaled_positions = False, False
    for line in lines:
        inp = line.split()
        if inp == []:
            continue
        if inp[0] == "atom":
            cart_positions = True
            if xyz.all():
                fix.append(i)
            elif xyz.any():
                fix_cart.append(FixCartesian(i, xyz))
            floatvect = float(inp[1]), float(inp[2]), float(inp[3])
            positions.append(floatvect)
            magmoms.append(0.0)
            charges.append(0.0)
            symbols.append(inp[-1])
            i += 1
            xyz = np.array([0, 0, 0])
        elif inp[0] == "atom_frac":
            scaled_positions = True
            if xyz.all():
                fix.append(i)
            elif xyz.any():
                fix_cart.append(FixCartesian(i, xyz))
            floatvect = float(inp[1]), float(inp[2]), float(inp[3])
            positions.append(floatvect)
            magmoms.append(0.0)
            symbols.append(inp[-1])
            i += 1
            xyz = np.array([0, 0, 0])

        elif inp[0] == "lattice_vector":
            floatvect = float(inp[1]), float(inp[2]), float(inp[3])
            cell.append(floatvect)
            n_periodic = n_periodic + 1
            periodic[n_periodic] = True

        elif inp[0] == "initial_moment":
            magmoms[-1] = float(inp[1])

        elif inp[0] == "initial_charge":
            charges[-1] = float(inp[1])

        elif inp[0] == "constrain_relaxation":
            if inp[1] == ".true.":
                fix.append(i)
            elif inp[1] == "x":
                xyz[0] = 1
            elif inp[1] == "y":
                xyz[1] = 1
            elif inp[1] == "z":
                xyz[2] = 1

        elif inp[0] == "velocity":
            floatvect = [v_unit * float(l) for l in inp[1:4]]
            velocities.append(floatvect)

        elif inp[0] in [
                "symmetry_n_params",
                "symmetry_params",
                "symmetry_lv",
                "symmetry_frac",
        ]:
            symmetry_block.append(" ".join(inp))

    if xyz.all():
        fix.append(i)
    elif xyz.any():
        fix_cart.append(FixCartesian(i, xyz))

    if cart_positions and scaled_positions:
        raise Exception("Can't specify atom positions with mixture of "
                        "Cartesian and fractional coordinates")
    elif scaled_positions and periodic.any():
        atoms = Atoms(symbols,
                      scaled_positions=positions,
                      cell=cell,
                      pbc=periodic)
    else:
        atoms = Atoms(symbols, positions)

    if len(velocities) > 0:
        if len(velocities) != len(positions):
            raise Exception(
                "Number of positions and velocities have to coincide.")
        atoms.set_velocities(velocities)

    fix_params = []

    if len(symmetry_block) > 5:
        params = symmetry_block[1].split()[1:]

        lattice_expressions = []
        lattice_params = []

        atomic_expressions = []
        atomic_params = []

        n_lat_param = int(symmetry_block[0].split(" ")[2])

        lattice_params = params[:n_lat_param]
        atomic_params = params[n_lat_param:]

        for ll, line in enumerate(symmetry_block[2:]):
            expression = " ".join(line.split(" ")[1:])
            if ll < 3:
                lattice_expressions += expression.split(",")
            else:
                atomic_expressions += expression.split(",")

        fix_params.append(
            FixCartesianParametricRelations.from_expressions(
                list(range(3)),
                lattice_params,
                lattice_expressions,
                use_cell=True,
            ))

        fix_params.append(
            FixScaledParametricRelations.from_expressions(
                list(range(len(atoms))), atomic_params, atomic_expressions))

    if any(magmoms):
        atoms.set_initial_magnetic_moments(magmoms)
    if any(charges):
        atoms.set_initial_charges(charges)

    if periodic.any():
        atoms.set_cell(cell)
        atoms.set_pbc(periodic)
    if len(fix):
        atoms.set_constraint([FixAtoms(indices=fix)] + fix_cart + fix_params)
    else:
        atoms.set_constraint(fix_cart + fix_params)

    if fix_params and apply_constraints:
        atoms.set_positions(atoms.get_positions())
    return atoms
Ejemplo n.º 3
0
# Generate lattice constraint
param_lat = ["a"]
expr_lat = [
    "a",
    "0",
    "0",
    "0",
    "a",
    "0",
    "0",
    "0",
    "a",
]
constr_lat = FixCartesianParametricRelations.from_expressions(
    indices=[0, 1, 2],
    params=param_lat,
    expressions=expr_lat,
    use_cell=True,
)

# Check expression generator
for const_expr, passed_expr in zip(constr_lat.expressions.flatten(), expr_lat):
    assert const_expr == passed_expr

# Check adjust_cell
constr_lat.adjust_cell(a, cell)

# Check serialization and construction from dict
constr_lat_dict = constr_lat.todict()
dict2constraint(constr_lat_dict)

cell_diff = (cell - a.cell).flatten()