def test_replace_in_fort3_sort_new_replace_args_non_bonds():
    tol = 1e-14
    atom_names, _, _, _, _, non_bonds, _, _, _ = _parse_fort_3_file(file_name)
    repl = (
        Fort3Replacement('non bond', replace=True, content=['O', 'O', 4, 2]),
        Fort3Replacement('non bond', replace=True, content=['H', 'H', 7, 6]),
        Fort3Replacement('non bond', new=True, content=['Be', 'H', 9.1, 3.6]),
        Fort3Replacement('non bond', new=True, content=['H+', 'O', 9.4, 3.3]),
    )
    non_bonds_new = _sort_new_replace_args_bonds(atom_names,
                                                 non_bonds,
                                                 *repl,
                                                 non_bond=True)
    assert len(non_bonds_new) == 4
    names = [('O', 'O'), ('H', 'H'), ('Be', 'H'), ('H+', 'O')]
    lengths = [4.0, 7.0, 9.1, 9.4]
    epsilons = [2.0, 6.0, 3.6, 3.3]
    for name, length, eps in zip(names, lengths, epsilons):
        found = False
        n1, n2 = name

        for non_bond in non_bonds_new:
            name_1, name_2 = non_bond._content[:2]
            if (((name_1 == n1) and (name_2 == n2))
                    or ((name_1 == n2) and (name_2 == n1))):
                found = True
                assert non_bond._content[2] == pytest.approx(length, abs=tol)
                assert non_bond._content[3] == pytest.approx(eps, abs=tol)
        assert found
def test_replace_in_fort3_sort_new_replace_args_atoms():
    tol = 1e-14
    atom_names, atoms, _, _, _, _, _, _, _ = _parse_fort_3_file(file_name)

    repl = (
        Fort3Replacement('atom', new=True, content=['P', 30.973, 0.0]),
        Fort3Replacement('atom', replace=True, content=['O', 16.000, 0.0]),
        Fort3Replacement('atom', new=True, content=['Ar-', 39.948, -1.0]),
    )
    atom_names, atoms = _sort_new_replace_args_atom(atom_names, atoms, *repl)
    assert len(atoms) == 6
    assert atoms[0]._content[0] == 'O'
    assert atoms[0]._content[1] == pytest.approx(16.0, abs=tol)
    for name, mass, charge in zip(['P', 'Ar-'], [30.973, 39.948], [0.0, -1.0]):
        found = False
        assert name in atom_names.values()
        for atom in atoms[4:]:
            if name == atom._content[0]:
                found = True
                assert atom._content[1] == pytest.approx(mass, abs=tol)
                assert atom._content[2] == pytest.approx(charge, abs=tol)
        assert found

    caught = False
    repl = (
        Fort3Replacement('atom', new=True, content=['Ar', 0]),
        Fort3Replacement('atom', new=True, content=['O', 1, 0]),
        Fort3Replacement('atom', replace=True, content=['not', 1, 0]),
    )
    for r in repl:
        try:
            _sort_new_replace_args_atom(atom_names, atoms, r)
        except ValueError:
            caught = True
        assert caught is True
def test_replace_in_fort3_sort_new_replace_args_angles():
    tol = 1e-14
    atom_names, _, _, angles, _, _, _, _, _ = _parse_fort_3_file(file_name)
    repl = (
        Fort3Replacement('angle', replace=True, content=['O', 'O', 'O', 4, 2]),
        Fort3Replacement('angle', replace=True, content=['O', 'H', 'O', 7, 6]),
        Fort3Replacement('angle', replace=True, content=['H', 'O', 'O', 3, 1]),
        Fort3Replacement('angle', new=True, content=['Be', 'H', 'H', 9, 3]),
        Fort3Replacement('angle', new=True, content=['H', 'O', 'H', 9.4, 3.3]),
    )
    angles_new = _sort_new_replace_args_angles(atom_names, angles, *repl)
    assert len(angles_new) == 7
    names = [('O', 'O', 'O'), ('O', 'H', 'O'), ('Be', 'H', 'H'),
             ('H', 'O', 'H'), ('O', 'O', 'H')]
    lengths = [4.0, 7.0, 9.0, 9.4, 3.0]
    epsilons = [2.0, 6.0, 3.0, 3.3, 1.0]
    for name, length, eps in zip(names, lengths, epsilons):
        found = False
        n1, n2, n3 = name
        for angle in angles_new:
            name_1, name_2, name_3 = angle._content[:3]
            if name_2 == n2:
                if (name_1 == n1) and (name_3 == n3):
                    found = True
                    assert angle._content[3] == pytest.approx(length, abs=tol)
                    assert angle._content[4] == pytest.approx(eps, abs=tol)
                    break
                elif (name_3 == n1) and (name_1 == n3):
                    found = True
                    assert angle._content[3] == pytest.approx(length, abs=tol)
                    assert angle._content[4] == pytest.approx(eps, abs=tol)
                    break
        assert found

    for n1, n2, n3 in zip(['not', 'H', 'O'], ['H', 'not', 'O'],
                          ['H', 'O', 'not']):
        caught = False
        repl = Fort3Replacement('angle', new=True, content=[n1, n2, n3, 0, 0]),
        try:
            _sort_new_replace_args_angles(atom_names, angles, *repl)
        except ValueError:
            caught = True
        assert caught is True

    repl = (
        Fort3Replacement('angle', new=True, content=['O', 'H', 0, 0]),
        Fort3Replacement('angle', new=True, content=['O', 'O', 'O', 0, 0]),
        Fort3Replacement('angle', replace=True, content=['.', 'H', 'A', 0, 0]),
        Fort3Replacement('angle', new=True, content=['not', 'O', 0, 0]),
        Fort3Replacement('angle', replace=True, content=['O', 'O', 'H+', 0,
                                                         0]),
    )
    for r in repl:
        caught = False
        try:
            _sort_new_replace_args_angles(atom_names, angles, r)
        except ValueError:
            caught = True
        assert caught is True
def test_replace_in_fort3_write_fort3_from_replace_objects():
    atom_names, atoms, bonds, angles, torsions, non_bonds, scf, kappa, chi = (
        _parse_fort_3_file(file_name))
    out_path = os.path.join(os.path.dirname(os.path.abspath(file_name)),
                            'example_fort.3_out')
    _write_fort3_from_replace_objects(atom_names, atoms, bonds, angles,
                                      torsions, non_bonds, scf, kappa, chi,
                                      atom_names, out_path)
    os.remove(out_path)
def test_replace_in_fort3():
    repl = (
        Fort3Replacement(property='atom', new=True, content=['Ar', 1.67, 0]),
        Fort3Replacement(property='atom', replace=True, content=['O', 16, 0]),
        Fort3Replacement(property='bond type',
                         new=True,
                         content=['Be', 'Be', 7.41, 5.42]),
        Fort3Replacement(property='bond type',
                         replace=True,
                         content=['H', 'O', 3.1, 9]),
        Fort3Replacement(property='angle',
                         new=True,
                         content=['H', 'H', 'H', 84.1, 5.9]),
        Fort3Replacement(property='angle',
                         replace=True,
                         content=['O', 'H', 'O', 16, 1]),
    )
    out_file = replace_in_fort3(file_name, None, *repl)

    with open(out_file, 'r') as in_file:
        lines = in_file.readlines()
    atom_name, _, _, _, _, _, _, _, _ = _parse_fort_3_file(out_file)
    ind = {val: key for key, val in atom_name.items()}
    expected = [
        f"{ind['Ar']} Ar 1.67 0.0", f"{ind['O']} O 16.0 0.0",
        f"{ind['Be']} {ind['Be']} 7.41 5.42", f"{ind['H']} {ind['O']} 3.1 9.0",
        f"{ind['H']} {ind['H']} {ind['H']} 84.1 5.9",
        f"{ind['O']} {ind['H']} {ind['O']} 16.0 1.0"
    ]

    for e in expected:
        found = False
        se = e.split()
        for line in lines:
            sline = line.split()
            if len(se) == len(sline):
                equal = True
                for a, b in zip(se, sline):
                    equal = _check_equal(a, b) and equal
                if equal is True:
                    found = True
                    break
        assert found is True

    caught = False
    repl = Fort3Replacement(property='bond type', content=['H', 'H', 1, 1])
    try:
        out_file = replace_in_fort3(file_name, None, repl)
    except ValueError:
        caught = True
    assert caught is True

    if os.path.exists(out_file) and os.path.isfile(out_file):
        os.remove(out_file)
def test_replace_in_fort3_replace_scf():
    inps = [[3, 4, 5], (3, 4, 5), '3 4 5', ['3 4 5'], np.array([3, 4, 5])]
    for scf_new in inps:
        replace_1 = Fort3Replacement(property='scf',
                                     replace=True,
                                     content=scf_new)
        out_path = replace_in_fort3(file_name, None, replace_1)
        _, _, _, _, _, _, scf, _, _ = _parse_fort_3_file(out_path)
        for expected, found in zip([3, 4, 5], scf):
            assert expected == found

    inps = [9, np.array([9]), [9], (9), '9']
    for scf_new in inps:
        replace_1 = Fort3Replacement(property='scf',
                                     replace=True,
                                     content=scf_new)
        out_path = replace_in_fort3(file_name, None, replace_1)
        _, _, _, _, _, _, scf, _, _ = _parse_fort_3_file(out_path)
        for expected, found in zip([9, 9, 9], scf):
            assert expected == found
    os.remove(out_path)
def test_replace_in_fort3_sort_new_replace_args_bonds():
    tol = 1e-14
    atom_names, _, bonds, _, _, _, _, _, _ = _parse_fort_3_file(file_name)
    repl = (
        Fort3Replacement('bond type', replace=True, content=['H', 'O', 4, 2]),
        Fort3Replacement('bond type', replace=True, content=['H+', 'H', 7, 6]),
        Fort3Replacement('bond type', new=True, content=['H', 'H', 9.1, 3.6]),
        Fort3Replacement('bond type', new=True, content=['H+', 'O', 9.4, 3.3]),
    )
    bonds_new = _sort_new_replace_args_bonds(atom_names, bonds, *repl)
    assert len(bonds_new) == 5
    names = [('H', 'O'), ('H+', 'H'), ('H', 'H'), ('H+', 'O')]
    lengths = [4.0, 7.0, 9.1, 9.4]
    epsilons = [2.0, 6.0, 3.6, 3.3]
    for name, length, eps in zip(names, lengths, epsilons):
        found = False
        n1, n2 = name

        for bond in bonds_new:
            name_1, name_2 = bond._content[:2]
            if (((name_1 == n1) and (name_2 == n2))
                    or ((name_1 == n2) and (name_2 == n1))):
                found = True
                assert bond._content[2] == pytest.approx(length, abs=tol)
                assert bond._content[3] == pytest.approx(eps, abs=tol)
        assert found

    for n1, n2 in zip(['not', 'H'], ['H', 'not']):
        caught = False
        repl = Fort3Replacement('bond type', new=True, content=[n1, n2, 0, 0]),
        try:
            _sort_new_replace_args_bonds(atom_names, bonds, *repl)
        except ValueError:
            caught = True
        assert caught is True

    repl = (
        Fort3Replacement('bond type', new=True, content=['O', 0, 0]),
        Fort3Replacement('bond type', new=True, content=['O', 'O', 0, 0]),
        Fort3Replacement('bond type', replace=True, content=['.', 'H', 0, 0]),
        Fort3Replacement('bond type', new=True, content=['H', 'O', 0, 0]),
        Fort3Replacement('bond type', replace=True, content=['H', 'H', 0, 0]),
    )
    for r in repl:
        caught = False
        try:
            _sort_new_replace_args_bonds(atom_names, bonds, r)
        except ValueError:
            caught = True
        assert caught is True
def test_replace_in_fort3_parse_fort_3_file():
    tol = 1e-14
    atom_names, atoms, bonds, angles, torsions, non_bonds, scf, kappa, chi = (
        _parse_fort_3_file(file_name))
    expected_names = ['O', 'H', 'Be', 'H+']
    for name in expected_names:
        assert name in atom_names.values()
    expected_masses = [15.999, 1.008, 9.012, 1.007]
    expected_charges = [0.0, 0.0, 0.0, 1.0]
    for name, mass, charge, atom in zip(expected_names, expected_masses,
                                        expected_charges, atoms):
        assert name == atom._content[0]
        assert mass == pytest.approx(atom._content[1], abs=tol)
        assert charge == pytest.approx(atom._content[2], abs=tol)

    expected_bonds = [(1, 1), (1, 2), (2, 4)]
    expected_bond_lengths = [3.21, 2.01, 5.98]
    expected_bond_eps = [2.4, 1.7, 8.8]
    for ind, length, eps, bond in zip(expected_bonds, expected_bond_lengths,
                                      expected_bond_eps, bonds):
        for a, b in zip(ind, bond._content[:2]):
            assert atom_names[a] == b
        assert bond._content[2] == pytest.approx(length, abs=tol)
        assert bond._content[3] == pytest.approx(eps, abs=tol)

    expected_bond_angles = [(1, 1, 1), (1, 2, 1), (3, 4, 3), (4, 4, 4)]
    expected_bond_theta = [75.0, 64.1, 90.9, 71.0]
    expected_bond_eps = [7.1, 4.0, 1.6, 17.2]
    for ind, theta, eps, angle in zip(expected_bond_angles,
                                      expected_bond_theta, expected_bond_eps,
                                      angles):
        for a, b in zip(ind, angle._content[:3]):
            assert atom_names[a] == b
        assert angle._content[3] == pytest.approx(theta, abs=tol)
        assert angle._content[4] == pytest.approx(eps, abs=tol)

    expected_torsions = [(1, 2, 3, 4), (2, 2, 2, 2)]
    expected_torsion_phi = [75.0, 12.5]
    expected_torsion_eps = [27.78, 0.24]
    for ind, theta, eps, torsion in zip(expected_torsions,
                                        expected_torsion_phi,
                                        expected_torsion_eps, torsions):
        for a, b in zip(ind, torsion._content[:4]):
            assert atom_names[a] == b
        assert torsion._content[4] == pytest.approx(theta, abs=tol)
        assert torsion._content[5] == pytest.approx(eps, abs=tol)

    expected_non_bonds = [(1, 1), (2, 2)]
    expected_non_bond_sigma = [1.8, 3.2]
    expected_non_bond_eps = [29.14, 2.349]
    for ind, sigma, eps, bond in zip(expected_non_bonds,
                                     expected_non_bond_sigma,
                                     expected_non_bond_eps, non_bonds):
        for a, b in zip(ind, bond._content[:2]):
            assert atom_names[a] == b
        assert bond._content[2] == pytest.approx(sigma, abs=tol)
        assert bond._content[3] == pytest.approx(eps, abs=tol)

    for m, expected in zip(scf, [5, 5, 10]):
        assert m == expected

    assert kappa == pytest.approx(1.204, abs=tol)

    expected_chi = [[0, 1, 0, -4], [1, 0, 2, 0], [0, 2, 0, 3], [-4, 0, 3, 0]]
    assert np.allclose(expected_chi, chi)