Skip to content

Commit 0b94534

Browse files
committed
Added posisbility to fix atoms in x,y,z. Updated tables accordingly
1 parent 921e4cd commit 0b94534

File tree

2 files changed

+43
-21
lines changed

2 files changed

+43
-21
lines changed

src/aiidalab_qe/app/result/components/viewer/structure/model.py

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,29 +75,48 @@ def _get_structure_info(self):
7575
"""
7676

7777
def _get_atom_table_data(self):
78-
structure = self.structure.get_ase()
79-
data = [
80-
[
81-
"Atom index",
82-
"Chemical symbol",
83-
"Tag",
84-
"x (Å)",
85-
"y (Å)",
86-
"z (Å)",
87-
]
88-
]
89-
positions = structure.positions
90-
chemical_symbols = structure.get_chemical_symbols()
91-
tags = structure.get_tags()
92-
93-
for index, (symbol, tag, position) in enumerate(
94-
zip(chemical_symbols, tags, positions), start=1
95-
):
96-
formatted_position = [f"{coord:.2f}" for coord in position]
97-
data.append([index, symbol, tag, *formatted_position])
78+
"""Build table data; if 'fixed_atoms' is present in structure attributes,
79+
add a 'Free x,y,z' column showing '✓' for free (1) and 'x' for fixed (0)."""
80+
# Try to get fixed_atoms from AiiDA StructureData attributes
81+
fixed_atoms = None
82+
try:
83+
fixed_atoms = self.structure.base.attributes.all['fixed_atoms']
84+
except KeyError:
85+
fixed_atoms = None
86+
87+
ase_atoms = self.structure.get_ase()
88+
89+
# Header
90+
data = [["Atom index", "Chemical symbol", "Tag", "x (Å)", "y (Å)", "z (Å)"]]
91+
if fixed_atoms is not None:
92+
data[0].append("Free x,y,z")
93+
94+
positions = ase_atoms.positions
95+
chemical_symbols = ase_atoms.get_chemical_symbols()
96+
tags = ase_atoms.get_tags()
97+
98+
def fmt_free(mask):
99+
"""mask: tuple/list of three 0/1; 0=free -> 'X', 1=fixed -> ' '."""
100+
try:
101+
x, y, z = mask
102+
except Exception:
103+
x = y = z = 0
104+
# If your UI collapses spaces, replace ' ' with '·' or '\u00A0' (NBSP).
105+
return f"({'x' if x == 0 else '✓'} {'x' if y == 0 else '✓'} {'x' if z == 0 else '✓'})"
106+
107+
for idx, (symbol, tag, pos) in enumerate(zip(chemical_symbols, tags, positions), start=1):
108+
formatted_position = [f"{coord:.2f}" for coord in pos]
109+
row = [idx, symbol, tag, *formatted_position]
110+
111+
if fixed_atoms is not None:
112+
mask = fixed_atoms[idx - 1] if idx - 1 < len(fixed_atoms) else (0, 0, 0)
113+
row.append(fmt_free(mask))
114+
115+
data.append(row)
98116

99117
return data
100118

119+
101120
def get_model_state(self):
102121
return {
103122
"selected_view": self.selected_view,

src/aiidalab_qe/workflows/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,10 @@ def get_builder_from_protocol(
206206
relax_builder.pop("structure", None)
207207
relax_builder.pop("clean_workdir", None)
208208
relax_builder.pop("base_final_scf", None) # never run a final scf
209-
builder.relax = relax_builder
209+
if 'fixed_atoms' in structure.base.attributes.all:
210+
211+
relax_builder.base.pw.settings = orm.Dict({'FIXED_COORDS':[[v == 0 for v in row] for row in structure.base.attributes.all['fixed_atoms']]})
212+
builder.relax = relax_builder
210213
else:
211214
builder.pop("relax")
212215

0 commit comments

Comments
 (0)