Skip to content

Commit 3661aff

Browse files
authored
Merge pull request #218 from jvalegre/jv_branch
Jv branch
2 parents df766e8 + c1c91d8 commit 3661aff

File tree

6 files changed

+125
-104
lines changed

6 files changed

+125
-104
lines changed

.circleci/config.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ jobs:
4646
conda install -y -c conda-forge openbabel=3.1.1
4747
# install dependencies
4848
conda install -y -c conda-forge xtb=6.7.1
49-
conda install -y -c conda-forge crest=3.0.2
50-
pip install ase
51-
conda install pytorch torchvision torchaudio cpuonly -c pytorch
49+
conda install -y -c conda-forge crest=2.12
50+
pip install ase==3.24.0
51+
pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cpu
5252
pip install torchani==2.2.3
5353
# install the dependencies of AQME with pip
5454
pip install .

aqme/qdescp.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ def run_sp_xtb(self, file, xyz_file, charge, mult, name, destination):
863863
"--uhf",
864864
str(mult - 1),
865865
"--etemp",
866-
str(self.args.qdescp_temp),
866+
'5000',
867867
"-P",
868868
"1",
869869
] # for FOD

aqme/qdescp_utils.py

+107-91
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ def extract_scc_energy(lines, filename):
417417
if "SCC energy" in line:
418418
return float(line.split()[3])
419419

420-
self.args.log.write(f"x WARNING! Could not find SCC energy value in the file: {filename}")
420+
self.args.log.write(f"x WARNING! Could not find SCC energy value in the file: {os.path.basename(filename)}. Some CDFT-based descriptors will be missing.")
421421
return None
422422

423423
try:
@@ -443,16 +443,17 @@ def extract_scc_energy(lines, filename):
443443
scc_energy_Nplus1 = extract_scc_energy(data3, file_Nplus1)
444444
scc_energy_Nplus2 = extract_scc_energy(data4, file_Nplus2)
445445

446-
if None in [scc_energy, scc_energy_Nminus1, scc_energy_Nminus2, scc_energy_Nplus1, scc_energy_Nplus2]:
447-
self.args.log.write(f"x WARNING! Missing SCC energy in one or more files. Cannot calculate global CDFT descriptors.")
448-
return None
449-
450446
# Convert SCC energies to Hartree
451-
scc_energy *= Hartree
452-
scc_energy_Nminus1 *= Hartree
453-
scc_energy_Nminus2 *= Hartree
454-
scc_energy_Nplus1 *= Hartree
455-
scc_energy_Nplus2 *= Hartree
447+
if scc_energy is not None:
448+
scc_energy *= Hartree
449+
if scc_energy_Nminus1 is not None:
450+
scc_energy_Nminus1 *= Hartree
451+
if scc_energy_Nminus2 is not None:
452+
scc_energy_Nminus2 *= Hartree
453+
if scc_energy_Nplus1 is not None:
454+
scc_energy_Nplus1 *= Hartree
455+
if scc_energy_Nplus2 is not None:
456+
scc_energy_Nplus2 *= Hartree
456457

457458
# Initialize variables
458459
delta_SCC_IP, delta_SCC_EA, electrophilicity_index = None, None, None
@@ -466,60 +467,66 @@ def extract_scc_energy(lines, filename):
466467
Electrophilic_descriptor, w_cubic = None, None
467468

468469
# Calculate Global CDFT descriptors
469-
delta_SCC_IP = round(((scc_energy_Nminus1 - corr_xtb) - scc_energy),4)
470-
delta_SCC_EA = round((scc_energy - (scc_energy_Nplus1 + corr_xtb)),4)
471-
chemical_hardness = round((delta_SCC_IP - delta_SCC_EA), 4)
472-
chemical_potential = round(-(delta_SCC_IP + delta_SCC_EA) / 2, 4)
473-
electrophilicity_index = (chemical_potential**2)/(2*chemical_hardness)
474-
mulliken_electronegativity = round(-chemical_potential, 4)
475-
electrofugality = round(-delta_SCC_EA + electrophilicity_index, 4)
476-
nucleofugality = round(delta_SCC_IP + electrophilicity_index, 4)
477-
electrodonating_maximum_electron_flow = round((-(chemical_potential/chemical_hardness)),4)
478-
electrodonating_chemical_potential = round(((1/4)*((-3*delta_SCC_IP) - delta_SCC_EA)),4)
479-
lectrodonating_maximum_electron_flow = round((-(electrodonating_chemical_potential/chemical_hardness)),4)
480-
Vertical_second_IP = round((((scc_energy_Nminus2 - scc_energy_Nminus1) - corr_xtb)), 4)
481-
Vertical_second_EA = round((((scc_energy_Nplus1 - scc_energy_Nplus2) + corr_xtb)), 4)
482-
hyper_hardness = round((-((0.5) * (delta_SCC_IP + delta_SCC_EA - Vertical_second_IP - Vertical_second_EA))), 4)
483-
484-
if chemical_hardness != 0:
470+
if None not in [scc_energy_Nminus1,scc_energy]:
471+
delta_SCC_IP = round(((scc_energy_Nminus1 - corr_xtb) - scc_energy),4)
472+
if None not in [scc_energy_Nplus1,scc_energy]:
473+
delta_SCC_EA = round((scc_energy - (scc_energy_Nplus1 + corr_xtb)),4)
474+
if None not in [delta_SCC_IP,delta_SCC_EA]:
475+
chemical_hardness = round((delta_SCC_IP - delta_SCC_EA), 4)
476+
chemical_potential = round(-(delta_SCC_IP + delta_SCC_EA) / 2, 4)
477+
electrophilicity_index = (chemical_potential**2)/(2*chemical_hardness)
478+
mulliken_electronegativity = round(-chemical_potential, 4)
479+
electrofugality = round(-delta_SCC_EA + electrophilicity_index, 4)
480+
nucleofugality = round(delta_SCC_IP + electrophilicity_index, 4)
481+
electrodonating_maximum_electron_flow = round((-(chemical_potential/chemical_hardness)),4)
482+
electrodonating_chemical_potential = round(((1/4)*((-3*delta_SCC_IP) - delta_SCC_EA)),4)
483+
electrodonating_maximum_electron_flow = round((-(electrodonating_chemical_potential/chemical_hardness)),4)
484+
if None not in [scc_energy_Nminus2,scc_energy_Nminus1]:
485+
Vertical_second_IP = round((((scc_energy_Nminus2 - scc_energy_Nminus1) - corr_xtb)), 4)
486+
if None not in [scc_energy_Nplus1,scc_energy_Nplus2]:
487+
Vertical_second_EA = round((((scc_energy_Nplus1 - scc_energy_Nplus2) + corr_xtb)), 4)
488+
if None not in [delta_SCC_IP,delta_SCC_EA,Vertical_second_IP,Vertical_second_EA]:
489+
hyper_hardness = round((-((0.5) * (delta_SCC_IP + delta_SCC_EA - Vertical_second_IP - Vertical_second_EA))), 4)
490+
491+
if chemical_hardness is not None and chemical_hardness != 0:
485492
chemical_softness = round(1 / chemical_hardness, 4)
486493
electrodonating_power_index = round(((delta_SCC_IP + 3 * delta_SCC_EA)**2) / (8 * chemical_hardness), 4)
487494
electroaccepting_power_index = round(((3 * delta_SCC_IP + delta_SCC_EA)**2) / (8 * chemical_hardness), 4)
488495
intrinsic_reactivity_index = round((delta_SCC_IP + delta_SCC_EA) / chemical_hardness, 4)
489-
Global_hypersoftness = round((hyper_hardness / ((chemical_hardness) ** 3)), 4)
496+
if hyper_hardness is not None:
497+
Global_hypersoftness = round((hyper_hardness / ((chemical_hardness) ** 3)), 4)
490498

491499
if electroaccepting_power_index != 0:
492500
nucleophilicity_index = round(10 / electroaccepting_power_index, 4)
493501

494-
net_electrophilicity = round((electrodonating_power_index - electroaccepting_power_index), 4)
495-
496-
# For lectrophilic descriptor calculations
497-
A = ((scc_energy_Nplus1 - scc_energy) + corr_xtb)
498-
c = (Vertical_second_IP - (2 * delta_SCC_IP) + A) / ((2 * Vertical_second_IP) - delta_SCC_IP - A)
499-
a = -((delta_SCC_IP + A) / 2) + (((delta_SCC_IP - A) / 2) * c)
500-
b = ((delta_SCC_IP - A) / 2) - (((delta_SCC_IP + A) / 2) * c)
501-
Gamma = (-3 * c) * (b - (a * c))
502-
Eta = 2 * (b - (a * c))
503-
chi = -a
504-
Mu = a
505-
506-
discriminant = Eta ** 2 - (2 * Gamma * Mu) # Checking the square root
507-
if discriminant < 0:
508-
self.args.log.write(f"x WARNING! Negative discriminant encountered, skipping Electrophilic descriptor calculation.")
509-
else:
510-
inter_phi = math.sqrt(discriminant)
511-
Phi = inter_phi - Eta
512-
Electrophilic_descriptor = round(((chi * (Phi / Gamma)) - (((Phi / Gamma) ** 2) * ((Eta / 2) + (Phi / 6)))), 4)
502+
if None not in [electrodonating_power_index,electroaccepting_power_index]:
503+
net_electrophilicity = round((electrodonating_power_index - electroaccepting_power_index), 4)
504+
505+
# For electrophilic descriptor calculations
506+
if None not in [scc_energy_Nplus1,scc_energy,Vertical_second_IP,delta_SCC_IP]:
507+
A = ((scc_energy_Nplus1 - scc_energy) + corr_xtb)
508+
c = (Vertical_second_IP - (2 * delta_SCC_IP) + A) / ((2 * Vertical_second_IP) - delta_SCC_IP - A)
509+
a = -((delta_SCC_IP + A) / 2) + (((delta_SCC_IP - A) / 2) * c)
510+
b = ((delta_SCC_IP - A) / 2) - (((delta_SCC_IP + A) / 2) * c)
511+
Gamma = (-3 * c) * (b - (a * c))
512+
Eta = 2 * (b - (a * c))
513+
chi = -a
514+
Mu = a
515+
516+
discriminant = Eta ** 2 - (2 * Gamma * Mu) # Checking the square root
517+
if discriminant >= 0:
518+
inter_phi = math.sqrt(discriminant)
519+
Phi = inter_phi - Eta
520+
Electrophilic_descriptor = round(((chi * (Phi / Gamma)) - (((Phi / Gamma) ** 2) * ((Eta / 2) + (Phi / 6)))), 4)
513521

514522
# For cubic electrophilicity index
515-
Gamma_cubic = 2 * delta_SCC_IP - Vertical_second_IP - delta_SCC_EA
516-
Eta_cubic = delta_SCC_IP - delta_SCC_EA
523+
if None not in [delta_SCC_IP,Vertical_second_IP,delta_SCC_EA]:
524+
Gamma_cubic = 2 * delta_SCC_IP - Vertical_second_IP - delta_SCC_EA
525+
Eta_cubic = delta_SCC_IP - delta_SCC_EA
517526

518527
if Eta_cubic != 0:
519528
Mu_cubic = (1 / 6) * ((-2 * delta_SCC_EA) - (5 * delta_SCC_IP) + Vertical_second_IP)
520529
w_cubic = round(((Mu_cubic ** 2) / (2 * Eta_cubic)) * (1 + ((Mu_cubic / (3 * (Eta_cubic) ** 2)) * Gamma_cubic)), 4)
521-
else:
522-
self.args.log.write(f"x WARNING! Eta_cubic is zero, skipping cub. electrophilicity idx calculation.")
523530

524531
# Return the calculated descriptors
525532
cdft_descriptors = {
@@ -545,7 +552,7 @@ def extract_scc_energy(lines, filename):
545552
"cub. electrophilicity idx": w_cubic,
546553
"max. electron flow": electrodonating_maximum_electron_flow,
547554
"Electrodon. Chem. potential": electrodonating_chemical_potential,
548-
"Electrodon. max. electron flow": lectrodonating_maximum_electron_flow
555+
"Electrodon. max. electron flow": electrodonating_maximum_electron_flow
549556
}
550557

551558
return cdft_descriptors
@@ -558,7 +565,13 @@ def calculate_local_CDFT_descriptors(file_fukui, cdft_descriptors,self):
558565
with open(file_fukui, "r") as f:
559566
data = f.readlines()
560567

568+
# Initialize variables
561569
f_pos, f_negs, f_rads = [], [], []
570+
dual_descriptor,s_pos,s_negs,s_rads = None,None,None,None
571+
Relative_nucleophilicity,Relative_electrophilicity,Grand_canonical_dual_descriptor = None,None,None
572+
w_pos,w_negs,w_rads,Multiphilic_descriptor = None,None,None,None
573+
Nu_pos,Nu_negs,Nu_rads = None,None,None
574+
562575
start, end = None, None
563576

564577
for i, line in enumerate(data):
@@ -578,50 +591,46 @@ def calculate_local_CDFT_descriptors(file_fukui, cdft_descriptors,self):
578591
f_rads.append(f_rad)
579592
except ValueError:
580593
continue
581-
else:
582-
self.args.log.write("WARNING: Fukui data not found in the file. Please check the '.fukui' file.")
583-
return None
584594

585-
if not f_pos or not f_negs or not f_rads:
586-
self.args.log.write("WARNING: Fukui data lists are empty. Please check the '.fukui' file.")
587-
return None
588-
589-
if None in [cdft_descriptors]:
590-
self.args.log.write("x WARNING! Missing required CDFT descriptors (Softness, Hypersoftness, Electrophil. idx or Nucleophilicity idx).")
591-
return None
595+
if f_pos == [] or f_negs == [] or f_rads == []:
596+
self.args.log.write("x WARNING! Fukui indices did not generate, please check the '.fukui' file.")
592597

593598
chemical_softness = cdft_descriptors.get("Softness")
594599
Global_hypersoftness = cdft_descriptors.get("Hypersoftness")
595600
electrophilicity_index = cdft_descriptors.get("Electrophil. idx")
596601
nucleophilicity_index = cdft_descriptors.get("Nucleophilicity idx")
597602

598-
if None in [chemical_softness, Global_hypersoftness, electrophilicity_index, nucleophilicity_index]:
599-
self.args.log.write("x WARNING! Missing required CDFT descriptors (Softness, Hypersoftness, Electrophil. idx or Nucleophilicity idx).")
600-
return None
601-
602-
# Calculating local descriptors:
603-
# 1) dual descrip.
604-
dual_descriptor = [round(f_po - f_neg, 4) for f_po, f_neg in zip(f_pos, f_negs)]
605-
# 2) softness+, softness- and softness0
606-
s_pos = [round(chemical_softness * f_po, 4) for f_po in f_pos]
607-
s_negs = [round(chemical_softness * f_neg, 4) for f_neg in f_negs]
608-
s_rads = [round(chemical_softness * f_rad, 4) for f_rad in f_rads]
609-
# 3) Rel. nucleophilicity
610-
Relative_nucleophilicity = [round(s_neg / s_po, 4) if s_po != 0 else None for s_neg, s_po in zip(s_negs, s_pos)]
611-
# 4) Rel. electrophilicity
612-
Relative_electrophilicity = [round(s_po / s_neg, 4) if s_neg != 0 else None for s_neg, s_po in zip(s_negs, s_pos)]
613-
# 5) GC Dual Descrip.
614-
Grand_canonical_dual_descriptor = [round(Global_hypersoftness * dual, 4) for dual in dual_descriptor]
615-
# 6) softness+, softness- and softness0
616-
w_pos = [round(electrophilicity_index * f_po, 4) for f_po in f_pos]
617-
w_negs = [round(electrophilicity_index * f_neg, 4) for f_negs in f_negs]
618-
w_rads = [round(electrophilicity_index * f_rad, 4) for f_rad in f_rads]
619-
# 7) softness+, softness- and softness0
620-
Multiphilic_descriptor = [round(electrophilicity_index * dual, 4) for dual in dual_descriptor]
621-
# 8) softness+, softness- and softness0
622-
Nu_pos = [round(nucleophilicity_index * f_po, 4) for f_po in f_pos]
623-
Nu_negs = [round(nucleophilicity_index * f_neg, 4) for f_neg in f_negs]
624-
Nu_rads = [round(nucleophilicity_index * f_rad, 4) for f_rad in f_rads]
603+
# Calculating local descriptors
604+
if chemical_softness is not None and f_pos != [] and f_negs != [] and f_rads != []:
605+
# 1) dual descrip.
606+
dual_descriptor = [round(f_po - f_neg, 4) for f_po, f_neg in zip(f_pos, f_negs)]
607+
# 2) softness+, softness- and softness0
608+
s_pos = [round(chemical_softness * f_po, 4) for f_po in f_pos]
609+
s_negs = [round(chemical_softness * f_neg, 4) for f_neg in f_negs]
610+
s_rads = [round(chemical_softness * f_rad, 4) for f_rad in f_rads]
611+
# 3) Rel. nucleophilicity
612+
Relative_nucleophilicity = [round(s_neg / s_po, 4) if s_po != 0 else None for s_neg, s_po in zip(s_negs, s_pos)]
613+
# 4) Rel. electrophilicity
614+
Relative_electrophilicity = [round(s_po / s_neg, 4) if s_neg != 0 else None for s_neg, s_po in zip(s_negs, s_pos)]
615+
616+
if Global_hypersoftness is not None and dual_descriptor is not None:
617+
# 5) GC Dual Descrip.
618+
Grand_canonical_dual_descriptor = [round(Global_hypersoftness * dual, 4) for dual in dual_descriptor]
619+
620+
if electrophilicity_index is not None and f_pos != [] and f_negs != [] and f_rads != []:
621+
# 6) softness+, softness- and softness0
622+
w_pos = [round(electrophilicity_index * f_po, 4) for f_po in f_pos]
623+
w_negs = [round(electrophilicity_index * f_neg, 4) for f_neg in f_negs]
624+
w_rads = [round(electrophilicity_index * f_rad, 4) for f_rad in f_rads]
625+
if dual_descriptor is not None:
626+
# 7) softness+, softness- and softness0
627+
Multiphilic_descriptor = [round(electrophilicity_index * dual, 4) for dual in dual_descriptor]
628+
629+
if nucleophilicity_index is not None and f_pos != [] and f_negs != [] and f_rads != []:
630+
# 8) softness+, softness- and softness0
631+
Nu_pos = [round(nucleophilicity_index * f_po, 4) for f_po in f_pos]
632+
Nu_negs = [round(nucleophilicity_index * f_neg, 4) for f_neg in f_negs]
633+
Nu_rads = [round(nucleophilicity_index * f_rad, 4) for f_rad in f_rads]
625634

626635
localDescriptors = {
627636
"fukui+": f_pos,
@@ -1598,7 +1607,10 @@ def update_atom_props_json(sorted_indices,match_names,atom_props,json_data,prefi
15981607
idx_xtb = atom_idx
15991608
for prop in atom_props:
16001609
try:
1601-
json_data[f'{match_name}_{prop}'] = json_data[prop][idx_xtb]
1610+
if json_data[prop] is not None:
1611+
json_data[f'{match_name}_{prop}'] = json_data[prop][idx_xtb]
1612+
else:
1613+
json_data[f'{match_name}_{prop}'] = None
16021614
if f'{match_name}_' not in prefixes_atom_prop:
16031615
prefixes_atom_prop.append(f'{match_name}_')
16041616
except (KeyError,IndexError): # prevents missing values
@@ -1610,8 +1622,12 @@ def update_atom_props_json(sorted_indices,match_names,atom_props,json_data,prefi
16101622
prop_values = []
16111623
for prop_name in match_names:
16121624
prop_values.append(json_data[f'{prop_name}_{prop}'])
1613-
json_data[f'{pattern}_max_{prop}'] = max(prop_values)
1614-
json_data[f'{pattern}_min_{prop}'] = min(prop_values)
1625+
if None not in prop_values:
1626+
json_data[f'{pattern}_max_{prop}'] = max(prop_values)
1627+
json_data[f'{pattern}_min_{prop}'] = min(prop_values)
1628+
else:
1629+
json_data[f'{pattern}_max_{prop}'] = None
1630+
json_data[f'{pattern}_min_{prop}'] = None
16151631
if f'{pattern}_max_{prop}' not in prefixes_atom_prop:
16161632
prefixes_atom_prop.append(f'{pattern}_max_')
16171633
if f'{pattern}_min_{prop}' not in prefixes_atom_prop:

aqme/utils.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
T = 298.15
2626

2727
obabel_version = "3.1.1" # this MUST match the meta.yaml
28-
aqme_version = "1.7.2"
28+
aqme_version = "1.7.1"
2929
time_run = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime())
3030
aqme_ref = f"AQME v {aqme_version}, Alegre-Requena, J. V.; Sowndarya, S.; Perez-Soto, R.; Alturaifi, T.; Paton, R. AQME: Automated Quantum Mechanical Environments for Researchers and Educators. Wiley Interdiscip. Rev. Comput. Mol. Sci. 2023, 13, e1663 (DOI: 10.1002/wcms.1663)."
3131
xtb_version = '6.7.1'
32-
crest_version = '3.0.2'
32+
crest_version = '2.12'
3333

3434
RDLogger.DisableLog("rdApp.*")
3535

@@ -1022,11 +1022,16 @@ def check_version(self, program, version_line, target_version, n_split, install_
10221022

10231023
lower_version = True
10241024
if int(version_found.split('.')[0]) == int(target_version.split('.')[0]):
1025-
if len(target_version.split('.')) >= 2 and int(version_found.split('.')[1]) == int(target_version.split('.')[1]):
1026-
if len(target_version.split('.')) >= 3 \
1027-
and int(version_found.split('.')[2]) >= int(target_version.split('.')[2]) \
1028-
and int(version_found.split('.')[2]) < int(target_version.split('.')[2])+5: # up to four versions ahead
1029-
lower_version = False
1025+
if len(target_version.split('.')) == 2 \
1026+
and int(version_found.split('.')[1]) >= int(target_version.split('.')[1]) \
1027+
and int(version_found.split('.')[1]) < int(target_version.split('.')[1])+3: # up to two versions ahead
1028+
lower_version = False
1029+
1030+
if len(target_version.split('.')) == 3 \
1031+
and int(version_found.split('.')[1]) == int(target_version.split('.')[1]) \
1032+
and int(version_found.split('.')[2]) >= int(target_version.split('.')[2]) \
1033+
and int(version_found.split('.')[2]) < int(target_version.split('.')[2])+5: # up to four versions ahead
1034+
lower_version = False
10301035

10311036
if version_found == '0.0.0':
10321037
version_found = 'Unknown'

docs/Misc/versions.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Version 1.7.1 [`url <https://github.com/jvalegre/aqme/releases/tag/1.7.1>`__]
99
- CSEARCH uses multithreading to ensure reproducbility acorss runs
1010
- Added T1-S0 gap (not only S0-T1)
1111
- PTB is now used to calculate HOMO-LUMO gaps, charges, dipole moments, and other descriptors
12-
- Using updated versions of xTB & CREST
12+
- Using xTB v6.7.1 and CREST v2.12
1313
- Fixed bug from MORFEUS descriptors in QDESCP
1414
- Improved SDF reader compatible with SDF files from GaussView
1515
- Refactoring of the QDESCP module and its utils (faster code execution)

docs/README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ Extra requirements if xTB or CREST are used (compatible with MacOS and Linux onl
130130
131131
.. code-block:: shell
132132
133-
conda install -y -c conda-forge crest=3.0.2
133+
conda install -y -c conda-forge crest=2.12
134134
135135
Extra requirements if `CMIN` is used with ANI models:
136136

0 commit comments

Comments
 (0)