ManasSharma07 commited on
Commit
7a3ef28
·
verified ·
1 Parent(s): c8f704d

update app to include latest features available locally

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +128 -9
src/streamlit_app.py CHANGED
@@ -905,10 +905,14 @@ MACE_MODELS = {
905
  "MACE MP 0b2 Medium": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_mp_0b2/mace-medium-density-agnesi-stress.model",
906
  "MACE MP 0b2 Large": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_mp_0b2/mace-large-density-agnesi-stress.model",
907
  "MACE MP 0b3 Medium": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_mp_0b3/mace-mp-0b3-medium.model",
 
 
 
908
  }
909
 
910
  FAIRCHEM_MODELS = {
911
- "UMA Small": "uma-s-1",
 
912
  "ESEN MD Direct All OMOL": "esen-md-direct-all-omol",
913
  "ESEN SM Conserving All OMOL": "esen-sm-conserving-all-omol",
914
  "ESEN SM Direct All OMOL": "esen-sm-direct-all-omol"
@@ -936,8 +940,8 @@ SEVEN_NET_MODELS = {
936
  "7net-mf-ompa": "7net-mf-ompa"
937
  }
938
  @st.cache_resource
939
- def get_mace_model(model_path, device, selected_default_dtype):
940
- return mace_mp(model=model_path, device=device, default_dtype=selected_default_dtype)
941
 
942
  @st.cache_resource
943
  def get_fairchem_model(selected_model_name, model_path_or_name, device, selected_task_type_fc): # Renamed args to avoid conflict
@@ -999,7 +1003,7 @@ if atoms is not None:
999
  if not hasattr(atoms, 'info'):
1000
  atoms.info = {}
1001
  atoms.info["charge"] = atoms.info.get("charge", 0) # Default charge
1002
- atoms.info["spin"] = atoms.info.get("spin", 0) # Default spin (usually 2S for ASE, model might want 2S+1)
1003
 
1004
 
1005
  st.sidebar.markdown("## Model Selection")
@@ -1016,6 +1020,16 @@ if model_type == "MACE":
1016
  st.sidebar.warning("Using model under Academic Software License (ASL).")
1017
  # selected_default_dtype = st.sidebar.selectbox("Select Precision (default_dtype):", ['float32', 'float64'])
1018
  selected_default_dtype = 'float64'
 
 
 
 
 
 
 
 
 
 
1019
  if model_type == "FairChem":
1020
  selected_model = st.sidebar.selectbox("Select FairChem Model:", list(FAIRCHEM_MODELS.keys()))
1021
  model_path = FAIRCHEM_MODELS[selected_model]
@@ -1024,7 +1038,7 @@ if model_type == "FairChem":
1024
  selected_task_type = st.sidebar.selectbox("Select UMA Model Task Type:", ["omol", "omat", "omc", "odac", "oc20"])
1025
  if selected_task_type == "omol" and atoms is not None:
1026
  charge = st.sidebar.number_input("Total Charge", min_value=-10, max_value=10, value=atoms.info.get("charge",0))
1027
- spin_multiplicity = st.sidebar.number_input("Spin Multiplicity (2S + 1)", min_value=1, max_value=11, step=2, value=int(atoms.info.get("spin",0)*2+1 if atoms.info.get("spin",0) is not None else 1)) # Assuming spin in atoms.info is S
1028
  atoms.info["charge"] = charge
1029
  atoms.info["spin"] = spin_multiplicity # FairChem expects multiplicity
1030
  if model_type == "ORB":
@@ -1061,7 +1075,9 @@ task = st.sidebar.selectbox("Select Calculation Task:",
1061
  "Atomization/Cohesive Energy", # New Task Added
1062
  "Geometry Optimization",
1063
  "Cell + Geometry Optimization",
1064
- "Vibrational Mode Analysis"])
 
 
1065
 
1066
  if "Optimization" in task:
1067
  st.sidebar.markdown("### Optimization Parameters")
@@ -1100,6 +1116,8 @@ if atoms is not None:
1100
  st.write(f"**Model:** {selected_model}")
1101
  if model_type == "FairChem" and selected_model == "UMA Small":
1102
  st.write(f"**UMA Task Type:** {selected_task_type}")
 
 
1103
  st.write(f"**Device:** {device}")
1104
 
1105
  st.markdown("### Selected Task")
@@ -1129,7 +1147,7 @@ if atoms is not None:
1129
 
1130
  if model_type == "MACE":
1131
  # st.write("Setting up MACE calculator...")
1132
- calc = get_mace_model(model_path, device, 'float32')
1133
  elif model_type == "FairChem": # FairChem
1134
  # st.write("Setting up FairChem calculator...")
1135
  # Workaround for potential dtype issues when switching models
@@ -1377,6 +1395,15 @@ if atoms is not None:
1377
 
1378
  show_trajectory_and_controls()
1379
  elif task == "Vibrational Mode Analysis":
 
 
 
 
 
 
 
 
 
1380
 
1381
  st.write("Running vibrational mode analysis using finite differences...")
1382
 
@@ -1391,9 +1418,21 @@ if atoms is not None:
1391
  with st.spinner("Calculating vibrational modes... This may take a few minutes."):
1392
  vib.run()
1393
  freqs = vib.get_frequencies()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1394
 
1395
- # Convert frequencies to cm⁻¹
1396
- freqs_cm = freqs #/ cm
1397
 
1398
  # Classify frequencies
1399
  mode_data = []
@@ -1443,6 +1482,86 @@ if atoms is not None:
1443
  file_name="vibrational_modes.csv",
1444
  mime="text/csv"
1445
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1446
  except Exception as e:
1447
  st.error(f"🔴 Calculation error: {str(e)}")
1448
  st.error("Please check the structure, model compatibility, and parameters. For FairChem UMA, ensure the task type (omol, omat etc.) is appropriate for your system (e.g. omol for molecules, omat for materials).")
 
905
  "MACE MP 0b2 Medium": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_mp_0b2/mace-medium-density-agnesi-stress.model",
906
  "MACE MP 0b2 Large": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_mp_0b2/mace-large-density-agnesi-stress.model",
907
  "MACE MP 0b3 Medium": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_mp_0b3/mace-mp-0b3-medium.model",
908
+ "MACE ANI-CC Large (500k)": "https://github.com/ACEsuit/mace/raw/main/mace/calculators/foundations_models/ani500k_large_CC.model",
909
+ "MACE OMOL-0 XL 4M": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_omol_0/mace-omol-0-extra-large-4M.model",
910
+ "MACE OMOL-0 XL 1024": "https://github.com/ACEsuit/mace-foundations/releases/download/mace_omol_0/MACE-omol-0-extra-large-1024.model"
911
  }
912
 
913
  FAIRCHEM_MODELS = {
914
+ "UMA Small 1": "uma-s-1",
915
+ "UMA Small 1.1": "uma-s-1p1",
916
  "ESEN MD Direct All OMOL": "esen-md-direct-all-omol",
917
  "ESEN SM Conserving All OMOL": "esen-sm-conserving-all-omol",
918
  "ESEN SM Direct All OMOL": "esen-sm-direct-all-omol"
 
940
  "7net-mf-ompa": "7net-mf-ompa"
941
  }
942
  @st.cache_resource
943
+ def get_mace_model(model_path, dispersion, device, selected_default_dtype):
944
+ return mace_mp(model=model_path, dispersion=True, device=device, default_dtype=selected_default_dtype)
945
 
946
  @st.cache_resource
947
  def get_fairchem_model(selected_model_name, model_path_or_name, device, selected_task_type_fc): # Renamed args to avoid conflict
 
1003
  if not hasattr(atoms, 'info'):
1004
  atoms.info = {}
1005
  atoms.info["charge"] = atoms.info.get("charge", 0) # Default charge
1006
+ atoms.info["spin"] = atoms.info.get("spin", 1) # Default spin (usually 2S for ASE, model might want 2S+1)
1007
 
1008
 
1009
  st.sidebar.markdown("## Model Selection")
 
1020
  st.sidebar.warning("Using model under Academic Software License (ASL).")
1021
  # selected_default_dtype = st.sidebar.selectbox("Select Precision (default_dtype):", ['float32', 'float64'])
1022
  selected_default_dtype = 'float64'
1023
+ dispersion = st.sidebar.checkbox("Dispersion correction?", value=False)
1024
+ if selected_model == "MACE OMOL-0 XL 4M" or selected_model == "MACE OMOL-0 XL 1024":
1025
+
1026
+ charge = st.sidebar.number_input("Total Charge", min_value=-10, max_value=10, value=atoms.info.get("charge",0))
1027
+ spin_multiplicity = st.sidebar.number_input("Spin Multiplicity (2S + 1)", min_value=1, max_value=11, step=1, value=int(atoms.info.get("spin",0) if atoms.info.get("spin",0) is not None else 1)) # Assuming spin in atoms.info is S
1028
+ atoms.info["charge"] = charge
1029
+ atoms.info["spin"] = spin_multiplicity # FairChem expects multiplicity
1030
+ # else:
1031
+ # atoms.info["charge"] = 0
1032
+ # atoms.info["spin"] = 1 # FairChem expects multiplicity
1033
  if model_type == "FairChem":
1034
  selected_model = st.sidebar.selectbox("Select FairChem Model:", list(FAIRCHEM_MODELS.keys()))
1035
  model_path = FAIRCHEM_MODELS[selected_model]
 
1038
  selected_task_type = st.sidebar.selectbox("Select UMA Model Task Type:", ["omol", "omat", "omc", "odac", "oc20"])
1039
  if selected_task_type == "omol" and atoms is not None:
1040
  charge = st.sidebar.number_input("Total Charge", min_value=-10, max_value=10, value=atoms.info.get("charge",0))
1041
+ spin_multiplicity = st.sidebar.number_input("Spin Multiplicity (2S + 1)", min_value=1, max_value=11, step=1, value=int(atoms.info.get("spin",0) if atoms.info.get("spin",0) is not None else 1)) # Assuming spin in atoms.info is S
1042
  atoms.info["charge"] = charge
1043
  atoms.info["spin"] = spin_multiplicity # FairChem expects multiplicity
1044
  if model_type == "ORB":
 
1075
  "Atomization/Cohesive Energy", # New Task Added
1076
  "Geometry Optimization",
1077
  "Cell + Geometry Optimization",
1078
+ "Vibrational Mode Analysis",
1079
+ #"Phonons"
1080
+ ])
1081
 
1082
  if "Optimization" in task:
1083
  st.sidebar.markdown("### Optimization Parameters")
 
1116
  st.write(f"**Model:** {selected_model}")
1117
  if model_type == "FairChem" and selected_model == "UMA Small":
1118
  st.write(f"**UMA Task Type:** {selected_task_type}")
1119
+ if model_type == "MACE":
1120
+ st.write(f"**Dispersion:** {dispersion}")
1121
  st.write(f"**Device:** {device}")
1122
 
1123
  st.markdown("### Selected Task")
 
1147
 
1148
  if model_type == "MACE":
1149
  # st.write("Setting up MACE calculator...")
1150
+ calc = get_mace_model(model_path, dispersion, device, 'float32')
1151
  elif model_type == "FairChem": # FairChem
1152
  # st.write("Setting up FairChem calculator...")
1153
  # Workaround for potential dtype issues when switching models
 
1395
 
1396
  show_trajectory_and_controls()
1397
  elif task == "Vibrational Mode Analysis":
1398
+ # Conversion factors
1399
+
1400
+ from ase.units import kB as kB_eVK, _Nav, J # ASE's constants
1401
+
1402
+ from scipy.constants import physical_constants
1403
+
1404
+ kB_JK = physical_constants["Boltzmann constant"][0] # J/K
1405
+
1406
+ is_periodic = any(calc_atoms.pbc)
1407
 
1408
  st.write("Running vibrational mode analysis using finite differences...")
1409
 
 
1418
  with st.spinner("Calculating vibrational modes... This may take a few minutes."):
1419
  vib.run()
1420
  freqs = vib.get_frequencies()
1421
+ energies = vib.get_energies()
1422
+
1423
+
1424
+
1425
+ print('\n\n\n\n\n\n\n\n')
1426
+ # vib.get_hessian_2d()
1427
+ # st.write(vib.summary())
1428
+ # print('\n')
1429
+ # vib.tabulate()
1430
+
1431
+
1432
+
1433
+ freqs_cm = freqs
1434
+ freqs_eV = energies
1435
 
 
 
1436
 
1437
  # Classify frequencies
1438
  mode_data = []
 
1482
  file_name="vibrational_modes.csv",
1483
  mime="text/csv"
1484
  )
1485
+ # -------- Thermodynamic Analysis for Molecules --------
1486
+ if not is_periodic:
1487
+
1488
+ # Filter physical frequencies > 1 cm⁻¹ (to avoid numerical issues)
1489
+ physical_freqs_eV = np.array([f for f in freqs_eV if f > 1e-5])
1490
+
1491
+ # Zero-point vibrational energy (ZPE)
1492
+ ZPE = 0.5 * np.sum(physical_freqs_eV) # in eV
1493
+
1494
+ # Vibrational entropy (in eV/K)
1495
+ vib_entropy = 0.0
1496
+ for f in physical_freqs_eV:
1497
+ x = f / (kB_eVK * T)
1498
+ vib_entropy += (x / (np.exp(x) - 1) - np.log(1 - np.exp(-x)))
1499
+
1500
+ S_vib_eVK = kB_eVK * vib_entropy # eV/K
1501
+ S_vib_JmolK = S_vib_eVK * J * _Nav # J/mol·K
1502
+
1503
+ results["ZPE (eV)"] = ZPE.real
1504
+ results["Vibrational Entropy (eV/K)"] = S_vib_eVK
1505
+ results["Vibrational Entropy (J/mol·K)"] = S_vib_JmolK
1506
+
1507
+ st.write(f"**Zero-point vibrational energy (ZPE)**: {ZPE.real:.6f} eV")
1508
+ st.write(f"**Vibrational entropy**: {S_vib_eVK:.6f} eV/K")
1509
+
1510
+ else:
1511
+ st.info("Thermodynamic properties like ZPE and entropy are currently only meaningful for isolated molecules (non-periodic systems).")
1512
+ elif task == "Phonons":
1513
+ from ase.phonons import Phonons
1514
+
1515
+ st.write("### Phonon Band Structure and Density of States")
1516
+ is_periodic = any(calc_atoms.pbc)
1517
+
1518
+ if not is_periodic:
1519
+ st.error("Phonon calculations require a periodic structure. Please use a periodic system.")
1520
+ else:
1521
+ with tempfile.TemporaryDirectory() as tmpdir:
1522
+ st.info("Running phonon calculation using finite displacements...")
1523
+ sc = (7, 7, 7)
1524
+
1525
+ # Create phonon object
1526
+ ph = Phonons(calc_atoms, calc_atoms.calc, supercell=sc, delta=0.001, name=os.path.join(tmpdir, 'phonon'))
1527
+
1528
+ with st.spinner("Displacing atoms and computing forces..."):
1529
+ ph.run()
1530
+
1531
+ # Build dynamical matrix
1532
+ ph.read(acoustic=True)
1533
+ ph.clean()
1534
+
1535
+ # Band path and DOS
1536
+ # path = calc_atoms.cell.bandpath('GXULGK', npoints=100)
1537
+ path = calc_atoms.cell.bandpath('GXKGL', npoints=100)
1538
+ # path = calc_atoms.cell.bandpath(eps=0.00001)
1539
+ bs = ph.get_band_structure(path)
1540
+ dos = ph.get_dos(kpts=(20, 20, 20)).sample_grid(npts=100, width=1e-3)
1541
+
1542
+ # Plotting
1543
+ fig = plt.figure(figsize=(7, 4))
1544
+ ax = fig.add_axes([0.12, 0.07, 0.67, 0.85])
1545
+
1546
+ emax = 0.075
1547
+ bs.plot(ax=ax, emin=0.0, emax=emax)
1548
+
1549
+ dosax = fig.add_axes([0.8, 0.07, 0.17, 0.85])
1550
+ dosax.fill_between(
1551
+ dos.get_weights(),
1552
+ dos.get_energies(),
1553
+ y2=0,
1554
+ color='grey',
1555
+ edgecolor='k',
1556
+ lw=1,
1557
+ )
1558
+ dosax.set_ylim(0, emax)
1559
+ dosax.set_yticks([])
1560
+ dosax.set_xticks([])
1561
+ dosax.set_xlabel('DOS', fontsize=14)
1562
+
1563
+ st.pyplot(fig)
1564
+ st.success("Phonon band structure and DOS successfully plotted.")
1565
  except Exception as e:
1566
  st.error(f"🔴 Calculation error: {str(e)}")
1567
  st.error("Please check the structure, model compatibility, and parameters. For FairChem UMA, ensure the task type (omol, omat etc.) is appropriate for your system (e.g. omol for molecules, omat for materials).")