Skip to content

Commit 99b1551

Browse files
authored
Update atat_module.py
1 parent aa1f46e commit 99b1551

1 file changed

Lines changed: 62 additions & 38 deletions

File tree

atat_module.py

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def render_concentration_sweep_section(chemical_symbols, target_concentrations,
4141
st.markdown("---")
4242
st.subheader("🔄 Concentration Sweep Mode")
4343
st.info("Multiple binary sublattices detected. Please select one for concentration sweep:")
44+
st.info(f"You can generate a script to automatically run the mcsqs search across concentration range.")
4445

4546
sublattice_options = []
4647
for sublattice_letter, elements in binary_sublattices:
@@ -75,8 +76,10 @@ def render_concentration_sweep_section(chemical_symbols, target_concentrations,
7576

7677
if selected_sublattice:
7778
st.info(f"**Binary sublattice {selected_sublattice} detected:** {sweep_element} + {complement_element}")
79+
st.info(f"You can generate a script to automatically run the mcsqs search across concentration range.")
7880
else:
7981
st.info(f"**Binary system detected:** {sweep_element} + {complement_element}")
82+
st.info(f"You can generate a script to automatically run the mcsqs search across concentration range.")
8083

8184
enable_sweep = st.checkbox(
8285
f"Enable concentration sweep for {sweep_element}",
@@ -99,7 +102,7 @@ def render_concentration_sweep_section(chemical_symbols, target_concentrations,
99102
sublattice_sites += 1
100103

101104
total_sites_for_sublattice = sublattice_sites * supercell_factor
102-
st.write(f"**Sites for sublattice {selected_sublattice} in primitive cell:** {sublattice_sites}")
105+
st.write(f"**Sites for sublattice {selected_sublattice} in initial unit cell:** {sublattice_sites}")
103106
st.write(f"**Total sites for sublattice {selected_sublattice} in supercell:** {total_sites_for_sublattice}")
104107

105108
possible_concentrations = []
@@ -219,7 +222,6 @@ def render_concentration_sweep_section(chemical_symbols, target_concentrations,
219222
with st.expander("Script Preview", expanded=False):
220223
st.code(script_content, language="bash")
221224

222-
223225
def generate_concentration_sweep_script(sweep_element, complement_element, selected_concentrations,
224226
time_per_conc, max_parallel, parallel_runs_per_conc,
225227
target_concentrations, chemical_symbols, transformation_matrix,
@@ -252,13 +254,13 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
252254
"",
253255
f'SWEEP_ELEMENT="{sweep_element}"',
254256
f'COMPLEMENT_ELEMENT="{complement_element}"',
255-
f"TIME_PER_CONC={time_per_conc}",
257+
f"TIME_PER_CONC_DEFAULT={time_per_conc}",
256258
f"MAX_PARALLEL={max_parallel}",
257-
f"PARALLEL_RUNS_PER_CONC={parallel_runs_per_conc}",
259+
f"PARALLEL_RUNS_PER_CONC_DEFAULT={parallel_runs_per_conc}",
258260
f'CORRDUMP_CMD="{corrdump_cmd}"',
259261
f"PROGRESS_UPDATE_INTERVAL={progress_update_interval}",
260262
"",
261-
'TOTAL_TIME_SECONDS=$(echo "$TIME_PER_CONC * 60" | bc | xargs printf "%.0f")',
263+
'TOTAL_TIME_SECONDS=$(echo "$TIME_PER_CONC_DEFAULT * 60" | bc | xargs printf "%.0f")',
262264
"",
263265
"GLOBAL_START_TIME=$(date +%s)",
264266
"declare -A CONC_START_TIMES",
@@ -269,8 +271,8 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
269271
'echo "🔬 Sweep element: $SWEEP_ELEMENT"',
270272
'echo "🔬 Complement element: $COMPLEMENT_ELEMENT"',
271273
'echo "🧪 Corrdump command: $CORRDUMP_CMD"',
272-
'echo "⏱️ Time per concentration: $TIME_PER_CONC minutes"',
273-
f'echo "⚙️ Parallel runs per concentration: $PARALLEL_RUNS_PER_CONC"',
274+
'echo "⏱️ Default time per concentration: $TIME_PER_CONC_DEFAULT minutes"',
275+
f'echo "⚙️ Default parallel runs per concentration: $PARALLEL_RUNS_PER_CONC_DEFAULT"',
274276
f'echo "🔍 Concentrations to be searched: {selected_concentrations}"',
275277
"",
276278
'mkdir -p best_poscars',
@@ -300,9 +302,10 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
300302
"get_best_objective_and_run() {",
301303
" local best_obj=\"N/A\"",
302304
" local best_run=\"N/A\"",
305+
" local parallel_runs_per_conc=$1",
303306
" ",
304-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
305-
" for ((i=1; i<=PARALLEL_RUNS_PER_CONC; i++)); do",
307+
" if [ $parallel_runs_per_conc -gt 1 ]; then",
308+
" for ((i=1; i<=parallel_runs_per_conc; i++)); do",
306309
" if [ -f \"mcsqs$i.log\" ]; then",
307310
" local current_obj=$(extract_latest_objective \"mcsqs$i.log\")",
308311
" if [ -n \"$current_obj\" ] && [ \"$current_obj\" != \"N/A\" ] && [ \"$current_obj\" != \"\" ]; then",
@@ -406,17 +409,19 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
406409
"",
407410
"monitor_progress() {",
408411
" local conc=$1",
412+
" local parallel_runs_per_conc=$2",
413+
" local total_time_seconds=$3",
409414
" local elapsed_seconds=0",
410415
" ",
411-
" while [ $elapsed_seconds -lt $TOTAL_TIME_SECONDS ]; do",
416+
" while [ $elapsed_seconds -lt $total_time_seconds ]; do",
412417
" sleep $PROGRESS_UPDATE_INTERVAL",
413418
" elapsed_seconds=$((elapsed_seconds + PROGRESS_UPDATE_INTERVAL))",
414419
" ",
415420
" local current_time=$(date +%s)",
416421
" local global_elapsed=$((current_time - GLOBAL_START_TIME))",
417422
" local conc_elapsed=$((current_time - CONC_START_TIMES[$conc]))",
418423
" ",
419-
" local result=$(get_best_objective_and_run)",
424+
" local result=$(get_best_objective_and_run $parallel_runs_per_conc)",
420425
" local best_obj=$(echo $result | cut -d',' -f1)",
421426
" local best_run=$(echo $result | cut -d',' -f2)",
422427
" ",
@@ -426,14 +431,14 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
426431
" local global_time_str=$(format_elapsed_time $global_elapsed)",
427432
" local conc_time_str=$(format_elapsed_time $conc_elapsed)",
428433
" ",
429-
" if [ \"$best_run\" != \"N/A\" ] && [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
434+
" if [ \"$best_run\" != \"N/A\" ] && [ $parallel_runs_per_conc -gt 1 ]; then",
430435
" printf \"[Conc %s] [%s] Global: %s | Conc %s: %s (sec %d/%d) | Best obj: %s (run %s)\\n\" \\",
431436
" \"$conc\" \"$(date +'%H:%M:%S')\" \"$global_time_str\" \"$conc\" \"$conc_time_str\" \\",
432-
" \"$elapsed_seconds\" \"$TOTAL_TIME_SECONDS\" \"$best_obj\" \"$best_run\"",
437+
" \"$elapsed_seconds\" \"$total_time_seconds\" \"$best_obj\" \"$best_run\"",
433438
" else",
434439
" printf \"[Conc %s] [%s] Global: %s | Conc %s: %s (sec %d/%d) | Best obj: %s\\n\" \\",
435440
" \"$conc\" \"$(date +'%H:%M:%S')\" \"$global_time_str\" \"$conc\" \"$conc_time_str\" \\",
436-
" \"$elapsed_seconds\" \"$TOTAL_TIME_SECONDS\" \"$best_obj\"",
441+
" \"$elapsed_seconds\" \"$total_time_seconds\" \"$best_obj\"",
437442
" fi",
438443
" done",
439444
"}",
@@ -447,13 +452,25 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
447452
' local folder="conc_${SWEEP_ELEMENT}_${conc}"',
448453
' local comp_conc=$(echo "1.0 - $conc" | bc -l)',
449454
" ",
455+
" local time_per_conc_current=$TIME_PER_CONC_DEFAULT",
456+
" local parallel_runs_per_conc_current=$PARALLEL_RUNS_PER_CONC_DEFAULT",
457+
" ",
458+
" if [ \"$sweep_atoms\" -le 1 ] || [ \"$comp_atoms\" -le 1 ]; then",
459+
" time_per_conc_current=0.1",
460+
" parallel_runs_per_conc_current=1",
461+
' echo ""',
462+
' echo "ℹ️ Note: Single or very few atoms detected. Reducing time to $time_per_conc_current min and parallel runs to $parallel_runs_per_conc_current."',
463+
" fi",
464+
" ",
465+
" local total_time_seconds_current=$(echo \"$time_per_conc_current * 60\" | bc | xargs printf \"%.0f\")",
466+
" ",
450467
" CONC_START_TIMES[$conc]=$(date +%s)",
451468
" ",
452469
' echo ""',
453470
' echo "=========================================="',
454471
' echo "($current_run/$total_runs) 🔬 Starting concentration $conc for $SWEEP_ELEMENT"',
455472
' ' 'echo "🔢 Target atoms: $sweep_atoms $SWEEP_ELEMENT + $comp_atoms $COMPLEMENT_ELEMENT"',
456-
f' echo "🏃 Running $PARALLEL_RUNS_PER_CONC parallel instances for $TIME_PER_CONC minutes"',
473+
' echo "🏃 Running $parallel_runs_per_conc_current parallel instances for $time_per_conc_current minutes"',
457474
' echo "=========================================="',
458475
' mkdir -p "$folder"',
459476
' cd "$folder"',
@@ -467,16 +484,23 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
467484

468485
for i, site in enumerate(primitive_structure):
469486
coord_str = f"{site.frac_coords[0]:.6f} {site.frac_coords[1]:.6f} {site.frac_coords[2]:.6f}"
470-
site_elements = chemical_symbols[i]
471487

472-
if isinstance(site_elements, list) and len(site_elements) > 1:
473-
if set(site_elements) == {sweep_element, complement_element}:
474-
script_lines.append(f"{coord_str} ${{SWEEP_ELEMENT}}=$conc,${{COMPLEMENT_ELEMENT}}=$comp_conc")
475-
else:
476-
script_lines.append(f"{coord_str} {','.join(sorted(site_elements))}")
488+
# Check if chemical_symbols is None (global mode) or populated (sublattice mode)
489+
if chemical_symbols is None:
490+
# Global mode: all sites get the sweep elements
491+
script_lines.append(f"{coord_str} ${{SWEEP_ELEMENT}}=$conc,${{COMPLEMENT_ELEMENT}}=$comp_conc")
477492
else:
478-
element = site_elements[0] if isinstance(site_elements, list) else str(site.specie)
479-
script_lines.append(f"{coord_str} {element}")
493+
# Sublattice mode: use the chemical_symbols array
494+
site_elements = chemical_symbols[i]
495+
496+
if isinstance(site_elements, list) and len(site_elements) > 1:
497+
if set(site_elements) == {sweep_element, complement_element}:
498+
script_lines.append(f"{coord_str} ${{SWEEP_ELEMENT}}=$conc,${{COMPLEMENT_ELEMENT}}=$comp_conc")
499+
else:
500+
script_lines.append(f"{coord_str} {','.join(sorted(site_elements))}")
501+
else:
502+
element = site_elements[0] if isinstance(site_elements, list) else str(site.specie)
503+
script_lines.append(f"{coord_str} {element}")
480504

481505
script_lines.extend([
482506
"EOF",
@@ -497,22 +521,22 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
497521
" return 1",
498522
" fi",
499523
"",
500-
' echo "✨ Starting $PARALLEL_RUNS_PER_CONC parallel mcsqs instances..."',
524+
' echo "✨ Starting $parallel_runs_per_conc_current parallel mcsqs instances..."',
501525
" ",
502526
" local pids=()",
503-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
504-
' for ((i=1; i<=PARALLEL_RUNS_PER_CONC; i++)); do',
505-
' timeout ${TOTAL_TIME_SECONDS}s mcsqs -rc -ip=$i > mcsqs$i.log 2>&1 || true &',
527+
" if [ $parallel_runs_per_conc_current -gt 1 ]; then",
528+
' for ((i=1; i<=parallel_runs_per_conc_current; i++)); do',
529+
' timeout ${total_time_seconds_current}s mcsqs -rc -ip=$i > mcsqs$i.log 2>&1 || true &',
506530
" pids+=($!)",
507531
' echo " ✅ Started mcsqs run $i for concentration $conc (PID: $!)"',
508532
" done",
509533
" else",
510-
' timeout ${TOTAL_TIME_SECONDS}s mcsqs -rc > mcsqs.log 2>&1 || true &',
534+
' timeout ${total_time_seconds_current}s mcsqs -rc > mcsqs.log 2>&1 || true &',
511535
" pids+=($!)",
512536
' echo " ✅ Started single mcsqs run for concentration $conc (PID: $!)"',
513537
" fi",
514538
" ",
515-
" monitor_progress $conc &",
539+
" monitor_progress $conc $parallel_runs_per_conc_current $total_time_seconds_current &",
516540
" local monitor_pid=$!",
517541
" ",
518542
" for pid in \"${pids[@]}\"; do",
@@ -530,8 +554,8 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
530554
" declare -a successful_runs",
531555
" declare -a run_scores",
532556
" ",
533-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
534-
" for ((i=1; i<=PARALLEL_RUNS_PER_CONC; i++)); do",
557+
" if [ $parallel_runs_per_conc_current -gt 1 ]; then",
558+
" for ((i=1; i<=parallel_runs_per_conc_current; i++)); do",
535559
" if [ -f \"bestsqs$i.out\" ]; then",
536560
' local score=$(extract_latest_objective "mcsqs$i.log")',
537561
" if [ -n \"$score\" ] && [ \"$score\" != \"N/A\" ] && [ \"$score\" != \"\" ]; then",
@@ -588,7 +612,7 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
588612
" ",
589613
" local bestsqs_filename",
590614
" local poscar_filename",
591-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
615+
" if [ $parallel_runs_per_conc_current -gt 1 ]; then",
592616
" bestsqs_filename=\"bestsqs${run_num}.out\"",
593617
" poscar_filename=\"POSCAR_$((rank + 1))\"",
594618
" else",
@@ -597,7 +621,7 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
597621
" fi",
598622
" ",
599623
" if convert_bestsqs_to_poscar \"$bestsqs_filename\" \"$poscar_filename\" \"$conc\"; then",
600-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
624+
" if [ $parallel_runs_per_conc_current -gt 1 ]; then",
601625
' echo " ✔️ POSCAR_$((rank + 1)): Run $run_num (score: $score)"',
602626
" else",
603627
' echo " ✔️ POSCAR: Run 1 (score: $score)"',
@@ -606,15 +630,15 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
606630
" if [ $rank -eq 0 ]; then",
607631
" best_run_found=true",
608632
" best_poscar_filename=\"$poscar_filename\"",
609-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
633+
" if [ $parallel_runs_per_conc_current -gt 1 ]; then",
610634
" cp \"POSCAR_1\" \"POSCAR\"",
611635
' echo " 🏆 → Best result: POSCAR_1 (also saved as POSCAR)"',
612636
" else",
613637
' echo " 🏆 → Best result: POSCAR"',
614638
" fi",
615639
" fi",
616640
" else",
617-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
641+
" if [ $parallel_runs_per_conc_current -gt 1 ]; then",
618642
' echo " ❌ Failed to convert run $run_num to POSCAR"',
619643
" else",
620644
' echo " ❌ Failed to convert single run to POSCAR"',
@@ -628,7 +652,7 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
628652
' echo ""',
629653
' echo "✅ Concentration $conc completed successfully"',
630654
' echo "✨ Best result has score: $best_score"',
631-
" if [ $PARALLEL_RUNS_PER_CONC -gt 1 ]; then",
655+
" if [ $parallel_runs_per_conc_current -gt 1 ]; then",
632656
' echo "📂 Generated ${#successful_runs[@]} POSCAR files (POSCAR_1 to POSCAR_${#successful_runs[@]})"',
633657
" else",
634658
' echo "📂 Generated POSCAR file"',
@@ -661,8 +685,8 @@ def generate_concentration_sweep_script(sweep_element, complement_element, selec
661685
script_lines.extend([
662686
")",
663687
"",
664-
'echo "Will process ${#concentrations[@]} concentrations with $PARALLEL_RUNS_PER_CONC parallel runs each"',
665-
'echo "Total estimated time: $(echo "${#concentrations[@]} * $TIME_PER_CONC" | bc -l | xargs printf "%.1f") minutes"',
688+
'echo "Will process ${#concentrations[@]} concentrations with a default of $PARALLEL_RUNS_PER_CONC_DEFAULT parallel runs each"',
689+
'echo "Total estimated time: $(echo "${#concentrations[@]} * $TIME_PER_CONC_DEFAULT" | bc -l | xargs printf "%.1f") minutes"',
666690
'echo "Maximum concurrent jobs: $MAX_PARALLEL"',
667691
'echo ""',
668692
"",

0 commit comments

Comments
 (0)