Skip to content

Commit e5c4e79

Browse files
authored
dump initial files
1 parent cc0cbd9 commit e5c4e79

File tree

3 files changed

+9280
-0
lines changed

3 files changed

+9280
-0
lines changed

HuckelTheory.wl

+223
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
(* ::Package:: *)
2+
3+
BeginPackage["HuckelTheory`"]
4+
5+
HuckelHamiltonianMatrix::usage =
6+
"HuckelHamiltonianMatrix[m] gives the pi-electron Hamiltonian matrix for the Molecule[] m."
7+
8+
HuckelMO::usage =
9+
"HuckelMO[m] returns an association whose keys are the eigenvalues and whose values are the corresponding eigenvectors (molecular orbitals) of Molecule[] m"
10+
11+
HuckelChargeDensityMatrix::usage =
12+
"HuckelChargeDensityMatrix[m] returns the pi-charge density matrix of Molecule[] m"
13+
14+
HuckelMOPlot::usage =
15+
"HuckelMOPlot[m] returns an association whose keys are the eigenvalues and whose values are plots of the pi-molecular orbitals on the 2D graph of Molecule[] m"
16+
17+
HuckelBondOrderPlot::usage =
18+
"HuckelBondOrderPlot[m] returns an image with the nearest-neighbor atom pi-bond orders plotted on the 2D dimensional graph of Molecule[] m"
19+
20+
HuckelTotalElectronsPlot::usage =
21+
"HuckelTotalElectronsPlot[m] returns an image of Molecule[] m depicting the total number of pi electrons on each atomic site."
22+
23+
HuckelNetChargePlot::usage =
24+
"HuckelNetChargePlot[m] returns an image of Molecule[] m depicting the net pi-charge on each atomic site."
25+
26+
Begin["`Private`"]
27+
28+
Once[If[$VersionNumber<12.,Print["Mathematica version 12 or greater is required."];Abort[];]]
29+
30+
HuckelHamiltonianMatrix[m_Molecule,t_:-1]:=With[{m2=sortPiAtoms[m]},
31+
With[
32+
{atomTypes=MoleculeProperty["AtomList"]@m2,
33+
piElectrons=effectivePiElectrons@m2,
34+
conjugatedAtomIndices=piSystemIndices@m2,
35+
piBonds=piBondList@m2},
36+
t*(diagonal[atomTypes,conjugatedAtomIndices,piElectrons]+(*diagonal terms*)
37+
offDiagonal[atomTypes,piElectrons,Length[conjugatedAtomIndices],piBonds])
38+
]]
39+
40+
HuckelMO[m_Molecule,t_:-1.]:=Map[Chop,AssociationThread@@Eigensystem@HuckelHamiltonianMatrix[m,t]]//KeySort
41+
42+
HuckelChargeDensityMatrix[m_Molecule,t_:-1.]:=With[
43+
{coeffs=Values@HuckelMO[m,t],
44+
nOcc=effectivePiElectronCount[m]/2, (*todo: add an option for net charge*)
45+
nPiAtoms=Length@piSystemIndices@m},
46+
Table[
47+
Sum[2*coeffs[[i,r]]*coeffs[[i,s]],{i,nOcc}],
48+
{r,nPiAtoms},{s,nPiAtoms}]//Chop]
49+
50+
onSp2Carbon[pattern_,bondType_:"Single"][m_Molecule]:=
51+
With[
52+
{sp2Carbons=AtomList[m,
53+
MoleculePattern[{Atom["C","OrbitalHybridization"->"SP2"]}],
54+
"AtomIndex"],
55+
targetAtoms=Flatten@BondList[m,
56+
MoleculePattern[{pattern,Atom["C","OrbitalHybridization"->"SP2"]},{Bond[{1,2},bondType]}],
57+
"AtomIndex"]},
58+
Complement[targetAtoms,sp2Carbons]]
59+
60+
nonRingSP2Atom[m_Molecule,symbol_String]:=AtomList[
61+
m,
62+
MoleculePattern[{Atom[symbol,"OrbitalHybridization"->"SP2","RingMemberQ"->False]}],
63+
"AtomIndex"]
64+
65+
piSystemIndices[m_Molecule]:=With[
66+
{sp2Atoms=AtomList[m,
67+
MoleculePattern[{Atom[_,"OrbitalHybridization"->"SP2"]}], (*any sp2 species*)
68+
"AtomIndex"],
69+
halogens=onSp2Carbon["F"|"Br"|"Cl"][m]},
70+
Union[sp2Atoms,halogens]]
71+
72+
sortPiAtoms[m_Molecule]:=With[
73+
{piAtoms=piSystemIndices[m],
74+
allAtoms=MoleculeProperty["AtomIndex"]@m},
75+
MoleculeModify[m, {"RenumberAtoms",Join[piAtoms,Complement[allAtoms,piAtoms]]}]
76+
]
77+
78+
effectivePiElectrons[m_Molecule]:=With[
79+
{default=MoleculeProperty["PiElectronCount"]@m,
80+
conjugatedHalogens=onSp2Carbon["F"|"Br"|"Cl"]@m,
81+
alcoholOrEtherOxygen=onSp2Carbon["O"]@m,
82+
anilineLikeNitrogen=nonRingSP2Atom[m,"N"]
83+
(*need to treat other cases?*)},
84+
ReplacePart[default,Partition[
85+
Join[conjugatedHalogens,alcoholOrEtherOxygen,anilineLikeNitrogen],
86+
1]->2]]
87+
88+
effectivePiElectronCount[m_Molecule]:=Total@effectivePiElectrons[m]
89+
90+
piBondList[m_Molecule]:=With[
91+
{bonds=BondList[m],
92+
piAtoms=piSystemIndices[m]},
93+
Select[bonds,ContainsOnly[First[#],piAtoms]&]]
94+
95+
haa[Atom["B"],0]=-1.;
96+
haa[Atom["N"],1]=0.5;
97+
haa[Atom["N"],2]=1.5;
98+
haa[Atom["O"],1]=1.0;
99+
haa[Atom["O"],2]=2.0;
100+
haa[Atom["C"],1]=0.0;
101+
haa[Atom["C"],2]=0.0; (*acetylene should be fine also*)
102+
haa[Atom["F"],2]=3.0;
103+
haa[Atom["Cl"],2]=2.0;
104+
haa[Atom["Br"],2]=1.5;
105+
hab[{Atom["B"],Atom["C"]},_,_]=0.7;
106+
hab[{Atom["B"],Atom["N"]},_,_]=0.8;
107+
hab[{Atom["C"],Atom["N"]} ,_,1]=1.0;
108+
hab[{Atom["C"],Atom["N"]} ,_,2]=0.8;
109+
hab[{Atom["C"],Atom["C"]},_,_]=1.0;
110+
hab[{Atom["C"],Atom["O"]},"Double",1]=1.0; (*carbonyl*)
111+
hab[{Atom["C"],Atom["O"]},_,2]=0.8;
112+
hab[{Atom["C"],Atom["Cl"]},_,_]=0.4;
113+
hab[{Atom["Br"],Atom["C"]},_,_]=0.3;
114+
hab[{Atom["C"],Atom["F"]},_,_]=0.7;
115+
116+
bondType[Bond[pair_List,type_String],atoms_List,piElectrons_List]:=With[
117+
{symbols=Sort@atoms[[pair]],
118+
atom1=atoms[[pair[[1]]]]},
119+
pair->hab[symbols,type,
120+
If[atom1===Atom["C"], (*get the non-carbon number of pi electrons*)
121+
piElectrons[[pair[[2]]]],
122+
piElectrons[[pair[[1]] ]]
123+
]
124+
]
125+
]
126+
127+
offDiagonal[atomTypes_,piElectrons_,conjugatedAtomCount_,piBonds_]:=With[
128+
{half=SparseArray[
129+
bondType[#,atomTypes,piElectrons]&/@piBonds,{conjugatedAtomCount,conjugatedAtomCount} (*force it to be a square matrix of this size; otherwise it breaks with linear molecules*)
130+
]
131+
},
132+
half+Transpose[half]]
133+
134+
diagonal[atomTypes_,conjugatedAtomIndices_,piElectrons_]:=With[
135+
{rules=MapIndexed[{First@#2,First@#2}->haa@@#1&,Transpose[{atomTypes[[conjugatedAtomIndices]],piElectrons[[conjugatedAtomIndices]]}]]
136+
}, (*warning...this assumes that the conjugated atoms all come first before non-conjugated...in any case this will get screwy with display too*)
137+
SparseArray[rules]]
138+
139+
huckelAdjacencyMatrix[m_Molecule]:=With[
140+
{atomTypes=MoleculeProperty["AtomList"]@m,
141+
piElectrons=effectivePiElectrons@m,
142+
conjugatedAtomCount=Length@piSystemIndices@m,
143+
piBonds=piBondList@m},
144+
(*kind of overkill, but easy*)
145+
Unitize@offDiagonal[atomTypes,piElectrons,conjugatedAtomCount,piBonds]]
146+
147+
HuckelMOPlot[m_Molecule,t_:-1.]:=With[
148+
{MOs=N@HuckelMO[m,t],
149+
nOcc=effectivePiElectronCount[m]/2}, (*assumes all doubly occupied MOs*)
150+
AssociationThread[
151+
Keys[MOs]->
152+
MapThread[
153+
moPlot[#1][m,#2]&,
154+
{ConstantArray[occupiedMO,nOcc]~Join~ConstantArray[unoccupiedMO,(Length[MOs]-nOcc)],
155+
Values@MOs}]
156+
]]
157+
158+
HuckelTotalElectronsPlot[m_Molecule,t_:-1.]:=With[
159+
{nElectronsHuckel=Chop@Diagonal@HuckelChargeDensityMatrix[m,t]},
160+
moPlot[netCharge][m,nElectronsHuckel]]
161+
162+
HuckelNetChargePlot[m_Molecule,t_:-1.]:=With[
163+
{nElectronsHuckel=Chop@Diagonal@HuckelChargeDensityMatrix[m,t],
164+
nElectronsInitial=effectivePiElectrons[m]},
165+
moPlot[netCharge][m,(*just take the subset of pi orbitals*)
166+
nElectronsInitial[[1;;Length[nElectronsHuckel]]]-nElectronsHuckel]
167+
]
168+
169+
HuckelBondOrderPlot[m_Molecule,t_:-1.]:=With[
170+
{chargeDensityMatrix=Chop@HuckelChargeDensityMatrix[m,t],
171+
piAdjacencyMatrix=huckelAdjacencyMatrix[m]},
172+
boPlot[bondOrder][m,chargeDensityMatrix*piAdjacencyMatrix]]
173+
174+
moPlot[colorRule_][m_Molecule,coeffs_List]:=With[
175+
{m2=MoleculeModify["RemoveHydrogens"]@sortPiAtoms[m]},
176+
With[
177+
{xyCoords=m2["AtomDiagramCoordinates"][[piSystemIndices[m2]]],
178+
refArea=(1/Max[ Max[#,10^-2]&/@Abs[coeffs]]) }, (*handle cases where charge is zero?*)
179+
Show[
180+
MoleculePlot[m2,PlotTheme->"HeavyAtom"],
181+
Graphics@MapThread[
182+
colorRule[#1,#2,refArea]&,(*turn off normalization scaling*)
183+
{coeffs,xyCoords}]]
184+
]]
185+
186+
boPlot[colorRule_][m_Molecule,coeffs_?MatrixQ]:=With[
187+
{m2=MoleculeModify["RemoveHydrogens"]@sortPiAtoms[m]},
188+
With[
189+
{xyCoords=m2["AtomDiagramCoordinates"][[piSystemIndices[m2]]],
190+
nAtoms=Length[coeffs]},
191+
Show[
192+
MoleculePlot[m2,PlotTheme->"HeavyAtom"],
193+
Graphics@Flatten@Table[
194+
colorRule[coeffs[[r,s]],Midpoint[xyCoords[[{r,s}]]]],
195+
{r,1,nAtoms-1},{s,r+1,nAtoms}]
196+
]
197+
]]
198+
199+
(*I thought I would want independent control over display characteristics like radius, but that's over-rated. Could probably be refactored*)
200+
occupiedMO[coeff_?NumericQ,xy_List,scaleFactor_:1,arbitraryRadius_:0.5]:=Tooltip[{If[coeff<0,Red,Blue],Opacity[0.3],Disk[xy,Abs[coeff*scaleFactor]*arbitraryRadius]},
201+
coeff]
202+
203+
unoccupiedMO[coeff_?NumericQ,xy_List,scaleFactor_:1.,arbitraryRadius_:0.5]:=Tooltip[{If[coeff<0,Yellow,Green],Opacity[0.4],Disk[xy,Abs[coeff*scaleFactor]*arbitraryRadius]},
204+
coeff]
205+
206+
netCharge[coeff_?NumericQ,xy_List,scaleFactor_:1., arbitraryRadius_:0.5]:=Tooltip[
207+
{If[coeff<0,Red,Black],Opacity[0.3],Disk[xy,Abs[coeff*scaleFactor]*arbitraryRadius]},
208+
coeff]
209+
210+
bondOrder[coeff_?NumericQ,xy_List,scaleFactor_:1.,arbitraryRadius_:0.5]:=
211+
Tooltip[
212+
{Orange,Opacity[0.5],Disk[xy,Abs[coeff*scaleFactor]*arbitraryRadius]},
213+
coeff]
214+
215+
End[ ]
216+
217+
EndPackage[ ]
218+
219+
220+
221+
222+
223+

0 commit comments

Comments
 (0)