|
| 1 | +""" |
| 2 | +Tests for MEAM pair_coeff handling in composition transformation |
| 3 | +""" |
| 4 | + |
| 5 | +import pytest |
| 6 | +from calphy.composition_transformation import CompositionTransformation |
| 7 | + |
| 8 | + |
| 9 | +def test_meam_two_file_format(): |
| 10 | + """Test that MEAM potentials with two files (library + parameter) are handled correctly""" |
| 11 | + |
| 12 | + # We'll test update_pair_coeff directly by creating a minimal mock |
| 13 | + # that has the necessary attributes but doesn't require file I/O |
| 14 | + |
| 15 | + class MinimalMock: |
| 16 | + def __init__(self): |
| 17 | + self.element = ["Si", "Al"] |
| 18 | + # For transformation from 50-50 to 30-70 Si-Al |
| 19 | + # Old: Si Al (equal amounts, one of each) |
| 20 | + # New: Si Si Al Al Al (30% Si, 70% Al - roughly) |
| 21 | + self.pair_list_old = ["Si", "Al"] |
| 22 | + self.pair_list_new = ["Si", "Al", "Al"] # More Al in output |
| 23 | + |
| 24 | + comp = MinimalMock() |
| 25 | + comp.__class__.iselement = CompositionTransformation.iselement |
| 26 | + comp.__class__.update_pair_coeff = CompositionTransformation.update_pair_coeff |
| 27 | + |
| 28 | + # MEAM format: pair_coeff * * library.meam El1 El2 parameter.meam El1 El2 |
| 29 | + pair_coeff = "* * ../potentials/library.meam Si Al ../potentials/si.meam Si Al" |
| 30 | + |
| 31 | + pc_old, pc_new = comp.update_pair_coeff(pair_coeff) |
| 32 | + |
| 33 | + print(f"\nOld: {pc_old}") |
| 34 | + print(f"New: {pc_new}") |
| 35 | + |
| 36 | + # Both element lists should be updated |
| 37 | + # The files should be preserved |
| 38 | + assert "../potentials/library.meam" in pc_old |
| 39 | + assert "../potentials/si.meam" in pc_old |
| 40 | + assert "../potentials/library.meam" in pc_new |
| 41 | + assert "../potentials/si.meam" in pc_new |
| 42 | + |
| 43 | + # Extract and verify element lists |
| 44 | + old_parts = pc_old.split() |
| 45 | + new_parts = pc_new.split() |
| 46 | + |
| 47 | + # Find file positions |
| 48 | + lib_idx_old = old_parts.index("../potentials/library.meam") |
| 49 | + param_idx_old = old_parts.index("../potentials/si.meam") |
| 50 | + lib_idx_new = new_parts.index("../potentials/library.meam") |
| 51 | + param_idx_new = new_parts.index("../potentials/si.meam") |
| 52 | + |
| 53 | + # Elements between library file and parameter file |
| 54 | + elements_after_lib_old = old_parts[lib_idx_old + 1 : param_idx_old] |
| 55 | + elements_after_lib_new = new_parts[lib_idx_new + 1 : param_idx_new] |
| 56 | + |
| 57 | + # Elements after parameter file (should be at end) |
| 58 | + elements_after_param_old = old_parts[param_idx_old + 1 :] |
| 59 | + elements_after_param_new = new_parts[param_idx_new + 1 :] |
| 60 | + |
| 61 | + # Both element lists in each command should match |
| 62 | + assert ( |
| 63 | + elements_after_lib_old == elements_after_param_old |
| 64 | + ), f"Old command has mismatched element lists: {elements_after_lib_old} vs {elements_after_param_old}" |
| 65 | + assert ( |
| 66 | + elements_after_lib_new == elements_after_param_new |
| 67 | + ), f"New command has mismatched element lists: {elements_after_lib_new} vs {elements_after_param_new}" |
| 68 | + |
| 69 | + |
| 70 | +def test_regular_pair_coeff_still_works(): |
| 71 | + """Ensure regular (single-file) pair_coeff still works after MEAM fix""" |
| 72 | + |
| 73 | + class MinimalMock: |
| 74 | + def __init__(self): |
| 75 | + self.element = ["Cu", "Zr"] |
| 76 | + self.pair_list_old = ["Cu", "Zr"] |
| 77 | + self.pair_list_new = ["Cu", "Zr", "Zr"] # More Zr |
| 78 | + |
| 79 | + comp = MinimalMock() |
| 80 | + comp.__class__.iselement = CompositionTransformation.iselement |
| 81 | + comp.__class__.update_pair_coeff = CompositionTransformation.update_pair_coeff |
| 82 | + |
| 83 | + # Regular EAM format: pair_coeff * * potential.eam.alloy El1 El2 |
| 84 | + pair_coeff = "* * CuZr.eam.alloy Cu Zr" |
| 85 | + |
| 86 | + pc_old, pc_new = comp.update_pair_coeff(pair_coeff) |
| 87 | + |
| 88 | + print(f"\nOld: {pc_old}") |
| 89 | + print(f"New: {pc_new}") |
| 90 | + |
| 91 | + assert "CuZr.eam.alloy" in pc_old |
| 92 | + assert "CuZr.eam.alloy" in pc_new |
| 93 | + |
| 94 | + # Should have element specification |
| 95 | + assert "Cu" in pc_old and "Zr" in pc_old |
| 96 | + assert "Cu" in pc_new and "Zr" in pc_new |
| 97 | + |
| 98 | + |
| 99 | +def test_meam_three_elements(): |
| 100 | + """Test MEAM with three elements""" |
| 101 | + |
| 102 | + class MinimalMock: |
| 103 | + def __init__(self): |
| 104 | + self.element = ["Al", "Si", "Mg"] |
| 105 | + self.pair_list_old = ["Al", "Si", "Mg"] |
| 106 | + self.pair_list_new = ["Al", "Al", "Si", "Mg"] # More Al |
| 107 | + |
| 108 | + comp = MinimalMock() |
| 109 | + comp.__class__.iselement = CompositionTransformation.iselement |
| 110 | + comp.__class__.update_pair_coeff = CompositionTransformation.update_pair_coeff |
| 111 | + |
| 112 | + pair_coeff = "* * library.meam Al Si Mg param.meam Al Si Mg" |
| 113 | + |
| 114 | + pc_old, pc_new = comp.update_pair_coeff(pair_coeff) |
| 115 | + |
| 116 | + print(f"\nOld: {pc_old}") |
| 117 | + print(f"New: {pc_new}") |
| 118 | + |
| 119 | + # Verify both files are present |
| 120 | + assert "library.meam" in pc_old and "library.meam" in pc_new |
| 121 | + assert "param.meam" in pc_old and "param.meam" in pc_new |
| 122 | + |
| 123 | + # Verify elements appear in both positions |
| 124 | + old_parts = pc_old.split() |
| 125 | + new_parts = pc_new.split() |
| 126 | + |
| 127 | + lib_idx_old = old_parts.index("library.meam") |
| 128 | + param_idx_old = old_parts.index("param.meam") |
| 129 | + |
| 130 | + elements_after_lib = old_parts[lib_idx_old + 1 : param_idx_old] |
| 131 | + elements_after_param = old_parts[param_idx_old + 1 :] |
| 132 | + |
| 133 | + # Both element lists should match in the old command |
| 134 | + assert elements_after_lib == elements_after_param |
| 135 | + assert len(elements_after_lib) == 3 |
0 commit comments