GaussSum-2.2.6.1/0000775000175000017500000000000012117172552012110 5ustar noelnoelGaussSum-2.2.6.1/Docs/0000775000175000017500000000000012117172552013000 5ustar noelnoelGaussSum-2.2.6.1/Docs/ch07s02.html0000664000175000017500000001512512117172552014760 0ustar noelnoel How to find the % contribution of a group to each molecular orbital (PDOS)

How to find the % contribution of a group to each molecular orbital (PDOS)

In order to define the atoms which comprise a group, a file, gausssum2.2/Groups.txt, should be created with a format similar to the following:

atoms
Ru
1
bpy1
2-11,14,17,22,27,34-35,42-43,50,57
bpy2
12,16,18-19,25-26,28-30,39-41,44-46,54-56,58,61
bpy3
13,15,20-21,23-24,31-33,36-38,47-49,51-53,59-60
			

The first line needs to be either "atoms", "orbitals", "allatoms" or "allorbitals". If it is "allatoms" or "allorbitals", then no further input is required and a separate group will be made for each atom or each orbital. Otherwise, as in the example above, you need to describe which atoms or which orbitals are in each group. The numbers correspond to the order of the atoms/orbitals in the output file. An easy way to obtain these for Gaussian calculations is to open the output file in GaussView and turn on the labels. Groups.txt needs to obey the following rules:

A single point calculation should be done with the following keywords: (Gaussian) pop=full iop(3/33=1,3/36=-1), (GAMESS) NPRINT=3. This creates a large log file containing information on the overlap matrix among other things. (Note: the 3/36=-1 option for Gaussian prevents the calculation and printing of the multipole matrices; this is purely to keep the output file size as small as possible. In some cases, for example SCRF calculations, the multipole matrices must be calculated - if so, leave out the 3/36=-1. It will not affect the calculation of the PDOS.)

Using GaussSum open the log file and choose Orbitals. Pick the DOS option. See the previous section for information on the options.

Click on the GaussSum logo. GaussSum calculates the percent contributions of each of the groups to each of the molecular orbitals. This may take a few minutes.

Afterwards, the partial density of states spectra (PDOS) are plotted. Note that each one is stacked on top of the previous one, which means that the line at the greatest height is equal to the sum of all of the partial density of states, and hence equal to the total density of states spectrum. The stacking order is undefined. Information on the spectra is written to gausssum2.2/DOS_spectrum.txt which can be used to plot your own graphs.

Information on the molecular orbitals and the percent contributions of the groups is written to gausssum2.2/orbital_data.txt. The last few columns of orbital_data.txt contain more accurate values for the percent contributions and are used by the Electronic transitions operation. You should not edit this file if you wish to use the information in it to calculate the changes in charge density associated with electronic transitions, as described in Chapter 8, How do I get the UV-Vis or circular dichroism spectrum of a molecule?.

Note that the percent contributions are calculated based on Mulliken Population Analysis (MPA). MPA has some well-known deficiencies which can lead to unphysical values such as negative percentage contributions. If this happens for an orbital in which you are interested, remember that the exact figures are less important than the trend across a group of compounds.

Creation of PDOS spectra is also supported for unrestricted calculations with Gaussian. The spectrum plotted is of the total DOS broken down by the contribution of each of the groups. orbital_data.txt contains information on the breakdown of the alpha and beta electrons by group.

GaussSum-2.2.6.1/Docs/ch08.html0000664000175000017500000001062612117172552014435 0ustar noelnoel Chapter 8. How do I get the UV-Vis or circular dichroism spectrum of a molecule?

Chapter 8. How do I get the UV-Vis or circular dichroism spectrum of a molecule?

Table of Contents

The UV-visible spectrum
The circular dichroism spectrum
The electron density difference map (EDDM) [Gaussian only]

The UV-visible spectrum

Open a log file that is the result of a TD-DFT calculation. For best results, a Gaussian TD-DFT calculation should include the following keyword "IOP(9/40=2)".

Choose the Electronic transitions from the list of operations on the left.

Choose the start and end (in nm) of the convoluted spectrum, as well as the number of points you wish to have in the calculated spectrum. FWHM refers to the full width at half-maximum of the gaussian curves used to convolute the spectrum. FWHM should be entered in cm-1.

After you have set the various parameters, click on the GaussSum logo to run convolute the spectrum.

The details are written to gausssum2.2/UVSpectrum.txt and gausssum2.2/UVData.txt. The file UVData.txt contains information on the contribution of singly-excited configurations to each electronic transition.

If there is a file in the gausssum2.2 directory called orbital_data.txt containing information on the percent contributions of various groups (e.g. ligands and metal centers) to the various molecular orbitals, GaussSum will use that data. It will calculate, for each transition, the change in charge density on each group. This information will be added to gausssum2.2/UVData.txt. (For more information, please see "How to find the % contribution of a group to each molecular orbital".)

GaussSum-2.2.6.1/Docs/index.html0000664000175000017500000000774612117172552015013 0ustar noelnoel GaussSum Version 2.2

GaussSum Version 2.2


Table of Contents

Introduction
Citation
Acknowledgments
1. Installation
Installing an all-in-one bundle on Windows
Installing the GaussSum scripts in Windows
Installing in Linux
2. How do I find all lines with a certain phrase?
3. What should I do if there are problems plotting?
4. How do I follow the progress of an SCF convergence?
5. How do I follow the progress of a geometry optimisation?
6. How do I get the IR or Raman spectrum of a molecule?
7. How do I extract molecular orbital information?
How to extract basic information (DOS)
How to find the % contribution of a group to each molecular orbital (PDOS)
How to find the nature of the overlap between different groups of atoms (COOP)
8. How do I get the UV-Vis or circular dichroism spectrum of a molecule?
The UV-visible spectrum
The circular dichroism spectrum
The electron density difference map (EDDM) [Gaussian only]
GaussSum-2.2.6.1/Docs/pr02.html0000664000175000017500000005344112117172552014460 0ustar noelnoel Citation

Citation

If you use GaussSum to obtain results for publication, please cite it as follows:

N. M. O'Boyle, A. L. Tenderholt and K. M. Langner. J. Comp. Chem., 2008, 29, 839-845.

Here is a list of some papers that cite GaussSum.

  1. Ligand-Selective Photodissociation from [Ru(bpy)(4AP)4]2+: a Spectroscopic and Computational Study Luca Salassa, Claudio Garino, Giovanni Salassa, Carlo Nervi, Roberto Gobetto, Carlo Lamberti, Diego Gianolio, Ranieri Bizzarri and Peter J. Sadler Inorg. Chem., 2009, 48 (4), pp 1469-1481

  2. Localised to intraligand charge-transfer states in cyclometalated platinum complexes: an experimental and theoretical study into the influence of electron-rich pendants and modulation of excited states by ion binding David L. Rochester, Stephanie Develay, Stanislav Zali, J. A. Gareth Williams, Dalton Trans., 2009, (10),1728-1741

  3. Synthetic, structural, photophysical and computational studies of -conjugated bis- and tris-1,3,2-benzodiazaboroles and related bis(boryl) dithiophenes Lothar Weber, Vanessa Werner, Mark A. Fox, Todd B. Marder, Stefanie Schwedler, Andreas Brockhinke, Hans-Georg Stammler, Beate Neumann, Dalton Trans., 2009, (8),1339-1351

  4. The Chromophore Structure of the Cyanobacterial Phytochrome Cph1 As Predicted by Time-Dependent Density Functional Theory Ricardo A. Matute and Renato Contreras, Guillermo Prez-Hernndez and Leticia Gonzlez J. Phys. Chem. B, 2008, 112 (51), pp 16253-16256

  5. Comparison of adsorption mechanism on colloidal silver surface of alafosfalin and its analogs Journal of Raman Spectroscopy Edyta Podstawka, Marcin Andrzejak, Pawelstrok Kafarski, Leonard M. Proniewicz Volume 39, Issue 9, Date: September 2008, Pages: 1238-1249

  6. Computational and Spectroscopic Studies of New Rhenium(I) Complexes Containing Pyridylimidazo[1,5-a]pyridine Ligands: Charge Transfer and Dual Emission by Fine-Tuning of Excited States Luca Salassa, Claudio Garino, Andrea Albertino, Giorgio Volpi, Carlo Nervi, Roberto Gobetto and Kenneth I. Hardcastle Organometallics, 2008, 27 (7), pp 1427-1435

  7. A Computational Study of the Ground and Excited State Structure and Absorption Spectra of Free-Base N-Confused Porphine and Free-Base N-Confused Tetraphenylporphyrin Shubham Vyas, Christopher M. Hadad and David A. Modarelli J. Phys. Chem. A, 2008, 112 (29), pp 6533-6549

  8. Determination of Absolute Configuration of Chiral Hemicage Metal Complexes Using Time-Dependent Density Functional Theory Frederick J. Coughlin, Karl D. Oyler, Robert A. Pascal, Jr., and Stefan Bernhard Inorg. Chem., 2008, 47 (3), pp 974-979

  9. Effect of an aliphatic spacer group on the adsorption mechanism of phosphonodipeptides containing N-terminal glycine on the colloidal silver surface Journal of Raman Spectroscopy Volume 39, Issue 10, Date: October 2008, Pages: 1396-1407 Edyta Podstawka, Pawelstrok Kafarski, Leonard M. Proniewicz

  10. Effect of an aliphatic spacer group on the adsorption mechanism on the colloidal silver surface of L-proline phosphonodipeptides Journal of Raman Spectroscopy Edyta Podstawka, Pawelstrok Kafarski, Leonard M. Proniewicz Volume 39, Issue 12, Date: December 2008, Pages: 1726-1739

  11. Electronic structure and reactivity analysis for a set of Zn-chelates with substituted 8-hydroxyquinoline ligands and their application in OLED Ricardo Vivas-Reyes, Francisco Nunez-Zarur, Emiliano Martinez Organic Electronics, Volume 9, Issue 5, October 2008, Pages 625-634

  12. A laser flash photolysis, matrix isolation, and DFT investigation of (?6-C6H5Y)Cr(CO)3 (Y = NH2, OCH3, H, CHO, or CO2CH3) Mohammed A.H. Alamiry, Peter Brennan, Conor Long, Mary T. Pryce, Journal of Organometallic Chemistry, Volume 693, Issue 17, 15 August 2008, Pages 2907-2914

  13. Mechanism of Forster-type hopping of charge transfer and excitation energy transfer along blocked oligothiophenes by Si-atoms Yong Ding, Xiangsi Wang, Fengcai Ma Chemical Physics, Volume 348, Issues 1-3, 2 June 2008, Pages 31-38

  14. Mechanism of Ligand Photodissociation in Photoactivable [Ru(bpy)2L2]2+ Complexes: A Density Functional Theory Study Luca Salassa, Claudio Garino, Giovanni Salassa, Roberto Gobetto and Carlo Nervi J. Am. Chem. Soc., 2008, 130 (29), pp 9590-9597

  15. Nature of Charge Carriers in Long Doped Oligothiophenes: The Effect of Counterions Natalia Zamoshchik, Ulrike Salzner and Michael Bendikov J. Phys. Chem. C, 2008, 112 (22), pp 8408-8418

  16. Photoinduced Se?C Insertion Following Photolysis of (?5-C4H4Se)Cr(CO)3. A Picosecond and Nanosecond Time-Resolved Infrared, Matrix Isolation, and DFT Investigation Peter Brennan, Michael W. George, Omar S. Jina, Conor Long, Jennifer McKenna, Mary T. Pryce, Xue-Zhong Sun and Khuong Q. Vuong Organometallics, 2008, 27 (15), pp 3671-3680

  17. Quantum chemical studies on the potentially important imidates Tarek M. El-Gogary Journal of Molecular Structure: THEOCHEM, Volume 861, Issues 1-3, 30 July 2008, Pages 62-67

  18. Reversible Intramolecular C?C Bond Formation/Breaking and Color Switching Mediated by a N,C-Chelate in (2-ph-py)BMes2 and (5-BMes2-2-ph-py)BMes2 Ying-Li Rao, Hazem Amarne, Shu-Bin Zhao, Theresa M. McCormick, Sanela Marti, Yi Sun, Rui-Yao Wang and Suning Wang J. Am. Chem. Soc., 2008, 130 (39), pp 12898-12900

  19. Ruthenium-carbonyl complexes of 1-alkyl-2-(arylazo)imidazoles: Synthesis, structure, spectra and redox properties T.K. Mondal, S.K. Sarker, P. Raghavaiah, C. Sinha Polyhedron, Volume 27, Issue 13, 10 September 2008, Pages 3020-3028

  20. Spectroscopic and theoretical studies on axial coordination of bis(pyrrol-2-ylmethyleneamine)phenyl complexes Jia-Mei Chen, Wen-Juan Ruan, Liang Meng, Feng Gao, Zhi-Ang Zhu Spectrochimica Acta Part A: Molecular and Biomolecular Spectroscopy, Volume 71, Issue 1, 1 November 2008, Pages 191-198

  21. Structural Properties of l-X-l-Met-l-Ala Phosphonate Tripeptides: A Combined FT-IR, FT-RS, and SERS Spectroscopy Studies and DFT Calculations Edyta Podstawka, Pawe? Kafarski and Leonard M. Proniewicz J. Phys. Chem. A, 2008, 112 (46), pp 11744-11755

  22. Structures and Bonding on a Colloidal Silver Surface of the Various Length Carboxyl Terminal Fragments of Bombesin Edyta Podstawka, Yukihiro Ozaki and Leonard M. Proniewicz Langmuir, 2008, 24 (19), pp 10807-10816

  23. Structure?Property Relationships of Polyselenoethers [?(CH2)ySe?]x (y = 1, 2, and 3) and Related Polyethers and Polysulfides Yuji Sasanuma, Akinori Watanabe and Kenta Tamura J. Phys. Chem. B, 2008, 112 (32), pp 9613-9624

  24. Structure, spectra and electrochemistry of ruthenium-carbonyl complexes of naphthylazoimidazole Inorganica Chimica Acta, Volume 361, Issue 8, 2 June 2008, Pages 2431-2438 Tapan Kumar Mondal, Joydev Dinda, Jack Cheng, Tian-Huey Lu, Chittaranjan Sinha

  25. Structure, Stereodynamics and Absolute Configuration of the Atropisomers of Hindered Arylanthraquinones Lodovico Lunazzi, Michele Mancinelli and Andrea Mazzanti J. Org. Chem., 2009, 74 (3), pp 1345-1348

  26. Synthesis, Separation, and Circularly Polarized Luminescence Studies of Enantiomers of Iridium(III) Luminophores Frederick J. Coughlin, Michael S. Westrol, Karl D. Oyler, Neal Byrne, Christina Kraml, Eli Zysman-Colman, Michael S. Lowry and Stefan Bernhard Inorg. Chem., 2008, 47 (6), pp 2039-2048

  27. Theoretical analysis on the electronic structures and properties of PPV fused with electron-withdrawing unit: Monomer, oligomer and polymer Yangwu Fu, Wei Shen, Ming Li Polymer, Volume 49, Issue 10, 13 May 2008, Pages 2614-2620

  28. Computational Study of Iron(II) Systems Containing Ligands with Nitrogen Heterocyclic Groups R. A. Kirgan and D. P. Rillema J. Phys. Chem. A, 2007, 111 (50), pp 13157-13162

  29. Electronic Spectroscopy of Nonalternant Hydrocarbons Inside Helium Nanodroplets Ozgur Birer, Paolo Moreschini, Kevin K. Lehmann, and Giacinto Scoles J. Phys. Chem. A, 2007, 111 (49), pp 12200-12209

  30. Spectroscopic and Computational Studies of a Ru(II) Terpyridine Complex: The Importance of Weak Intermolecular Forces to Photophysical Properties Claudio Garino, Roberto Gobetto, Carlo Nervi, Luca Salassa, Edward Rosenberg, J. B. Alexander Ross, Xi Chu, Kenneth I. Hardcastle, and Cristiana Sabatini Inorg. Chem., 2007, 46 (21), pp 8752-8762

  31. Influence of the Substituted Side Group on the Molecular Structure and Electronic Properties of TPP and Related Implications on Organic Zeolites Use Godefroid Gahungu, Bin Zhang, and Jingping Zhang J. Phys. Chem. B, 2007, 111 (19), pp 5031-5033

  32. Syntheses and structures of mononuclear lutetium imido complexes with very short Lu-N bonds Tarun K. Panda, Soren Randoll, Cristian G. Hrib, Peter G. Jones, Thomas Bannenberg, Matthias Tamm, Chem. Commun., 2007, (47),5007-5009

  33. A DFT/TDDFT study of the structural and spectroscopic properties of Al(III) complexes with 4-nitrocatechol in acidic aqueous solution Jean-Paul Cornard, Christine Lapouge, Jean-Claude Merlin Chemical Physics, Volume 340, Issues 1-3, 9 November 2007, Pages 273-282

  34. Adsorption mechanism of physiologically active l-phenylalanine phosphonodipeptide analogues: Comparison of colloidal silver and macroscopic silver substrates E. Podstawka, A. Kudelski, L.M. Proniewicz Surface Science, Volume 601, Issue 21, 1 November 2007, Pages 4971-4983

  35. Theoretical studies on electrochemistry of p-aminophenol Yuanzhi Song Spectrochimica Acta Part A: Molecular and Biomolecular Spectroscopy, Volume 67, Issues 3-4, July 2007, Pages 611-618

  36. Intramolecular hydrogen bonding and photoinduced intramolecular proton and electron transfer in 2-(2'-hydroxyphenyl)benzothiazole Dongjie Sun, Jinghai Fang, Guanghua Yu, Fengcai Ma Journal of Molecular Structure: THEOCHEM, Volume 806, Issues 1-3, 31 March 2007, Pages 105-112

  37. Photophysical properties and computational investigations of tricarbonylrhenium(I)[2-(4-methylpyridin-2-yl)benzo[d]-X-azole]L and tricarbonylrhenium(I)[2-(benzo[d]-X-azol-2-yl)-4-methylquinoline]L derivatives (X = N-CH3, O, or S; L = Cl-, pyridine) Andrea Albertino, Claudio Garino, Simona Ghiani, Roberto Gobetto, Carlo Nervi, Luca Salassa, Edward Rosenberg, Ayesha Sharmin, Guido Viscardi, Roberto Buscaino, Gianluca Croce, Marco Milanesio Journal of Organometallic Chemistry, Volume 692, Issue 6, 15 February 2007, Pages 1377-1391

  38. A Density Functional Theory Study of the Electronic Properties of Os(II) and Os(III) Complexes Immobilized on Au(111). O'Boyle, N. M.; Albrecht, T.; Murgida, D. H.; Cassidy, L.; Ulstrup, J.; Vos, J. G., Inorg. Chem., 2007, 46, 117.

  39. Photophysical and electrochemical properties of new ortho-metalated complexes of rhodium(III) containing 2,2-dipyridylketone and 2,2-dipyridylamine. An experimental and theoretical study Wei Lin Su, Yu Cheng Yu, Mei Ching Tseng, Shao Pin Wang and Wen Liang Huang Dalton Trans., 2007, 3440.

  40. Photochemical cis-trans Isomerization of cis-(eta6-1,2-Diphenylethene)Cr(CO)3 and the Molecular Structure of trans-(eta6-1,2-Diphenylethene)Cr(CO)3 A. Coleman, S.M. Draper, C. Long, and M.T. Pryce Organometallics, 2007, 26, 4128.

  41. Density Functional Studies on the Effects of Hydrogen Bonding on the Formation of a Charge-Transfer Complex between p-Benzoquinone and 2,6-Dimethoxyphenol Bangal, P. R. J. Phys. Chem. A.; (Article); 2007; 111(25); 5536-5543.

  42. Lone Pair-pi and pi-pi Interactions Play an Important Role in Proton-Coupled Electron Transfer Reactions DiLabio, G. A.; Johnson, E. R. J. Am. Chem. Soc.; (Article); 2007; 129(19); 6199-620

  43. Intramolecular hydrogen bonding and photoinduced intramolecular proton and electron transfer in 2-(2'-hydroxyphenyl)benzothiazole. D. Sun, J. Fang, G. Yu and F. Ma. J. Mol. Struct. THEOCHEM, 2007, 806, 105.

  44. Photophysical properties and computational investigations of tricarbonylrhenium(I)[2-(4-methylpyridin-2-yl)benzo[d]-X-azole]L and tricarbonylrhenium(I)[2-(benzo[d]-X-azol-2-yl)-4-methylquinoline]L derivatives (X = N--CH3, O, or S; L = Cl-, pyridine). A. Albertino, C. Garino, S. Ghiani, R. Gobetto, C. Nervi, L. Salassa, E. Rosenberg, A. Sharmin, G. Viscardi, R. Buscaino, G. Croce, and M. Milanesio, J. Organomet. Chem., 2007, 692, 1377.

  45. Electronic transitions and bonding properties in a series of five-coordinate "16-electron" complexes [Mn(CO)3(L2)]- (L2 = chelating redox-active p-donor ligand). F. Hartl, P. Rosa, L. Ricard, P. Le Floch and S. Zalis. Coord. Chem. Rev., 2007, 251, 557.

  46. Theoretical studies on electrochemistry of p-aminophenol Y. Song Spectrochimica Acta Part A: Molecular and Biomolecular Spectroscopy, 2007, 67, 611.

  47. The electronic and structural properties of nonclassical bicyclic thiophene: Monomer, oligomer and polymer W. Shen, M. Li, R. He, J. Zhang and W. Lei Polymer, 2007, 48, 3912-3918

  48. Spectroscopic and computational studies on self-assembly complexes of bis(pyrrol-2- ylmethyleneamine) ligands linked by alkyl spacers with Cu(II) W. Li, Y. Wang, L. Yang, A. Szeghalmi, Y. Ye, J. Ma, M. Luo, J.-m. Hu and W. Kiefer J. Raman. Spectros., 2007, 38, 483-495.

  49. CO2 Fixation and Transformation by a Dinuclear Copper Cryptate under Acidic Conditions J.-M. Chen, W. W., X.-L. Feng and T.-B. Lu Chemistry - An Asian Journal, 2007, 2, 710-719.

  50. A DFT study of the chemisorption of methoxy on clean and low oxygen precovered Ru(0 0 0 1) surfaces M.N.D.S. Cordeiro, A.S.S. Pinto and J.A.N.F. Gomes Surface Science, 2007, 601, 2473-2485

  51. Syntheses, crystallography and spectroelectrochemical studies of ruthenium azomethine complexes M.Z. Al-Noaimi, H. Saadeh, S.F. Haddad, M.I. El-Barghouthi, M. El-khateeb and R.J. Crutchley Polyhedron, 2007, 26, 3675.

  52. Field-induced conformational changes in bimetallic oligoaniline junctions J.C. Sotelo, L. Yan, M. Wang and J.M. Seminario Phys. Rev. A, 2007, 75, 022511

  53. Density functional theoretical study of Cun, Aln (n = 4-31) and copper doped aluminum clusters: Electronic properties and reactivity with atomic oxygen C. Lacaze-Dufaure, C. Blanc, G. Mankowski and C. Mijoule Surface Science, 2007, 601, 1544-1553

  54. Electronic Structure and Excited States of Rhenium(I) Amido and Phosphido Carbonyl-Bipyridine Complexes Studied by Picosecond Time-Resolved IR Spectroscopy and DFT Calculations. Gabrielsson, A.; Busby, M.; Matousek, P.; Towrie, M.; Hevia, E.; Cuesta, L.; Perez, J.; Zalis, S.; Vlcek, A., Jr., Inorg. Chem., 2006, 45, 9789.

  55. Spectroscopic and Computational Studies on the Coordination-Driven Self-Assembly Complexes (ZnL)2 and (NiL)2 [L= Bis(2,4-dimethyldipyrrin-3-yl)methane]. Li, W.; Wang, Y.-B.; Yang, L.-Y.; Shan, X.-F.; Cai, X.; Szeghalmi, A.; Ye, Y.; Ma, J.-S.; Luo, M.-D.; Hu, J.; Kiefer, W., J. Phys. Chem. B., 2006, 110, 21958.

  56. The hydrogen bond in the acetylene-2(HF) complex: A theoretical study about intramolecular and unusual PI...H interactions using DFT and AIM calculations. B.G. Oliveira, R.C.M.U. Araujo, A.B. Carvalho, E.F. Lima, W.L.V. Silva, M.N. Ramos and A.M. Tavares, J. Mol. Struct. THEOCHEM, 2006, 775, 39.

  57. Calculation of standard electrode potential of half reaction for benzoquinone and hydroquinone. Y. Song, J. Xie, Y. Song, H. Shu, G. Zhao, X. Lv and W. Xie, Spectrochimica Acta Part A: Molecular and Biomolecular Spectroscopy, 2006, 65, 333.

  58. A theoretical quantum study on the distribution of electrophilic and nucleophilic active sites on Ag(100) surfaces modeled as Finite Clusters. C. H. Rios-Reyes, R. L. Camacho-Mendoza and L. H. Mendoza-Huizar, J. Mex. Chem. Soc., 2006, 50, 19.

  59. Computational studies of the interactions between emeraldine and palladium atom. B. Bialek, Surf. Sci., 2006, 600, 1679.

  60. Excited States of Nitro-Polypyridine Metal Complexes and Their Ultrafast Decay. Time-Resolved IR Absorption, Spectroelectrochemistry, and TD-DFT Calculations of fac-[Re(Cl)(CO)3(5-Nitro-1,10-phenanthroline)]. A. Gabrielsson, P. Matousek, M. Towrie, F. Hartl, S. Zalis, and A. Vlcek, Jr., J. Phys. Chem. A, 2005, 109, 6147.

  61. Molecular geometry, electronic structure and optical properties study of meridianal tris(8-hydroxyquinolinato)gallium(III) with ab initio and DFT methods. G. Gahungu, and J. Zhang, J. Mol. Struct. THEOCHEM, 2005, 755, 19.

  62. CH/N Substituted mer-Gaq3 and mer-Alq3 Derivatives: An Effective Approach for the Tuning of Emitting Color. G. Gahungu and J. Zhang. J. Phys. Chem. B, 2005, 109, 17762.

  63. Ground- and excited-state electronic structure of an emissive pyrazine-bridged ruthenium(II) dinuclear complex. W.R. Browne, N.M. O'Boyle, W. Henry, A.L. Guckian, S. Horn, T. Fett, C.M. O'Connor, M. Duati, L. De Cola, C.G. Coates, K.L. Ronayne, J.J. McGarvey, and J.G. Vos, J. Am. Chem. Soc., 2005, 127, 1229.

  64. Bimetallic Clusters Pt6Au: Geometric and Electronic Structures within Density Functional Theory W. Quan Tian, M. Ge, F. Gu, and Y. Aoki, J. Phys. Chem. A, 2005, 109, 9860.

  65. Ground vs. excited state interaction in ruthenium-thienyl dyads: implications for through bond interactions in multicomponent systems. W. Henry, W.R. Browne, K.L. Ronayne, N.M. O'Boyle, J.G. Vos, and J.J. McGarvey, J. Mol. Struct., 2005, 735-736, 123.

  66. (NH3CH2CH2NH3)Ag2SnS4: a quaternary sulfide-containing chiral layers. Y. An, B. Menghe, L. Ye, M. Ji, X. Liu, and G. Ning, Inorg. Chem. Commun., 2005, 8, 301.

  67. Ligand-to-Diimine/Metal-to-Diimine Charge-Transfer Excited States of [Re(NCS)(CO)3(alpha-diimine)] (alpha-diimine = 2,2'-bipyridine, di-iPr-N,N-1,4-diazabutadiene). A Spectroscopic and Computational Study. A.M. Blanco Rodriguez, A. Gabrielsson, M. Motevalli, P. Matousek, M. Towrie, J. Syebera, S. Zalis, and Antonin Vlcek, Jr., J. Phys. Chem. A, 2005, 109, 5016.

  68. DFT and HF Studies of the Geometry, Electronic Structure, and Vibrational Spectra of 2-Nitrotetraphenylporphyrin and Zinc 2-Nitrotetraphenylporphyrin. W. Li, Y.-B. Wang, I. Pavel, Y. Ye, Z.-P. Chen, M.-D. Luo, J.-M. Hu, and W. Kiefer, J. Phys. Chem. A, 2004, 108, 6052.

  69. Assessment of intercomponent interaction in phenylene bridged dinuclear ruthenium(II) and osmium(II) polypyridyl complexes. A.L. Guckian, M.Doering, M. Ciesielski, O. Walter, J. Hjelm, N.M. O'Boyle, W. Henry, W.R. Browne, J.J. McGarvey, and J.G. Vos, Dalton Trans., 2004, 3943.

  70. Ab initio study of the electronic and structural properties of the crystalline polyethyleneimine polymer. G. Herlem and B. Lakard, J. Chem. Phys., 2004, 120, 9376.

GaussSum-2.2.6.1/Docs/ch02.html0000664000175000017500000000525412117172552014430 0ustar noelnoel Chapter 2. How do I find all lines with a certain phrase?

Chapter 2. How do I find all lines with a certain phrase?

Open the file you wish to search and choose Find from the list of operations on the left.

Either choose one of the default search terms or choose Custom. If you choose Custom, enter a search term into the box. Note: you can change the default search terms using the Settings dialog box.

Click on the GaussSum logo to start the script.

If you wish to find all lines containing either TERM_A or TERM_B, then use the following notation, TERM_A%TERM_B, for the search term. Any number of terms may be combined in this way.

GaussSum-2.2.6.1/Docs/ch01.html0000664000175000017500000000730512117172552014426 0ustar noelnoel Chapter 1. Installation

Chapter 1. Installation

Table of Contents

Installing an all-in-one bundle on Windows
Installing the GaussSum scripts in Windows
Installing in Linux

This chapter describes how to install and run GaussSum on computers running Windows or Linux. Note that there are two choices for installing in Windows. One is to install an all-in-one bundle of Python/Numpy/PIL/GaussSum (the easier method), the other is to install the GaussSum sources and the required libraries separately.

Installing an all-in-one bundle on Windows

Download the quite large all-in-one bundle from here. Extract the zip file into something like C:\Program Files\GaussSum2.2. To run, just doubleclick on GaussSum.exe. You may find it useful to create a shortcut on your desktop to GaussSum.exe (to do so, right-click on an empty part of the desktop, choose New -> Shortcut, browse to the folder where you installed GaussSum and choose GaussSum.exe). If you want to set a startup folder, right-click on the icon, choose Properties -> Shortcut -> Start in:, and type the name of the startup folder.

GaussSum-2.2.6.1/Docs/ch07.html0000664000175000017500000001165212117172552014434 0ustar noelnoel Chapter 7. How do I extract molecular orbital information?

Chapter 7. How do I extract molecular orbital information?

Table of Contents

How to extract basic information (DOS)
How to find the % contribution of a group to each molecular orbital (PDOS)
How to find the nature of the overlap between different groups of atoms (COOP)

This chapter has been divided into three sections. The first section describes how to extract information on the eigenvalues and symmetries of the molecular orbitals. The second section describes how to extract information on the contributions of groups of atoms to each of the molecular orbitals. The third section describes how to extract information on the nature of the overlap between different groups of atoms.

How to extract basic information (DOS)

Open the log file containing the relevant information and choose Orbitals from the list of operations on the left. Pick the DOS option.

The boxes labeled "Start" and "End" are the start and end points (in eV) of the density of states spectrum. The box labeled "FWHM" is the full width at half-maximum (in eV) of the gaussian curves used to convolute the DOS and COOP spectra.

Click on the GaussSum logo to start the script. The molecular orbital information is written to gausssum2.2/orbital_data.txt.

The density of states (DOS) spectrum is convoluted using Gaussian curves of unit height and the specified full width at half-maximum. Gnuplot is then used to plot the spectrum. The details are written to gausssum2.2/DOS_spectrum.txt.

If you tick the box labelled "Create originorbs.txt?", a file gausssum2.2/orginorbs.txt will be created which can be used to plot the orbital energies as a series of bars, one above the other, using a program such as Origin (Windows) or Grace (Linux). See the worked example on the GaussSum web site for more information.

Unrestricted calculations are supported for Gaussian. The same files are created but with the data broken down into sections for alpha and beta electrons. The DOS spectrum plotted is also different, containing an alpha DOS, a beta DOS and a (scaled) total DOS. If you ticked the box to create originorbs.txt, the beta eigenvalues are listed after all of the alpha eigenvalues.

GaussSum-2.2.6.1/Docs/ch01s02.html0000664000175000017500000001346412117172552014756 0ustar noelnoel Installing the GaussSum scripts in Windows

Installing the GaussSum scripts in Windows

Install Python

GaussSum requires Python, which is a programming language commonly used for scripting.

Go to the Python 2.7 install page. Download and run the Windows installer, Python-2.7.3.msi. Install it into something like C:\Python2.7. GaussSum also works well with Python 2.5 and 2.6.

Install Numpy

GaussSum requires Numpy, which is a Python extension that allows efficient matrix algebra.

Go to the Numpy download page. Download and run the Windows installer for your version of Python.

Install the Python Imaging Library (PIL)

In order to create .png images, GaussSum requires the Python Imaging Library, which is a Python package that allows image manipulation.

Go to the PIL download page. Download the run the Windows installer for your version of Python.

Install the GaussSum Python scripts and Gnuplot

The scripts can be found here. Extract the zip file into something like C:\Program Files\GaussSum (note: Gnuplot is included in this zip file in the sub folder gnuplot400).

Create a shortcut on your desktop to GaussSum.py (to do this, right-click on an empty part of the desktop, choose New -> Shortcut, browse to the folder where you installed GaussSum and choose GaussSum.py). To change the icon, right-click on the icon, choose Properties -> General -> Change Icon -> Browse. Find the folder where you installed GaussSum and choose GaussSum.ico. In addition, change the program used to open GaussSum by following these instructions: right-click on the icon, choose Properties -> General -> Opens with -> Change -> PythonW. If you want to set a startup folder, right-click on the icon, choose Properties -> Shortcut -> Start in:, and type the name of the startup folder.

If you have any questions or requests, or if you wish to be added to the mailing list for information on new versions and bug fixes, please send an email to gausssum-help@lists.sourceforge.net.

Start GaussSum

Just double-click the shortcut to GaussSum.py to start GaussSum.

GaussSum-2.2.6.1/Docs/style.css0000664000175000017500000000134612117172552014656 0ustar noelnoelp { font-size: 90%; color: #333300; line-height: 160%; font-family: Verdana,Arial,Helvetica,Sans-Serif,MS Sans Serif, sans-serif; text-align: justify; } a { font-size: 100%; line-height: 160%; font-family: Verdana,Arial,Helvetica,Sans-Serif,MS Sans Serif, sans-serif; text-align: justify } .application { color: red; } .year { font-weight: bold; } .journal { font-style: italic; } .volume { text-decoration: underline; } h2 { font-size: 110%; color: black; font-family: Georgia, Verdana, sans-serif; text-align: justify; line-height:50%; } GaussSum-2.2.6.1/Docs/ch08s03.html0000664000175000017500000000630312117172552014760 0ustar noelnoel The electron density difference map (EDDM) [Gaussian only]

The electron density difference map (EDDM) [Gaussian only]

An EDDM is a representation of the changes in electron density that occur for a given electronic transition. It is calculated using the information on the single-excited configurations that contribute to each transition. The relative contribution is based on the square of the configuration's coefficient. Note that for some programs (e.g. Gaussian) these squares are not guaranteed to sum to 1.0 and so should not be regarded as scientifically accurate. However, they should be sufficient for the purposes of generating a diagram.

After you have plotted the UV-Vis or circular dichroism spectrum, copy a checkpoint file (or formatted checkpoint file) into the gausssum2.2 directory. Then select "Electronic transitions" and choose the "Create EDDM script?" option. Click on the GaussSum logo to convolute the spectrum and generate gausssum2.2/eddm.bat (gausssum2.2/eddm.sh on Linux).

Next you need to set the environment variable G03DIR to the directory containing the Gaussian binaries. To generate the EDDM, at a command prompt run "eddm.bat N", where N is the transition number (starting from 1 for the lowest energy transition).

GaussSum-2.2.6.1/Docs/ch06.html0000664000175000017500000001300712117172552014427 0ustar noelnoel Chapter 6. How do I get the IR or Raman spectrum of a molecule?

Chapter 6. How do I get the IR or Raman spectrum of a molecule?

(Gaussian,GAMESS)

Next, open a log file containing the results of a freq calculation. It isn't necessary to specify whether you wish to calculate the IR or the Raman spectrum - the IR spectrum will always be calculated, and if you ran a freq=raman job, then the Raman activity and Raman intensity spectra will be calculated.

Choose Frequencies from the list of operations on the left.

Parameters for Frequencies

Start, End

The spectra will be calculated for wavelengths between Start and End. The units of Start and End are cm-1.

Num pts

This parameter determines the number of points in the calculated spectra.

FWHM

The Full Width at Half Maximum of each peak.

Scaling factor

You can choose either a general or individual scaling factor (see below).The calculated frequencies are multiplied by the scaling factor. The scaled frequencies are then used to generate the spectra.

Exc. wavelength (nm)

(Only available for Raman) The value of the excitation wavelength is used to calculate the Raman intensities from the Raman activity (see below) using the equation described by Krishnakumar et al. (J. Mol. Struct., 2004, 702, 9) and Keresztury et al. (Spectrochimica Acta, 1993, 49A, 2007).

Temp. (K)

(Only available for Raman) This value determines the temperature used in the Raman intensity equation (see above).

Click on the GaussSum icon to run the script.

The spectra are convoluted with Lorentzian curves and then plotted with Gnuplot.

Information on the each spectrum and on the normal modes are written to gausssum2.2/IRSpectrum.txt and gausssum2.2/RamanSpectrum.txt.

The first few lines of an example IRSpectrum.txt are shown below. Tabs are used to separate each column of information. This allows easy import into spreadsheet software (e.g. Excel), just by right-clicking on the file and choosing "Open with".

Spectrum			Normal Modes
Freq (cm-1)	IR act		Mode	Label	Freq (cm-1)	IR act	Scaling factors	Unscaled freq
8	0.000612391353264		1	A	466.3941	0.0	1.0	466.3941
16	0.000624493504806		2	A	466.3945	0.0	1.0	466.3945
24	0.000636968752613		3	A	698.2427	0.0	1.0	698.2427
32	0.000649832766662		4	A	698.2429	0.0	1.0	698.2429
		

If you want to use individual scaling factors, you should open a previously created IRSpectrum.txt or RamanSpectrum.txt and edit the column titled 'Scaling Factors'. You can do this in (for example) Excel, and then save as 'Tab Delimited'. Run the Frequencies option again but choose individual scaling factors this time. The new IRSpectrum.txt or RamanSpectrum.txt will contain the scaled frequencies.

GaussSum-2.2.6.1/Docs/pr03.html0000664000175000017500000001426012117172552014455 0ustar noelnoel Acknowledgments

Acknowledgments

A number of people provided helpful feedback during the development of GaussSum. The following names are listed in no particular order:

In order to create GaussSum, I had to learn a few things. I found the following resources very helpful:

GaussSum-2.2.6.1/Docs/mesh.gif0000664000175000017500000010425712117172552014434 0ustar noelnoelGIF89a@      .' !%*/+#-&?"(),%%5( 6365811;9F42<9%?77a4S8 CA ECG>>KEJH RINKYH QG7OFGKNMP jJ PRTQYPtI aO[QULMRT}H SUaNLXY ]XaW\[yR Z[iX sU mW eZQ_UTMOS_[^^__ VLJl`Wdc}] icv` [hfpc V^j^^c``ig jd;_ ]{gnlf qnj d {mwo g `so ps i/\uq5h?q uo[twxpL}tt o xyzwh {nmspqw yz tvsu q ~}y }vs xv ~ ||~v|r1 tOM%m    LE<y٩S͚I2˗0Pxfnbg/~Dԏ$H;~@ALΜ]ժ pj]٪f"IGMYZgbߨ ޺T@q 8.>[~(gllHz$Z\MW 3L)_G>B7B >`2*qIˆne~3e0bWvj`W-WLï\a{_}L~0eQ3 x-Rp!R>5HE$n"G/j iMJu &!I\KAW+KzQ`abI]L%CFV`~UO~PueBbFh ٕV*Ȅ>GBiDbl 4AuJ+DmWaX*| u3\cON LyS]6PXvŧi$ꧥ^\dz rޢg2l6&k%Agi MAhn`pt[mz_/}pcUZQcl{mGV~inUںcbU^īW*`LAVnGM-M)gWIk  c"ݺGضd#) YŨcUbW̒l3}nJK[XN酹^)eyAM^SeIȕIim#i4,CQR}rv+w("E-J5% 0tsϣl%^TG4cAWS+i/<+T\^3@MVCВC/ɶZQH~xl=T˝ OOG+QX0}p:=wslBŌ"~?z|iKͺc/xVObcE"b/RT$ox׸~me0fK+'@/})Fᬗ=_h g3x I@SYQr سk4)^a!LVct^ Uͮ@"eLH (0*Y sKu7Y`r88Q⼄ 1#`(@ 2HDq/DFCf`d9E-+,YY֘%?@/&OH ] @@$H}#է. IM\UI# I!蔧7pU$7[X RzIR.1 fUb,V` Kk#(/CgN EWd*C0 (e}̤[ C0sv_xH-IєJArv PET/!, v{Cgj:#/I\*ǝLb}|k,;p]R @Lm[;ynNtd.[ǐ=pYȘ7q.r? ;w"Oҗ;c{vFӛ.u*<զs15mp,}K]wk@OƖ/|(Z9;P+һ.O@ ZP8jqw=˦70=o~S\ @ uV%gO{kOUIF1a|8icAb0q`5˻Z&@uxX E@X@+EPBPYhHb𬃀ؗ;4p;H ݈]ak5 꺖l),YZx0_Qsp kkۑp&)/ŠM{F}Xy@;VPPfLJY <<9b@Ib@}'{$P{4G;ՈG&= +C2;ET\[9p m q+@v._uUaya*@t70ɓjlXYlؚB,߻B Măŗ;żZI˕ 3~K[td[I!Bu ݂{;52yL^!HN`KɍP j@D`Dhfz]lp ;j}b+2P{$T9˽x Sq:lllH 2W(z'q |LBh =+ :$ [58pk0 @k[p` @l`zʊJهP0˵|$5{؈-$躴&m5O~8ܹfUKǡ:_1!DAP \N~0; Tm?gP5@gg?p8p[ɕ hp ޝЗP+}z˪K+@ =kG̗kHaߒS `];b+tl۷ULO,nl*O,@.^g|vpAPgpɚݫ p 4ȬIz} i޳|~Q[ z^~=̞d;`^81\Q 4U;A mcH,.WKI͖w`&*@`018^]e`O`Po0 p  а hVz͚jM 4kZZ~B Sl]HaPzd[tWIJ!vޡz^y_[qv/@*M.055&ꙮ1e0U<?P 0 ð ` PKzp*߬LZB`Wp 2V,BG 1 E э?ANCMZ@[<@cP B)@&~(^qo33`Oop ` À ߼;)߬H !Lhc<,QbD ,^hD27=B~lXl[W2e#J5mđƉN0Ç9:eMRM5*S\ŚUVXGVذ c6_k"9m*G++?OfpG> EUTtuş_+b#+@T˭q+$XA+&૯Tb0 aÇ ʐ,B YOZh 4|ga@idӌ#+а !dȁ"djy<4 (Fz«@JB.\l*&L1!R/`ܳ*O,Ӣ 4@r6@`.Rh U 9D,Ğ('Vbj`UwVr܂< c5+("H3d‘"~Ş$݈Jg{VWZ.KV:m7!;Wr!7ɓ3]>!>t&^Y(sݫ; MT"K*K/ 6417(ĎIJQ%VxmiUqāPb)  4b"`%VjP! fY)_9{)i榦zjpz"bˤҍC;mld /+ 29ϳXF`rXFk" 4|B ;DC{B8dXJb1'eaFP2#^FugׄЃX(X>J.R&oZAjv:/"{N:fmG߳ن_B/ɧA9Za!9C|A*,shEZ F`. qֽD]#P"8 A`cIzȔ$0 :s^tWnEk!^Гqχi˛UNEIre8v2?,N_$0܈;bbE)XыepƁi67 Ox Үt@B55(C 15d%኉ W}jPZ Mr5fUЕd|x5iMhb>WeaQD0EW9)1` \q܁whx+Djl?֮7P8zӞG#[p q!t蹏t[3d:&p $:zS? D+d8HIH,`ű/wIa1p Ȃfrcx D…q9pFX.<1A[ Ԑ# yh'Cx=7Vy#_ d5y,&Sb- D"QkCG}ar#yn!G3FRr 0PO h*M C3cԼ .hԣV#XD  89YU#  ?ܸgt;z#2)K pP׭g+> K,*(?+8,b bk.&ƝH 4AL2ДAa?O]Bs.ʦ!RLfBaFfFrye<4 ,$Aw T*@;~h3+eWLh ɖ5e+4^W'#(IwhBg ,H!04^ĨF5\ Aw[Z,*C"`-\q<+#7$_O#K)Iڒ'!({"hpwgHVB33TeДDġ20X $1Jc5[;Dh.H-AEB"`5 xM_V '8r 3&;5u}L)ɒ UwH&/Sn@ ,E@*C<ܩ);xE&v@C(D h3q8h2ʪ+DC󮷎3cՇ3:qY%uU(Y }e-r^S\T!8y?0PN1yų `ETUЈ'[e!XDO W=nTc< ,ЅHxJFB{ ݫ`s[eu &&F7vAͣra#X+O<94 T`5+>UBZ/} ԎX:-E( Z50u:PC5<=7xH:zKW1W` L0Q?>) V{%%/?&3 Q !06/j @h &cUd`r[ER@Ѓ7 ؂I\!2OX*'.zì+ID0\'IJR(PYAt/;) 9)ua5 @$H|r){*pZ,)ʩ8s&X 'x2^H<&rbPpZ7 C6w5H #O-}` C|H܇rKĆ ;)Q;XX ?zDv3B30paxK-R6 F94 ːϠ-q YZūCr :n<=䪟I+DJcG+WJP} c7B2S<8.KʱJ$18ZC1")j k3 a0rW *ܪ-hbCpkG[l$7o|LCO(2J(İ\JvtG2ʀ Kqʮ z`r\B(J,]ppHQE'XaT4KA9@s9^0qXFWцI#2@bDp:k$#0="PFXO>xQ7ͫgJTN,݌r,ͬ ?2q"*g@_BDP9p;Q{\sK?#3[@3:ƾV#mZCx˔ .-/- 4?rA &P\JءՊ? `M\D +g g o(x# -' a$-e ^L"2,{-mг8jREL7 lk 983؂l<=<0Þ.V/bSK?, @)hS88M ~p,y,r+pJd% t7*L00'`>paҋ%$@~8]V۵`պ}~Saͯ|pdMXuʇoͯrHh,Ё5a 0 mk8{-32z Si\ [g "U@ 6bIxFbԭ)G;U1Y `_ٙ%bMԝ`  %TBTBav/ ^ױj ah7*H(J[<0):*^/2 c\eUR=Mõ3Ȝ* B(:q+.,W>& V5]` U]C"2ɎQ:pd xQH  &جB(ca̔D[fC^$%^ (@Tƃ2b5Ն+e Y@ ۘ%k73a05CCp4XOhlFnoFBv'ϠG `)"+۫g~ ; 5|# -0%aXV9Q5jXYٰjEUOC?T.#fVf3CfsF镅 +f:N jtN">.B݆C!:HtJgX0,xy[vHdV a4bSXNΈXe^ n^bWE3PEO*'8Y:ƈb-=NͶ]nmCVW|xT86V3_\@=nobebe8[h ^XPR f ;OeBWU+,]H~o:R&w'~JN,їln z᩶  0Qf!U[hr芡QV6z둼ebH&sNh@qiQtEVfPcac|}^`wl%V ٟR7uih>QdD-Ӧr X^'`? aSZme#-#v 0lh jZdeHbR` Z!pte646]#.[,UO$lR S(rU{L)| ލnVȂrY7ᯎ/T6F:œƸcVU*nb0tPј;Ϙc GJC9[\ ).ezFz+PHߥ)YhruPOjn;[  &EӶ4CiiEb6$[\f#3_ewoI3h\wX0X،)oCP<^7&c$'֟}gnńHTOmHucmhZ JPHuHo;P۾ѓ 3m6[3] ZilOYՆwjå랰4)sJ3fL`) AL~NED9?BFR,o޼3aw e={K>#WHyUx`MFx 1F!Ta `WCCaOć1,c AQ fAG F+2˚|t 6ذBI͝zM:p{fՄ&L)0P@A$Q`b,)v PR00u 0*", <]sf`qxR +(,kζv$/Ă +,gvZou'CUVAэ,r 5|5@5Y=G'Ԍ~?, 0<4 [09?(~$AAce'|Fbk=]w,D "FT؍'cν8n썞h4(IL2B洴RJ%,mmBex2I\"to8QBnRFᔉ"U"#+H!& hD؛7 Ē\,p\$HBq|S4ɉRtsE\ r0*@. RY@1"D )L NXa<@p4dhQD3MgڱRXAl$=9 )4S |(.T7Wfqaog?~?E"@GaJfh-8i&"AgC-],ن'2X{/ƜnxJhDh5kL$lM5VD7dəH'6ɑ]ۙE4Z/e`kIJW6|"{(NrL& re%A x:@ C*L$v0Ҫ:f5af2`H-iSR}{iq'FΌk Ęq9OЁb#W> 0|^e @yM/Ӌbb^HJ0*־~̹o faBH*@$p8 `E'6Ā2\z ʧJ+'ViQL2M^h<@KfZ)ͬ I$ڗ% .~&[~]܍nhi$E&=ffXc՜xp,> PG%x`p̼L01O 4Zj VHzM }S[({J~ϛ[D>3kTT <x~lgx m^%-c/l`>w(~{do.LЄwݲH RC ,b PP Us@܎"ZD Ja2~4UL-5"ƽ=@z F=PCɍ BJ`|!B!Z%"Ǯa <@:6U2(^;(}cZ;k2&ۮTE= qT:!r2nؔ@pS2Ag@  =$T(p.9ԃi5+HnLF<PnB t%*v̂!`avA xD1]Y/hEjy߻85@/,ԅĀ8W@=Ab"XFsTB%O <`*Sł0y9|`2L+tQȘĈ\ M x . %(aI\cVaT>p»49\L@^,ƽr@^픍hO]FDT^)x Ҝ#j 赃;8 4B%(JuՀ"@9ܗTdFWA* +&K "//@O`0cS$Kpnҿ:}h@=]9.,utB 8_X `: ˽#iO"B/D@,C;4F[:2L5:5G@p\r@Q  BY %Ѐ $!&ЀFFd e@zi1h0__:p xjE[T X1džΆa̝fjLPR@PP6a1Z+0P.Cv`(B n@Ā*+6 `Fx. @|L*^' hb/0BMJhGxفp8lD#h<@r }HKUIjB%2i6Bʦ%N ,.’J<l`, k=6 A20l +C)P 8@_mmB^ |N*i@~]'TJU$MC((,9ZPB_h;M*aƽˆ+@%BZlh\ 1\*T-. Bn6ՔI0C,kBmVphBB(B)+L'Бa%Ѐ ̭(mBMM-p[ ' P9n@J.DAp\ [5 "@CŶli@=TB.pQ.CV,,k%!∮T"p1.;Bh,Bׂ9L΁BH! )W-DQTi"N* eT 0 bLzl%208c0/0ܒ e5@ l)L`) / /TôB)/ G׾9@\0. ԃO%XWi  EO1=(R4@Бu؁7eM& C ː 4s<9F+2C,er$j(a,AorB/(>Ó0lf2+w29 /nt ӒY Ε % 3O4O]3P@&ICA368(E DlCEg*G@S dKs+"cMV6m$wF`-@ =6Xt;c?i%p4z+.78zrw=GUhoh GoUtt^-V3vI Q`T@qCR_D \8+@6lFlJZz | /XBOFBԎ ;4e2HMc/pt6/¢ -c8L_<L'T'l D3@x$ <Gy@rt&غ2dw5{kk1|I_}Fĝq9hF%1\)?W6XfC,ڼk2`O!DgPEC@~5q)`zq/L5C C!=R씕ԖIqt$ ,(2Ş: rtMal (@fR Ń | TB- NIdJw-/xDw |{/;ɘ-M+MQ d+|UfP!D_3` jJ 7J#cVJXOPE8,lzI_ "āFby#͒}>xidل^@^ J|@ kdCnGr}yċ6`"Wp#-7@5+upюKJ:cq4@)P*)%^ġE|B@ws̩&<0@*\yEl'j*a+ayE:z^Fqz)J`Qz3GhY&\Td|V' jH@HtA!&``1STĆxj!`&1kn2$& cI h튣bt.Ī5+kR"k+p=(b j,h(8Yb Ae1:V٘'`h&a~8T"0FEMvSGeoB!.t-8:s j@Q r` fJq;e}_MfwTT]$)3ʓ!T^[IvģA@PB!Vd6UY 9Ӷ$'lE n]EUS{B#؏UL &0'"@91HU2,_z+"5MQ1Εs!|M/(Z ab%h;aPUUYהE)aB+F'0d%EH!RtF|zmg+Rվ*0@ ʊjC>q)F1$q#MnlFUCy@*Ir["?,L8! H91 qca S,ʾF'h*hī2` dnA(6Щ BeXШ 8beM鳤w<D%/f:L'LO,ɸ$(Z|`$RA Ԁ/1o`k``Fd5ޠ@xJ(Z@0,vͺ&A ,BF)JItڄBe NοT!ܸG'/Mlz*0e& Y p'` @E Xl ` GİHvb -x@L ``kv#̆P(kʨ,a6VƉ!wȂa epǞl^2PLή&g` Ԡx21AQF(3T|pb*b#'qٱި6*0,ωewrb<:&QlCOx@ ! F{S&}PB#J)hk JJNif& 5Z^36eSPcbzM(Lcl7E8b*+x`KxhwʀFf6Hʹ9z&@`zx#*A*b'H)Q'#m(n;uB*JIf!B@=!{/A)8 $kN2% =jc@Q5 4Cs ` ` n\OUP/aP'.P8ɑ_BB90XpWS9##<,:XHUsH,JPXc'پIf`@A*S,igY-R<-m bЈ5*vʮ# jr OA] D F^]ȗ8E:VdBCL*bL@Fvp9*l@dFC#۾(;HcB'J&@Gd(x,xeݳ "t( >.rD%k2 k2v iVj #P6ޯPVj37 A84ʀQ): l*Ev4lS.FQ i:tP8"ɜhfbah@k*poasZNU*6S=Pw+sbBf1O##(!cJ܁;[!sˈ:JIrIwu(ۊVOѕV ֜v"LXXX*h<+tpZvz[zIx ɖ٩6JxBJ/<'zA{PɑG鈛Չ )M%sdii nW㹶\jU0'ȼK(&i:AdKvOmM9bcڦtt޺:tgzt[(:>fޗ󝼅 ba$<"8#JUtWwV Y &}cX3^p (0+*(ȱ]1K\ }΀ʷ0'(*٘TZ](Dn,&:&C{)"baʫf1hrё%tjHzBu`͜!oBc'ru"nZ}\t2+Z>ûh@ޠЈ" ^"0>=9c<|8|z=8L3o:>)hRĒ1bɖUM3U[L0^pjSByc0o4-I2O@ q`E.xЖ@%ֈZE7ܹtڍ޽ w 6l`Nb8Q%Ɠ*>b8|pEO\#thI*<.^21x=>ޜa{<dՇ`=KX"$>70e 2b*B z]ZSL&UYCOhQ?P!hmV[muW"_{_baƂjTT0ejQ0m11QPkVE3@C6E#` ]i0 EQ㤊% )# 5:R @d؂`$xH^ xx+_@Ozۢ7w\u0L0 d8) )9NFX㙧UŤ"!pDlZHkP*BSff24:Ab4&Jx WԔA"$45E DSIѵ($XM (W AäT2zv),P:({J$ SvGP;b dRi*zSk|Yn~$Fg%Dj (W!A L^/,ZϠѳHN p VIhe#H2 Ul"G2X@%#D-:dinhJ[ҷ@%X@5y0p=2ses =}Nͯ*8FX<)m{F)MSk֧W6$KK*;˰_^#i"N|#I+Th$FarQ$gCJD@)NZ\‚CBjA II0 "5JP/T j@0X[ EȀL##9&G&Ek;ܰ>Ĩ 4WtkSYRyk ^Vdh 6iga  7@-TA ^ M5QN!P:OXqBWdꪅKd`.-h!CAi\c y1RO"XַFra/K[y }hcΦ֤-3h Е*C Ӷ*,3䢌o4\B* mÓrLz[}zF|ÂB*J+ κĮ%u[>Ԩ&s|hB Z"ǜCt >‡C t8;)\NL5w]7D@TYA@ p&'Œ1j >jKa;ѭOkߨ"MWBOUݻA9|Z6mUW#Wr%nq{gh Bʢ=gi7ko:9 }ba?9myBR+Ԅ,$ivi`wr*Gwh>rfz`1 MLT& 8Y?l8ߨeOb-fuAn[Hn q{T!?gv5WY|AQ 0J8ah"$JvG 71v0r`+CP1wb[\92;F0EPy1c`DODJ$MXz63rp@g[0!I?pqml#[WujXXPqXdK3p``n:Z9)֏'J@:ːP! P( ɖiiK#1$I7FEQ3 k`FPD)Bkm! V`Dʹɥ1Tv<8 ɓs?`rjZ(suvH`U#C%h\X[\vth%8@0 7qaY{ BIsOR5T,:B d´jp(3*P0MT[JdjU 7П@8PY44,ztpz!)Ȕ?9.6n S7Kq:M;hGĨI;eJ-jī}%TCq3~" 4Z1]!EP[Cy`DԫiBfP3[T ;/[p;?0z,Heu|X.s5Kw\P )v} &h2QRvI QA{ţBU%S"z`)=,LAX:fpDf`PИkRAFm]^5і  @_!;wWCCr)ݳܱ=S|{V")"Iؑb,Q{P2Qv~IR (6iůX98ᎌ` gOuܩTӪЪ`!v:(U*U^b*_P~J a<RnAGX@|4 2s@Z!Y 51TՇ8p>hbAg[g1ZGnfLc1Nf(α}H rLAM~ޥ~/ 6 V̺:0(( j~jAI.Ic&dU TFj@݈*P;ːH"ݸ&k/0^ F~nGIPwpaM LW0WnюCJ7.3p/:( .4KQخcac6jIjy@kÅ[f9~H9DUT No KN?嗱 qhSz4fRvD PiQD8(8Al}"bCw1aQj׎j0sr؝tPX0k: H@ATU pօl4/oNX2 O R0v ͛J&Md W,^TTV!y2mk;w.eΤY_;wtj&U,UT*3eΜSL'P92UDB 4jЌSl+h͘ !B yK _0pĄ 6¿ `1oYgСE&]4TfHwӄa3OCQQh+\cUJxk4h:UkivU)P -2P0HhkV"5+<,+ (BpB,1 $0;4K4Q4^SqM*7n2ѱR pdH3G)RdN:O&a߆+!0B+;B- :Dk@+ l+|B ӯcD4NTtQScQHi ;l<(@y JzuzPe [{Pg01I>_w? q#V%cl,Iij$H mXʰnM1B@!cAa P0Ct68n1,`0TC F!Q ^/%kt;m,i''YN QCb #O&ie$C86ZB&! {B(F1@ 5ut"HhBi_V&{XMj$+@@ΛV;h5ʙ&4} N"k g,yы:ϰ0 `UHPA>A 3&FbzPFTE"'4'7GITJ'NAhj紈3#@!pBef'pXRBc)Rjj `Uj BN m辰HoY%-)a˰rZFlh^]=tZ,Q.-z`@9viHKFBM(g(d沥qfY]iW xC2\K]3'U,V1OyX\VWY ; J\( Y's {"v%T&DŜ2wˌw4W5f;[7{U}?ڎ.a)IAU,0o 7Bu2,AF沁 b^B/>83LfVL3lf[8k6g>;  }hB&o%%AcÀF/VdMG_  V̠8B#Ne`fP,! y 35/">| A;Gzz!ku@t }c@MtZ%=鑬¿)&ϓ(TЁKG=\7@!^6vt<w0l@1=lPf PhY~}&f?orxЃ%0O@ےJʋI*DW:wjj +Ueu1A odؔw#@ȥ)Yri]2yk.6 ϗd c淚 M4Nj4_pBQG9ʭք`3" y KX8'pB wov& kv3Ꟶw=6 mx xe)j7}[Zt7Є(4q _ ף*Xۻ=Sܳ8 >S/L@ӬQa2l>T9q>>1X s<˻47&s;zT7>I$M2j ~#:R$p,7D?}DVcJl5sDȂK%; 1;.̸X 4Q8C6@W͊ ;j>;;L9B6"?n>8Rc(D+:QDp#.*K!(C*KDM7;D=D*QH`8+-dV0C31<HCW L34>5DLCEHC bFjeTƒ$5CF7oBG,*{r m%CDsI*Q\1GȀw?H  ,\EH.,hY$&![t3| LTL_<>FH`H\ACkgCPK$̲ÂB|rř =;rGɞE}KG.;ٛ=jXJDM}􃨄*r!8E0ʹ[L,WHW(N5E>S@u>LL(W\,T-nY (LUrҹEOTBwRD4U\Vl8FXVDMŸŨ8ɕY7Lp>\\={Dd6ά‹/R%L %^C3[v0@$aE4US%X%U1=a}M-8͊xb\˵D6[]ށU^(p=F1 @vxG,MP$.e1M_jV37% 0e0Y,bYS>-⢵bHY_`W[uxumZJW`Jmݔ{ն}o;BLDFdX&E&8^J.Ʋ^ĿOX b!GSdbU>6bŒb:Xev/⛵_>Ӥbn֭[YZ[Z(ZvU]`{S6dn1&riEF^ gxBMBzTꢂ]h6U--xhbY\-٠Wh g鎆vcAc5S]TxGm;o f,^i5sV^4Lv&a*MG`[1p2 gҬh(v_MTF }k 0Xbe>vWc.fg%fT6;f5vWivWfM+Cʶl^ igr1Ef^mmm$~.9 ?p`kmYpbVkb_8^n[Y8>i`>g>~fl=ބ6l7. ? U->UorqVgC$j؅N[[aNX7M傆3'wFsfsVfhGbfnkWq[ q֍?3[<&X~1j1No!opj#W4?{y}ZOLն b,r=6mHx(r m3Gsboh/Vkgfi@;ihpkG?/;xEt+rtɶtSm>t{{{n(]oUV|=cl ͸['F(kug2t_mham5m8g;ixgxn>5fYvf񞯅wl&4iC ۳g mZ0_;f՗ VXTdE8@mڶn+wۺjm7n{ŋ7-†޽)4hڮNJ.cy3jXq4i3L1Ķt۶ ]tFr1[TZl^6E6[TtӨ~WYVe% Vدlv]u/w+_={<c 5] 2XhVE <jK:/֒oo$Ťl:r5THWP}#MVBYTw",XW-_\) |}u}k-c4e} 5_;|h \ZCkuF':Xn$SoxS7B54X7NLHUX3@]ﵗdJ vה~Xgc0&`J_Lf G#S'3<[>Vg96t8u 6,uIUݹB74PuVUzL:MV:{Xmik 36_NQ?nƯ- ḅRMRqvCN H:t9~RA'T7/V:b%HT:ؾ~A# ecmЮP ]w= D=ُm醲4-cOk(6Ґ#3:136|sA[wiTXɻ:5eUaڳa]+vCP>wn\lu<ʿ'(m<86X>RMtUE/Ep]NuWN P.  cE6<ʣGn,(Yz9t׋6bry/ ;A#Q;猒>$iU?%u]61PxS$AA2,07 ew c7>ɅCq!Fr :[;A.is+t|=a}20BҪD4fQ+I6l" mcx_2g#' *Q8q!=rC!Zƌv$ S2JXB|`t$%Hʐf8*GncHFҳiS)BN,KgN;}(OGNi8Ŏ|p ^ efp+RӋ Bթ>Z꺪G ("E+ia I`d*ST 3̞e7"CQOr0qPAFt}29˳<$Җ) ;GaussSum-2.2.6.1/Docs/ch03.html0000664000175000017500000000563212117172552014431 0ustar noelnoel Chapter 3. What should I do if there are problems plotting?

Chapter 3. What should I do if there are problems plotting?

Click on "File", "Settings". Check the path to the Gnuplot executable. You can test this by clicking on the "Test" button, which should display the GaussSum logo drawn using Gnuplot.

Note that the default location used by GaussSum for Gnuplot under Linux is "/usr/bin/gnuplot", but yours may be located in "/usr/local/bin/gnuplot". Under Windows, the default location used is the Gnuplot distribution bundled with GaussSum (e.g. "C:\Program Files\GaussSum-2.2\gnuplot400\bin\wgnuplot.exe"). However, if you are upgrading from an earlier version of GaussSum, the new version of GaussSum will use the configuration file of the earlier version, and so you will need to correct the path to Gnuplot.

If you still have problems, please let me know by sending an email to gausssum-help@lists.sourceforge.net.

GaussSum-2.2.6.1/Docs/pr01.html0000664000175000017500000002002712117172552014451 0ustar noelnoel Introduction

Introduction

GaussSum parses the output files of ADF, GAMESS, GAMESS-UK, Gaussian, Jaguar and PC GAMESS calculations to extract useful information.

It is written by Noel O'Boyle and is available for free under the GNU Public License. For up-to-date information, please see http://gausssum.sf.net.

GaussSum version 2.2 can do the following:

  • display all lines containing a certain phrase

  • follow the progress of the SCF convergence

  • follow the progress of a geometry optimisation

  • extract molecular orbital information, including contributions of groups of atoms to the molecular orbitals

  • plot the density of states spectrum (and the partial density of states, in the case of groups of atoms)

  • plot the crystal orbital overlap population (COOP) spectrum, which gives information on the bonding/anti-bonding nature of an overlap between atoms/groups

  • extract information on the UV-Vis transitions, including the change in the charge density of groups of atoms

  • plot the UV-Vis spectrum and the circular dichroism spectrum

  • extract information on IR and Raman vibrations

  • plot the IR and Raman spectra, which may be scaled using general or individual scaling factors

  • Handle compressed log files (.zip, .gz, .bz2) as easily as regular log files.

Release Notes for Version 2.2.6.1: Bugfix for 2.2.6. Gnuplot location undefined for new users of GaussSum (Guillaume Lamoureux).

Release Notes for Version 2.2.6: A patch from Thomas Pijper was integrated to enable calculation of Raman intensities (from Raman activity). Support has been added for calculating charge density changes for unrestricted calculations (requested by Phil Schauer). Blank lines in Groups.txt are now ignored.

Release Notes for Version 2.2.5: Parser updated to cclib r923 (Ben Stein, Marius Retegan). Removed minus signs in output for TD-DFT (previously these indicated the sign of the contribution). Corrected equation used for circular dichroism to match that from Stephens and Harada (see circular dichroism docs for ref). Thanks to Li-She Gan for identifying this problem and pointing me to this paper.

Release Notes for Version 2.2.4: Parser updated to cclib r912 (Tiago Silva).

Release Notes for Version 2.2.3: Fix serious bug with EDDM (Carlo Nervi, Carlos Silva Lopez). Parser updated to cclib r884 (Mahesh Kumar, Dan Matusek).

Release Notes for Version 2.2.2: Fix problems with Linux version (Daniel Liedert). Minor doc fixes (Irena Efremenko).

Release Notes for Version 2.2.1: Fix bug in importing cclib (Daniel Liedert). Parser updated to handle Gaussian09 CD output (Rino Pescitelli).

Release Notes for Version 2.2.0:

  • Update in parsing library (to cclib r877)

  • Added support for creating EDDM maps with Gaussian

Release Notes for Version 2.1.6: Can now handle unrestricted TD-DFT calculations correctly (previously there were errors in the contribution descriptions in UVData.txt).

Release Notes for Version 2.1.5: Updated cclib to cclib 0.9+ (r840). Fixed problem reparsing GeoOpts. Fixed problem with exe on Windows with default Gnuplot and Docs locations.

Release Notes for Version 2.1.4: Bugfixes for UVData.txt which had incorrect % contributions of singly-excited configurations and incorrect changes in electron density of groups.

Release Notes for Version 2.1.3: Bugfixes for incorrect data for energies in CDSpectrum.txt and incorrect units in heading in UVData.txt. Updated cclib to cclib 0.8 beta

Release Notes for Version 2.1.2: Bugfix for off-by-one error in orbital names in major and minor contributions in UVData.txt.

Release Notes for Version 2.1.1: Updated the code to save results to gausssum2.1 subfolder, along with some minor documentation fixes

Release Notes for Version 2.1.0:

  • Major update in parsing library (upgraded from cclib 0.6.1 to cclib 0.8dev)

  • Jaguar log files now supported

  • Compressed log files (.zip, .gz., .bz2) supported

  • Underlying code now uses Numpy for numerical calculation, rather than the deprecated Numeric

  • Fixed error in the output of DOS_spectrum.txt where the 'Total' column was equal to the values for the first group

  • Fixed problem plotting the COOP

Release Notes for Version 2.0.6: Plotting the PDOS was failing due to 'type' issues with Numeric arrays (due to changes in cclib 0.6.1).

Release Notes for Version 2.0.5: Parsing was failing for Gaussian files with "pop=regular".

Release Notes for Version 2.0.4: Plotting vibrational frequencies now works for GAMESS calculations that have imaginary frequencies (bug fix in cclib).

Release Notes for Version 2.0.3: Plotting vibrational frequencies now works for frequencies that don't have symmetry labels.

Release Notes for Version 2.0.2: COOP now works for unrestricted calculations.

Release Notes for Version 2.0: main differences compared to GaussSum 1.0

  • This is the first release of GaussSum that uses cclib to parse output files.

  • Calculation of the DOS and COOP uses matrix algebra now, and is almost instant.

  • Images can now be saved as .png files.

  • Groups can be described in terms of atomic orbitals now (and not just atoms).

GaussSum-2.2.6.1/Docs/ch07s03.html0000664000175000017500000000755112117172552014765 0ustar noelnoel How to find the nature of the overlap between different groups of atoms (COOP)

How to find the nature of the overlap between different groups of atoms (COOP)

Crystal Orbital Overlap Population (COOP) diagrams were first developed by Huckel. They are especially used in the area of extended solids. They are equivalent to a multiplication of the DOS spectrum and the overlap population (positive or negative) between two groups. In this way, the bond between two groups can be described as bonding or antibonding with respect to each of the molecular orbitals.

Exactly the same information as for creating a PDOS diagram is needed for creating a COOP diagram. That is, you need a log file which is the result of a single-point calculation containing the same keywords as described in "How to find the % contribution of a group to each molecular orbital". You also need a file Groups.txt describing the groups of interest in the molecule (see "How to find the % contribution of a group to each molecular orbital"). The rules for Groups.txt are not as strict in this case: no atom can be listed twice, but not every atom needs to be listed.

Choose COOP after picking Orbitals. The options for creating a COOP diagram are the same as for creating a DOS or PDOS diagram.

Click on the GaussSum logo to calculate the COOP. Information on the overlap is written to gausssum2.2/COOP_data.txt and gausssum2.2/COOP_spectrum.txt.

GaussSum-2.2.6.1/Docs/ch08s02.html0000664000175000017500000000625012117172552014760 0ustar noelnoel The circular dichroism spectrum

The circular dichroism spectrum

Open a log file that is the result of a TD-DFT calculation. For best results, a Gaussian TD-DFT calculation should include the following keyword "IOP(9/40=2)".

From the list of operations on the left, choose Electronic transitions.

Choose the start and end (in nm) of the convoluted spectrum, as well as the number of points you wish to have in the calculated spectrum. Sigma refers to the width of the band at 1/e height for the gaussian curves used to convolute the spectrum. The units for sigma are eV. (The equation used is Equation 8 from Stephens and Harada, Chirality, 2010, 22, 229-233. Delta in that equation is Sigma/2.)

After you have set the various parameters, click on the GaussSum logo to convolute the spectrum. The details are written to gausssum2.2/CDSpectrum.txt.

GaussSum-2.2.6.1/Docs/ch05.html0000664000175000017500000000616512117172552014435 0ustar noelnoel Chapter 5. How do I follow the progress of a geometry optimisation?

Chapter 5. How do I follow the progress of a geometry optimisation?

Using GaussSum open the file you want to examine. Usually this will be the output file of a job which is currently running.

Choose Monitor GeoOpt and click on the GaussSum logo to run the script.

Two graphs will be plotted. The first is of energy vs optimisation step. The second is the deviation from the targets vs optimisation step.

The deviation is found by considering the convergence criteria. Each of the current values is divided by the target values. The log is taken of any results greater than 1. The deviation is then calculated by summing the logs. Note that convergence is achieved when the progress value equals 0.

You may wish to leave out the initial points, so as to focus on the last few points. You can do this by entering a non-zero value into the box labeled "Leave out the first n points", and re-running the script.

GaussSum-2.2.6.1/Docs/ch01s03.html0000664000175000017500000001575312117172552014762 0ustar noelnoel Installing in Linux

Installing in Linux

Install Gnuplot

Check to see if you already have Gnuplot, by typing 'which gnuplot' in a shell window. If Gnuplot is installed, you need to make sure that it is version 4.0 or newer ('gnuplot --version').

If you need to install Gnuplot, rpms are available from rpmfind.net and gzipped tar files from SourceForge. If you are using Debian Linux, Gnuplot will be downloaded and installed if you issue the following command as root: 'apt-get install gnuplot'.

Install Python

Check to see if you already have Python, by typing 'which python' in a shell window.

If you have Python, type 'python'. The version number should be displayed. If this is less than 2.4, the scripts may not work with your currently installed Python version. (Press 'CTRL+D, ENTER' to exit.)

If you need to install Python, follow the appropriate instructions for your system at www.python.org. You should install the latest version of Python 2.7 (although Python 2.5 and 2.6 also work fine with GaussSum). If you are using Debian Linux, Python will be downloaded and installed if you issue the following command as root: 'apt-get install python python-tk'.

Install Numpy

Numpy is an extension to Python that allows efficient matrix manipulation. You should try to find a binary package for your system rather than compiling it yourself (check your package management system). If you are using Debian Linux, Numpy will be downloaded and installed if you issue the following command as root: 'apt-get install python-numpy python-numpy-ext'.

Install the Python Imaging Library (PIL)

The Python Imaging Library is a Python package that allows manipulation of images. GaussSum requires PIL to handle PNG images. You can get PIL 1.1.7 from here under "Python Imaging Library 1.1.7 Source Kit (all platforms)". This should be untarred into a folder in the usual way, using 'tar zxvf Imaging-1.1.7.tar.gz'. Next, go into the folder created and (as root) install the package as follows: 'python setup.py install'.

If you are using Debian Linux, the Python Imaging Library will be downloaded and installed if you issue the following command as root: 'apt-get install python-imaging python-imaging-tk'.

Download GaussSum

Download a gzipped tar of GaussSum here. This should be untarred into a folder in the usual way, using 'tar zxvf GaussSum-2.2.6.1.tar.gz'.

If you wish to be added to the mailing list for information on new versions and bug fixes, please send an email to gausssum-help@lists.sourceforge.net.

Start GaussSum

To run GaussSum, change directory to the GaussSum directory and type 'python GaussSum.py'. You can also pass a filename as an argument: for example, 'python GaussSum.py myoutputfile.out'.

GaussSum-2.2.6.1/Docs/ch04.html0000664000175000017500000000735312117172552014434 0ustar noelnoel Chapter 4. How do I follow the progress of an SCF convergence?

Chapter 4. How do I follow the progress of an SCF convergence?

For Gaussian to print SCF convergence information, it is necessary to specify additional print, by using #P in the route section.

Using GaussSum, open the file you want to examine. Usually this will be the output file of a job which is currently running.

Choose Monitor SCF and click on the GaussSum logo to run the script. A graph will be plotted of the progress of the SCF convergence versus step number. Details of the SCF cycles are written to the screen. Where there is information on several SCF convergence cycles in a log file (e.g. in the case of a geometry optimisation), GaussSum plots the one closest to the end of the file.

The progress of the SCF convergence is calculated by considering the convergence criteria. For example, for Gaussian, these criteria are the RMS density, MAX density and change in energy. Each of the current values is divided by the target values. The log is taken of any results greater than 1. The 'progress value' is then calculated by summing the logs. Note that convergence is achieved when the progress value equals 0.

You may wish to leave out the initial points, so as to focus on the last few points. You can do this by entering a non-zero value into the box labeled "Leave out the first n points", and re-running the script.

Note that, at the moment, this procedure does not work for SCF=QC (Gaussian).

GaussSum-2.2.6.1/GaussSum.py0000775000175000017500000000147312117172552014241 0ustar noelnoel#!/usr/bin/env python # -*- coding: cp1252 -*- # # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from Tkinter import * # GUI stuff from gausssum import gausssumgui if __name__=="__main__": root = Tk() root.title("GaussSum") app = gausssumgui.App(root,sys.argv) # Set up the app... mainloop() # ...and sit back GaussSum-2.2.6.1/GaussSum.ico0000664000175000017500000002267612117172552014370 0ustar noelnoel00 %(0` %! !!! !!! !!! !!! !!! !!! !!! !!! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!kikRUR 1RQZ!!km{{  1! !! 9Z]U)(9{189   )0RE{mmQ1uRQZ{{{sy{s}{s}{s}RYZ  49Mc]{U{UUaueJ}{yJIR!(1) ces{}{}sysususu{sy{s}{s}{sskqs  ,1iki]Y{]}}qaIs!(9)! 1km{sususususqsq{sy{s}{sy{ky{ky!UZ!i{]s]{emem]4Z9ARsqsususqsukq{kq{Zy{J1!!!!u{ek]ke{e{Y{U{]M$J JMR!R]kcm{RisBes1ek!akikqs!!!qsecYc]ke{e{Y{Q{Q{ BJMZJMR ! )()0189>KEJH RINKYH QG7OFGKNMP jJ PRTQYPtI aO[QULMRT}H SUaNLXY ]XaW\[yR Z[iX sU mW eZQ_UTMOS_[^^__ VLJl`Wdc}] icv` [hfpc V^j^^c``ig jd;_ ]{gnlf qnj d {mwo g `so ps i/\uq5h?q uo[twxpL}tt o xyzwh {nmspqw yz tvsu q ~}y }vs xv ~ ||~v|r1 tOM%m    LE<y٩S͚I2˗0Pxfnbg/~Dԏ$H;~@ALΜ]ժ pj]٪f"IGMYZgbߨ ޺T@q 8.>[~(gllHz$Z\MW 3L)_G>B7B >`2*qIˆne~3e0bWvj`W-WLï\a{_}L~0eQ3 x-Rp!R>5HE$n"G/j iMJu &!I\KAW+KzQ`abI]L%CFV`~UO~PueBbFh ٕV*Ȅ>GBiDbl 4AuJ+DmWaX*| u3\cON LyS]6PXvŧi$ꧥ^\dz rޢg2l6&k%Agi MAhn`pt[mz_/}pcUZQcl{mGV~inUںcbU^īW*`LAVnGM-M)gWIk  c"ݺGضd#) YŨcUbW̒l3}nJK[XN酹^)eyAM^SeIȕIim#i4,CQR}rv+w("E-J5% 0tsϣl%^TG4cAWS+i/<+T\^3@MVCВC/ɶZQH~xl=T˝ OOG+QX0}p:=wslBŌ"~?z|iKͺc/xVObcE"b/RT$ox׸~me0fK+'@/})Fᬗ=_h g3x I@SYQr سk4)^a!LVct^ Uͮ@"eLH (0*Y sKu7Y`r88Q⼄ 1#`(@ 2HDq/DFCf`d9E-+,YY֘%?@/&OH ] @@$H}#է. IM\UI# I!蔧7pU$7[X RzIR.1 fUb,V` Kk#(/CgN EWd*C0 (e}̤[ C0sv_xH-IєJArv PET/!, v{Cgj:#/I\*ǝLb}|k,;p]R @Lm[;ynNtd.[ǐ=pYȘ7q.r? ;w"Oҗ;c{vFӛ.u*<զs15mp,}K]wk@OƖ/|(Z9;P+һ.O@ ZP8jqw=˦70=o~S\ @ uV%gO{kOUIF1a|8icAb0q`5˻Z&@uxX E@X@+EPBPYhHb𬃀ؗ;4p;H ݈]ak5 꺖l),YZx0_Qsp kkۑp&)/ŠM{F}Xy@;VPPfLJY <<9b@Ib@}'{$P{4G;ՈG&= +C2;ET\[9p m q+@v._uUaya*@t70ɓjlXYlؚB,߻B Măŗ;żZI˕ 3~K[td[I!Bu ݂{;52yL^!HN`KɍP j@D`Dhfz]lp ;j}b+2P{$T9˽x Sq:lllH 2W(z'q |LBh =+ :$ [58pk0 @k[p` @l`zʊJهP0˵|$5{؈-$躴&m5O~8ܹfUKǡ:_1!DAP \N~0; Tm?gP5@gg?p8p[ɕ hp ޝЗP+}z˪K+@ =kG̗kHaߒS `];b+tl۷ULO,nl*O,@.^g|vpAPgpɚݫ p 4ȬIz} i޳|~Q[ z^~=̞d;`^81\Q 4U;A mcH,.WKI͖w`&*@`018^]e`O`Po0 p  а hVz͚jM 4kZZ~B Sl]HaPzd[tWIJ!vޡz^y_[qv/@*M.055&ꙮ1e0U<?P 0 ð ` PKzp*߬LZB`Wp 2V,BG 1 E э?ANCMZ@[<@cP B)@&~(^qo33`Oop ` À ߼;)߬H !Lhc<,QbD ,^hD27=B~lXl[W2e#J5mđƉN0Ç9:eMRM5*S\ŚUVXGVذ c6_k"9m*G++?OfpG> EUTtuş_+b#+@T˭q+$XA+&૯Tb0 aÇ ʐ,B YOZh 4|ga@idӌ#+а !dȁ"djy<4 (Fz«@JB.\l*&L1!R/`ܳ*O,Ӣ 4@r6@`.Rh U 9D,Ğ('Vbj`UwVr܂< c5+("H3d‘"~Ş$݈Jg{VWZ.KV:m7!;Wr!7ɓ3]>!>t&^Y(sݫ; MT"K*K/ 6417(ĎIJQ%VxmiUqāPb)  4b"`%VjP! fY)_9{)i榦zjpz"bˤҍC;mld /+ 29ϳXF`rXFk" 4|B ;DC{B8dXJb1'eaFP2#^FugׄЃX(X>J.R&oZAjv:/"{N:fmG߳ن_B/ɧA9Za!9C|A*,shEZ F`. qֽD]#P"8 A`cIzȔ$0 :s^tWnEk!^Гqχi˛UNEIre8v2?,N_$0܈;bbE)XыepƁi67 Ox Үt@B55(C 15d%኉ W}jPZ Mr5fUЕd|x5iMhb>WeaQD0EW9)1` \q܁whx+Djl?֮7P8zӞG#[p q!t蹏t[3d:&p $:zS? D+d8HIH,`ű/wIa1p Ȃfrcx D…q9pFX.<1A[ Ԑ# yh'Cx=7Vy#_ d5y,&Sb- D"QkCG}ar#yn!G3FRr 0PO h*M C3cԼ .hԣV#XD  89YU#  ?ܸgt;z#2)K pP׭g+> K,*(?+8,b bk.&ƝH 4AL2ДAa?O]Bs.ʦ!RLfBaFfFrye<4 ,$Aw T*@;~h3+eWLh ɖ5e+4^W'#(IwhBg ,H!04^ĨF5\ Aw[Z,*C"`-\q<+#7$_O#K)Iڒ'!({"hpwgHVB33TeДDġ20X $1Jc5[;Dh.H-AEB"`5 xM_V '8r 3&;5u}L)ɒ UwH&/Sn@ ,E@*C<ܩ);xE&v@C(D h3q8h2ʪ+DC󮷎3cՇ3:qY%uU(Y }e-r^S\T!8y?0PN1yų `ETUЈ'[e!XDO W=nTc< ,ЅHxJFB{ ݫ`s[eu &&F7vAͣra#X+O<94 T`5+>UBZ/} ԎX:-E( Z50u:PC5<=7xH:zKW1W` L0Q?>) V{%%/?&3 Q !06/j @h &cUd`r[ER@Ѓ7 ؂I\!2OX*'.zì+ID0\'IJR(PYAt/;) 9)ua5 @$H|r){*pZ,)ʩ8s&X 'x2^H<&rbPpZ7 C6w5H #O-}` C|H܇rKĆ ;)Q;XX ?zDv3B30paxK-R6 F94 ːϠ-q YZūCr :n<=䪟I+DJcG+WJP} c7B2S<8.KʱJ$18ZC1")j k3 a0rW *ܪ-hbCpkG[l$7o|LCO(2J(İ\JvtG2ʀ Kqʮ z`r\B(J,]ppHQE'XaT4KA9@s9^0qXFWцI#2@bDp:k$#0="PFXO>xQ7ͫgJTN,݌r,ͬ ?2q"*g@_BDP9p;Q{\sK?#3[@3:ƾV#mZCx˔ .-/- 4?rA &P\JءՊ? `M\D +g g o(x# -' a$-e ^L"2,{-mг8jREL7 lk 983؂l<=<0Þ.V/bSK?, @)hS88M ~p,y,r+pJd% t7*L00'`>paҋ%$@~8]V۵`պ}~Saͯ|pdMXuʇoͯrHh,Ё5a 0 mk8{-32z Si\ [g "U@ 6bIxFbԭ)G;U1Y `_ٙ%bMԝ`  %TBTBav/ ^ױj ah7*H(J[<0):*^/2 c\eUR=Mõ3Ȝ* B(:q+.,W>& V5]` U]C"2ɎQ:pd xQH  &جB(ca̔D[fC^$%^ (@Tƃ2b5Ն+e Y@ ۘ%k73a05CCp4XOhlFnoFBv'ϠG `)"+۫g~ ; 5|# -0%aXV9Q5jXYٰjEUOC?T.#fVf3CfsF镅 +f:N jtN">.B݆C!:HtJgX0,xy[vHdV a4bSXNΈXe^ n^bWE3PEO*'8Y:ƈb-=NͶ]nmCVW|xT86V3_\@=nobebe8[h ^XPR f ;OeBWU+,]H~o:R&w'~JN,їln z᩶  0Qf!U[hr芡QV6z둼ebH&sNh@qiQtEVfPcac|}^`wl%V ٟR7uih>QdD-Ӧr X^'`? aSZme#-#v 0lh jZdeHbR` Z!pte646]#.[,UO$lR S(rU{L)| ލnVȂrY7ᯎ/T6F:œƸcVU*nb0tPј;Ϙc GJC9[\ ).ezFz+PHߥ)YhruPOjn;[  &EӶ4CiiEb6$[\f#3_ewoI3h\wX0X،)oCP<^7&c$'֟}gnńHTOmHucmhZ JPHuHo;P۾ѓ 3m6[3] ZilOYՆwjå랰4)sJ3fL`) AL~NED9?BFR,o޼3aw e={K>#WHyUx`MFx 1F!Ta `WCCaOć1,c AQ fAG F+2˚|t 6ذBI͝zM:p{fՄ&L)0P@A$Q`b,)v PR00u 0*", <]sf`qxR +(,kζv$/Ă +,gvZou'CUVAэ,r 5|5@5Y=G'Ԍ~?, 0<4 [09?(~$AAce'|Fbk=]w,D "FT؍'cν8n썞h4(IL2B洴RJ%,mmBex2I\"to8QBnRFᔉ"U"#+H!& hD؛7 Ē\,p\$HBq|S4ɉRtsE\ r0*@. RY@1"D )L NXa<@p4dhQD3MgڱRXAl$=9 )4S |(.T7Wfqaog?~?E"@GaJfh-8i&"AgC-],ن'2X{/ƜnxJhDh5kL$lM5VD7dəH'6ɑ]ۙE4Z/e`kIJW6|"{(NrL& re%A x:@ C*L$v0Ҫ:f5af2`H-iSR}{iq'FΌk Ęq9OЁb#W> 0|^e @yM/Ӌbb^HJ0*־~̹o faBH*@$p8 `E'6Ā2\z ʧJ+'ViQL2M^h<@KfZ)ͬ I$ڗ% .~&[~]܍nhi$E&=ffXc՜xp,> PG%x`p̼L01O 4Zj VHzM }S[({J~ϛ[D>3kTT <x~lgx m^%-c/l`>w(~{do.LЄwݲH RC ,b PP Us@܎"ZD Ja2~4UL-5"ƽ=@z F=PCɍ BJ`|!B!Z%"Ǯa <@:6U2(^;(}cZ;k2&ۮTE= qT:!r2nؔ@pS2Ag@  =$T(p.9ԃi5+HnLF<PnB t%*v̂!`avA xD1]Y/hEjy߻85@/,ԅĀ8W@=Ab"XFsTB%O <`*Sł0y9|`2L+tQȘĈ\ M x . %(aI\cVaT>p»49\L@^,ƽr@^픍hO]FDT^)x Ҝ#j 赃;8 4B%(JuՀ"@9ܗTdFWA* +&K "//@O`0cS$Kpnҿ:}h@=]9.,utB 8_X `: ˽#iO"B/D@,C;4F[:2L5:5G@p\r@Q  BY %Ѐ $!&ЀFFd e@zi1h0__:p xjE[T X1džΆa̝fjLPR@PP6a1Z+0P.Cv`(B n@Ā*+6 `Fx. @|L*^' hb/0BMJhGxفp8lD#h<@r }HKUIjB%2i6Bʦ%N ,.’J<l`, k=6 A20l +C)P 8@_mmB^ |N*i@~]'TJU$MC((,9ZPB_h;M*aƽˆ+@%BZlh\ 1\*T-. Bn6ՔI0C,kBmVphBB(B)+L'Бa%Ѐ ̭(mBMM-p[ ' P9n@J.DAp\ [5 "@CŶli@=TB.pQ.CV,,k%!∮T"p1.;Bh,Bׂ9L΁BH! )W-DQTi"N* eT 0 bLzl%208c0/0ܒ e5@ l)L`) / /TôB)/ G׾9@\0. ԃO%XWi  EO1=(R4@Бu؁7eM& C ː 4s<9F+2C,er$j(a,AorB/(>Ó0lf2+w29 /nt ӒY Ε % 3O4O]3P@&ICA368(E DlCEg*G@S dKs+"cMV6m$wF`-@ =6Xt;c?i%p4z+.78zrw=GUhoh GoUtt^-V3vI Q`T@qCR_D \8+@6lFlJZz | /XBOFBԎ ;4e2HMc/pt6/¢ -c8L_<L'T'l D3@x$ <Gy@rt&غ2dw5{kk1|I_}Fĝq9hF%1\)?W6XfC,ڼk2`O!DgPEC@~5q)`zq/L5C C!=R씕ԖIqt$ ,(2Ş: rtMal (@fR Ń | TB- NIdJw-/xDw |{/;ɘ-M+MQ d+|UfP!D_3` jJ 7J#cVJXOPE8,lzI_ "āFby#͒}>xidل^@^ J|@ kdCnGr}yċ6`"Wp#-7@5+upюKJ:cq4@)P*)%^ġE|B@ws̩&<0@*\yEl'j*a+ayE:z^Fqz)J`Qz3GhY&\Td|V' jH@HtA!&``1STĆxj!`&1kn2$& cI h튣bt.Ī5+kR"k+p=(b j,h(8Yb Ae1:V٘'`h&a~8T"0FEMvSGeoB!.t-8:s j@Q r` fJq;e}_MfwTT]$)3ʓ!T^[IvģA@PB!Vd6UY 9Ӷ$'lE n]EUS{B#؏UL &0'"@91HU2,_z+"5MQ1Εs!|M/(Z ab%h;aPUUYהE)aB+F'0d%EH!RtF|zmg+Rվ*0@ ʊjC>q)F1$q#MnlFUCy@*Ir["?,L8! H91 qca S,ʾF'h*hī2` dnA(6Щ BeXШ 8beM鳤w<D%/f:L'LO,ɸ$(Z|`$RA Ԁ/1o`k``Fd5ޠ@xJ(Z@0,vͺ&A ,BF)JItڄBe NοT!ܸG'/Mlz*0e& Y p'` @E Xl ` GİHvb -x@L ``kv#̆P(kʨ,a6VƉ!wȂa epǞl^2PLή&g` Ԡx21AQF(3T|pb*b#'qٱި6*0,ωewrb<:&QlCOx@ ! F{S&}PB#J)hk JJNif& 5Z^36eSPcbzM(Lcl7E8b*+x`KxhwʀFf6Hʹ9z&@`zx#*A*b'H)Q'#m(n;uB*JIf!B@=!{/A)8 $kN2% =jc@Q5 4Cs ` ` n\OUP/aP'.P8ɑ_BB90XpWS9##<,:XHUsH,JPXc'پIf`@A*S,igY-R<-m bЈ5*vʮ# jr OA] D F^]ȗ8E:VdBCL*bL@Fvp9*l@dFC#۾(;HcB'J&@Gd(x,xeݳ "t( >.rD%k2 k2v iVj #P6ޯPVj37 A84ʀQ): l*Ev4lS.FQ i:tP8"ɜhfbah@k*poasZNU*6S=Pw+sbBf1O##(!cJ܁;[!sˈ:JIrIwu(ۊVOѕV ֜v"LXXX*h<+tpZvz[zIx ɖ٩6JxBJ/<'zA{PɑG鈛Չ )M%sdii nW㹶\jU0'ȼK(&i:AdKvOmM9bcڦtt޺:tgzt[(:>fޗ󝼅 ba$<"8#JUtWwV Y &}cX3^p (0+*(ȱ]1K\ }΀ʷ0'(*٘TZ](Dn,&:&C{)"baʫf1hrё%tjHzBu`͜!oBc'ru"nZ}\t2+Z>ûh@ޠЈ" ^"0>=9c<|8|z=8L3o:>)hRĒ1bɖUM3U[L0^pjSByc0o4-I2O@ q`E.xЖ@%ֈZE7ܹtڍ޽ w 6l`Nb8Q%Ɠ*>b8|pEO\#thI*<.^21x=>ޜa{<dՇ`=KX"$>70e 2b*B z]ZSL&UYCOhQ?P!hmV[muW"_{_baƂjTT0ejQ0m11QPkVE3@C6E#` ]i0 EQ㤊% )# 5:R @d؂`$xH^ xx+_@Ozۢ7w\u0L0 d8) )9NFX㙧UŤ"!pDlZHkP*BSff24:Ab4&Jx WԔA"$45E DSIѵ($XM (W AäT2zv),P:({J$ SvGP;b dRi*zSk|Yn~$Fg%Dj (W!A L^/,ZϠѳHN p VIhe#H2 Ul"G2X@%#D-:dinhJ[ҷ@%X@5y0p=2ses =}Nͯ*8FX<)m{F)MSk֧W6$KK*;˰_^#i"N|#I+Th$FarQ$gCJD@)NZ\‚CBjA II0 "5JP/T j@0X[ EȀL##9&G&Ek;ܰ>Ĩ 4WtkSYRyk ^Vdh 6iga  7@-TA ^ M5QN!P:OXqBWdꪅKd`.-h!CAi\c y1RO"XַFra/K[y }hcΦ֤-3h Е*C Ӷ*,3䢌o4\B* mÓrLz[}zF|ÂB*J+ κĮ%u[>Ԩ&s|hB Z"ǜCt >‡C t8;)\NL5w]7D@TYA@ p&'Œ1j >jKa;ѭOkߨ"MWBOUݻA9|Z6mUW#Wr%nq{gh Bʢ=gi7ko:9 }ba?9myBR+Ԅ,$ivi`wr*Gwh>rfz`1 MLT& 8Y?l8ߨeOb-fuAn[Hn q{T!?gv5WY|AQ 0J8ah"$JvG 71v0r`+CP1wb[\92;F0EPy1c`DODJ$MXz63rp@g[0!I?pqml#[WujXXPqXdK3p``n:Z9)֏'J@:ːP! P( ɖiiK#1$I7FEQ3 k`FPD)Bkm! V`Dʹɥ1Tv<8 ɓs?`rjZ(suvH`U#C%h\X[\vth%8@0 7qaY{ BIsOR5T,:B d´jp(3*P0MT[JdjU 7П@8PY44,ztpz!)Ȕ?9.6n S7Kq:M;hGĨI;eJ-jī}%TCq3~" 4Z1]!EP[Cy`DԫiBfP3[T ;/[p;?0z,Heu|X.s5Kw\P )v} &h2QRvI QA{ţBU%S"z`)=,LAX:fpDf`PИkRAFm]^5і  @_!;wWCCr)ݳܱ=S|{V")"Iؑb,Q{P2Qv~IR (6iůX98ᎌ` gOuܩTӪЪ`!v:(U*U^b*_P~J a<RnAGX@|4 2s@Z!Y 51TՇ8p>hbAg[g1ZGnfLc1Nf(α}H rLAM~ޥ~/ 6 V̺:0(( j~jAI.Ic&dU TFj@݈*P;ːH"ݸ&k/0^ F~nGIPwpaM LW0WnюCJ7.3p/:( .4KQخcac6jIjy@kÅ[f9~H9DUT No KN?嗱 qhSz4fRvD PiQD8(8Al}"bCw1aQj׎j0sr؝tPX0k: H@ATU pօl4/oNX2 O R0v ͛J&Md W,^TTV!y2mk;w.eΤY_;wtj&U,UT*3eΜSL'P92UDB 4jЌSl+h͘ !B yK _0pĄ 6¿ `1oYgСE&]4TfHwӄa3OCQQh+\cUJxk4h:UkivU)P -2P0HhkV"5+<,+ (BpB,1 $0;4K4Q4^SqM*7n2ѱR pdH3G)RdN:O&a߆+!0B+;B- :Dk@+ l+|B ӯcD4NTtQScQHi ;l<(@y JzuzPe [{Pg01I>_w? q#V%cl,Iij$H mXʰnM1B@!cAa P0Ct68n1,`0TC F!Q ^/%kt;m,i''YN QCb #O&ie$C86ZB&! {B(F1@ 5ut"HhBi_V&{XMj$+@@ΛV;h5ʙ&4} N"k g,yы:ϰ0 `UHPA>A 3&FbzPFTE"'4'7GITJ'NAhj紈3#@!pBef'pXRBc)Rjj `Uj BN m辰HoY%-)a˰rZFlh^]=tZ,Q.-z`@9viHKFBM(g(d沥qfY]iW xC2\K]3'U,V1OyX\VWY ; J\( Y's {"v%T&DŜ2wˌw4W5f;[7{U}?ڎ.a)IAU,0o 7Bu2,AF沁 b^B/>83LfVL3lf[8k6g>;  }hB&o%%AcÀF/VdMG_  V̠8B#Ne`fP,! y 35/">| A;Gzz!ku@t }c@MtZ%=鑬¿)&ϓ(TЁKG=\7@!^6vt<w0l@1=lPf PhY~}&f?orxЃ%0O@ےJʋI*DW:wjj +Ueu1A odؔw#@ȥ)Yri]2yk.6 ϗd c淚 M4Nj4_pBQG9ʭք`3" y KX8'pB wov& kv3Ꟶw=6 mx xe)j7}[Zt7Є(4q _ ף*Xۻ=Sܳ8 >S/L@ӬQa2l>T9q>>1X s<˻47&s;zT7>I$M2j ~#:R$p,7D?}DVcJl5sDȂK%; 1;.̸X 4Q8C6@W͊ ;j>;;L9B6"?n>8Rc(D+:QDp#.*K!(C*KDM7;D=D*QH`8+-dV0C31<HCW L34>5DLCEHC bFjeTƒ$5CF7oBG,*{r m%CDsI*Q\1GȀw?H  ,\EH.,hY$&![t3| LTL_<>FH`H\ACkgCPK$̲ÂB|rř =;rGɞE}KG.;ٛ=jXJDM}􃨄*r!8E0ʹ[L,WHW(N5E>S@u>LL(W\,T-nY (LUrҹEOTBwRD4U\Vl8FXVDMŸŨ8ɕY7Lp>\\={Dd6ά‹/R%L %^C3[v0@$aE4US%X%U1=a}M-8͊xb\˵D6[]ށU^(p=F1 @vxG,MP$.e1M_jV37% 0e0Y,bYS>-⢵bHY_`W[uxumZJW`Jmݔ{ն}o;BLDFdX&E&8^J.Ʋ^ĿOX b!GSdbU>6bŒb:Xev/⛵_>Ӥbn֭[YZ[Z(ZvU]`{S6dn1&riEF^ gxBMBzTꢂ]h6U--xhbY\-٠Wh g鎆vcAc5S]TxGm;o f,^i5sV^4Lv&a*MG`[1p2 gҬh(v_MTF }k 0Xbe>vWc.fg%fT6;f5vWivWfM+Cʶl^ igr1Ef^mmm$~.9 ?p`kmYpbVkb_8^n[Y8>i`>g>~fl=ބ6l7. ? U->UorqVgC$j؅N[[aNX7M傆3'wFsfsVfhGbfnkWq[ q֍?3[<&X~1j1No!opj#W4?{y}ZOLն b,r=6mHx(r m3Gsboh/Vkgfi@;ihpkG?/;xEt+rtɶtSm>t{{{n(]oUV|=cl ͸['F(kug2t_mham5m8g;ixgxn>5fYvf񞯅wl&4iC ۳g mZ0_;f՗ VXTdE8@mڶn+wۺjm7n{ŋ7-†޽)4hڮNJ.cy3jXq4i3L1Ķt۶ ]tFr1[TZl^6E6[TtӨ~WYVe% Vدlv]u/w+_={<c 5] 2XhVE <jK:/֒oo$Ťl:r5THWP}#MVBYTw",XW-_\) |}u}k-c4e} 5_;|h \ZCkuF':Xn$SoxS7B54X7NLHUX3@]ﵗdJ vה~Xgc0&`J_Lf G#S'3<[>Vg96t8u 6,uIUݹB74PuVUzL:MV:{Xmik 36_NQ?nƯ- ḅRMRqvCN H:t9~RA'T7/V:b%HT:ؾ~A# ecmЮP ]w= D=ُm醲4-cOk(6Ґ#3:136|sA[wiTXɻ:5eUaڳa]+vCP>wn\lu<ʿ'(m<86X>RMtUE/Ep]NuWN P.  cE6<ʣGn,(Yz9t׋6bry/ ;A#Q;猒>$iU?%u]61PxS$AA2,07 ew c7>ɅCq!Fr :[;A.is+t|=a}20BҪD4fQ+I6l" mcx_2g#' *Q8q!=rC!Zƌv$ S2JXB|`t$%Hʐf8*GncHFҳiS)BN,KgN;}(OGNi8Ŏ|p ^ efp+RӋ Bթ>Z꺪G ("E+ia I`d*ST 3̞e7"CQOr0qPAFt}29˳<$Җ) ;GaussSum-2.2.6.1/mesh2.gif0000664000175000017500000001336312117172552013623 0ustar noelnoelGIF89aZC!!!!!!!!!!!!!)11))))!1!1)!!)!+#6#9- 91991!!!)!!1!!11!9)!)!))))1))9))91)))11)1111911919B!B)B1B1B9B9BBJ1J1J9JBJBR)W3ZBe<JJRJZJkJJJRRZRcRkRRRZZcZkZcckckkB1*A;5?1tbE&8L$홲cqrġ+Ƭ>1F|%玏5{FO`UMrV8XbbeL22|ⶍ;13fck?z2Lc `dc0c꤉fe1`r 3X $@` 5Cu cNt6@̐'&}Mט$Ly &>t|6qCP0`3!|LL2f 䐌7p7Uc(S'zq0HS7@L69w Ca̐]ǠMyL5c04cM'2$rt p )`a%Ѩ 9a@ :!Kz#,f1E}XB= qU;ġ!3 `SMV! -ҩQ $d TĢr uc<ڊ@ &y+DtCD`TCtv9&,TAUJO_iH!!@Hݰ^OWd`8C4c83 0͋ICwPjN9URAOρɴhJ Y  H縇=t[a+GXpy{& a pN #^ܪV%a4G*I-A fMk\MA^@$5BHny{bGrc+1hBSD$`8A `"%ɐxZd@! Eiњ/dxK0 4l! $,QM0(ʣ6,ya]]zHʣP<<`c' 6d SDoz4.ha C]H`?QCr yB6BL`Q= LcVB"bj!N'm ]0D$C kD$@سAd}$`m i$H.1'?Ϯ7KKȂh4׼NC$FA\E$ܬVC;X\zЇ> O4@L!phqz<Êx7U8- qVoG"_Jq 6ObD\נHg~{z'? tdJ b0#4W5% ЂIq U|3,ʍ tݜ4UT[ @4jS<"Qguۮ qud#LM#VIm4EMnO\*_(6)8H5z#3) p0q~#ߵx@" z' -:e/}Tw-n7@QPB xp@[ X$_:K+n߼% 4 (>CTQԣ dj0 wr_ji  GSP}cq g@ 6s7p fe*|"q'x*" fi(nbg p},0\wG%`~uf`k6@ElW`VTjT fncZ&r `j'vZ`^3(}FECwx6\ H7d  ii ^StZY0 gŇ|f憼 vTje^ifYPUs@g t 𐅍 heWI`fbpV!V)ƃ>xuxrbb׀'`U#ۀ 2~p] ` &n0Duf[XN`DuYVr]i`bf"`az` Y3 :` vq7Vjjfhb_`N(Rjب'mFvq  Ɛ ptPD4,:( T`Rfa&Nj jqE` N( mPj Jv tf {! yIS4fUf+RUu&pN^f*mƏe& O @0DyWD `"qaai[-fb5 7nZTn ]jT|jn:ɍ0& ϴYi7ℛeeV_^ɏqvrnEW%wtx^H`X_k ~)DQD"GIe yVY m`V pnj؈(ckj pԑ &ĊjovYVEg0 ʧ PFy&_ 0ٚY-zMZ""&u8iUy, `ujnjZ" pVwRJ ܆^Vv_:٣8yG &n6hpXvؠ ÂYqeq%N&wV=ʍf kj g '&n&nXP[ pO)p 0WmqgkH x5TE0]u&Vy_g[k XX L Ib]| $6Z!j|Pz prh4`kL2~yaP$N2ZEJ rjuuj [Gr8 u + "`,p#* Yvqgbu櫿j Cd\0g<Py@ h ^ɈVZ]kZǍ`Zuf ]F[yw8 2\3A#~X,Q{ewPR`1[miXT|*ٳ@l.fvr@[ H`,})j*-D`;fe^' rP0jfjj'gl u5tt;oX ЕTR&;Z;ˍ鳟Evq\ P뿬2 ְ/u\YL,f5 ` odžXI>+ g;;hYrGK 0Sу}~ U,i*J(BOe :0>k{HNY'xJ!;Ucsx`*Y`GA5`Pƌȟ ?˾Hܻ&`'TDL@ 0qǀK-" f\ ]ԝԁ O΢P EZ}J31$0}Jjm*T`P׸ PѬ׫ LPO0XϧdJА `2`X6a}P P  ؁mN0-S aM=& /Н p @ ؽ P = =MN" Ӥ`ߑQ:9fِ P~ Ͱ p `.} ,x=y2,P -ٰ 3tQ p 9@GGJ0 `0(.` p:];c>5ܲ- !֠ ` h0۵ mFK@ АRN m-cN:@&ݡ ` ` 0 wm }NP`8 QT96*a a ~7M%eLPPP`7 P˾}0zO;GaussSum-2.2.6.1/gausssum/0000775000175000017500000000000012117172552013757 5ustar noelnoelGaussSum-2.2.6.1/gausssum/preferencesbox.py0000664000175000017500000002660112117172552017350 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from Tkinter import * # GUI stuff import tkMessageBox # For the About Dialog import tkFileDialog # For the Open File and Save File import webbrowser import tkSimpleDialog import traceback import copy # For deepcopy...until I find a better way of doing this import ConfigParser # For writing the settings to an .ini file from gausssum.plot import DisplayPlot from gausssum.gnupy import Gnuplot import os import sys import string class PreferencesPopupBox(tkSimpleDialog.Dialog): def __init__(self, parent, settings, title = None): # Override (just to set the geometry!) Toplevel.__init__(self, parent) self.transient(parent) self.settings=settings # Note that changes to self.settings will affect the global self.settings thru 'settings' self.oldsettings=settings.copy() # Remember the current settings if title: self.title(title) self.parent = parent self.result = None body = Frame(self) self.initial_focus = self.body(body) body.pack(padx=5, pady=5) self.buttonbox() if not self.initial_focus: self.initial_focus = self self.protocol("WM_DELETE_WINDOW", self.cancel) self.initial_focus.focus_set() self.wait_window(self) def body(self,master): # Override # The content of the settings dialog box # Creation of the main sections self.resizable(False,False) self.frame1=Frame(master,relief=SUNKEN,borderwidth=2) self.frame1.pack() Label(self.frame1,text="Global Settings").pack() self.frame2=Frame(self.frame1) self.frame2.pack() Label(self.frame1,text="").pack() Label(self.frame1,text="Search file").pack() self.frame3=Frame(self.frame1) self.frame3.pack() Label(self.frame1,text="").pack() Label(self.frame1,text="Frequencies").pack() self.frame4=Frame(self.frame1) self.frame4.pack() Label(self.frame1,text="").pack() Label(self.frame1,text="Orbitals").pack() self.frame5=Frame(self.frame1) self.frame5.pack() Label(self.frame1,text="").pack() Label(self.frame1,text="Electronic transitions").pack() self.frame6=Frame(self.frame1) self.frame6.pack() Label(self.frame1,text="").pack() # The Global Settings section self.frame2a=Frame(self.frame2) self.frame2a.pack() self.frame2b=Frame(self.frame2) self.frame2b.pack() Label(self.frame2b,text="Gnuplot:").grid(row=0,column=0) self.gnuplot=Entry(self.frame2b,width=35) self.gnuplot.grid(row=0,column=1) self.gnuplot.delete(0,END) self.gnuplot.insert(0,self.settings['global settings.gnuplot']) Button(self.frame2b,text="Test",command=self.testgnuplot).grid(row=0,column=2,padx=5) # The Find.py section Label(self.frame3,text="Search for:").grid(row=0,column=0) self.find=[None]*4 self.find[0]=Entry(self.frame3,width=15) self.find[1]=Entry(self.frame3,width=15) self.find[2]=Entry(self.frame3,width=15) self.find[3]=Entry(self.frame3,width=15) self.find[0].grid(row=0,column=1) self.find[1].grid(row=1,column=1) self.find[2].grid(row=0,column=2) self.find[3].grid(row=1,column=2) for i in range(4): self.find[i].delete(0,END) self.find[i].insert(0,self.settings[ 'find.text%d'%(i+1) ]) # The IR_Raman.py section self.frame4a = Frame(self.frame4) self.frame4a.pack() self.irraman=[None]*6 Label(self.frame4a,text="Start:").grid(row=0,column=0) self.irraman[0]=Entry(self.frame4a,width=5) self.irraman[0].grid(row=0,column=1) Label(self.frame4a,text="End:").grid(row=0,column=2) self.irraman[1]=Entry(self.frame4a,width=5) self.irraman[1].grid(row=0,column=3) Label(self.frame4a,text="Num pts:").grid(row=0,column=4) self.irraman[2]=Entry(self.frame4a,width=5) self.irraman[2].grid(row=0,column=5) Label(self.frame4a,text="FWHM:").grid(row=0,column=6) self.irraman[3]=Entry(self.frame4a,width=5) self.irraman[3].grid(row=0,column=7) self.frame4b = Frame(self.frame4) self.frame4b.pack() Label(self.frame4b,text="Exc. wavelength:").grid(row=0,column=0) self.irraman[4]=Entry(self.frame4b,width=5) self.irraman[4].grid(row=0,column=1) Label(self.frame4b,text="Temp:").grid(row=0,column=2) self.irraman[5]=Entry(self.frame4b,width=6) self.irraman[5].grid(row=0,column=3) a=['start','end','numpoints','fwhm','excitation','temperature'] for i in range(6): self.irraman[i].delete(0,END) self.irraman[i].insert(0,self.settings[ 'ir_raman.%s'%a[i] ]) # The MO.py section self.mo=[None]*3 Label(self.frame5,text="Start:").grid(row=0,column=0) self.mo[0]=Entry(self.frame5,width=5) self.mo[0].grid(row=0,column=1) Label(self.frame5,text="End:").grid(row=0,column=2) self.mo[1]=Entry(self.frame5,width=5) self.mo[1].grid(row=0,column=3) Label(self.frame5,text="FWHM").grid(row=0,column=4) self.mo[2]=Entry(self.frame5,width=5) self.mo[2].grid(row=0,column=5) a=['start','end','fwhm'] for i in range(3): self.mo[i].delete(0,END) self.mo[i].insert(0,self.settings['mo.%s'%(a[i])]) # UVVis.py section self.uvvis=[None]*5 Label(self.frame6,text="Start:").grid(row=0,column=0) self.uvvis[0]=Entry(self.frame6,width=5) self.uvvis[0].grid(row=0,column=1) Label(self.frame6,text="End:").grid(row=0,column=2) self.uvvis[1]=Entry(self.frame6,width=5) self.uvvis[1].grid(row=0,column=3) Label(self.frame6,text="Num pts:").grid(row=0,column=4) self.uvvis[2]=Entry(self.frame6,width=5) self.uvvis[2].grid(row=0,column=5) Label(self.frame6,text="FWHM:").grid(row=0,column=6) self.uvvis[3]=Entry(self.frame6,width=5) self.uvvis[3].grid(row=0,column=7) Label(self.frame6,text="sigma:").grid(row=0,column=8) self.uvvis[4]=Entry(self.frame6,width=5) self.uvvis[4].grid(row=0,column=9) a=['start','end','numpoints','fwhm','sigma'] for i in range(5): self.uvvis[i].delete(0,END) self.uvvis[i].insert(0,self.settings['uvvis.%s'%(a[i])]) x=(652-450)/2+self.parent.winfo_rootx() y=(480-410)/2+self.parent.winfo_rooty() self.geometry("450x460+"+str(x)+"+"+str(y)) # Place it in the centre of the root window def buttonbox(self): # Override box = Frame(self) cancel=Button(box,text="Cancel",width=10,command=self.cancel,default=ACTIVE) cancel.pack(side=LEFT,padx=5,pady=5) self.save = Button(box, text="Save", width=10, command=self.ok, default=ACTIVE) self.save.pack(side=LEFT, padx=5, pady=5) self.bind("",self.ok) self.bind("",self.cancel) box.pack() def checkcubman(self, event=None): # Checks for existence of cubman at specificed location if not os.path.isfile(self.cubman.get()): tkMessageBox.showerror(title="No such file", message=''' There isn't any file with this name. Make sure you include the full path, filename and extension (if any). For example (in Windows): C:\\Program Files\\Gaussian\\cubman.exe''' ) def checkformchk(self, event=None): # Checks for existence of formchk at specificed location if not os.path.isfile(self.formchk.get()): tkMessageBox.showerror(title="No such file", message=''' There isn't any file with this name. Make sure you include the full path, filename and extension (if any). For example (in Windows): C:\\Program Files\\Gaussian\\formchk.exe''' ) def checkcubegen(self, event=None): # Checks for existence of formchk at specificed location if not os.path.isfile(self.cubegen.get()): tkMessageBox.showerror(title="No such file", message=''' There isn't any file with this name. Make sure you include the full path, filename and extension (if any). For example (in Windows): C:\\Program Files\\Gaussian\\cubegen.exe''' ) def testgnuplot(self, event=None): # Tests Gnuplot!! if os.path.isfile(self.gnuplot.get()): g = Gnuplot(self.gnuplot.get()) g.commands("set isosample 50") g.commands("set hidden3d") g.commands("unset border") g.commands("unset xtics") g.commands("unset ytics") g.commands("unset ztics") g.commands("set xrange [-1.5:1.5]") g.commands("set yrange [-1.5:1.5]") g.commands("set zrange [0:1]") g.commands("set view 50,50,,1.4") g.function3d("exp(-x*x-y*y)","notitle") DisplayPlot(self.parent,g,"You should see the GaussSum logo below...drawn by Gnuplot") else: tkMessageBox.showerror(title="No such file", message=''' There isn't any file with this name. Make sure you include the full path, filename and extension (if any). For example (in Windows): C:\\Program Files\\Gnuplot\\bin\\Wgnuplot.exe''' ) def ok(self, event=None): # Override # Remembers the settings # If they are different from before, they will be saved by 'preferences()' self.settings['global settings.gnuplot']=self.gnuplot.get() a=['start','end','numpoints','fwhm','excitation','temperature'] for i in range(6): self.settings['ir_raman.%s'%(a[i])]=self.irraman[i].get() a=['start','end','numpoints','fwhm'] for i in range(4): self.settings['find.text%d'%(i+1)]=self.find[i].get() self.settings['uvvis.%s'%(a[i])]=self.uvvis[i].get() self.settings['uvvis.sigma']=self.uvvis[4].get() a=['start','end','fwhm'] for i in range(3): self.settings['mo.%s'%(a[i])]=self.mo[i].get() if not self.validate(): self.initial_focus.focus_set() # put focus back return self.withdraw() self.update_idletasks() self.apply() self.cancel() GaussSum-2.2.6.1/gausssum/utils.py0000664000175000017500000003214212117172552015473 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from Tkinter import * # GUI stuff import tkMessageBox # For the About Dialog import tkFileDialog # For the Open File and Save File import webbrowser import tkSimpleDialog import traceback import copy # For deepcopy...until I find a better way of doing this import ConfigParser # For writing the settings to an .ini file from gausssum.cclib.parser.utils import PeriodicTable # from cclib.parser.utils import PeriodicTable import numpy import os import sys import math import string # This class allows Find.py, etc. to write directly to the 'console screen' # in GaussSum.py. # It also allows Find.py, etc. to write to stdout when testing. class Redirect: def __init__(self,write_function,root,other): self.outputfn=write_function self.args=other self.root=root def write(self,text): if self.args=="None": self.outputfn(text) else: self.outputfn(self.args[0],text) self.root.update() # so it shows it immediately self.args[1].see(END) # scroll if necessary to see last text inserted def flush(self): pass def readinconfigfile(inifile): # Taken from the Python Cookbook (O'Reilly): # reads in configuration information from a # Windows-style .ini file, and returns a # dictionary of settings. # # Uses the Python module ConfigParser for the complicated stuff. cp=ConfigParser.ConfigParser() cp.read(inifile) config={} for sec in cp.sections(): name=string.lower(sec) for opt in cp.options(sec): config[name+"."+string.lower(opt)]=string.strip(cp.get(sec,opt)) return config def writeoutconfigfile(config,inifile): # The companion to readinconfigile # Written by me! cp=ConfigParser.ConfigParser() for key,value in config.items(): sec=key.split('.')[0] opt=key.split('.')[1] if not cp.has_section(sec): cp.add_section(sec) cp.set(sec,opt,value) out=open(inifile,"w") cp.write(out) out.close() class NMRstandards(object): def __init__(self,location): """ Read in the nmr standards file (if it exists) Returns a list of dictionaries: nmrdata=[dict_1,dict_2,dict_3...] dict_n=['theory':'B3LYP/6-31G(d)','name':'TMS','C':12.23,'H':123] """ self.location = location self.nmrdata = [] # Check for nmr standards file in location described in settings try: readin = open(self.location,"r") except IOError: # File does not exist - i.e. no settings yet pass else: for line in readin: if not line.lstrip().startswith("#"): # Ignore comments temp=line.split("\t") adict={} adict['theory']=temp[0] adict['name']=temp[1] for i in range(2,len(temp),2): # Read in the calculated shifts adict[temp[i]]=float(temp[i+1]) self.nmrdata.append(adict) readin.close() def __getitem__(self,index): """Shortcut to access the data directly.""" return self.nmrdata[index] def save(self): """Write the NMR standards to disk.""" outputfile = open(self.location,"w") lines = [] for adict in self.nmrdata: output = [adict['theory'],adict['name']] for k,v in adict.iteritems(): if k not in ["theory","name"]: output.append(k) output.append(str(v)) lines.append("\t".join(output)) outputfile.write("\n".join(lines)) outputfile.close() class ErrorCatcher: def __init__(self): self.log="" self.longlog="" def write(self,text): self.log=self.log+text def clear(self): self.longlog=self.longlog+self.log self.log="" def percent(number): return str(int(round(number*100))) # round leaves .0 at the end of a number def levelname(i,HOMO): if iHOMO+1: level='L+'+str(i-HOMO-1) elif i==HOMO+1: level="LUMO" else: level="HOMO" return level def lorentzian(x,peak,height,width): """The lorentzian curve. f(x) = a/(1+a) where a is FWHM**2/4 """ a = width**2./4. return float(height)*a/( (peak-x)**2 + a ) class Spectrum(object): """Convolutes and stores spectrum data. Usage: Spectrum(start,end,numpts,peaks,width,formula) where peaks is [(pos,height),...] formula is a function such as gaussianpeak or delta >>> t = Spectrum(0,50,11,[[(10,1),(30,0.9),(35,1)]],5,delta) >>> t.spectrum array([[ 0. ], [ 1. ], [ 1. ], [ 1. ], [ 0. ], [ 0.89999998], [ 1.89999998], [ 1.89999998], [ 1. ], [ 0. ], [ 0. ]],'d') """ def __init__(self,start,end,numpts,peaks,width,formula): self.start = start self.end = end self.numpts = numpts self.peaks = peaks self.width = width self.formula = formula # len(peaks) is the number of spectra in this object self.spectrum = numpy.zeros( (numpts,len(peaks)),"d") self.xvalues = numpy.arange(numpts)*float(end-start)/(numpts-1) + start for i in range(numpts): x = self.xvalues[i] for spectrumno in range(len(peaks)): for (pos,height) in peaks[spectrumno]: self.spectrum[i,spectrumno] = self.spectrum[i,spectrumno] + formula(x,pos,height,width) class GaussianSpectrum(object): """An optimised version of Spectrum for convoluting gaussian curves. Usage: GaussianSpectrum(start,end,numpts,peaks,width) where peaks -- ( [List of peaks],[ [list of heights],[list of heights],..] ) """ def __init__(self,start,end,numpts,peaks,width): self.start = start self.end = end self.numpts = numpts self.peaks = peaks[0] self.heights = peaks[1] self.width = width # make heights a local variable as it's accessed in the inner loop heights = self.heights # len(heights) is the number of spectra in this object data = [] self.xvalues = numpy.arange(self.numpts)*float(self.end-self.start)/(self.numpts-1) + self.start A = -2.7726/self.width**2 for x in self.xvalues: tot = [0]*len(self.heights) # The total for each spectrum for this x value for peakno in range(len(self.peaks)): # For each peak pos = self.peaks[peakno] exponent = math.exp(A*(pos-x)**2) for spectrumno in range(len(heights)): tot[spectrumno] += heights[spectrumno][peakno]*exponent data.append(tot) self.spectrum = numpy.swapaxes(numpy.array(data),0,1) class Groups(object): """Stores the groups to be used for a DOS or COOP calculation Essentially, the groups are a partitioning of the orbitals among atoms or a group of atoms. Usage: Groups(filename, atomnos, aonames, atombasis) where atomnos is a list of the atomic numbers of the atoms aonames is a list of the 'names' of each atomic orbital atombasis is a list for each atom of the indices of the basis fns on that atom Attributes: groups -- a dictionary of the partition of the orbitals among groups """ def __init__(self, filename, atomnos, aonames, atombasis): self.atomnos = atomnos self.aonames = aonames self.atombasis = atombasis self._makeatomnames() if not self.aonames: self._makeaonames() self._readfile(filename) self._setup() def _readfile(self,filename): """Read group info from a file. File format: First line must be one of "orbitals","atoms","allorbitals","allatoms". The remainder of the file is ignored in the case of allatoms/allorbitals. Otherwise a series of groups must be described with a name by itself on one line and a list of group members on the following line. As an example: atoms Phenyl ring 1,4-6,8 The rest 2,3,7 """ inputfile = open(filename,"r") grouptype = inputfile.next().strip() while not grouptype: # Ignore blank lines grouptype = inputfile.next().strip() groups = {} for line in inputfile: if not line.strip(): continue # Ignore blank lines groupname = line.strip() atoms = [] line = inputfile.next() parts = line.split(",") for x in parts: temp = x.split("-") if len(temp)==1: atoms.append(int(temp[0])) else: atoms.extend(range(int(temp[0]),int(temp[1])+1)) groups[groupname] = atoms inputfile.close() self.filegroups = groups self.grouptype = grouptype def _makeatomnames(self): """Create unique names for the atoms""" pt = PeriodicTable() d = {} names = [] for atomno in self.atomnos: if d.has_key(atomno): d[atomno] += 1 else: d[atomno] = 1 names.append(pt.element[atomno] + str(d[atomno])) self.atomnames = names def _makeaonames(self): """Create unique names for the atomic basis if needed""" d = {} for atomname, ab in zip(self.atomnames, self.atombasis): names.extend([atomname + "_" + x for x in range(len(ab))]) self.aonames = names def __str__(self): """Return a string representation of this object.""" ans = [] for k,v in self.groups.iteritems(): ans.append("%s: %s" % (k,",".join(map(str,v)))) return "\n".join(ans) def _setup(self): """Create the groups attribute.""" type = self.grouptype.lower() if not self.filegroups: if type=="allorbitals": self.groups = {} for i in range(len(self.aonames)): orbital = self.aonames[i] self.groups[orbital] = [i] elif type=="allatoms": self.groups = dict(zip(self.atomnames, self.atombasis)) else: raise TypeError,"You need to specify groups" else: if type=="orbitals": self.groups = {} for k,v in self.filegroups.iteritems(): # Convert the indices to start from 0 self.groups[k] = [x-1 for x in v] elif type=="atoms": self.groups = {} for k,v in self.filegroups.iteritems(): self.groups[k] = [] for x in v: # Convert the indices to start from 0 self.groups[k].extend(self.atombasis[x - 1]) else: raise TypeError,"%s is not a valid type of group" % type def verify(self,purpose): """Verify that the groups attribute is consistent. purpose is one of "DOS" or "COOP" """ status = "" # Create one big list of all of the atom orbitals in the groups all = reduce(lambda a,b:a+b, self.groups.values()) all.sort() if purpose=="DOS": # Each atom orb must appear exactly once ok = (all==range(len(self.aonames))) if not ok: status = "Problem with Groups.txt!\n(1)Every atom/orbital must " \ "be listed as a member of some group\n(2)No " \ "atom/orbital can be listed twice" elif purpose=="COOP": # No atom can appear twice (and cannot have any crazy atoms either) badatom = [x for x in all if x not in range(len(self.aonames))] if badatom: status = "Atomic orb number out of range in Groups.txt\n" else: for i in range(len(all)-1): if all[i]==all[i+1]: status += "Atomic orb %d has been included twice\n" % all[i] return status if __name__=="__main__": import doctest doctest.testmod(verbose=True) GaussSum-2.2.6.1/gausssum/scf.py0000664000175000017500000000354712117172552015115 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. import os import sys import math from plot import DisplayPlot from gnupy import Gnuplot from tempfile import mkstemp from Tkinter import * def SCF(root,screen,logfile,numpoints,gnuplotexec): screen.write("Starting to analyse the progress of the SCF\n") scfvalues = logfile.scfvalues[-1] # The most recent in the logfile scftargets = logfile.scftargets[-1] # Ditto deviation = [] for i in range(len(scfvalues)): # Which SCF cycle dev = 0 for j in range(len(scftargets)): # Which target if abs(scfvalues[i][j]) > scftargets[j]: dev += math.log(abs(scfvalues[i][j]) / scftargets[j]) deviation.append(dev) if len(deviation)>=numpoints+2: # If there are two points to plot h = Gnuplot(gnuplotexec) h.commands("set yrange [0:*]") h.commands("set xlabel 'SCF convergence step'") h.commands("set ylabel 'Deviation from targets'") data = zip(range(len(deviation)-numpoints),deviation[numpoints:]) h.data(data,"notitle with lines") h.data(data,"notitle") DisplayPlot(root,h,"Plot of SCF deviation vs Iteration") else: screen.write("I need at least two points to plot\n") screen.write("Finished\n") GaussSum-2.2.6.1/gausssum/vibfreq.py0000664000175000017500000001545212117172552015776 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2012 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. import os import math import gausssum.utils from plot import DisplayPlot from gnupy import Gnuplot from folder import folder def activity_to_intensity(activity, frequency, excitation, temperature): """Convert Raman acitivity to Raman intensity according to Krishnakumar et al, J. Mol. Struct., 2004, 702, 9.""" excitecm = 1 / (1e-7 * excitation) f = 1e-13 above = f * (excitecm - frequency)**4 * activity exponential = -6.626068e-34 * 299792458 * frequency / (1.3806503e-23 * temperature) below = frequency * (1 - math.exp(exponential)) return above / below def get_scaling_factors(filename, scale): """Read in scaling factors from an existing output file. Note: Scale is prepopulated with the general scaling factor """ inputfile = open(filename, "r") line = inputfile.readline() line = inputfile.readline() i = 0 line = inputfile.readline().split('\t') while len(line) > 6: # Read in the individual scaling factors sf = line[-2] if sf != '': scale[i] = float(sf) i += 1 line = inputfile.readline().split('\t') inputfile.close() return scale def Vibfreq(root,screen,logfile,logfilename,start,end,numpts,FWHM,typeofscale,scalefactor,excitation,temperature,gnuplotexec): def dofreqs(name,act): screen.write("\n************* Doing the "+name+" *****************\n") filename=name+"Spectrum.txt" freq = logfile.vibfreqs.copy() # Copy so that it won't be changed by the routine if hasattr(logfile, "vibsyms"): vibsyms = logfile.vibsyms else: vibsyms = ['?'] * len(freq) # Handle the scaling of the frequencies scale = [scalefactor] * len(freq) if typeofscale == "Gen": screen.write("Going to scale with a scaling factor of "+str(scalefactor)+"\n") general = True else: screen.write("Going to use individual scaling factors\n") screen.write("Looking for scaling factors in "+filename+"...") inputfilename = os.path.join(gaussdir,filename) if not os.path.isfile(inputfilename): screen.write("not found\nGoing to use general scale factor of "+str(scalefactor)+" instead\n") general = True else: screen.write("found\n") general = False get_scaling_factors(inputfilename, scale) # Update scaling factors in 'scale' from file for i in range(len(freq)): # Scale the freqs freq[i] = freq[i]*scale[i] # Convolute the spectrum spectrum = gausssum.utils.Spectrum(start,end,numpts, [zip(freq,act)], FWHM,gausssum.utils.lorentzian) if name == "Raman": intensity = [activity_to_intensity(activity, frequency, excitation, temperature) for activity, frequency in zip(act, freq)] spectrum_intensity = gausssum.utils.Spectrum(start,end,numpts, [zip(freq, intensity)], FWHM,gausssum.utils.lorentzian) outputfile = open(os.path.join(gaussdir,filename),"w") screen.write("Writing scaled spectrum to "+filename+"\n") outputfile.write("Spectrum\t%s\t\tNormal Modes\n" % ["", "\t"][name=="Raman"]) outputfile.write("Freq (cm-1)\t%s act\t%s\tMode\tLabel\tFreq (cm-1)\t%s act\t" % (name, ["", "Intensity\t"][name=="Raman"],name)) outputfile.write("%sScaling factors\tUnscaled freq\n" % ["", "Intensity\t"][name=="Raman"]) width = end-start for x in range(0,numpts): if spectrum.spectrum[x,0]<1e-20: spectrum.spectrum[x,0] = 0. realx = width*(x+1)/numpts+start outputfile.write(str(realx)+"\t"+str(spectrum.spectrum[x,0])) if name == "Raman": outputfile.write("\t%f" % spectrum_intensity.spectrum[x,0]) if x # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. def Search(screen, logfilename, searchstring, case_sensitive): screen.write("Starting to search\n") searchterm = searchstring.split("%") inputfile = open(logfilename, "r") if not case_sensitive: # change all the searchterms to lowercase temp=[] for x in searchterm: temp.append(x.lower()) searchterm=temp screenoutput = [] for line in inputfile: searchline = line if not case_sensitive: searchline = line.lower() for x in searchterm: if searchline.find(x) >= 0: screenoutput.append(line) break inputfile.close() screen.write("".join(screenoutput)) screen.write("Finished searching\n") GaussSum-2.2.6.1/gausssum/plot.py0000664000175000017500000001100712117172552015306 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # This class takes a string containing commands to Gnuplot # and creates a window showing the Gnuplot # Changing from gifs to pngs import os import time import shutil import tkFileDialog import tkMessageBox # For the Error Dialog from tempfile import mkstemp from Tkinter import * from PIL import Image # Python Imaging Library from PIL import ImageTk # Python Imaging Library from gnupy import Gnuplot # Kludge necessary for using PIL when using py2exe # (see http://www.py2exe.org/index.cgi/PIL_and_py2exe) from PIL import PngImagePlugin # Python Imaging Library Image._initialized = 2 class DisplayPlot(object): def __init__(self,root,g,title): self.filedes,self.filename=mkstemp() # filedes is the "file descriptor" status = g.plot(self.filename) if status==1: # i.e. gnuplot executable not present tkMessageBox.showerror( title = "Check the path to Gnuplot in Settings", message = "No plot was created as the Gnuplot executable cannot be found.\n" "Go to 'File'/'Settings' and set the correct path." ) return self.popup=Toplevel(root) self.popup.focus_set() self.popup.title(title) self.title=title # do this better self.popup.resizable(False,False) self.frame1=Frame(self.popup) self.frame1.grid() # To create the examples use the following instead: # self.canvas2 = Canvas(self.frame1,width=490,height=370,background="blue") self.canvas2 = Canvas(self.frame1,width=650,height=490,background="blue") self.canvas2.pack(side=TOP) frame2=Frame(self.frame1) frame2.pack(side=TOP) try: image = Image.open(self.filename) self.graph = ImageTk.PhotoImage(image) self.item2 = self.canvas2.create_image(7,7,anchor=NW,image=self.graph) Label(self.frame1,text="").pack(side=TOP) except IOError: # This happens anytime that gnuplot doesn't create a graph # (for some reason...e.g. bad input) tkMessageBox.showerror(title="The script is complaining...", message="No graph has been created. This may be due \ to a problem with your gnuplot installation or with your \ input file. Contact the author if you think GaussSum is the problem.") self.close() return else: # Only put the save button there if there's something to save Button(frame2,text="Save As",underline=0,command=self.save).pack(side=LEFT) self.popup.bind("",self.save) Button(frame2,text="Close",underline=0,command=self.close).pack(side=LEFT) frame3=Frame(self.frame1) frame3.pack(side=TOP) Label(self.frame1,text="").pack(side=TOP) self.popup.bind("",self.close) self.popup.bind("",self.close) self.popup.bind("",self.close) self.popup.protocol("WM_DELETE_WINDOW", self.close) def close(self,event=None): os.close(self.filedes) os.remove(self.filename) self.popup.destroy() def save(self,event=None): filename=tkFileDialog.asksaveasfilename(filetypes=[("PeNGuin",".png")], parent=self.popup, defaultextension=".png" ) if filename!="": if filename.find(".")==-1: filename=filename+".png" shutil.copyfile(self.filename,filename) self.popup.title(self.title+" - "+filename) if __name__=="__main__": line='plot sin(x)\n' root=Tk() app=Gnuplot(root,line,"Test plot") mainloop() GaussSum-2.2.6.1/gausssum/popanalysis.py0000664000175000017500000005145212117172552016702 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. ## Automatically adapted for numpy.oldnumeric Jun 15, 2007 by import string import os import sys import numpy import numpy.oldnumeric as Numeric from math import exp,log from Tkinter import * from plot import DisplayPlot from gnupy import Gnuplot from folder import folder from gausssum.utils import levelname from gausssum.utils import GaussianSpectrum from gausssum.utils import Groups def Popanalysis(root,screen,logfile,logfilename,start,end,COOP,FWHM,makeorigin,gnuplotexec): def DOSconvolute(orb_MPA,evalue): """Convolute the DOS spectrum""" heights =[x for x in numpy.swapaxes(orb_MPA,0,1)] spectrum = GaussianSpectrum(start, end, 1000, (evalue, heights), FWHM) return spectrum def tidy(num): # Changes +-0.155648 into +-0.16 if num>=0: rounded=int(num*100+.5)/100. return str(rounded)[:4] else: rounded=int(num*100-.5)/100. return str(rounded)[:5] def originoutput(MPA): """Write a file suitable for reading with Origin.""" outputfile=open(os.path.join(gaussdir,"origin_orbs.txt"),"w") for i in range(len(evalue[0])): if numgroups>0 and pop: total=0 for j in range(numgroups): outputfile.write(str(total)+"\t"+str(evalue[0][i])+"\t") total += MPA[0][i,j] outputfile.write("\n") total=0 for j in range(numgroups): total += MPA[0][i,j] outputfile.write(str(total)+"\t"+str(evalue[0][i])+"\t") outputfile.write("\n") else: outputfile.write("0\t"+str(evalue[0][i])+"\n") outputfile.write("1\t"+str(evalue[0][i])+"\n") if unres: for i in range(len(evalue[1])): if numgroups>0 and pop: total=0 for j in range(numgroups): outputfile.write(str(total)+"\t"+str(evalue[1][i])+"\t") total += MPA[1][i,j] outputfile.write("\n") total=0 for j in range(numgroups): total += MPA[1][i,j] outputfile.write(str(total)+"\t"+str(evalue[1][i])+"\t") outputfile.write("\n") else: outputfile.write("0\t"+str(evalue[1][i])+"\n") outputfile.write("1\t"+str(evalue[1][i])+"\n") outputfile.close() def densityofstates(): """Do the density of status calculation.""" if groups and pop: contrib = [x * numpy.dot(x,overlap) for x in MOCoeff] if not unres: MPA = [numpy.zeros( (logfile.nmo,numgroups), "d")] else: MPA = [numpy.zeros( (logfile.nmo,numgroups), "d") for x in range(2)] for i,groupname in enumerate(groups.groups.keys()): for basisfn in groups.groups[groupname]: MPA[0][:,i] += contrib[0][:,basisfn] if unres: MPA[1][:,i] += contrib[1][:,basisfn] else: # Set MPA to be all ones MPA = [numpy.ones( (logfile.nmo,1), "d")] if unres: MPA = [numpy.ones( (logfile.nmo,1), "d") for x in range(2)] # Write DOS and PDOS data to orbital_data.txt screen.write("Writing orbital data to orbital_data.txt\n") outputfile=open(os.path.join(gaussdir,"orbital_data.txt"),"w") outputfile.write("NBasis:\t"+str(NBsUse)+"\n") outputfile.write("HOMO:\t%s" % "\t".join([str(x+1) for x in HOMO])) if not (groups and pop): # No point outputting group info since we don't have the %contribs outputfile.write("\nGroups:\t0\n") else: outputfile.write("\nGroups:\t"+str(len(groups.groups))+"\n") line = [] for k,v in groups.groups.iteritems(): line.append("%s\t%s" % (k," ".join(map(str,v)))) outputfile.write("\n".join(line) + "\n") if unres: outputfile.write("\nAlpha MO\t\teV\tSymmetry") else: outputfile.write("\nMO\t\teV\tSymmetry") if groups and pop: t = "\t".join(groups.groups.keys()) outputfile.write("\t" + t+"\tAccurate values (for the Electronic Transitions module)") if unres: if groups and pop: outputfile.write("\t"*(len(groups.groups)-1)) outputfile.write("\tBeta MO\t\teV\tSymmetry") if groups and pop: outputfile.write(t+"\tAccurate values (for UVVis.py)") outputfile.write("\n") for i in range(max([len(x) for x in evalue])-1,-1,-1): # Print them out backwards line=str(i+1)+"\t"+levelname(i, HOMO[0])+"\t"+str(round(evalue[0][i],2))+"\t"+symmetry[0][i] if groups and pop: for j in range(len(groups.groups)): line=line+"\t"+str(int(MPA[0][i,j]*100+.5)) for j in range(len(groups.groups)): line=line+"\t"+str(MPA[0][i,j]) if unres and i=len(evalue[1]): continue output.write(str(k+1)+"\t"+levelname(k, HOMO[j])+"\t"+str(evalue[j][k])) for fragx in range(len(groups.groups)-1): for fragy in range(fragx+1,len(groups.groups)): output.write("\t"+str(groupoverlap[j][k,fragx,fragy])) output.write("\n") output.close() # Convolute the COOP spectrum spectrum = [] for j in range(len(HOMO)): overlaps = [] for fragx in range(numgroups - 1): for fragy in range(fragx+1, numgroups): overlaps.append(groupoverlap[j][:,fragx,fragy]) spectrum.append(GaussianSpectrum(start, end, 1000, (evalue[j], overlaps), FWHM)) # Create COOP_spectrum.txt output = open(os.path.join(gaussdir,"COOP_spectrum.txt"),"w") output.write("\t") if unres: output.write("Alpha%sBeta%s" % ("\t"*numoverlaps,"\t"*numoverlaps)) output.write("Total\n") output.write("eV\t%s" % listofoverlaps) if unres: output.write("\t%s\t%s" % (listofoverlaps, listofoverlaps)) output.write("\n") for i in range(len(spectrum[0].xvalues)): output.write("%f" % spectrum[0].xvalues[i]) for k in range(len(spectrum)): for j in range(len(spectrum[k].spectrum[:,0])): output.write("\t%f" % spectrum[k].spectrum[j,i]) if unres: output.write("\t%f" % sum([spectrum[x].spectrum[j,i] for x in [0,1]])) output.write("\n") output.close() # Gnuplot the COOP g = Gnuplot(gnuplotexec) g.commands("set xrange [%f:%f]" % (start,end), "set xlabel 'Energy (eV)'") i = 0 for fragx in range(numgroups-1): for fragy in range(fragx+1, numgroups): for j in range(len(spectrum)): if not unres: g.data( zip(spectrum[j].xvalues,spectrum[j].spectrum[i,:]), " title 'overlap of %s with %s' with lines" % (groupnames[fragx], groupnames[fragy])) else: g.data( zip(spectrum[j].xvalues,spectrum[j].spectrum[i,:]), " title '%s overlap of %s with %s' with lines" % (['Alpha','Beta'][j], groupnames[fragx], groupnames[fragy])) ## if unres: # Plot the total or not? ## g.data( zip(spectrum[j].xvalues,spectrum[0].spectrum[i,:] + spectrum[1].spectrum[i,:]), ## " title 'Total overlap of %s with %s' with lines" % ( groupnames[fragx], ## groupnames[fragy])) i += 1 DisplayPlot(root,g,"COOP spectrum") return # End of crystalorbital() ############### START OF MAIN ################## screen.write("Starting to analyse the molecular orbitals\n") groupatoms=[]; groupname=[]; atomorb=[] # Create the output directory if necessary gaussdir=folder(screen,logfilename) # Read in the groups (if they exist!) filename = os.path.join(gaussdir,"Groups.txt") groups = False numgroups = 0 if not os.path.isfile(filename): screen.write("Groups.txt not found\n") elif not (hasattr(logfile, "atombasis") and hasattr(logfile, "atomnos")): screen.write("Groups.txt found but not used as logfile does not have" " atombasis or atomnos\n") # not necessary depending on the groups else: screen.write("Reading Groups.txt\n") if not hasattr(logfile, "aonames"): groups = Groups(filename, logfile.atomnos, None, logfile.atombasis) else: groups = Groups(filename, logfile.atomnos, logfile.aonames, logfile.atombasis) numgroups = len(groups.groups) screen.write("There are %d groups\n" % numgroups) NAtoms = logfile.natom NBasis = logfile.nbasis NBsUse = logfile.nmo # Verify that groups.txt is okay if groups: if COOP==False: status = groups.verify("DOS") else: status = groups.verify("COOP") if status: screen.write(status) return 1 screen.write("The number of atoms is "+str(NAtoms)+"\n") screen.write("NBasis is "+str(NBasis)+"\n") screen.write("NBsUse is "+str(NBsUse)+"\n") pop=False if hasattr(logfile, "aooverlaps") and hasattr(logfile, "mocoeffs"): screen.write("Found an overlap matrix and MO coefficients\n") pop=True # Assuming you never get an overlap matrix without the MOCoeffs MOCoeff = logfile.mocoeffs overlap = logfile.aooverlaps atomorb = logfile.aonames if len(MOCoeff)==2: screen.write("This is an unrestricted calculation - found the Beta MO coefficents\n") unres=False HOMO = logfile.homos if len(HOMO)==2: screen.write("This is an unrestricted calculation\n") unres=True evalue = logfile.moenergies if hasattr(logfile,"mosyms"): symmetry = logfile.mosyms else: symmetry = [["?" for x in evalue[0]]] if unres: symmetry.append(["?" for x in evalue[1]]) screen.write("Number of evalues found: %s\n" % " ".join([str(len(x)) for x in evalue])) screen.write("Number of orbital symmetries found: %s\n" % " ".join([str(len(x)) for x in symmetry])) if COOP==True: if not (groups and pop): screen.write("To calculate the COOP spectrum, you need Groups.txt and a log file containing a full population analysis\n") return 1 crystalorbital() else: # Density of States densityofstates() screen.write("Finished\n") GaussSum-2.2.6.1/gausssum/__init__.py0000664000175000017500000000000012117172552016056 0ustar noelnoelGaussSum-2.2.6.1/gausssum/electrontrans.py0000664000175000017500000005102312117172552017215 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details import os import sys import math import stat import numpy import glob from gausssum.utils import GaussianSpectrum, levelname, percent from gausssum.cclib.parser.utils import convertor from Tkinter import * from gnupy import Gnuplot from plot import DisplayPlot from folder import folder def createEDDM(screen, logfile, contrib, gaussdir, unres): def cubman(cmds): if cmds[0] == "sc": output.write("echo Scaling %s by %s\n" % (cmds[1], cmds[-1])) elif cmds[0] == "a": output.write("echo Adding to %s\n" % cmds[3]) elif cmds[0] == "sq": output.write("echo Squaring %s\n" % cmds[1]) elif cmds[0] == "su": output.write("echo Subtracting %s from %s\n" % (cmds[1], cmds[3])) lines = [] lines.append("echo %s > tmp.txt" % cmds[0]) for cmd in cmds[1:]: lines.append("echo %s >> tmp.txt" % cmd) cmdname = syscmd[CAT] lines.append("%s tmp.txt | %s%scubman > tmp2.txt\n" % (cmdname, envvar('G03DIR'), os.sep)) output.write("\n".join(lines)) def envvar(x): if windows: return "%" + x + "%" else: return "${" + x + "}" def createcubes(mo): cube = "mo%s.cub" % getmo(mo) report = "echo Creating cubefile %s" % cube orb = mo[0] + 1 if unres: calctype = ['alpha', 'beta'][mo[1]] orb += len(logfile.moenergies[0]) * mo[1] cmd = "%s%scubegen 0 MO=%d %s %s -2 h\n" % ( envvar('G03DIR'), os.sep, orb, fchkpoint, cube) if windows: line = "if not exist %s %s & %s\n" % (cube, report, cmd) else: line = 'if [ ! -e "%s" ]\nthen\n %s\n %s\nfi\n' % (cube, report, cmd) output.write(line) def getmo(mo): suffix = "" if unres: suffix = ["A", "B"][mo[1]] return "%d%s" % (mo[0] + 1, suffix) def createsquares(mo): cube = "mo%s.cub" % getmo(mo) sq = "sq%s.cub" % getmo(mo) if windows: output.write("if not exist %s (\n" % sq) else: output.write("if [ ! -e %s ]\nthen\n" % sq) cubman(["sq", cube, "y", sq, "y"]) if windows: output.write(")\n") else: output.write("fi\n") def formchk(filename): filename = filename.split(fakeossep)[-1] fchkpoint = filename.replace('.chk', '.fck') report = "echo Formatting %s to %s" % (filename, fchkpoint) cmd = "%s%sformchk %s %s > tmp2.txt\n" % (envvar('G03DIR'), os.sep, filename, fchkpoint) if windows: line = "if not exist %s %s & %s\n" % (fchkpoint, report, cmd) else: line = 'if [ ! -e "%s" ]\nthen\n %s\n %s\nfi\n' % (fchkpoint, report, cmd) return fchkpoint, line windows = sys.platform == "win32" ## windows = False fakeossep = os.sep ## fakeossep = "\\" ## os.sep = "/" COPY, DELETE, CAT, MOVE = range(4) syscmd = ['cp', 'rm', 'cat', 'mv'] if windows: syscmd = ['copy', 'del', 'type', 'move'] fchkpoint = glob.glob(os.path.join(gaussdir, "*.fck")) + glob.glob(os.path.join(gaussdir, "*.fchk")) line = "" if len(fchkpoint) == 0: chkpoint = glob.glob(os.path.join(gaussdir, "*.chk")) fchkpoint, line = formchk(chkpoint[0]) else: fchkpoint = fchkpoint[0].split(fakeossep)[-1] # Error! screen.write("Creating the EDDM script file for %s\n" % fchkpoint) if windows: output = open(os.path.join(gaussdir, "eddm.bat"), "w") output.write("@echo off\n") else: finalsection = [] output = open(os.path.join(gaussdir, "eddm.sh"), "w") os.chmod(os.path.join(gaussdir, "eddm.sh"), stat.S_IRWXU) # Make executable if line: output.write(line) output.write("echo === Using formatted checkpoint %s ===\n" % fchkpoint) for i in range(len(logfile.etenergies)): # For each transition if windows: output.write("""if "%%1" == "%d" goto :tran%d\n""" % (i+1, i+1)) else: finalsection.append("""if [ "$1" == "%d" ]\nthen\n tran%d\nfi\n""" % (i+1, i+1)) line = "echo You need to specify a transition in the range 1 to %d\n" % len(logfile.etenergies) if windows: output.write("%s\ngoto :end\n" % line) else: finalsection.append(line) for i in range(len(logfile.etenergies)): # For each transition if windows: output.write(":tran%d\n" % (i+1)) else: output.write("function tran%d\n{\n" % (i+1)) totalcon = sum(contrib[i]) scales = [x / float(totalcon) for x in contrib[i]] minimum_scale = 0 # Don't include contributions that don't contribute! # Create any necessary cube and squared files alreadydone = set() for sec, scale in zip(logfile.etsecs[i], scales): if scale > minimum_scale: for M in range(2): if sec[M] not in alreadydone: createcubes(sec[M]) createsquares(sec[M]) alreadydone.add(sec[M]) N = 0 # Find the first transition with non-zero scale while N < len(scales) and scales[N] <= minimum_scale: N += 1 if N < len(scales): scale = scales[N] cubman(["sc","sq%s.cub" % getmo(logfile.etsecs[i][N][0]),"y","before.cub","y",str(scale)]) cubman(["sc","sq%s.cub" % getmo(logfile.etsecs[i][N][1]),"y","after.cub","y",str(scale)]) created_tmp = False for j in range(N + 1, len(logfile.etsecs[i])): scale = scales[j] if scale > minimum_scale: created_tmp = True cubman(["sc","sq%s.cub" % getmo(logfile.etsecs[i][j][0]),"y","tmp.cub","y",str(scale)]) cubman(["a","tmp.cub","y","before.cub","y","tmp2.cub","y"]) output.write("%s tmp2.cub before.cub\n" % syscmd[MOVE]) cubman(["sc","sq%s.cub" % getmo(logfile.etsecs[i][j][1]),"y","tmp.cub","y",str(scale)]) cubman(["a","tmp.cub","y","after.cub","y","tmp2.cub","y"]) output.write("%s tmp2.cub after.cub\n" % syscmd[MOVE]) if created_tmp: output.write("%s tmp.cub\n" % syscmd[DELETE]) cubman(["su","before.cub","y","after.cub","y", "trans%d.cub" % (i+1,),"y"]) else: output.write("echo No significant contributions found") if windows: output.write("goto :end\n") else: output.write("}\n") if windows: output.write(":end\n") else: output.write("\n".join(finalsection)) output.close() def readorbital_data(inputfile): # Reads in all data from orbital_data.txt line=inputfile.readline(); NBasis=int(line.split()[1]) line=inputfile.readline().split(); HOMO=[int(line[1])-1] unres=False if len(line)==3: unres=True # This is an unrestricted calculation HOMO.append(int(line[2])-1) line=inputfile.readline(); NGroups=int(line.split()[1]) groupname=[]; groupatoms=[] for i in range(NGroups): # Read in group info line=inputfile.readline() temp=line.split('\t') groupname.append(temp[0]) groupatoms.append(map(int,temp[1].split())) line=inputfile.readline() headers = inputfile.readline() # Contribs for orbital#1 will be in contrib[0][0-->NGroups] if not unres: contrib = numpy.zeros((1,NBasis,NGroups), "d") else: contrib = numpy.zeros((2,NBasis,NGroups), "d") evalues=[] for i in range(NBasis-1,-1,-1): line=inputfile.readline().split() evalue = [float(line[2])] more = line[4+NGroups:4+NGroups*2] # Strip off the crud at the start contrib[0,i,:] = [float(x) for x in more] if unres: evalue.append(float(line[6+NGroups*2])) more = line[8+NGroups*3:8+NGroups*4] contrib[1,i,:] = [float(x) for x in more] evalues.append(evalue) evalue.reverse() # Because you're reading them in backwards return HOMO,NBasis,NGroups,groupname,groupatoms,contrib,evalues def ET(root,screen,logfile,logfilename, start,end,numpts,FWHM,UVplot ,gnuplotexec, EDDM): screen.write("Starting to analyse the electronic transitions\n") # Create output directory if necessary gaussdir=folder(screen,logfilename) unres = len(logfile.homos) > 1 CIS = logfile.etsecs if UVplot==True: ####################################################### # UV-Visible section # ####################################################### # Read in orbital_data.txt if it exists(which contains info on the contribs) NGroups=0 orbdata = False try: inputfile=open(os.path.join(gaussdir,"orbital_data.txt"),"r") except IOError: screen.write("orbital_data.txt not found\n") else: thisHOMO,NBasis,NGroups,groupname,groupatoms,contrib,evalue=readorbital_data(inputfile) inputfile.close() orbdata=True screen.write("Using orbital_data.txt\n") if thisHOMO != list(logfile.homos): screen.write("Disagreement on HOMO...orbital_data.txt says "+str(thisHOMO)+"\n"+logfile.filename+" says "+str(logfile.homos)+"\n") return False screenCD=[] for i in range(len(logfile.etenergies)): # For each transition screenCD.append("") # charge density [before, after] for each of the groups for each of the transitions majorCIS, minorCIS = [[] for x in logfile.etenergies], [[] for x in logfile.etenergies] allpercent = [[] for x in logfile.etenergies] for i in range(len(logfile.etenergies)): # For each transition if orbdata: CD=[ [0, 0] for x in range(NGroups)] totcontribs = 0 for j in range(len(CIS[i])): # For each contribution thisCIS = CIS[i][j] mycontrib = thisCIS[2] ** 2 totcontribs += mycontrib # tot up the contribs percontrib = int(mycontrib * 100 + .5) if orbdata: for k in range(NGroups): CD[k][0] += mycontrib * contrib[thisCIS[0][1], thisCIS[0][0], k] # Add to 'before' charge density CD[k][1] += mycontrib * contrib[thisCIS[1][1], thisCIS[1][0], k] # Add to 'after' charge density alphabeta = ["", ""] if unres: alphabeta = [["(A)", "(B)"][thisCIS[0][1]], ["(A)", "(B)"][thisCIS[1][1]]] CIStext = "%s%s->%s%s (%d%%)" % (levelname(thisCIS[0][0], logfile.homos[thisCIS[0][1]]), alphabeta[0], levelname(thisCIS[1][0], logfile.homos[thisCIS[1][1]]), alphabeta[1], percontrib) if percontrib >= 10: # Major contributions (>=10%) majorCIS[i].append(CIStext) elif percontrib >= 2: #Minor contributions (>=2%) minorCIS[i].append(CIStext) allpercent[i].append(percontrib) if orbdata: for j in range(len(groupname)): # The charge densities are scaled so that they add to one CD[j][0]=CD[j][0]/totcontribs CD[j][1]=CD[j][1]/totcontribs screenCD[i]=screenCD[i]+percent(CD[j][0])+"-->"+percent(CD[j][1])+" ("+percent(round(CD[j][1],2)-round(CD[j][0],2))+")\t" if EDDM: createEDDM(screen, logfile, allpercent, gaussdir, unres) # Write UVData.txt containing info on the transitions fileoutput = "" for i in range(len(logfile.etenergies)): # For each transition temp = [i+1,logfile.etenergies[i], convertor(logfile.etenergies[i],"cm-1","nm"), logfile.etoscs[i],logfile.etsyms[i], ", ".join(majorCIS[i]),", ".join(minorCIS[i])] if orbdata: temp.append(screenCD[i]) fileoutput += "\t".join(map(str,temp)) + "\n" screen.write("Writing the transition info to UVData.txt\n") outputfile=open(os.path.join(gaussdir,"UVData.txt"),"w") outputfile.write("HOMO is "+str(logfile.homos[0]+1)) if unres: outputfile.write("\t%d" % (logfile.homos[1] + 1,)) outputfile.write("\nNo.\tEnergy (cm-1)\tWavelength (nm)\tOsc. Strength\tSymmetry\tMajor contribs\tMinor contribs") for i in range(NGroups): outputfile.write("\t"+groupname[i]) outputfile.write("\n"+fileoutput) outputfile.close() endwaveno = convertor(start,"nm","cm-1") startwaveno = convertor(end,"nm","cm-1") t = GaussianSpectrum(startwaveno,endwaveno,numpts, ( logfile.etenergies,[[x*2.174e8/FWHM for x in logfile.etoscs]] ), FWHM) screen.write("Writing the spectrum to UVSpectrum.txt\n") outputfile=open(os.path.join(gaussdir,"UVSpectrum.txt"),"w") outputfile.write("Energy (cm-1)\tWavelength (nm)\tAbs\t<--UV Spectrum\tUV-Vis transitions-->\tEnergy (cm-1)\tWavelength (nm)\tOsc. strength\n") width=endwaveno-startwaveno for x in range(numpts): realx=width*x/numpts+startwaveno outputfile.write(str(realx)+"\t"+str(convertor(realx,"cm-1","nm"))+"\t"+str(t.spectrum[0,x])) if x\tWavelength (nm)\tEnergy (cm-1)\tR(length)\n") width = endwaveno - startwaveno for x in range(numpts): # Need to use float, otherwise it's an integer # realx = float(width)*x/numpts+start realx = width * x / numpts + startwaveno outputfile.write("%f\t%f\t%f" % (realx, 1.0e7/realx, t.spectrum[0,x])) if x < len(logfile.etenergies): # Write the R values out also outputfile.write( "\t\t\t%f\t%f\t%f" % (convertor(logfile.etenergies[x], "cm-1", "nm"), logfile.etenergies[x],logfile.etrotats[x]) ) outputfile.write("\n") outputfile.close() if root: # Plot the UV Spectrum using Gnuplot screen.write("Plotting using Gnuplot\n") if max(t.spectrum[0,:])<1E-8: # Gnuplot won't draw it if the spectrum is flat screen.write("There are no peaks in this wavelength range!\n") else: g = Gnuplot(gnuplotexec) g.commands("set ytics nomirror", "set y2tics", "set y2label 'R (length) / 1e-40'", "set xlabel 'Wavelength (nm)'", "set ylabel 'epsilon'", "set xrange [%d:%d]" % (start,end) ) xvalues_nm = [convertor(x,"cm-1","nm") for x in t.xvalues] g.data(zip(xvalues_nm,t.spectrum[0,:]),"notitle with lines") energies_nm = [convertor(x,"cm-1","nm") for x in logfile.etenergies] g.data(zip(energies_nm,logfile.etrotats),"axes x1y2 notitle with impulses") # line="set ytics nomirror\nset y2tics\nset y2label 'R (length) / 1e-40'\n" # line=line+"set xlabel 'Wavelength (nm)'\nset ylabel 'epsilon'\nset xrange ["+str(start)+":"+str(end)+"]\n" # line=line+"plot '"+os.path.join(gaussdir,"CDSpectrum.txt")+"' using 1:3 notitle with lines, '"+os.path.join(gaussdir,"CDSpectrum.txt")+"' using 4:6 axes x1y2 notitle with impulses\n" DisplayPlot(root,g,"Circular dichroism spectrum") screen.write("Finished") ####################################################### # End of main # ####################################################### GaussSum-2.2.6.1/gausssum/aboutbox.py0000664000175000017500000000652012117172552016157 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from Tkinter import * # GUI stuff import tkMessageBox # For the About Dialog import tkFileDialog # For the Open File and Save File import webbrowser import tkSimpleDialog import traceback import copy # For deepcopy...until I find a better way of doing this import ConfigParser # For writing the settings to an .ini file from gausssum.cclib.parser import ADF, GAMESS, Gaussian import os, sys if hasattr(sys, "frozen"): # i.e. if using py2exe installlocation = os.path.dirname(sys.executable) else: import gausssum installlocation = gausssum.__path__[0] class AboutPopupBox(tkSimpleDialog.Dialog): def __init__(self, parent, title = None): # Override (just to set the geometry!) Toplevel.__init__(self, parent) self.transient(parent) if title: self.title(title) self.parent = parent self.result = None body = Frame(self) self.initial_focus = self.body(body) body.pack(padx=5, pady=5) self.buttonbox() self.grab_set() if not self.initial_focus: self.initial_focus = self self.protocol("WM_DELETE_WINDOW", self.cancel) self.initial_focus.focus_set() self.wait_window(self) def body(self,master): # Override self.resizable(False,False) self.canvas2 = Canvas(master,width=340,height=260) self.canvas2.pack(side=TOP) self.photo2 = PhotoImage(file=os.path.join(installlocation,"mesh.gif")) self.item2 = self.canvas2.create_image(11,11,anchor=NW,image=self.photo2) Label(master,text="(c) 2009 Noel O'Boyle").pack(side=TOP) Label(master,text="http://gausssum.sf.net").pack(side=TOP) Label(master,text="").pack(side=TOP) # Creates a bit of spacing at the bottom Label(master,text="Support GaussSum by citing:").pack(side=TOP) Label(master,text="N.M. O'Boyle, A.L. Tenderholt and K.M. Langner.",font=("Times",10,"bold")).pack(side=TOP) Label(master,text="J. Comp. Chem. 2008, 29, 839-845.",font=("Times",10,"bold")).pack(side=TOP) #Button(master,text="GaussSum home page on SourceForge",command=self.openmybrowser).pack(side=TOP) Label(master,text="").pack(side=TOP) # Creates a bit of spacing at the bottom x=(652-354)/2+self.parent.winfo_rootx() # Popup is 354x389 y=(480-405)/2+self.parent.winfo_rooty() self.geometry("354x405+"+str(x)+"+"+str(y)) # Place it in the centre of the root window def openmybrowser(self): # New webbrowser.open("http://gausssum.sf.net") def buttonbox(self): # Override box = Frame(self) w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE) w.pack(side=LEFT, padx=5, pady=5) self.bind("", self.ok) box.pack() GaussSum-2.2.6.1/gausssum/cclib/0000775000175000017500000000000012117172552015033 5ustar noelnoelGaussSum-2.2.6.1/gausssum/cclib/parser/0000775000175000017500000000000012117172552016327 5ustar noelnoelGaussSum-2.2.6.1/gausssum/cclib/parser/utils.py0000664000175000017500000000543712117172552020052 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 993 $" def convertor(value, fromunits, tounits): """Convert from one set of units to another. >>> print "%.1f" % convertor(8, "eV", "cm-1") 64524.8 """ _convertor = {"eV_to_cm-1": lambda x: x*8065.6, "eV_to_kJmol-1": lambda x: x*96.48538, "hartree_to_eV": lambda x: x*27.2113845, "Hartree_to_ kJmol-1": lambda x: x*2625.5002, "bohr_to_Angstrom": lambda x: x*0.529177, "Angstrom_to_bohr": lambda x: x*1.889716, "nm_to_cm-1": lambda x: 1e7/x, "cm-1_to_nm": lambda x: 1e7/x, "hartree_to_cm-1": lambda x: x*219474.6, # Taken from GAMESS docs, "Further information", # "Molecular Properties and Conversion Factors" "Debye^2/amu-Angstrom^2_to_km/mol": lambda x: x*42.255} return _convertor["%s_to_%s" % (fromunits, tounits)] (value) class PeriodicTable(object): """Allows conversion between element name and atomic no. >>> t = PeriodicTable() >>> t.element[6] 'C' >>> t.number['C'] 6 >>> t.element[44] 'Ru' >>> t.number['Au'] 79 """ def __init__(self): self.element = [None, 'H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Uub'] self.number = {} for i in range(1, len(self.element)): self.number[self.element[i]] = i if __name__ == "__main__": import doctest, utils doctest.testmod(utils, verbose=False) GaussSum-2.2.6.1/gausssum/cclib/parser/logfileparser.py0000664000175000017500000002600412117172552021541 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 992 $" import StringIO try: import bz2 # New in Python 2.3. except ImportError: bz2 = None import fileinput import gzip import inspect import logging logging.logMultiprocessing = 0 # To avoid a problem with Avogadro import os import random try: set # Standard type from Python 2.4+. except NameError: from sets import Set as set import sys import types import zipfile import numpy import utils from data import ccData def openlogfile(filename): """Return a file object given a filename. Given the filename of a log file or a gzipped, zipped, or bzipped log file, this function returns a regular Python file object. Given an address starting with http://, this function retrieves the url and returns a file object using a temporary file. Given a list of filenames, this function returns a FileInput object, which can be used for seamless iteration without concatenation. """ # If there is a single string argument given. if type(filename) in [str, unicode]: extension = os.path.splitext(filename)[1] if extension == ".gz": fileobject = gzip.open(filename, "r") elif extension == ".zip": zip = zipfile.ZipFile(filename, "r") assert len(zip.namelist()) == 1, "ERROR: Zip file contains more than 1 file" fileobject = StringIO.StringIO(zip.read(zip.namelist()[0])) elif extension in ['.bz', '.bz2']: # Module 'bz2' is not always importable. assert bz2 != None, "ERROR: module bz2 cannot be imported" fileobject = bz2.BZ2File(filename, "r") else: fileobject = open(filename, "r") return fileobject elif hasattr(filename, "__iter__"): # Compression (gzip and bzip) is supported as of Python 2.5. if sys.version_info[0] >= 2 and sys.version_info[1] >= 5: fileobject = fileinput.input(filename, openhook=fileinput.hook_compressed) else: fileobject = fileinput.input(filename) return fileobject class Logfile(object): """Abstract class for logfile objects. Subclasses defined by cclib: ADF, GAMESS, GAMESSUK, Gaussian, Jaguar, Molpro, ORCA """ def __init__(self, source, progress=None, loglevel=logging.INFO, logname="Log", logstream=sys.stdout, fupdate=0.05, cupdate=0.002, datatype=ccData): """Initialise the Logfile object. This should be called by a ubclass in its own __init__ method. Inputs: source - a single logfile, a list of logfiles, or input stream """ # Set the filename to source if it is a string or a list of filenames. # In the case of an input stream, set some arbitrary name and the stream. # Elsewise, raise an Exception. if isinstance(source, types.StringTypes): self.filename = source self.isstream = False elif isinstance(source, list) and all([isinstance(s, types.StringTypes) for s in source]): self.filename = source self.isstream = False elif hasattr(source, "read"): self.filename = "stream %s" % str(type(source)) self.isstream = True self.stream = source else: raise ValueError # Progress indicator. self.progress = progress self.fupdate = fupdate self.cupdate = cupdate # Set up the logger. # Note that calling logging.getLogger() with one name always returns the same instance. # Presently in cclib, all parser instances of the same class use the same logger, # which means that care needs to be taken not to duplicate handlers. self.loglevel = loglevel self.logname = logname self.logger = logging.getLogger('%s %s' % (self.logname, self.filename)) self.logger.setLevel(self.loglevel) if len(self.logger.handlers) == 0: handler = logging.StreamHandler(logstream) handler.setFormatter(logging.Formatter("[%(name)s %(levelname)s] %(message)s")) self.logger.addHandler(handler) # Periodic table of elements. self.table = utils.PeriodicTable() # This is the class that will be used in the data object returned by parse(), # and should normally be ccData or a subclass. self.datatype = datatype def __setattr__(self, name, value): # Send info to logger if the attribute is in the list self._attrlist. if name in getattr(self, "_attrlist", {}) and hasattr(self, "logger"): # Call logger.info() only if the attribute is new. if not hasattr(self, name): if type(value) in [numpy.ndarray, list]: self.logger.info("Creating attribute %s[]" %name) else: self.logger.info("Creating attribute %s: %s" %(name, str(value))) # Set the attribute. object.__setattr__(self, name, value) def parse(self, fupdate=None, cupdate=None): """Parse the logfile, using the assumed extract method of the child.""" # Check that the sub-class has an extract attribute, # that is callable with the proper number of arguemnts. if not hasattr(self, "extract"): raise AttributeError, "Class %s has no extract() method." % self.__class__.__name__ if not callable(self.extract): raise AttributeError, "Method %s._extract not callable." % self.__class__.__name__ if len(inspect.getargspec(self.extract)[0]) != 3: raise AttributeError, "Method %s._extract takes wrong number of arguments." % self.__class__.__name__ # Save the current list of attributes to keep after parsing. # The dict of self should be the same after parsing. _nodelete = list(set(self.__dict__.keys())) # Initiate the FileInput object for the input files. # Remember that self.filename can be a list of files. if not self.isstream: inputfile = openlogfile(self.filename) else: inputfile = self.stream # Intialize self.progress. if self.progress: inputfile.seek(0, 2) nstep = inputfile.tell() inputfile.seek(0) self.progress.initialize(nstep) self.progress.step = 0 if fupdate: self.fupdate = fupdate if cupdate: self.cupdate = cupdate # Initialize the ccData object that will be returned. # This is normally ccData, but can be changed by passing # the datatype argument to __init__(). data = self.datatype() # Copy the attribute list, so that the parser knows what to expect, # specifically in __setattr__(). # The class self.datatype (normally ccData) must have this attribute. self._attrlist = data._attrlist # Maybe the sub-class has something to do before parsing. self.before_parsing() # Loop over lines in the file object and call extract(). # This is where the actual parsing is done. for line in inputfile: self.updateprogress(inputfile, "Unsupported information", cupdate) # This call should check if the line begins a section of extracted data. # If it does, it parses some lines and sets the relevant attributes (to self). # Any attributes can be freely set and used across calls, however only those # in data._attrlist will be moved to final data object that is returned. self.extract(inputfile, line) # Close input file object. if not self.isstream: inputfile.close() # Maybe the sub-class has something to do after parsing. self.after_parsing() # If atomcoords were not parsed, but some input coordinates were ("inputcoords"). # This is originally from the Gaussian parser, a regression fix. if not hasattr(self, "atomcoords") and hasattr(self, "inputcoords"): self.atomcoords = numpy.array(self.inputcoords, 'd') # Set nmo if not set already - to nbasis. if not hasattr(self, "nmo") and hasattr(self, "nbasis"): self.nmo = self.nbasis # Creating deafult coreelectrons array. if not hasattr(self, "coreelectrons") and hasattr(self, "natom"): self.coreelectrons = numpy.zeros(self.natom, "i") # Move all cclib attributes to the ccData object. # To be moved, an attribute must be in data._attrlist. for attr in data._attrlist: if hasattr(self, attr): setattr(data, attr, getattr(self, attr)) # Now make sure that the cclib attributes in the data object # are all the correct type (including arrays and lists of arrays). data.arrayify() # Delete all temporary attributes (including cclib attributes). # All attributes should have been moved to a data object, # which will be returned. for attr in self.__dict__.keys(): if not attr in _nodelete: self.__delattr__(attr) # Update self.progress as done. if self.progress: self.progress.update(nstep, "Done") # Return the ccData object that was generated. return data def before_parsing(self): pass def after_parsing(self): pass def updateprogress(self, inputfile, msg, xupdate=0.05): """Update progress.""" if self.progress and random.random() < xupdate: newstep = inputfile.tell() if newstep != self.progress.step: self.progress.update(newstep, msg) self.progress.step = newstep def normalisesym(self, symlabel): """Standardise the symmetry labels between parsers. This method should be overwritten by individual parsers, and should contain appropriate doctests. If is not overwritten, this is detected as an error by unit tests. """ return "ERROR: This should be overwritten by this subclass" def float(self, number): """Convert a string to a float avoiding the problem with Ds. >>> t = Logfile("dummyfile") >>> t.float("123.2323E+02") 12323.23 >>> t.float("123.2323D+02") 12323.23 """ number = number.replace("D","E") return float(number) if __name__ == "__main__": import doctest doctest.testmod() GaussSum-2.2.6.1/gausssum/cclib/parser/adfparser.py0000664000175000017500000011240112117172552020647 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 1000 $" import numpy import logfileparser import utils class ADF(logfileparser.Logfile): """An ADF log file""" def __init__(self, *args, **kwargs): # Call the __init__ method of the superclass super(ADF, self).__init__(logname="ADF", *args, **kwargs) def __str__(self): """Return a string representation of the object.""" return "ADF log file %s" % (self.filename) def __repr__(self): """Return a representation of the object.""" return 'ADF("%s")' % (self.filename) def normalisesym(self, label): """Use standard symmetry labels instead of ADF labels. To normalise: (1) any periods are removed (except in the case of greek letters) (2) XXX is replaced by X, and a " added. (3) XX is replaced by X, and a ' added. (4) The greek letters Sigma, Pi, Delta and Phi are replaced by their lowercase equivalent. >>> sym = ADF("dummyfile").normalisesym >>> labels = ['A','s','A1','A1.g','Sigma','Pi','Delta','Phi','Sigma.g','A.g','AA','AAA','EE1','EEE1'] >>> map(sym,labels) ['A', 's', 'A1', 'A1g', 'sigma', 'pi', 'delta', 'phi', 'sigma.g', 'Ag', "A'", 'A"', "E1'", 'E1"'] """ greeks = ['Sigma', 'Pi', 'Delta', 'Phi'] for greek in greeks: if label.startswith(greek): return label.lower() ans = label.replace(".", "") if ans[1:3] == "''": temp = ans[0] + '"' ans = temp l = len(ans) if l > 1 and ans[0] == ans[1]: # Python only tests the second condition if the first is true if l > 2 and ans[1] == ans[2]: ans = ans.replace(ans[0]*3, ans[0]) + '"' else: ans = ans.replace(ans[0]*2, ans[0]) + "'" return ans def normalisedegenerates(self, label, num, ndict=None): """Generate a string used for matching degenerate orbital labels To normalise: (1) if label is E or T, return label:num (2) if label is P or D, look up in dict, and return answer """ if not ndict: ndict = { 'P': {0:"P:x", 1:"P:y", 2:"P:z"}, \ 'D': {0:"D:z2", 1:"D:x2-y2", 2:"D:xy", 3:"D:xz", 4:"D:yz"}} if ndict.has_key(label): if ndict[label].has_key(num): return ndict[label][num] else: return "%s:%i" % (label, num+1) else: return "%s:%i" % (label, num+1) def before_parsing(self): # Used to avoid extracting the final geometry twice in a GeoOpt self.NOTFOUND, self.GETLAST, self.NOMORE = range(3) self.finalgeometry = self.NOTFOUND # Used for calculating the scftarget (variables names taken from the ADF manual) self.accint = self.SCFconv = self.sconv2 = None # keep track of nosym and unrestricted case to parse Energies since it doens't have an all Irreps section self.nosymflag = False self.unrestrictedflag = False SCFCNV, SCFCNV2 = range(2) #used to index self.scftargets[] maxelem, norm = range(2) # used to index scf.values def extract(self, inputfile, line): """Extract information from the file object inputfile.""" if line.find("INPUT FILE") >= 0: #check to make sure we aren't parsing Create jobs while line: self.updateprogress(inputfile, "Unsupported Information", self.fupdate) if line.find("INPUT FILE") >=0 and hasattr(self,"scftargets"): #does this file contain multiple calculations? #if so, print a warning and skip to end of file self.logger.warning("Skipping remaining calculations") inputfile.seek(0, 2) break if line.find("INPUT FILE") >= 0: line2 = inputfile.next() else: line2 = None if line2 and len(line2) <= 2: #make sure that it's not blank like in the NiCO4 regression line2 = inputfile.next() if line2 and (line2.find("Create") < 0 and line2.find("create") < 0): break line = inputfile.next() if line[1:10] == "Symmetry:": info = line.split() if info[1] == "NOSYM": self.nosymflag = True # Use this to read the subspecies of irreducible representations. # It will be a list, with each element representing one irrep. if line.strip() == "Irreducible Representations, including subspecies": dashes = inputfile.next() self.irreps = [] line = inputfile.next() while line.strip() != "": self.irreps.append(line.split()) line = inputfile.next() if line[4:13] == 'Molecule:': info = line.split() if info[1] == 'UNrestricted': self.unrestrictedflag = True if line[1:6] == "ATOMS": # Find the number of atoms and their atomic numbers # Also extract the starting coordinates (for a GeoOpt anyway) # and the atommasses (previously called vibmasses) self.updateprogress(inputfile, "Attributes", self.cupdate) self.atomnos = [] self.atommasses = [] self.atomcoords = [] self.coreelectrons = [] underline = inputfile.next() #clear pointless lines label1 = inputfile.next() # label2 = inputfile.next() # line = inputfile.next() atomcoords = [] while len(line)>2: #ensure that we are reading no blank lines info = line.split() element = info[1].split('.')[0] self.atomnos.append(self.table.number[element]) atomcoords.append(map(float, info[2:5])) self.coreelectrons.append(int(float(info[5]) - float(info[6]))) self.atommasses.append(float(info[7])) line = inputfile.next() self.atomcoords.append(atomcoords) self.natom = len(self.atomnos) self.atomnos = numpy.array(self.atomnos, "i") if line[1:10] == "FRAGMENTS": header = inputfile.next() self.frags = [] self.fragnames = [] line = inputfile.next() while len(line) > 2: #ensure that we are reading no blank lines info = line.split() if len(info) == 7: #fragment name is listed here self.fragnames.append("%s_%s" % (info[1], info[0])) self.frags.append([]) self.frags[-1].append(int(info[2]) - 1) elif len(info) == 5: #add atoms into last fragment self.frags[-1].append(int(info[0]) - 1) line = inputfile.next() # Extract charge if line[1:11] == "Net Charge": self.charge = int(line.split()[2]) line = inputfile.next() if len(line.strip()): # Spin polar: 1 (Spin_A minus Spin_B electrons) self.mult = int(line.split()[2]) + 1 # (Not sure about this for higher multiplicities) else: self.mult = 1 if line[1:22] == "S C F U P D A T E S": # find targets for SCF convergence if not hasattr(self,"scftargets"): self.scftargets = [] #underline, blank, nr for i in range(3): inputfile.next() line = inputfile.next() self.SCFconv = float(line.split()[-1]) line = inputfile.next() self.sconv2 = float(line.split()[-1]) if line[1:11] == "CYCLE 1": self.updateprogress(inputfile, "QM convergence", self.fupdate) newlist = [] line = inputfile.next() if not hasattr(self,"geovalues"): # This is the first SCF cycle self.scftargets.append([self.sconv2*10, self.sconv2]) elif self.finalgeometry in [self.GETLAST, self.NOMORE]: # This is the final SCF cycle self.scftargets.append([self.SCFconv*10, self.SCFconv]) else: # This is an intermediate SCF cycle oldscftst = self.scftargets[-1][1] grdmax = self.geovalues[-1][1] scftst = max(self.SCFconv, min(oldscftst, grdmax/30, 10**(-self.accint))) self.scftargets.append([scftst*10, scftst]) while line.find("SCF CONVERGED") == -1 and line.find("SCF not fully converged, result acceptable") == -1 and line.find("SCF NOT CONVERGED") == -1: if line[4:12] == "SCF test": if not hasattr(self, "scfvalues"): self.scfvalues = [] info = line.split() newlist.append([float(info[4]), abs(float(info[6]))]) try: line = inputfile.next() except StopIteration: #EOF reached? self.logger.warning("SCF did not converge, so attributes may be missing") break if line.find("SCF not fully converged, result acceptable") > 0: self.logger.warning("SCF not fully converged, results acceptable") if line.find("SCF NOT CONVERGED") > 0: self.logger.warning("SCF did not converge! moenergies and mocoeffs are unreliable") if hasattr(self, "scfvalues"): self.scfvalues.append(newlist) # Parse SCF energy for SP calcs from bonding energy decomposition section. # It seems ADF does not print it earlier for SP calculations. # Geometry optimization runs also print this, and we want to parse it # for them, too, even if it repeats the last "Geometry Convergence Tests" # section (but it's usually a bit different). if line[:21] == "Total Bonding Energy:": if not hasattr(self, "scfenergies"): self.scfenergies = [] energy = utils.convertor(float(line.split()[3]), "hartree", "eV") self.scfenergies.append(energy) if line[51:65] == "Final Geometry": self.finalgeometry = self.GETLAST # Get the coordinates from each step of the GeoOpt. if line[1:24] == "Coordinates (Cartesian)" and self.finalgeometry in [self.NOTFOUND, self.GETLAST]: if not hasattr(self, "atomcoords"): self.atomcoords = [] equals = inputfile.next() blank = inputfile.next() title = inputfile.next() title = inputfile.next() hyphens = inputfile.next() atomcoords = [] line = inputfile.next() while line != hyphens: atomcoords.append(map(float, line.split()[5:8])) line = inputfile.next() self.atomcoords.append(atomcoords) if self.finalgeometry == self.GETLAST: # Don't get any more coordinates self.finalgeometry = self.NOMORE # Extract Geometry convergence information. if line[1:27] == 'Geometry Convergence Tests': if not hasattr(self, "geotargets"): self.geovalues = [] self.geotargets = numpy.array([0.0, 0.0, 0.0, 0.0, 0.0], "d") if not hasattr(self, "scfenergies"): self.scfenergies = [] equals = inputfile.next() blank = inputfile.next() line = inputfile.next() temp = inputfile.next().strip().split() self.scfenergies.append(utils.convertor(float(temp[-1]), "hartree", "eV")) for i in range(6): line = inputfile.next() values = [] for i in range(5): temp = inputfile.next().split() self.geotargets[i] = float(temp[-3]) values.append(float(temp[-4])) self.geovalues.append(values) if line[1:27] == 'General Accuracy Parameter': # Need to know the accuracy of the integration grid to # calculate the scftarget...note that it changes with time self.accint = float(line.split()[-1]) if line.find('Orbital Energies, per Irrep and Spin') > 0 and not hasattr(self, "mosyms") and self.nosymflag and not self.unrestrictedflag: #Extracting orbital symmetries and energies, homos for nosym case #Should only be for restricted case because there is a better text block for unrestricted and nosym self.mosyms = [[]] self.moenergies = [[]] underline = inputfile.next() header = inputfile.next() underline = inputfile.next() label = inputfile.next() line = inputfile.next() info = line.split() if not info[0] == '1': self.logger.warning("MO info up to #%s is missing" % info[0]) #handle case where MO information up to a certain orbital are missing while int(info[0]) - 1 != len(self.moenergies[0]): self.moenergies[0].append(99999) self.mosyms[0].append('A') homoA = None while len(line) > 10: info = line.split() self.mosyms[0].append('A') self.moenergies[0].append(utils.convertor(float(info[2]), 'hartree', 'eV')) if info[1] == '0.000' and not hasattr(self, 'homos'): self.homos = [len(self.moenergies[0]) - 2] line = inputfile.next() self.moenergies = [numpy.array(self.moenergies[0], "d")] self.homos = numpy.array(self.homos, "i") if line[1:29] == 'Orbital Energies, both Spins' and not hasattr(self, "mosyms") and self.nosymflag and self.unrestrictedflag: #Extracting orbital symmetries and energies, homos for nosym case #should only be here if unrestricted and nosym self.mosyms = [[], []] moenergies = [[], []] underline = inputfile.next() blank = inputfile.next() header = inputfile.next() underline = inputfile.next() line = inputfile.next() homoa = 0 homob = None while len(line) > 5: info = line.split() if info[2] == 'A': self.mosyms[0].append('A') moenergies[0].append(utils.convertor(float(info[4]), 'hartree', 'eV')) if info[3] != '0.00': homoa = len(moenergies[0]) - 1 elif info[2] == 'B': self.mosyms[1].append('A') moenergies[1].append(utils.convertor(float(info[4]), 'hartree', 'eV')) if info[3] != '0.00': homob = len(moenergies[1]) - 1 else: print "Error reading line: %s" % line line = inputfile.next() self.moenergies = [numpy.array(x, "d") for x in moenergies] self.homos = numpy.array([homoa, homob], "i") if line[1:29] == 'Orbital Energies, all Irreps' and not hasattr(self, "mosyms"): #Extracting orbital symmetries and energies, homos self.mosyms = [[]] self.symlist = {} self.moenergies = [[]] underline = inputfile.next() blank = inputfile.next() header = inputfile.next() underline2 = inputfile.next() line = inputfile.next() homoa = None homob = None #multiple = {'E':2, 'T':3, 'P':3, 'D':5} # The above is set if there are no special irreps names = [irrep[0].split(':')[0] for irrep in self.irreps] counts = [len(irrep) for irrep in self.irreps] multiple = dict(zip(names, counts)) irrepspecies = {} for n in range(len(names)): indices = range(counts[n]) subspecies = self.irreps[n] irrepspecies[names[n]] = dict(zip(indices, subspecies)) while line.strip(): info = line.split() if len(info) == 5: #this is restricted #count = multiple.get(info[0][0],1) count = multiple.get(info[0], 1) for repeat in range(count): # i.e. add E's twice, T's thrice self.mosyms[0].append(self.normalisesym(info[0])) self.moenergies[0].append(utils.convertor(float(info[3]), 'hartree', 'eV')) sym = info[0] if count > 1: # add additional sym label sym = self.normalisedegenerates(info[0], repeat, ndict=irrepspecies) try: self.symlist[sym][0].append(len(self.moenergies[0])-1) except KeyError: self.symlist[sym] = [[]] self.symlist[sym][0].append(len(self.moenergies[0])-1) if info[2] == '0.00' and not hasattr(self, 'homos'): self.homos = [len(self.moenergies[0]) - (count + 1)] #count, because need to handle degenerate cases line = inputfile.next() elif len(info) == 6: #this is unrestricted if len(self.moenergies) < 2: #if we don't have space, create it self.moenergies.append([]) self.mosyms.append([]) # count = multiple.get(info[0][0], 1) count = multiple.get(info[0], 1) if info[2] == 'A': for repeat in range(count): # i.e. add E's twice, T's thrice self.mosyms[0].append(self.normalisesym(info[0])) self.moenergies[0].append(utils.convertor(float(info[4]), 'hartree', 'eV')) sym = info[0] if count > 1: #add additional sym label sym = self.normalisedegenerates(info[0], repeat) try: self.symlist[sym][0].append(len(self.moenergies[0])-1) except KeyError: self.symlist[sym] = [[], []] self.symlist[sym][0].append(len(self.moenergies[0])-1) if info[3] == '0.00' and homoa == None: homoa = len(self.moenergies[0]) - (count + 1) #count because degenerate cases need to be handled if info[2] == 'B': for repeat in range(count): # i.e. add E's twice, T's thrice self.mosyms[1].append(self.normalisesym(info[0])) self.moenergies[1].append(utils.convertor(float(info[4]), 'hartree', 'eV')) sym = info[0] if count > 1: #add additional sym label sym = self.normalisedegenerates(info[0], repeat) try: self.symlist[sym][1].append(len(self.moenergies[1])-1) except KeyError: self.symlist[sym] = [[], []] self.symlist[sym][1].append(len(self.moenergies[1])-1) if info[3] == '0.00' and homob == None: homob = len(self.moenergies[1]) - (count + 1) line = inputfile.next() else: #different number of lines print "Error", info if len(info) == 6: #still unrestricted, despite being out of loop self.homos = [homoa, homob] self.moenergies = [numpy.array(x, "d") for x in self.moenergies] self.homos = numpy.array(self.homos, "i") if line[1:28] == "Vibrations and Normal Modes": # Section on extracting vibdisps # Also contains vibfreqs, but these are extracted in the # following section (see below) self.vibdisps = [] equals = inputfile.next() blank = inputfile.next() header = inputfile.next() header = inputfile.next() blank = inputfile.next() blank = inputfile.next() freqs = inputfile.next() while freqs.strip()!="": minus = inputfile.next() p = [ [], [], [] ] for i in range(len(self.atomnos)): broken = map(float, inputfile.next().split()[1:]) for j in range(0, len(broken), 3): p[j/3].append(broken[j:j+3]) self.vibdisps.extend(p[:(len(broken)/3)]) blank = inputfile.next() blank = inputfile.next() freqs = inputfile.next() self.vibdisps = numpy.array(self.vibdisps, "d") if line[1:24] == "List of All Frequencies": # Start of the IR/Raman frequency section self.updateprogress(inputfile, "Frequency information", self.fupdate) # self.vibsyms = [] # Need to look into this a bit more self.vibirs = [] self.vibfreqs = [] for i in range(8): line = inputfile.next() line = inputfile.next().strip() while line: temp = line.split() self.vibfreqs.append(float(temp[0])) self.vibirs.append(float(temp[2])) # or is it temp[1]? line = inputfile.next().strip() self.vibfreqs = numpy.array(self.vibfreqs, "d") self.vibirs = numpy.array(self.vibirs, "d") if hasattr(self, "vibramans"): self.vibramans = numpy.array(self.vibramans, "d") #******************************************************************************************************************8 #delete this after new implementation using smat, eigvec print,eprint? if line[1:49] == "Total nr. of (C)SFOs (summation over all irreps)": # Extract the number of basis sets self.nbasis = int(line.split(":")[1].split()[0]) # now that we're here, let's extract aonames self.fonames = [] self.start_indeces = {} blank = inputfile.next() note = inputfile.next() symoffset = 0 blank = inputfile.next() blank = inputfile.next() if len(blank) > 2: #fix for ADF2006.01 as it has another note blank = inputfile.next() blank = inputfile.next() blank = inputfile.next() self.nosymreps = [] while len(self.fonames) < self.nbasis: symline = inputfile.next() sym = symline.split()[1] line = inputfile.next() num = int(line.split(':')[1].split()[0]) self.nosymreps.append(num) #read until line "--------..." is found while line.find('-----') < 0: line = inputfile.next() line = inputfile.next() # the start of the first SFO while len(self.fonames) < symoffset + num: info = line.split() #index0 index1 occ2 energy3/4 fragname5 coeff6 orbnum7 orbname8 fragname9 if not sym in self.start_indeces.keys(): #have we already set the start index for this symmetry? self.start_indeces[sym] = int(info[1]) orbname = info[8] orbital = info[7] + orbname.replace(":", "") fragname = info[5] frag = fragname + info[9] coeff = float(info[6]) line = inputfile.next() while line.strip() and not line[:7].strip(): # while it's the same SFO # i.e. while not completely blank, but blank at the start info = line[43:].split() if len(info)>0: # len(info)==0 for the second line of dvb_ir.adfout frag += "+" + fragname + info[-1] coeff = float(info[-4]) if coeff < 0: orbital += '-' + info[-3] + info[-2].replace(":", "") else: orbital += '+' + info[-3] + info[-2].replace(":", "") line = inputfile.next() # At this point, we are either at the start of the next SFO or at # a blank line...the end self.fonames.append("%s_%s" % (frag, orbital)) symoffset += num # blankline blankline inputfile.next(); inputfile.next() if line[1:32] == "S F O P O P U L A T I O N S ,": #Extract overlap matrix # self.fooverlaps = numpy.zeros((self.nbasis, self.nbasis), "d") symoffset = 0 for nosymrep in self.nosymreps: line = inputfile.next() while line.find('===') < 10: #look for the symmetry labels line = inputfile.next() #blank blank text blank col row blank = inputfile.next() blank = inputfile.next() text = inputfile.next() if text[13:20] != "Overlap": # verify this has overlap info break col = inputfile.next() row = inputfile.next() if not hasattr(self,"fooverlaps"): # make sure there is a matrix to store this self.fooverlaps = numpy.zeros((self.nbasis, self.nbasis), "d") base = 0 while base < nosymrep: #have we read all the columns? for i in range(nosymrep - base): self.updateprogress(inputfile, "Overlap", self.fupdate) line = inputfile.next() parts = line.split()[1:] for j in range(len(parts)): k = float(parts[j]) self.fooverlaps[base + symoffset + j, base + symoffset +i] = k self.fooverlaps[base + symoffset + i, base + symoffset + j] = k #blank, blank, column for i in range(3): inputfile.next() base += 4 symoffset += nosymrep base = 0 # The commented code below makes the atombasis attribute based on the BAS function in ADF, # but this is probably not so useful, since SFOs are used to build MOs in ADF. # if line[1:54] == "BAS: List of all Elementary Cartesian Basis Functions": # # self.atombasis = [] # # # There will be some text, followed by a line: # # (power of) X Y Z R Alpha on Atom # while not line[1:11] == "(power of)": # line = inputfile.next() # dashes = inputfile.next() # blank = inputfile.next() # line = inputfile.next() # # There will be two blank lines when there are no more atom types. # while line.strip() != "": # atoms = [int(i)-1 for i in line.split()[1:]] # for n in range(len(atoms)): # self.atombasis.append([]) # dashes = inputfile.next() # line = inputfile.next() # while line.strip() != "": # indices = [int(i)-1 for i in line.split()[5:]] # for i in range(len(indices)): # self.atombasis[atoms[i]].append(indices[i]) # line = inputfile.next() # line = inputfile.next() if line[48:67] == "SFO MO coefficients": self.mocoeffs = [numpy.zeros((self.nbasis, self.nbasis), "d")] spin = 0 symoffset = 0 lastrow = 0 # Section ends with "1" at beggining of a line. while line[0] != "1": line = inputfile.next() # If spin is specified, then there will be two coefficient matrices. if line.strip() == "***** SPIN 1 *****": self.mocoeffs = [numpy.zeros((self.nbasis, self.nbasis), "d"), numpy.zeros((self.nbasis, self.nbasis), "d")] # Bump up the spin. if line.strip() == "***** SPIN 2 *****": spin = 1 symoffset = 0 lastrow = 0 # Next symmetry. if line.strip()[:4] == "=== ": sym = line.split()[1] if self.nosymflag: aolist = range(self.nbasis) else: aolist = self.symlist[sym][spin] # Add to the symmetry offset of AO ordering. symoffset += lastrow # Blocks with coefficient always start with "MOs :". if line[1:6] == "MOs :": # Next line has the MO index contributed to. monumbers = [int(n) for n in line[6:].split()] occup = inputfile.next() label = inputfile.next() line = inputfile.next() # The table can end with a blank line or "1". row = 0 while not line.strip() in ["", "1"]: info = line.split() if int(info[0]) < self.start_indeces[sym]: #check to make sure we aren't parsing CFs line = inputfile.next() continue self.updateprogress(inputfile, "Coefficients", self.fupdate) row += 1 coeffs = [float(x) for x in info[1:]] moindices = [aolist[n-1] for n in monumbers] # The AO index is 1 less than the row. aoindex = symoffset + row - 1 for i in range(len(monumbers)): self.mocoeffs[spin][moindices[i], aoindex] = coeffs[i] line = inputfile.next() lastrow = row if line[4:53] == "Final excitation energies from Davidson algorithm": # move forward in file past some various algorthm info # * Final excitation energies from Davidson algorithm * # * * # ************************************************************************** # Number of loops in Davidson routine = 20 # Number of matrix-vector multiplications = 24 # Type of excitations = SINGLET-SINGLET for i in range(8): inputfile.next() symm = self.normalisesym(inputfile.next().split()[1]) # move forward in file past some more txt and header info # Excitation energies E in a.u. and eV, dE wrt prev. cycle, # oscillator strengths f in a.u. # no. E/a.u. E/eV f dE/a.u. # ----------------------------------------------------- for i in range(6): inputfile.next() # now start parsing etenergies and etoscs etenergies = [] etoscs = [] etsyms = [] line = inputfile.next() while len(line) > 2: info = line.split() etenergies.append(utils.convertor(float(info[2]), "eV", "cm-1")) etoscs.append(float(info[3])) etsyms.append(symm) line = inputfile.next() # move past next section while line[1:53] != "Major MO -> MO transitions for the above excitations": line = inputfile.next() # move past headers # Excitation Occupied to virtual Contribution # Nr. orbitals weight contribibutions to # (sum=1) transition dipole moment # x y z for i in range(6): inputfile.next() # before we start handeling transitions, we need # to create mosyms with indices # only restricted calcs are possible in ADF counts = {} syms = [] for mosym in self.mosyms[0]: if counts.keys().count(mosym) == 0: counts[mosym] = 1 else: counts[mosym] += 1 syms.append(str(counts[mosym]) + mosym) import re etsecs = [] printed_warning = False for i in range(len(etenergies)): etsec = [] line = inputfile.next() info = line.split() while len(info) > 0: match = re.search('[^0-9]', info[1]) index1 = int(info[1][:match.start(0)]) text = info[1][match.start(0):] symtext = text[0].upper() + text[1:] sym1 = str(index1) + self.normalisesym(symtext) match = re.search('[^0-9]', info[3]) index2 = int(info[3][:match.start(0)]) text = info[3][match.start(0):] symtext = text[0].upper() + text[1:] sym2 = str(index2) + self.normalisesym(symtext) try: index1 = syms.index(sym1) except ValueError: if not printed_warning: self.logger.warning("Etsecs are not accurate!") printed_warning = True try: index2 = syms.index(sym2) except ValueError: if not printed_warning: self.logger.warning("Etsecs are not accurate!") printed_warning = True etsec.append([(index1, 0), (index2, 0), float(info[4])]) line = inputfile.next() info = line.split() etsecs.append(etsec) if not hasattr(self, "etenergies"): self.etenergies = etenergies else: self.etenergies += etenergies if not hasattr(self, "etoscs"): self.etoscs = etoscs else: self.etoscs += etoscs if not hasattr(self, "etsyms"): self.etsyms = etsyms else: self.etsyms += etsyms if not hasattr(self, "etsecs"): self.etsecs = etsecs else: self.etsecs += etsecs if "M U L L I K E N P O P U L A T I O N S" in line: if not hasattr(self, "atomcharges"): self.atomcharges = {} while line[1:5] != "Atom": line = inputfile.next() dashes = inputfile.next() mulliken = [] line = inputfile.next() while line.strip(): mulliken.append(float(line.split()[2])) line = inputfile.next() self.atomcharges["mulliken"] = mulliken if __name__ == "__main__": import doctest, adfparser doctest.testmod(adfparser, verbose=False) GaussSum-2.2.6.1/gausssum/cclib/parser/gamessparser.py0000664000175000017500000015021512117172552021401 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 1030 $" import re import numpy import logfileparser import utils class GAMESS(logfileparser.Logfile): """A GAMESS log file.""" SCFRMS, SCFMAX, SCFENERGY = range(3) # Used to index self.scftargets[] def __init__(self, *args, **kwargs): # Call the __init__ method of the superclass super(GAMESS, self).__init__(logname="GAMESS", *args, **kwargs) def __str__(self): """Return a string representation of the object.""" return "GAMESS log file %s" % (self.filename) def __repr__(self): """Return a representation of the object.""" return 'GAMESS("%s")' % (self.filename) def normalisesym(self, label): """Normalise the symmetries used by GAMESS. To normalise, two rules need to be applied: (1) Occurences of U/G in the 2/3 position of the label must be lower-cased (2) Two single quotation marks must be replaced by a double >>> t = GAMESS("dummyfile").normalisesym >>> labels = ['A', 'A1', 'A1G', "A'", "A''", "AG"] >>> answers = map(t, labels) >>> print answers ['A', 'A1', 'A1g', "A'", 'A"', 'Ag'] """ if label[1:] == "''": end = '"' else: end = label[1:].replace("U", "u").replace("G", "g") return label[0] + end def before_parsing(self): self.firststdorient = True # Used to decide whether to wipe the atomcoords clean self.geooptfinished = False # Used to avoid extracting the final geometry twice self.cihamtyp = "none" # Type of CI Hamiltonian: saps or dets. self.scftype = "none" # Type of SCF calculation: BLYP, RHF, ROHF, etc. def extract(self, inputfile, line): """Extract information from the file object inputfile.""" if line [1:12] == "INPUT CARD>": return # We are looking for this line: # PARAMETERS CONTROLLING GEOMETRY SEARCH ARE # ... # OPTTOL = 1.000E-04 RMIN = 1.500E-03 if line[10:18] == "OPTTOL =": if not hasattr(self, "geotargets"): opttol = float(line.split()[2]) self.geotargets = numpy.array([opttol, 3. / opttol], "d") if line.find("FINAL") == 1: if not hasattr(self, "scfenergies"): self.scfenergies = [] # Has to deal with such lines as: # FINAL R-B3LYP ENERGY IS -382.0507446475 AFTER 10 ITERATIONS # FINAL ENERGY IS -379.7594673378 AFTER 9 ITERATIONS # ...so take the number after the "IS" temp = line.split() self.scfenergies.append(utils.convertor(float(temp[temp.index("IS") + 1]), "hartree", "eV")) # Total energies after Moller-Plesset corrections if (line.find("RESULTS OF MOLLER-PLESSET") >= 0 or line[6:37] == "SCHWARZ INEQUALITY TEST SKIPPED"): # Output looks something like this: # RESULTS OF MOLLER-PLESSET 2ND ORDER CORRECTION ARE # E(0)= -285.7568061536 # E(1)= 0.0 # E(2)= -0.9679419329 # E(MP2)= -286.7247480864 # where E(MP2) = E(0) + E(2) # # with GAMESS-US 12 Jan 2009 (R3) the preceding text is different: ## DIRECT 4-INDEX TRANSFORMATION ## SCHWARZ INEQUALITY TEST SKIPPED 0 INTEGRAL BLOCKS ## E(SCF)= -76.0088477471 ## E(2)= -0.1403745370 ## E(MP2)= -76.1492222841 if not hasattr(self, "mpenergies"): self.mpenergies = [] # Each iteration has a new print-out self.mpenergies.append([]) # GAMESS-US presently supports only second order corrections (MP2) # PC GAMESS also has higher levels (3rd and 4th), with different output # Only the highest level MP4 energy is gathered (SDQ or SDTQ) while re.search("DONE WITH MP(\d) ENERGY", line) is None: line = inputfile.next() if len(line.split()) > 0: # Only up to MP2 correction if line.split()[0] == "E(MP2)=": mp2energy = float(line.split()[1]) self.mpenergies[-1].append(utils.convertor(mp2energy, "hartree", "eV")) # MP2 before higher order calculations if line.split()[0] == "E(MP2)": mp2energy = float(line.split()[2]) self.mpenergies[-1].append(utils.convertor(mp2energy, "hartree", "eV")) if line.split()[0] == "E(MP3)": mp3energy = float(line.split()[2]) self.mpenergies[-1].append(utils.convertor(mp3energy, "hartree", "eV")) if line.split()[0] in ["E(MP4-SDQ)", "E(MP4-SDTQ)"]: mp4energy = float(line.split()[2]) self.mpenergies[-1].append(utils.convertor(mp4energy, "hartree", "eV")) # Total energies after Coupled Cluster calculations # Only the highest Coupled Cluster level result is gathered if line[12:23] == "CCD ENERGY:": if not hasattr(self, "ccenergies"): self.ccenergies = [] ccenergy = float(line.split()[2]) self.ccenergies.append(utils.convertor(ccenergy, "hartree", "eV")) if line.find("CCSD") >= 0 and line.split()[0:2] == ["CCSD", "ENERGY:"]: if not hasattr(self, "ccenergies"): self.ccenergies = [] ccenergy = float(line.split()[2]) line = inputfile.next() if line[8:23] == "CCSD[T] ENERGY:": ccenergy = float(line.split()[2]) line = inputfile.next() if line[8:23] == "CCSD(T) ENERGY:": ccenergy = float(line.split()[2]) self.ccenergies.append(utils.convertor(ccenergy, "hartree", "eV")) # Also collect MP2 energies, which are always calculated before CC if line [8:23] == "MBPT(2) ENERGY:": if not hasattr(self, "mpenergies"): self.mpenergies = [] self.mpenergies.append([]) mp2energy = float(line.split()[2]) self.mpenergies[-1].append(utils.convertor(mp2energy, "hartree", "eV")) # Extract charge and multiplicity if line[1:19] == "CHARGE OF MOLECULE": self.charge = int(line.split()[-1]) self.mult = int(inputfile.next().split()[-1]) # etenergies (used only for CIS runs now) if "EXCITATION ENERGIES" in line and line.find("DONE WITH") < 0: if not hasattr(self, "etenergies"): self.etenergies = [] header = inputfile.next().rstrip() get_etosc = False if header.endswith("OSC. STR."): # water_cis_dets.out does not have the oscillator strength # in this table...it is extracted from a different section below get_etosc = True self.etoscs = [] dashes = inputfile.next() line = inputfile.next() broken = line.split() while len(broken) > 0: # Take hartree value with more numbers, and convert. # Note that the values listed after this are also less exact! etenergy = float(broken[1]) self.etenergies.append(utils.convertor(etenergy, "hartree", "cm-1")) if get_etosc: etosc = float(broken[-1]) self.etoscs.append(etosc) broken = inputfile.next().split() # Detect the CI hamiltonian type, if applicable. # Should always be detected if CIS is done. if line[8:64] == "RESULTS FROM SPIN-ADAPTED ANTISYMMETRIZED PRODUCT (SAPS)": self.cihamtyp = "saps" if line[8:64] == "RESULTS FROM DETERMINANT BASED ATOMIC ORBITAL CI-SINGLES": self.cihamtyp = "dets" # etsecs (used only for CIS runs for now) if line[1:14] == "EXCITED STATE": if not hasattr(self, 'etsecs'): self.etsecs = [] if not hasattr(self, 'etsyms'): self.etsyms = [] statenumber = int(line.split()[2]) spin = int(float(line.split()[7])) if spin == 0: sym = "Singlet" if spin == 1: sym = "Triplet" sym += '-' + line.split()[-1] self.etsyms.append(sym) # skip 5 lines for i in range(5): line = inputfile.next() line = inputfile.next() CIScontribs = [] while line.strip()[0] != "-": MOtype = 0 # alpha/beta are specified for hamtyp=dets if self.cihamtyp == "dets": if line.split()[0] == "BETA": MOtype = 1 fromMO = int(line.split()[-3])-1 toMO = int(line.split()[-2])-1 coeff = float(line.split()[-1]) # With the SAPS hamiltonian, the coefficients are multiplied # by sqrt(2) so that they normalize to 1. # With DETS, both alpha and beta excitations are printed. # if self.cihamtyp == "saps": # coeff /= numpy.sqrt(2.0) CIScontribs.append([(fromMO,MOtype), (toMO,MOtype), coeff]) line = inputfile.next() self.etsecs.append(CIScontribs) # etoscs (used only for CIS runs now) if line[1:50] == "TRANSITION FROM THE GROUND STATE TO EXCITED STATE": if not hasattr(self, "etoscs"): self.etoscs = [] statenumber = int(line.split()[-1]) # skip 7 lines for i in range(8): line = inputfile.next() strength = float(line.split()[3]) self.etoscs.append(strength) # TD-DFT for GAMESS-US. # The format for excitations has changed a bit between 2007 and 2012. # Original format parser was written for: # # ------------------- # TRIPLET EXCITATIONS # ------------------- # # STATE # 1 ENERGY = 3.027228 EV # OSCILLATOR STRENGTH = 0.000000 # DRF COEF OCC VIR # --- ---- --- --- # 35 -1.105383 35 -> 36 # 69 -0.389181 34 -> 37 # 103 -0.405078 33 -> 38 # 137 0.252485 32 -> 39 # 168 -0.158406 28 -> 40 # # STATE # 2 ENERGY = 4.227763 EV # ... # # Here is the corresponding 2012 version: # # ------------------- # TRIPLET EXCITATIONS # ------------------- # # STATE # 1 ENERGY = 3.027297 EV # OSCILLATOR STRENGTH = 0.000000 # LAMBDA DIAGNOSTIC = 0.925 (RYDBERG/CHARGE TRANSFER CHARACTER) # SYMMETRY OF STATE = A # EXCITATION DE-EXCITATION # OCC VIR AMPLITUDE AMPLITUDE # I A X(I->A) Y(A->I) # --- --- -------- -------- # 35 36 -0.929190 -0.176167 # 34 37 -0.279823 -0.109414 # ... # # We discern these two by the presence of the arrow in the old version. # # The "LET EXCITATIONS" pattern used below catches both # singlet and triplet excitations output. if line[14:29] == "LET EXCITATIONS": self.etenergies = [] self.etoscs = [] self.etsecs = [] etsyms = [] minuses = inputfile.next() blanks = inputfile.next() # Loop while states are still being printed. line = inputfile.next() while line[1:6] == "STATE": if self.progress: self.updateprogress(inputfile, "Excited States") etenergy = utils.convertor(float(line.split()[-2]), "eV", "cm-1") etoscs = float(inputfile.next().split()[-1]) self.etenergies.append(etenergy) self.etoscs.append(etoscs) # Symmetry is not always present, especially in old versions. # Newer versions, on the other hand, can also provide a line # with lambda diagnostic and some extra headers. line = inputfile.next() if "LAMBDA DIAGNOSTIC" in line: line = inputfile.next() if "SYMMETRY" in line: etsyms.append(line.split()[-1]) line = inputfile.next() if "EXCITATION" in line and "DE-EXCITATION" in line: line = inputfile.next() if line.count("AMPLITUDE") == 2: line = inputfile.next() minuses = inputfile.next() CIScontribs = [] line = inputfile.next() while line.strip(): cols = line.split() if "->" in line: i_occ_vir = [2, 4] i_coeff = 1 else: i_occ_vir = [0, 1] i_coeff = 2 fromMO, toMO = [int(cols[i]) - 1 for i in i_occ_vir] coeff = float(cols[i_coeff]) CIScontribs.append([(fromMO, 0), (toMO, 0), coeff]) line = inputfile.next() self.etsecs.append(CIScontribs) line = inputfile.next() # The symmetries are not always present. if etsyms: self.etsyms = etsyms # Maximum and RMS gradients. if "MAXIMUM GRADIENT" in line or "RMS GRADIENT" in line: parts = line.split() # Avoid parsing the following... ## YOU SHOULD RESTART "OPTIMIZE" RUNS WITH THE COORDINATES ## WHOSE ENERGY IS LOWEST. RESTART "SADPOINT" RUNS WITH THE ## COORDINATES WHOSE RMS GRADIENT IS SMALLEST. THESE ARE NOT ## ALWAYS THE LAST POINT COMPUTED! if parts[0] not in ["MAXIMUM", "RMS", "(1)"]: return if not hasattr(self, "geovalues"): self.geovalues = [] # Newer versions (around 2006) have both maximum and RMS on one line: # MAXIMUM GRADIENT = 0.0531540 RMS GRADIENT = 0.0189223 if len(parts) == 8: maximum = float(parts[3]) rms = float(parts[7]) # In older versions of GAMESS, this spanned two lines, like this: # MAXIMUM GRADIENT = 0.057578167 # RMS GRADIENT = 0.027589766 if len(parts) == 4: maximum = float(parts[3]) line = inputfile.next() parts = line.split() rms = float(parts[3]) # FMO also prints two final one- and two-body gradients (see exam37): # (1) MAXIMUM GRADIENT = 0.0531540 RMS GRADIENT = 0.0189223 if len(parts) == 9: maximum = float(parts[4]) rms = float(parts[8]) self.geovalues.append([maximum, rms]) if line[11:50] == "ATOMIC COORDINATES": # This is the input orientation, which is the only data available for # SP calcs, but which should be overwritten by the standard orientation # values, which is the only information available for all geoopt cycles. if not hasattr(self, "atomcoords"): self.atomcoords = [] self.atomnos = [] line = inputfile.next() atomcoords = [] atomnos = [] line = inputfile.next() while line.strip(): temp = line.strip().split() atomcoords.append([utils.convertor(float(x), "bohr", "Angstrom") for x in temp[2:5]]) atomnos.append(int(round(float(temp[1])))) # Don't use the atom name as this is arbitary line = inputfile.next() self.atomnos = numpy.array(atomnos, "i") self.atomcoords.append(atomcoords) if line[12:40] == "EQUILIBRIUM GEOMETRY LOCATED": # Prevent extraction of the final geometry twice self.geooptfinished = True if line[1:29] == "COORDINATES OF ALL ATOMS ARE" and not self.geooptfinished: # This is the standard orientation, which is the only coordinate # information available for all geometry optimisation cycles. # The input orientation will be overwritten if this is a geometry optimisation # We assume that a previous Input Orientation has been found and # used to extract the atomnos if self.progress: self.updateprogress(inputfile, "Coordinates") if self.firststdorient: self.firststdorient = False # Wipes out the single input coordinate at the start of the file self.atomcoords = [] line = inputfile.next() hyphens = inputfile.next() atomcoords = [] line = inputfile.next() for i in range(self.natom): temp = line.strip().split() atomcoords.append(map(float, temp[2:5])) line = inputfile.next() self.atomcoords.append(atomcoords) # Section with SCF information. # # The space at the start of the search string is to differentiate from MCSCF. # Everything before the search string is stored as the type of SCF. # SCF types may include: BLYP, RHF, ROHF, UHF, etc. # # For example, in exam17 the section looks like this (note that this is GVB): # ------------------------ # ROHF-GVB SCF CALCULATION # ------------------------ # GVB STEP WILL USE 119875 WORDS OF MEMORY. # # MAXIT= 30 NPUNCH= 2 SQCDF TOL=1.0000E-05 # NUCLEAR ENERGY= 6.1597411978 # EXTRAP=T DAMP=F SHIFT=F RSTRCT=F DIIS=F SOSCF=F # # ITER EX TOTAL ENERGY E CHANGE SQCDF DIIS ERROR # 0 0 -38.298939963 -38.298939963 0.131784454 0.000000000 # 1 1 -38.332044339 -0.033104376 0.026019716 0.000000000 # ... and will be terminated by a blank line. if line.rstrip()[-16:] == " SCF CALCULATION": # Remember the type of SCF. self.scftype = line.strip()[:-16] dashes = inputfile.next() while line [:5] != " ITER": if self.progress: self.updateprogress(inputfile, "Attributes") # GVB uses SQCDF for checking convergence (for example in exam17). if "GVB" in self.scftype and "SQCDF TOL=" in line: scftarget = float(line.split("=")[-1]) # Normally however the density is used as the convergence criterium. # Deal with various versions: # (GAMESS VERSION = 12 DEC 2003) # DENSITY MATRIX CONV= 2.00E-05 DFT GRID SWITCH THRESHOLD= 3.00E-04 # (GAMESS VERSION = 22 FEB 2006) # DENSITY MATRIX CONV= 1.00E-05 # (PC GAMESS version 6.2, Not DFT?) # DENSITY CONV= 1.00E-05 elif "DENSITY CONV" in line or "DENSITY MATRIX CONV" in line: scftarget = float(line.split()[-1]) line = inputfile.next() if not hasattr(self, "scftargets"): self.scftargets = [] self.scftargets.append([scftarget]) if not hasattr(self,"scfvalues"): self.scfvalues = [] line = inputfile.next() # Normally the iteration print in 6 columns. # For ROHF, however, it is 5 columns, thus this extra parameter. if "ROHF" in self.scftype: valcol = 4 else: valcol = 5 # SCF iterations are terminated by a blank line. # The first four characters usually contains the step number. # However, lines can also contain messages, including: # * * * INITIATING DIIS PROCEDURE * * * # CONVERGED TO SWOFF, SO DFT CALCULATION IS NOW SWITCHED ON # DFT CODE IS SWITCHING BACK TO THE FINER GRID values = [] while line.strip(): try: temp = int(line[0:4]) except ValueError: pass else: values.append([float(line.split()[valcol])]) line = inputfile.next() self.scfvalues.append(values) # Extract normal coordinate analysis, including vibrational frequencies (vibfreq), # IT intensities (vibirs) and displacements (vibdisps). # # This section typically looks like the following in GAMESS-US: # # MODES 1 TO 6 ARE TAKEN AS ROTATIONS AND TRANSLATIONS. # # FREQUENCIES IN CM**-1, IR INTENSITIES IN DEBYE**2/AMU-ANGSTROM**2, # REDUCED MASSES IN AMU. # # 1 2 3 4 5 # FREQUENCY: 52.49 41.45 17.61 9.23 10.61 # REDUCED MASS: 3.92418 3.77048 5.43419 6.44636 5.50693 # IR INTENSITY: 0.00013 0.00001 0.00004 0.00000 0.00003 # # ...or in the case of a numerical Hessian job... # # MODES 1 TO 5 ARE TAKEN AS ROTATIONS AND TRANSLATIONS. # # FREQUENCIES IN CM**-1, IR INTENSITIES IN DEBYE**2/AMU-ANGSTROM**2, # REDUCED MASSES IN AMU. # # 1 2 3 4 5 # FREQUENCY: 0.05 0.03 0.03 30.89 30.94 # REDUCED MASS: 8.50125 8.50137 8.50136 1.06709 1.06709 # # ...whereas PC-GAMESS has... # # MODES 1 TO 6 ARE TAKEN AS ROTATIONS AND TRANSLATIONS. # # FREQUENCIES IN CM**-1, IR INTENSITIES IN DEBYE**2/AMU-ANGSTROM**2 # # 1 2 3 4 5 # FREQUENCY: 5.89 1.46 0.01 0.01 0.01 # IR INTENSITY: 0.00000 0.00000 0.00000 0.00000 0.00000 # # If Raman is present we have (for PC-GAMESS)... # # MODES 1 TO 6 ARE TAKEN AS ROTATIONS AND TRANSLATIONS. # # FREQUENCIES IN CM**-1, IR INTENSITIES IN DEBYE**2/AMU-ANGSTROM**2 # RAMAN INTENSITIES IN ANGSTROM**4/AMU, DEPOLARIZATIONS ARE DIMENSIONLESS # # 1 2 3 4 5 # FREQUENCY: 5.89 1.46 0.04 0.03 0.01 # IR INTENSITY: 0.00000 0.00000 0.00000 0.00000 0.00000 # RAMAN INTENSITY: 12.675 1.828 0.000 0.000 0.000 # DEPOLARIZATION: 0.750 0.750 0.124 0.009 0.750 # # If GAMESS-US or PC-GAMESS has not reached the stationary point we have # and additional warning, repeated twice, like so (see n_water.log for an example): # # ******************************************************* # * THIS IS NOT A STATIONARY POINT ON THE MOLECULAR PES * # * THE VIBRATIONAL ANALYSIS IS NOT VALID !!! * # ******************************************************* # # There can also be additional warnings about the selection of modes, for example: # # * * * WARNING, MODE 6 HAS BEEN CHOSEN AS A VIBRATION # WHILE MODE12 IS ASSUMED TO BE A TRANSLATION/ROTATION. # PLEASE VERIFY THE PROGRAM'S DECISION MANUALLY! # if "NORMAL COORDINATE ANALYSIS IN THE HARMONIC APPROXIMATION" in line: self.vibfreqs = [] self.vibirs = [] self.vibdisps = [] # Need to get to the modes line, which is often preceeded by # a list of atomic weights and some possible warnings. # Pass the warnings to the logger if they are there. while not "MODES" in line: if self.progress: self.updateprogress(inputfile, "Frequency Information") line = inputfile.next() if "THIS IS NOT A STATIONARY POINT" in line: msg = "\n This is not a stationary point on the molecular PES" msg += "\n The vibrational analysis is not valid!!!" self.logger.warning(msg) if "* * * WARNING, MODE" in line: line1 = line.strip() line2 = inputfile.next().strip() line3 = inputfile.next().strip() self.logger.warning("\n " + "\n ".join((line1,line2,line3))) # In at least one case (regression zolm_dft3a.log) for older version of GAMESS-US, # the header concerning the range of nodes is formatted wrong and can look like so: # MODES 9 TO14 ARE TAKEN AS ROTATIONS AND TRANSLATIONS. # ... although it's unclear whether this happens for all two-digit values. startrot = int(line.split()[1]) if len(line.split()[2]) == 2: endrot = int(line.split()[3]) else: endrot = int(line.split()[2][2:]) blank = inputfile.next() line = inputfile.next() # This is to skip the output associated with symmetry analysis, fixes bug #3476063. if "ANALYZING SYMMETRY OF NORMAL MODES" in line: blank = inputfile.next() line = inputfile.next() while line != blank: line = inputfile.next() # Skip over FREQUENCIES, etc., and get past the possibly second warning. line = inputfile.next() while line != blank: line = inputfile.next() line = inputfile.next() if "*****" in line: while line != blank: line = inputfile.next() line = inputfile.next() while not "SAYVETZ" in line: if self.progress: self.updateprogress(inputfile, "Frequency Information") # Note: there may be imaginary frequencies like this (which we make negative): # FREQUENCY: 825.18 I 111.53 12.62 10.70 0.89 # # A note for debuggers: some of these frequencies will be removed later, # assumed to be translations or rotations (see startrot/endrot above). for col in inputfile.next().split()[1:]: if col == "I": self.vibfreqs[-1] *= -1 else: self.vibfreqs.append(float(col)) line = inputfile.next() # Skip the symmetry (appears in newer versions), fixes bug #3476063. if line.find("SYMMETRY") >= 0: line = inputfile.next() # Skip the reduced mass (not always present). if line.find("REDUCED") >= 0: line = inputfile.next() # Not present in numerical Hessian calculations. if line.find("IR INTENSITY") >= 0: irIntensity = map(float, line.strip().split()[2:]) self.vibirs.extend([utils.convertor(x, "Debye^2/amu-Angstrom^2", "km/mol") for x in irIntensity]) line = inputfile.next() # Read in Raman vibrational intensities if present. if line.find("RAMAN") >= 0: if not hasattr(self,"vibramans"): self.vibramans = [] ramanIntensity = line.strip().split() self.vibramans.extend(map(float, ramanIntensity[2:])) depolar = inputfile.next() line = inputfile.next() # This line seems always to be blank. assert line == blank # Extract the Cartesian displacement vectors. p = [ [], [], [], [], [] ] for j in range(self.natom): q = [ [], [], [], [], [] ] for coord in ['x', 'y', 'z']: cols = map(float, inputfile.next()[21:].split()) for i, val in enumerate(cols): q[i].append(val) for k in range(len(cols)): p[k].append(q[k]) self.vibdisps.extend(p[:len(cols)]) # Skip the Sayvetz stuff at the end. for j in range(10): line = inputfile.next() blank = inputfile.next() line = inputfile.next() # Exclude rotations and translations. self.vibfreqs = numpy.array(self.vibfreqs[:startrot-1]+self.vibfreqs[endrot:], "d") self.vibirs = numpy.array(self.vibirs[:startrot-1]+self.vibirs[endrot:], "d") self.vibdisps = numpy.array(self.vibdisps[:startrot-1]+self.vibdisps[endrot:], "d") if hasattr(self, "vibramans"): self.vibramans = numpy.array(self.vibramans[:startrot-1]+self.vibramans[endrot:], "d") if line[5:21] == "ATOMIC BASIS SET": self.gbasis = [] line = inputfile.next() while line.find("SHELL")<0: line = inputfile.next() blank = inputfile.next() atomname = inputfile.next() # shellcounter stores the shell no of the last shell # in the previous set of primitives shellcounter = 1 while line.find("TOTAL NUMBER")<0: blank = inputfile.next() line = inputfile.next() shellno = int(line.split()[0]) shellgap = shellno - shellcounter gbasis = [] # Stores basis sets on one atom shellsize = 0 while len(line.split())!=1 and line.find("TOTAL NUMBER")<0: shellsize += 1 coeff = {} # coefficients and symmetries for a block of rows while line.strip(): temp = line.strip().split() sym = temp[1] assert sym in ['S', 'P', 'D', 'F', 'G', 'L'] if sym == "L": # L refers to SP if len(temp)==6: # GAMESS US coeff.setdefault("S", []).append( (float(temp[3]), float(temp[4])) ) coeff.setdefault("P", []).append( (float(temp[3]), float(temp[5])) ) else: # PC GAMESS assert temp[6][-1] == temp[9][-1] == ')' coeff.setdefault("S", []).append( (float(temp[3]), float(temp[6][:-1])) ) coeff.setdefault("P", []).append( (float(temp[3]), float(temp[9][:-1])) ) else: if len(temp)==5: # GAMESS US coeff.setdefault(sym, []).append( (float(temp[3]), float(temp[4])) ) else: # PC GAMESS assert temp[6][-1] == ')' coeff.setdefault(sym, []).append( (float(temp[3]), float(temp[6][:-1])) ) line = inputfile.next() # either a blank or a continuation of the block if sym == "L": gbasis.append( ('S', coeff['S'])) gbasis.append( ('P', coeff['P'])) else: gbasis.append( (sym, coeff[sym])) line = inputfile.next() # either the start of the next block or the start of a new atom or # the end of the basis function section numtoadd = 1 + (shellgap / shellsize) shellcounter = shellno + shellsize for x in range(numtoadd): self.gbasis.append(gbasis) if line.find("EIGENVECTORS") == 10 or line.find("MOLECULAR OBRITALS") == 10: # The details returned come from the *final* report of evalues and # the last list of symmetries in the log file. # Should be followed by lines like this: # ------------ # EIGENVECTORS # ------------ # # 1 2 3 4 5 # -10.0162 -10.0161 -10.0039 -10.0039 -10.0029 # BU AG BU AG AG # 1 C 1 S 0.699293 0.699290 -0.027566 0.027799 0.002412 # 2 C 1 S 0.031569 0.031361 0.004097 -0.004054 -0.000605 # 3 C 1 X 0.000908 0.000632 -0.004163 0.004132 0.000619 # 4 C 1 Y -0.000019 0.000033 0.000668 -0.000651 0.005256 # 5 C 1 Z 0.000000 0.000000 0.000000 0.000000 0.000000 # 6 C 2 S -0.699293 0.699290 0.027566 0.027799 0.002412 # 7 C 2 S -0.031569 0.031361 -0.004097 -0.004054 -0.000605 # 8 C 2 X 0.000908 -0.000632 -0.004163 -0.004132 -0.000619 # 9 C 2 Y -0.000019 -0.000033 0.000668 0.000651 -0.005256 # 10 C 2 Z 0.000000 0.000000 0.000000 0.000000 0.000000 # 11 C 3 S -0.018967 -0.019439 0.011799 -0.014884 -0.452328 # 12 C 3 S -0.007748 -0.006932 0.000680 -0.000695 -0.024917 # 13 C 3 X 0.002628 0.002997 0.000018 0.000061 -0.003608 # and so forth... with blanks lines between blocks of 5 orbitals each. # Warning! There are subtle differences between GAMESS-US and PC-GAMES # in the formatting of the first four columns. # # Watch out for F orbitals... # PC GAMESS # 19 C 1 YZ 0.000000 0.000000 0.000000 0.000000 0.000000 # 20 C XXX 0.000000 0.000000 0.000000 0.000000 0.002249 # 21 C YYY 0.000000 0.000000 -0.025555 0.000000 0.000000 # 22 C ZZZ 0.000000 0.000000 0.000000 0.002249 0.000000 # 23 C XXY 0.000000 0.000000 0.001343 0.000000 0.000000 # GAMESS US # 55 C 1 XYZ 0.000000 0.000000 0.000000 0.000000 0.000000 # 56 C 1XXXX -0.000014 -0.000067 0.000000 0.000000 0.000000 # # This is fine for GeoOpt and SP, but may be weird for TD and Freq. # This is the stuff that we can read from these blocks. self.moenergies = [[]] self.mosyms = [[]] if not hasattr(self, "nmo"): self.nmo = self.nbasis self.mocoeffs = [numpy.zeros((self.nmo, self.nbasis), "d")] readatombasis = False if not hasattr(self, "atombasis"): self.atombasis = [] self.aonames = [] for i in range(self.natom): self.atombasis.append([]) self.aonames = [] readatombasis = True dashes = inputfile.next() for base in range(0, self.nmo, 5): if self.progress: self.updateprogress(inputfile, "Coefficients") line = inputfile.next() # Make sure that this section does not end prematurely - checked by regression test 2CO.ccsd.aug-cc-pVDZ.out. if line.strip() != "": break; numbers = inputfile.next() # Eigenvector numbers. # Sometimes there are some blank lines here. while not line.strip(): line = inputfile.next() # Eigenvalues for these orbitals (in hartrees). try: self.moenergies[0].extend([utils.convertor(float(x), "hartree", "eV") for x in line.split()]) except: self.logger.warning('MO section found but could not be parsed!') break; # Orbital symmetries. line = inputfile.next() if line.strip(): self.mosyms[0].extend(map(self.normalisesym, line.split())) # Now we have nbasis lines. # Going to use the same method as for normalise_aonames() # to extract basis set information. p = re.compile("(\d+)\s*([A-Z][A-Z]?)\s*(\d+)\s*([A-Z]+)") oldatom = '0' i_atom = 0 # counter to keep track of n_atoms > 99 flag_w = True # flag necessary to keep from adding 100's at wrong time for i in range(self.nbasis): line = inputfile.next() # If line is empty, break (ex. for FMO in exam37). if not line.strip(): break # Fill atombasis and aonames only first time around if readatombasis and base == 0: aonames = [] start = line[:17].strip() m = p.search(start) if m: g = m.groups() g2 = int(g[2]) # atom index in GAMESS file; changes to 0 after 99 # Check if we have moved to a hundred # if so, increment the counter and add it to the parsed value # There will be subsequent 0's as that atoms AO's are parsed # so wait until the next atom is parsed before resetting flag if g2 == 0 and flag_w: i_atom = i_atom + 100 flag_w = False # handle subsequent AO's if g2 != 0: flag_w = True # reset flag g2 = g2 + i_atom aoname = "%s%i_%s" % (g[1].capitalize(), g2, g[3]) oldatom = str(g2) atomno = g2-1 orbno = int(g[0])-1 else: # For F orbitals, as shown above g = [x.strip() for x in line.split()] aoname = "%s%s_%s" % (g[1].capitalize(), oldatom, g[2]) atomno = int(oldatom)-1 orbno = int(g[0])-1 self.atombasis[atomno].append(orbno) self.aonames.append(aoname) coeffs = line[15:] # Strip off the crud at the start. j = 0 while j*11+4 < len(coeffs): self.mocoeffs[0][base+j, i] = float(coeffs[j * 11:(j + 1) * 11]) j += 1 line = inputfile.next() # If it's restricted and no more properties: # ...... END OF RHF/DFT CALCULATION ...... # If there are more properties (DENSITY MATRIX): # -------------- # # If it's unrestricted we have: # # ----- BETA SET ----- # # ------------ # EIGENVECTORS # ------------ # # 1 2 3 4 5 # ... and so forth. line = inputfile.next() if line[2:22] == "----- BETA SET -----": self.mocoeffs.append(numpy.zeros((self.nmo, self.nbasis), "d")) self.moenergies.append([]) self.mosyms.append([]) for i in range(4): line = inputfile.next() for base in range(0, self.nmo, 5): if self.progress: self.updateprogress(inputfile, "Coefficients") blank = inputfile.next() line = inputfile.next() # Eigenvector no line = inputfile.next() self.moenergies[1].extend([utils.convertor(float(x), "hartree", "eV") for x in line.split()]) line = inputfile.next() self.mosyms[1].extend(map(self.normalisesym, line.split())) for i in range(self.nbasis): line = inputfile.next() temp = line[15:] # Strip off the crud at the start j = 0 while j * 11 + 4 < len(temp): self.mocoeffs[1][base+j, i] = float(temp[j * 11:(j + 1) * 11]) j += 1 line = inputfile.next() self.moenergies = [numpy.array(x, "d") for x in self.moenergies] # Natural orbitals - presently support only CIS. # Looks basically the same as eigenvectors, without symmetry labels. if line[10:30] == "CIS NATURAL ORBITALS": self.nocoeffs = numpy.zeros((self.nmo, self.nbasis), "d") dashes = inputfile.next() for base in range(0, self.nmo, 5): blank = inputfile.next() numbers = inputfile.next() # Eigenvector numbers. # Eigenvalues for these natural orbitals (not in hartrees!). # Sometimes there are some blank lines before it. line = inputfile.next() while not line.strip(): line = inputfile.next() eigenvalues = line # Orbital symemtry labels are normally here for MO coefficients. line = inputfile.next() # Now we have nbasis lines with the coefficients. for i in range(self.nbasis): line = inputfile.next() coeffs = line[15:] j = 0 while j*11+4 < len(coeffs): self.nocoeffs[base+j, i] = float(coeffs[j * 11:(j + 1) * 11]) j += 1 # We cannot trust this self.homos until we come to the phrase: # SYMMETRIES FOR INITAL GUESS ORBITALS FOLLOW # which either is followed by "ALPHA" or "BOTH" at which point we can say # for certain that it is an un/restricted calculations. # Note that MCSCF calcs also print this search string, so make sure # that self.homos does not exist yet. if line[1:28] == "NUMBER OF OCCUPIED ORBITALS" and not hasattr(self,'homos'): homos = [int(line.split()[-1])-1] line = inputfile.next() homos.append(int(line.split()[-1])-1) self.homos = numpy.array(homos, "i") if line.find("SYMMETRIES FOR INITIAL GUESS ORBITALS FOLLOW") >= 0: # Not unrestricted, so lop off the second index. # In case the search string above was not used (ex. FMO in exam38), # we can try to use the next line which should also contain the # number of occupied orbitals. if line.find("BOTH SET(S)") >= 0: nextline = inputfile.next() if "ORBITALS ARE OCCUPIED" in nextline: homos = int(nextline.split()[0])-1 if hasattr(self,"homos"): try: assert self.homos[0] == homos except AssertionError: self.logger.warning("Number of occupied orbitals not consistent. This is normal for ECP and FMO jobs.") else: self.homos = [homos] self.homos = numpy.resize(self.homos, [1]) # Set the total number of atoms, only once. # Normally GAMESS print TOTAL NUMBER OF ATOMS, however in some cases # this is slightly different (ex. lower case for FMO in exam37). if not hasattr(self,"natom") and "NUMBER OF ATOMS" in line.upper(): self.natom = int(line.split()[-1]) if line.find("NUMBER OF CARTESIAN GAUSSIAN BASIS") == 1 or line.find("TOTAL NUMBER OF BASIS FUNCTIONS") == 1: # The first is from Julien's Example and the second is from Alexander's # I think it happens if you use a polar basis function instead of a cartesian one self.nbasis = int(line.strip().split()[-1]) elif line.find("TOTAL NUMBER OF CONTAMINANTS DROPPED") >= 0: number = int(line.split()[-1]) if hasattr(self, "nmo"): self.nmo -= number else: self.nmo = self.nbasis - number elif line.find("SPHERICAL HARMONICS KEPT IN THE VARIATION SPACE") >= 0: # Note that this line is present if ISPHER=1, e.g. for C_bigbasis self.nmo = int(line.strip().split()[-1]) elif line.find("TOTAL NUMBER OF MOS IN VARIATION SPACE") == 1: # Note that this line is not always present, so by default # NBsUse is set equal to NBasis (see below). self.nmo = int(line.split()[-1]) elif line.find("OVERLAP MATRIX") == 0 or line.find("OVERLAP MATRIX") == 1: # The first is for PC-GAMESS, the second for GAMESS # Read 1-electron overlap matrix if not hasattr(self, "aooverlaps"): self.aooverlaps = numpy.zeros((self.nbasis, self.nbasis), "d") else: self.logger.info("Reading additional aooverlaps...") base = 0 while base < self.nbasis: if self.progress: self.updateprogress(inputfile, "Overlap") blank = inputfile.next() line = inputfile.next() # Basis fn number blank = inputfile.next() for i in range(self.nbasis - base): # Fewer lines each time line = inputfile.next() temp = line.split() for j in range(4, len(temp)): self.aooverlaps[base+j-4, i+base] = float(temp[j]) self.aooverlaps[i+base, base+j-4] = float(temp[j]) base += 5 # ECP Pseudopotential information if "ECP POTENTIALS" in line: if not hasattr(self, "coreelectrons"): self.coreelectrons = [0]*self.natom dashes = inputfile.next() blank = inputfile.next() header = inputfile.next() while header.split()[0] == "PARAMETERS": name = header[17:25] atomnum = int(header[34:40]) # The pseudopotnetial is given explicitely if header[40:50] == "WITH ZCORE": zcore = int(header[50:55]) lmax = int(header[63:67]) self.coreelectrons[atomnum-1] = zcore # The pseudopotnetial is copied from another atom if header[40:55] == "ARE THE SAME AS": atomcopy = int(header[60:]) self.coreelectrons[atomnum-1] = self.coreelectrons[atomcopy-1] line = inputfile.next() while line.split() <> []: line = inputfile.next() header = inputfile.next() # This was used before refactoring the parser, geotargets was set here after parsing. #if not hasattr(self, "geotargets"): # opttol = 1e-4 # self.geotargets = numpy.array([opttol, 3. / opttol], "d") #if hasattr(self,"geovalues"): self.geovalues = numpy.array(self.geovalues, "d") # This is quite simple to parse, but some files seem to print certain # lines twice, repeating the populations without charges. # Now, unrestricted calculations are bit tricky, since GAMESS-US prints # populations for both alpha and beta orbitals in the same format # and with the same title, but it still prints the charges only # at the very end. So, check for the number of columns in the header. if "TOTAL MULLIKEN AND LOWDIN ATOMIC POPULATIONS" in line: if not hasattr(self, "atomcharges"): self.atomcharges = {} header = inputfile.next() line = inputfile.next() double = line.strip() if double: header = inputfile.next() skip = inputfile.next() line = inputfile.next() # Only go further if the header had five columns, which should # be the case when both populations and charges are printed. if not header.split() == 5: return mulliken, lowdin = [], [] while line.strip(): mulliken.append(float(line.split()[3])) lowdin.append(float(line.split()[5])) line = inputfile.next() if line.strip() and double: line = inputfile.next() self.atomcharges["mulliken"] = mulliken self.atomcharges["lowdin"] = lowdin if __name__ == "__main__": import doctest, gamessparser, sys if len(sys.argv) == 1: doctest.testmod(gamessparser, verbose=False) if len(sys.argv) >= 2: parser = gamessparser.GAMESS(sys.argv[1]) data = parser.parse() if len(sys.argv) > 2: for i in range(len(sys.argv[2:])): if hasattr(data, sys.argv[2 + i]): print getattr(data, sys.argv[2 + i]) GaussSum-2.2.6.1/gausssum/cclib/parser/__init__.py0000664000175000017500000000201712117172552020440 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 960 $" # These import statements are added for the convenience of users... # Rather than having to type: # from cclib.parser.gaussianparser import Gaussian # they can use: # from cclib.parser import Gaussian from adfparser import ADF from gamessparser import GAMESS from gamessukparser import GAMESSUK from gaussianparser import Gaussian from jaguarparser import Jaguar from molproparser import Molpro from orcaparser import ORCA # This allow users to type: # from cclib.parser import ccopen from ccopen import ccopen GaussSum-2.2.6.1/gausssum/cclib/parser/data.py0000664000175000017500000003050612117172552017616 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2007, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 992 $" import numpy class ccData(object): """Class for objects containing data from cclib parsers and methods. Description of cclib attributes: aonames -- atomic orbital names (list) aooverlaps -- atomic orbital overlap matrix (array[2]) atombasis -- indices of atomic orbitals on each atom (list of lists) atomcharges -- atomic partial charges (dict of arrays[1]) atomcoords -- atom coordinates (array[3], angstroms) atommasses -- atom masses (array[1], daltons) atomnos -- atomic numbers (array[1]) atomspins -- atomic spin densities (dict of arrays[1]) charge -- net charge of the system (integer) ccenergies -- molecular energies with Coupled-Cluster corrections (array[2], eV) coreelectrons -- number of core electrons in atom pseudopotentials (array[1]) etenergies -- energies of electronic transitions (array[1], 1/cm) etoscs -- oscillator strengths of electronic transitions (array[1]) etrotats -- rotatory strengths of electronic transitions (array[1], ??) etsecs -- singly-excited configurations for electronic transitions (list of lists) etsyms -- symmetries of electronic transitions (list) fonames -- fragment orbital names (list) fooverlaps -- fragment orbital overlap matrix (array[2]) fragnames -- names of fragments (list) frags -- indices of atoms in a fragment (list of lists) gbasis -- coefficients and exponents of Gaussian basis functions (PyQuante format) geotargets -- targets for convergence of geometry optimization (array[1]) geovalues -- current values for convergence of geometry optmization (array[1]) grads -- current values of forces (gradients) in geometry optimization (array[3]) hessian -- elements of the force constant matrix (array[1]) homos -- molecular orbital indices of HOMO(s) (array[1]) mocoeffs -- molecular orbital coefficients (list of arrays[2]) moenergies -- molecular orbital energies (list of arrays[1], eV) mosyms -- orbital symmetries (list of lists) mpenergies -- molecular electronic energies with Moller-Plesset corrections (array[2], eV) mult -- multiplicity of the system (integer) natom -- number of atoms (integer) nbasis -- number of basis functions (integer) nmo -- number of molecular orbitals (integer) nocoeffs -- natural orbital coefficients (array[2]) scfenergies -- molecular electronic energies after SCF (Hartree-Fock, DFT) (array[1], eV) scftargets -- targets for convergence of the SCF (array[2]) scfvalues -- current values for convergence of the SCF (list of arrays[2]) vibanharms -- vibrational anharmonicity constants (array[2], 1/cm) vibdisps -- cartesian displacement vectors (array[3], delta angstrom) vibfreqs -- vibrational frequencies (array[1], 1/cm) vibirs -- IR intensities (array[1], km/mol) vibramans -- Raman intensities (array[1], A^4/Da) vibsyms -- symmetries of vibrations (list) scannames -- Names of varaibles scanned (list) scanenergies -- energies of potential energy surface (list) scanparm -- values of parameters in potential energy surface (list of tuples) scancoords -- Geometries of each scan step (array[3], angstroms) enthaply -- Sum of electronic and thermal Enthalpie (float hartree/particle) freeenergy -- Sum of electronic and thermal Free Energies (float hartree/particle) temperature -- Tempature used for Thermochemistry (float kelvin) entropy -- Entropy (float hartree/particle) optdone -- Stores if an optimisation job has completed (boolean) (1) The term 'array' refers to a numpy array (2) The number of dimensions of an array is given in square brackets (3) Python indexes arrays/lists starting at zero, so if homos==[10], then the 11th molecular orbital is the HOMO """ def __init__(self, attributes=None): """Initialize the cclibData object. Normally called in the parse() method of a Logfile subclass. Inputs: attributes - dictionary of attributes to load """ # The expected types for all supported attributes in dectionary, # and their names which can be extracted as the keys. self._attrtypes = { "aonames": list, "aooverlaps": numpy.ndarray, "atombasis": list, "atomcharges": dict, "atomcoords": numpy.ndarray, "atommasses": numpy.ndarray, "atomnos": numpy.ndarray, "atomspins": dict, "ccenergies": numpy.ndarray, "charge": int, "coreelectrons": numpy.ndarray, "etenergies": numpy.ndarray, "etoscs": numpy.ndarray, "etrotats": numpy.ndarray, "etsecs": list, "etsyms": list, "fonames": list, "fooverlaps": numpy.ndarray, "fragnames": list, "frags": list, 'gbasis': list, "geotargets": numpy.ndarray, "geovalues": numpy.ndarray, "grads": numpy.ndarray, "hessian": numpy.ndarray, "homos": numpy.ndarray, "mocoeffs": list, "moenergies": list, "mosyms": list, "mpenergies": numpy.ndarray, "mult": int, "natom": int, "nbasis": int, "nmo": int, "nocoeffs": numpy.ndarray, "scfenergies": numpy.ndarray, "scftargets": numpy.ndarray, "scfvalues": list, "vibanharms": numpy.ndarray, "vibdisps": numpy.ndarray, "vibfreqs": numpy.ndarray, "vibirs": numpy.ndarray, "vibramans": numpy.ndarray, "vibsyms": list, "scannames": list, "scanenergies": list, "scanparm": list, "scancoords": numpy.ndarray, "enthaply": float, "freeenergy": float, "temperature": float, "entropy": float, "optdone": bool } # Names of all supported attributes. self._attrlist = self._attrtypes.keys() # Names of all supported attributes. self._attrlist = ['aonames', 'aooverlaps', 'atombasis', 'atomcharges', 'atomcoords', 'atommasses', 'atomnos', 'atomspins', 'ccenergies', 'charge', 'coreelectrons', 'etenergies', 'etoscs', 'etrotats', 'etsecs', 'etsyms', 'fonames', 'fooverlaps', 'fragnames', 'frags', 'gbasis', 'geotargets', 'geovalues', 'grads', 'hessian', 'homos', 'mocoeffs', 'moenergies', 'mosyms', 'mpenergies', 'mult', 'natom', 'nbasis', 'nmo', 'nocoeffs', 'scfenergies', 'scftargets', 'scfvalues', 'vibanharms', 'vibdisps', 'vibfreqs', 'vibirs', 'vibramans', 'vibsyms', 'scannames', 'scanenergies', 'scanparm', 'scancoords', 'enthaply', 'freeenergy', 'temperature', 'entropy', 'optdone'] # Arrays are double precision by default, but these will be integer arrays. self._intarrays = ['atomnos', 'coreelectrons', 'homos'] # Attributes that should be lists of arrays (double precision). self._listsofarrays = ['mocoeffs', 'moenergies', 'scfvalues'] # Attributes that should be dictionaries of arrays (double precision). self._dictsofarrays = ["atomcharges", "atomspins"] if attributes: self.setattributes(attributes) def listify(self): """Converts all attributes that are arrays or lists/dicts of arrays to lists.""" attrlist = [k for k in self._attrlist if hasattr(self, k)] for k in attrlist: v = self._attrtypes[k] if v == numpy.ndarray: setattr(self, k, getattr(self, k).tolist()) elif v == list and k in self._listsofarrays: setattr(self, k, [x.tolist() for x in getattr(self, k)]) elif v == dict and k in self._dictsofarrays: items = getattr(self, k).iteritems() pairs = [(key, val.tolist()) for key, val in items] setattr(self, k, dict(pairs)) def arrayify(self): """Converts appropriate attributes to arrays or lists/dicts of arrays.""" attrlist = [k for k in self._attrlist if hasattr(self, k)] for k in attrlist: v = self._attrtypes[k] precision = 'd' if k in self._intarrays: precision = 'i' if v == numpy.ndarray: setattr(self, k, numpy.array(getattr(self, k), precision)) elif v == list and k in self._listsofarrays: setattr(self, k, [numpy.array(x, precision) for x in getattr(self, k)]) elif v == dict and k in self._dictsofarrays: items = getattr(self, k).iteritems() pairs = [(key, numpy.array(val, precision)) for key, val in items] setattr(self, k, dict(pairs)) def getattributes(self, tolists=False): """Returns a dictionary of existing data attributes. Inputs: tolists - flag to convert attributes to lists where applicable """ if tolists: self.listify() attributes = {} for attr in self._attrlist: if hasattr(self, attr): attributes[attr] = getattr(self, attr) if tolists: self.arrayify() return attributes def setattributes(self, attributes): """Sets data attributes given in a dictionary. Inputs: attributes - dictionary of attributes to set Outputs: invalid - list of attributes names that were not set, which means they are not specified in self._attrlist """ if type(attributes) is not dict: raise TypeError, "attributes must be in a dictionary" valid = [a for a in attributes if a in self._attrlist] invalid = [a for a in attributes if a not in self._attrlist] for attr in valid: setattr(self, attr, attributes[attr]) self.arrayify() return invalid GaussSum-2.2.6.1/gausssum/cclib/parser/orcaparser.py0000664000175000017500000005313312117172552021047 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2007, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 1033 $" import numpy import logfileparser class ORCA(logfileparser.Logfile): """An ORCA log file.""" def __init__(self, *args, **kwargs): # Call the __init__ method of the superclass super(ORCA, self).__init__(logname="ORCA", *args, **kwargs) def __str__(self): """Return a string representation of the object.""" return "ORCA log file %s" % (self.filename) def __repr__(self): """Return a representation of the object.""" return 'ORCA("%s")' % (self.filename) def normalisesym(self, label): """Use standard symmetry labels instead of Gaussian labels. To normalise: (1) If label is one of [SG, PI, PHI, DLTA], replace by [sigma, pi, phi, delta] (2) replace any G or U by their lowercase equivalent >>> sym = Gaussian("dummyfile").normalisesym >>> labels = ['A1', 'AG', 'A1G', "SG", "PI", "PHI", "DLTA", 'DLTU', 'SGG'] >>> map(sym, labels) ['A1', 'Ag', 'A1g', 'sigma', 'pi', 'phi', 'delta', 'delta.u', 'sigma.g'] """ def before_parsing(self): # A geometry optimization is started only when # we parse a cycle (so it will be larger than zero(). self.gopt_cycle = 0 def extract(self, inputfile, line): """Extract information from the file object inputfile.""" if line[0:15] == "Number of atoms": natom = int(line.split()[-1]) # This assert will probably never be executed. if hasattr(self, "natom"): assert self.natom == natom else: self.natom = natom if line[1:13] == "Total Charge": charge = int(line.split()[-1]) line = inputfile.next() mult = int(line.split()[-1]) self.charge = charge self.mult = mult # Here is how a typical SCF convergence output looks like: # # -------------- # SCF ITERATIONS # -------------- # ITER Energy Delta-E Max-DP RMS-DP [F,P] Damp # *** Starting incremental Fock matrix formation *** # 0 -384.5203638934 0.000000000000 0.03375012 0.00223249 0.1351565 0.7000 # 1 -384.5792776162 -0.058913722842 0.02841696 0.00175952 0.0734529 0.7000 # ***Turning on DIIS*** # 2 -384.6074211837 -0.028143567475 0.04968025 0.00326114 0.0310435 0.0000 # 3 -384.6479682063 -0.040547022616 0.02097477 0.00121132 0.0361982 0.0000 # 4 -384.6571124353 -0.009144228947 0.00576471 0.00035160 0.0061205 0.0000 # 5 -384.6574659959 -0.000353560584 0.00191156 0.00010160 0.0025838 0.0000 # 6 -384.6574990782 -0.000033082375 0.00052492 0.00003800 0.0002061 0.0000 # 7 -384.6575005762 -0.000001497987 0.00020257 0.00001146 0.0001652 0.0000 # 8 -384.6575007321 -0.000000155848 0.00008572 0.00000435 0.0000745 0.0000 # **** Energy Check signals convergence **** if "SCF ITERATIONS" in line: dashes = inputfile.next() line = inputfile.next().split() assert line[1] == "Energy" assert line[2] == "Delta-E" assert line[3] == "Max-DP" if not hasattr(self, "scfvalues"): self.scfvalues = [] self.scfvalues.append([]) # Try to keep track of the converger (NR, DIIS, SOSCF, etc.). diis_active = True while not line == []: if 'Newton-Raphson' in line: diis_active = False elif 'SOSCF' in line: diis_active = False elif line[0].isdigit() and diis_active: energy = float(line[1]) deltaE = float(line[2]) maxDP = float(line[3]) rmsDP = float(line[4]) self.scfvalues[-1].append([deltaE, maxDP, rmsDP]) elif line[0].isdigit() and not diis_active: energy = float(line[1]) deltaE = float(line[2]) maxDP = float(line[5]) rmsDP = float(line[6]) self.scfvalues[-1].append([deltaE, maxDP, rmsDP]) line = inputfile.next().split() # Read in values for last SCF iteration and scftargets. if "SCF CONVERGENCE" in line: if not hasattr(self, "scfvalues"): self.scfvalues = [] if not hasattr(self, "scftargets"): self.scftargets = [] dashes = inputfile.next() blank = inputfile.next() line = inputfile.next() assert "Last Energy change" in line deltaE_value = float(line.split()[4]) deltaE_target = float(line.split()[7]) line = inputfile.next() assert "Last MAX-Density change" in line maxDP_value = float(line.split()[4]) maxDP_target = float(line.split()[7]) line = inputfile.next() assert "Last RMS-Density change" in line rmsDP_value = float(line.split()[4]) rmsDP_target = float(line.split()[7]) line = inputfile.next() # Non-DIIS convergers do not contain this line. # assert "Last DIIS Error" in line self.scfvalues[-1].append([deltaE_value, maxDP_value, rmsDP_value]) self.scftargets.append([deltaE_target, maxDP_target, rmsDP_target]) # SCF energies are printed differently in single point calculations # and in the inner steps of geometry optimizations. However, there is # always a banner announcing the convergence, like this: # # ***************************************************** # * SUCCESS * # * SCF CONVERGED AFTER 9 CYCLES * # ***************************************************** if "SCF CONVERGED AFTER" in line: while line[:20] != "Total Energy :": line = inputfile.next() if not hasattr(self, "scfenergies"): self.scfenergies = [] energy = float(line.split()[5]) self.scfenergies.append(energy) # Sometimes the SCF does not converge, but does not halt the # the run (like in bug 3184890). In this this case, we should # remain consistent and use the energy from the last reported # SCF cycle. In this case, ORCA print a banner like this: # # ***************************************************** # * ERROR * # * SCF NOT CONVERGED AFTER 8 CYCLES * # ***************************************************** if "SCF NOT CONVERGED AFTER" in line: if not hasattr(self, "scfenergies"): self.scfenergies = [] energy = self.scfvalues[-1][-1][0] self.scfenergies.append(energy) if line[25:50] == "Geometry Optimization Run": line = inputfile.next() while line[0:23] != "Convergence Tolerances:": line = inputfile.next() self.geotargets = numpy.zeros((5,), "d") for i in range(5): line = inputfile.next() self.geotargets[i] = float(line.split()[-2]) #get geometry convergence criteria if line[33:53] == "Geometry convergence": if not hasattr(self, "geovalues"): self.geovalues = [ ] newlist = [] headers = inputfile.next() dashes = inputfile.next() #check if energy change is present (steps > 1) line = inputfile.next() if line.find("Energy change") > 0: newlist.append(float(line.split()[2])) line = inputfile.next() else: newlist.append(0.0) #get rest of info for i in range(4): newlist.append(float(line.split()[2])) line = inputfile.next() self.geovalues.append(newlist) #if not an optimization, determine structure used if line[0:21] == "CARTESIAN COORDINATES" and not hasattr(self, "atomcoords"): dashes = inputfile.next() atomnos = [] atomcoords = [] line = inputfile.next() while len(line) > 1: broken = line.split() atomnos.append(self.table.number[broken[0]]) atomcoords.append(map(float, broken[1:4])) line = inputfile.next() self.atomcoords = [atomcoords] if not hasattr(self, "atomnos"): self.atomnos = atomnos self.natom = len(atomnos) # There's always a banner announcing the next geometry optimization cycle, # which looks something like this: # # ************************************************************* # * GEOMETRY OPTIMIZATION CYCLE 2 * # ************************************************************* if "GEOMETRY OPTIMIZATION CYCLE" in line: # Keep track of the current cycle jsut in case, because some things # are printed differently inside the first/last and other cycles. self.gopt_cycle = int(line.split()[4]) #parse geometry coords stars = inputfile.next() dashes = inputfile.next() text = inputfile.next() dashes = inputfile.next() if not hasattr(self,"atomcoords"): self.atomcoords = [] atomnos = [] atomcoords = [] for i in range(self.natom): line = inputfile.next() broken = line.split() atomnos.append(self.table.number[broken[0]]) atomcoords.append(map(float, broken[1:4])) self.atomcoords.append(atomcoords) if not hasattr(self, "atomnos"): self.atomnos = numpy.array(atomnos,'i') if line[21:68] == "FINAL ENERGY EVALUATION AT THE STATIONARY POINT": text = inputfile.next() broken = text.split() assert int(broken[2]) == len(self.atomcoords) stars = inputfile.next() dashes = inputfile.next() text = inputfile.next() dashes = inputfile.next() atomcoords = [] for i in range(self.natom): line = inputfile.next() broken = line.split() atomcoords.append(map(float, broken[1:4])) self.atomcoords.append(atomcoords) if line[0:16] == "ORBITAL ENERGIES": dashes = inputfile.next() text = inputfile.next() text = inputfile.next() self.moenergies = [[]] self.homos = [[0]] line = inputfile.next() while len(line) > 20: #restricted calcs are terminated by ------ info = line.split() self.moenergies[0].append(float(info[3])) if float(info[1]) > 0.00: #might be 1 or 2, depending on restricted-ness self.homos[0] = int(info[0]) line = inputfile.next() line = inputfile.next() #handle beta orbitals if line[17:35] == "SPIN DOWN ORBITALS": text = inputfile.next() self.moenergies.append([]) self.homos.append(0) line = inputfile.next() while len(line) > 20: #actually terminated by ------ info = line.split() self.moenergies[1].append(float(info[3])) if float(info[1]) == 1.00: self.homos[1] = int(info[0]) line = inputfile.next() if line[1:32] == "# of contracted basis functions": self.nbasis = int(line.split()[-1]) if line[0:14] == "OVERLAP MATRIX": dashes = inputfile.next() self.aooverlaps = numpy.zeros( (self.nbasis, self.nbasis), "d") for i in range(0, self.nbasis, 6): if self.progress: self.updateprogress(inputfile, "Overlap") header = inputfile.next() size = len(header.split()) for j in range(self.nbasis): line = inputfile.next() broken = line.split() self.aooverlaps[j, i:i+size] = map(float, broken[1:size+1]) # Molecular orbital coefficients. # This is also where atombasis is parsed. if line[0:18] == "MOLECULAR ORBITALS": dashses = inputfile.next() mocoeffs = [ numpy.zeros((self.nbasis, self.nbasis), "d") ] self.aonames = [] self.atombasis = [] for n in range(self.natom): self.atombasis.append([]) for spin in range(len(self.moenergies)): if spin == 1: blank = inputfile.next() mocoeffs.append(numpy.zeros((self.nbasis, self.nbasis), "d")) for i in range(0, self.nbasis, 6): if self.progress: self.updateprogress(inputfile, "Coefficients") numbers = inputfile.next() energies = inputfile.next() occs = inputfile.next() dashes = inputfile.next() broken = dashes.split() size = len(broken) for j in range(self.nbasis): line = inputfile.next() broken = line.split() #only need this on the first time through if spin == 0 and i == 0: atomname = line[3:5].split()[0] num = int(line[0:3]) orbital = broken[1].upper() self.aonames.append("%s%i_%s"%(atomname, num+1, orbital)) self.atombasis[num].append(j) temp = [] vals = line[16:-1] #-1 to remove the last blank space for k in range(0, len(vals), 10): temp.append(float(vals[k:k+10])) mocoeffs[spin][i:i+size, j] = temp self.mocoeffs = mocoeffs if line[0:18] == "TD-DFT/TDA EXCITED": sym = "Triplet" # Could be singlets or triplets if line.find("SINGLETS") >= 0: sym = "Singlet" self.etsecs = [] self.etenergies = [] self.etsyms = [] lookup = {'a':0, 'b':1} line = inputfile.next() while line.find("STATE") < 0: line = inputfile.next() # Contains STATE or is blank while line.find("STATE") >= 0: broken = line.split() self.etenergies.append(float(broken[-2])) self.etsyms.append(sym) line = inputfile.next() sec = [] # Contains SEC or is blank while line.strip(): start = line[0:8].strip() start = (int(start[:-1]), lookup[start[-1]]) end = line[10:17].strip() end = (int(end[:-1]), lookup[end[-1]]) contrib = float(line[35:47].strip()) sec.append([start, end, contrib]) line = inputfile.next() self.etsecs.append(sec) line = inputfile.next() if line[25:44] == "ABSORPTION SPECTRUM": minus = inputfile.next() header = inputfile.next() header = inputfile.next() minus = inputfile.next() self.etoscs = [] for x in self.etsyms: osc = inputfile.next().split()[3] if osc == "spin": # "spin forbidden" osc = 0 else: osc = float(osc) self.etoscs.append(osc) if line[0:23] == "VIBRATIONAL FREQUENCIES": dashes = inputfile.next() blank = inputfile.next() self.vibfreqs = numpy.zeros((3 * self.natom,),"d") for i in range(3 * self.natom): line = inputfile.next() self.vibfreqs[i] = float(line.split()[1]) if line[0:11] == "IR SPECTRUM": dashes = inputfile.next() blank = inputfile.next() header = inputfile.next() dashes = inputfile.next() self.vibirs = numpy.zeros((3 * self.natom,),"d") line = inputfile.next() while len(line) > 2: num = int(line[0:4]) self.vibirs[num] = float(line.split()[2]) line = inputfile.next() if line[0:14] == "RAMAN SPECTRUM": dashes = inputfile.next() blank = inputfile.next() header = inputfile.next() dashes = inputfile.next() self.vibramans = numpy.zeros((3 * self.natom,),"d") line = inputfile.next() while len(line) > 2: num = int(line[0:4]) self.vibramans[num] = float(line.split()[2]) line = inputfile.next() # ORCA will print atomic charges along with the spin populations, # so care must be taken about choosing the proper column. # Population analyses are performed usually only at the end # of a geometry optimization or other run, so we want to # leave just the final atom charges. # Here is an example for Mulliken charges: # -------------------------------------------- # MULLIKEN ATOMIC CHARGES AND SPIN POPULATIONS # -------------------------------------------- # 0 H : 0.126447 0.002622 # 1 C : -0.613018 -0.029484 # 2 H : 0.189146 0.015452 # 3 H : 0.320041 0.037434 # ... # Sum of atomic charges : -0.0000000 # Sum of atomic spin populations: 1.0000000 if line[:23] == "MULLIKEN ATOMIC CHARGES": has_spins = "AND SPIN POPULATIONS" in line if not hasattr(self, "atomcharges"): self.atomcharges = { } if has_spins and not hasattr(self, "atomspins"): self.atomspins = {} dashes = inputfile.next() charges = [] if has_spins: spins = [] line = inputfile.next() while line[:21] != "Sum of atomic charges": charges.append(float(line[8:20])) if has_spins: spins.append(float(line[20:])) line = inputfile.next() self.atomcharges["mulliken"] = charges if has_spins: self.atomspins["mulliken"] = spins # Things are the same for Lowdin populations, except that the sums # are not printed (there is a blank line at the end). if line[:22] == "LOEWDIN ATOMIC CHARGES": has_spins = "AND SPIN POPULATIONS" in line if not hasattr(self, "atomcharges"): self.atomcharges = { } if has_spins and not hasattr(self, "atomspins"): self.atomspins = {} dashes = inputfile.next() charges = [] if has_spins: spins = [] line = inputfile.next() while line.strip(): charges.append(float(line[8:20])) if has_spins: spins.append(float(line[20:])) line = inputfile.next() self.atomcharges["lowdin"] = charges if has_spins: self.atomspins["lowdin"] = spins if __name__ == "__main__": import sys import doctest, orcaparser if len(sys.argv) == 1: doctest.testmod(orcaparser, verbose=False) if len(sys.argv) == 2: parser = orcaparser.ORCA(sys.argv[1]) data = parser.parse() if len(sys.argv) > 2: for i in range(len(sys.argv[2:])): if hasattr(data, sys.argv[2 + i]): print getattr(data, sys.argv[2 + i]) GaussSum-2.2.6.1/gausssum/cclib/parser/molproparser.py0000664000175000017500000007434012117172552021436 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2007, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 992 $" import numpy import logfileparser import utils class Molpro(logfileparser.Logfile): """Molpro file parser""" def __init__(self, *args, **kwargs): # Call the __init__ method of the superclass super(Molpro, self).__init__(logname="Molpro", *args, **kwargs) def __str__(self): """Return a string representation of the object.""" return "Molpro log file %s" % (self.filename) def __repr__(self): """Return a representation of the object.""" return 'Molpro("%s")' % (self.filename) def normalisesym(self, label): """Normalise the symmetries used by Molpro.""" ans = label.replace("`", "'").replace("``", "''") return ans def before_parsing(self): self.electronorbitals = "" self.insidescf = False def after_parsing(self): # If optimization thresholds are default, they are normally not printed. if not hasattr(self, "geotargets"): self.geotargets = [] # Default THRGRAD (required accuracy of the optimized gradient). self.geotargets.append(3E-4) # Default THRENERG (required accuracy of the optimized energy). self.geotargets.append(1E-6) # Default THRSTEP (convergence threshold for the geometry optimization step). self.geotargets.append(3E-4) def extract(self, inputfile, line): """Extract information from the file object inputfile.""" if line[1:19] == "ATOMIC COORDINATES": if not hasattr(self,"atomcoords"): self.atomcoords = [] self.atomnos = [] line = inputfile.next() line = inputfile.next() line = inputfile.next() atomcoords = [] atomnos = [] line = inputfile.next() while line.strip(): columns = line.strip().split() coords = [utils.convertor(float(x), "bohr", "Angstrom") for x in columns[3:6]] #bohrs to angs atomcoords.append(coords) atomnos.append(int(round(float(columns[2])))) line = inputfile.next() self.atomnos = numpy.array(atomnos, "i") self.atomcoords.append(atomcoords) self.natom = len(self.atomnos) # Use BASIS DATA to parse input for aonames and atombasis. # This is always the first place this information is printed, so no attribute check is needed. if line[1:11] == "BASIS DATA": blank = inputfile.next() header = inputfile.next() blank = inputfile.next() self.aonames = [] self.atombasis = [] self.gbasis = [] for i in range(self.natom): self.atombasis.append([]) self.gbasis.append([]) line = "dummy" while line.strip() != "": line = inputfile.next() funcnr = line[1:6] funcsym = line[7:9] funcatom_ = line[11:14] functype_ = line[16:22] funcexp = line[25:38] funccoeffs = line[38:] # If a new function type is printed or the BASIS DATA block ends, # then the previous functions can be added to gbasis. # When translating the Molpro function type name into a gbasis code, # note that Molpro prints all components, and we want to add # only one to gbasis, with the proper code (S,P,D,F,G). # Warning! The function types differ for cartesian/spherical functions. # Skip the first printed function type, however (line[3] != '1'). if (functype_.strip() and line[1:4] != ' 1') or line.strip() == "": funcbasis = None if functype in ['1s', 's']: funcbasis = 'S' if functype in ['x', '2px']: funcbasis = 'P' if functype in ['xx', '3d0']: funcbasis = 'D' if functype in ['xxx', '4f0']: funcbasis = 'F' if functype in ['xxxx', '5g0']: funcbasis = 'G' if funcbasis: # The function is split into as many columns as there are. for i in range(len(coefficients[0])): func = (funcbasis, []) for j in range(len(exponents)): func[1].append((exponents[j], coefficients[j][i])) self.gbasis[funcatom-1].append(func) # If it is a new type, set up the variables for the next shell(s). if functype_.strip(): exponents = [] coefficients = [] functype = functype_.strip() funcatom = int(funcatom_.strip()) # Add exponents and coefficients to lists. if line.strip(): funcexp = float(funcexp) funccoeffs = [float(s) for s in funccoeffs.split()] exponents.append(funcexp) coefficients.append(funccoeffs) # If the function number is there, add to atombasis and aonames. if funcnr.strip(): funcnr = int(funcnr.split('.')[0]) self.atombasis[funcatom-1].append(funcnr-1) element = self.table.element[self.atomnos[funcatom-1]] aoname = "%s%i_%s" % (element, funcatom, functype) self.aonames.append(aoname) if line[1:23] == "NUMBER OF CONTRACTIONS": nbasis = int(line.split()[3]) if hasattr(self, "nbasis"): assert nbasis == self.nbasis else: self.nbasis = nbasis # This is used to signalize whether we are inside an SCF calculation. if line[1:8] == "PROGRAM" and line[14:18] == "-SCF": self.insidescf = True # Use this information instead of 'SETTING ...', in case the defaults are standard. # Note that this is sometimes printed in each geometry optimization step. if line[1:20] == "NUMBER OF ELECTRONS": spinup = int(line.split()[3][:-1]) spindown = int(line.split()[4][:-1]) # Nuclear charges (atomnos) should be parsed by now. nuclear = numpy.sum(self.atomnos) charge = nuclear - spinup - spindown mult = spinup - spindown + 1 # Copy charge, or assert for exceptions if already exists. if not hasattr(self, "charge"): self.charge = charge else: assert self.charge == charge # Copy multiplicity, or assert for exceptions if already exists. if not hasattr(self, "mult"): self.mult = mult else: assert self.mult == mult # Convergenve thresholds for SCF cycle, should be contained in a line such as: # CONVERGENCE THRESHOLDS: 1.00E-05 (Density) 1.40E-07 (Energy) if self.insidescf and line[1:24] == "CONVERGENCE THRESHOLDS:": if not hasattr(self, "scftargets"): self.scftargets = [] scftargets = map(float, line.split()[2::2]) self.scftargets.append(scftargets) # Usually two criteria, but save the names this just in case. self.scftargetnames = line.split()[3::2] # Read in the print out of the SCF cycle - for scfvalues. For RHF looks like: # ITERATION DDIFF GRAD ENERGY 2-EL.EN. DIPOLE MOMENTS DIIS # 1 0.000D+00 0.000D+00 -379.71523700 1159.621171 0.000000 0.000000 0.000000 0 # 2 0.000D+00 0.898D-02 -379.74469736 1162.389787 0.000000 0.000000 0.000000 1 # 3 0.817D-02 0.144D-02 -379.74635529 1162.041033 0.000000 0.000000 0.000000 2 # 4 0.213D-02 0.571D-03 -379.74658063 1162.159929 0.000000 0.000000 0.000000 3 # 5 0.799D-03 0.166D-03 -379.74660889 1162.144256 0.000000 0.000000 0.000000 4 if self.insidescf and line[1:10] == "ITERATION": if not hasattr(self, "scfvalues"): self.scfvalues = [] line = inputfile.next() energy = 0.0 scfvalues = [] while line.strip() != "": if line.split()[0].isdigit(): ddiff = float(line.split()[1].replace('D','E')) newenergy = float(line.split()[3]) ediff = newenergy - energy energy = newenergy # The convergence thresholds must have been read above. # Presently, we recognize MAX DENSITY and MAX ENERGY thresholds. numtargets = len(self.scftargetnames) values = [numpy.nan]*numtargets for n, name in zip(range(numtargets), self.scftargetnames): if "ENERGY" in name.upper(): values[n] = ediff elif "DENSITY" in name.upper(): values[n] = ddiff scfvalues.append(values) line = inputfile.next() self.scfvalues.append(numpy.array(scfvalues)) # SCF result - RHF/UHF and DFT (RKS) energies. if line[1:5] in ["!RHF", "!UHF", "!RKS"] and line[16:22] == "ENERGY": if not hasattr(self, "scfenergies"): self.scfenergies = [] scfenergy = float(line.split()[4]) self.scfenergies.append(utils.convertor(scfenergy, "hartree", "eV")) # We are now done with SCF cycle (after a few lines). self.insidescf = False # MP2 energies. if line[1:5] == "!MP2": if not hasattr(self, 'mpenergies'): self.mpenergies = [] mp2energy = float(line.split()[-1]) mp2energy = utils.convertor(mp2energy, "hartree", "eV") self.mpenergies.append([mp2energy]) # MP2 energies if MP3 or MP4 is also calculated. if line[1:5] == "MP2:": if not hasattr(self, 'mpenergies'): self.mpenergies = [] mp2energy = float(line.split()[2]) mp2energy = utils.convertor(mp2energy, "hartree", "eV") self.mpenergies.append([mp2energy]) # MP3 (D) and MP4 (DQ or SDQ) energies. if line[1:8] == "MP3(D):": mp3energy = float(line.split()[2]) mp2energy = utils.convertor(mp3energy, "hartree", "eV") line = inputfile.next() self.mpenergies[-1].append(mp2energy) if line[1:9] == "MP4(DQ):": mp4energy = float(line.split()[2]) line = inputfile.next() if line[1:10] == "MP4(SDQ):": mp4energy = float(line.split()[2]) mp4energy = utils.convertor(mp4energy, "hartree", "eV") self.mpenergies[-1].append(mp4energy) # The CCSD program operates all closed-shel coupled cluster runs. if line[1:15] == "PROGRAM * CCSD": if not hasattr(self, "ccenergies"): self.ccenergies = [] while line[1:20] != "Program statistics:": # The last energy (most exact) will be read last and thus saved. if line[1:5] == "!CCD" or line[1:6] == "!CCSD" or line[1:9] == "!CCSD(T)": ccenergy = float(line.split()[-1]) ccenergy = utils.convertor(ccenergy, "hartree", "eV") line = inputfile.next() self.ccenergies.append(ccenergy) # Read the occupancy (index of HOMO s). # For restricted calculations, there is one line here. For unrestricted, two: # Final alpha occupancy: ... # Final beta occupancy: ... if line[1:17] == "Final occupancy:": self.homos = [int(line.split()[-1])-1] if line[1:23] == "Final alpha occupancy:": self.homos = [int(line.split()[-1])-1] line = inputfile.next() self.homos.append(int(line.split()[-1])-1) # From this block atombasis, moenergies, and mocoeffs can be parsed. # Note that Molpro does not print this by default, you must add this in the input: # GPRINT,ORBITALS # What's more, this prints only the occupied orbitals. To get virtuals, add also: # ORBPTIN,NVIRT # where NVIRT is how many to print (can be some large number, like 99999, to print all). # The block is in general flipped when compared to other programs (GAMESS, Gaussian), and # MOs in the rows. Also, it does not cut the table into parts, rather each MO row has # as many lines as it takes to print all the coefficients, as shown below: # # ELECTRON ORBITALS # ================= # # # Orb Occ Energy Couls-En Coefficients # # 1 1s 1 1s 1 2px 1 2py 1 2pz 2 1s (...) # 3 1s 3 1s 3 2px 3 2py 3 2pz 4 1s (...) # (...) # # 1.1 2 -11.0351 -43.4915 0.701460 0.025696 -0.000365 -0.000006 0.000000 0.006922 (...) # -0.006450 0.004742 -0.001028 -0.002955 0.000000 -0.701460 (...) # (...) # # For unrestricted calcualtions, ELECTRON ORBITALS is followed on the same line # by FOR POSITIVE SPIN or FOR NEGATIVE SPIN. # For examples, see data/Molpro/basicMolpro2006/dvb_sp*. if line[1:18] == "ELECTRON ORBITALS" or self.electronorbitals: # Detect if we are reading beta (negative spin) orbitals. spin = 0 if line[19:36] == "FOR NEGATIVE SPIN" or self.electronorbitals[19:36] == "FOR NEGATIVE SPIN": spin = 1 if not self.electronorbitals: dashes = inputfile.next() blank = inputfile.next() blank = inputfile.next() headers = inputfile.next() blank = inputfile.next() # Parse the list of atomic orbitals if atombasis or aonames is missing. line = inputfile.next() if not hasattr(self, "atombasis") or not hasattr(self, "aonames"): self.atombasis = [] for i in range(self.natom): self.atombasis.append([]) self.aonames = [] aonum = 0 while line.strip(): for s in line.split(): if s.isdigit(): atomno = int(s) self.atombasis[atomno-1].append(aonum) aonum += 1 else: functype = s element = self.table.element[self.atomnos[atomno-1]] aoname = "%s%i_%s" % (element, atomno, functype) self.aonames.append(aoname) line = inputfile.next() else: while line.strip(): line = inputfile.next() # Now there can be one or two blank lines. while not line.strip(): line = inputfile.next() # Create empty moenergies and mocoeffs if they don't exist. if not hasattr(self, "moenergies"): self.moenergies = [[]] self.mocoeffs = [[]] # Do the same if they exist and are being read again (spin=0), # this means only the last print-out of these data are saved, # which consistent with current cclib practices. elif len(self.moenergies) == 1 and spin == 0: self.moenergies = [[]] self.mocoeffs = [[]] else: self.moenergies.append([]) self.mocoeffs.append([]) while line.strip() and not "ORBITALS" in line: coeffs = [] while line.strip() != "": if line[:30].strip(): moenergy = float(line.split()[2]) moenergy = utils.convertor(moenergy, "hartree", "eV") self.moenergies[spin].append(moenergy) line = line[31:] # Each line has 10 coefficients in 10.6f format. num = len(line)/10 for i in range(num): try: coeff = float(line[10*i:10*(i+1)]) # Molpro prints stars when coefficients are huge. except ValueError, detail: self.logger.warn("Set coefficient to zero: %s" %detail) coeff = 0.0 coeffs.append(coeff) line = inputfile.next() self.mocoeffs[spin].append(coeffs) line = inputfile.next() # Check if last line begins the next ELECTRON ORBITALS section. if line[1:18] == "ELECTRON ORBITALS": self.electronorbitals = line else: self.electronorbitals = "" # If the MATROP program was called appropriately, # the atomic obital overlap matrix S is printed. # The matrix is printed straight-out, ten elements in each row, both halves. # Note that is the entire matrix is not printed, then aooverlaps # will not have dimensions nbasis x nbasis. if line[1:9] == "MATRIX S": blank = inputfile.next() symblocklabel = inputfile.next() if not hasattr(self, "aooverlaps"): self.aooverlaps = [[]] line = inputfile.next() while line.strip() != "": elements = [float(s) for s in line.split()] if len(self.aooverlaps[-1]) + len(elements) <= self.nbasis: self.aooverlaps[-1] += elements else: n = len(self.aooverlaps[-1]) + len(elements) - self.nbasis self.aooverlaps[-1] += elements[:-n] self.aooverlaps.append([]) self.aooverlaps[-1] += elements[-n:] line = inputfile.next() # Thresholds are printed only if the defaults are changed with GTHRESH. # In that case, we can fill geotargets with non-default values. # The block should look like this as of Molpro 2006.1: # THRESHOLDS: # ZERO = 1.00D-12 ONEINT = 1.00D-12 TWOINT = 1.00D-11 PREFAC = 1.00D-14 LOCALI = 1.00D-09 EORDER = 1.00D-04 # ENERGY = 0.00D+00 ETEST = 0.00D+00 EDENS = 0.00D+00 THRDEDEF= 1.00D-06 GRADIENT= 1.00D-02 STEP = 1.00D-03 # ORBITAL = 1.00D-05 CIVEC = 1.00D-05 COEFF = 1.00D-04 PRINTCI = 5.00D-02 PUNCHCI = 9.90D+01 OPTGRAD = 3.00D-04 # OPTENERG= 1.00D-06 OPTSTEP = 3.00D-04 THRGRAD = 2.00D-04 COMPRESS= 1.00D-11 VARMIN = 1.00D-07 VARMAX = 1.00D-03 # THRDOUB = 0.00D+00 THRDIV = 1.00D-05 THRRED = 1.00D-07 THRPSP = 1.00D+00 THRDC = 1.00D-10 THRCS = 1.00D-10 # THRNRM = 1.00D-08 THREQ = 0.00D+00 THRDE = 1.00D+00 THRREF = 1.00D-05 SPARFAC = 1.00D+00 THRDLP = 1.00D-07 # THRDIA = 1.00D-10 THRDLS = 1.00D-07 THRGPS = 0.00D+00 THRKEX = 0.00D+00 THRDIS = 2.00D-01 THRVAR = 1.00D-10 # THRLOC = 1.00D-06 THRGAP = 1.00D-06 THRLOCT = -1.00D+00 THRGAPT = -1.00D+00 THRORB = 1.00D-06 THRMLTP = 0.00D+00 # THRCPQCI= 1.00D-10 KEXTA = 0.00D+00 THRCOARS= 0.00D+00 SYMTOL = 1.00D-06 GRADTOL = 1.00D-06 THROVL = 1.00D-08 # THRORTH = 1.00D-08 GRID = 1.00D-06 GRIDMAX = 1.00D-03 DTMAX = 0.00D+00 if line [1:12] == "THRESHOLDS": blank = inputfile.next() line = inputfile.next() while line.strip(): if "OPTENERG" in line: start = line.find("OPTENERG") optenerg = line[start+10:start+20] if "OPTGRAD" in line: start = line.find("OPTGRAD") optgrad = line[start+10:start+20] if "OPTSTEP" in line: start = line.find("OPTSTEP") optstep = line[start+10:start+20] line = inputfile.next() self.geotargets = [optenerg, optgrad, optstep] # The optimization history is the source for geovlues: # END OF GEOMETRY OPTIMIZATION. TOTAL CPU: 246.9 SEC # # ITER. ENERGY(OLD) ENERGY(NEW) DE GRADMAX GRADNORM GRADRMS STEPMAX STEPLEN STEPRMS # 1 -382.02936898 -382.04914450 -0.01977552 0.11354875 0.20127947 0.01183997 0.12972761 0.20171740 0.01186573 # 2 -382.04914450 -382.05059234 -0.00144784 0.03299860 0.03963339 0.00233138 0.05577169 0.06687650 0.00393391 # 3 -382.05059234 -382.05069136 -0.00009902 0.00694359 0.01069889 0.00062935 0.01654549 0.02016307 0.00118606 # 4 -382.05069136 -382.05069130 0.00000006 0.00295497 0.00363023 0.00021354 0.00234307 0.00443525 0.00026090 # 5 -382.05069130 -382.05069206 -0.00000075 0.00098220 0.00121031 0.00007119 0.00116863 0.00140452 0.00008262 # 6 -382.05069206 -382.05069209 -0.00000003 0.00011350 0.00022306 0.00001312 0.00013321 0.00024526 0.00001443 if line[1:30] == "END OF GEOMETRY OPTIMIZATION.": blank = inputfile.next() headers = inputfile.next() # Although criteria can be changed, the printed format should not change. # In case it does, retrieve the columns for each parameter. headers = headers.split() index_THRENERG = headers.index('DE') index_THRGRAD = headers.index('GRADMAX') index_THRSTEP = headers.index('STEPMAX') line = inputfile.next() self.geovalues = [] while line.strip() != "": line = line.split() geovalues = [] geovalues.append(float(line[index_THRENERG])) geovalues.append(float(line[index_THRGRAD])) geovalues.append(float(line[index_THRSTEP])) self.geovalues.append(geovalues) line = inputfile.next() # This block should look like this: # Normal Modes # # 1 Au 2 Bu 3 Ag 4 Bg 5 Ag # Wavenumbers [cm-1] 151.81 190.88 271.17 299.59 407.86 # Intensities [km/mol] 0.33 0.28 0.00 0.00 0.00 # Intensities [relative] 0.34 0.28 0.00 0.00 0.00 # CX1 0.00000 -0.01009 0.02577 0.00000 0.06008 # CY1 0.00000 -0.05723 -0.06696 0.00000 0.06349 # CZ1 -0.02021 0.00000 0.00000 0.11848 0.00000 # CX2 0.00000 -0.01344 0.05582 0.00000 -0.02513 # CY2 0.00000 -0.06288 -0.03618 0.00000 0.00349 # CZ2 -0.05565 0.00000 0.00000 0.07815 0.00000 # ... # Molpro prints low frequency modes in a subsequent section with the same format, # which also contains zero frequency modes, with the title: # Normal Modes of low/zero frequencies if line[1:13] == "Normal Modes": if line[1:37] == "Normal Modes of low/zero frequencies": islow = True else: islow = False blank = inputfile.next() # Each portion of five modes is followed by a single blank line. # The whole block is followed by an additional blank line. line = inputfile.next() while line.strip(): if line[1:25].isspace(): numbers = map(int, line.split()[::2]) vibsyms = line.split()[1::2] if line[1:12] == "Wavenumbers": vibfreqs = map(float, line.strip().split()[2:]) if line[1:21] == "Intensities [km/mol]": vibirs = map(float, line.strip().split()[2:]) # There should always by 3xnatom displacement rows. if line[1:11].isspace() and line[13:25].strip().isdigit(): # There are a maximum of 5 modes per line. nmodes = len(line.split())-1 vibdisps = [] for i in range(nmodes): vibdisps.append([]) for n in range(self.natom): vibdisps[i].append([]) for i in range(nmodes): disp = float(line.split()[i+1]) vibdisps[i][0].append(disp) for i in range(self.natom*3 - 1): line = inputfile.next() iatom = (i+1)/3 for i in range(nmodes): disp = float(line.split()[i+1]) vibdisps[i][iatom].append(disp) line = inputfile.next() if not line.strip(): if not hasattr(self, "vibfreqs"): self.vibfreqs = [] if not hasattr(self, "vibsyms"): self.vibsyms = [] if not hasattr(self, "vibirs") and "vibirs" in dir(): self.vibirs = [] if not hasattr(self, "vibdisps") and "vibdisps" in dir(): self.vibdisps = [] if not islow: self.vibfreqs.extend(vibfreqs) self.vibsyms.extend(vibsyms) if "vibirs" in dir(): self.vibirs.extend(vibirs) if "vibdisps" in dir(): self.vibdisps.extend(vibdisps) else: nonzero = [f > 0 for f in vibfreqs] vibfreqs = [f for f in vibfreqs if f > 0] self.vibfreqs = vibfreqs + self.vibfreqs vibsyms = [vibsyms[i] for i in range(len(vibsyms)) if nonzero[i]] self.vibsyms = vibsyms + self.vibsyms if "vibirs" in dir(): vibirs = [vibirs[i] for i in range(len(vibirs)) if nonzero[i]] self.vibirs = vibirs + self.vibirs if "vibdisps" in dir(): vibdisps = [vibdisps[i] for i in range(len(vibdisps)) if nonzero[i]] self.vibdisps = vibdisps + self.vibdisps line = inputfile.next() if line[1:16] == "Force Constants": self.logger.info("Creating attribute hessian") self.hessian = [] line = inputfile.next() hess = [] tmp = [] while line.strip(): try: map(float, line.strip().split()[2:]) except: line = inputfile.next() line.strip().split()[1:] hess.extend([map(float, line.strip().split()[1:])]) line = inputfile.next() lig = 0 while (lig==0) or (len(hess[0]) > 1): tmp.append(hess.pop(0)) lig += 1 k = 5 while len(hess) != 0: tmp[k] += hess.pop(0) k += 1 if (len(tmp[k-1]) == lig): break if k >= lig: k = len(tmp[-1]) for l in tmp: self.hessian += l if line[1:14] == "Atomic Masses" and hasattr(self,"hessian"): line = inputfile.next() self.amass = map(float, line.strip().split()[2:]) while line.strip(): line = inputfile.next() self.amass += map(float, line.strip().split()[2:]) if __name__ == "__main__": import doctest, molproparser doctest.testmod(molproparser, verbose=False) GaussSum-2.2.6.1/gausssum/cclib/parser/ccopen.py0000664000175000017500000000630612117172552020155 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2009, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 992 $" import types import logfileparser import adfparser import gamessparser import gamessukparser import gaussianparser import jaguarparser import molproparser import orcaparser def ccopen(source, *args, **kargs): """Guess the identity of a particular log file and return an instance of it. Inputs: source - a single logfile, a list of logfiles, or an input stream Returns: one of ADF, GAMESS, GAMESS UK, Gaussian, Jaguar, Molpro, ORCA, or None (if it cannot figure it out or the file does not exist). """ filetype = None # Try to open the logfile(s), using openlogfile. if isinstance(source, types.StringTypes) or \ isinstance(source, list) and all([isinstance(s, types.StringTypes) for s in source]): try: inputfile = logfileparser.openlogfile(source) except IOError, (errno, strerror): print "I/O error %s (%s): %s" % (errno, source, strerror) return None isstream = False elif hasattr(source, "read"): inputfile = source isstream = True else: raise ValueError # Read through the logfile(s) and search for a clue. for line in inputfile: if line.find("Amsterdam Density Functional") >= 0: filetype = adfparser.ADF break # Don't break in this case as it may be a GAMESS-UK file. elif line.find("GAMESS") >= 0: filetype = gamessparser.GAMESS # This can break, since it is non-GAMESS-UK specific. elif line.find("GAMESS VERSION") >= 0: filetype = gamessparser.GAMESS break elif line.find("G A M E S S - U K") >= 0: filetype = gamessukparser.GAMESSUK break elif line.find("Gaussian, Inc.") >= 0: filetype = gaussianparser.Gaussian break elif line.find("Jaguar") >= 0: filetype = jaguarparser.Jaguar break elif line.find("PROGRAM SYSTEM MOLPRO") >= 0: filetype = molproparser.Molpro break # Molpro log files don't have the line above. Set this only if # nothing else is detected, and notice it can be overwritten, # since it does not break the loop. elif line[0:8] == "1PROGRAM" and not filetype: filetype = molproparser.Molpro elif line.find("O R C A") >= 0: filetype = orcaparser.ORCA break # Need to close file before creating a instance. if not isstream: inputfile.close() # Return an instance of the chosen class. try: return filetype(source, *args, **kargs) except TypeError: print "Log file type not identified." raise GaussSum-2.2.6.1/gausssum/cclib/parser/gaussianparser.py0000664000175000017500000014762112117172552021743 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 1026 $" import re import numpy import logfileparser import utils class Gaussian(logfileparser.Logfile): """A Gaussian 98/03 log file.""" def __init__(self, *args, **kwargs): # Call the __init__ method of the superclass super(Gaussian, self).__init__(logname="Gaussian", *args, **kwargs) def __str__(self): """Return a string representation of the object.""" return "Gaussian log file %s" % (self.filename) def __repr__(self): """Return a representation of the object.""" return 'Gaussian("%s")' % (self.filename) def normalisesym(self, label): """Use standard symmetry labels instead of Gaussian labels. To normalise: (1) If label is one of [SG, PI, PHI, DLTA], replace by [sigma, pi, phi, delta] (2) replace any G or U by their lowercase equivalent >>> sym = Gaussian("dummyfile").normalisesym >>> labels = ['A1', 'AG', 'A1G', "SG", "PI", "PHI", "DLTA", 'DLTU', 'SGG'] >>> map(sym, labels) ['A1', 'Ag', 'A1g', 'sigma', 'pi', 'phi', 'delta', 'delta.u', 'sigma.g'] """ # note: DLT must come after DLTA greek = [('SG', 'sigma'), ('PI', 'pi'), ('PHI', 'phi'), ('DLTA', 'delta'), ('DLT', 'delta')] for k, v in greek: if label.startswith(k): tmp = label[len(k):] label = v if tmp: label = v + "." + tmp ans = label.replace("U", "u").replace("G", "g") return ans def before_parsing(self): # Used to index self.scftargets[]. SCFRMS, SCFMAX, SCFENERGY = range(3) # Flag that indicates whether it has reached the end of a geoopt. self.optfinished = False # Flag for identifying Coupled Cluster runs. self.coupledcluster = False # Fragment number for counterpoise or fragment guess calculations # (normally zero). self.counterpoise = 0 # Flag for identifying ONIOM calculations. self.oniom = False def after_parsing(self): # Correct the percent values in the etsecs in the case of # a restricted calculation. The following has the # effect of including each transition twice. if hasattr(self, "etsecs") and len(self.homos) == 1: new_etsecs = [[(x[0], x[1], x[2] * numpy.sqrt(2)) for x in etsec] for etsec in self.etsecs] self.etsecs = new_etsecs if hasattr(self, "scanenergies"): self.scancoords = [] self.scancoords = self.atomcoords if (hasattr(self, 'enthaply') and hasattr(self, 'temperature') and hasattr(self, 'freeenergy')): self.entropy = (self.enthaply - self.freeenergy)/self.temperature def extract(self, inputfile, line): """Extract information from the file object inputfile.""" #Extract PES scan data #Summary of the potential surface scan: # N A SCF #---- --------- ----------- # 1 109.0000 -76.43373 # 2 119.0000 -76.43011 # 3 129.0000 -76.42311 # 4 139.0000 -76.41398 # 5 149.0000 -76.40420 # 6 159.0000 -76.39541 # 7 169.0000 -76.38916 # 8 179.0000 -76.38664 # 9 189.0000 -76.38833 # 10 199.0000 -76.39391 # 11 209.0000 -76.40231 #---- --------- ----------- if "Summary of the potential surface scan:" in line: scanenergies = [] scanparm = [] colmnames = inputfile.next() hyphens = inputfile.next() line = inputfile.next() while line != hyphens: broken = line.split() scanenergies.append(float(broken[-1])) scanparm.append(map(float, broken[1:-1])) line = inputfile.next() if not hasattr(self, "scanenergies"): self.scanenergies = [] self.scanenergies = scanenergies if not hasattr(self, "scanparm"): self.scanparm = [] self.scanparm = scanparm if not hasattr(self, "scannames"): self.scannames = colmnames.split()[1:-1] #Extract Thermochemistry #Temperature 298.150 Kelvin. Pressure 1.00000 Atm. #Zero-point correction= 0.342233 (Hartree/ #Thermal correction to Energy= 0. #Thermal correction to Enthalpy= 0. #Thermal correction to Gibbs Free Energy= 0.302940 #Sum of electronic and zero-point Energies= -563.649744 #Sum of electronic and thermal Energies= -563.636699 #Sum of electronic and thermal Enthalpies= -563.635755 #Sum of electronic and thermal Free Energies= -563.689037 if "Sum of electronic and thermal Enthalpies" in line: if not hasattr(self, 'enthaply'): self.enthaply = float(line.split()[6]) if "Sum of electronic and thermal Free Energies=" in line: if not hasattr(self, 'freeenergy'): self.freeenergy = float(line.split()[7]) if line[1:12] == "Temperature": if not hasattr(self, 'temperature'): self.temperature = float(line.split()[1]) # Number of atoms. if line[1:8] == "NAtoms=": self.updateprogress(inputfile, "Attributes", self.fupdate) natom = int(line.split()[1]) if not hasattr(self, "natom"): self.natom = natom # Catch message about completed optimization. if line[1:23] == "Optimization completed": self.optfinished = True self.optdone = True # Extract the atomic numbers and coordinates from the input orientation, # in the event the standard orientation isn't available. if not self.optfinished and line.find("Input orientation") > -1 or line.find("Z-Matrix orientation") > -1: # If this is a counterpoise calculation, this output means that # the supermolecule is now being considered, so we can set: self.counterpoise = 0 self.updateprogress(inputfile, "Attributes", self.cupdate) if not hasattr(self, "inputcoords"): self.inputcoords = [] self.inputatoms = [] hyphens = inputfile.next() colmNames = inputfile.next() colmNames = inputfile.next() hyphens = inputfile.next() atomcoords = [] line = inputfile.next() while line != hyphens: broken = line.split() self.inputatoms.append(int(broken[1])) atomcoords.append(map(float, broken[3:6])) line = inputfile.next() self.inputcoords.append(atomcoords) if not hasattr(self, "atomnos"): self.atomnos = numpy.array(self.inputatoms, 'i') self.natom = len(self.atomnos) # Extract the atomic masses. # Typical section: # Isotopes and Nuclear Properties: #(Nuclear quadrupole moments (NQMom) in fm**2, nuclear magnetic moments (NMagM) # in nuclear magnetons) # # Atom 1 2 3 4 5 6 7 8 9 10 # IAtWgt= 12 12 12 12 12 1 1 1 12 12 # AtmWgt= 12.0000000 12.0000000 12.0000000 12.0000000 12.0000000 1.0078250 1.0078250 1.0078250 12.0000000 12.0000000 # NucSpn= 0 0 0 0 0 1 1 1 0 0 # AtZEff= -3.6000000 -3.6000000 -3.6000000 -3.6000000 -3.6000000 -1.0000000 -1.0000000 -1.0000000 -3.6000000 -3.6000000 # NQMom= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 # NMagM= 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 2.7928460 2.7928460 2.7928460 0.0000000 0.0000000 # ... with blank lines dividing blocks of ten, and Leave Link 101 at the end. # This is generally parsed before coordinates, so atomnos is not defined. # Note that in Gaussian03 the comments are not there yet and the labels are different. if line.strip() == "Isotopes and Nuclear Properties:": if not hasattr(self, "atommasses"): self.atommasses = [] line = inputfile.next() while line[1:16] != "Leave Link 101": if line[1:8] == "AtmWgt=": self.atommasses.extend(map(float, line.split()[1:])) line = inputfile.next() # Extract the atomic numbers and coordinates of the atoms. if not self.optfinished and line.strip() == "Standard orientation:": self.updateprogress(inputfile, "Attributes", self.cupdate) # If this is a counterpoise calculation, this output means that # the supermolecule is now being considered, so we can set: self.counterpoise = 0 if not hasattr(self, "atomcoords"): self.atomcoords = [] hyphens = inputfile.next() colmNames = inputfile.next() colmNames = inputfile.next() hyphens = inputfile.next() atomnos = [] atomcoords = [] line = inputfile.next() while line != hyphens: broken = line.split() atomnos.append(int(broken[1])) atomcoords.append(map(float, broken[-3:])) line = inputfile.next() self.atomcoords.append(atomcoords) if not hasattr(self, "natom"): self.atomnos = numpy.array(atomnos, 'i') self.natom = len(self.atomnos) # make sure atomnos is added for the case where natom has already been set elif not hasattr(self, "atomnos"): self.atomnos = numpy.array(atomnos, 'i') # Find the targets for SCF convergence (QM calcs). if line[1:44] == 'Requested convergence on RMS density matrix': if not hasattr(self, "scftargets"): self.scftargets = [] # The following can happen with ONIOM which are mixed SCF # and semi-empirical if type(self.scftargets) == type(numpy.array([])): self.scftargets = [] scftargets = [] # The RMS density matrix. scftargets.append(self.float(line.split('=')[1].split()[0])) line = inputfile.next() # The MAX density matrix. scftargets.append(self.float(line.strip().split('=')[1][:-1])) line = inputfile.next() # For G03, there's also the energy (not for G98). if line[1:10] == "Requested": scftargets.append(self.float(line.strip().split('=')[1][:-1])) self.scftargets.append(scftargets) # Extract SCF convergence information (QM calcs). if line[1:10] == 'Cycle 1': if not hasattr(self, "scfvalues"): self.scfvalues = [] scfvalues = [] line = inputfile.next() while line.find("SCF Done") == -1: self.updateprogress(inputfile, "QM convergence", self.fupdate) if line.find(' E=') == 0: self.logger.debug(line) # RMSDP=3.74D-06 MaxDP=7.27D-05 DE=-1.73D-07 OVMax= 3.67D-05 # or # RMSDP=1.13D-05 MaxDP=1.08D-04 OVMax= 1.66D-04 if line.find(" RMSDP") == 0: parts = line.split() newlist = [self.float(x.split('=')[1]) for x in parts[0:2]] energy = 1.0 if len(parts) > 4: energy = parts[2].split('=')[1] if energy == "": energy = self.float(parts[3]) else: energy = self.float(energy) if len(self.scftargets[0]) == 3: # Only add the energy if it's a target criteria newlist.append(energy) scfvalues.append(newlist) try: line = inputfile.next() # May be interupted by EOF. except StopIteration: break self.scfvalues.append(scfvalues) # Extract SCF convergence information (AM1 calcs). if line[1:4] == 'It=': self.scftargets = numpy.array([1E-7], "d") # This is the target value for the rms self.scfvalues = [[]] line = inputfile.next() while line.find(" Energy") == -1: if self.progress: step = inputfile.tell() if step != oldstep: self.progress.update(step, "AM1 Convergence") oldstep = step if line[1:4] == "It=": parts = line.strip().split() self.scfvalues[0].append(self.float(parts[-1][:-1])) line = inputfile.next() # Note: this needs to follow the section where 'SCF Done' is used # to terminate a loop when extracting SCF convergence information. if line[1:9] == 'SCF Done': if not hasattr(self, "scfenergies"): self.scfenergies = [] self.scfenergies.append(utils.convertor(self.float(line.split()[4]), "hartree", "eV")) # gmagoon 5/27/09: added scfenergies reading for PM3 case # Example line: " Energy= -0.077520562724 NIter= 14." # See regression Gaussian03/QVGXLLKOCUKJST-UHFFFAOYAJmult3Fixed.out if line[1:8] == 'Energy=': if not hasattr(self, "scfenergies"): self.scfenergies = [] self.scfenergies.append(utils.convertor(self.float(line.split()[1]), "hartree", "eV")) # Total energies after Moller-Plesset corrections. # Second order correction is always first, so its first occurance # triggers creation of mpenergies (list of lists of energies). # Further MP2 corrections are appended as found. # # Example MP2 output line: # E2 = -0.9505918144D+00 EUMP2 = -0.28670924198852D+03 # Warning! this output line is subtly different for MP3/4/5 runs if "EUMP2" in line[27:34]: if not hasattr(self, "mpenergies"): self.mpenergies = [] self.mpenergies.append([]) mp2energy = self.float(line.split("=")[2]) self.mpenergies[-1].append(utils.convertor(mp2energy, "hartree", "eV")) # Example MP3 output line: # E3= -0.10518801D-01 EUMP3= -0.75012800924D+02 if line[34:39] == "EUMP3": mp3energy = self.float(line.split("=")[2]) self.mpenergies[-1].append(utils.convertor(mp3energy, "hartree", "eV")) # Example MP4 output lines: # E4(DQ)= -0.31002157D-02 UMP4(DQ)= -0.75015901139D+02 # E4(SDQ)= -0.32127241D-02 UMP4(SDQ)= -0.75016013648D+02 # E4(SDTQ)= -0.32671209D-02 UMP4(SDTQ)= -0.75016068045D+02 # Energy for most substitutions is used only (SDTQ by default) if line[34:42] == "UMP4(DQ)": mp4energy = self.float(line.split("=")[2]) line = inputfile.next() if line[34:43] == "UMP4(SDQ)": mp4energy = self.float(line.split("=")[2]) line = inputfile.next() if line[34:44] == "UMP4(SDTQ)": mp4energy = self.float(line.split("=")[2]) self.mpenergies[-1].append(utils.convertor(mp4energy, "hartree", "eV")) # Example MP5 output line: # DEMP5 = -0.11048812312D-02 MP5 = -0.75017172926D+02 if line[29:32] == "MP5": mp5energy = self.float(line.split("=")[2]) self.mpenergies[-1].append(utils.convertor(mp5energy, "hartree", "eV")) # Total energies after Coupled Cluster corrections. # Second order MBPT energies (MP2) are also calculated for these runs, # but the output is the same as when parsing for mpenergies. # Read the consecutive correlated energies # but append only the last one to ccenergies. # Only the highest level energy is appended - ex. CCSD(T), not CCSD. if line[1:10] == "DE(Corr)=" and line[27:35] == "E(CORR)=": self.ccenergy = self.float(line.split()[3]) if line[1:10] == "T5(CCSD)=": line = inputfile.next() if line[1:9] == "CCSD(T)=": self.ccenergy = self.float(line.split()[1]) if line[12:53] == "Population analysis using the SCF density": if hasattr(self, "ccenergy"): if not hasattr(self, "ccenergies"): self.ccenergies = [] self.ccenergies.append(utils.convertor(self.ccenergy, "hartree", "eV")) del self.ccenergy # Geometry convergence information. if line[49:59] == 'Converged?': if not hasattr(self, "geotargets"): self.geovalues = [] self.geotargets = numpy.array([0.0, 0.0, 0.0, 0.0], "d") newlist = [0]*4 for i in range(4): line = inputfile.next() self.logger.debug(line) parts = line.split() try: value = self.float(parts[2]) except ValueError: self.logger.error("Problem parsing the value for geometry optimisation: %s is not a number." % parts[2]) else: newlist[i] = value self.geotargets[i] = self.float(parts[3]) self.geovalues.append(newlist) # Gradients. # Read in the cartesian energy gradients (forces) from a block like this: # ------------------------------------------------------------------- # Center Atomic Forces (Hartrees/Bohr) # Number Number X Y Z # ------------------------------------------------------------------- # 1 1 -0.012534744 -0.021754635 -0.008346094 # 2 6 0.018984731 0.032948887 -0.038003451 # 3 1 -0.002133484 -0.006226040 0.023174772 # 4 1 -0.004316502 -0.004968213 0.023174772 # -2 -0.001830728 -0.000743108 -0.000196625 # ------------------------------------------------------------------ # # The "-2" line is for a dummy atom # # Then optimization is done in internal coordinates, Gaussian also # print the forces in internal coordinates, which can be produced from # the above. This block looks like this: # Variable Old X -DE/DX Delta X Delta X Delta X New X # (Linear) (Quad) (Total) # ch 2.05980 0.01260 0.00000 0.01134 0.01134 2.07114 # hch 1.75406 0.09547 0.00000 0.24861 0.24861 2.00267 # hchh 2.09614 0.01261 0.00000 0.16875 0.16875 2.26489 # Item Value Threshold Converged? if line[37:43] == "Forces": if not hasattr(self, "grads"): self.grads = [] header = inputfile.next() dashes = inputfile.next() line = inputfile.next() forces = [] while line != dashes: broken = line.split() Fx, Fy, Fz = broken[-3:] forces.append([float(Fx), float(Fy), float(Fz)]) line = inputfile.next() self.grads.append(forces) # Charge and multiplicity. # If counterpoise correction is used, multiple lines match. # The first one contains charge/multiplicity of the whole molecule.: # Charge = 0 Multiplicity = 1 in supermolecule # Charge = 0 Multiplicity = 1 in fragment 1. # Charge = 0 Multiplicity = 1 in fragment 2. if line[1:7] == 'Charge' and line.find("Multiplicity")>=0: regex = ".*=(.*)Mul.*=\s*-?(\d+).*" match = re.match(regex, line) assert match, "Something unusual about the line: '%s'" % line if not hasattr(self, "charge"): self.charge = int(match.groups()[0]) if not hasattr(self, "mult"): self.mult = int(match.groups()[1]) # Orbital symmetries. if line[1:20] == 'Orbital symmetries:' and not hasattr(self, "mosyms"): # For counterpoise fragments, skip these lines. if self.counterpoise != 0: return self.updateprogress(inputfile, "MO Symmetries", self.fupdate) self.mosyms = [[]] line = inputfile.next() unres = False if line.find("Alpha Orbitals") == 1: unres = True line = inputfile.next() i = 0 while len(line) > 18 and line[17] == '(': if line.find('Virtual') >= 0: self.homos = numpy.array([i-1], "i") # 'HOMO' indexes the HOMO in the arrays parts = line[17:].split() for x in parts: self.mosyms[0].append(self.normalisesym(x.strip('()'))) i += 1 line = inputfile.next() if unres: line = inputfile.next() # Repeat with beta orbital information i = 0 self.mosyms.append([]) while len(line) > 18 and line[17] == '(': if line.find('Virtual')>=0: # Here we consider beta # If there was also an alpha virtual orbital, # we will store two indices in the array # Otherwise there is no alpha virtual orbital, # only beta virtual orbitals, and we initialize # the array with one element. See the regression # QVGXLLKOCUKJST-UHFFFAOYAJmult3Fixed.out # donated by Gregory Magoon (gmagoon). if (hasattr(self, "homos")): # Extend the array to two elements # 'HOMO' indexes the HOMO in the arrays self.homos.resize([2]) self.homos[1] = i-1 else: # 'HOMO' indexes the HOMO in the arrays self.homos = numpy.array([i-1], "i") parts = line[17:].split() for x in parts: self.mosyms[1].append(self.normalisesym(x.strip('()'))) i += 1 line = inputfile.next() # Alpha/Beta electron eigenvalues. if line[1:6] == "Alpha" and line.find("eigenvalues") >= 0: # For counterpoise fragments, skip these lines. if self.counterpoise != 0: return # For ONIOM calcs, ignore this section in order to bypass assertion failure. if self.oniom: return self.updateprogress(inputfile, "Eigenvalues", self.fupdate) self.moenergies = [[]] HOMO = -2 while line.find('Alpha') == 1: if line.split()[1] == "virt." and HOMO == -2: # If there aren't any symmetries, this is a good way to find the HOMO. # Also, check for consistency if homos was already parsed. HOMO = len(self.moenergies[0])-1 if hasattr(self, "homos"): assert HOMO == self.homos[0] else: self.homos = numpy.array([HOMO], "i") # Convert to floats and append to moenergies, but sometimes Gaussian # doesn't print correctly so test for ValueError (bug 1756789). part = line[28:] i = 0 while i*10+4 < len(part): s = part[i*10:(i+1)*10] try: x = self.float(s) except ValueError: x = numpy.nan self.moenergies[0].append(utils.convertor(x, "hartree", "eV")) i += 1 line = inputfile.next() # If, at this point, self.homos is unset, then there were not # any alpha virtual orbitals if not hasattr(self, "homos"): HOMO = len(self.moenergies[0])-1 self.homos = numpy.array([HOMO], "i") if line.find('Beta') == 2: self.moenergies.append([]) HOMO = -2 while line.find('Beta') == 2: if line.split()[1] == "virt." and HOMO == -2: # If there aren't any symmetries, this is a good way to find the HOMO. # Also, check for consistency if homos was already parsed. HOMO = len(self.moenergies[1])-1 if len(self.homos) == 2: assert HOMO == self.homos[1] else: self.homos.resize([2]) self.homos[1] = HOMO part = line[28:] i = 0 while i*10+4 < len(part): x = part[i*10:(i+1)*10] self.moenergies[1].append(utils.convertor(self.float(x), "hartree", "eV")) i += 1 line = inputfile.next() self.moenergies = [numpy.array(x, "d") for x in self.moenergies] # Gaussian Rev <= B.0.3 (?) # AO basis set in the form of general basis input: # 1 0 # S 3 1.00 0.000000000000 # 0.7161683735D+02 0.1543289673D+00 # 0.1304509632D+02 0.5353281423D+00 # 0.3530512160D+01 0.4446345422D+00 # SP 3 1.00 0.000000000000 # 0.2941249355D+01 -0.9996722919D-01 0.1559162750D+00 # 0.6834830964D+00 0.3995128261D+00 0.6076837186D+00 # 0.2222899159D+00 0.7001154689D+00 0.3919573931D+00 if line[1:16] == "AO basis set in": # For counterpoise fragment calcualtions, skip these lines. if self.counterpoise != 0: return self.gbasis = [] line = inputfile.next() while line.strip(): gbasis = [] line = inputfile.next() while line.find("*")<0: temp = line.split() symtype = temp[0] numgau = int(temp[1]) gau = [] for i in range(numgau): temp = map(self.float, inputfile.next().split()) gau.append(temp) for i, x in enumerate(symtype): newgau = [(z[0], z[i+1]) for z in gau] gbasis.append((x, newgau)) line = inputfile.next() # i.e. "****" or "SP ...." self.gbasis.append(gbasis) line = inputfile.next() # i.e. "20 0" or blank line # Start of the IR/Raman frequency section. # Caution is advised here, as additional frequency blocks # can be printed by Gaussian (with slightly different formats), # often doubling the information printed. # See, for a non-standard exmaple, regression Gaussian98/test_H2.log if line[1:14] == "Harmonic freq": self.updateprogress(inputfile, "Frequency Information", self.fupdate) removeold = False # The whole block should not have any blank lines. while line.strip() != "": # The line with indices if line[1:15].strip() == "" and line[15:22].strip().isdigit(): freqbase = int(line[15:22]) if freqbase == 1 and hasattr(self, 'vibfreqs'): # This is a reparse of this information removeold = True # Lines with symmetries and symm. indices begin with whitespace. if line[1:15].strip() == "" and not line[15:22].strip().isdigit(): if not hasattr(self, 'vibsyms'): self.vibsyms = [] syms = line.split() self.vibsyms.extend(syms) if line[1:15] == "Frequencies --": if not hasattr(self, 'vibfreqs'): self.vibfreqs = [] if removeold: # This is a reparse, so throw away the old info if hasattr(self, "vibsyms"): # We have already parsed the vibsyms so don't throw away! self.vibsyms = self.vibsyms[-len(line[15:].split()):] if hasattr(self, "vibirs"): self.vibirs = [] if hasattr(self, 'vibfreqs'): self.vibfreqs = [] if hasattr(self, 'vibramans'): self.vibramans = [] if hasattr(self, 'vibdisps'): self.vibdisps = [] removeold = False freqs = [self.float(f) for f in line[15:].split()] self.vibfreqs.extend(freqs) if line[1:15] == "IR Inten --": if not hasattr(self, 'vibirs'): self.vibirs = [] irs = [self.float(f) for f in line[15:].split()] self.vibirs.extend(irs) if line[1:15] == "Raman Activ --": if not hasattr(self, 'vibramans'): self.vibramans = [] ramans = [self.float(f) for f in line[15:].split()] self.vibramans.extend(ramans) # Block with displacement should start with this. if line.strip().split()[0:3] == ["Atom", "AN", "X"]: if not hasattr(self, 'vibdisps'): self.vibdisps = [] disps = [] for n in range(self.natom): line = inputfile.next() numbers = [float(s) for s in line[10:].split()] N = len(numbers) / 3 if not disps: for n in range(N): disps.append([]) for n in range(N): disps[n].append(numbers[3*n:3*n+3]) self.vibdisps.extend(disps) line = inputfile.next() # Below is the old code for the IR/Raman frequency block, can probably be removed. # while len(line[:15].split()) == 0: # self.logger.debug(line) # self.vibsyms.extend(line.split()) # Adding new symmetry # line = inputfile.next() # # Read in frequencies. # freqs = [self.float(f) for f in line.split()[2:]] # self.vibfreqs.extend(freqs) # line = inputfile.next() # line = inputfile.next() # line = inputfile.next() # irs = [self.float(f) for f in line.split()[3:]] # self.vibirs.extend(irs) # line = inputfile.next() # Either the header or a Raman line # if line.find("Raman") >= 0: # if not hasattr(self, "vibramans"): # self.vibramans = [] # ramans = [self.float(f) for f in line.split()[3:]] # self.vibramans.extend(ramans) # line = inputfile.next() # Depolar (P) # line = inputfile.next() # Depolar (U) # line = inputfile.next() # Header # line = inputfile.next() # First line of cartesian displacement vectors # p = [[], [], []] # while len(line[:15].split()) > 0: # # Store the cartesian displacement vectors # broken = map(float, line.strip().split()[2:]) # for i in range(0, len(broken), 3): # p[i/3].append(broken[i:i+3]) # line = inputfile.next() # self.vibdisps.extend(p[0:len(broken)/3]) # line = inputfile.next() # Should be the line with symmetries # self.vibfreqs = numpy.array(self.vibfreqs, "d") # self.vibirs = numpy.array(self.vibirs, "d") # self.vibdisps = numpy.array(self.vibdisps, "d") # if hasattr(self, "vibramans"): # self.vibramans = numpy.array(self.vibramans, "d") # Electronic transitions. if line[1:14] == "Excited State": if not hasattr(self, "etenergies"): self.etenergies = [] self.etoscs = [] self.etsyms = [] self.etsecs = [] # Need to deal with lines like: # (restricted calc) # Excited State 1: Singlet-BU 5.3351 eV 232.39 nm f=0.1695 # (unrestricted calc) (first excited state is 2!) # Excited State 2: ?Spin -A 0.1222 eV 10148.75 nm f=0.0000 # (Gaussian 09 ZINDO) # Excited State 1: Singlet-?Sym 2.5938 eV 478.01 nm f=0.0000 =0.000 p = re.compile(":(?P.*?)(?P-?\d*\.\d*) eV") groups = p.search(line).groups() self.etenergies.append(utils.convertor(self.float(groups[1]), "eV", "cm-1")) self.etoscs.append(self.float(line.split("f=")[-1].split()[0])) self.etsyms.append(groups[0].strip()) line = inputfile.next() p = re.compile("(\d+)") CIScontrib = [] while line.find(" ->") >= 0: # This is a contribution to the transition parts = line.split("->") self.logger.debug(parts) # Has to deal with lines like: # 32 -> 38 0.04990 # 35A -> 45A 0.01921 frommoindex = 0 # For restricted or alpha unrestricted fromMO = parts[0].strip() if fromMO[-1] == "B": frommoindex = 1 # For beta unrestricted fromMO = int(p.match(fromMO).group())-1 # subtract 1 so that it is an index into moenergies t = parts[1].split() tomoindex = 0 toMO = t[0] if toMO[-1] == "B": tomoindex = 1 toMO = int(p.match(toMO).group())-1 # subtract 1 so that it is an index into moenergies percent = self.float(t[1]) # For restricted calculations, the percentage will be corrected # after parsing (see after_parsing() above). CIScontrib.append([(fromMO, frommoindex), (toMO, tomoindex), percent]) line = inputfile.next() self.etsecs.append(CIScontrib) # Circular dichroism data (different for G03 vs G09) # G03 ## <0|r|b> * (Au), Rotatory Strengths (R) in ## cgs (10**-40 erg-esu-cm/Gauss) ## state X Y Z R(length) ## 1 0.0006 0.0096 -0.0082 -0.4568 ## 2 0.0251 -0.0025 0.0002 -5.3846 ## 3 0.0168 0.4204 -0.3707 -15.6580 ## 4 0.0721 0.9196 -0.9775 -3.3553 # G09 ## 1/2[<0|r|b>* + (<0|rxdel|b>*)*] ## Rotatory Strengths (R) in cgs (10**-40 erg-esu-cm/Gauss) ## state XX YY ZZ R(length) R(au) ## 1 -0.3893 -6.7546 5.7736 -0.4568 -0.0010 ## 2 -17.7437 1.7335 -0.1435 -5.3845 -0.0114 ## 3 -11.8655 -297.2604 262.1519 -15.6580 -0.0332 if (line[1:52] == "<0|r|b> * (Au), Rotatory Strengths (R)" or line[1:50] == "1/2[<0|r|b>* + (<0|rxdel|b>*)*]"): self.etrotats = [] inputfile.next() # Units headers = inputfile.next() # Headers Ncolms = len(headers.split()) line = inputfile.next() parts = line.strip().split() while len(parts) == Ncolms: try: R = self.float(parts[4]) except ValueError: # nan or -nan if there is no first excited state # (for unrestricted calculations) pass else: self.etrotats.append(R) line = inputfile.next() temp = line.strip().split() parts = line.strip().split() self.etrotats = numpy.array(self.etrotats, "d") # Number of basis sets functions. # Has to deal with lines like: # NBasis = 434 NAE= 97 NBE= 97 NFC= 34 NFV= 0 # and... # NBasis = 148 MinDer = 0 MaxDer = 0 # Although the former is in every file, it doesn't occur before # the overlap matrix is printed. if line[1:7] == "NBasis" or line[4:10] == "NBasis": # For counterpoise fragment, skip these lines. if self.counterpoise != 0: return # For ONIOM calcs, ignore this section in order to bypass assertion failure. if self.oniom: return # If nbasis was already parsed, check if it changed. nbasis = int(line.split('=')[1].split()[0]) if hasattr(self, "nbasis"): assert nbasis == self.nbasis else: self.nbasis = nbasis # Number of linearly-independent basis sets. if line[1:7] == "NBsUse": # For counterpoise fragment, skip these lines. if self.counterpoise != 0: return # For ONIOM calcs, ignore this section in order to bypass assertion failure. if self.oniom: return nmo = int(line.split('=')[1].split()[0]) if hasattr(self, "nmo"): assert nmo == self.nmo else: self.nmo = nmo # For AM1 calculations, set nbasis by a second method, # as nmo may not always be explicitly stated. if line[7:22] == "basis functions, ": nbasis = int(line.split()[0]) if hasattr(self, "nbasis"): assert nbasis == self.nbasis else: self.nbasis = nbasis # Molecular orbital overlap matrix. # Has to deal with lines such as: # *** Overlap *** # ****** Overlap ****** # Note that Gaussian sometimes drops basis functions, # causing the overlap matrix as parsed below to not be # symmetric (which is a problem for population analyses, etc.) if line[1:4] == "***" and (line[5:12] == "Overlap" or line[8:15] == "Overlap"): # Ensure that this is the main calc and not a fragment if self.counterpoise != 0: return self.aooverlaps = numpy.zeros( (self.nbasis, self.nbasis), "d") # Overlap integrals for basis fn#1 are in aooverlaps[0] base = 0 colmNames = inputfile.next() while base < self.nbasis: self.updateprogress(inputfile, "Overlap", self.fupdate) for i in range(self.nbasis-base): # Fewer lines this time line = inputfile.next() parts = line.split() for j in range(len(parts)-1): # Some lines are longer than others k = float(parts[j+1].replace("D", "E")) self.aooverlaps[base+j, i+base] = k self.aooverlaps[i+base, base+j] = k base += 5 colmNames = inputfile.next() self.aooverlaps = numpy.array(self.aooverlaps, "d") # Molecular orbital coefficients (mocoeffs). # Essentially only produced for SCF calculations. # This is also the place where aonames and atombasis are parsed. if line[5:35] == "Molecular Orbital Coefficients" or line[5:41] == "Alpha Molecular Orbital Coefficients" or line[5:40] == "Beta Molecular Orbital Coefficients": # If counterpoise fragment, return without parsing orbital info if self.counterpoise != 0: return # Skip this for ONIOM calcs if self.oniom: return if line[5:40] == "Beta Molecular Orbital Coefficients": beta = True if self.popregular: return # This was continue before refactoring the parsers. #continue # Not going to extract mocoeffs # Need to add an extra array to self.mocoeffs self.mocoeffs.append(numpy.zeros((self.nmo, self.nbasis), "d")) else: beta = False self.aonames = [] self.atombasis = [] mocoeffs = [numpy.zeros((self.nmo, self.nbasis), "d")] base = 0 self.popregular = False for base in range(0, self.nmo, 5): self.updateprogress(inputfile, "Coefficients", self.fupdate) colmNames = inputfile.next() if not colmNames.split(): self.logger.warning("Molecular coefficients header found but no coefficients.") break; if base == 0 and int(colmNames.split()[0]) != 1: # Implies that this is a POP=REGULAR calculation # and so, only aonames (not mocoeffs) will be extracted self.popregular = True symmetries = inputfile.next() eigenvalues = inputfile.next() for i in range(self.nbasis): line = inputfile.next() if i == 0: # Find location of the start of the basis function name start_of_basis_fn_name = line.find(line.split()[3]) - 1 if base == 0 and not beta: # Just do this the first time 'round parts = line[:start_of_basis_fn_name].split() if len(parts) > 1: # New atom if i > 0: self.atombasis.append(atombasis) atombasis = [] atomname = "%s%s" % (parts[2], parts[1]) orbital = line[start_of_basis_fn_name:20].strip() self.aonames.append("%s_%s" % (atomname, orbital)) atombasis.append(i) part = line[21:].replace("D", "E").rstrip() temp = [] for j in range(0, len(part), 10): temp.append(float(part[j:j+10])) if beta: self.mocoeffs[1][base:base + len(part) / 10, i] = temp else: mocoeffs[0][base:base + len(part) / 10, i] = temp if base == 0 and not beta: # Do the last update of atombasis self.atombasis.append(atombasis) if self.popregular: # We now have aonames, so no need to continue break if not self.popregular and not beta: self.mocoeffs = mocoeffs # Natural Orbital Coefficients (nocoeffs) - alternative for mocoeffs. # Most extensively formed after CI calculations, but not only. # Like for mocoeffs, this is also where aonames and atombasis are parsed. if line[5:33] == "Natural Orbital Coefficients": self.aonames = [] self.atombasis = [] nocoeffs = numpy.zeros((self.nmo, self.nbasis), "d") base = 0 self.popregular = False for base in range(0, self.nmo, 5): self.updateprogress(inputfile, "Coefficients", self.fupdate) colmNames = inputfile.next() if base == 0 and int(colmNames.split()[0]) != 1: # Implies that this is a POP=REGULAR calculation # and so, only aonames (not mocoeffs) will be extracted self.popregular = True # No symmetry line for natural orbitals. # symmetries = inputfile.next() eigenvalues = inputfile.next() for i in range(self.nbasis): line = inputfile.next() # Just do this the first time 'round. if base == 0: # Changed below from :12 to :11 to deal with Elmar Neumann's example. parts = line[:11].split() # New atom. if len(parts) > 1: if i > 0: self.atombasis.append(atombasis) atombasis = [] atomname = "%s%s" % (parts[2], parts[1]) orbital = line[11:20].strip() self.aonames.append("%s_%s" % (atomname, orbital)) atombasis.append(i) part = line[21:].replace("D", "E").rstrip() temp = [] for j in range(0, len(part), 10): temp.append(float(part[j:j+10])) nocoeffs[base:base + len(part) / 10, i] = temp # Do the last update of atombasis. if base == 0: self.atombasis.append(atombasis) # We now have aonames, so no need to continue. if self.popregular: break if not self.popregular: self.nocoeffs = nocoeffs # For FREQ=Anharm, extract anharmonicity constants if line[1:40] == "X matrix of Anharmonic Constants (cm-1)": Nvibs = len(self.vibfreqs) self.vibanharms = numpy.zeros( (Nvibs, Nvibs), "d") base = 0 colmNames = inputfile.next() while base < Nvibs: for i in range(Nvibs-base): # Fewer lines this time line = inputfile.next() parts = line.split() for j in range(len(parts)-1): # Some lines are longer than others k = float(parts[j+1].replace("D", "E")) self.vibanharms[base+j, i+base] = k self.vibanharms[i+base, base+j] = k base += 5 colmNames = inputfile.next() # Pseudopotential charges. if line.find("Pseudopotential Parameters") > -1: dashes = inputfile.next() label1 = inputfile.next() label2 = inputfile.next() dashes = inputfile.next() line = inputfile.next() if line.find("Centers:") < 0: return # This was continue before parser refactoring. # continue # Needs to handle code like the following: # # Center Atomic Valence Angular Power Coordinates # Number Number Electrons Momentum of R Exponent Coefficient X Y Z # =================================================================================================================================== # Centers: 1 # Centers: 16 # Centers: 21 24 # Centers: 99100101102 # 1 44 16 -4.012684 -0.696698 0.006750 # F and up # 0 554.3796303 -0.05152700 centers = [] while line.find("Centers:") >= 0: temp = line[10:] for i in range(0, len(temp)-3, 3): centers.append(int(temp[i:i+3])) line = inputfile.next() centers.sort() # Not always in increasing order self.coreelectrons = numpy.zeros(self.natom, "i") for center in centers: front = line[:10].strip() while not (front and int(front) == center): line = inputfile.next() front = line[:10].strip() info = line.split() self.coreelectrons[center-1] = int(info[1]) - int(info[2]) line = inputfile.next() # This will be printed for counterpoise calcualtions only. # To prevent crashing, we need to know which fragment is being considered. # Other information is also printed in lines that start like this. if line[1:14] == 'Counterpoise:': if line[42:50] == "fragment": self.counterpoise = int(line[51:54]) # This will be printed only during ONIOM calcs; use it to set a flag # that will allow assertion failures to be bypassed in the code. if line[1:7] == "ONIOM:": self.oniom = True if (line[1:24] == "Mulliken atomic charges" or line[1:22] == "Lowdin Atomic Charges"): if not hasattr(self, "atomcharges"): self.atomcharges = {} ones = inputfile.next() charges = [] nline = inputfile.next() while not "Sum of" in nline: charges.append(float(nline.split()[2])) nline = inputfile.next() if "Mulliken" in line: self.atomcharges["mulliken"] = charges else: self.atomcharges["lowdin"] = charges if __name__ == "__main__": import doctest, gaussianparser, sys if len(sys.argv) == 1: doctest.testmod(gaussianparser, verbose=False) if len(sys.argv) >= 2: parser = gaussianparser.Gaussian(sys.argv[1]) data = parser.parse() if len(sys.argv) > 2: for i in range(len(sys.argv[2:])): if hasattr(data, sys.argv[2 + i]): print getattr(data, sys.argv[2 + i]) GaussSum-2.2.6.1/gausssum/cclib/parser/gamessukparser.py0000664000175000017500000006147512117172552021752 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 1031 $" import re import numpy import logfileparser import utils class GAMESSUK(logfileparser.Logfile): """A GAMESS UK log file""" SCFRMS, SCFMAX, SCFENERGY = range(3) # Used to index self.scftargets[] def __init__(self, *args, **kwargs): # Call the __init__ method of the superclass super(GAMESSUK, self).__init__(logname="GAMESSUK", *args, **kwargs) def __str__(self): """Return a string representation of the object.""" return "GAMESS UK log file %s" % (self.filename) def __repr__(self): """Return a representation of the object.""" return 'GAMESSUK("%s")' % (self.filename) def normalisesym(self, label): """Use standard symmetry labels instead of GAMESS UK labels. >>> t = GAMESSUK("dummyfile.txt") >>> labels = ['a', 'a1', 'ag', "a'", 'a"', "a''", "a1''", 'a1"'] >>> labels.extend(["e1+", "e1-"]) >>> answer = [t.normalisesym(x) for x in labels] >>> answer ['A', 'A1', 'Ag', "A'", 'A"', 'A"', 'A1"', 'A1"', 'E1', 'E1'] """ label = label.replace("''", '"').replace("+", "").replace("-", "") ans = label[0].upper() + label[1:] return ans def before_parsing(self): # This will be used to detect the first set of "nuclear coordinates" in # a geometry-optimization self.firstnuccoords = True # used for determining whether to add a second mosyms, etc. self.betamosyms = self.betamoenergies = self.betamocoeffs = False def extract(self, inputfile, line): """Extract information from the file object inputfile.""" if line[1:22] == "total number of atoms": if not hasattr(self, "natom"): self.natom = int(line.split()[-1]) if line[3:44] == "convergence threshold in optimization run": # Assuming that this is only found in the case of OPTXYZ # (i.e. an optimization in Cartesian coordinates) self.geotargets = [float(line.split()[-2])] if line[32:61] == "largest component of gradient": # This is the geotarget in the case of OPTXYZ if not hasattr(self, "geovalues"): self.geovalues = [] self.geovalues.append([float(line.split()[4])]) if line[37:49] == "convergence?": # Get the geovalues and geotargets for OPTIMIZE if not hasattr(self, "geovalues"): self.geovalues = [] self.geotargets = [] geotargets = [] geovalues = [] for i in range(4): temp = line.split() geovalues.append(float(temp[2])) if not self.geotargets: geotargets.append(float(temp[-2])) line = inputfile.next() self.geovalues.append(geovalues) if not self.geotargets: self.geotargets = geotargets if line[40:58] == "molecular geometry": # Only one set of atomcoords is taken from this section # For geo-opts, more coordinates are taken from the "nuclear coordinates" if not hasattr(self, "atomcoords"): self.atomcoords = [] self.atomnos = [] stop = " "*9 + "*"*79 line = inputfile.next() while not line.startswith(stop): line = inputfile.next() line = inputfile.next() while not line.startswith(stop): line = inputfile.next() empty = inputfile.next() atomcoords = [] empty = inputfile.next() while not empty.startswith(stop): line = inputfile.next().split() # the coordinate data atomcoords.append(map(float, line[3:6])) self.atomnos.append(int(round(float(line[2])))) while line != empty: line = inputfile.next() # at this point, line is an empty line, right after # 1 or more lines containing basis set information empty = inputfile.next() # empty is either a row of asterisks or the empty line # before the row of coordinate data self.atomcoords.append(atomcoords) self.atomnos = numpy.array(self.atomnos, "i") if line[40:59] == "nuclear coordinates": # We need not remember the first geometry in the geo-opt as this will # be recorded already, in the "molecular geometry" section # (note: single-point calculations have no "nuclear coordinates" only # "molecular geometry") if self.progress: self.updateprogress(inputfile, "Coordinates") if self.firstnuccoords: self.firstnuccoords = False return # This was continue (in loop) before parser refactoring. # continue if not hasattr(self, "atomcoords"): self.atomcoords = [] self.atomnos = [] asterisk = inputfile.next() blank = inputfile.next() colmname = inputfile.next() equals = inputfile.next() atomcoords = [] atomnos = [] line = inputfile.next() while line != equals: temp = line.strip().split() atomcoords.append([utils.convertor(float(x), "bohr", "Angstrom") for x in temp[0:3]]) if not hasattr(self, "atomnos") or len(self.atomnos) == 0: atomnos.append(int(float(temp[3]))) line = inputfile.next() self.atomcoords.append(atomcoords) if not hasattr(self, "atomnos") or len(self.atomnos) == 0: self.atomnos = atomnos if line[1:32] == "total number of basis functions": self.nbasis = int(line.split()[-1]) while line.find("charge of molecule")<0: line = inputfile.next() self.charge = int(line.split()[-1]) self.mult = int(inputfile.next().split()[-1]) alpha = int(inputfile.next().split()[-1])-1 beta = int(inputfile.next().split()[-1])-1 if self.mult == 1: self.homos = numpy.array([alpha], "i") else: self.homos = numpy.array([alpha, beta], "i") if line[37:69] == "s-matrix over gaussian basis set": self.aooverlaps = numpy.zeros((self.nbasis, self.nbasis), "d") minus = inputfile.next() blank = inputfile.next() i = 0 while i < self.nbasis: if self.progress: self.updateprogress(inputfile, "Overlap") blank = inputfile.next() blank = inputfile.next() header = inputfile.next() blank = inputfile.next() blank = inputfile.next() for j in range(self.nbasis): temp = map(float, inputfile.next().split()[1:]) self.aooverlaps[j,(0+i):(len(temp)+i)] = temp i += len(temp) if line[18:43] == 'EFFECTIVE CORE POTENTIALS': self.coreelectrons = numpy.zeros(self.natom, 'i') asterisk = inputfile.next() line = inputfile.next() while line[15:46] != "*"*31: if line.find("for atoms ...")>=0: atomindex = [] line = inputfile.next() while line.find("core charge")<0: broken = line.split() atomindex.extend([int(x.split("-")[0]) for x in broken]) line = inputfile.next() charge = float(line.split()[4]) for idx in atomindex: self.coreelectrons[idx-1] = self.atomnos[idx-1] - charge line = inputfile.next() if line[3:27] == "Wavefunction convergence": self.scftarget = float(line.split()[-2]) self.scftargets = [] if line[11:22] == "normal mode": if not hasattr(self, "vibfreqs"): self.vibfreqs = [] self.vibirs = [] units = inputfile.next() xyz = inputfile.next() equals = inputfile.next() line = inputfile.next() while line != equals: temp = line.split() self.vibfreqs.append(float(temp[1])) self.vibirs.append(float(temp[-2])) line = inputfile.next() # Use the length of the vibdisps to figure out # how many rotations and translations to remove self.vibfreqs = self.vibfreqs[-len(self.vibdisps):] self.vibirs = self.vibirs[-len(self.vibdisps):] if line[44:73] == "normalised normal coordinates": self.vibdisps = [] equals = inputfile.next() blank = inputfile.next() blank = inputfile.next() freqnum = inputfile.next() while freqnum.find("=")<0: blank = inputfile.next() equals = inputfile.next() freqs = inputfile.next() equals = inputfile.next() blank = inputfile.next() header = inputfile.next() equals = inputfile.next() p = [ [] for x in range(9) ] for i in range(len(self.atomnos)): brokenx = map(float, inputfile.next()[25:].split()) brokeny = map(float, inputfile.next()[25:].split()) brokenz = map(float, inputfile.next()[25:].split()) for j, x in enumerate(zip(brokenx, brokeny, brokenz)): p[j].append(x) self.vibdisps.extend(p) blank = inputfile.next() blank = inputfile.next() freqnum = inputfile.next() if line[26:36] == "raman data": self.vibramans = [] stars = inputfile.next() blank = inputfile.next() header = inputfile.next() blank = inputfile.next() line = inputfile.next() while line[1] != "*": self.vibramans.append(float(line.split()[3])) blank = inputfile.next() line = inputfile.next() # Use the length of the vibdisps to figure out # how many rotations and translations to remove self.vibramans = self.vibramans[-len(self.vibdisps):] if line[3:11] == "SCF TYPE": self.scftype = line.split()[-2] assert self.scftype in ['rhf', 'uhf', 'gvb'], "%s not one of 'rhf', 'uhf' or 'gvb'" % self.scftype if line[15:31] == "convergence data": if not hasattr(self, "scfvalues"): self.scfvalues = [] self.scftargets.append([self.scftarget]) # Assuming it does not change over time while line[1:10] != "="*9: line = inputfile.next() line = inputfile.next() tester = line.find("tester") # Can be in a different place depending assert tester >= 0 while line[1:10] != "="*9: # May be two or three lines (unres) line = inputfile.next() scfvalues = [] line = inputfile.next() while line.strip(): if line[2:6] != "****": # e.g. **** recalulation of fock matrix on iteration 4 (examples/chap12/pyridine.out) scfvalues.append([float(line[tester-5:tester+6])]) line = inputfile.next() self.scfvalues.append(scfvalues) if line[10:22] == "total energy" and len(line.split()) == 3: if not hasattr(self, "scfenergies"): self.scfenergies = [] scfenergy = utils.convertor(float(line.split()[-1]), "hartree", "eV") self.scfenergies.append(scfenergy) # Total energies after Moller-Plesset corrections # Second order correction is always first, so its first occurance # triggers creation of mpenergies (list of lists of energies) # Further corrections are appended as found # Note: GAMESS-UK sometimes prints only the corrections, # so they must be added to the last value of scfenergies if line[10:32] == "mp2 correlation energy" or \ line[10:42] == "second order perturbation energy": if not hasattr(self, "mpenergies"): self.mpenergies = [] self.mpenergies.append([]) self.mp2correction = self.float(line.split()[-1]) self.mp2energy = self.scfenergies[-1] + self.mp2correction self.mpenergies[-1].append(utils.convertor(self.mp2energy, "hartree", "eV")) if line[10:41] == "third order perturbation energy": self.mp3correction = self.float(line.split()[-1]) self.mp3energy = self.mp2energy + self.mp3correction self.mpenergies[-1].append(utils.convertor(self.mp3energy, "hartree", "eV")) if line[40:59] == "molecular basis set": self.gbasis = [] line = inputfile.next() while line.find("contraction coefficients")<0: line = inputfile.next() equals = inputfile.next() blank = inputfile.next() atomname = inputfile.next() basisregexp = re.compile("\d*(\D+)") # Get everything after any digits shellcounter = 1 while line != equals: gbasis = [] # Stores basis sets on one atom blank = inputfile.next() blank = inputfile.next() line = inputfile.next() shellno = int(line.split()[0]) shellgap = shellno - shellcounter shellsize = 0 while len(line.split())!=1 and line!=equals: if line.split(): shellsize += 1 coeff = {} # coefficients and symmetries for a block of rows while line.strip() and line!=equals: temp = line.strip().split() # temp[1] may be either like (a) "1s" and "1sp", or (b) "s" and "sp" # See GAMESS-UK 7.0 distribution/examples/chap12/pyridine2_21m10r.out # for an example of the latter sym = basisregexp.match(temp[1]).groups()[0] assert sym in ['s', 'p', 'd', 'f', 'sp'], "'%s' not a recognized symmetry" % sym if sym == "sp": coeff.setdefault("S", []).append( (float(temp[3]), float(temp[6])) ) coeff.setdefault("P", []).append( (float(temp[3]), float(temp[10])) ) else: coeff.setdefault(sym.upper(), []).append( (float(temp[3]), float(temp[6])) ) line = inputfile.next() # either a blank or a continuation of the block if coeff: if sym == "sp": gbasis.append( ('S', coeff['S'])) gbasis.append( ('P', coeff['P'])) else: gbasis.append( (sym.upper(), coeff[sym.upper()])) if line == equals: continue line = inputfile.next() # either the start of the next block or the start of a new atom or # the end of the basis function section (signified by a line of equals) numtoadd = 1 + (shellgap / shellsize) shellcounter = shellno + shellsize for x in range(numtoadd): self.gbasis.append(gbasis) if line[50:70] == "----- beta set -----": self.betamosyms = True self.betamoenergies = True self.betamocoeffs = True # betamosyms will be turned off in the next # SYMMETRY ASSIGNMENT section if line[31:50] == "SYMMETRY ASSIGNMENT": if not hasattr(self, "mosyms"): self.mosyms = [] multiple = {'a':1, 'b':1, 'e':2, 't':3, 'g':4, 'h':5} equals = inputfile.next() line = inputfile.next() while line != equals: # There may be one or two lines of title (compare mg10.out and duhf_1.out) line = inputfile.next() mosyms = [] line = inputfile.next() while line != equals: temp = line[25:30].strip() if temp[-1] == '?': # e.g. e? or t? or g? (see example/chap12/na7mg_uhf.out) # for two As, an A and an E, and two Es of the same energy respectively. t = line[91:].strip().split() for i in range(1, len(t), 2): for j in range(multiple[t[i][0]]): # add twice for 'e', etc. mosyms.append(self.normalisesym(t[i])) else: for j in range(multiple[temp[0]]): mosyms.append(self.normalisesym(temp)) # add twice for 'e', etc. line = inputfile.next() assert len(mosyms) == self.nmo, "mosyms: %d but nmo: %d" % (len(mosyms), self.nmo) if self.betamosyms: # Only append if beta (otherwise with IPRINT SCF # it will add mosyms for every step of a geo opt) self.mosyms.append(mosyms) self.betamosyms = False elif self.scftype == 'gvb': # gvb has alpha and beta orbitals but they are identical self.mosysms = [mosyms, mosyms] else: self.mosyms = [mosyms] if line[50:62] == "eigenvectors": # Mocoeffs...can get evalues from here too # (only if using FORMAT HIGH though will they all be present) if not hasattr(self, "mocoeffs"): self.aonames = [] aonames = [] minus = inputfile.next() mocoeffs = numpy.zeros( (self.nmo, self.nbasis), "d") readatombasis = False if not hasattr(self, "atombasis"): self.atombasis = [] for i in range(self.natom): self.atombasis.append([]) readatombasis = True blank = inputfile.next() blank = inputfile.next() evalues = inputfile.next() p = re.compile(r"\d+\s+(\d+)\s*(\w+) (\w+)") oldatomname = "DUMMY VALUE" mo = 0 while mo < self.nmo: if self.progress: self.updateprogress(inputfile, "Coefficients") blank = inputfile.next() blank = inputfile.next() nums = inputfile.next() blank = inputfile.next() blank = inputfile.next() for basis in range(self.nbasis): line = inputfile.next() # Fill atombasis only first time around. if readatombasis: orbno = int(line[1:5])-1 atomno = int(line[6:9])-1 self.atombasis[atomno].append(orbno) if not self.aonames: pg = p.match(line[:18].strip()).groups() atomname = "%s%s%s" % (pg[1][0].upper(), pg[1][1:], pg[0]) if atomname != oldatomname: aonum = 1 oldatomname = atomname name = "%s_%d%s" % (atomname, aonum, pg[2].upper()) if name in aonames: aonum += 1 name = "%s_%d%s" % (atomname, aonum, pg[2].upper()) aonames.append(name) temp = map(float, line[19:].split()) mocoeffs[mo:(mo+len(temp)), basis] = temp # Fill atombasis only first time around. readatombasis = False if not self.aonames: self.aonames = aonames line = inputfile.next() # blank line while line == blank: line = inputfile.next() evalues = line if evalues[:17].strip(): # i.e. if these aren't evalues break # Not all the MOs are present mo += len(temp) mocoeffs = mocoeffs[0:(mo+len(temp)), :] # In case some aren't present if self.betamocoeffs: self.mocoeffs.append(mocoeffs) else: self.mocoeffs = [mocoeffs] if line[7:12] == "irrep": ########## eigenvalues ########### # This section appears once at the start of a geo-opt and once at the end # unless IPRINT SCF is used (when it appears at every step in addition) if not hasattr(self, "moenergies"): self.moenergies = [] equals = inputfile.next() while equals[1:5] != "====": # May be one or two lines of title (compare duhf_1.out and mg10.out) equals = inputfile.next() moenergies = [] line = inputfile.next() if not line.strip(): # May be a blank line here (compare duhf_1.out and mg10.out) line = inputfile.next() while line.strip() and line != equals: # May end with a blank or equals temp = line.strip().split() moenergies.append(utils.convertor(float(temp[2]), "hartree", "eV")) line = inputfile.next() self.nmo = len(moenergies) if self.betamoenergies: self.moenergies.append(moenergies) self.betamoenergies = False elif self.scftype == 'gvb': self.moenergies = [moenergies, moenergies] else: self.moenergies = [moenergies] # Net atomic charges are not printed at all, it seems, # but you can get at them from nuclear charges and # electron populations, which are printed like so: # # --------------------------------------- # mulliken and lowdin population analyses # --------------------------------------- # # ----- total gross population in aos ------ # # 1 1 c s 1.99066 1.98479 # 2 1 c s 1.14685 1.04816 # ... # # ----- total gross population on atoms ---- # # 1 c 6.0 6.00446 5.99625 # 2 c 6.0 6.00446 5.99625 # 3 c 6.0 6.07671 6.04399 # ... if line[10:49] == "mulliken and lowdin population analyses": if not hasattr(self, "atomcharges"): self.atomcharges = {} while not "total gross population on atoms" in line: line = inputfile.next() blank = inputfile.next() line = inputfile.next() mulliken, lowdin = [], [] while line.strip(): nuclear = float(line.split()[2]) mulliken.append(nuclear - float(line.split()[3])) lowdin.append(nuclear - float(line.split()[4])) line = inputfile.next() self.atomcharges["mulliken"] = mulliken self.atomcharges["lowdin"] = lowdin if __name__ == "__main__": import doctest doctest.testmod() GaussSum-2.2.6.1/gausssum/cclib/parser/jaguarparser.py0000664000175000017500000005012712117172552021374 0ustar noelnoel# This file is part of cclib (http://cclib.sf.net), a library for parsing # and interpreting the results of computational chemistry packages. # # Copyright (C) 2006, the cclib development team # # The library is free software, distributed under the terms of # the GNU Lesser General Public version 2.1 or later. You should have # received a copy of the license along with cclib. You can also access # the full license online at http://www.gnu.org/copyleft/lgpl.html. __revision__ = "$Revision: 1032 $" import re import numpy import logfileparser import utils class Jaguar(logfileparser.Logfile): """A Jaguar output file""" def __init__(self, *args, **kwargs): # Call the __init__ method of the superclass super(Jaguar, self).__init__(logname="Jaguar", *args, **kwargs) def __str__(self): """Return a string representation of the object.""" return "Jaguar output file %s" % (self.filename) def __repr__(self): """Return a representation of the object.""" return 'Jaguar("%s")' % (self.filename) def normalisesym(self, label): """Normalise the symmetries used by Jaguar. To normalise, three rules need to be applied: (1) To handle orbitals of E symmetry, retain everything before the / (2) Replace two p's by " (2) Replace any remaining single p's by ' >>> t = Jaguar("dummyfile").normalisesym >>> labels = ['A', 'A1', 'Ag', 'Ap', 'App', "A1p", "A1pp", "E1pp/Ap"] >>> answers = map(t, labels) >>> print answers ['A', 'A1', 'Ag', "A'", 'A"', "A1'", 'A1"', 'E1"'] """ ans = label.split("/")[0].replace("pp", '"').replace("p", "'") return ans def before_parsing(self): self.geoopt = False # Is this a GeoOpt? Needed for SCF targets/values. def extract(self, inputfile, line): """Extract information from the file object inputfile.""" if line[0:4] == "etot": # Get SCF convergence information if not hasattr(self, "scfvalues"): self.scfvalues = [] self.scftargets = [[5E-5, 5E-6]] values = [] while line[0:4] == "etot": # Jaguar 4.2 # etot 1 N N 0 N -382.08751886450 2.3E-03 1.4E-01 # etot 2 Y Y 0 N -382.27486023153 1.9E-01 1.4E-03 5.7E-02 # Jaguar 6.5 # etot 1 N N 0 N -382.08751881733 2.3E-03 1.4E-01 # etot 2 Y Y 0 N -382.27486018708 1.9E-01 1.4E-03 5.7E-02 temp = line.split()[7:] if len(temp)==3: denergy = float(temp[0]) else: denergy = 0 # Should really be greater than target value # or should we just ignore the values in this line ddensity = float(temp[-2]) maxdiiserr = float(temp[-1]) if not self.geoopt: values.append([denergy, ddensity]) else: values.append([ddensity]) line = inputfile.next() self.scfvalues.append(values) # Hartree-Fock energy after SCF if line[1:18] == "SCFE: SCF energy:": if not hasattr(self, "scfenergies"): self.scfenergies = [] temp = line.strip().split() scfenergy = float(temp[temp.index("hartrees") - 1]) scfenergy = utils.convertor(scfenergy, "hartree", "eV") self.scfenergies.append(scfenergy) # Energy after LMP2 correction if line[1:18] == "Total LMP2 Energy": if not hasattr(self, "mpenergies"): self.mpenergies = [[]] lmp2energy = float(line.split()[-1]) lmp2energy = utils.convertor(lmp2energy, "hartree", "eV") self.mpenergies[-1].append(lmp2energy) if line[2:14] == "new geometry" or line[1:21] == "Symmetrized geometry" or line.find("Input geometry") > 0: # Get the atom coordinates if not hasattr(self, "atomcoords") or line[1:21] == "Symmetrized geometry": # Wipe the "Input geometry" if "Symmetrized geometry" present self.atomcoords = [] p = re.compile("(\D+)\d+") # One/more letters followed by a number atomcoords = [] atomnos = [] angstrom = inputfile.next() title = inputfile.next() line = inputfile.next() while line.strip(): temp = line.split() element = p.findall(temp[0])[0] atomnos.append(self.table.number[element]) atomcoords.append(map(float, temp[1:])) line = inputfile.next() self.atomcoords.append(atomcoords) self.atomnos = numpy.array(atomnos, "i") self.natom = len(atomcoords) # Extract charge and multiplicity if line[2:22] == "net molecular charge": self.charge = int(line.split()[-1]) self.mult = int(inputfile.next().split()[-1]) if line[2:24] == "start of program geopt": if not self.geoopt: # Need to keep only the RMS density change info # if this is a geoopt self.scftargets = [[self.scftargets[0][0]]] if hasattr(self, "scfvalues"): self.scfvalues[0] = [[x[0]] for x in self.scfvalues[0]] self.geoopt = True else: self.scftargets.append([5E-5]) if line[2:28] == "geometry optimization step": # Get Geometry Opt convergence information if not hasattr(self, "geovalues"): self.geovalues = [] self.geotargets = numpy.zeros(5, "d") gopt_step = int(line.split()[-1]) energy = inputfile.next() # quick hack for messages of the sort: # ** restarting optimization from step 2 ** # as found in regression file ptnh3_2_H2O_2_2plus.out if inputfile.next().strip(): blank = inputfile.next() line = inputfile.next() values = [] target_index = 0 if gopt_step == 1: # The first optimization step does not produce an energy change values.append(0.0) target_index = 1 while line.strip(): if len(line) > 40 and line[41] == "(": # A new geo convergence value values.append(float(line[26:37])) self.geotargets[target_index] = float(line[43:54]) target_index += 1 line = inputfile.next() self.geovalues.append(values) if line.find("number of occupied orbitals") > 0: # Get number of MOs occs = int(line.split()[-1]) line = inputfile.next() virts = int(line.split()[-1]) self.nmo = occs + virts self.homos = numpy.array([occs-1], "i") self.unrestrictedflag = False if line.find("number of alpha occupied orb") > 0: # Get number of MOs for an unrestricted calc aoccs = int(line.split()[-1]) line = inputfile.next() avirts = int(line.split()[-1]) line = inputfile.next() boccs = int(line.split()[-1]) line = inputfile.next() bvirt = int(line.split()[-1]) self.nmo = aoccs + avirts self.homos = numpy.array([aoccs-1, boccs-1], "i") self.unrestrictedflag = True # MO energies and symmetries. # Jaguar 7.0: provides energies and symmetries for both # restricted and unrestricted calculations, like this: # Alpha Orbital energies/symmetry label: # -10.25358 Bu -10.25353 Ag -10.21931 Bu -10.21927 Ag # -10.21792 Bu -10.21782 Ag -10.21773 Bu -10.21772 Ag # ... # Jaguar 6.5: prints both only for restricted calculations, # so for unrestricted calculations the output it looks like this: # Alpha Orbital energies: # -10.25358 -10.25353 -10.21931 -10.21927 -10.21792 -10.21782 # -10.21773 -10.21772 -10.21537 -10.21537 -1.02078 -0.96193 # ... # Presence of 'Orbital energies' is enough to catch all versions. if "Orbital energies" in line: # Parsing results is identical for restricted/unrestricted # calculations, just assert later that alpha/beta order is OK. spin = int(line[2:6] == "Beta") # Check if symmetries are printed also. issyms = "symmetry label" in line if not hasattr(self, "moenergies"): self.moenergies = [] if issyms and not hasattr(self, "mosyms"): self.mosyms = [] # Grow moeneriges/mosyms and make sure they are empty when # parsed multiple times - currently cclib returns only # the final output (ex. in a geomtry optimization). if len(self.moenergies) < spin+1: self.moenergies.append([]) self.moenergies[spin] = [] if issyms: if len(self.mosyms) < spin+1: self.mosyms.append([]) self.mosyms[spin] = [] line = inputfile.next().split() while len(line) > 0: if issyms: energies = [float(line[2*i]) for i in range(len(line)/2)] syms = [line[2*i+1] for i in range(len(line)/2)] else: energies = [float(e) for e in line] energies = [utils.convertor(e, "hartree", "eV") for e in energies] self.moenergies[spin].extend(energies) if issyms: syms = [self.normalisesym(s) for s in syms] self.mosyms[spin].extend(syms) line = inputfile.next().split() # There should always be an extra blank line after all this. line = inputfile.next() if line.find("Occupied + virtual Orbitals- final wvfn") > 0: blank = inputfile.next() stars = inputfile.next() blank = inputfile.next() blank = inputfile.next() if not hasattr(self,"mocoeffs"): if self.unrestrictedflag: spin = 2 else: spin = 1 self.mocoeffs = [] aonames = [] lastatom = "X" readatombasis = False if not hasattr(self, "atombasis"): self.atombasis = [] for i in range(self.natom): self.atombasis.append([]) readatombasis = True offset = 0 for s in range(spin): mocoeffs = numpy.zeros((len(self.moenergies[s]), self.nbasis), "d") if s == 1: #beta case stars = inputfile.next() blank = inputfile.next() title = inputfile.next() blank = inputfile.next() stars = inputfile.next() blank = inputfile.next() blank = inputfile.next() for k in range(0, len(self.moenergies[s]), 5): if self.progress: self.updateprogress(inputfile, "Coefficients") numbers = inputfile.next() eigens = inputfile.next() line = inputfile.next() for i in range(self.nbasis): info = line.split() # Fill atombasis only first time around. if readatombasis and k == 0: orbno = int(info[0]) atom = info[1] if atom[1].isalpha(): atomno = int(atom[2:]) else: atomno = int(atom[1:]) self.atombasis[atomno-1].append(orbno-1) if not hasattr(self,"aonames"): if lastatom != info[1]: scount = 1 pcount = 3 dcount = 6 #six d orbitals in Jaguar if info[2] == 'S': aonames.append("%s_%i%s"%(info[1], scount, info[2])) scount += 1 if info[2] == 'X' or info[2] == 'Y' or info[2] == 'Z': aonames.append("%s_%iP%s"%(info[1], pcount / 3, info[2])) pcount += 1 if info[2] == 'XX' or info[2] == 'YY' or info[2] == 'ZZ' or \ info[2] == 'XY' or info[2] == 'XZ' or info[2] == 'YZ': aonames.append("%s_%iD%s"%(info[1], dcount / 6, info[2])) dcount += 1 lastatom = info[1] for j in range(len(info[3:])): mocoeffs[j+k, i] = float(info[3+j]) line = inputfile.next() if not hasattr(self,"aonames"): self.aonames = aonames offset += 5 self.mocoeffs.append(mocoeffs) if line[2:6] == "olap": if line[6] == "-": return # This was continue (in loop) before parser refactoring. # continue # avoid "olap-dev" self.aooverlaps = numpy.zeros((self.nbasis, self.nbasis), "d") for i in range(0, self.nbasis, 5): if self.progress: self.updateprogress(inputfile, "Overlap") blank = inputfile.next() header = inputfile.next() for j in range(i, self.nbasis): temp = map(float, inputfile.next().split()[1:]) self.aooverlaps[j, i:(i+len(temp))] = temp self.aooverlaps[i:(i+len(temp)), j] = temp if line[1:28] == "number of occupied orbitals": self.homos = numpy.array([float(line.strip().split()[-1])-1], "i") if line[2:27] == "number of basis functions": self.nbasis = int(line.strip().split()[-1]) # IR output looks like this: # frequencies 72.45 113.25 176.88 183.76 267.60 312.06 # symmetries Au Bg Au Bu Ag Bg # intensities 0.07 0.00 0.28 0.52 0.00 0.00 # reduc. mass 1.90 0.74 1.06 1.42 1.19 0.85 # force const 0.01 0.01 0.02 0.03 0.05 0.05 # C1 X 0.00000 0.00000 0.00000 -0.05707 -0.06716 0.00000 # C1 Y 0.00000 0.00000 0.00000 0.00909 -0.02529 0.00000 # C1 Z 0.04792 -0.06032 -0.01192 0.00000 0.00000 0.11613 # C2 X 0.00000 0.00000 0.00000 -0.06094 -0.04635 0.00000 # ... etc. ... # This is a complete ouput, some files will not have intensities, # and older Jaguar versions sometimes skip the symmetries. if line[2:23] == "start of program freq": self.vibfreqs = [] self.vibdisps = [] forceconstants = False intensities = False blank = inputfile.next() line = inputfile.next() while line.strip(): if "force const" in line: forceconstants = True if "intensities" in line: intensities = True line = inputfile.next() freqs = inputfile.next() # The last block has an extra blank line after it - catch it. while freqs.strip(): # Number of modes (columns printed in this block). nmodes = len(freqs.split())-1 # Append the frequencies. self.vibfreqs.extend(map(float, freqs.split()[1:])) line = inputfile.next().split() # May skip symmetries (older Jaguar versions). if line[0] == "symmetries": if not hasattr(self, "vibsyms"): self.vibsyms = [] self.vibsyms.extend(map(self.normalisesym, line[1:])) line = inputfile.next().split() if intensities: if not hasattr(self, "vibirs"): self.vibirs = [] self.vibirs.extend(map(float, line[1:])) line = inputfile.next().split() if forceconstants: line = inputfile.next() # Start parsing the displacements. # Variable 'q' holds up to 7 lists of triplets. q = [ [] for i in range(7) ] for n in range(self.natom): # Variable 'p' holds up to 7 triplets. p = [ [] for i in range(7) ] for i in range(3): line = inputfile.next() disps = [float(disp) for disp in line.split()[2:]] for j in range(nmodes): p[j].append(disps[j]) for i in range(nmodes): q[i].append(p[i]) self.vibdisps.extend(q[:nmodes]) blank = inputfile.next() freqs = inputfile.next() # Convert new data to arrays. self.vibfreqs = numpy.array(self.vibfreqs, "d") self.vibdisps = numpy.array(self.vibdisps, "d") if hasattr(self, "vibirs"): self.vibirs = numpy.array(self.vibirs, "d") # Parse excited state output (for CIS calculations). # Jaguar calculates only singlet states. if line[2:15] == "Excited State": if not hasattr(self, "etenergies"): self.etenergies = [] if not hasattr(self, "etoscs"): self.etoscs = [] if not hasattr(self, "etsecs"): self.etsecs = [] self.etsyms = [] etenergy = float(line.split()[3]) etenergy = utils.convertor(etenergy, "eV", "cm-1") self.etenergies.append(etenergy) # Skip 4 lines for i in range(5): line = inputfile.next() self.etsecs.append([]) # Jaguar calculates only singlet states. self.etsyms.append('Singlet-A') while line.strip() != "": fromMO = int(line.split()[0])-1 toMO = int(line.split()[2])-1 coeff = float(line.split()[-1]) self.etsecs[-1].append([(fromMO, 0), (toMO, 0), coeff]) line = inputfile.next() # Skip 3 lines for i in range(4): line = inputfile.next() strength = float(line.split()[-1]) self.etoscs.append(strength) if __name__ == "__main__": import doctest, jaguarparser doctest.testmod(jaguarparser, verbose=False) GaussSum-2.2.6.1/gausssum/cclib/__init__.py0000664000175000017500000000000012117172552017132 0ustar noelnoelGaussSum-2.2.6.1/gausssum/gnupy.py0000664000175000017500000001043012117172552015471 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. """gnupy.py """ # For Gnuplot import os,sys,string from tempfile import mkstemp # For DisplayImage from Tkinter import * import tkMessageBox, tkFileDialog, shutil class Gnuplot(object): """Simple interface to Gnuplot that uses os.system. >>> g = Gnuplot() >>> g.data( [(1,1),(2,2),(3,0)],"notitle with lines" ) >>> g.data( [(1,0.5),(2,1.9),(3,1)],"title 'Hey' with linespoints" ) >>> g.function( 'sin(x)', "title 'sin(x)' with lines" ) >>> g.function3d( 'sin(x+y)', "notitle") >>> g.commands("set title 'Testing'") >>> g.plot("tmp.png") """ def __init__(self,gnuplotexec=None): """Initialise the Gnuplot object. Parameters: filename -- a filename is required gnuplotexec -- the location of the gnuplot executable (optional) """ if not gnuplotexec: if sys.platform=='win32': gnuplotexec = "pgnuplot.exe" else: gnuplotexec = "gnuplot" self.gnuplotexec = gnuplotexec self.filedata = [] self.plotcommand = [] self.splotcommand = [] self.settings = [] def commands(self,*listofcommands): """Add a list of commands for the plot.""" self.settings.extend(listofcommands) def data(self,tuples,style): """Save the data to a temporary file.""" filedes,filename = mkstemp() # filedes is the "file descriptor" self.filedata.append( (filedes,filename) ) output = open(filename,"w") for tuple in tuples: line = map(str,tuple) output.write("\t".join(line)+"\n") output.close() self.plotcommand.append( '"%s" %s' % (self._fixname(filename),style)) def function(self,function,style): """Remember function information.""" self.plotcommand.append( '%s %s' % (function,style) ) def function3d(self,function,style): """Remember splot function information.""" self.splotcommand.append( '%s %s' % (function,style) ) def plot(self,filename): """Plot the graph.""" self.settings.extend(["set terminal png small", 'set output "%s"' % self._fixname(filename)]) # To create the examples uncomment the following: # self.settings.extend(['set size 0.75,0.75']) filedes, filename = mkstemp() output = open(filename,"w") output.write("\n".join(self.settings)) output.write("\n") if self.plotcommand: output.write('plot %s \n' % ",".join(self.plotcommand)) elif self.splotcommand: output.write('splot %s \n' % ",".join(self.splotcommand)) output.close() # Double quotation marks needed here, esp. for Windows where there # may be spaces in the path to gnuplotexec status = 0 if os.path.isfile(self.gnuplotexec): os.system('"%s" %s' % (self.gnuplotexec,filename)) else: status = 1 os.close(filedes) os.remove(filename) return status def __del__(self): """Remove temporary files.""" for tuple in self.filedata: os.close(tuple[0]) # Close the file descriptor os.remove(tuple[1]) # Remove the temporary file def _fixname(self,filename): """Replace " and \ by their escaped equivalents.""" # Taken from gnuplot-py (Michael Haggerty) for c in ['\\', '\"']: filename = string.replace(filename, c, '\\' + c) return filename if __name__=="__main__": import doctest,gnupy doctest.testmod(gnupy) GaussSum-2.2.6.1/gausssum/geoopt.py0000664000175000017500000000421612117172552015631 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. import os import sys import math from Tkinter import * from plot import DisplayPlot from gnupy import Gnuplot from tempfile import mkstemp def GeoOpt(root,screen,logfile,numpts,gnuplotexec): screen.write("Starting GeoOpt.py\n") deviation = [] for i in range(len(logfile.geovalues)): dev = 0 for j in range(len(logfile.geotargets)): if abs(logfile.geovalues[i][j])>logfile.geotargets[j]: dev += math.log(abs(logfile.geovalues[i][j])/logfile.geotargets[j]) deviation.append(dev) if len(logfile.scfenergies)>=numpts+2: # If there are two points to plot g = Gnuplot(gnuplotexec) g.commands("set xlabel 'Optimisation Step'") g.commands("set ylabel 'Energy'") data = zip(range(len(logfile.scfenergies)-numpts),logfile.scfenergies[numpts:]) g.data(data,"notitle with lines") g.data(data,"notitle") DisplayPlot(root,g,"Geometry optimisation") if len(deviation)>=numpts+2: h = Gnuplot(gnuplotexec) h.commands("set yrange [0:]") h.commands("set xlabel 'Optimisation Step'") h.commands("set ylabel 'Deviation from targets'") data = zip(range(len(deviation)-numpts),deviation[numpts:]) h.data(data,"notitle with lines") h.data(data,"notitle") DisplayPlot(root,h,"Deviation from targets") else: screen.write("I need at least two points to plot\n") screen.write("Finishing GeoOpt.py\n") GaussSum-2.2.6.1/gausssum/mesh.gif0000664000175000017500000010425712117172552015413 0ustar noelnoelGIF89a@      .' !%*/+#-&?"(),%%5( 6365811;9F42<9%?77a4S8 CA ECG>>KEJH RINKYH QG7OFGKNMP jJ PRTQYPtI aO[QULMRT}H SUaNLXY ]XaW\[yR Z[iX sU mW eZQ_UTMOS_[^^__ VLJl`Wdc}] icv` [hfpc V^j^^c``ig jd;_ ]{gnlf qnj d {mwo g `so ps i/\uq5h?q uo[twxpL}tt o xyzwh {nmspqw yz tvsu q ~}y }vs xv ~ ||~v|r1 tOM%m    LE<y٩S͚I2˗0Pxfnbg/~Dԏ$H;~@ALΜ]ժ pj]٪f"IGMYZgbߨ ޺T@q 8.>[~(gllHz$Z\MW 3L)_G>B7B >`2*qIˆne~3e0bWvj`W-WLï\a{_}L~0eQ3 x-Rp!R>5HE$n"G/j iMJu &!I\KAW+KzQ`abI]L%CFV`~UO~PueBbFh ٕV*Ȅ>GBiDbl 4AuJ+DmWaX*| u3\cON LyS]6PXvŧi$ꧥ^\dz rޢg2l6&k%Agi MAhn`pt[mz_/}pcUZQcl{mGV~inUںcbU^īW*`LAVnGM-M)gWIk  c"ݺGضd#) YŨcUbW̒l3}nJK[XN酹^)eyAM^SeIȕIim#i4,CQR}rv+w("E-J5% 0tsϣl%^TG4cAWS+i/<+T\^3@MVCВC/ɶZQH~xl=T˝ OOG+QX0}p:=wslBŌ"~?z|iKͺc/xVObcE"b/RT$ox׸~me0fK+'@/})Fᬗ=_h g3x I@SYQr سk4)^a!LVct^ Uͮ@"eLH (0*Y sKu7Y`r88Q⼄ 1#`(@ 2HDq/DFCf`d9E-+,YY֘%?@/&OH ] @@$H}#է. IM\UI# I!蔧7pU$7[X RzIR.1 fUb,V` Kk#(/CgN EWd*C0 (e}̤[ C0sv_xH-IєJArv PET/!, v{Cgj:#/I\*ǝLb}|k,;p]R @Lm[;ynNtd.[ǐ=pYȘ7q.r? ;w"Oҗ;c{vFӛ.u*<զs15mp,}K]wk@OƖ/|(Z9;P+һ.O@ ZP8jqw=˦70=o~S\ @ uV%gO{kOUIF1a|8icAb0q`5˻Z&@uxX E@X@+EPBPYhHb𬃀ؗ;4p;H ݈]ak5 꺖l),YZx0_Qsp kkۑp&)/ŠM{F}Xy@;VPPfLJY <<9b@Ib@}'{$P{4G;ՈG&= +C2;ET\[9p m q+@v._uUaya*@t70ɓjlXYlؚB,߻B Măŗ;żZI˕ 3~K[td[I!Bu ݂{;52yL^!HN`KɍP j@D`Dhfz]lp ;j}b+2P{$T9˽x Sq:lllH 2W(z'q |LBh =+ :$ [58pk0 @k[p` @l`zʊJهP0˵|$5{؈-$躴&m5O~8ܹfUKǡ:_1!DAP \N~0; Tm?gP5@gg?p8p[ɕ hp ޝЗP+}z˪K+@ =kG̗kHaߒS `];b+tl۷ULO,nl*O,@.^g|vpAPgpɚݫ p 4ȬIz} i޳|~Q[ z^~=̞d;`^81\Q 4U;A mcH,.WKI͖w`&*@`018^]e`O`Po0 p  а hVz͚jM 4kZZ~B Sl]HaPzd[tWIJ!vޡz^y_[qv/@*M.055&ꙮ1e0U<?P 0 ð ` PKzp*߬LZB`Wp 2V,BG 1 E э?ANCMZ@[<@cP B)@&~(^qo33`Oop ` À ߼;)߬H !Lhc<,QbD ,^hD27=B~lXl[W2e#J5mđƉN0Ç9:eMRM5*S\ŚUVXGVذ c6_k"9m*G++?OfpG> EUTtuş_+b#+@T˭q+$XA+&૯Tb0 aÇ ʐ,B YOZh 4|ga@idӌ#+а !dȁ"djy<4 (Fz«@JB.\l*&L1!R/`ܳ*O,Ӣ 4@r6@`.Rh U 9D,Ğ('Vbj`UwVr܂< c5+("H3d‘"~Ş$݈Jg{VWZ.KV:m7!;Wr!7ɓ3]>!>t&^Y(sݫ; MT"K*K/ 6417(ĎIJQ%VxmiUqāPb)  4b"`%VjP! fY)_9{)i榦zjpz"bˤҍC;mld /+ 29ϳXF`rXFk" 4|B ;DC{B8dXJb1'eaFP2#^FugׄЃX(X>J.R&oZAjv:/"{N:fmG߳ن_B/ɧA9Za!9C|A*,shEZ F`. qֽD]#P"8 A`cIzȔ$0 :s^tWnEk!^Гqχi˛UNEIre8v2?,N_$0܈;bbE)XыepƁi67 Ox Үt@B55(C 15d%኉ W}jPZ Mr5fUЕd|x5iMhb>WeaQD0EW9)1` \q܁whx+Djl?֮7P8zӞG#[p q!t蹏t[3d:&p $:zS? D+d8HIH,`ű/wIa1p Ȃfrcx D…q9pFX.<1A[ Ԑ# yh'Cx=7Vy#_ d5y,&Sb- D"QkCG}ar#yn!G3FRr 0PO h*M C3cԼ .hԣV#XD  89YU#  ?ܸgt;z#2)K pP׭g+> K,*(?+8,b bk.&ƝH 4AL2ДAa?O]Bs.ʦ!RLfBaFfFrye<4 ,$Aw T*@;~h3+eWLh ɖ5e+4^W'#(IwhBg ,H!04^ĨF5\ Aw[Z,*C"`-\q<+#7$_O#K)Iڒ'!({"hpwgHVB33TeДDġ20X $1Jc5[;Dh.H-AEB"`5 xM_V '8r 3&;5u}L)ɒ UwH&/Sn@ ,E@*C<ܩ);xE&v@C(D h3q8h2ʪ+DC󮷎3cՇ3:qY%uU(Y }e-r^S\T!8y?0PN1yų `ETUЈ'[e!XDO W=nTc< ,ЅHxJFB{ ݫ`s[eu &&F7vAͣra#X+O<94 T`5+>UBZ/} ԎX:-E( Z50u:PC5<=7xH:zKW1W` L0Q?>) V{%%/?&3 Q !06/j @h &cUd`r[ER@Ѓ7 ؂I\!2OX*'.zì+ID0\'IJR(PYAt/;) 9)ua5 @$H|r){*pZ,)ʩ8s&X 'x2^H<&rbPpZ7 C6w5H #O-}` C|H܇rKĆ ;)Q;XX ?zDv3B30paxK-R6 F94 ːϠ-q YZūCr :n<=䪟I+DJcG+WJP} c7B2S<8.KʱJ$18ZC1")j k3 a0rW *ܪ-hbCpkG[l$7o|LCO(2J(İ\JvtG2ʀ Kqʮ z`r\B(J,]ppHQE'XaT4KA9@s9^0qXFWцI#2@bDp:k$#0="PFXO>xQ7ͫgJTN,݌r,ͬ ?2q"*g@_BDP9p;Q{\sK?#3[@3:ƾV#mZCx˔ .-/- 4?rA &P\JءՊ? `M\D +g g o(x# -' a$-e ^L"2,{-mг8jREL7 lk 983؂l<=<0Þ.V/bSK?, @)hS88M ~p,y,r+pJd% t7*L00'`>paҋ%$@~8]V۵`պ}~Saͯ|pdMXuʇoͯrHh,Ё5a 0 mk8{-32z Si\ [g "U@ 6bIxFbԭ)G;U1Y `_ٙ%bMԝ`  %TBTBav/ ^ױj ah7*H(J[<0):*^/2 c\eUR=Mõ3Ȝ* B(:q+.,W>& V5]` U]C"2ɎQ:pd xQH  &جB(ca̔D[fC^$%^ (@Tƃ2b5Ն+e Y@ ۘ%k73a05CCp4XOhlFnoFBv'ϠG `)"+۫g~ ; 5|# -0%aXV9Q5jXYٰjEUOC?T.#fVf3CfsF镅 +f:N jtN">.B݆C!:HtJgX0,xy[vHdV a4bSXNΈXe^ n^bWE3PEO*'8Y:ƈb-=NͶ]nmCVW|xT86V3_\@=nobebe8[h ^XPR f ;OeBWU+,]H~o:R&w'~JN,їln z᩶  0Qf!U[hr芡QV6z둼ebH&sNh@qiQtEVfPcac|}^`wl%V ٟR7uih>QdD-Ӧr X^'`? aSZme#-#v 0lh jZdeHbR` Z!pte646]#.[,UO$lR S(rU{L)| ލnVȂrY7ᯎ/T6F:œƸcVU*nb0tPј;Ϙc GJC9[\ ).ezFz+PHߥ)YhruPOjn;[  &EӶ4CiiEb6$[\f#3_ewoI3h\wX0X،)oCP<^7&c$'֟}gnńHTOmHucmhZ JPHuHo;P۾ѓ 3m6[3] ZilOYՆwjå랰4)sJ3fL`) AL~NED9?BFR,o޼3aw e={K>#WHyUx`MFx 1F!Ta `WCCaOć1,c AQ fAG F+2˚|t 6ذBI͝zM:p{fՄ&L)0P@A$Q`b,)v PR00u 0*", <]sf`qxR +(,kζv$/Ă +,gvZou'CUVAэ,r 5|5@5Y=G'Ԍ~?, 0<4 [09?(~$AAce'|Fbk=]w,D "FT؍'cν8n썞h4(IL2B洴RJ%,mmBex2I\"to8QBnRFᔉ"U"#+H!& hD؛7 Ē\,p\$HBq|S4ɉRtsE\ r0*@. RY@1"D )L NXa<@p4dhQD3MgڱRXAl$=9 )4S |(.T7Wfqaog?~?E"@GaJfh-8i&"AgC-],ن'2X{/ƜnxJhDh5kL$lM5VD7dəH'6ɑ]ۙE4Z/e`kIJW6|"{(NrL& re%A x:@ C*L$v0Ҫ:f5af2`H-iSR}{iq'FΌk Ęq9OЁb#W> 0|^e @yM/Ӌbb^HJ0*־~̹o faBH*@$p8 `E'6Ā2\z ʧJ+'ViQL2M^h<@KfZ)ͬ I$ڗ% .~&[~]܍nhi$E&=ffXc՜xp,> PG%x`p̼L01O 4Zj VHzM }S[({J~ϛ[D>3kTT <x~lgx m^%-c/l`>w(~{do.LЄwݲH RC ,b PP Us@܎"ZD Ja2~4UL-5"ƽ=@z F=PCɍ BJ`|!B!Z%"Ǯa <@:6U2(^;(}cZ;k2&ۮTE= qT:!r2nؔ@pS2Ag@  =$T(p.9ԃi5+HnLF<PnB t%*v̂!`avA xD1]Y/hEjy߻85@/,ԅĀ8W@=Ab"XFsTB%O <`*Sł0y9|`2L+tQȘĈ\ M x . %(aI\cVaT>p»49\L@^,ƽr@^픍hO]FDT^)x Ҝ#j 赃;8 4B%(JuՀ"@9ܗTdFWA* +&K "//@O`0cS$Kpnҿ:}h@=]9.,utB 8_X `: ˽#iO"B/D@,C;4F[:2L5:5G@p\r@Q  BY %Ѐ $!&ЀFFd e@zi1h0__:p xjE[T X1džΆa̝fjLPR@PP6a1Z+0P.Cv`(B n@Ā*+6 `Fx. @|L*^' hb/0BMJhGxفp8lD#h<@r }HKUIjB%2i6Bʦ%N ,.’J<l`, k=6 A20l +C)P 8@_mmB^ |N*i@~]'TJU$MC((,9ZPB_h;M*aƽˆ+@%BZlh\ 1\*T-. Bn6ՔI0C,kBmVphBB(B)+L'Бa%Ѐ ̭(mBMM-p[ ' P9n@J.DAp\ [5 "@CŶli@=TB.pQ.CV,,k%!∮T"p1.;Bh,Bׂ9L΁BH! )W-DQTi"N* eT 0 bLzl%208c0/0ܒ e5@ l)L`) / /TôB)/ G׾9@\0. ԃO%XWi  EO1=(R4@Бu؁7eM& C ː 4s<9F+2C,er$j(a,AorB/(>Ó0lf2+w29 /nt ӒY Ε % 3O4O]3P@&ICA368(E DlCEg*G@S dKs+"cMV6m$wF`-@ =6Xt;c?i%p4z+.78zrw=GUhoh GoUtt^-V3vI Q`T@qCR_D \8+@6lFlJZz | /XBOFBԎ ;4e2HMc/pt6/¢ -c8L_<L'T'l D3@x$ <Gy@rt&غ2dw5{kk1|I_}Fĝq9hF%1\)?W6XfC,ڼk2`O!DgPEC@~5q)`zq/L5C C!=R씕ԖIqt$ ,(2Ş: rtMal (@fR Ń | TB- NIdJw-/xDw |{/;ɘ-M+MQ d+|UfP!D_3` jJ 7J#cVJXOPE8,lzI_ "āFby#͒}>xidل^@^ J|@ kdCnGr}yċ6`"Wp#-7@5+upюKJ:cq4@)P*)%^ġE|B@ws̩&<0@*\yEl'j*a+ayE:z^Fqz)J`Qz3GhY&\Td|V' jH@HtA!&``1STĆxj!`&1kn2$& cI h튣bt.Ī5+kR"k+p=(b j,h(8Yb Ae1:V٘'`h&a~8T"0FEMvSGeoB!.t-8:s j@Q r` fJq;e}_MfwTT]$)3ʓ!T^[IvģA@PB!Vd6UY 9Ӷ$'lE n]EUS{B#؏UL &0'"@91HU2,_z+"5MQ1Εs!|M/(Z ab%h;aPUUYהE)aB+F'0d%EH!RtF|zmg+Rվ*0@ ʊjC>q)F1$q#MnlFUCy@*Ir["?,L8! H91 qca S,ʾF'h*hī2` dnA(6Щ BeXШ 8beM鳤w<D%/f:L'LO,ɸ$(Z|`$RA Ԁ/1o`k``Fd5ޠ@xJ(Z@0,vͺ&A ,BF)JItڄBe NοT!ܸG'/Mlz*0e& Y p'` @E Xl ` GİHvb -x@L ``kv#̆P(kʨ,a6VƉ!wȂa epǞl^2PLή&g` Ԡx21AQF(3T|pb*b#'qٱި6*0,ωewrb<:&QlCOx@ ! F{S&}PB#J)hk JJNif& 5Z^36eSPcbzM(Lcl7E8b*+x`KxhwʀFf6Hʹ9z&@`zx#*A*b'H)Q'#m(n;uB*JIf!B@=!{/A)8 $kN2% =jc@Q5 4Cs ` ` n\OUP/aP'.P8ɑ_BB90XpWS9##<,:XHUsH,JPXc'پIf`@A*S,igY-R<-m bЈ5*vʮ# jr OA] D F^]ȗ8E:VdBCL*bL@Fvp9*l@dFC#۾(;HcB'J&@Gd(x,xeݳ "t( >.rD%k2 k2v iVj #P6ޯPVj37 A84ʀQ): l*Ev4lS.FQ i:tP8"ɜhfbah@k*poasZNU*6S=Pw+sbBf1O##(!cJ܁;[!sˈ:JIrIwu(ۊVOѕV ֜v"LXXX*h<+tpZvz[zIx ɖ٩6JxBJ/<'zA{PɑG鈛Չ )M%sdii nW㹶\jU0'ȼK(&i:AdKvOmM9bcڦtt޺:tgzt[(:>fޗ󝼅 ba$<"8#JUtWwV Y &}cX3^p (0+*(ȱ]1K\ }΀ʷ0'(*٘TZ](Dn,&:&C{)"baʫf1hrё%tjHzBu`͜!oBc'ru"nZ}\t2+Z>ûh@ޠЈ" ^"0>=9c<|8|z=8L3o:>)hRĒ1bɖUM3U[L0^pjSByc0o4-I2O@ q`E.xЖ@%ֈZE7ܹtڍ޽ w 6l`Nb8Q%Ɠ*>b8|pEO\#thI*<.^21x=>ޜa{<dՇ`=KX"$>70e 2b*B z]ZSL&UYCOhQ?P!hmV[muW"_{_baƂjTT0ejQ0m11QPkVE3@C6E#` ]i0 EQ㤊% )# 5:R @d؂`$xH^ xx+_@Ozۢ7w\u0L0 d8) )9NFX㙧UŤ"!pDlZHkP*BSff24:Ab4&Jx WԔA"$45E DSIѵ($XM (W AäT2zv),P:({J$ SvGP;b dRi*zSk|Yn~$Fg%Dj (W!A L^/,ZϠѳHN p VIhe#H2 Ul"G2X@%#D-:dinhJ[ҷ@%X@5y0p=2ses =}Nͯ*8FX<)m{F)MSk֧W6$KK*;˰_^#i"N|#I+Th$FarQ$gCJD@)NZ\‚CBjA II0 "5JP/T j@0X[ EȀL##9&G&Ek;ܰ>Ĩ 4WtkSYRyk ^Vdh 6iga  7@-TA ^ M5QN!P:OXqBWdꪅKd`.-h!CAi\c y1RO"XַFra/K[y }hcΦ֤-3h Е*C Ӷ*,3䢌o4\B* mÓrLz[}zF|ÂB*J+ κĮ%u[>Ԩ&s|hB Z"ǜCt >‡C t8;)\NL5w]7D@TYA@ p&'Œ1j >jKa;ѭOkߨ"MWBOUݻA9|Z6mUW#Wr%nq{gh Bʢ=gi7ko:9 }ba?9myBR+Ԅ,$ivi`wr*Gwh>rfz`1 MLT& 8Y?l8ߨeOb-fuAn[Hn q{T!?gv5WY|AQ 0J8ah"$JvG 71v0r`+CP1wb[\92;F0EPy1c`DODJ$MXz63rp@g[0!I?pqml#[WujXXPqXdK3p``n:Z9)֏'J@:ːP! P( ɖiiK#1$I7FEQ3 k`FPD)Bkm! V`Dʹɥ1Tv<8 ɓs?`rjZ(suvH`U#C%h\X[\vth%8@0 7qaY{ BIsOR5T,:B d´jp(3*P0MT[JdjU 7П@8PY44,ztpz!)Ȕ?9.6n S7Kq:M;hGĨI;eJ-jī}%TCq3~" 4Z1]!EP[Cy`DԫiBfP3[T ;/[p;?0z,Heu|X.s5Kw\P )v} &h2QRvI QA{ţBU%S"z`)=,LAX:fpDf`PИkRAFm]^5і  @_!;wWCCr)ݳܱ=S|{V")"Iؑb,Q{P2Qv~IR (6iůX98ᎌ` gOuܩTӪЪ`!v:(U*U^b*_P~J a<RnAGX@|4 2s@Z!Y 51TՇ8p>hbAg[g1ZGnfLc1Nf(α}H rLAM~ޥ~/ 6 V̺:0(( j~jAI.Ic&dU TFj@݈*P;ːH"ݸ&k/0^ F~nGIPwpaM LW0WnюCJ7.3p/:( .4KQخcac6jIjy@kÅ[f9~H9DUT No KN?嗱 qhSz4fRvD PiQD8(8Al}"bCw1aQj׎j0sr؝tPX0k: H@ATU pօl4/oNX2 O R0v ͛J&Md W,^TTV!y2mk;w.eΤY_;wtj&U,UT*3eΜSL'P92UDB 4jЌSl+h͘ !B yK _0pĄ 6¿ `1oYgСE&]4TfHwӄa3OCQQh+\cUJxk4h:UkivU)P -2P0HhkV"5+<,+ (BpB,1 $0;4K4Q4^SqM*7n2ѱR pdH3G)RdN:O&a߆+!0B+;B- :Dk@+ l+|B ӯcD4NTtQScQHi ;l<(@y JzuzPe [{Pg01I>_w? q#V%cl,Iij$H mXʰnM1B@!cAa P0Ct68n1,`0TC F!Q ^/%kt;m,i''YN QCb #O&ie$C86ZB&! {B(F1@ 5ut"HhBi_V&{XMj$+@@ΛV;h5ʙ&4} N"k g,yы:ϰ0 `UHPA>A 3&FbzPFTE"'4'7GITJ'NAhj紈3#@!pBef'pXRBc)Rjj `Uj BN m辰HoY%-)a˰rZFlh^]=tZ,Q.-z`@9viHKFBM(g(d沥qfY]iW xC2\K]3'U,V1OyX\VWY ; J\( Y's {"v%T&DŜ2wˌw4W5f;[7{U}?ڎ.a)IAU,0o 7Bu2,AF沁 b^B/>83LfVL3lf[8k6g>;  }hB&o%%AcÀF/VdMG_  V̠8B#Ne`fP,! y 35/">| A;Gzz!ku@t }c@MtZ%=鑬¿)&ϓ(TЁKG=\7@!^6vt<w0l@1=lPf PhY~}&f?orxЃ%0O@ےJʋI*DW:wjj +Ueu1A odؔw#@ȥ)Yri]2yk.6 ϗd c淚 M4Nj4_pBQG9ʭք`3" y KX8'pB wov& kv3Ꟶw=6 mx xe)j7}[Zt7Є(4q _ ף*Xۻ=Sܳ8 >S/L@ӬQa2l>T9q>>1X s<˻47&s;zT7>I$M2j ~#:R$p,7D?}DVcJl5sDȂK%; 1;.̸X 4Q8C6@W͊ ;j>;;L9B6"?n>8Rc(D+:QDp#.*K!(C*KDM7;D=D*QH`8+-dV0C31<HCW L34>5DLCEHC bFjeTƒ$5CF7oBG,*{r m%CDsI*Q\1GȀw?H  ,\EH.,hY$&![t3| LTL_<>FH`H\ACkgCPK$̲ÂB|rř =;rGɞE}KG.;ٛ=jXJDM}􃨄*r!8E0ʹ[L,WHW(N5E>S@u>LL(W\,T-nY (LUrҹEOTBwRD4U\Vl8FXVDMŸŨ8ɕY7Lp>\\={Dd6ά‹/R%L %^C3[v0@$aE4US%X%U1=a}M-8͊xb\˵D6[]ށU^(p=F1 @vxG,MP$.e1M_jV37% 0e0Y,bYS>-⢵bHY_`W[uxumZJW`Jmݔ{ն}o;BLDFdX&E&8^J.Ʋ^ĿOX b!GSdbU>6bŒb:Xev/⛵_>Ӥbn֭[YZ[Z(ZvU]`{S6dn1&riEF^ gxBMBzTꢂ]h6U--xhbY\-٠Wh g鎆vcAc5S]TxGm;o f,^i5sV^4Lv&a*MG`[1p2 gҬh(v_MTF }k 0Xbe>vWc.fg%fT6;f5vWivWfM+Cʶl^ igr1Ef^mmm$~.9 ?p`kmYpbVkb_8^n[Y8>i`>g>~fl=ބ6l7. ? U->UorqVgC$j؅N[[aNX7M傆3'wFsfsVfhGbfnkWq[ q֍?3[<&X~1j1No!opj#W4?{y}ZOLն b,r=6mHx(r m3Gsboh/Vkgfi@;ihpkG?/;xEt+rtɶtSm>t{{{n(]oUV|=cl ͸['F(kug2t_mham5m8g;ixgxn>5fYvf񞯅wl&4iC ۳g mZ0_;f՗ VXTdE8@mڶn+wۺjm7n{ŋ7-†޽)4hڮNJ.cy3jXq4i3L1Ķt۶ ]tFr1[TZl^6E6[TtӨ~WYVe% Vدlv]u/w+_={<c 5] 2XhVE <jK:/֒oo$Ťl:r5THWP}#MVBYTw",XW-_\) |}u}k-c4e} 5_;|h \ZCkuF':Xn$SoxS7B54X7NLHUX3@]ﵗdJ vה~Xgc0&`J_Lf G#S'3<[>Vg96t8u 6,uIUݹB74PuVUzL:MV:{Xmik 36_NQ?nƯ- ḅRMRqvCN H:t9~RA'T7/V:b%HT:ؾ~A# ecmЮP ]w= D=ُm醲4-cOk(6Ґ#3:136|sA[wiTXɻ:5eUaڳa]+vCP>wn\lu<ʿ'(m<86X>RMtUE/Ep]NuWN P.  cE6<ʣGn,(Yz9t׋6bry/ ;A#Q;猒>$iU?%u]61PxS$AA2,07 ew c7>ɅCq!Fr :[;A.is+t|=a}20BҪD4fQ+I6l" mcx_2g#' *Q8q!=rC!Zƌv$ S2JXB|`t$%Hʐf8*GncHFҳiS)BN,KgN;}(OGNi8Ŏ|p ^ efp+RӋ Bթ>Z꺪G ("E+ia I`d*ST 3̞e7"CQOr0qPAFt}29˳<$Җ) ;GaussSum-2.2.6.1/gausssum/folder.py0000664000175000017500000000230012117172552015577 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # Creates a new output folder if it doesn't already exist # The folder is created in the same directory as the input file import os def folder(screen, logfilename, create=True): # Create the output directory if necessary logdir=os.path.dirname(logfilename) logname=os.path.basename(logfilename) gaussdir=os.path.join(logdir,"gausssum2.2") if create: if not os.path.isdir(gaussdir): screen.write("Creating new output folder\n") os.mkdir(gaussdir) else: screen.write("Using old output folder\n") return gaussdir GaussSum-2.2.6.1/gausssum/mesh2.gif0000664000175000017500000001336312117172552015472 0ustar noelnoelGIF89aZC!!!!!!!!!!!!!)11))))!1!1)!!)!+#6#9- 91991!!!)!!1!!11!9)!)!))))1))9))91)))11)1111911919B!B)B1B1B9B9BBJ1J1J9JBJBR)W3ZBe<JJRJZJkJJJRRZRcRkRRRZZcZkZcckckkB1*A;5?1tbE&8L$홲cqrġ+Ƭ>1F|%玏5{FO`UMrV8XbbeL22|ⶍ;13fck?z2Lc `dc0c꤉fe1`r 3X $@` 5Cu cNt6@̐'&}Mט$Ly &>t|6qCP0`3!|LL2f 䐌7p7Uc(S'zq0HS7@L69w Ca̐]ǠMyL5c04cM'2$rt p )`a%Ѩ 9a@ :!Kz#,f1E}XB= qU;ġ!3 `SMV! -ҩQ $d TĢr uc<ڊ@ &y+DtCD`TCtv9&,TAUJO_iH!!@Hݰ^OWd`8C4c83 0͋ICwPjN9URAOρɴhJ Y  H縇=t[a+GXpy{& a pN #^ܪV%a4G*I-A fMk\MA^@$5BHny{bGrc+1hBSD$`8A `"%ɐxZd@! Eiњ/dxK0 4l! $,QM0(ʣ6,ya]]zHʣP<<`c' 6d SDoz4.ha C]H`?QCr yB6BL`Q= LcVB"bj!N'm ]0D$C kD$@سAd}$`m i$H.1'?Ϯ7KKȂh4׼NC$FA\E$ܬVC;X\zЇ> O4@L!phqz<Êx7U8- qVoG"_Jq 6ObD\נHg~{z'? tdJ b0#4W5% ЂIq U|3,ʍ tݜ4UT[ @4jS<"Qguۮ qud#LM#VIm4EMnO\*_(6)8H5z#3) p0q~#ߵx@" z' -:e/}Tw-n7@QPB xp@[ X$_:K+n߼% 4 (>CTQԣ dj0 wr_ji  GSP}cq g@ 6s7p fe*|"q'x*" fi(nbg p},0\wG%`~uf`k6@ElW`VTjT fncZ&r `j'vZ`^3(}FECwx6\ H7d  ii ^StZY0 gŇ|f憼 vTje^ifYPUs@g t 𐅍 heWI`fbpV!V)ƃ>xuxrbb׀'`U#ۀ 2~p] ` &n0Duf[XN`DuYVr]i`bf"`az` Y3 :` vq7Vjjfhb_`N(Rjب'mFvq  Ɛ ptPD4,:( T`Rfa&Nj jqE` N( mPj Jv tf {! yIS4fUf+RUu&pN^f*mƏe& O @0DyWD `"qaai[-fb5 7nZTn ]jT|jn:ɍ0& ϴYi7ℛeeV_^ɏqvrnEW%wtx^H`X_k ~)DQD"GIe yVY m`V pnj؈(ckj pԑ &ĊjovYVEg0 ʧ PFy&_ 0ٚY-zMZ""&u8iUy, `ujnjZ" pVwRJ ܆^Vv_:٣8yG &n6hpXvؠ ÂYqeq%N&wV=ʍf kj g '&n&nXP[ pO)p 0WmqgkH x5TE0]u&Vy_g[k XX L Ib]| $6Z!j|Pz prh4`kL2~yaP$N2ZEJ rjuuj [Gr8 u + "`,p#* Yvqgbu櫿j Cd\0g<Py@ h ^ɈVZ]kZǍ`Zuf ]F[yw8 2\3A#~X,Q{ewPR`1[miXT|*ٳ@l.fvr@[ H`,})j*-D`;fe^' rP0jfjj'gl u5tt;oX ЕTR&;Z;ˍ鳟Evq\ P뿬2 ְ/u\YL,f5 ` odžXI>+ g;;hYrGK 0Sу}~ U,i*J(BOe :0>k{HNY'xJ!;Ucsx`*Y`GA5`Pƌȟ ?˾Hܻ&`'TDL@ 0qǀK-" f\ ]ԝԁ O΢P EZ}J31$0}Jjm*T`P׸ PѬ׫ LPO0XϧdJА `2`X6a}P P  ؁mN0-S aM=& /Н p @ ؽ P = =MN" Ӥ`ߑQ:9fِ P~ Ͱ p `.} ,x=y2,P -ٰ 3tQ p 9@GGJ0 `0(.` p:];c>5ܲ- !֠ ` h0۵ mFK@ АRN m-cN:@&ݡ ` ` 0 wm }NP`8 QT96*a a ~7M%eLPPP`7 P˾}0zO;GaussSum-2.2.6.1/gausssum/gausssumgui.py0000664000175000017500000006606612117172552016723 0ustar noelnoel# # GaussSum (http://gausssum.sf.net) # Copyright (C) 2006-2009 Noel O'Boyle # # This program is free software; you can redistribute and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from Tkinter import * # GUI stuff import tkMessageBox # For the About Dialog import tkFileDialog # For the Open File and Save File import webbrowser import tkSimpleDialog import traceback import copy # For deepcopy...until I find a better way of doing this import ConfigParser # For writing the settings to an .ini file import logging import glob from gausssum.cclib.parser import ADF, GAMESS, Gaussian, ccopen from gausssum.preferencesbox import PreferencesPopupBox from gausssum.aboutbox import AboutPopupBox from gausssum.popanalysis import Popanalysis from gausssum.electrontrans import ET from gausssum.geoopt import GeoOpt from gausssum.search import Search from gausssum.vibfreq import Vibfreq from gausssum.scf import SCF from gausssum.utils import * from gausssum.folder import folder import os, sys if hasattr(sys, "frozen"): # i.e. if using py2exe installlocation = os.path.dirname(sys.executable) else: import gausssum installlocation = gausssum.__path__[0] class App: # This sets up the GUI def __init__(self,root,argv): self.root = root self.root.resizable(False,False) self.addmenubar() self.frame1=Frame(self.root) self.frame1.grid() frame2=Frame(self.root) frame2.grid(row=1) self.scrollbar=Scrollbar(frame2) self.scrollbar.pack(side=RIGHT,fill=Y) if sys.platform == "win32": self.txt=Text(frame2,font=("Courier New",8),yscrollcommand=self.scrollbar.set,width=90,height=21) else: # Avoid font problems (? I don't remember the reason for this) self.txt=Text(frame2,yscrollcommand=self.scrollbar.set,width=90,height=21) self.txt.pack(expand=1,fill=Y) self.scrollbar.config(command=self.txt.yview) self.screen=Redirect(self.txt.insert,self.root,[END,self.txt]) # Oh yeah! Could I have done it in a more roundabout way? self.screen.write("Support GaussSum by citing:\nN.M. O'Boyle, A.L. Tenderholt and K.M. Langner. J. Comp. Chem. 2008, 29, 839-845.\n") frame3=Frame(self.frame1,relief=GROOVE,borderwidth=3) frame3.pack(side=LEFT,anchor=W) self.middleframe=Frame(self.frame1,width=380,height=140) self.middleframe.pack(side=LEFT) # Thanks to the students from Ulm for the next line # which prevents self.middleframe resizing when you choose a different option self.middleframe.pack_propagate(0) self.frame4=Frame(self.middleframe) self.frame4.pack(side=LEFT) self.script = StringVar() self.b3=Radiobutton(frame3, text="Search file", variable=self.script, value="FIND",command=self.option,state=DISABLED) self.b3.pack(anchor=W) self.b0=Radiobutton(frame3, text="Monitor SCF", variable=self.script, value="SCF",command=self.option,state=DISABLED) self.b0.pack(anchor=W) self.b1=Radiobutton(frame3, text="Monitor GeoOpt", variable=self.script, value="GEOOPT",command=self.option,state=DISABLED) self.b1.pack(anchor=W) self.b2=Radiobutton(frame3, text="Frequencies", variable=self.script, value="IR_RAMAN",command=self.option,state=DISABLED) self.b2.pack(anchor=W) self.b5=Radiobutton(frame3, text="Orbitals", variable=self.script, value="MO",command=self.option,state=DISABLED) self.b5.pack(anchor=W) self.b4=Radiobutton(frame3, text="Electronic transitions", variable=self.script, value="UVVIS",command=self.option,state=DISABLED) self.b4.pack(anchor=W) ## self.b6=Radiobutton(frame3, text="EDDM.py", variable=self.script, value="EDDM", command=self.option,state=DISABLED) ## self.b6.pack(anchor=W) ## self.b7=Radiobutton(frame3, text="NMR.py (beta)", variable=self.script, value="NMR", command=self.option,state=DISABLED) ## self.b7.pack(anchor=W) self.b3.select(); self.frame5=Frame(self.frame1) self.frame5.pack(side=LEFT) self.photo = PhotoImage(file=os.path.join(installlocation,"mesh2.gif")) # Doesn't work if don't use self. Button(self.frame5,image=self.photo,command=self.runscript).pack(side=LEFT) self.root.bind("", self.runscript) x=(self.root.winfo_screenwidth()-652)/2 # The window is 652x480 y=(self.root.winfo_screenheight()-580)/2 self.root.geometry("652x480+"+str(x)+"+"+str(y)) # Get the window dead-centre self.error=ErrorCatcher() # Read in the preferences from the preferences file. # If it doesn't exist, create one using the defaults. self.readprefs() if len(argv)>1: # What to do if a filename is passed as an argument if os.path.isfile(argv[1]): # Does it exist? self.inputfilename=os.path.basename(argv[1]) t=os.path.dirname(argv[1]) if t: os.chdir(t) # Create an instance of the parser self.logfile = ccopen(self.inputfilename) self.fileopenednow() else: self.screen.write(argv[1]+" does not exist or is not a valid filename\n") self.inputfilename=None else: self.inputfilename=None ### Read in the nmr standards file (if it exists) ## self.nmrstandards = NMRstandards(self.settings['nmr.data']) def option(self): # What to do when they choose a script s=self.script.get() self.frame4.destroy() self.frame4=Frame(self.middleframe,width=380) self.frame4.pack(side=LEFT) if s=="SCF" or s=="GEOOPT": Label(self.frame4,text="Leave out the first n points").pack(side=LEFT) self.numpts=Entry(self.frame4,width=3) self.numpts.pack(side=LEFT) self.numpts.insert(0,"0") self.reparse = IntVar() ckb = Checkbutton(self.frame4, text="Reparse first?", variable=self.reparse) ckb.pack(side=LEFT) elif s=="IR_RAMAN": frame5=Frame(self.frame4) frame5.pack(side=TOP) frame6=Frame(self.frame4) frame6.pack(side=TOP) frame7=Frame(self.frame4) frame7.pack(side=TOP) frame8=Frame(self.frame4) frame8.pack(side=TOP) frame9=Frame(self.frame4) frame9.pack(side=TOP) Label(frame5,text="Start:").pack(side=LEFT) self.start=Entry(frame5,width=5) self.start.pack(side=LEFT) self.start.insert(0,self.settings['ir_raman.start']) Label(frame5,text="End:").pack(side=LEFT) self.end=Entry(frame5,width=5) self.end.pack(side=LEFT) self.end.insert(0,self.settings['ir_raman.end']) Label(frame5,text="Num pts:").pack(side=LEFT) self.numpts=Entry(frame5,width=6) self.numpts.pack(side=LEFT) self.numpts.insert(0,self.settings['ir_raman.numpoints']) Label(frame5,text="FWHM").pack(side=LEFT) self.FWHM=Entry(frame5,width=3) self.FWHM.pack(side=LEFT) self.FWHM.insert(0,self.settings['ir_raman.fwhm']) Label(frame6,text="Scaling factors:").pack(side=LEFT) self.scale=StringVar() r=Radiobutton(frame6,text="General",variable=self.scale,value="Gen") r.pack(side=LEFT) self.scalefactor=Entry(frame6,width=5) self.scalefactor.insert(0,'1.00') self.scalefactor.pack(side=LEFT) r2=Radiobutton(frame6,text="Individual",variable=self.scale,value="Indiv") r2.pack(side=LEFT) r.select() Label(frame7, text="The following are used to calculate Raman intensities:").pack() Label(frame8, text="Exc. wavelength (nm)").pack(side=LEFT) self.excitation = Entry(frame8, width=6) self.excitation.pack(side=LEFT) self.excitation.insert(0, self.settings['ir_raman.excitation']) Label(frame8, text="Temp. (K)").pack(side=LEFT) self.temperature = Entry(frame8,width=6) self.temperature.pack(side=LEFT) self.temperature.insert(0, self.settings['ir_raman.temperature']) if not hasattr(self.data, "vibramans"): self.excitation.configure(state=DISABLED) self.temperature.configure(state=DISABLED) elif s=="FIND": frame6=Frame(self.frame4) frame6.pack(side=LEFT) frame7=Frame(self.frame4) frame7.pack(side=LEFT) self.searchrad=StringVar() for i in range(4): t="find.text%d" % (i+1) Radiobutton(frame6, text=self.settings[t], variable=self.searchrad, value=self.settings[t]).grid(sticky=W) r=Radiobutton(frame6, text="Custom", variable=self.searchrad, value="Custom") r.grid(sticky=W) r.select() self.customsearch=Entry(frame6,width=15) self.customsearch.grid(row=4,column=1) self.customsearch.insert(END,"Enter phrase here") self.casesensitive=IntVar() casetick=Checkbutton(frame6,text="Case sensitive",variable=self.casesensitive) casetick.grid(row=4,column=2) elif s=="MO": frame8=Frame(self.frame4) frame6=Frame(self.frame4) frame7=Frame(self.frame4) frame8.pack() frame6.pack(side=TOP) frame7.pack(side=TOP) self.MOplot=IntVar() self.MODOS=Radiobutton(frame8, text="DOS", variable=self.MOplot, value=False) self.MODOS.pack(anchor=W) self.MOCOOP=Radiobutton(frame8, text="COOP", variable=self.MOplot, value=True) self.MOCOOP.pack(anchor=W) self.MODOS.select() Label(frame6,text="Start:").pack(side=LEFT) self.start=Entry(frame6,width=5) self.start.pack(side=LEFT) self.start.insert(0,self.settings['mo.start']) Label(frame6,text="End:").pack(side=LEFT) self.end=Entry(frame6,width=5) self.end.pack(side=LEFT) self.end.insert(0,self.settings['mo.end']) Label(frame6,text="FWHM:").pack(side=LEFT) self.FWHM=Entry(frame6,width=5) self.FWHM.pack(side=LEFT) self.FWHM.insert(0,self.settings['mo.fwhm']) self.makeorigin=IntVar() self.makeoriginbtn=Checkbutton(frame7,text="Create originorbs.txt?",variable=self.makeorigin) self.makeoriginbtn.pack(anchor=W) elif s=="UVVIS": frame7=Frame(self.frame4) frame7.pack(side=TOP) frame6=Frame(self.frame4) frame6.pack() self.UVplot=IntVar() self.UVbox=Radiobutton(frame7, text="UV-Visible", variable=self.UVplot, command=self.UVupdate, value=True) self.UVbox.pack(anchor=W) self.CDbox=Radiobutton(frame7, text="Circular dichroism", variable=self.UVplot, command=self.UVupdate, value=False) self.CDbox.pack(anchor=W) self.UVbox.select() Label(frame6,text="Start:").grid(row=0,column=0) Label(frame6,text="nm").grid(row=1,column=1) self.start=Entry(frame6,width=5) self.start.grid(row=0,column=1) self.start.insert(0,self.settings['uvvis.start']) Label(frame6,text="End:").grid(row=0,column=2) Label(frame6,text="nm").grid(row=1,column=3) self.end=Entry(frame6,width=5) self.end.grid(row=0,column=3) self.end.insert(0,self.settings['uvvis.end']) Label(frame6,text="Num pts:").grid(row=0,column=4) self.numpts=Entry(frame6,width=5) self.numpts.grid(row=0,column=5) self.numpts.insert(0,self.settings['uvvis.numpoints']) self.fwhmlabel=Label(frame6,text="FWHM",width=6) self.fwhmlabel.grid(row=0,column=6) self.fwhmunits=Label(frame6,text="1/cm") self.fwhmunits.grid(row=1,column=7) self.FWHM=Entry(frame6,width=5) self.FWHM.grid(row=0,column=7) self.FWHM.insert(0,self.settings['uvvis.fwhm']) self.eddm = IntVar() self.eddmbtn = Checkbutton(frame7, text="Create EDDM script?", variable=self.eddm) self.eddmbtn.pack(anchor=W) gaussdir = folder(self.screen, self.logfile.filename, create=False) if (len(glob.glob(os.path.join(gaussdir, "*.fck"))) == 0 and len(glob.glob(os.path.join(gaussdir, "*.fchk"))) == 0 and len(glob.glob(os.path.join(gaussdir, "*.chk"))) == 0): self.eddmbtn.configure(state=DISABLED) def createnmrpanel(self,parent): # Sets up the Panel for the NMR options frame6=Frame(parent) frame6.grid(row=0,column=0) # Set up the Radiobuttons self.nmrrb = StringVar() # Extract, Comment, Listbox self.nmrrb1=Radiobutton(frame6, text="Just extract NMR data", variable=self.nmrrb, value="Extract",command=self.nmrrbcb) self.nmrrb1.pack(anchor=W) self.nmrrb2=Radiobutton(frame6, text="Take level of theory from comment", variable=self.nmrrb, value="Comment",command=self.nmrrbcb) self.nmrrb2.pack(anchor=W) self.nmrrb3=Radiobutton(frame6, text="Take level of theory from listbox", variable=self.nmrrb, value="Listbox",command=self.nmrrbcb) self.nmrrb3.pack(anchor=W) self.nmrrb1.select() # Set up the Listbox frame7=Frame(parent) frame7.grid(row=1,column=0) nmrscrlbar=Scrollbar(frame7,orient=VERTICAL) self.nmrlbx1=Listbox(frame7,yscrollcommand=nmrscrlbar.set,height=5) nmrscrlbar.config(command=self.nmrlbx1.yview) nmrscrlbar.pack(side=RIGHT,fill=Y) self.nmrlbx1.pack(side=LEFT,fill=BOTH,expand=1) for x in self.nmrstandards: self.nmrlbx1.insert(END,x['theory']) self.nmrlbx1.select_set(0) self.nmrlbx1.configure(state=DISABLED) # Set up more Radiobuttons frame8=Frame(parent) frame8.grid(row=0,column=1) self.nmrrb2 = StringVar() # Calculate, Standard self.nmrrb2a=Radiobutton(frame8, text="Calculate relative ppm", variable=self.nmrrb2, value="Calculate") self.nmrrb2a.pack(anchor=W) self.nmrrb2b=Radiobutton(frame8, text="Add new standard", variable=self.nmrrb2, value="Standard") self.nmrrb2b.pack(anchor=W) self.nmrrb2a.select() self.nmrrb2a.configure(state=DISABLED) self.nmrrb2b.configure(state=DISABLED) def nmrrbcb(self): # What to do when the user chooses one of the NMR radiobuttons # (NMR RadioButton CallBack) value=self.nmrrb.get() if value=="Listbox": # Configure the listbox self.nmrlbx1.configure(state=NORMAL) else: self.nmrlbx1.configure(state=DISABLED) if value=="Extract": # Configure everything self.nmrrb2a.configure(state=DISABLED) self.nmrrb2b.configure(state=DISABLED) elif value=="Listbox": self.nmrrb2a.configure(state=NORMAL) self.nmrrb2b.configure(state=DISABLED) else: self.nmrrb2a.configure(state=NORMAL) self.nmrrb2b.configure(state=NORMAL) def UVupdate(self): # What to do when the user chooses UVVis or CD for UVVis.py if self.UVplot.get()==False: # Choose CD self.fwhmlabel.configure(text="sigma:") self.fwhmunits.configure(text="eV") self.FWHM.delete(0,END) self.FWHM.insert(0,self.settings['uvvis.sigma']) else: # Choose UVVis self.fwhmlabel.configure(text="FWHM:") self.fwhmunits.configure(text="1/cm") self.FWHM.delete(0,END) self.FWHM.insert(0,self.settings['uvvis.fwhm']) def runscript(self,event=None): # What to do when the user clicks on the GaussSum logo # to run the script if not self.inputfilename: self.screen.write("You need to open a log file first\n") return # Do nothing if no file opened s = self.script.get() self.txt.delete(1.0, END) worked=False try: if s=="SCF": if self.reparse.get(): self.data = self.logfile.parse() worked = SCF(self.root,self.screen,self.data,int(self.numpts.get()),self.settings['global settings.gnuplot']) elif s=="GEOOPT": if self.reparse.get(): self.data = self.logfile.parse() worked = GeoOpt(self.root,self.screen,self.data,int(self.numpts.get()),self.settings['global settings.gnuplot']) elif s=="IR_RAMAN": worked = Vibfreq(self.root,self.screen,self.data,self.logfile.filename,int(self.start.get()),int(self.end.get()),int(self.numpts.get()),float(self.FWHM.get()),self.scale.get(),float(self.scalefactor.get()),float(self.excitation.get()),float(self.temperature.get()),self.settings['global settings.gnuplot']) elif s=="FIND": if self.searchrad.get()=="Custom": worked = Search(self.screen,self.logfile.filename,self.customsearch.get(),self.casesensitive.get()) else: worked = Search(self.screen,self.logfile.filename,self.searchrad.get(),1) elif s=="MO": worked = Popanalysis(self.root,self.screen,self.data,self.logfile.filename,float(self.start.get()),float(self.end.get()),self.MOplot.get(),float(self.FWHM.get()),self.makeorigin.get(),self.settings['global settings.gnuplot']) elif s=="UVVIS": worked = ET(self.root,self.screen,self.data,self.logfile.filename,int(self.start.get()),int(self.end.get()),int(self.numpts.get()),float(self.FWHM.get()),self.UVplot.get(),self.settings['global settings.gnuplot'], self.eddm.get()) ## elif s=="EDDM": ## worked=GaussSum.EDDM.EDDM(self.screen,self.logfile,self.trans.get(),self.settings['eddm.cubman'],self.settings['eddm.formchk'],self.settings['eddm.cubegen']) ## elif s=="NMR": ## listboxvalue=self.nmrlbx1.curselection() ## try: # Works for both list of strings and list of ints (see Tkinter documentation for details) ## listboxvalue=map(int,listboxvalue) ## except ValueError: pass ## if len(listboxvalue)>0: ## selected = self.nmrlbx1.get(listboxvalue[0]) ## else: ## selected = [] ## worked=GaussSum.NMR.NMR(self.screen,self.logfile,self.nmrrb.get(), ## selected,self.nmrrb2.get(),self.nmrstandards) except: traceback.print_exc(file=self.error) # Catch errors from the python scripts (user GIGO errors, of course!) tkMessageBox.showerror(title="The script is complaining...",message=self.error.log) self.error.clear() self.root.update() def addmenubar(self): """Set up the menubar.""" menu = Menu(self.root) self.root.config(menu=menu) filemenu = Menu(menu) menu.add_cascade(label="File", underline=0, menu=filemenu) filemenu.add_command(label="Open...", underline=0, command=self.fileopen) filemenu.add_command(label="Settings...",underline=0, command=self.preferences) filemenu.add_separator() filemenu.add_command(label="Exit", underline=1, command=self.fileexit) viewmenu=Menu(menu) menu.add_cascade(label="View", underline=0, menu=viewmenu) viewmenu.add_command(label="Error messages", underline=1, command=self.showerrors) helpmenu = Menu(menu) menu.add_cascade(label="Help", underline=0, menu=helpmenu) helpmenu.add_command(label="Documentation",underline=0, command=self.webdocs) helpmenu.add_separator() helpmenu.add_command(label="About...", underline=0, command=self.aboutdialog) def aboutdialog(self,event=None): # Soaks up event if provided d=AboutPopupBox(self.root,title="About GaussSum") def showerrors(self): self.screen.write("Log of error messages\n%s\n%s\n" % ('*'*20,self.error.longlog) ) def fileexit(self): self.root.destroy() def fileopen(self): if self.inputfilename!=None: mydir=os.path.dirname(self.inputfilename) else: mydir="." inputfilename=tkFileDialog.askopenfilename( filetypes=[ ("All files",".*"), ("Output Files",".out"), ("Log Files",".log"), ("ADF output",".adfout") ], initialdir=mydir ) if inputfilename!="": self.inputfilename=os.path.basename(inputfilename) os.chdir(os.path.dirname(inputfilename)) # Create an instance of the parser if hasattr(self, "logfile") and self.logfile!=None: self.logfile.logger.removeHandler(self.logfile.logger.handlers[0]) self.logfile = ccopen(self.inputfilename) self.fileopenednow() def fileopenednow(self): """What to do once a file is opened.""" if self.logfile==None: tkMessageBox.showerror( title="Not a valid log file", message=("cclib does not recognise %s as a valid logfile.\n\n" "If the file *is* valid, please send an email to " "gausssum-help@lists.sourceforge.net\n describing the problem." % self.inputfilename) ) for button in [self.b0, self.b1, self.b2, self.b3, self.b4, self.b5]: button.configure(state=DISABLED) return # Prevent the logger writing to stdout; instead, write to screen self.logfile.logger.removeHandler(self.logfile.logger.handlers[0]) newhandler = logging.StreamHandler(self.screen) newhandler.setFormatter(logging.Formatter("[%(name)s %(levelname)s] %(message)s")) self.logfile.logger.addHandler(newhandler) try: self.data = self.logfile.parse() except: tkMessageBox.showerror( title="Problems parsing the logfile", message=("cclib has problems parsing %s.\n\n" "If you think it shouldn't, please send an email to " "gausssum-help@lists.sourceforge.net\n describing the problem." % self.inputfilename) ) for button in [self.b0, self.b1, self.b2, self.b3, self.b4, self.b5]: button.configure(state=DISABLED) return self.screen.write("Opened and parsed %s.\n" % self.inputfilename) has = lambda x: hasattr(self.data, x) self.b3.configure(state=NORMAL) # Search if has("scftargets") and has("scfvalues"): self.b0.configure(state=NORMAL) else: self.b0.configure(state=DISABLED) if has("geotargets") and has("geovalues"): self.b1.configure(state=NORMAL) else: self.b1.configure(state=DISABLED) if has("vibfreqs") and (has("vibirs") or has("vibramans")): self.b2.configure(state=NORMAL) else: self.b2.configure(state=DISABLED) if has("etenergies") and has("etoscs"): self.b4.configure(state=NORMAL) else: self.b4.configure(state=DISABLED) self.b5.configure(state=NORMAL) # Orbitals ## self.b6.configure(state=NORMAL) # EDDM ## self.b7.configure(state=NORMAL) # NMR self.b3.invoke() # Click on Find.py self.root.title("GaussSum - "+self.inputfilename) def preferences(self): # The Preferences Dialog Box oldsettings=copy.deepcopy(self.settings) # Remember the old settings d=PreferencesPopupBox(self.root,self.settings,title="Settings") if self.settings!=oldsettings: # if there are any changes self.saveprefs() def getsettingsfile(self): # Check for GaussSum.ini in $APPDATA/GaussSum2.2 (XP) # or $HOME/.GaussSum2.2 (Linux) if sys.platform == "win32": settingsfile = os.path.join(os.getenv("APPDATA"),"GaussSum2.2","GaussSum.ini") else: settingsfile = os.path.join(os.getenv("HOME"), ".GaussSum2.2","GaussSum.ini") return settingsfile def saveprefs(self): # Save the settings settingsfile = self.getsettingsfile() writeoutconfigfile(self.settings,settingsfile) def readprefs(self): # The default settings are overwritten by any existing stored # settings. defaultgnuplot = os.path.join(installlocation,"gnuplot460","bin","wgnuplot.exe") if not sys.platform == "win32": defaultgnuplot = os.path.join(os.sep, "usr", "bin", "gnuplot") self.settings = { 'global settings.gnuplot': defaultgnuplot, 'find.text1':'SCF Done', 'find.text2':'k 501%k502', 'find.text3':'imaginary', 'find.text4':'Framework', 'ir_raman.start':'0', 'ir_raman.end':'4000', 'ir_raman.numpoints':'500', 'ir_raman.fwhm':'10', 'ir_raman.excitation':'785', 'ir_raman.temperature':'293.15', 'mo.start':'-20', 'mo.end':'0', 'mo.fwhm':'0.3', 'uvvis.start':'300', 'uvvis.end':'800', 'uvvis.numpoints':'500', 'uvvis.fwhm':'3000', 'uvvis.sigma':'0.2', } settingsfile = self.getsettingsfile() if os.path.isfile(settingsfile): # Check for settings file # Found it! - so read it in. self.settings.update(readinconfigfile(settingsfile)) else: # Initialise the settings file (and directory) settingsdir = os.path.dirname(settingsfile) if not os.path.isdir(settingsdir): os.mkdir(settingsdir) self.saveprefs() # Save the inital settings file def webdocs(self): webbrowser.open(os.path.join(installlocation,"..","Docs","index.html"))