├── .gitattributes ├── .gitignore ├── .gitmodules ├── COPYRIGHT.txt ├── Doxyfile ├── LICENSE.txt ├── README.rst ├── bin ├── __init__.py ├── cc2molden.py ├── print_doc.py ├── theodore ├── theotools.py └── write_den.bash ├── cclib ├── colt ├── doc ├── Makefile ├── README ├── html │ ├── cap.html │ ├── contact.html │ ├── doc.html │ ├── download.html │ ├── images │ │ ├── COH.png │ │ ├── COV.png │ │ ├── CT.png │ │ ├── CTnt.png │ │ ├── Corr.png │ │ ├── NTOI1.2_1o_0.42.png │ │ ├── NTOI1.2_1v_0.42.png │ │ ├── NTOI1.2_2o_0.32.png │ │ ├── NTOI1.2_2v_0.32.png │ │ ├── NTOI2.1_1o_1.65.png │ │ ├── NTOI2.1_1v_1.65.png │ │ ├── NTOI2.2_1o_0.52.png │ │ ├── NTOI2.2_1v_0.52.png │ │ ├── NTOI2.2_2o_0.32.png │ │ ├── NTOI2.2_2v_0.32.png │ │ ├── Om.png │ │ ├── OmFrag.html │ │ ├── POS.png │ │ ├── PR.png │ │ ├── PRNTO.png │ │ ├── cbar.png │ │ ├── dE(eV).png │ │ ├── dexc.png │ │ ├── f.png │ │ ├── graphs.html │ │ ├── nto.html │ │ ├── pcolor_10a.png │ │ ├── pcolor_1a.png │ │ ├── pcolor_2a.png │ │ ├── pcolor_3a.png │ │ ├── pcolor_4a.png │ │ ├── pcolor_5a.png │ │ ├── pcolor_6a.png │ │ ├── pcolor_7a.png │ │ ├── pcolor_8a.png │ │ ├── pcolor_9a.png │ │ ├── screenshot.png │ │ ├── sigE.png │ │ └── sigH.png │ ├── include │ │ ├── end.inc │ │ └── start.inc │ ├── index.html │ ├── libwfa.html │ ├── literature.html │ ├── styles.css │ └── template.html ├── latex │ ├── Om_bars.png │ ├── Om_desc.tex │ ├── avo_instructions.png │ ├── fa2 │ │ ├── NTO1-1-a_1o_56.png │ │ ├── NTO1-1-a_1v_56.png │ │ ├── NTO1-1-a_2o_39.png │ │ ├── NTO1-1-a_2v_39.png │ │ ├── NTO2-1-a_1o_56.png │ │ ├── NTO2-1-a_1v_56.png │ │ ├── NTO2-1-a_2o_41.png │ │ ├── NTO2-1-a_2v_41.png │ │ ├── axes.png │ │ ├── fa2avo.png │ │ ├── pcolor_11a.png │ │ ├── pcolor_21a.png │ │ ├── pcolor_31a.png │ │ ├── pcolor_41a.png │ │ ├── pcolor_51a.png │ │ └── pcolor_61a.png │ ├── naphth │ │ ├── rho_p_S_B3u_1_hole-F02.png │ │ ├── rho_p_S_B3u_1_hole-F03.png │ │ ├── rho_p_S_B3u_2_hole-F02.png │ │ ├── rho_p_S_B3u_2_hole-F03.png │ │ ├── rho_p_T_B3u_1_hole-F02.png │ │ ├── rho_p_T_B3u_1_hole-F03.png │ │ ├── rho_p_T_B3u_2_hole-F02.png │ │ └── rho_p_T_B3u_2_hole-F03.png │ ├── naphth_frag.png │ └── tutorial.tex └── source │ ├── _static │ └── theodore.png │ ├── chemical_shielding.rst │ ├── conf.py │ ├── contents.rst │ ├── difference_density_analysis.rst │ ├── figures │ ├── 2M.png │ ├── 2P.png │ ├── Om_bars.png │ ├── VIST-all.png │ ├── frag_decomp.png │ └── neut.png │ ├── input_generation.rst │ ├── installation.rst │ ├── keywords.rst │ ├── orbitals_and_densities.rst │ ├── plotting.rst │ ├── program_specific_information.rst │ ├── refs.bib │ ├── transition_density_analysis.rst │ └── usage.rst ├── make_distrib.bash ├── orbkit ├── periodictable ├── push_docs.bash ├── pyinstall.bash ├── setpaths.bash ├── setpaths.csh ├── setup.py └── theodore ├── OB_repl.py ├── Om_descriptors.py ├── __init__.py ├── actions ├── __init__.py ├── actions.py ├── analyze_NOs.py ├── analyze_correlations.py ├── analyze_sden.py ├── analyze_tden.py ├── analyze_tden_soc.py ├── babel.py ├── cc2molden.py ├── cc_check.py ├── cc_opt.py ├── convert_table.py ├── dgrid_prep.py ├── draw_moments.py ├── extract_molden.py ├── fcd.py ├── jmol_MOs.py ├── jmol_vibs.py ├── parse_libwfa.py ├── plot_OmFrag.py ├── plot_Om_bars.py ├── plot_frag_decomp.py ├── plot_graph.py ├── plot_graph_nx.py ├── plot_vist.py ├── spectrum.py ├── tden_OV.py ├── theoinp.py ├── theotools.py └── vmd_plots.py ├── atominfo.py ├── cclib_interface.py ├── dens_ana_base.py ├── error_handler.py ├── fchk_parser.py ├── file_parser.py ├── input_options.py ├── lib_NICS.py ├── lib_diab.py ├── lib_exciton.py ├── lib_file.py ├── lib_mo.py ├── lib_plot.py ├── lib_pytest.py ├── lib_sden.py ├── lib_soc.py ├── lib_struc.py ├── lib_tden.py ├── lib_util.py ├── orbkit_full.py ├── orbkit_interface.py ├── pop_ana.py ├── theo_header.py └── units.py /.gitattributes: -------------------------------------------------------------------------------- 1 | EXAMPLES/* linguist-language=data 2 | EXAMPLES/*/* linguist-language=data 3 | EXAMPLES/*/*/* linguist-language=data 4 | EXAMPLES/*/*/*/* linguist-language=data 5 | *.mo linguist-language=data 6 | external/* linguist-vendored 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | lib/cclib 3 | lib/orbkit 4 | DOXYGEN 5 | *.komodoproject 6 | EXAMPLES/*/RUN 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/cclib"] 2 | path = external/cclib 3 | url = https://github.com/felixplasser/cclib.git 4 | [submodule "external/orbkit"] 5 | path = external/orbkit 6 | url = https://github.com/felixplasser/orbkit.git 7 | [submodule "external/colt"] 8 | path = external/colt 9 | url = https://github.com/MFSJMenger/colt.git 10 | [submodule "external/periodictable"] 11 | path = external/periodictable 12 | url = https://github.com/pkienzle/periodictable.git 13 | -------------------------------------------------------------------------------- /COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | TheoDORE 1.x 2 | 3 | Copyright 2018 Felix Plasser 4 | 5 | This package is free software governed by the terms of the GNU 6 | General Public License 3.0 as published by the Free Software 7 | Foundation. 8 | 9 | This package is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | 13 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | TheoDORE 2 | -------- 3 | 4 | The **TheoDORE** (Theoretical Density, Orbital Relaxation and Exciton analysis) package is a program suite for the analysis of excited states obtained from quantum chemical excited state calculations. 5 | 6 | *Author*: Felix Plasser 7 | 8 | *Contributors*: Ljiljana Stojanovic, Gunter Hermann, Sebastian Mai, Maximilian F.S.J. Menger, Patrick Kimber 9 | 10 | TheoDORE is distributed under the GNU General Public License 3.0 (see `LICENSE.txt `_). 11 | 12 | *Main citation for TheoDORE*: F. Plasser, `"TheoDORE: A toolbox for a detailed and automated analysis of electronic excited state computations" `_, 13 | *J. Chem. Phys.*, (**2020**), 152, 084108. 14 | More literature, regarding the individual implemented methods, is given in the header file when calling TheoDORE. 15 | 16 | .. image:: ./doc/source/_static/theodore.png 17 | 18 | Documentation 19 | ~~~~~~~~~~~~~ 20 | * `Documentation of TheoDORE 3 `_ 21 | 22 | For user support, please use the `forum `_. 23 | 24 | For bugs / feature requests, please use the `issues page `_. 25 | 26 | Installation 27 | ~~~~~~~~~~~~ 28 | * You can obtain the newest TheoDORE release from `github releases `_. 29 | * Alternatively, to get the current development version of the code and test suite, run 30 | 31 | :: 32 | 33 | git clone --recursive https://github.com/felixplasser/theodore-qc.git 34 | git clone https://github.com/felixplasser/theodore-test.git 35 | 36 | * To run TheoDORE, setup ``PATH`` and ``PYTHONPATH`` as explained in the `installation instructions `_. 37 | 38 | Usage 39 | ~~~~~ 40 | A detailed description of the usage is given `here `_. 41 | 42 | * As opposed to earlier versions, TheoDORE 3 is activated with a central driver script ``theodore``. 43 | * To get a list of all implemented options simply type 44 | 45 | :: 46 | 47 | theodore -h 48 | 49 | * For input generation 50 | 51 | :: 52 | 53 | theodore theoinp 54 | 55 | * Analysis of transition density matrices 56 | 57 | :: 58 | 59 | theodore analyze_tden 60 | 61 | External libraries 62 | ~~~~~~~~~~~~~~~~~~ 63 | 64 | *Libraries distributed along with TheoDORE are listed below.* 65 | 66 | TheoDORE uses the `cclib library `_ for some of its file parsing work. 67 | cclib is distributed under a BSD 3-Clause License, see cclib/LICENSE . 68 | Copyright (c) 2017, the cclib development team. 69 | Citation for cclib: 70 | N. M. O'Boyle, A. L. Tenderholt, K. M. Langner, *J. Comput. Chem.* (**2008**), 29, 839. 71 | 72 | TheoDORE uses `periodictable `_ in connection with cclib. 73 | 74 | TheoDORE uses `colt `_ for its commandline interface. 75 | colt is distributed under the Apache License 2.0. 76 | 77 | *Optional libraries that can be interfaced with TheoDORE* 78 | 79 | TheoDORE uses `Open Babel `_ for reading chemical structure files. 80 | Open Babel is distributed under a GPL license. Install Open Babel if you want to use this functionality. 81 | Citation for Open Babel: 82 | N. M. O'Boyle, M. Banck, C. A. James, C. Morley, T. Vandermeersch, and G. R. Hutchison, *J. Cheminf.* (**2011**), 3, 33. 83 | 84 | TheoDORE uses `ORBKIT `_ for visualization of orbitals and densities. 85 | ORBKIT is distributed under an LGPL license. Install orbkit if you want to use this functionality. 86 | Citation for ORBKIT: 87 | G. Hermann, V. Pohl, J. C. Tremblay, B. Paulus, H.-C. Hege, A. Schild, *J. Comput. Chem.* (**2016**), 37, 1511. 88 | 89 | Disclaimer 90 | ~~~~~~~~~~ 91 | 92 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 93 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 95 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 96 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 97 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 98 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 99 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 100 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 101 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 102 | -------------------------------------------------------------------------------- /bin/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/bin/__init__.py -------------------------------------------------------------------------------- /bin/cc2molden.py: -------------------------------------------------------------------------------- 1 | """ 2 | Convert a log-file to Molden format with the help of cclib. 3 | """ 4 | from __future__ import print_function, division 5 | import sys 6 | import argparse 7 | 8 | from .. import theo_header, cclib_interface, input_options, error_handler, lib_mo 9 | 10 | def print_warning(): 11 | print("cc2molden.py ") 12 | print("Convert a log-file to Molden format with the help of cclib.") 13 | print(" WARNING: This script is not well-tested and might fail for some of the quantum chemistry codes.") 14 | 15 | 16 | def get_logfile(): 17 | parser = argparse.ArgumentParser(description=None) 18 | parser.add_argument('logfile', help='name of the logfile') 19 | args = parser.parse_args() 20 | return args.logfile 21 | 22 | 23 | def cc2molden(): 24 | theo_header.print_header('cc2molden') 25 | print_warning() 26 | logfile = get_logfile() 27 | 28 | 29 | 30 | ioptions = input_options.dens_ana_options(ifile=None, check_init=False) 31 | ioptions['rtype'] = 'cclib' 32 | ioptions['rfile'] = logfile 33 | 34 | ccparser = cclib_interface.file_parser_cclib(ioptions) 35 | 36 | errcode = ccparser.check() 37 | if errcode == 0: 38 | mos = ccparser.read_mos() 39 | mos.write_molden_file(fname="cc.mld") 40 | print("\n Finished: molden format file cc.mld written.") 41 | else: 42 | print(" Conversion to Molden format not possible!") 43 | print(" %s does not contain all required information"%logfile) 44 | -------------------------------------------------------------------------------- /bin/print_doc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from theodore import input_options 4 | 5 | ioptions = input_options.dens_ana_options(None) 6 | 7 | outstr = 'Keywords\n' 8 | outstr += '--------\n\n' 9 | outstr += 'Keywords are generally written to a file ``dens_ana.in``.' 10 | outstr += 'This file can be conveniently created using ``theodore theoinp``.\n\n' 11 | outstr += 'For reference an autogenerated list of input options is given below.\n\n' 12 | outstr += ioptions.doc_info() 13 | 14 | print(outstr) 15 | -------------------------------------------------------------------------------- /bin/theodore: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from theodore import run 3 | 4 | 5 | if __name__ == '__main__': 6 | run() 7 | -------------------------------------------------------------------------------- /bin/theotools.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | # Python 2/3 compatibility 4 | try: 5 | from time import process_time 6 | except ImportError: 7 | from time import clock as process_time # clock is depricated and will be removed in 3.8 8 | try: 9 | from time import perf_counter 10 | except ImportError: 11 | from time import time as perf_counter 12 | 13 | 14 | 15 | def isfile(filename): 16 | if not os.path.exists(filename): 17 | raise SystemExit('Input file %s not found!\nPlease create this file using theoinp or specify its location using -ifile\n' % filename) 18 | return filename 19 | 20 | 21 | def get_ifile_commandline(): 22 | parser = argparse.ArgumentParser(description=None) 23 | parser.add_argument('-ifile', default='dens_ana.in', help='name of the input file') 24 | args = parser.parse_args() 25 | return isfile(args.ifile) 26 | 27 | 28 | def timeit(func): 29 | def _wrapper(*args, **kwargs): 30 | (tc, tt) = (process_time(), perf_counter()) 31 | result = func(*args, **kwargs) 32 | print("CPU time: % .1f s, wall time: %.1f s"%(process_time() - tc, perf_counter() - tt)) 33 | return result 34 | return _wrapper 35 | -------------------------------------------------------------------------------- /bin/write_den.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # reduced version where the transformation happens in the python script 4 | 5 | rm -v WORK/*iwfmt 6 | 7 | cd WORK 8 | echo -e "aoints\n 1\n" |$COLUMBUS/iwfmt.x > aoints.iwfmt 2> err.ignore 9 | 10 | for file in *d1fl.* *d1trfl.* 11 | do 12 | if [ -f $file ]; then 13 | echo $file 14 | echo -e "$file\n 1\n" |$COLUMBUS/iwfmt.x > $file.iwfmt 2> err.ignore 15 | fi 16 | done 17 | -------------------------------------------------------------------------------- /cclib: -------------------------------------------------------------------------------- 1 | external/cclib/cclib -------------------------------------------------------------------------------- /colt: -------------------------------------------------------------------------------- 1 | external/colt/colt -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | Download the newest TheoDORE release and tutorial. 2 | 3 | - Include Q-Chem SF-TDDFT 4 | 5 | TheoDORE 3.2 6 | - Compute absorption cross section and extinction coefficient in spectrum.py 7 | - Updates for DFT/MRCI, including triplets 8 | - OpenMolcas input via: theodore theoinp -a 9 | - Standalone Orca interface 10 | - Fix for es2es 11 | - VIST plots for Turbomole 12 | 13 | TheoDORE 3.1.1 14 | - Fix for QTa values 15 | 16 | TheoDORE 3.1 17 | - Transition charges for ionic/covalent states 18 | - Fixes for Q-Chem EOM-CC and fchk 19 | - Fixes for Columbus, Turbomole 20 | 21 | TheoDORE 3.0 22 | - New user interface and documentation 23 | - LOC for ionic states (analyze_tden) 24 | - Analysis of unrestricted NOs (analyze_nos) 25 | - Improvement for VIST (plot_vist) 26 | - Jmol densities (jmol_mos) 27 | 28 | TheoDORE 3.0_alpha 29 | - New user interface and documentation 30 | - State-to-state TDM 31 | - Updated ADF interface 32 | - ONETEP interface 33 | - Update to analyze_nos 34 | - Excitation number, modified from [DOI: 10.1021/acs.jctc.7b00963] 35 | 36 | TheoDORE 2.4 37 | - Visualization of chemical shielding tensors (VIST) [DOI: 10.1002/ejoc.202100352] 38 | - New pytest verification system 39 | 40 | TheoDORE 2.3 41 | - Compute (unpaired) densities using orbkit 42 | - Fix for theo_test.bash 43 | - Fix for ORCA osc. strengths 44 | - Old RASSI interface removed (was not working properly) 45 | 46 | TheoDORE 2.2 47 | - Unrestricted computations in Orca (Sebastian Mai) 48 | - Substituent-induced electron localization (SIEL) [DOI: 10.1039/D0SC01684E] 49 | 50 | TheoDORE 2.1 51 | - Support for DFT/MRCI 52 | - Support for Q-Chem 5.2/5.3 53 | - De-excitation measure (Phe) [DOI: 10.1039/D0CP00369G] 54 | - Improvements in plot_Om_bars.py 55 | - Natural orbital analysis 56 | 57 | TheoDORE 2.0.2 58 | - Fix for runs without openbabel 59 | 60 | TheoDORE 2.0.1 61 | - Updated Orca interface 62 | - Support for all elements of the periodic table 63 | 64 | TheoDORE 2.0 65 | - Compatibility with TM >= 7.2 66 | - Some bugfixes related to python3 67 | 68 | TheoDORE 2.0_beta 69 | - Compatibility to python3 (Max Menger) 70 | - Conditional electron densities 71 | - Plot dipole and quadrupole moments (draw_moments.py) 72 | - Plot vibrations in Jmol (jmol_vibs.py) 73 | - Simple script for analyzing geometry optimiziations (cc_opt.py) 74 | - Support for fchk files from Q-Chem 75 | - Automatic plotting of state characters (plot_Om_bars.py) 76 | - Volume integrals for vmd_plots.py 77 | 78 | TheoDORE 1.7.2 79 | - Automatic fragment generation (analyze_correlations.py) by Sebastian Mai 80 | - Fix for ricc2 with symmetry + read_binary + Om_formula=2 81 | - Improved orbkit interface 82 | 83 | TheoDORE 1.7.1 84 | - ORCA: read binary file 85 | 86 | TheoDORE 1.7 87 | - Interface to orbkit for extended orbital/density plotting capabilities 88 | 89 | TheoDORE 1.6 90 | - Lowdin orthogonalization for CT numbers 91 | - Improved algorithm for Omega matrix computation 92 | - Support for spin-orbit coupled states (ADF) 93 | - DFTB+ interface (Ljiljana Stojanovic) 94 | - Improved support for Molcas/libwfa 95 | 96 | TheoDORE 1.5.1 97 | - New interface for ADF (reading only the TAPE21 file) 98 | 99 | TheoDORE 1.5 100 | - Interface to Newton-X (plot_graph_nx.py) 101 | - Interface to dgrid for plotting (dgrid_prep.py) 102 | - Interface to gnuplot (plot_graph.py) 103 | - Interface to VMD for plotting (vmd_plots.py) 104 | - New script for transition density matrix overlap 105 | - Restart option for analyze_tden.py 106 | - Minor bug fixes 107 | 108 | TheoDORE 1.4 109 | - Population analysis of MOs 110 | - Interface to Terachem 111 | - Parse libwfa output (parse_libwfa.py) 112 | - Support for MOLCAS/libwfa 113 | - Script for fragment decomposition (plot_frag_decomp.py) 114 | - More flexible spectrum generation (spectrum.py) 115 | 116 | TheoDORE 1.3 117 | - Interface for ADF 118 | - cclib taken as part of the distribution 119 | - Electron/hole entanglement entropy 120 | - Automatic fragment definition by element 121 | 122 | TheoDORE 1.2.2 123 | - Crucial bugfix for all cclib jobs 124 | 125 | TheoDORE 1.2.1 126 | - Fixes for Q-Chem and Turbomole read-out 127 | - Automatic file detection for babel.py 128 | 129 | TheoDORE 1.2 130 | - Extended output for e/h populations 131 | - Support for Q-Chem/CC computations 132 | - Fragment charge differences (experimental) 133 | - User input 134 | 135 | TheoDORE 1.1.4 136 | - Bugfix for e/h correlation plots 137 | 138 | TheoDORE 1.1.3 139 | - Create Molden files directly from cclib output 140 | - Enhanced exciton analysis 141 | - Support for Mayer bond order analysis 142 | - Add spectrum.py script for generating a convoluted spectrum 143 | - Improved print out 144 | 145 | TheoDORE 1.1.2 146 | - Support for MOLCAS rassi calculations 147 | - Some adjustments for Q-Chem 4.3 148 | - Fix for FIREFLY ECP computations 149 | 150 | TheoDORE 1.1.1 151 | - Improved output and graphics 152 | 153 | TheoDORE 1.1 154 | - Interface to cclib for parsing of ORCA, Gaussian, GAMESS and other programs 155 | - Parsing of binary files for ricc2 response vector read-out 156 | - New script plot_graph.py for convenient generation of graphs 157 | - New script convert_table.py for creating tables in LaTeX format 158 | - Additional Utility scripts 159 | 160 | TheoDORE 1.0 161 | - First release 162 | -------------------------------------------------------------------------------- /doc/html/cap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TheoDORE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 91 | 92 |

TheoDORE

14 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

15 |
19 | 20 | 21 | 22 | 36 | 86 | 87 |
37 | 38 | 39 |

Capabilities

40 |

Wavefunction analysis

41 |

Analysis of state density matrices 42 |

    43 |
  • Population analysis
  • 44 |
  • Attachment/detachment densities and natural difference orbitals
  • 45 |
46 |

47 | 48 |

Analysis of transition density matrices 49 |

    50 |
  • Charge transfer numbers - electron-hole correlation plots
  • 51 |
  • Natural transition orbitals
  • 52 |
  • Exciton size
  • 53 |
54 |

55 | 56 |

Interfaces

57 |

TheoDORE is interfaced to a number of quantum chemical programs providing a wide range of computational methods: 58 |

    59 |
  • Q-Chem: ADC, TDDFT
  • 60 |
  • Columbus: MR-CI, MCSCF
  • 61 |
  • Molcas: RASSCF, CASPT2
  • 62 |
  • Turbomole: CC2, ADC(2), TDDFT
  • 63 |
  • Terachem: TDDFT
  • 64 |
  • Natural orbitals in Molden format (generated by any program)
  • 65 |
  • ORCA, Gaussian, GAMESS, ADF: TDDFT (starting in version 1.1, parsed with the external 66 | cclib library)
  • 67 |
68 | 69 |

70 | 71 |

Graphical output

72 |

Internal plotting utilities: 73 |

    74 |
  • Electron-hole correlation plots
  • 75 |
  • Property graphs
  • 76 |

77 | 78 |

Interfaces to external graphics programs: 79 |

    80 |
  • Orbital export in Molden format
  • 81 |
  • Compact export of orbitals as Jmol script
  • 82 |

83 | 84 | 85 |
88 | 89 | 90 |
93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /doc/html/contact.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TheoDORE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 52 | 53 |

TheoDORE

14 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

15 |
19 | 20 | 21 | 22 | 36 | 47 | 48 |
37 | 38 | 39 |

Contact

40 |

The TheoDORE code is developed and maintained by Felix Plasser. 41 | 42 | 43 |

Please use github issues 44 | or the discussion forum if you have any questions or encounter problems.

45 | 46 |
49 | 50 | 51 |
54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /doc/html/doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TheoDORE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 74 | 75 |

TheoDORE

14 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

15 |
19 | 20 | 21 | 22 | 36 | 69 | 70 |
37 | 38 |

Visit the 39 | quick start page, check the documentation wiki 40 | or directly go to your documentation topic of interest: 41 |

63 |

64 |

Development: Documentation for TheoDORE 3.0 (alpha) 65 |

66 | 67 | 68 |
71 | 72 | 73 |
76 | 77 | 78 | -------------------------------------------------------------------------------- /doc/html/download.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TheoDORE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 62 | 63 |

TheoDORE

14 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

15 |
19 | 20 | 21 | 22 | 36 | 57 | 58 |
37 | 38 | 39 |

Download

40 |

Please visit the github release page 41 | or click below to directly access the latest version of TheoDORE. 42 |

43 | 44 |
45 | 46 |
47 | 48 |

To get started, please download the tutorial

49 | 50 |
51 | 52 |
53 | 54 | 55 | 56 |
59 | 60 | 61 |
64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /doc/html/images/COH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/COH.png -------------------------------------------------------------------------------- /doc/html/images/COV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/COV.png -------------------------------------------------------------------------------- /doc/html/images/CT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/CT.png -------------------------------------------------------------------------------- /doc/html/images/CTnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/CTnt.png -------------------------------------------------------------------------------- /doc/html/images/Corr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/Corr.png -------------------------------------------------------------------------------- /doc/html/images/NTOI1.2_1o_0.42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI1.2_1o_0.42.png -------------------------------------------------------------------------------- /doc/html/images/NTOI1.2_1v_0.42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI1.2_1v_0.42.png -------------------------------------------------------------------------------- /doc/html/images/NTOI1.2_2o_0.32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI1.2_2o_0.32.png -------------------------------------------------------------------------------- /doc/html/images/NTOI1.2_2v_0.32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI1.2_2v_0.32.png -------------------------------------------------------------------------------- /doc/html/images/NTOI2.1_1o_1.65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI2.1_1o_1.65.png -------------------------------------------------------------------------------- /doc/html/images/NTOI2.1_1v_1.65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI2.1_1v_1.65.png -------------------------------------------------------------------------------- /doc/html/images/NTOI2.2_1o_0.52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI2.2_1o_0.52.png -------------------------------------------------------------------------------- /doc/html/images/NTOI2.2_1v_0.52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI2.2_1v_0.52.png -------------------------------------------------------------------------------- /doc/html/images/NTOI2.2_2o_0.32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI2.2_2o_0.32.png -------------------------------------------------------------------------------- /doc/html/images/NTOI2.2_2v_0.32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/NTOI2.2_2v_0.32.png -------------------------------------------------------------------------------- /doc/html/images/Om.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/Om.png -------------------------------------------------------------------------------- /doc/html/images/OmFrag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Electron-hole correlation plots 4 | 5 | 6 |

Electron-hole correlation plots of the Omega matrices for the individual states.

8 | 10 | 12 | 14 | 15 | 17 | 19 | 21 | 23 | 24 | 26 | 28 | 30 |
7 |
1a
9 |
2a
11 |
3a
13 |
4a
16 |
5a
18 |
6a
20 |
7a
22 |
8a
25 |
9a
27 |
10a
29 |
Scale
31 | 32 | -------------------------------------------------------------------------------- /doc/html/images/POS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/POS.png -------------------------------------------------------------------------------- /doc/html/images/PR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/PR.png -------------------------------------------------------------------------------- /doc/html/images/PRNTO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/PRNTO.png -------------------------------------------------------------------------------- /doc/html/images/cbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/cbar.png -------------------------------------------------------------------------------- /doc/html/images/dE(eV).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/dE(eV).png -------------------------------------------------------------------------------- /doc/html/images/dexc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/dexc.png -------------------------------------------------------------------------------- /doc/html/images/f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/f.png -------------------------------------------------------------------------------- /doc/html/images/graphs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Property graphs 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | -------------------------------------------------------------------------------- /doc/html/images/nto.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | nto 4 | 5 | 6 | 7 | 8 |

I2.1

9 | 10 | 11 | 12 | 13 | 14 |

1.651

1.651
15 | 16 |

I2.2

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |

0.523

0.523

0.323

0.323
27 | 28 |

I1.2

29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |

0.422

0.422

0.319

0.319
39 | 40 | 41 | -------------------------------------------------------------------------------- /doc/html/images/pcolor_10a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_10a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_1a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_1a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_2a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_2a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_3a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_3a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_4a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_4a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_5a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_5a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_6a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_6a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_7a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_7a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_8a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_8a.png -------------------------------------------------------------------------------- /doc/html/images/pcolor_9a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/pcolor_9a.png -------------------------------------------------------------------------------- /doc/html/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/screenshot.png -------------------------------------------------------------------------------- /doc/html/images/sigE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/sigE.png -------------------------------------------------------------------------------- /doc/html/images/sigH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/images/sigH.png -------------------------------------------------------------------------------- /doc/html/include/end.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /doc/html/include/start.inc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TheoDORE 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 |

TheoDORE

13 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

14 |
18 | 19 | 20 | 21 | 35 |
-------------------------------------------------------------------------------- /doc/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TheoDORE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 63 | 64 |

TheoDORE

14 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

15 |
19 | 20 | 21 | 22 | 36 | 58 | 59 |
37 | 38 | 52 | 55 |
39 |

Wavefunction analysis

40 |

The TheoDORE (Theoretical Density, Orbital Relaxation and Exciton analysis) package is a general purpose program suite for the analysis of excited states obtained from quantum chemical excited state calculations. 41 |

42 | 43 |

Density matrices

44 |

Wavefunction analysis is based on state and transition density matrices, which provides a unified formalism applicable independent of the wavefunction model. 45 |

46 | 47 |

Flexible implementation

48 |

TheoDORE is interfaced to a number of quantum chemical programs (Q-Chem, Columbus, Turbomole, Molcas, Orca, Gaussian, Firefly, Terachem) and can be used for a wide range of excited state methods (CASSCF, MR-CI, ADC, CC, TDDFT). 49 | It is written in a modular fashion to allow for an easy extension of these capabilities.

50 | 51 |
53 | theodore output by felix plasser 54 |
56 | 57 |
60 | 61 | 62 |
65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /doc/html/libwfa.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TheoDORE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 57 | 58 |

TheoDORE

14 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

15 |
19 | 20 | 21 | 22 | 36 | 52 | 53 |
37 | 38 |

The libwfa library

39 | 40 |

While TheoDORE focuses on an external analysis of the output of standard quantum chemical programs, an integrated wavefunction analysis environment is provided by the wavefunction analysis library libwfa. 41 |

42 | 43 |

The libwfa library was developed by F. Plasser, M. Wormit, S. A. Bäppler, B. Thomitzni, and A. Dreuw at the University of Heidelberg. 44 | Currently libwfa is interfaced to the ADC, CC and TDDFT modules of Q-Chem 45 | as well as the RASSCF and RASSI modules of OpenMolcas.

46 | 47 |

The libwfa source can be accessed via github. 48 | If you are interested in writing a new interface or in including new functionality, please contact one of the authors. 49 |

50 | 51 |
54 | 55 | 56 |
59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /doc/html/styles.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/html/styles.css -------------------------------------------------------------------------------- /doc/html/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TheoDORE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 45 | 46 |

TheoDORE

14 |

A package for Theoretical Density, Orbital Relaxation and Exciton analysis

15 |
19 | 20 | 21 | 22 | 36 | 40 | 41 |
37 | 38 | 39 |
42 | 43 | 44 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /doc/latex/Om_bars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/Om_bars.png -------------------------------------------------------------------------------- /doc/latex/Om_desc.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt,a4paper]{article} 2 | \usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry} 3 | \usepackage[utf8]{inputenc} 4 | \usepackage[english]{babel} 5 | \usepackage{amsmath} 6 | \usepackage{amsfonts} 7 | \usepackage{amssymb} 8 | \usepackage{hyperref} 9 | \usepackage{color} 10 | \author{Felix Plasser} 11 | \title{1TDM Descriptors} 12 | 13 | \newcommand{\om}[1]{\omega_{\textrm{#1}}} 14 | \newcommand{\doi}[1]{\href{http://dx.doi.org/#1}{\textcolor{blue}{\bf DOI: #1}}} 15 | 16 | \begin{document} 17 | \section{Standard 1TDM descriptors} 18 | Standard fragment based descriptors of the one-particle transition density matrix (1TDM). 19 | $A$ and $B$ are the indices of the fragments as defined in \texttt{at\_lists} . 20 | For more information see Ref~\cite{DMAT}. 21 | \\~\\ 22 | \begin{tabular}{clc} 23 | \hline 24 | \textbf{Key} & \textbf{Formula} & \textbf{Description} \\ 25 | \hline 26 | \\ 27 | Om & $\Omega = \sum_{AB}\Omega_{AB}$ & norm of the 1TDM, single-exc. character \\*[1.5ex] 28 | POSi & $\om{POSi}=\Omega^{-1}\sum_A A\left(\sum_B \Omega_{AB}\right)$ & initial/hole position \\*[1.5ex] 29 | POSf & $\om{POSf}=\Omega^{-1}\sum_B B\left(\sum_A \Omega_{AB}\right)$ & final/electron position \\*[1.5ex] 30 | POS & $\om{POS}=(\om{POSi} + \om{POSf})/2$ & average position \\*[1.2ex] 31 | CT & $\om{CT}=\Omega^{-1}\sum_{A,B\neq A}\Omega_{AB}$ & charge transfer \\*[1.5ex] 32 | CT2 & $\om{CT2}=\Omega^{-1}\sum_{A,B\not\in \lbrace A-1,A,A+1\rbrace}\Omega_{AB}$ & CT to second nearest neighbour \\*[1.5ex] 33 | CTnt & $\om{CTnt}=\om{POSf} - \om{POSi}$ & net CT distance \\*[1.2ex] 34 | PRi & $\om{PRi}=\Omega^{2}/\sum_A\left(\sum_B \Omega_{AB}\right)^2$ & initial/hole delocalization \\*[1.5ex] 35 | PRf & $\om{PRf}=\Omega^{2}/\sum_B\left(\sum_A \Omega_{AB}\right)^2$ & final/electron delocalization \\*[1.5ex] 36 | PR & $\om{PR}=(\om{PRi}+\om{PRf})/2$ & arithmetic mean delocalization\\*[1.2ex] 37 | PRh & $\om{PRh}=2/(\om{PRi}^{-1}+\om{PRf}^{-1})$ & harmonic mean delocalization\\*[1.2ex] 38 | DEL & $\om{DEL}=\Omega^{2}/\sum_B\left(\sum_A (\Omega_{AB}+\Omega_{BA})/2\right)^2$ & symmetrized/total delocalization\\*[1.2ex] 39 | COH & $\om{COH}=\Omega^{2}/\left(\om{PR}\sum_{AB}\Omega_{AB}{}^2\right)$ & coherence length\\*[1.5ex] 40 | COHh & $\om{COHh}=\Omega^{2}/\left(\om{PRh}\sum_{AB}\Omega_{AB}{}^2\right)$ & harmonic mean coherence length\\*[1.5ex] 41 | \hline 42 | \end{tabular} 43 | 44 | \section{Transition metal complexes} 45 | Specific 1TDM descriptors to be used for transition metal complexes \cite{Ircomp}. 46 | $M$ is the central metal atom (specified as the first fragment in \texttt{at\_lists}), $L,L'$ are the ligands. 47 | \\~\\ 48 | \begin{tabular}{clc} 49 | \hline 50 | \textbf{Key} & \textbf{Formula} & \textbf{Description} \\ 51 | \hline 52 | \\ 53 | MC & $\om{MC}=\Omega^{-1}\Omega_{MM}$ & metal centered contribution \\*[1.5ex] 54 | LC & $\om{LC}=\Omega^{-1}\sum_L\Omega_{LL}$ & locally excited ligand centered contribution \\*[1.5ex] 55 | MLCT & $\om{MLCT}=\Omega^{-1}\sum_L\Omega_{ML}$ & metal-to-ligand CT contribution \\*[1.5ex] 56 | LMCT & $\om{LMCT}=\Omega^{-1}\sum_L\Omega_{LM}$ & ligand-to-metal CT contribution\\*[1.5ex] 57 | LLCT & $\om{LLCT}=\Omega^{-1}\sum_{L\neq L'}\Omega_{LL'}$ & ligand-to-ligand CT contribution\\*[1.5ex] 58 | \hline 59 | \end{tabular} 60 | 61 | \begin{thebibliography}{9} 62 | \bibitem{DMAT} F. Plasser and H. Lischka \textit{JCTC} \doi{10.1021/ct300307c}. 63 | \bibitem{Ircomp} F. Plasser and A. Dreuw \textit{JPCA} \doi{10.1021/jp5122917}. 64 | \end{thebibliography} 65 | 66 | \end{document} -------------------------------------------------------------------------------- /doc/latex/avo_instructions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/avo_instructions.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO1-1-a_1o_56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO1-1-a_1o_56.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO1-1-a_1v_56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO1-1-a_1v_56.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO1-1-a_2o_39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO1-1-a_2o_39.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO1-1-a_2v_39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO1-1-a_2v_39.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO2-1-a_1o_56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO2-1-a_1o_56.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO2-1-a_1v_56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO2-1-a_1v_56.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO2-1-a_2o_41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO2-1-a_2o_41.png -------------------------------------------------------------------------------- /doc/latex/fa2/NTO2-1-a_2v_41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/NTO2-1-a_2v_41.png -------------------------------------------------------------------------------- /doc/latex/fa2/axes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/axes.png -------------------------------------------------------------------------------- /doc/latex/fa2/fa2avo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/fa2avo.png -------------------------------------------------------------------------------- /doc/latex/fa2/pcolor_11a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/pcolor_11a.png -------------------------------------------------------------------------------- /doc/latex/fa2/pcolor_21a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/pcolor_21a.png -------------------------------------------------------------------------------- /doc/latex/fa2/pcolor_31a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/pcolor_31a.png -------------------------------------------------------------------------------- /doc/latex/fa2/pcolor_41a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/pcolor_41a.png -------------------------------------------------------------------------------- /doc/latex/fa2/pcolor_51a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/pcolor_51a.png -------------------------------------------------------------------------------- /doc/latex/fa2/pcolor_61a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/fa2/pcolor_61a.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_S_B3u_1_hole-F02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_S_B3u_1_hole-F02.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_S_B3u_1_hole-F03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_S_B3u_1_hole-F03.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_S_B3u_2_hole-F02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_S_B3u_2_hole-F02.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_S_B3u_2_hole-F03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_S_B3u_2_hole-F03.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_T_B3u_1_hole-F02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_T_B3u_1_hole-F02.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_T_B3u_1_hole-F03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_T_B3u_1_hole-F03.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_T_B3u_2_hole-F02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_T_B3u_2_hole-F02.png -------------------------------------------------------------------------------- /doc/latex/naphth/rho_p_T_B3u_2_hole-F03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth/rho_p_T_B3u_2_hole-F03.png -------------------------------------------------------------------------------- /doc/latex/naphth_frag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/latex/naphth_frag.png -------------------------------------------------------------------------------- /doc/source/_static/theodore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/source/_static/theodore.png -------------------------------------------------------------------------------- /doc/source/chemical_shielding.rst: -------------------------------------------------------------------------------- 1 | Analysis of chemical shielding 2 | ------------------------------ 3 | 4 | TheoDORE provides functionalities to analyse chemical shielding tensors and, in particular their use to analyze aromaticity. 5 | 6 | 7 | Visualisation of chemical shielding tensors (VIST) 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | 10 | The VIST method [`Eur. J. Org. Chem., (2021) `_] allows to visualise chemical shielding tensors in the context of the molecular structure showing local variations of the shielding along with its anisotropy. The method proceeds in the following order 11 | 12 | * Computation of shielding tensors 13 | * Interfaces exists for Gaussian, Q-Chem and Turbomole. 14 | * Creation of VIST input via ``theodore plot_vist`` 15 | * Rendering of VIST plot in `VMD `_ 16 | 17 | The tools have only been recently developed and still might require a bit of manual tuning of script files by the user. Any feedback on the user-friendliness of the tools is appreciated. 18 | 19 | Command line options 20 | ____________________ 21 | 22 | Run ``theodore plot_vist -h`` to see all command line options 23 | 24 | .. code-block:: text 25 | 26 | plot_VIST.py [options] 27 | Command line options: 28 | -h, -H, --help: print this help 29 | -v, --vist : VIST for only these dummy atoms, e.g. -v '0 3 5' 30 | -o : Name of output file (for VMD) 31 | -s, --scale : Scale factor VIST dumb-bells 32 | -c, --coor : Create coordinate files (using cclib) 33 | -p : Render and plot all tensors separately 34 | -l/--lab_min : Add labels for eigenvalues above this value (in ppm), e.g. -l 10 35 | -q/--qccode : Quantum chemistry code (g09, qchem, turbomole) 36 | 37 | Simple example 38 | ______________ 39 | 40 | Create a Gaussian input file for an NMR calculation with the positions of the shielding tensors indicated as dummy (Bq) atoms and run Gaussian. 41 | :: 42 | 43 | # PBE1PBE/Def2SVP scf=tight nmr 44 | 45 | Shielding tensors 46 | 47 | 0 1 48 | C 0.00000 1.20802 0.69749 49 | C 0.00000 1.20802 -0.69749 50 | C 0.00000 -0.00000 -1.39501 51 | C -0.00000 -1.20802 -0.69749 52 | C -0.00000 -1.20802 0.69749 53 | C -0.00000 -0.00000 1.39501 54 | H 0.00000 2.15464 -1.24395 55 | H -0.00000 2.15464 1.24395 56 | H -0.00000 -2.15464 -1.24395 57 | H 0.00000 -0.00000 -2.48803 58 | H -0.00000 -0.00000 2.48803 59 | H -0.00000 -2.15464 1.24395 60 | Bq 0.0 0.0 0.0 61 | Bq 1.0 0.0 0.0 62 | Bq 2.0 0.0 0.0 63 | 64 | 65 | After the job finishes simply run (assuming you named the output file ``gaussian.log``) 66 | 67 | :: 68 | 69 | plot_VIST.py gaussian.log 70 | 71 | Open a molecular coordinate file in VMD. Then from inside VMD click: `File` - `Load Visualization State` - `VIST.vmd` 72 | 73 | In the first instance, this will plot the shielding tensors of all Bq positions on top of each other. 74 | 75 | .. figure:: figures/VIST-all.png 76 | 77 | Use, the `-p` option to plot them all individually or use the `-v` option to select individual tensors. 78 | 79 | Processing several output files 80 | _______________________________ 81 | 82 | In many cases, it is desirable to process several output files at the same time to produce a consistent representation of several output files, for example to represent the shielding in different electronic states. The following figures represent the shielding in the dication, neutral state, and dianion of a macrocycle. 83 | 84 | 85 | .. image:: figures/2P.png 86 | .. image:: figures/neut.png 87 | .. image:: figures/2M.png 88 | 89 | 90 | 91 | 92 | This figure was created with the command 93 | 94 | :: 95 | 96 | theodore plot_vist -c -v '0 4' */gaussian.log 97 | 98 | The ``-c`` option specifies that the molecular coordinates are directly parsed from the log-file. ``-v 0 4`` indicates that only the Bq atoms with index 0 and 4 are included in the representation. ``*/gaussian.log`` indicates that the gaussian.log files in all subdirectories are processed. 99 | 100 | The files are loaded into VMD via 101 | 102 | :: 103 | 104 | vmd -e VIST.vmd 105 | 106 | Initially all geometries are superposed on top of each other. To hide some of the molecules use the ``D`` option (part of ``T A D F Molecule``) in the VMD Main menu. 107 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'theodore' 21 | copyright = '2023, Felix Plasser' 22 | author = 'Felix Plasser' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = '3.1.1' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ "sphinx_rtd_theme", 34 | "colt.sphinx", 35 | ] 36 | 37 | html_logo='_static/theodore.png' 38 | 39 | bibtex_bibfiles = ['refs.bib'] 40 | bibtex_encoding = 'latin' 41 | bibtex_default_style = 'unsrt' 42 | 43 | # Add any paths that contain templates here, relative to this directory. 44 | templates_path = ['_templates'] 45 | 46 | # List of patterns, relative to source directory, that match files and 47 | # directories to ignore when looking for source files. 48 | # This pattern also affects html_static_path and html_extra_path. 49 | exclude_patterns = [] 50 | 51 | root_doc = 'contents' 52 | 53 | # -- Options for HTML output ------------------------------------------------- 54 | 55 | # The theme to use for HTML and HTML Help pages. See the documentation for 56 | # a list of builtin themes. 57 | # 58 | html_theme = 'sphinx_rtd_theme' 59 | html_theme_options = { 60 | 'logo_only': True, 61 | } 62 | 63 | # Add any paths that contain custom static files (such as style sheets) here, 64 | # relative to this directory. They are copied after the builtin static files, 65 | # so a file named "default.css" will overwrite the builtin "default.css". 66 | html_static_path = ['_static'] 67 | -------------------------------------------------------------------------------- /doc/source/contents.rst: -------------------------------------------------------------------------------- 1 | .. theodore documentation master file, created by 2 | sphinx-quickstart on Thu May 13 13:39:18 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | TheoDORE 7 | ==================================== 8 | 9 | Welcome to the TheoDORE 3 documentation! 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | :caption: Contents: 14 | 15 | installation 16 | usage 17 | input_generation 18 | transition_density_analysis 19 | difference_density_analysis 20 | chemical_shielding 21 | plotting 22 | orbitals_and_densities 23 | program_specific_information 24 | keywords 25 | 26 | If you have any questions, 27 | write to the `discussion forum `_, 28 | post an `issue on github `_ 29 | or send me an email to f.plasser(at)lboro.ac.uk. 30 | 31 | .. include:: ../../README.rst 32 | 33 | 34 | 35 | Indices and tables 36 | ================== 37 | 38 | * :ref:`genindex` 39 | * :ref:`modindex` 40 | * :ref:`search` 41 | -------------------------------------------------------------------------------- /doc/source/difference_density_analysis.rst: -------------------------------------------------------------------------------- 1 | State density matrix analysis 2 | ----------------------------- 3 | 4 | Analysis of state and difference density matrices is performed via ``theodore analyze_sden``. 5 | In the case of an analysis of natural orbital (NO) files, also the shortcut ``theodore analyze_nos`` may be invoked. 6 | 7 | For NO files, it may be necessary to adjust the occupations manually (or use the -o option). Bond-order and unpaired electrons analysis currently only works for spin-restricted orbitals. Population and attachement-detachment analysis also works for unrestricted orbitals. 8 | 9 | Population analysis 10 | ~~~~~~~~~~~~~~~~~~~ 11 | 12 | TheoDORE features Mulliken population analysis capabilities, which can be applied to normal densities, densities of effectively unpaired electrons or attachment/detachment densities (see below). 13 | 14 | Unpaired electrons 15 | ~~~~~~~~~~~~~~~~~~ 16 | 17 | Two measures for a number of effectively unpaired electrons can be computed: 18 | 19 | .. math:: 20 | 21 | n_u=\sum_i \min \left(n_i,2-n_i\right) 22 | 23 | and 24 | 25 | .. math:: 26 | 27 | n_{u,nl} = \sum_i n_i^2 (2-n_i^2) 28 | 29 | 30 | where :math:`n_i` marks the occupation number of natural orbital *i*. 31 | 32 | Attachment/detachment analysis and natural difference orbitals 33 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 | The difference density between an excited and a reference state can be diagonalized to provide the natural difference orbitals (NDOs). 35 | Summing over all NDOs of positive (negative) sign, the attachment (detachment) densities can be constructed. 36 | This has to be performed by an :ref:`external program `. 37 | 38 | Bond order and valence analysis 39 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 | 41 | Bond order and valences are computed according to the formulas given by I. Mayer, 42 | see `Int. J. Quant. Chem. 1986 XXIX, 477 `_ for more information. 43 | -------------------------------------------------------------------------------- /doc/source/figures/2M.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/source/figures/2M.png -------------------------------------------------------------------------------- /doc/source/figures/2P.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/source/figures/2P.png -------------------------------------------------------------------------------- /doc/source/figures/Om_bars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/source/figures/Om_bars.png -------------------------------------------------------------------------------- /doc/source/figures/VIST-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/source/figures/VIST-all.png -------------------------------------------------------------------------------- /doc/source/figures/frag_decomp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/source/figures/frag_decomp.png -------------------------------------------------------------------------------- /doc/source/figures/neut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixplasser/theodore-qc/4c6474d9ebf449fd9f9401e44ed12571aa8a46dd/doc/source/figures/neut.png -------------------------------------------------------------------------------- /doc/source/input_generation.rst: -------------------------------------------------------------------------------- 1 | Input generation 2 | ---------------- 3 | 4 | The ``theoinp`` utility allows quick generation of the input information needed by TheoDORE. You can invoke ``theoinp`` using 5 | 6 | :: 7 | 8 | theodore theoinp 9 | 10 | When running ``theoinp``, the relevant options are suggested by default and only minimal input by the user is needed. 11 | It is however advised to take a look at the :ref:`program specific information ` for the different interfaced quantum chemistry codes. 12 | After running ``theoinp`` a list of keywords is written to the file ``dens_ana.in``. 13 | 14 | 15 | 16 | .. colt_commandline:: theodore run 17 | :subparsers: options(theoinp) 18 | :header: False 19 | 20 | alias = theodore 21 | 22 | [arg_format] 23 | name = 25 24 | comment = 60 25 | 26 | [subparser_format] 27 | name = 25 28 | comment = 60 29 | 30 | 31 | Molecular fragment definition 32 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 33 | 34 | A key input quantity for the charge transfer number analysis in TheoDORE is the molecular fragment definition. First, the user has to decide on how to separate the system under study into fragments. There is no unique way to do so, and it may be necessary to try out different fragmentation schemes to produce the most meaningful results. 35 | 36 | There are six different ways of specifying the fragment information in `theoinp`. 37 | 38 | .. code-block:: text 39 | 40 | Mode for specifying molecular fragments (at_lists): 41 | [ 1] Manual input 42 | [ 2] Automatic generation by fragment (using python-openbabel) 43 | [ 3] Automatic generation for transition metal complexes (using python-openbabel) 44 | [ 4] Mixed manual/automatic generation (using python-openbabel) 45 | [ 5] Automatic generation by element (using python-openbabel) 46 | [ 6] Leave empty and fill out later 47 | 48 | - In mode 1 you will be asked to enter the indices of the atoms that belong to the different fragments successively. 49 | 50 | - Mode 2 is a special utility for automatic fragment definition. If the system of interest is composed of different molecules, these are detected automatically. Further customization can be performed by exporting the molecule in ``.mol`` format and changing the bond definitions by using for example `Avogadro `_. 51 | 52 | - Mode 3 is a shortcut version of mode 2 that specifically works for transition metal complexes, see `Coord. Chem. Rev., 361, 74 (2018) `_. You simply have to add the atom of the transition metal and the system is automatically separated into the transition metal and the different ligands. 53 | 54 | - Mode 4 allows you to specify one or more fragments manually and applies Mode 2 for the remaining atoms. 55 | 56 | - Mode 5 automatically separates the list according to the different chemical elements present. 57 | 58 | - For mode 6 the ``dens_ana.in`` file has to be edited manually. For example, the input 59 | 60 | :: 61 | 62 | at_lists = [ [1,3,4], [2,5,6] ] 63 | 64 | means that there are two molecular fragments. The first contains atoms 1, 3, and 4, the second 2, 5, and 6. 65 | 66 | **Note:** For Modes 2-4, the molecule should be given in a file format containing information about bonds, for example ``.mol`` format. 67 | -------------------------------------------------------------------------------- /doc/source/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ------------ 3 | 4 | The installation on a Linux system is split into four simple parts: 5 | 6 | Download and extract the source file 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | Download the newest release TheoDORE_v.s.tgz from the `github releases page `_. 10 | 11 | Extract the source file 12 | 13 | :: 14 | 15 | tar -xf TheoDORE_v.s.tgz 16 | 17 | Setup the path specification 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | To use TheoDORE the `PATH` and `PYTHONPATH` variables have to be adjusted. For this purpose you can use the provided bash script `setpaths.bash` 20 | 21 | :: 22 | 23 | #!/bin/bash 24 | export THEODIR=/yourpath/TheoDORE/TheoDORE_v.s 25 | export PATH=$THEODIR/bin:$PATH 26 | export PYTHONPATH=$THEODIR:$PYTHONPATH 27 | 28 | 29 | **Note:** `PYTHONPATH` no longer points to the `lib` directory starting in TheoDORE_2.0. 30 | 31 | Copy the above lines into your .bashrc file or run: 32 | 33 | :: 34 | 35 | source setpaths.bash 36 | 37 | Alternatively, a csh script setpaths.csh is provided. 38 | 39 | Python3 40 | ~~~~~~~ 41 | 42 | TheoDORE 3 is compatible with python3 (ideally >3.7). 43 | No compatibility to python2 is maintained. 44 | 45 | The older release, TheoDORE 2.4, is still compatible with python v2.7.14. 46 | 47 | External packages 48 | ~~~~~~~~~~~~~~~~~ 49 | 50 | The following external packages are used by TheoDORE and require a separate installation: 51 | 52 | - `python3-numpy `_ - for basic numerical manipulations 53 | - `python3-matplotlib `_ *(optional)* - for plotting of graphs 54 | - `python3-openbabel `_ *(optional)* - for extended file-parsing capabilities of molecular structure files 55 | - `ORBKIT `_ *(optional)* - For creating cube files of densities 56 | 57 | The first three are usually readily available with the standard installation tools, e.g. ``apt-get``, ``yum`` etc. 58 | Alternatively, they may be downloaded from the URLs specified. 59 | If no integrated installation is performed, then it is necessary to add these libraries to the `PYTHONPATH` (see above). 60 | For ORBKIT, you can try 61 | 62 | :: 63 | 64 | cd $THEODIR/external/orbkit 65 | python3 setup.py build_ext --inplace 66 | 67 | Otherwise, please follow the `ORBKIT installation instructions `_. 68 | 69 | The following external packages are provided along with the TheoDORE distribution and do not require installation. 70 | 71 | - `cclib `_ - for file parsing work 72 | - `periodictable `_ - information about periodic table (needed by cclib) 73 | - `colt `_ - user interface 74 | 75 | Using anaconda 76 | ~~~~~~~~~~~~~~ 77 | 78 | A straightforward and universal way of installing most of the required packages is through the use of Anaconda. 79 | 80 | First download the `anaconda distribution `_ and do the installation. Then run the commands: 81 | 82 | :: 83 | 84 | conda install numpy matplotlib 85 | conda install -c openbabel openbabel 86 | 87 | Testing 88 | ~~~~~~~ 89 | 90 | The tests are invoked with ``pytest-3``. In the ``EXAMPLES`` directory run (depending on the packages you want to test) 91 | 92 | :: 93 | 94 | pytest-3 UTILS STANDARD CCLIB 95 | pytest-3 EXTRA 96 | 97 | The first three tests should always work. 98 | For all tests in ``EXTRA`` to pass openbabel, ADF and ORBKIT need to be installed. 99 | 100 | The tests are distributed within the standard TheoDORE distribution. 101 | They are maintained via the `theodore-test `_ repository. 102 | -------------------------------------------------------------------------------- /doc/source/orbitals_and_densities.rst: -------------------------------------------------------------------------------- 1 | .. _orb-dens: 2 | 3 | Orbitals and Densities 4 | ---------------------- 5 | 6 | Orbitals are exported in three forms: 7 | 8 | * `Molden format `_, which can be directly read by a number of visualization programs 9 | 10 | * As a compact script for the `Jmol `_ program 11 | 12 | * Cube files of densities created by the `ORBKIT `_ 13 | 14 | Using the Jmol script 15 | ~~~~~~~~~~~~~~~~~~~~~ 16 | 17 | After running ``analyze_tden`` (``analyze_sden``) the file ``nto_jmol.spt`` (``ndo_jmol.spt``) is created. 18 | This is an input file for jmol, which can be directly executed as 19 | 20 | :: 21 | 22 | jmol -n nto_jmol.spt 23 | 24 | For more flexibility, the following semi-interactive procedure can be applied: 25 | 26 | + Open Jmol 27 | 28 | + Run the first few lines of the script to preview the settings (simply copy them into the Jmol console) 29 | 30 | + Adjust the perspective 31 | 32 | + Run the remaining lines of the script (by copying into the Jmol console) 33 | 34 | + Open the file ``nto.html`` (``ndo.html``) to view the result (`Example `_). 35 | 36 | Density plotting (ORBKIT) 37 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 38 | 39 | Cube files of densities can be directly created with `ORBKIT `_. The interface is controlled via ``theoinp``. 40 | 41 | The cube files can be loaded into VMD and visualized using VMD network files provided by ORBKIT or by using the ``vmd_plots`` facility of TheoDORE. For the latter, just run: 42 | 43 | :: 44 | 45 | theodore vmd_plots *.cb 46 | 47 | ORBKIT is somewhat sensitive in terms of the molden file with orbital information. To achieve the best result, it is advisable to create this file within Molden rather than through TheoDORE. 48 | 49 | Density plotting (Jmol / Molden) 50 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | 52 | The weighted sum over the NTOs gives the *hole* / *particle* densities, while the NDOs yield the *attachment* / *detachment* densities. 53 | First, create Molden format files of the NTOs / NDOs using analyze_tden.py / analyze_sden.py 54 | 55 | Jmol 56 | ^^^^ 57 | 58 | To use Jmol use the ``jmol_mos`` tool. Run, e.g. 59 | 60 | :: 61 | 62 | theodore jmol_mos nto*.mld 63 | 64 | Activate occupancy weighted densities using the following set of options: 65 | 66 | :: 67 | 68 | Specification of the orbital indices to be plotted (spec): 69 | [ 1] sten - Start and end indices 70 | [ 2] frontier - Number of frontier orbitals 71 | [ 3] occ - Occupation threshold 72 | Choice: 3 73 | 74 | ... 75 | 76 | Preprocess and merge the Molden files (preprocess): 77 | Choice (y/n): [n] n 78 | 79 | Compute occupancy-weighted densities (attachment/dentachment, hole/electron, etc)? (do_dens): 80 | Choice (y/n): [n] y 81 | 82 | This will plot densities corresponding to all orbitals that fit the occupation threshold. 83 | Separate densities (``dens_plus.png``, ``dens_minus.png``) are computed for orbitals with positive and negative eigenvalues. 84 | 85 | Molden 86 | ^^^^^^ 87 | 88 | For Molden the following procedure is suggested. 89 | 90 | + To extract the separate *hole* / *particle* contributions use the ``extract_molden`` functitonality 91 | 92 | Run, e.g.: 93 | 94 | :: 95 | 96 | theodore extract_molden nto_1-1-a.mld 97 | 98 | This will create a new directory ``nto_1-1-a.mld.dir`` containing the files ``nto_1-1-a.mld_elec.mld`` and 99 | ``nto_1-1-a.mld_hole.mld`` with the separate contributions. 100 | 101 | * Open ``nto_1-1-a.mld_elec.mld`` in Molden (or preferably gmolden) 102 | * Go to "density mode" 103 | * Select "Plot Function" - "Density" 104 | * Use "Plot Mode" - "Space" 105 | * The result is the *particle* density as defined in `JCP, 141, 024106 (2014) `_. 106 | -------------------------------------------------------------------------------- /doc/source/plotting.rst: -------------------------------------------------------------------------------- 1 | .. _plotting: 2 | 3 | Plotting 4 | -------- 5 | 6 | Electron-hole correlation plots 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | *Electron-hole* correlation plots can be created with the ``theodore plot_omfrag`` utility. 10 | You are asked about the output options directly by this script. 11 | To view the output, simply open the file ``OmFrag.html`` in a web browser (`Example plots `_). 12 | 13 | Generation of property graphs 14 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | 16 | ``plot_graph`` allows automatic generation of graphs of the different properties evaluated by TheoDORE. 17 | For this purpose, it is assumed that several directories with analagous computations are present (e.g. from a potential curve). 18 | 19 | Call ``theodore plot_graph`` and follow the instructions on the screen. 20 | 21 | The graphs are collected in a file ``graphs.html`` (`Example graphs `_). 22 | 23 | For parsing `Newton-X `_ trajectories, a specialized script ``plot_graph_nx.py`` exists. 24 | 25 | Absorption spectrum 26 | ~~~~~~~~~~~~~~~~~~~ 27 | Create a convoluted absorption spectrum from the energies and oscillator strengths parsed by ``analyze_tden``. 28 | 29 | :: 30 | 31 | theodore spectrum [ ...] 32 | 33 | It is also possible to compute the density of states (no weighting by oscillator strengths) and to add restrictions with respect to the states chosen (e.g. only states with CT > 0.5). 34 | 35 | Fragment decomposition (e/h populations) 36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | 38 | An interactive script ``plot_frag_decomp`` can be used for plotting the fragment decomposition of the electron and hole populations of the excited states. 39 | To be called after ``analyze_tden`` 40 | 41 | .. figure:: figures/frag_decomp.png 42 | 43 | Fragment decomposition (Omega matrices) 44 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 45 | 46 | An interactive script ``plot_om_bars`` can be used for plotting the fragment decomposition of the electron and hole populations of the excited states. 47 | To be called after ``analyze_tden``. 48 | The script proceeds by asking for different components, which are each in turn composed of several donor/acceptor pairs. 49 | To define, for example, the MLCT states in a complex with three ligands, proceed like this: 50 | 51 | .. code-block:: text 52 | 53 | Name of component 1 54 | Choice: MLCT 55 | 56 | Color for plotting 57 | Choice: blue 58 | 59 | *** Fragment pairs belonging to MLCT *** 60 | Enter two indices between 1 and 4, separated by spaces 61 | Leave empty to finish 62 | 63 | Hole/electron indices for pair 1 64 | Choice: 1 2 65 | 66 | Hole/electron indices for pair 2 67 | Choice: 1 3 68 | 69 | Hole/electron indices for pair 3 70 | Choice: 1 4 71 | 72 | Hole/electron indices for pair 4 73 | Choice: 74 | 75 | ... switching to next component. 76 | 77 | .. figure:: figures/Om_bars.png 78 | -------------------------------------------------------------------------------- /doc/source/refs.bib: -------------------------------------------------------------------------------- 1 | @article{MAI2018, 2 | title = {Quantitative wave function analysis for excited states of transition metal complexes}, 3 | journal = {Coordination Chemistry Reviews}, 4 | volume = {361}, 5 | pages = {74-97}, 6 | year = {2018}, 7 | issn = {0010-8545}, 8 | author = {Sebastian Mai and Felix Plasser and Johann Dorn and Maria Fumanal and Chantal Daniel and Leticia González}, 9 | } 10 | 11 | @Article{Buckingham:67, 12 | Title = {Permanent and Induced Molecular Moments and Long-Range Intermolecular Forces}, 13 | Author = {A. D. Buckingham}, 14 | Journal = {Adv. Chem. Phys.}, 15 | Pages = {107-142}, 16 | Volume = {12}, 17 | Year = {1967}, 18 | Doi = {10.1002/9780470143582.ch2} 19 | } 20 | 21 | -------------------------------------------------------------------------------- /doc/source/transition_density_analysis.rst: -------------------------------------------------------------------------------- 1 | Transition density matrix analysis 2 | ---------------------------------- 3 | 4 | .. colt_commandline:: theodore run 5 | :subparsers: options(analyze_tden) 6 | :header: False 7 | 8 | main_order = usage, pos_args, opt_args, subparser_args, space 9 | alias = theodore 10 | 11 | [arg_format] 12 | name = 20 13 | comment = 60 14 | 15 | 16 | 17 | Analysis of the transition density matrix (1TDM) is invoked via ``theodore analyze_tden``. 18 | The main types of analysis that can be performed are charge transfer numbers, natural transition orbitals, and an exciton size analysis. 19 | 20 | **Note:** Traditionally, only spin-restricted computations are supported by TheoDORE and the treatment of unrestricted computations via the new script ``analyze_tden_unr`` (see below) is not well-tested yet. 21 | 22 | Charge transfer numbers 23 | ~~~~~~~~~~~~~~~~~~~~~~~ 24 | 25 | The charge transfer numbers are computed as partial summations over squared transition density matrix elements of molecular fragments. The key step for a charge transfer analysis is to [divde the molecule into meaningful fragments](Input). 26 | 27 | The actual charge transfer number analysis is a generalized population analysis. Currently, three formulas are implemented: ``Om_formula=0`` yields a Mulliken style analysis 28 | 29 | .. math:: 30 | 31 | \Omega_{AB}=\sum_{\mu\in A}\sum_{\nu\in B}\left(\mathbf{D}^{0I}\mathbf{S}\right)_{\mu\nu}\left(\mathbf{S}\mathbf{D}^{0I}\right)_{\mu\nu} 32 | 33 | ``Om_formula=1`` yields a somewhat different Mulliken style analysis 34 | 35 | .. math:: 36 | 37 | \Omega_{AB}=0.5\sum_{\mu\in A}\sum_{\nu\in B}\left(\mathbf{D}^{0I}\mathbf{S}\right)_{\mu\nu}\left(\mathbf{S}\mathbf{D}^{0I}\right)_{\mu\nu}+D^{0I}_{\mu\nu}\left(\mathbf{S}\mathbf{D}^{0I}\mathbf{S}\right)_{\mu\nu} 38 | 39 | ``Om_formula=2`` yields a Lowdin style analysis 40 | 41 | .. math:: 42 | 43 | \Omega_{AB}=\sum_{\mu\in A}\sum_{\nu\in B}\left(\mathbf{S}^{1/2}\mathbf{D}^{0I}\mathbf{S}^{1/2}\right)_{\mu\nu}{}^{2} 44 | 45 | The last case (``Om_formula=2``) is probably the best option in terms of, both, computational effort and numerical stability. 46 | 47 | Subsequently TheoDORE computes fragment based descriptors of the Omega-matrix. These are specified using the ``prop_list`` keyword, e.g. 48 | 49 | :: 50 | 51 | prop_list=['Om', 'POS', 'PR', 'CT', 'CTnt'] 52 | 53 | The complete list of available descriptors can be found [here](Transition density matrix analysis/attachment/Om_desc.pdf), see also the source file [Om_descriptors.py](https://sourceforge.net/p/theodore-qc/code/ci/master/tree/lib/Om_descriptors.py). 54 | 55 | Natural transition orbitals 56 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 57 | 58 | The natural transition orbitals (NTOs) are constructed through a singular value decomposition of the transition density matrx :math:`\mathbf{D}^{0I}` 59 | 60 | .. math:: 61 | 62 | \mathbf{D}^{0I}=\mathbf{U}diag(\lambda_1,\lambda_2,\ldots \mathbf{V}^T) 63 | 64 | 65 | The are written to either a Molden format file or a compact script, which can be executed in Jmol. In the case of the Molden file the following convention is adopted: NTO singular values are written into the Occ field of the Molden file where negative values denote hole orbitals and positive values electron orbitals. 66 | 67 | To count the number of NTO transitions involved, use the NTO participation ratio :math:`PR_{NTO}` 68 | 69 | .. math:: 70 | PR_{NTO}=\frac{\Omega}{\sum_i\lambda_i^2} 71 | 72 | or the entanglement measures defined in `J. Chem. Phys., 144, 194107 (2016) `_ 73 | 74 | .. math:: 75 | S_{H|E}=-\sum_i\lambda_i\log_2\lambda_i 76 | 77 | and 78 | 79 | .. math:: 80 | Z_{HE}=2^{S_{H|E}}, 81 | 82 | which are accessed by the following keywords: 83 | 84 | :: 85 | 86 | prop_list=['PRNTO', 'S_HE', 'Z_HE'] 87 | 88 | The *hole*/*particle* densities, which are analogous to the [attachment/detachment densities](State density matrix analysis), can be obtained as weighted sums over squared NTOs. 89 | This has to be :ref:`done externally `, e.g. in Molden. 90 | 91 | Conditional densities / domain NTOs 92 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 93 | An alternative to the charge transfer numbers and NTOs has been introduced in `ChemPhotoChem 3, 702, (2019) `_. 94 | To compute conditional densities or domain NTOs, specify in ``theoinp``: 95 | 96 | :: 97 | 98 | Perform analysis of domain NTOs and conditional densities? (comp_dntos): 99 | Choice (y/n): [n] y 100 | 101 | Using `ORBKIT `_, you can directly generate cube files of the conditional densities, see also :ref:`Orbitals and Densities `. 102 | Specify whether you want to compute the conditional densities for fixed hole (1), fixed electron (2) or both (3). 103 | 104 | :: 105 | 106 | Compute conditional densities as cube files? 107 | 0 - no, 1 - hole, 2 - electron, 3 - both (comp_dnto_dens): 108 | Choice: [0] 1 109 | 110 | Plotting in VMD using ``theodore vmd_plots``. 111 | 112 | Exciton size analysis 113 | ~~~~~~~~~~~~~~~~~~~~~ 114 | 115 | An approximate exciton size, `PCCP, 18, 2548 (2016) `_, (computed as the root-mean-square *electron-hole* separation, denoted ``RMSeh``) is constructed as 116 | 117 | .. math:: 118 | d_{exc}=\sqrt{\sum_{MN}\Omega_{MN}d_{MN}^2/\Omega} 119 | 120 | where M and N are two atom indices and dMN is the distance between them. The result is given in Angstrom. 121 | 122 | :: 123 | 124 | prop_list=['RMSeh'] 125 | 126 | Analysis of unrestricted computations 127 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 128 | 129 | Unrestricted computations are supported via the script `` theodore analyze_tden_unr``. This has only been tested with ORCA. For a well-tested support of unrestricted computations you have to resort to the implementations in Q-Chem and OpenMolcas. 130 | 131 | The tool ``analyze_tden_unr`` performs independent calculations for alpha and beta spin and writes the results to the subdirectories `ALPHA` and `BETA`. Natural transition orbitals can be written into these subdirectories as Molden files. Subsequently, the information is added up and collected in the main directory. 132 | 133 | Analysis of spin-orbit coupled states 134 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 135 | 136 | The analysis of spin-orbit coupled states, see `Coord. Chem. Rev., 361, 74 (2018) `_, is possible using ``theodore analyze_tden_soc``. 137 | Note, however, that this analysis is still in an experimental stage and is only possible for ADF. 138 | -------------------------------------------------------------------------------- /doc/source/usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ----- 3 | 4 | Below an autogenerated documentation of all of the functionality in TheoDORE is given. 5 | 6 | .. colt_commandline:: theodore run 7 | 8 | main_order = usage, args, space 9 | alias = theodore 10 | 11 | [arg_format] 12 | name = 20 13 | comment = 60 14 | 15 | [subparser_format] 16 | name = 25 17 | comment = 60 18 | 19 | .. colt_commandline:: theodore run 20 | :subparsers: options(*) 21 | :header: True 22 | 23 | main_order = comment, usage, args, space 24 | alias = theodore 25 | 26 | [arg_format] 27 | name = 20 28 | comment = 60 29 | 30 | [subparser_format] 31 | name = 25 32 | comment = 60 33 | -------------------------------------------------------------------------------- /make_distrib.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Create a new distribution version 3 | 4 | # TODO before: 5 | # - Check version number in theo_header.py and doc/source/conf.py 6 | # - doc/README up to date? 7 | # - git tag set by this script 8 | 9 | echo "Syntax: make_distrib.bash [Version]" 10 | echo 11 | 12 | if [ $# -eq 0 ] 13 | then 14 | echo "Please enter version number!" 15 | exit 1 16 | fi 17 | 18 | SDIR=`pwd` 19 | 20 | LTDIR="TheoDORE_$1" 21 | TDIR="$SDIR/../Versions/$LTDIR" 22 | echo "Creating new version in $TDIR" 23 | 24 | mkdir $TDIR || exit 2 25 | 26 | git tag -a v$1 27 | 28 | cp README.rst COPYRIGHT.txt LICENSE.txt $TDIR 29 | 30 | sed "s/GIT/$LTDIR/" setpaths.bash > $TDIR/setpaths.bash 31 | sed "s/GIT/$LTDIR/" setpaths.csh > $TDIR/setpaths.csh 32 | 33 | cp -r bin $TDIR 34 | mkdir $TDIR/EXAMPLES 35 | cp -r ../EXAMPLES/STANDARD $TDIR/EXAMPLES 36 | cp -r ../EXAMPLES/CCLIB $TDIR/EXAMPLES 37 | cp -r ../EXAMPLES/UTILS $TDIR/EXAMPLES 38 | cp -r ../EXAMPLES/EXTRA $TDIR/EXAMPLES 39 | rm -r $TDIR/EXAMPLES/*/*/RUN 40 | 41 | cp -r theodore $TDIR 42 | 43 | # cclib as used by TheoDORE 44 | cp -r external/cclib/cclib $TDIR 45 | cp external/cclib/LICENSE $TDIR/cclib 46 | 47 | # periodictable 48 | cp -r external/periodictable/periodictable $TDIR 49 | cp external/periodictable/LICENSE.txt $TDIR/periodictable 50 | 51 | # colt as used by TheoDORE 52 | cp -r external/colt/colt $TDIR 53 | cp external/colt/LICENSE $TDIR/colt 54 | 55 | echo "Removing binary pyc files" 56 | find $TDIR -name '*pyc' -exec rm {} \; 57 | 58 | # create tar with shorter relative paths 59 | cd $SDIR/../Versions 60 | tar -czf $LTDIR.tar.gz $LTDIR 61 | -------------------------------------------------------------------------------- /orbkit: -------------------------------------------------------------------------------- 1 | external/orbkit/orbkit/ -------------------------------------------------------------------------------- /periodictable: -------------------------------------------------------------------------------- 1 | external/periodictable/periodictable/ -------------------------------------------------------------------------------- /push_docs.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Udpate the documentation via the sourceforge server 3 | 4 | cd doc || exit 1 5 | 6 | # main html files 7 | rsync -auv html/ fffelix@web.sourceforge.net:/home/project-web/theodore-qc/htdocs 8 | 9 | # sphinx documentation 10 | ../bin/print_doc.py > source/keywords.rst || exit 1 11 | make html || exit 1 12 | rsync -auv build/html/ fffelix@web.sourceforge.net:/home/project-web/theodore-qc/htdocs/docs 13 | -------------------------------------------------------------------------------- /pyinstall.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # call this on vanadium 3 | 4 | cd pyinstall || exit 2 5 | 6 | for file in `ls ../bin/*.py` ../bin/theoinp 7 | do 8 | # pyinstaller -F $file 9 | pyinstaller --strip -F $file 10 | done 11 | 12 | # strip could make smaller files. But does this work? 13 | #cd dist 14 | #strip * 15 | -------------------------------------------------------------------------------- /setpaths.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # source this file to set the paths 3 | 4 | # Find the path of this script and set THEODIR automatically 5 | ABSPATH=`readlink -e ${BASH_SOURCE[@]}` 6 | export THEODIR=`dirname ${ABSPATH}` 7 | # If this does not work set it manually and modify the next line 8 | # export THEODIR=/user/plasserf/programs/TheoDORE/GIT 9 | 10 | echo "THEODIR set to $THEODIR" 11 | 12 | # set PATH and PYTHONPATH 13 | export PATH=$THEODIR/bin:$PATH 14 | export PYTHONPATH=$THEODIR 15 | 16 | # add external packages here if they have not been installed in the default locations 17 | #export PYTHONPATH=$HOME/programs/cclib/cclib-1.3.1/build/lib:$PYTHONPATH 18 | -------------------------------------------------------------------------------- /setpaths.csh: -------------------------------------------------------------------------------- 1 | #!/bin/csh 2 | # source this file to set the paths 3 | 4 | setenv THEODIR /home/felix/programs/TheoDORE/GIT 5 | setenv PATH ${THEODIR}/bin:${PATH} 6 | setenv PYTHONPATH ${THEODIR} 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """The setup script.""" 5 | 6 | from setuptools import setup, find_packages 7 | 8 | with open('README.rst') as readme_file: 9 | readme = readme_file.read() 10 | print(readme) 11 | 12 | requirements = ['pycolt>=0.5', 'cclib>=1.7', 'numpy>=1.17', 'orbkit>=1.0', 'matplotlib', 'openbabel'] 13 | 14 | setup_requirements = ['pytest-runner', ] 15 | 16 | test_requirements = ['pytest>=3', ] 17 | 18 | setup( 19 | author="Felix Plasser", 20 | python_requires='>=3.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5*', 21 | classifiers=[ 22 | 'Development Status :: Alpha', 23 | 'Intended Audience :: Developers', 24 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 25 | 'Natural Language :: English', 26 | 'Programming Language :: Python :: 3.6', 27 | 'Programming Language :: Python :: 3.7', 28 | 'Programming Language :: Python :: 3.8', 29 | 'Programming Language :: Python :: 3.9', 30 | ], 31 | description="Theoretical Density, Orbital Relaxation and Exciton analysis", 32 | install_requires=requirements, 33 | license="GNU General Public License 3.0", 34 | long_description=readme, 35 | include_package_data=True, 36 | keywords='theodore', 37 | name='theodore', 38 | packages=find_packages(include=['theodore', 'theodore.*']), 39 | entry_points = { 40 | 'console_scripts': ['theodore=theodore:run',] 41 | }, 42 | setup_requires=setup_requirements, 43 | tests_require=test_requirements, 44 | url='https://github.com/felixplasser/theodore-qc', 45 | version='3.0_alpha', 46 | zip_safe=False, 47 | ) 48 | -------------------------------------------------------------------------------- /theodore/OB_repl.py: -------------------------------------------------------------------------------- 1 | """ 2 | version 1.0.1 3 | author: Felix Plasser, University of Vienna, Institute for Theoretical Chemistry 4 | Waehringerstr. 17, 1090, Vienna, Austria 5 | usage: OB_repl is intended as a replacement that supplies some of the functionalities of the python-openbabel 6 | package in case this is not available. 7 | """ 8 | 9 | from __future__ import print_function, division 10 | 11 | import sys 12 | from . import units 13 | 14 | Z_mass_dict = {1:1.008,6:12.011,7:14.007,8:16.,15:30.97,16:32.066,17:35.453,77:192.22} 15 | Z_exact_mass_dict = {1:1.00782504,6:12.,7:14.00307401,8:15.99491464,17:34.96885273,77:192.962917} 16 | from .atominfo import symbol_Z_dict, Z_symbol_dict 17 | 18 | class OBConversion: 19 | """ 20 | Emulate the openbabel OBConversion class with support for a reduced number of file formats. 21 | """ 22 | def __init__(self): 23 | self.in_format = None 24 | self.out_format = None 25 | 26 | def SetInFormat(self,iformat): 27 | self.in_format = iformat 28 | 29 | return True 30 | 31 | def SetOutFormat(self,oformat): 32 | self.out_format = oformat 33 | 34 | return True 35 | 36 | def ReadFile(self,mol,file): 37 | """ 38 | Read information from a file into mol. 39 | """ 40 | if self.in_format == 'xyz': 41 | self.read_xyz(mol, file) 42 | elif self.in_format == 'tmol': 43 | self.read_tmol(mol, file) 44 | elif self.in_format == None: 45 | print("Input format for %s not set!"%file) 46 | sys.exit(14) 47 | else: 48 | print("File format %s not supported for input!"%self.in_format) 49 | print("Install python-openbabel for complete support.") 50 | sys.exit(15) 51 | 52 | return True 53 | 54 | def read_xyz(self,mol,file): 55 | """ 56 | Read file in xyz format (Angstrom). 57 | """ 58 | infile = open(file,'r') 59 | 60 | # the first two lines do not contain any coordinate information 61 | line = infile.readline() 62 | line = infile.readline() 63 | line = infile.readline() 64 | 65 | 66 | while(line!=''): 67 | words = line.split() 68 | obatom = OBAtom() 69 | obatom.SetAtomicNum(symbol_Z_dict[words[0]]) 70 | coords = [float(word) for word in words[1:4]] 71 | obatom.SetVector(*coords) 72 | 73 | mol.AddAtom(obatom) 74 | line = infile.readline() 75 | 76 | def read_tmol(self, mol, file): 77 | """ 78 | Read Turbomole format (Bohr) 79 | """ 80 | infile = open(file,'r') 81 | 82 | line = infile.readline() 83 | line = infile.readline() 84 | 85 | while(not '$' in line): 86 | words = line.split() 87 | obatom = OBAtom() 88 | obatom.SetAtomicNum(symbol_Z_dict[words[3][0].upper()+words[3][1:]]) 89 | coords = [float(word) * units.length['A'] for word in words[0:3]] 90 | obatom.SetVector(*coords) 91 | 92 | mol.AddAtom(obatom) 93 | line = infile.readline() 94 | 95 | def WriteFile(self,mol,file): 96 | """ 97 | Print structure to a file. 98 | """ 99 | if self.out_format == 'xyz': 100 | self.write_xyz(mol,file) 101 | elif self.out_format == 'tmol': 102 | self.write_tmol(mol,file) 103 | elif self.out_format == None: 104 | print("Output format for %s not set!"%file) 105 | sys.exit(14) 106 | else: 107 | print("File format %s not supported for output!"%self.out_format) 108 | print("Install python-openbabel for complete support.") 109 | sys.exit(15) 110 | 111 | def write_xyz(self,mol,file): 112 | outfile = open(file,'w') 113 | num_at = mol.NumAtoms() 114 | 115 | outfile.write('%i\n\n'%num_at) 116 | 117 | for ind in range(1, num_at+1): 118 | obatom = mol.GetAtom(ind) 119 | outstr = '%2s'%Z_symbol_dict[obatom.GetAtomicNum()] 120 | outstr += '% 14.10f'%(obatom.x()) 121 | outstr += '% 14.10f'%(obatom.y()) 122 | outstr += '% 14.10f'%(obatom.z()) 123 | outfile.write(outstr+'\n') 124 | 125 | outfile.close() 126 | 127 | def write_tmol(self,mol,file): 128 | outfile = open(file,'w') 129 | num_at = mol.NumAtoms() 130 | 131 | outfile.write('$coord\n') 132 | 133 | for ind in range(1, num_at+1): 134 | obatom = mol.GetAtom(ind) 135 | 136 | outstr = '% 14.8f'%(obatom.x() / units.length['A']) 137 | outstr += '% 14.8f'%(obatom.y() / units.length['A']) 138 | outstr += '% 14.8f'%(obatom.z() / units.length['A']) 139 | outstr += '%2s'%Z_symbol_dict[obatom.GetAtomicNum()] 140 | outfile.write(outstr+'\n') 141 | 142 | outfile.write('$end\n') 143 | outfile.close() 144 | 145 | class OBMol: 146 | def __init__(self): 147 | self.atoms = [] 148 | 149 | def AddAtom(self,Atom): 150 | self.atoms.append(Atom) 151 | 152 | def GetAtom(self,ind): 153 | """ 154 | Return an atom, indices start with 1. 155 | """ 156 | return self.atoms[ind-1] 157 | 158 | def NumAtoms(self): 159 | return len(self.atoms) 160 | 161 | class OBAtom: 162 | def __init__(self): 163 | self.AtomicNum = None 164 | self.Vector = [None,None,None] 165 | 166 | def SetAtomicNum(self,AtomicNum): 167 | self.AtomicNum = AtomicNum 168 | 169 | def GetAtomicNum(self): 170 | return self.AtomicNum 171 | 172 | def SetVector(self,*Vector): 173 | self.Vector=Vector 174 | 175 | def GetVector(self): 176 | return self.Vector 177 | 178 | def x(self): 179 | return self.Vector[0] 180 | 181 | def y(self): 182 | return self.Vector[1] 183 | 184 | def z(self): 185 | return self.Vector[2] 186 | 187 | def GetExactMass(self): 188 | return Z_exact_mass_dict[self.AtomicNum] 189 | 190 | class OBAtomAtomIter: 191 | def __init__(self, atom): 192 | print("\n Functionality not supported!") 193 | print("Install python-openbabel for complete support.") 194 | sys.exit(16) 195 | -------------------------------------------------------------------------------- /theodore/Om_descriptors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Computation and storage of Omega descriptors, which are derived from the charge 3 | transfer numbers. 4 | """ 5 | 6 | from __future__ import print_function, division 7 | 8 | import numpy 9 | 10 | class Om_desc_coll: 11 | """ 12 | Collection of Omega descriptors. 13 | """ 14 | def __init__(self, Om, OmFrag): 15 | self.descriptors = {} 16 | self.OmFrag = OmFrag 17 | self.OmNorm = OmFrag / Om 18 | self.numFrag = len(OmFrag) 19 | 20 | def ret_val_string(self, desc_list, oformat=' % 4.3f'): 21 | ret_str = '' 22 | 23 | for desc in desc_list: 24 | ret_str += oformat%self.ret_desc(desc) 25 | 26 | return ret_str 27 | 28 | def ret_desc(self, desc): 29 | """ 30 | Return the value of a descriptor. It is either taken from storage or computed. 31 | 32 | Return None if the descriptor is not available. 33 | """ 34 | if desc in self.descriptors: 35 | return self.descriptors[desc] 36 | else: 37 | return self.compute_desc(desc) 38 | 39 | def compute_desc(self, desc): 40 | """ 41 | Compute the value of descriptor desc. 42 | """ 43 | #print "Computing %s ..."%desc 44 | 45 | self.descriptors[desc] = 0. 46 | 47 | if desc == 'POSi': 48 | self.descriptors[desc] = \ 49 | sum( \ 50 | (A+1) * sum(self.OmNorm[A,B] for B in range(self.numFrag)) \ 51 | for A in range(self.numFrag)) 52 | 53 | elif desc == 'POSf': 54 | self.descriptors[desc] = \ 55 | sum( \ 56 | (B+1) * sum(self.OmNorm[A,B] for A in range(self.numFrag)) \ 57 | for B in range(self.numFrag)) 58 | 59 | elif desc == 'POS': 60 | self.descriptors[desc] = \ 61 | 0.5 * (self.ret_desc('POSi') + self.ret_desc('POSf')) 62 | 63 | elif desc == 'CT': 64 | for A in range(self.numFrag): 65 | for B in range(A+1, self.numFrag): 66 | self.descriptors[desc] += self.OmNorm[A, B] + self.OmNorm[B, A] 67 | 68 | elif desc == 'CT2': 69 | for A in range(self.numFrag): 70 | for B in range(A+2, self.numFrag): 71 | self.descriptors[desc] += self.OmNorm[A, B] + self.OmNorm[B, A] 72 | 73 | elif desc == 'CTnt': 74 | self.descriptors[desc] = \ 75 | self.ret_desc('POSf') - self.ret_desc('POSi') 76 | 77 | elif desc == 'PRi': 78 | self.descriptors[desc] = \ 79 | 1. / sum( \ 80 | sum (self.OmNorm[A,B] for B in range(self.numFrag))**2 \ 81 | for A in range(self.numFrag)) 82 | 83 | elif desc == 'PRf' or desc == 'EEDL': 84 | self.descriptors[desc] = \ 85 | 1. / sum( \ 86 | sum (self.OmNorm[A,B] for A in range(self.numFrag))**2 \ 87 | for B in range(self.numFrag)) 88 | 89 | elif desc == 'PR': 90 | self.descriptors[desc] = \ 91 | 0.5 * (self.ret_desc('PRi') + self.ret_desc('PRf')) 92 | 93 | elif desc == 'PRh': 94 | self.descriptors[desc] = \ 95 | 2. / (self.ret_desc('PRi')**-1. + self.ret_desc('PRf')**-1.) 96 | 97 | elif desc == 'DEL': 98 | self.descriptors[desc] = \ 99 | 1. / sum( \ 100 | sum ((self.OmNorm[A,B] + self.OmNorm[B,A])/2. for B in range(self.numFrag))**2 \ 101 | for A in range(self.numFrag)) 102 | 103 | elif desc == 'COH': 104 | self.descriptors[desc] = \ 105 | 1. / sum( \ 106 | sum(self.OmNorm[A,B]**2. for B in range(self.numFrag)) \ 107 | for A in range(self.numFrag)) / self.ret_desc('PR') 108 | 109 | elif desc == 'COHh': 110 | self.descriptors[desc] = \ 111 | 1. / sum( \ 112 | sum(self.OmNorm[A,B]**2. for B in range(self.numFrag)) \ 113 | for A in range(self.numFrag)) / self.ret_desc('PRh') 114 | 115 | elif desc in ['MC', 'LC', 'MLCT', 'LMCT', 'LLCT', 'SIEL']: 116 | self.compute_trans_met() 117 | 118 | else: 119 | return None 120 | #print "\n ERROR: descriptor %s not implemented!"%desc 121 | #exit(7) 122 | 123 | return self.descriptors[desc] 124 | 125 | def compute_trans_met(self): 126 | """ 127 | Routines specifically for transition metals. 128 | """ 129 | self.descriptors['MC'] = self.OmNorm[0, 0] 130 | 131 | self.descriptors['LC'] = 0. 132 | self.descriptors['MLCT'] = 0. 133 | self.descriptors['LMCT'] = 0. 134 | self.descriptors['LLCT'] = 0. 135 | for A in range(1, self.numFrag): 136 | self.descriptors['LC'] += self.OmNorm[A,A] 137 | self.descriptors['MLCT'] += self.OmNorm[0,A] 138 | self.descriptors['LMCT'] += self.OmNorm[A,0] 139 | for B in range(A+1, self.numFrag): 140 | self.descriptors['LLCT'] += self.OmNorm[A,B] + self.OmNorm[B,A] 141 | 142 | #hpop = numpy.sum(OmFrag, 1) 143 | if self.numFrag >= 3: 144 | epop = numpy.sum(self.OmFrag, 0) 145 | self.descriptors['SIEL'] = -epop[1] + 1./(self.numFrag-2.) * numpy.sum(epop[2:]) 146 | else: 147 | self.descriptors['SIEL'] = None 148 | -------------------------------------------------------------------------------- /theodore/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from . import error_handler 3 | 4 | if sys.version_info[0] != 3: 5 | estr = "python3 (ideally >= v3.7) required!\n" 6 | estr += " Found python version: %s"%sys.version 7 | raise error_handler.MsgError(estr) 8 | 9 | from .actions import run 10 | -------------------------------------------------------------------------------- /theodore/actions/__init__.py: -------------------------------------------------------------------------------- 1 | from .actions import ActionFactory 2 | from .theoinp import TheodoreInput 3 | from .analyze_tden import AnalyzeTden, AnalyzeTdenUnr, AnalyzeTdenEs2Es 4 | from .analyze_tden_soc import AnalyzeTdenSoc 5 | from .analyze_sden import AnalyzeSden 6 | from .analyze_NOs import AnalyzeNOs 7 | from .parse_libwfa import ParseLibwfa 8 | from .plot_vist import PlotVist 9 | from .plot_OmFrag import PlotOmFrag 10 | from .plot_Om_bars import PlotOmBars 11 | from .plot_frag_decomp import PlotFragDecomp 12 | from .plot_graph import PlotGraph 13 | from .plot_graph_nx import PlotGraphNx 14 | from .jmol_MOs import JMolMOs 15 | from .jmol_vibs import JMolVibs 16 | from .vmd_plots import VMDPlots 17 | from .draw_moments import DrawMoments 18 | from .babel import Babel 19 | from .cc_opt import CCOpt 20 | from .cc_check import CCCheck 21 | from .extract_molden import ExtractMolden 22 | from .spectrum import Spectrum 23 | from .tden_OV import TDenOv 24 | from .convert_table import ConvertTable 25 | from .dgrid_prep import DGridPrep 26 | from .fcd import FCD 27 | 28 | 29 | from .. import theo_header 30 | 31 | 32 | settings = { 33 | 'description': theo_header.ret_header(), 34 | 'logo': None, 35 | 'error_order': ['logo', 'description', 'args', 'usage', 'space', 'comment', 'space', 'error'], 36 | 'arg_format': { 37 | 'name': 20, 38 | 'comment': 50, 39 | 'seperator': ' | ', 40 | }, 41 | 'subparser_args': { 42 | 'title': 'Actions: %s', 43 | }, 44 | 'subparser_format': { 45 | 'name': 20, 46 | 'comment': 50, 47 | }, 48 | } 49 | 50 | run = ActionFactory.from_commandline(description=settings, as_parser=True) 51 | -------------------------------------------------------------------------------- /theodore/actions/actions.py: -------------------------------------------------------------------------------- 1 | from colt import Plugin 2 | 3 | 4 | class ActionFactory(Plugin): 5 | _is_plugin_factory = True 6 | _plugins_storage = '_actions' 7 | 8 | _user_input = """ 9 | options = :: str 10 | """ 11 | 12 | @classmethod 13 | def _extend_user_input(cls, questions): 14 | questions.generate_cases("options", {action.name: action.colt_user_input 15 | for action in cls.plugins.values()}) 16 | @classmethod 17 | def from_config(cls, config): 18 | config = config['options'] 19 | for action in cls.plugins.values(): 20 | if action.name == config.value: 21 | return action.from_config(config) 22 | raise Exception(f"Action '{config[config.value]}' unknown") 23 | 24 | 25 | class Action(ActionFactory): 26 | 27 | _register_plugin = False 28 | 29 | @classmethod 30 | def from_config(cls, config): 31 | if not isinstance(cls.run, staticmethod): 32 | cls.run = staticmethod(cls.run) 33 | return cls.run(**config) 34 | 35 | def run(**options): 36 | raise NotImplementedError 37 | -------------------------------------------------------------------------------- /theodore/actions/analyze_NOs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Driver script for analyzing a set of NO files. 3 | """ 4 | 5 | from __future__ import print_function, division 6 | import sys 7 | 8 | from .actions import Action 9 | from colt.lazyimport import LazyImportCreator, LazyImporter 10 | 11 | 12 | with LazyImportCreator() as importer: 13 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 14 | lib_sden = importer.lazy_import_as('..lib_sden', 'lib_sden') 15 | input_options = importer.lazy_import_as('..input_options', 'input_options') 16 | 17 | class AnalyzeNOs(Action): 18 | 19 | name = 'analyze_nos' 20 | 21 | _colt_description = 'Analysis of natural orbital (NO) files' 22 | 23 | _user_input = """ 24 | # List of NO files in Molden format 25 | no_files = :: list(existing_file) 26 | # Input file (optional) 27 | ifile = dens_ana.in :: file, alias=f 28 | # Reference MO file for computing AO overlap matrix 29 | ref = :: existing_file, optional, alias=r 30 | # Multiply occupations with this factor 31 | occ_fac = :: float, optional, alias=o 32 | # Use if unrestricted orbitals are present 33 | unrestricted = false :: bool, alias=u 34 | # Interpret energies as occupations 35 | rd_ene = false :: bool, alias=e 36 | """ 37 | 38 | _lazy_imports = LazyImporter({ 39 | '..theo_header': 'theo_header', 40 | '..lib_sden': 'lib_sden', 41 | '..input_options': 'input_options' 42 | }) 43 | 44 | def run(no_files, ifile, ref, occ_fac, unrestricted, rd_ene): 45 | theo_header.print_header(__class__._colt_description, cfile=__file__) 46 | 47 | # set options 48 | ioptions = input_options.sden_ana_options(ifile, check_init=False) 49 | ioptions['rtype'] = 'nos' 50 | if not occ_fac is None: 51 | ioptions['occ_fac'] = occ_fac 52 | ioptions['unrestricted'] = unrestricted 53 | ioptions['rd_ene'] = rd_ene 54 | 55 | # optionally use a manually specified MO file for computing the AO overlap matrix 56 | if ref is None: 57 | ioptions['mo_file'] = no_files[0] 58 | else: 59 | ioptions['mo_file'] = ref 60 | ioptions['ana_files'] = no_files 61 | 62 | #--------------------------------------------------------------------------# 63 | # Parsing and computations 64 | #--------------------------------------------------------------------------# 65 | 66 | sdena = lib_sden.sden_ana(ioptions) 67 | if unrestricted: 68 | sdena.read_mos(spin=1) 69 | else: 70 | sdena.read_mos() 71 | sdena.read_dens() 72 | 73 | if unrestricted: 74 | sdena.compute_all_NO() 75 | if ioptions['AD_ana']: 76 | sdena.compute_all_AD() 77 | if ioptions['pop_ana']: 78 | sdena.print_all_pop_table() 79 | if ioptions['BO_ana']: 80 | sdena.compute_all_BO() 81 | sdena.print_all_BO() 82 | 83 | sdena.print_summary() 84 | -------------------------------------------------------------------------------- /theodore/actions/analyze_sden.py: -------------------------------------------------------------------------------- 1 | from .actions import Action 2 | from .theotools import timeit 3 | from colt.lazyimport import LazyImportCreator, LazyImporter 4 | 5 | 6 | with LazyImportCreator() as importer: 7 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 8 | lib_sden = importer.lazy_import_as('..lib_sden', 'lib_sden') 9 | lib_exciton = importer.lazy_import_as('..lib_exciton', 'lib_exciton') 10 | input_options = importer.lazy_import_as('..input_options', 'input_options') 11 | 12 | 13 | class AnalyzeSden(Action): 14 | 15 | name = 'analyze_sden' 16 | 17 | _colt_description = 'State density matrix analysis' 18 | 19 | _user_input = """ 20 | # Main input file 21 | ifile = dens_ana.in :: existing_file, alias=f 22 | # Print all keywords and their current values 23 | keywords = false :: bool, alias=k 24 | """ 25 | 26 | _lazy_imports = LazyImporter({ 27 | '..theo_header': 'theo_header', 28 | '..lib_sden': 'lib_sden', 29 | '..lib_exciton': 'lib_exciton', 30 | '..input_options': 'input_options' 31 | }) 32 | 33 | @timeit 34 | def run(ifile, keywords): 35 | # header 36 | theo_header.print_header(__class__._colt_description, cfile=__name__) 37 | # 38 | ioptions = input_options.sden_ana_options(ifile) 39 | if keywords: 40 | print(ioptions.doc_info()) 41 | exit(0) 42 | 43 | #--------------------------------------------------------------------------# 44 | # Parsing and computations 45 | #--------------------------------------------------------------------------# 46 | 47 | sdena = lib_sden.sden_ana(ioptions) 48 | if 'mo_file' in ioptions: sdena.read_mos() 49 | sdena.read_dens() 50 | 51 | if ioptions['NO_ana']: sdena.compute_all_NO() 52 | if ioptions['AD_ana']: sdena.compute_all_AD() 53 | if ioptions['BO_ana']: sdena.compute_all_BO() 54 | 55 | if ioptions['comp_rho']: sdena.compute_rho() 56 | 57 | #--------------------------------------------------------------------------# 58 | # Print out 59 | #--------------------------------------------------------------------------# 60 | if ioptions['pop_ana']: sdena.print_all_pop_table() 61 | if ioptions['BO_ana']: sdena.print_all_BO() 62 | if ioptions['mo_pop_type'] > 0: sdena.print_mo_pops(ioptions['mo_pop_type']) 63 | 64 | sdena.print_summary() 65 | -------------------------------------------------------------------------------- /theodore/actions/analyze_tden_soc.py: -------------------------------------------------------------------------------- 1 | """ 2 | Driver script for transition density matrix analysis. 3 | """ 4 | from __future__ import print_function, division 5 | import os, sys, time 6 | 7 | from .actions import Action 8 | from .theotools import timeit 9 | 10 | from colt.lazyimport import LazyImportCreator, LazyImporter 11 | 12 | 13 | with LazyImportCreator() as importer: 14 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 15 | lib_soc = importer.lazy_import_as('..lib_soc', 'lib_soc') 16 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 17 | input_options = importer.lazy_import_as('..input_options', 'input_options') 18 | 19 | 20 | #--------------------------------------------------------------------------# 21 | # Parsing and computations 22 | #--------------------------------------------------------------------------# 23 | 24 | class AnalyzeTdenSoc(Action): 25 | name = 'analyze_tden_soc' 26 | 27 | _colt_description = '1TDM analysis for spin-orbit coupled states' 28 | 29 | _user_input = """ 30 | ifile = dens_ana.in :: existing_file, alias=f 31 | spin_comp = False :: bool, alias=s 32 | """ 33 | 34 | _lazy_imports = LazyImporter({ 35 | '..theo_header': 'theo_header', 36 | '..lib_soc': 'lib_soc', 37 | '..error_handler': 'error_handler', 38 | '..input_options': 'input_options', 39 | }) 40 | 41 | @timeit 42 | def run(ifile, spin_comp): 43 | ioptions = input_options.tden_ana_options(ifile) 44 | theo_header.print_header(__class__._colt_description, ioptions=ioptions, cfile=__file__) 45 | 46 | tdena = lib_soc.tden_ana_soc(ioptions) 47 | if 'mo_file' in ioptions: tdena.read_mos() 48 | tdena.read_dens() 49 | tdena.compute_all_OmAt(fullmat=True) 50 | tdena.soc_transform() 51 | 52 | tdena.print_info('mch') 53 | if spin_comp is True: 54 | tdena.print_info('aa') 55 | tdena.print_info('bb') 56 | tdena.print_info('ab') 57 | tdena.print_info('ba') 58 | tdena.print_info('soc') 59 | -------------------------------------------------------------------------------- /theodore/actions/babel.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division 2 | import sys 3 | 4 | from .actions import Action 5 | from colt.lazyimport import LazyImportCreator, LazyImporter 6 | 7 | 8 | with LazyImportCreator() as importer: 9 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 10 | lib_struc = importer.lazy_import_as('..lib_struc', 'lib_struc') 11 | 12 | 13 | class Babel(Action): 14 | 15 | name = 'babel' 16 | 17 | _colt_description = 'Openbabel wrapper - conversion of coordinate files' 18 | 19 | _user_input = """ 20 | # Input molecular structure file 21 | infile = :: existing_file 22 | # Output molecular structure file 23 | outfile = :: file 24 | # File type for input file 25 | intype = :: str, optional, alias=i 26 | # File type for output file 27 | outtype = :: str, optional, alias=o 28 | """ 29 | 30 | _lazy_imports = LazyImporter({ 31 | '..theo_header': 'theo_header', 32 | '..lib_struc': 'lib_struc', 33 | }) 34 | 35 | def run(infile, intype, outtype, outfile): 36 | theo_header.print_header(__class__._colt_description) 37 | 38 | if intype in lib_struc.veloc_types: # special treatment of velocities 39 | veloc = struc_linalg.veloc() 40 | veloc.read_file(file_path=infile, file_type=intype) 41 | veloc.write_veloc(file_path=outfile,file_type=outtype) 42 | else: 43 | struc = lib_struc.structure() 44 | struc.read_file(file_path=infile, file_type=intype) 45 | struc.make_coord_file(file_path=outfile,file_type=outtype) 46 | 47 | print("Finished: file %s written."%outfile) 48 | -------------------------------------------------------------------------------- /theodore/actions/cc2molden.py: -------------------------------------------------------------------------------- 1 | """ 2 | Convert a log-file to Molden format with the help of cclib. 3 | """ 4 | from __future__ import print_function, division 5 | import sys 6 | 7 | from .actions import Action 8 | from colt.lazyimport import LazyImportCreator, LazyImporter 9 | 10 | 11 | with LazyImportCreator() as importer: 12 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 13 | cclib_interface = importer.lazy_import_as('..cclib_interface', 'cclib_interface') 14 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 15 | lib_mo = importer.lazy_import_as('..lib_mo', 'lib_mo') 16 | input_options = importer.lazy_import_as('..input_options', 'input_options') 17 | 18 | 19 | class CC2Molden(Action): 20 | 21 | name = 'cc2molden' 22 | 23 | _user_input = """ 24 | logfile = :: existing_file 25 | """ 26 | _colt_description = "Convert a log-file to Molden format with the help of cclib." 27 | 28 | _lazy_imports = LazyImporter({ 29 | '..theo_header': 'theo_header', 30 | '..cclib_interface': 'cclib_interface', 31 | '..error_handler': 'error_handler', 32 | '..input_options': 'input_options', 33 | '..lib_mo': 'lib_mo', 34 | }) 35 | 36 | def run(logfile): 37 | theo_header.print_header(__class__._colt_description) 38 | print(" WARNING: This script is not well-tested and might fail for some of the quantum chemistry codes.") 39 | 40 | ioptions = input_options.dens_ana_options(ifile=None, check_init=False) 41 | ioptions['rtype'] = 'cclib' 42 | ioptions['rfile'] = logfile 43 | 44 | ccparser = cclib_interface.file_parser_cclib(ioptions) 45 | 46 | errcode = ccparser.check() 47 | if errcode == 0: 48 | mos = ccparser.read_mos() 49 | mos.write_molden_file(fname="cc.mld") 50 | print("\n Finished: molden format file cc.mld written.") 51 | else: 52 | print(" Conversion to Molden format not possible!") 53 | print(" %s does not contain all required information"%logfile) 54 | -------------------------------------------------------------------------------- /theodore/actions/cc_check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Check if a file can be read by cclib and if all the required information is available. 4 | """ 5 | from __future__ import print_function, division 6 | import sys 7 | 8 | from .actions import Action 9 | from colt.lazyimport import LazyImportCreator, LazyImporter 10 | 11 | 12 | with LazyImportCreator() as importer: 13 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 14 | cclib_interface = importer.lazy_import_as('..cclib_interface', 'cclib_interface') 15 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 16 | input_options = importer.lazy_import_as('..input_options', 'input_options') 17 | 18 | class CCCheck(Action): 19 | 20 | name = 'cc_check' 21 | 22 | _user_input = """ 23 | logfile = :: existing_file 24 | printlevel = 1 :: int, alias=p 25 | """ 26 | _colt_description = "Check if a logfile can be parsed with cclib" 27 | 28 | _lazy_imports = LazyImporter({ 29 | '..theo_header': 'theo_header', 30 | '..cclib_interface': 'cclib_interface', 31 | '..error_handler': 'error_handler', 32 | '..input_options': 'input_options' 33 | }) 34 | 35 | def run(logfile, printlevel): 36 | theo_header.print_header(__class__._colt_description) 37 | 38 | 39 | ioptions = input_options.dens_ana_options(ifile=None, check_init=False) 40 | ioptions['rtype'] = 'cclib' 41 | ioptions['rfile'] = logfile 42 | 43 | ccparser = cclib_interface.file_parser_cclib(ioptions) 44 | errcode = ccparser.check(lvprt=printlevel) 45 | 46 | if errcode <= 1: 47 | print(("\n %s can be parsed by using rtype='cclib' in dens_ana.in."%logfile)) 48 | if errcode == 0: 49 | print(" Conversion to Molden format also possible") 50 | else: 51 | print(" But conversion to Molden format is not possible") 52 | else: 53 | print(("\n %s cannot be parsed by cclib (errcode=%i)!"%(logfile, errcode))) 54 | -------------------------------------------------------------------------------- /theodore/actions/cc_opt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Use cclib and openbabel to analyze a geometry optimization. 4 | """ 5 | 6 | from __future__ import print_function, division 7 | import sys 8 | 9 | from .actions import Action 10 | from colt.lazyimport import LazyImportCreator, LazyImporter 11 | 12 | 13 | with LazyImportCreator() as importer: 14 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 15 | cclib_interface = importer.lazy_import_as('..cclib_interface', 'cclib_interface') 16 | input_options = importer.lazy_import_as('..input_options', 'input_options') 17 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 18 | units = importer.lazy_import_as('..units', 'units') 19 | 20 | 21 | 22 | 23 | class CCOpt(Action): 24 | 25 | _colt_description = 'Analysis of geom. opt. or relaxed scan' 26 | 27 | _user_input = """ 28 | # Logfile of quant. chemistry program 29 | logfile = :: existing_file 30 | # Analyse a relaxed scan 31 | scan = false :: bool, alias=s 32 | # Threshold for energy change (for scan) 33 | thresh = 500 :: float, alias=t 34 | # Name of output xyz file 35 | output = cc_opt.xyz :: file, alias=o 36 | """ 37 | 38 | name = 'cc_opt' 39 | 40 | _lazy_imports = LazyImporter({ 41 | '..theo_header': 'theo_header', 42 | '..cclib_interface': 'cclib_interface', 43 | '..error_handler': 'error_handler', 44 | '..input_options': 'input_options', 45 | '..units': 'units', 46 | }) 47 | 48 | def run(logfile, scan, thresh, output): 49 | import openbabel 50 | 51 | theo_header.print_header(__class__._colt_description) 52 | 53 | fname = output 54 | 55 | ioptions = input_options.dens_ana_options(ifile=None, check_init=False) 56 | ioptions['rtype'] = 'cclib' 57 | ioptions['rfile'] = logfile 58 | 59 | ccparser = cclib_interface.file_parser_cclib(ioptions) 60 | 61 | obconversion = openbabel.OBConversion() 62 | obconversion.SetOutFormat('xyz') 63 | struc = cclib_interface.structure_cclib() 64 | f = open(fname, 'w') 65 | 66 | try: 67 | scfens = ccparser.data.scfenergies 68 | except AttributeError: 69 | print(' WARNING: No SCF energies found. Quitting ...') 70 | sys.exit() 71 | 72 | try: 73 | etens = ccparser.data.etenergies 74 | et = True 75 | print(' +++ Found excitation energies +++') 76 | except AttributeError: 77 | etens = [] 78 | et = False 79 | 80 | print('\n%21s'%'SCF energies (a.u.)', end=' ') 81 | if et: print('%15s'%'Exc. (a.u.)') 82 | else: print() 83 | 84 | ngeo = 0 85 | for i,scfen in enumerate(scfens): 86 | en_au = scfen/units.energy['eV'] 87 | print('%5i:% 15.7f'%(i,en_au), end=' ') 88 | if et: 89 | try: 90 | en_au += etens[i]/units.energy['rcm'] 91 | print('% 15.7f'%(en_au)) 92 | except IndexError: 93 | print() 94 | else: 95 | print() 96 | 97 | # For a potential scan: find the discontinuity when one cylce is converged 98 | if scan: 99 | try: 100 | dE1 = scfen - scfens[i-1] 101 | except IndexError: 102 | dE1 = 1. 103 | try: 104 | dE2 = scfens[i+1] - scfen 105 | except IndexError: 106 | dE2 = 1. 107 | 108 | if abs(dE2) > thresh * abs(dE1): 109 | print(' -> Geometry written to %s (% .4f / % .4f / % .1f)'%(f.name, dE1, dE2, dE2/dE1)) 110 | else: 111 | print(' -> Geometry skipped') 112 | continue 113 | 114 | try: 115 | struc.read_cclib(ccparser.data, ind=i,lvprt=0) 116 | except IndexError: 117 | pass 118 | else: 119 | lines = obconversion.WriteString(struc.mol).split('\n') 120 | f.write('%i\n'%ccparser.data.natom) 121 | f.write('Energy = % .7f\n'%(en_au)) 122 | for line in lines[2:-1]: 123 | f.write(line + '\n') 124 | ngeo += 1 125 | 126 | f.close() 127 | print("\n*** Done *** \n%i geometries written to %s"%(ngeo, f.name)) 128 | if scan: 129 | print(" ... lower threshold (-t) to get more geometries.") 130 | 131 | try: 132 | optdone = ccparser.data.optdone 133 | except AttributeError: 134 | optdone = False 135 | if optdone: 136 | print("\n *** Geometry optimization converged ***") 137 | -------------------------------------------------------------------------------- /theodore/actions/convert_table.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Convert the TheoDORE output data to a table in latex or html format. 4 | """ 5 | 6 | from __future__ import print_function, division 7 | from .actions import Action 8 | from colt.lazyimport import LazyImportCreator, LazyImporter 9 | 10 | 11 | with LazyImportCreator() as importer: 12 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 13 | input_options = importer.lazy_import_as('..input_options', 'input_options') 14 | lib_file = importer.lazy_import_as('..lib_file', 'lib_file') 15 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 16 | 17 | 18 | 19 | class write_table_options(input_options.write_options): 20 | def table_input(self): 21 | print("Convert the output from a TheoDORE run into a latex or html table.\n") 22 | 23 | self.read_str("Name of the file to analyze", "ana_file", "tden_summ.txt") 24 | 25 | rstr = self.ret_str("Properties of interest (separated by spaces).\n Leave empty to print all") 26 | if rstr == '': 27 | self['prop_list'] = [] 28 | else: 29 | self.write_list('prop_list', rstr.split(), lformat="'%s'") 30 | 31 | self.choose_list('Output format', 'output_format', 32 | [ ('latex', 'LaTeX source file'), 33 | ('html', 'HTML format') 34 | ], 'latex') 35 | 36 | if self['output_format'] == 'latex': 37 | self.write_option('fname', "table.tex") 38 | self.read_yn('Write state labels as LaTeX formulas', 'lformula', False) 39 | elif self['output_format'] == 'html': 40 | self.write_option('fname', "table.html") 41 | self['lformula'] = False 42 | 43 | digs = self.ret_int('Number of decimal digits', 2) 44 | fformat = '%.' + str(digs) + 'f' 45 | self.write_option('fformat', fformat) 46 | 47 | def write_table(self): 48 | sfile = lib_file.summ_file(self['ana_file']) 49 | header = sfile.ret_header() 50 | ddict = sfile.ret_ddict() 51 | state_labels = sfile.ret_state_labels() 52 | 53 | if self['prop_list'] == []: 54 | self['prop_list'] = header[1:] 55 | 56 | if self['output_format'] == 'html': 57 | wfile = lib_file.htmlfile 58 | wtable = lib_file.htmltable 59 | elif self['output_format'] == 'latex': 60 | wfile = lib_file.latexfile 61 | wtable = lib_file.latextable 62 | else: 63 | raise error_handler.ElseError(self['output_format'], 'output_format') 64 | 65 | wf = wfile(self['fname']) 66 | wf.pre(title='TheoDORE data') 67 | 68 | wt = wtable(ncol = len(self['prop_list']) + 1) 69 | wt.add_row(['State'] + self['prop_list']) 70 | 71 | for state in state_labels: 72 | if not self['lformula']: 73 | wt.add_el(state) 74 | else: 75 | wt.add_el('$%s$'%(state.replace('(', '^').replace(')', ''))) 76 | 77 | for prop in self['prop_list']: 78 | try: 79 | wt.add_el(self['fformat']%ddict[state][prop]) 80 | except KeyError: 81 | wt.add_el('-') 82 | 83 | wf.write(wt.ret_table()) 84 | wf.post(lvprt=1) 85 | 86 | class read_table_options(input_options.read_options): 87 | def set_defaults(self): 88 | self['ana_file'] = 'tden_summ.txt' 89 | self['output_format'] = 'latex' 90 | self['lformula'] = False 91 | self['prop_list'] = [] 92 | self['fname'] = None 93 | self['fformat'] = '%.2f' 94 | 95 | 96 | class ConvertTable(Action): 97 | 98 | name = 'convert_table' 99 | 100 | _colt_description = 'Convert the output to latex/html table' 101 | 102 | _lazy_imports = LazyImporter({ 103 | '..theo_header': 'theo_header', 104 | '..input_options': 'input_options', 105 | '..lib_file': 'lib_file', 106 | '..error_handler': 'error_handler', 107 | }) 108 | 109 | def run(): 110 | theo_header.print_header(title=__class__._colt_description) 111 | infilen = 'table.in' 112 | 113 | topt = write_table_options(infilen) 114 | ropt = read_table_options(infilen, False) 115 | 116 | if ropt.init == 0: 117 | copy = topt.ret_yn('Found %s. Use this file directly rather than performing an interactive input?'%infilen, True) 118 | else: 119 | copy = False 120 | 121 | if copy: 122 | topt.copy(ropt) 123 | else: 124 | topt.table_input() 125 | 126 | topt.write_table() 127 | 128 | if not copy: 129 | topt.flush() 130 | -------------------------------------------------------------------------------- /theodore/actions/dgrid_prep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function, division 4 | import sys 5 | 6 | from .actions import Action 7 | from colt.lazyimport import LazyImportCreator, LazyImporter 8 | 9 | 10 | with LazyImportCreator() as importer: 11 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 12 | input_options = importer.lazy_import_as('..input_options', 'input_options') 13 | 14 | 15 | class dgrid_options(input_options.write_options): 16 | def input(self): 17 | self.read_float('Mesh size (a.u.)', 'msize', 0.2) 18 | self.read_float('Mesh border (a.u.)', 'mborder', 4.0) 19 | self.read_int('Number of parallel processes', 'nproc', 1) 20 | 21 | 22 | class DGridPrep(Action): 23 | 24 | name = 'dgrid_prep' 25 | 26 | _colt_description = 'Prepare input for DGrid' 27 | 28 | _user_input = """ 29 | # Molden files 30 | mldfiles = :: list(existing_file) 31 | """ 32 | 33 | _lazy_imports = LazyImporter({ 34 | '..theo_header': 'theo_header', 35 | '..input_options': 'input_options' 36 | }) 37 | 38 | def run(mldfiles): 39 | 40 | theo_header.print_header(title=__class__._colt_description) 41 | print("Using the Molden files:", mldfiles) 42 | 43 | dopt = dgrid_options('dgrid.in') 44 | dopt.input() 45 | 46 | wfile = open('run_dgrid.bash', 'w') 47 | wfile.write('#!/bin/bash\n') 48 | wfile.write('\n###\nDGRID=dgrid\n###\n\n') 49 | 50 | iproc = 0 51 | for mldfile in mldfiles: 52 | # adjust the names to be compatible with dgrid 53 | rind = mldfile.rfind('.') 54 | basen = mldfile if rind < 0 else mldfile[:rind] 55 | basen2 = basen.split('/')[-1] 56 | bfilen = basen + '.md' 57 | ifilen = basen + '.inp' 58 | 59 | print('\nAnalyzing %s -> %s ...'%(mldfile, bfilen)) 60 | 61 | iproc += 1 62 | if iproc%dopt['nproc'] == 0: 63 | lend = '|| exit 1' 64 | else: 65 | lend = '&' 66 | 67 | wfile.write('echo " *** Running %s ..."\n'%mldfile) 68 | wfile.write('$DGRID %s && $DGRID %s %s\n'%(mldfile, ifilen, lend)) 69 | wfile.write('ln -s %s.md.rho_r %s.cube\n\n'%(basen, basen2)) 70 | 71 | with open(ifilen, 'w') as ifile: 72 | ifile.write(f""":: dgrid_prep.py 73 | basis={bfilen} 74 | output=. 75 | 76 | compute=rho 77 | format=cube 78 | mesh={dopt['msize']:.4f} {dopt['mborder']:.2f}\n""") 79 | 80 | wfile.close() 81 | print("File run_dgrid.bash written.\n Run as:\n bash run_dgrid.bash") 82 | -------------------------------------------------------------------------------- /theodore/actions/extract_molden.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function, division 4 | import os, sys 5 | import numpy 6 | 7 | from .actions import Action 8 | from colt.lazyimport import LazyImportCreator, LazyImporter 9 | 10 | 11 | with LazyImportCreator() as importer: 12 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 13 | lib_mo = importer.lazy_import_as('..lib_mo', 'lib_mo') 14 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 15 | 16 | 17 | class extract_mld: 18 | def __init__(self, thresh=0.001, rd_ene=False, decompose=True): 19 | self.thresh = thresh # threshold for print-out into output file 20 | self.rd_ene = rd_ene # interpret energies as occupations 21 | self.decompose = decompose # decompose (for NDOs or NTOs) 22 | 23 | self.stdir = os.getcwd() 24 | 25 | def extract(self, mo_file): 26 | print("Extracting %s ..."%mo_file) 27 | os.chdir(self.stdir) 28 | 29 | mos = lib_mo.MO_set_molden(file=mo_file) 30 | mos.read() 31 | 32 | 33 | if self.decompose: 34 | orb_dir = "%s.dir"%mo_file 35 | try: 36 | os.chdir(orb_dir) 37 | except: 38 | os.makedirs(orb_dir) 39 | os.chdir(orb_dir) 40 | 41 | self.ex_hp(mos, 1.) 42 | self.ex_hp(mos, -1.) 43 | else: 44 | self.alphabeta(mos) 45 | 46 | def ex_hp(self, mos, sign=1.): 47 | """ 48 | Extract hole or particle component 49 | """ 50 | suffix = {-1.:'hole', 51 | 1.:'elec'}[sign] 52 | outfile = "%s_%s.mld"%(mos.file, suffix) 53 | 54 | # extract only the ones with the required sign 55 | mat_list = [] 56 | 57 | ens = [] 58 | occs = [] 59 | #syms = [] 60 | 61 | if self.rd_ene: 62 | tmp_occs = mos.ens 63 | else: 64 | tmp_occs = mos.occs 65 | 66 | Ct_orig = mos.mo_mat.transpose() 67 | for i, occ in enumerate(tmp_occs): 68 | #print occ, occ*sign, self.thresh, occ*sign > self.thresh 69 | if occ * sign > self.thresh: 70 | mat_list.append(Ct_orig[i]) 71 | ens.append(mos.ens[i]) 72 | occs.append(occ * sign) 73 | 74 | Ct = numpy.array(mat_list) 75 | 76 | mos.export_AO(ens, occs, Ct, fname=outfile, occmin=self.thresh) 77 | print(" ... %s written, containing %i orbitals."%(outfile, len(ens))) 78 | 79 | def alphabeta(self, mos): 80 | """ 81 | Use alpha/beta labels for hole/electron 82 | """ 83 | outfile = "%s_ab.mld"%(mos.file) 84 | 85 | # extract only the ones above thresh 86 | mat_list = [] 87 | 88 | ens = [] 89 | occs = [] 90 | 91 | if self.rd_ene: 92 | tmp_occs = mos.ens 93 | else: 94 | tmp_occs = mos.occs 95 | 96 | Ct_orig = mos.mo_mat.transpose() 97 | for i, occ in enumerate(tmp_occs): 98 | if abs(occ) > self.thresh: 99 | mat_list.append(Ct_orig[i]) 100 | ens.append(mos.ens[i]) 101 | occs.append(occ) 102 | 103 | Ct = numpy.array(mat_list) 104 | 105 | mos.export_AO(ens, occs, Ct, fname=outfile, occmin=self.thresh, alphabeta=True) 106 | print(" ... %s written, containing %i orbitals."%(outfile, len(ens))) 107 | 108 | 109 | class ExtractMolden(Action): 110 | 111 | _user_input = """ 112 | # List of MO files to analyse 113 | mo_files = :: list(existing_file) 114 | # Interpret energies as occupations 115 | ene = False :: bool, alias=e 116 | # Threshold for print-out 117 | thresh = 0.001 :: float, alias=t 118 | # Use alpha/beta labels for hole/electron 119 | alphabeta = False :: bool, alias=ab 120 | """ 121 | 122 | name = 'extract_molden' 123 | 124 | _colt_description = 'Extract hole/particle parts from Molden file' 125 | 126 | _lazy_imports = LazyImporter({ 127 | '..theo_header': 'theo_header', 128 | '..error_handler': 'error_handler', 129 | '..lib_mo': 'lib_mo', 130 | }) 131 | 132 | def run(mo_files, ene, thresh, alphabeta): 133 | theo_header.print_header(title=__class__._colt_description) 134 | 135 | extr = extract_mld(thresh=thresh, rd_ene=ene, decompose=not alphabeta) 136 | mo_files = [] 137 | 138 | for mo_file in mo_files: 139 | extr.extract(mo_file) 140 | -------------------------------------------------------------------------------- /theodore/actions/fcd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Perform a fragment charge difference analysis, following 4 | A. A. Voityuk, N. Roesch J. Chem. Phys. 2002, 117, 5607. 5 | """ 6 | 7 | from __future__ import print_function, division 8 | 9 | from .actions import Action 10 | from colt.lazyimport import LazyImportCreator, LazyImporter 11 | 12 | 13 | with LazyImportCreator() as importer: 14 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 15 | input_options = importer.lazy_import_as('..input_options', 'input_options') 16 | lib_diab = importer.lazy_import_as('..lib_diab', 'lib_diab') 17 | 18 | class FCD(Action): 19 | 20 | name = 'fcd' 21 | 22 | _colt_description = 'Fragment charge difference analysis' 23 | 24 | _user_input = """ 25 | # name of the input file 26 | ifile = fcd.in :: existing_file, alias=f 27 | """ 28 | 29 | _lazy_imports = LazyImporter({ 30 | '..theo_header': 'theo_header', 31 | '..input_options': 'input_options', 32 | '..lib_diab': 'lib_diab', 33 | }) 34 | 35 | def run(ifile): 36 | theo_header.print_header(title=__class__._colt_description) 37 | 38 | ifile = 'fcd.in' 39 | 40 | ioptions = input_options.fcd_ana_options(ifile) 41 | 42 | fcda = lib_diab.fcd_ana(ioptions) 43 | fcda.read_mos() 44 | fcda.read_dens() 45 | 46 | fcda.do_pop_ana() 47 | fcda.do_fcd() 48 | -------------------------------------------------------------------------------- /theodore/actions/jmol_vibs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Automatic plotting of vibrations with jmol. 4 | """ 5 | # Code adapted from jmol_MOs.py 6 | 7 | from __future__ import print_function, division 8 | 9 | from .actions import Action 10 | from colt.lazyimport import LazyImportCreator, LazyImporter 11 | 12 | 13 | with LazyImportCreator() as importer: 14 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 15 | lib_file = importer.lazy_import_as('..lib_file', 'lib_file') 16 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 17 | input_options = importer.lazy_import_as('..input_options', 'input_options') 18 | 19 | 20 | class jmol_vib_opts(input_options.write_options): 21 | def input(self): 22 | self.read_int('Index of first vibration to be plotted', 'st_ind', 7) 23 | self.read_int('Index of last vibration to be plotted', 'en_ind', 20) 24 | self.read_int('Width of vibration vectors', 'vwidth', 5) 25 | self.read_int('Scale of vibration vectors', 'vscale', 5) 26 | 27 | self.read_yn('Use "rotate best" command (only available in Jmol 14)', 'rot_best', True) 28 | self.read_yn('Additional custom rotation of the molecule?', 'rot_custom') 29 | if self['rot_custom']: 30 | self.read_float('Rotation around the x-axis', 'rot_x', 0.) 31 | self.read_float('Rotation around the y-axis', 'rot_y', 0.) 32 | self.read_float('Rotation around the z-axis', 'rot_z', 0.) 33 | self.read_str('Format of the output files (png, pngt, ...)', 'oformat', 'png') 34 | self.read_int('Width of images in output html file', 'width', 400) 35 | self.read_yn('Run Jmol?', 'run_jmol', False) 36 | 37 | class vib_output: 38 | """ 39 | Abstract base class for vib output. 40 | """ 41 | def __init__(self, vibc, jopt): 42 | self.vibc = vibc 43 | self.jopt = jopt 44 | self.outstr = '' 45 | 46 | def output(self, ofileh): 47 | self.pre() 48 | self.print_vibs() 49 | self.post(ofileh) 50 | 51 | def vibpath(self, ivib, of='png'): 52 | if of == 'pngt': of = 'png' 53 | return "vib_%i.%s"%(ivib,of) 54 | 55 | def pre(self): 56 | raise error_handler.PureVirtualError() 57 | 58 | def print_vibs(self): 59 | raise error_handler.PureVirtualError() 60 | 61 | def post(self, ofileh): 62 | ofileh.write(self.outstr) 63 | 64 | class vib_output_jmol(vib_output): 65 | """ 66 | Vib output in standard jmol format. 67 | """ 68 | def pre(self): 69 | self.outstr += '\nload "' + self.vibc.mldfile + '" FILTER "nosort"\n' 70 | if self.jopt['rot_best']: 71 | self.outstr += "rotate best\n" 72 | if self.jopt['rot_custom']: 73 | self.outstr += "rotate x %.3f\n"%self.jopt['rot_x'] 74 | self.outstr += "rotate y %.3f\n"%self.jopt['rot_y'] 75 | self.outstr += "rotate z %.3f\n"%self.jopt['rot_z'] 76 | self.outstr += "background white\n" + "vector on\n" 77 | self.outstr += "vector %i\n"%self.jopt['vwidth'] 78 | self.outstr += "vector scale %.2f\n"%self.jopt['vscale'] 79 | 80 | def print_vibs(self): 81 | for ivib in self.vibc.viblist: 82 | self.outstr += "model %i\n"%(ivib+1) 83 | self.outstr += "write image %s \"%s\"\n"%(self.jopt['oformat'], self.vibc.vibpath(ivib, self.jopt['oformat'])) 84 | 85 | class vib_output_html(vib_output): 86 | """ 87 | HTML file for visualizing vibrations created with jmol. 88 | """ 89 | def pre(self): 90 | self.htable = lib_file.htmltable(ncol=3) 91 | 92 | def print_vibs(self): 93 | for ivib in self.vibc.viblist: 94 | el = ''%(self.vibc.vibpath(ivib, self.jopt['oformat']), self.jopt['width']) 95 | el += '
Mode %i'%(ivib) 96 | self.htable.add_el(el) 97 | 98 | def post(self, ofileh): 99 | ofileh.write("

Vibrations - %s

\n"%self.vibc.mldfile) 100 | self.htable.close_table() 101 | ofileh.write(self.htable.ret_table()) 102 | 103 | class vibcoll: 104 | """ 105 | Output of molecular vibrations. 106 | """ 107 | def __init__(self, st_ind, en_ind, mldfile): 108 | self.mldfile = mldfile 109 | self.viblist = list(range(st_ind, en_ind+1)) 110 | 111 | def vibname(self, ivib): 112 | return str(ivib) 113 | 114 | def vibpath(self, ivib, of='png'): 115 | if of == 'pngt': of = 'png' 116 | return "vib_%i.%s"%(ivib,of) 117 | 118 | 119 | class JMolVibs(Action): 120 | 121 | name = 'jmol_vibs' 122 | 123 | _colt_description = 'Plotting of vibrations in Jmol' 124 | 125 | _user_input = """ 126 | # Molden file with info about vibrations 127 | vibfile = :: existing_file 128 | """ 129 | 130 | _lazy_imports = LazyImporter({ 131 | '..error_handler': 'error_handler', 132 | '..lib_file': 'lib_file', 133 | '..theo_header': 'theo_header', 134 | '..input_options': 'input_options', 135 | }) 136 | 137 | def run(vibfile): 138 | 139 | theo_header.print_header(__class__._colt_description) 140 | 141 | jopt = jmol_vib_opts('jmol.in') 142 | jopt.input() 143 | 144 | jo = lib_file.wfile('jmol_vibs.spt') 145 | ho = lib_file.htmlfile('vibs.html') 146 | 147 | ho.pre('Vibrations') 148 | 149 | vibc = vibcoll(jopt['st_ind'], jopt['en_ind'], vibfile) 150 | 151 | vibout = vib_output_jmol(vibc, jopt) 152 | vibout.output(jo) 153 | 154 | vibh = vib_output_html(vibc, jopt) 155 | vibh.output(ho) 156 | 157 | ho.post(lvprt=1) 158 | jo.post(lvprt=1) 159 | if jopt['run_jmol']: 160 | import subprocess 161 | print("Running jmol ...") 162 | 163 | subprocess.call(["jmol", "-n", jo.name]) 164 | else: 165 | print(" -> Now simply run \"jmol -n %s\" to plot all the orbitals.\n"%jo) 166 | -------------------------------------------------------------------------------- /theodore/actions/parse_libwfa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Script for parsing libwfa output. 4 | """ 5 | from __future__ import print_function, division 6 | import sys 7 | 8 | from .actions import Action 9 | from colt.lazyimport import LazyImportCreator, LazyImporter 10 | 11 | 12 | with LazyImportCreator() as importer: 13 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 14 | dens_ana_base = importer.lazy_import_as('..dens_ana_base', 'dens_ana_base') 15 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 16 | input_options = importer.lazy_import_as('..input_options', 'input_options') 17 | 18 | class ParseLibwfa(Action): 19 | 20 | name = 'parse_libwfa' 21 | 22 | _colt_description = 'Parse libwfa output from Q-Chem or OpenMolcas' 23 | 24 | _user_input = """ 25 | # Logfile from Q-Chem or OpenMolcas 26 | logfile = :: existing_file 27 | # Type of calculation (qcadc, qctddft, qctda, rassi) 28 | typ = :: str :: qcadc, qctddft, qctda, rassi 29 | # Input file 30 | ifile = :: file, optional, alias=f 31 | """ 32 | 33 | _lazy_imports = LazyImporter({ 34 | '..theo_header': 'theo_header', 35 | '..dens_ana_base': 'dens_ana_base', 36 | '..error_handler': 'error_handler', 37 | '..input_options': 'input_options', 38 | }) 39 | 40 | def run(logfile, typ, ifile): 41 | #--------------------------------------------------------------------------# 42 | # Input options 43 | #--------------------------------------------------------------------------# 44 | 45 | ioptions = input_options.libwfa_parse_options(ifile, check_init=False) 46 | 47 | ioptions['rfile'] = logfile 48 | if typ is not None: 49 | ioptions['rtype'] = typ 50 | 51 | if ioptions['rtype'] == 'qctda': 52 | ioptions['TDA'] = True 53 | ioptions['rtype'] = 'qctddft' 54 | 55 | theo_header.print_header(__class__._colt_description, ioptions=ioptions) 56 | 57 | #--------------------------------------------------------------------------# 58 | # Parsing and computations 59 | #--------------------------------------------------------------------------# 60 | 61 | dena = dens_ana_base.dens_ana_base(ioptions) 62 | #sdena.read_mos() 63 | 64 | dena.read_dens() 65 | 66 | dena.print_summary() 67 | -------------------------------------------------------------------------------- /theodore/actions/plot_frag_decomp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Script for plotting fragment decomposition. 4 | """ 5 | 6 | from __future__ import print_function, division 7 | from .actions import Action 8 | import numpy 9 | from colt.lazyimport import LazyImportCreator, LazyImporter 10 | 11 | 12 | with LazyImportCreator() as importer: 13 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 14 | input_options = importer.lazy_import_as('..input_options', 'input_options') 15 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 16 | matplotlib = importer.lazy_import('matplotlib') 17 | pylab = importer.lazy_import('pylab') 18 | 19 | 20 | 21 | class decomp_options(input_options.write_options): 22 | """ 23 | Set and store the options for plotting. 24 | """ 25 | def __init__(self, *args, **kwargs): 26 | self.state_list = [] 27 | self.numF = 0 # number of fragments 28 | 29 | input_options.write_options.__init__(self, *args, **kwargs) 30 | self['colors'] = ['b', 'g', 'orange', 'red', 'gray'] 31 | 32 | ## \param fname file with the data produced in a previous analyze_tden.py run 33 | def read_OmFrag(self, fname='OmFrag.txt'): 34 | """ 35 | Read the OmFrag.txt file written by analyze_tden.py 36 | """ 37 | Ofile = open(fname, 'r') 38 | line = next(Ofile) 39 | 40 | self.numF = int(line) 41 | 42 | while True: 43 | try: 44 | line = next(Ofile) 45 | except StopIteration: 46 | break 47 | 48 | words = line.split() 49 | 50 | self.state_list.append({}) 51 | state = self.state_list[-1] 52 | state['name'] = words[0] 53 | state['Om'] = words[1] 54 | state['OmFrag'] = numpy.zeros([self.numF, self.numF], float) 55 | 56 | for iel, el in enumerate(words[2:]): 57 | iF = iel % self.numF 58 | jF = iel // self.numF 59 | state['OmFrag'][iF, jF] = el # max(float(el), 0.) 60 | 61 | def decomp_input(self): 62 | 63 | self.read_float('Relative width of the bars', 'barwidth', 0.75) 64 | self.read_int('Resolution (dpi) for plotting', 'plot_dpi', 200) 65 | self.read_int('Font size', 'fsize', 8) 66 | self.read_str("Format of output graphics files", "output_format", "png", autocomp=False) 67 | self.labels = [] 68 | for iF in range(self.numF): 69 | self.labels.append(self.ret_str("Label for fragment %i"%(iF+1), 'F%i'%(iF+1))) 70 | 71 | def plot(self): 72 | matplotlib.rc('font', size=self['fsize']) 73 | 74 | hpops = numpy.zeros([len(self.state_list),self.numF]) 75 | epops = numpy.zeros([len(self.state_list),self.numF]) 76 | ind = numpy.arange(len(self.state_list)) 77 | 78 | for istate, state in enumerate(self.state_list): 79 | hpops[istate, :] = -numpy.sum(state['OmFrag'], 0) 80 | epops[istate, :] = numpy.sum(state['OmFrag'], 1) 81 | 82 | pylab.figure(figsize=[len(self.state_list)+1, 5]) 83 | 84 | barkwargs = {'width':self['barwidth']} 85 | 86 | ebottom = numpy.zeros(len(self.state_list)) 87 | hbottom = numpy.zeros(len(self.state_list)) 88 | for iF in range(self.numF): 89 | pylab.bar(ind, epops[:, iF], bottom=ebottom, color=self['colors'][iF], label=self.labels[iF], **barkwargs) 90 | ebottom += epops[:, iF] 91 | 92 | pylab.bar(ind, hpops[:, iF], bottom=hbottom, color=self['colors'][iF], **barkwargs) 93 | hbottom += hpops[:, iF] 94 | 95 | pylab.xlabel('Excited states') 96 | pylab.ylabel(' Hole <---> Electron') 97 | pylab.plot([ind[0]-0.5, ind[-1]+0.5+self['barwidth']], [0.,0.], 'k-') 98 | 99 | pylab.legend() 100 | pylab.xticks(ind, [state['name'] for state in self.state_list], rotation='vertical') 101 | 102 | pylab.subplots_adjust(bottom=0.2, left=0.2) 103 | 104 | fname = 'frag_decomp.%s'%self['output_format'] 105 | pylab.savefig(fname, dpi=self['plot_dpi']) 106 | print(("File %s written."%fname)) 107 | 108 | 109 | class PlotFragDecomp(Action): 110 | name = 'plot_frag_decomp' 111 | 112 | _colt_description = 'Plot fragment decomposition of Omega matrix' 113 | 114 | _lazy_imports = LazyImporter({ 115 | '..theo_header': 'theo_header', 116 | '..input_options': 'input_options', 117 | '..error_handler': 'error_handler', 118 | 'matplotlib': 'matplotlib', 119 | 'pylab': 'pylab', 120 | }) 121 | 122 | def run(): 123 | matplotlib.use('Agg') 124 | theo_header.print_header(__class__._colt_description) 125 | opt = decomp_options('plot.in') 126 | opt.read_OmFrag() 127 | 128 | opt.decomp_input() 129 | 130 | opt.plot() 131 | -------------------------------------------------------------------------------- /theodore/actions/plot_graph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Script for creating graphs from multiple directories, e.g. potential curves. 4 | """ 5 | 6 | from __future__ import print_function, division 7 | 8 | from .actions import Action 9 | from colt.lazyimport import LazyImportCreator, LazyImporter 10 | 11 | 12 | with LazyImportCreator() as importer: 13 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 14 | lib_plot = importer.lazy_import_as('..lib_plot', 'lib_plot') 15 | 16 | 17 | class PlotGraph(Action): 18 | 19 | name = 'plot_graph' 20 | 21 | _colt_description = 'Graph plotting for potential curves etc.' 22 | 23 | _user_input = """ 24 | # List of directories to analyze 25 | dlist = :: list(str), optional, alias=f 26 | 27 | """ 28 | _lazy_imports = LazyImporter({ 29 | '..theo_header': 'theo_header', 30 | '..lib_plot': 'lib_plot', 31 | }) 32 | 33 | def run(dlist): 34 | theo_header.print_header(title=__class__._colt_description) 35 | infilen = 'graph.in' 36 | 37 | popt = lib_plot.write_plot_options(infilen) 38 | ropt = lib_plot.read_plot_options(infilen, False) 39 | 40 | if ropt.init == 0: 41 | copy = popt.ret_yn('Found %s. Use this file directly rather than performing an interactive input?'%infilen, True) 42 | else: 43 | copy = False 44 | 45 | if copy: 46 | popt.copy(ropt) 47 | else: 48 | popt.plot_input(dlist) 49 | popt.flush() 50 | 51 | popt.read_data() 52 | 53 | if popt['doplots']: popt.plot() 54 | if popt['dotxt']: popt.txt_files() 55 | if popt['dognu']: popt.gnu_inp() 56 | -------------------------------------------------------------------------------- /theodore/actions/plot_graph_nx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Script for creating graphs from multiple directories, e.g. potential curves. 4 | """ 5 | 6 | from __future__ import print_function, division 7 | from .actions import Action 8 | from colt.lazyimport import LazyImportCreator, LazyImporter 9 | 10 | 11 | with LazyImportCreator() as importer: 12 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 13 | input_options = importer.lazy_import_as('..input_options', 'input_options') 14 | lib_plot = importer.lazy_import_as('..lib_plot', 'lib_plot') 15 | lib_file = importer.lazy_import_as('..lib_file', 'lib_file') 16 | 17 | 18 | class write_plot_options_nx(lib_plot.write_plot_options): 19 | def plot_input(self): 20 | self['ana_dirs']=[] 21 | self['ana_file']='nx.log' 22 | self['state_labels']=None 23 | self['dognu'] = False 24 | 25 | self.read_int('Number of states to plot', 'nstate', 10) 26 | self.read_float('Minimum time', 'tmin', 0.) 27 | self.read_float('Maximum time', 'tmax', 10000.) 28 | 29 | self.read_yn('Create plots using pylab?', 'doplots', True) 30 | if self['doplots']: 31 | self.read_int('Font size', 'fsize', 15) 32 | self.read_str("Format of output graphics files", "output_format", "png") 33 | 34 | self.read_yn('Print txt files with the information', 'dotxt', True) 35 | 36 | def read_data(self): 37 | self.data = [] 38 | self.main_header = '' 39 | self.data_avail = [] 40 | self.times = [] 41 | self.act = [] 42 | 43 | f = open(self['ana_file']) 44 | while True: 45 | try: 46 | line = next(f) 47 | except StopIteration: 48 | break 49 | 50 | if 'state dE(eV)' in line: 51 | ddict = {} 52 | state_labels = [] 53 | 54 | header = line.split() 55 | 56 | line = next(f) # ------ 57 | line = next(f) 58 | 59 | for istate in range(self['nstate']): 60 | if 'Finished' in line: break 61 | 62 | words = line.split() 63 | state_label = words[0] 64 | ddict[state_label] = {} 65 | pdict = ddict[state_label] 66 | state_labels.append(state_label) 67 | 68 | for i, prop in enumerate(header[1:]): 69 | try: 70 | pdict[prop] = float(words[i+1]) 71 | except ValueError: 72 | pass 73 | pdict['ddE'] = pdict['dE(eV)'] - ddict[state_labels[0]]['dE(eV)'] 74 | line = next(f) 75 | 76 | if 'FINISHING STEP' in line: 77 | words = line.split() 78 | time = float(words[4]) 79 | 80 | if self['tmax'] <= time: 81 | break 82 | elif self['tmin'] <= time: 83 | self['ana_dirs'].append(time) 84 | self.times.append(time) 85 | act = int(words[-1]) - 2 86 | ddict['act'] = ddict[state_labels[act]] 87 | self.data.append(ddict) 88 | 89 | f.close() 90 | 91 | self.main_header = header + ['ddE'] 92 | self['state_labels'] = state_labels + ['act'] 93 | self['leg_labels'] = state_labels + ['act'] 94 | 95 | 96 | def plot(self): 97 | """ 98 | Create the plots. 99 | For this purpose, self.data has to be rearranged. 100 | """ 101 | try: 102 | import matplotlib 103 | matplotlib.use('Agg') 104 | import pylab 105 | except: 106 | print("pylab/matplotlib not installed - plotting not possible") 107 | print("exiting ...") 108 | return 109 | 110 | hfname = 'graphs.html' 111 | hfile = lib_file.htmlfile(hfname) 112 | hfile.pre('Property graphs') 113 | htable = lib_file.htmltable(ncol=3) 114 | 115 | lfname = 'graphs.tex' 116 | lfile = lib_file.latexfile(lfname) 117 | lfile.pre('Property graphs', graphicx=True) 118 | ltable = lib_file.latextable(ncol=2) 119 | 120 | #set1 = self.data[0][self['state_labels'][0]] # not used anywhere?? 121 | 122 | matplotlib.rc('font', size=self['fsize']) 123 | 124 | for key in self.main_header[1:]: 125 | if key == 'fname': continue 126 | 127 | print('Plotting %s ...'%key) 128 | pylab.figure(figsize=(max(12,len(self.times)/100),6)) 129 | 130 | for state in self['state_labels']: 131 | if state == 'act': 132 | symb = 'ro' 133 | else: 134 | symb = '-' 135 | 136 | ylist = [] 137 | for iana_dir in range(len(self['ana_dirs'])): 138 | try: 139 | ylist.append(self.data[iana_dir][state][key]) 140 | except KeyError: 141 | print(" ... not able to plot %s for %s."%(key, state)) 142 | break 143 | else: 144 | pylab.plot(self.times, ylist, symb) 145 | 146 | pylab.title(key) 147 | pylab.ylabel(key) 148 | pylab.xlabel('time (fs)') 149 | 150 | pname = '%s.%s'%(key, self['output_format']) 151 | pylab.savefig(pname) 152 | 153 | tel = ''%(pname, max(len(self.times)/2, 400)) 154 | htable.add_el(tel) 155 | 156 | lel = "\\incplot{%s}"%pname 157 | ltable.add_el(lel) 158 | 159 | hfile.write(htable.ret_table()) 160 | hfile.post(lvprt=1) 161 | 162 | lfile.write(ltable.ret_table()) 163 | lfile.post(lvprt=1) 164 | 165 | 166 | class PlotGraphNx(Action): 167 | 168 | name = 'plot_graph_nx' 169 | 170 | _colt_description = 'Graph plotting (Newton-X)' 171 | 172 | _lazy_imports = LazyImporter({ 173 | '..theo_header': 'theo_header', 174 | '..input_options': 'input_options', 175 | '..lib_plot': 'lib_plot', 176 | '..lib_file': 'lib_file', 177 | }) 178 | 179 | 180 | def run(): 181 | theo_header.print_header(title=__class__._colt_description) 182 | infilen = 'graph.in' 183 | 184 | popt = write_plot_options_nx(infilen) 185 | 186 | popt.plot_input() 187 | popt.read_data() 188 | 189 | if popt['doplots']: popt.plot() 190 | if popt['dotxt']: popt.txt_files() 191 | if popt['dognu']: popt.gnu_inp() 192 | -------------------------------------------------------------------------------- /theodore/actions/plot_vist.py: -------------------------------------------------------------------------------- 1 | from .actions import Action 2 | from .theotools import timeit 3 | from colt.lazyimport import LazyImportCreator, LazyImporter 4 | 5 | 6 | with LazyImportCreator() as importer: 7 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 8 | lib_NICS = importer.lazy_import_as('..lib_NICS', 'lib_NICS') 9 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 10 | cclib_interface = importer.lazy_import_as('..cclib_interface', 'cclib_interface') 11 | input_options = importer.lazy_import_as('..input_options', 'input_options') 12 | 13 | 14 | class PlotVist(Action): 15 | 16 | name = 'plot_vist' 17 | 18 | _user_input = """ 19 | 20 | # VIST for only these dummy atoms, e.g. -v '0 3 5' 21 | vist = :: ilist, optional, alias=v 22 | # Name of output file (for VMD) 23 | ofile = VIST.vmd :: str, alias=o 24 | # Scale factor for VIST dumb-bells 25 | scale = 1.0 :: float, alias=s 26 | # Create coordinate files (using cclib) 27 | coor = false :: bool, alias=c 28 | # Render and plot all tensors separately 29 | plot_all = false :: bool, alias=p 30 | # Add labels for eigenvalues above this value (in ppm), e.g. -l 10 31 | lab_min = 1000. :: float, alias=l 32 | # Log files to be parsed 33 | logfiles = :: list(str) 34 | # Quantum chemistry code (g09, qchem, turbomole) 35 | qccode = g09 :: str, alias=q 36 | """ 37 | 38 | _colt_description = "Read NICS values and prepare VIST plot" 39 | 40 | _lazy_imports = LazyImporter({ 41 | '..theo_header': 'theo_header', 42 | '..lib_NICS': 'lib_NICS', 43 | '..error_handler': 'error_handler', 44 | '..cclib_interface': 'cclib_interface', 45 | '..input_options': 'input_options', 46 | }) 47 | 48 | @timeit 49 | def run(vist, ofile, scale, coor, plot_all, lab_min, logfiles, qccode): 50 | if vist is not None and len(vist) == 0: 51 | vist = None 52 | theo_header.print_header('Read NICS values and prepare VIST plot', cfile='plot_VIST.py') 53 | 54 | with open(ofile, 'w') as fh: 55 | pass 56 | 57 | ioptions = input_options.dens_ana_options(ifile=None, check_init=False) 58 | ioptions['rtype'] = 'cclib' 59 | 60 | if qccode == 'g09': 61 | nv = lib_NICS.NICS_parser_g09() 62 | elif qccode == 'qchem': 63 | nv = lib_NICS.NICS_parser_QC() 64 | elif qccode == 'turbomole': 65 | nv = lib_NICS.NICS_parser_TM() 66 | else: 67 | raise error_handler.ElseError(qccode, 'qccode') 68 | 69 | for ilog, logfile in enumerate(logfiles): 70 | nv.read(logfile) 71 | nv.print_data() 72 | if coor: # create coor file to be read by VMD 73 | ioptions['rfile'] = logfile 74 | ccparser = cclib_interface.file_parser_cclib(ioptions) 75 | struc = cclib_interface.structure_cclib() 76 | struc.read_cclib(ccparser.data) 77 | coorf = "coor%i.xyz"%ilog 78 | struc.make_coord_file(file_path=coorf,file_type='Bqxyz') 79 | open(ofile, 'a').write("mol new %s\n"%coorf) 80 | nv.vmd_tensors(ofile, vist, scale, plot_all, lab_min) 81 | 82 | # Instructions for VMD 83 | if coor: 84 | print(""" 85 | Input file for VMD and coordinate file(s) created. Now run: 86 | vmd -e %s 87 | """%ofile) 88 | else: 89 | print(""" 90 | Input file for VMD created. Now do the following: 91 | 1. Open VMD and load coordinate file 92 | 2. File - Load Visualization State - %s 93 | """%ofile) 94 | -------------------------------------------------------------------------------- /theodore/actions/tden_OV.py: -------------------------------------------------------------------------------- 1 | """ 2 | Compute the overlap between transition density matrices. 3 | """ 4 | 5 | from __future__ import print_function, division 6 | from .actions import Action 7 | import numpy 8 | import os 9 | from colt.lazyimport import LazyImportCreator, LazyImporter 10 | 11 | 12 | with LazyImportCreator() as importer: 13 | theo_header = importer.lazy_import_as('..theo_header', 'theo_header') 14 | lib_tden = importer.lazy_import_as('..lib_tden', 'lib_tden') 15 | input_options = importer.lazy_import_as('..input_options', 'input_options') 16 | error_handler = importer.lazy_import_as('..error_handler', 'error_handler') 17 | 18 | 19 | class TDenOv(Action): 20 | 21 | name = 'tden_ov' 22 | 23 | _colt_description = 'Transition density matrix overlap' 24 | 25 | _user_input = """ 26 | dir1 = :: existing_folder 27 | dir2 = :: existing_folder 28 | ao_ov = :: existing_file, optional 29 | # name of the input file 30 | ifile = tden_OV.in :: existing_file, alias=f 31 | # name of input file for the second computation 32 | ifile2 = :: existing_file, optional, alias=f2 33 | """ 34 | 35 | _lazy_imports = LazyImporter({ 36 | '..theo_header': 'theo_header', 37 | '..lib_tden': 'lib_tden', 38 | '..error_handler': 'error_handler', 39 | '..input_options': 'input_options', 40 | }) 41 | 42 | def run(dir1, dir2, ao_ov, ifile, ifile2): 43 | ifile = 'tden_OV.in' 44 | ifile2 = '' 45 | 46 | ioptions = input_options.tden_ana_options(ifile) 47 | theo_header.print_header(title=__class__._colt_description, ioptions=ioptions) 48 | 49 | if ifile2 is None: 50 | ioptions2 = ioptions 51 | else: 52 | ioptions2 = input_options.tden_ana_options(ifile2) 53 | 54 | sdir = os.getcwd() 55 | 56 | # Read info for the first job 57 | os.chdir(dir1) 58 | tdena1 = lib_tden.tden_ana(ioptions) 59 | if 'mo_file' in ioptions: 60 | tdena1.read_mos() 61 | tdena1.read_dens() 62 | os.chdir(sdir) 63 | 64 | # Read info for the second job 65 | os.chdir(dir2) 66 | tdena2 = lib_tden.tden_ana(ioptions2) 67 | if 'mo_file' in ioptions2: 68 | tdena2.read_mos() 69 | tdena2.read_dens() 70 | os.chdir(sdir) 71 | 72 | if AO_OV == None: 73 | print("Constructing AO-overlap matrix from MO-coefficients") 74 | tdena1.mos.compute_inverse() 75 | SMO = numpy.dot(tdena1.mos.inv_mo_mat, tdena2.mos.mo_mat) 76 | if ioptions['lvprt'] >= 2: 77 | SAO = numpy.dot(tdena1.mos.inv_mo_mat.T, tdena1.mos.inv_mo_mat) 78 | else: 79 | SAO = numpy.array([[float(s) for s in line.split()] for line in open(AO_OV, 'r').readlines()[1:]]) 80 | 81 | CS = numpy.dot(tdena1.mos.mo_mat.T, SAO) 82 | SMO = numpy.dot(CS, tdena2.mos.mo_mat) 83 | 84 | if ioptions['lvprt'] >= 2: 85 | print("AO-overlap matrix:", SAO.shape) 86 | print(SAO) 87 | print() 88 | 89 | print("MO-overlap matrix:", SMO.shape) 90 | print(SMO) 91 | print() 92 | 93 | print(" ", end=' ') 94 | for state2 in tdena2.state_list: 95 | print(" |%7s>"%state2['name'], end=' ') 96 | print() 97 | 98 | for state1 in tdena1.state_list: 99 | print("<%7s|"%state1['name'], end=' ') 100 | tden1 = state1['tden'] 101 | DS1 = numpy.dot(tden1, SMO) 102 | #print DS1.shape 103 | mdim = tden1.shape[0] 104 | SDS1 = numpy.dot(SMO[:mdim,:mdim], DS1) 105 | #print SDS1.shape 106 | for state2 in tdena2.state_list: 107 | #if (not 'mult' in state1 or not 'mult' in state2) or (state1['mult'] == state2['mult']): 108 | tden2 = state2['tden'] 109 | #print tden2.shape 110 | OV = sum((SDS1 * tden2).flatten()) 111 | print(" % .8f"%OV, end=' ') 112 | #else: 113 | #print " % .1f "%0., 114 | print() 115 | -------------------------------------------------------------------------------- /theodore/actions/theotools.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | # Python 2/3 compatibility 4 | try: 5 | from time import process_time 6 | except ImportError: 7 | from time import clock as process_time # clock is depricated and will be removed in 3.8 8 | try: 9 | from time import perf_counter 10 | except ImportError: 11 | from time import time as perf_counter 12 | 13 | 14 | 15 | def isfile(filename): 16 | if not os.path.exists(filename): 17 | raise SystemExit('Input file %s not found!\nPlease create this file using theoinp or specify its location using -ifile\n' % filename) 18 | return filename 19 | 20 | 21 | def get_ifile_commandline(): 22 | parser = argparse.ArgumentParser(description=None) 23 | parser.add_argument('-ifile', default='dens_ana.in', help='name of the input file') 24 | args = parser.parse_args() 25 | return isfile(args.ifile) 26 | 27 | 28 | def timeit(func): 29 | def _wrapper(*args, **kwargs): 30 | (tc, tt) = (process_time(), perf_counter()) 31 | result = func(*args, **kwargs) 32 | print("CPU time: % .1f s, wall time: %.1f s"%(process_time() - tc, perf_counter() - tt)) 33 | return result 34 | return _wrapper 35 | -------------------------------------------------------------------------------- /theodore/error_handler.py: -------------------------------------------------------------------------------- 1 | 2 | from __future__ import print_function, division 3 | 4 | class MsgError(Exception): 5 | def __init__(self, errmsg): 6 | self.errmsg = errmsg 7 | 8 | def __str__(self): 9 | return "\n\n ERROR: %s"%self.errmsg 10 | 11 | class ElseError(MsgError): 12 | def __init__(self, val, key): 13 | self.errmsg = "Option %s not implemented for '%s'!"%(val, key) 14 | # call e.g. 15 | # raise error_handler.ElseError(ana_type, 'ana_type') 16 | 17 | 18 | class NIError(MsgError): 19 | def __init__(self): 20 | self.errmsg = "Functionality no implemented yet!" 21 | 22 | class PureVirtualError(MsgError): 23 | """ 24 | Use this to mark pure virtual functions in an abstract base class 25 | These have to be redefined by the inherited class. 26 | -> One could use NotImplementedError instead 27 | """ 28 | def __init__(self): 29 | self.errmsg = "Virtual function is pure!" 30 | -------------------------------------------------------------------------------- /theodore/lib_diab.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division 2 | 3 | from . import error_handler, dens_ana_base, file_parser, pop_ana, units 4 | import numpy 5 | 6 | """ 7 | Routines for property based diabatization. 8 | """ 9 | class diab_base(dens_ana_base.dens_ana_base): 10 | """ 11 | Basic routines for diabatization. 12 | """ 13 | def print_summ(self, O11, O22, O12=None, Ead=None): 14 | """ 15 | Print a summary. 16 | """ 17 | #O_ren = (O22 - O11) / (O11 + O22) 18 | etas = 0.5 * numpy.arccos((O22-O11)/2.) 19 | 20 | print("FCD analysis. Correct?") 21 | 22 | if O12==None: 23 | print('%15s%12s'%('', 'simplified')) 24 | print('%15s% 12.5f'%('Mixing angle', etas)) 25 | if not Ead==None: 26 | coups = 0.5 * Ead * numpy.sin(2*etas) 27 | print('%15s% 12.5f'%('Coupling', coups)) 28 | else: 29 | etaf = 0.5 * numpy.arctan2(2*O12, O22-O11) 30 | print('%15s%12s%12s'%('', 'full', 'simplified')) 31 | print('%15s% 12.5f% 12.5f'%('Mixing angle', etaf, etas)) 32 | if not Ead==None: 33 | coups = 0.5 * Ead * numpy.sin(2*etas) 34 | coupf = 0.5 * Ead * numpy.sin(2*etaf) 35 | print('%15s% 12.5f% 12.5f'%('Coupling', coupf, coups)) 36 | 37 | class fcd_ana(diab_base): 38 | """ 39 | FCD analysis class. 40 | """ 41 | def read_dens(self): 42 | self.Ead = None 43 | 44 | rtype = self.ioptions.get('rtype') 45 | if rtype in ['mcscf', 'colmcscf']: 46 | (self.st1, self.st2, self.trans) = file_parser.file_parser_col_mcscf(self.ioptions).read_fcd(self.mos) 47 | self.Ead = (self.st2['exc_en'] - self.st1['exc_en']) * units.energy['eV'] 48 | elif rtype in ['nos']: 49 | state_list = file_parser.file_parser_nos(self.ioptions).read(self.mos) 50 | if not len(state_list) == 2: 51 | raise error_handler.MsgError("Specify two states for FCD analysis") 52 | (self.st1, self.st2) = state_list 53 | self.trans = None 54 | elif rtype in ['mrci', 'colmrci']: 55 | (self.st1, self.st2, self.trans) = file_parser.file_parser_col_mrci(self.ioptions).read_fcd(self.mos) 56 | self.Ead = self.trans['exc_en'] 57 | else: 58 | raise error_handler.ElseError(rtype, 'rtype') 59 | 60 | self.extra_info() 61 | 62 | def do_pop_ana(self, ana_type='mullpop', lvprt=2): 63 | if ana_type == 'mullpop': 64 | pana = pop_ana.mullpop_ana() 65 | else: 66 | raise error_handler.ElseError('ana_type', ana_type) 67 | 68 | self.st1['pop'] = pana.ret_pop(self.st1['sden'], self.mos) 69 | self.st2['pop'] = pana.ret_pop(self.st2['sden'], self.mos) 70 | if self.trans: self.trans['pop'] = pana.ret_pop(self.trans['tden'], self.mos) 71 | 72 | if lvprt>=2: 73 | pop_pr = pop_ana.pop_printer(self.struc) 74 | pop_pr.add_pop('state 1', self.st1['pop']) 75 | pop_pr.add_pop('state 2', self.st2['pop']) 76 | if self.trans: pop_pr.add_pop('trans.', self.trans['pop']) 77 | print(pop_pr.ret_table()) 78 | 79 | def do_fcd(self): 80 | # two entries for the two fragments 81 | qst1 = numpy.zeros(2) 82 | qst2 = numpy.zeros(2) 83 | if self.trans: qtrans = numpy.zeros(2) 84 | 85 | if not len(self.ioptions['at_lists']) == 2: 86 | raise error_handler.MsgError("Fragment definitions for two fragments required in at_lists") 87 | 88 | for atind in self.ioptions['at_lists'][0]: 89 | qst1[0] += self.st1['pop'][atind-1] 90 | qst2[0] += self.st2['pop'][atind-1] 91 | if self.trans: qtrans[0] += self.trans['pop'][atind-1] 92 | for atind in self.ioptions['at_lists'][1]: 93 | qst1[1] += self.st1['pop'][atind-1] 94 | qst2[1] += self.st2['pop'][atind-1] 95 | if self.trans: qtrans[1] += self.trans['pop'][atind-1] 96 | 97 | pop_pr = pop_ana.pop_printer(self.struc) 98 | pop_pr.add_pop('state 1', qst1) 99 | pop_pr.add_pop('state 2', qst2) 100 | if self.trans: pop_pr.add_pop('trans.', qtrans) 101 | print(pop_pr.ret_table_FCD(self.ioptions['at_lists'])) 102 | 103 | fcd1 = qst1[1] - qst1[0] 104 | fcd2 = qst2[1] - qst2[0] 105 | fcd12 = qtrans[1] - qtrans[0] if self.trans else None 106 | 107 | self.print_summ(fcd1, fcd2, fcd12, self.Ead) 108 | -------------------------------------------------------------------------------- /theodore/lib_exciton.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division 2 | 3 | from . import lib_struc, error_handler, units 4 | import numpy 5 | 6 | class exciton_analysis: 7 | """ 8 | Perform analysis of an effective exciton wavefunction. 9 | Approximate atom centered solutions. 10 | """ 11 | # TODO: add correlation coefficient and covariance 12 | # use the same moment construction as in the JCC paper, only discretized 13 | 14 | def __init__(self): 15 | self.distmat = None 16 | self.Ohnomat = None 17 | 18 | def get_distance_matrix(self, struc, U = 8.0, eps = 2): 19 | """ 20 | Get distance matrix and compute ERIs according to Ohno formula. 21 | """ 22 | self.distmat = struc.ret_distance_matrix() 23 | 24 | # Ohno formula from W. Barford, PRB, 106, 035201 (2022) 25 | self.Ohnomat = U / (1 + (U * eps * self.distmat)**2)**.5 26 | # TODO: use for K2 and J2 27 | 28 | def ret_RMSeh(self, Om, OmAt): 29 | """ 30 | Return the root mean square electron-hole distance (Ang). 31 | """ 32 | if not type(self.distmat) is numpy.ndarray: 33 | raise error_handler.MsgError("Compute the distance matrix first!") 34 | 35 | try: 36 | MS_dist = numpy.dot(OmAt.flatten(), self.distmat.flatten()**2.) / Om 37 | except: 38 | print("\n Error when computing MS_dist!") 39 | print(" Please check the coordinate file.") 40 | print(" OmAt: %i x %i"%(len(OmAt), len(OmAt[0]))) 41 | print(" distmat: %i x %i"%(len(self.distmat), len(self.distmat[0]))) 42 | raise 43 | 44 | RMS_dist = numpy.sqrt(MS_dist) 45 | 46 | return RMS_dist 47 | 48 | def ret_MAeh(self, Om, OmAt): 49 | """ 50 | Return the mean absolute electron-hole distance (Ang). 51 | """ 52 | if not type(self.distmat) is numpy.ndarray: 53 | raise error_handler.MsgError("Compute the distance matrix first!") 54 | 55 | MA_dist = numpy.dot(OmAt.flatten(), self.distmat.flatten()) / Om 56 | 57 | return MA_dist 58 | 59 | def ret_Eb(self, Om, OmAt, Eb_diag=1.0): 60 | """ 61 | Return an approximate exciton binding energy (eV). 62 | TODO: One could use the Ohno formula here. 63 | """ 64 | if not type(self.distmat) is numpy.ndarray: 65 | raise error_handler.MsgError("Compute the distance matrix first!") 66 | 67 | Eb_dist = self.distmat.flatten() / units.length['A'] 68 | 69 | for i in range(len(self.distmat)): 70 | Eb_dist[i + i*len(self.distmat)] = Eb_diag 71 | 72 | Eb_au = numpy.dot(OmAt.flatten(), Eb_dist**-1.) / Om 73 | 74 | return Eb_au * units.energy['eV'] 75 | 76 | def ret_rTD(self, QT2, tpop): 77 | """ 78 | Compute effective transition density size. 79 | """ 80 | if QT2 < 0.01: 81 | return None 82 | pot = 0 83 | for A, popA in enumerate(tpop): 84 | for B, popB in enumerate(tpop): 85 | if A != B: 86 | pot += popA * popB / self.distmat[A, B] 87 | #if abs(popA * popB / self.distmat[A, B]) > 0.01: 88 | # print('%3i %3i % .5f % .5f % .5f % .5f'%(A, B, popA, popB, popA*popB / self.distmat[A, B], pot)) 89 | 90 | return -QT2 / pot 91 | -------------------------------------------------------------------------------- /theodore/lib_pytest.py: -------------------------------------------------------------------------------- 1 | """ 2 | General tools for using pytest. 3 | """ 4 | 5 | import os, shutil, subprocess, difflib 6 | import io 7 | import sys 8 | from contextlib import contextmanager 9 | from .actions import ActionFactory 10 | 11 | 12 | class StringIO_(io.StringIO): 13 | 14 | def read(self): 15 | pos = super().tell() 16 | super().seek(0) 17 | result = super().read() 18 | super().seek(pos) 19 | return result 20 | 21 | 22 | @contextmanager 23 | def mock_stdout(): 24 | old = sys.stdout 25 | sys.stdout = StringIO_() 26 | yield sys.stdout 27 | sys.stdout = old 28 | 29 | 30 | @contextmanager 31 | def mock_stdin(string): 32 | old = sys.stdin 33 | sys.stdin = StringIO_(string) 34 | yield sys.stdin 35 | sys.stdin = old 36 | 37 | 38 | @contextmanager 39 | def commandline(string): 40 | old = sys.argv 41 | sys.argv = string.split() 42 | yield sys.argv 43 | sys.argv = old 44 | 45 | 46 | class pytest_job: 47 | """ 48 | Run and check job in EXAMPLES directory using pytest. 49 | """ 50 | def __init__(self, cfile, thresh=1.e-6): 51 | self.wstring = '' 52 | self.epath = os.path.dirname(os.path.abspath(cfile)) 53 | self.prep() 54 | self.thresh = thresh 55 | 56 | def run_standard(self): 57 | """ 58 | Run tests in standard format. 59 | """ 60 | os.chdir(self.epath + '/RUN') 61 | for ifile in sorted(os.listdir('../IN_FILES')): 62 | shutil.copy("../IN_FILES/"+ifile, ifile) 63 | col = ifile.split('.') 64 | dtype, atype = col[0], col[2] 65 | with commandline(f'theodore analyze_{dtype} -f {ifile}'), mock_stdout() as out: 66 | ActionFactory.from_commandline() 67 | outlines = out.read() 68 | with open(f'analyze_{atype}.out', 'w') as fh: 69 | fh.write(outlines) 70 | self.check() 71 | 72 | def run_util(self, args, stdin='', outf=None): 73 | """ 74 | This is for running an arbitrary utility script. 75 | Generate the input for stdin as, e.g.: 76 | tee plot_omfrag.in | theodore plot_omfrag 77 | After this, self.check() has to be run. 78 | """ 79 | os.chdir(f'{self.epath}/RUN') 80 | with commandline(f'theodore {args}'), mock_stdin(stdin), mock_stdout() as out: 81 | ActionFactory.from_commandline() 82 | if not outf is None: 83 | open(outf, 'w').write(out.read()) 84 | 85 | def prep(self): 86 | """Create `RUN` dir""" 87 | os.chdir(self.epath) 88 | if os.path.exists('RUN'): 89 | shutil.rmtree('RUN') 90 | shutil.copytree('QC_FILES', 'RUN') 91 | os.chdir(self.epath + '/RUN') 92 | 93 | def check(self): 94 | """ Check if there are any differences. """ 95 | os.chdir(self.epath + '/RUN') 96 | print("Checking primary output files") 97 | for rfile in os.listdir('../REF_FILES'): 98 | print(" -> " + rfile) 99 | self.file_diff('../REF_FILES/'+rfile, rfile) 100 | 101 | if len(self.wstring) > 0: 102 | raise pytestDiffError(self.epath + '\n\n' + self.wstring) 103 | 104 | def file_diff(self, reff, runf): 105 | """ 106 | Check if the files are different. 107 | line-by-line treatment for txt files, otherwise general diff. 108 | """ 109 | wstring = "\n" 110 | 111 | ref = open(reff).readlines() 112 | run = open(runf).readlines() 113 | # suffix = runf.split('.')[-1] 114 | 115 | # These files should match line-by-line 116 | if '.txt' in runf: 117 | for iline, line in enumerate(ref): 118 | if not line == run[iline]: 119 | print(' *** Running numerical diff ***') 120 | if self.num_diff(line, run[iline]) > 0: 121 | self.wstring += 'Numerical threshold exceeded \n\n' 122 | diffl = list(difflib.unified_diff(ref, run, fromfile=reff, tofile=runf)) 123 | wstring = "\n" 124 | for line in diffl: 125 | self.wstring += line 126 | return 127 | # Use a general diff here 128 | else: 129 | diffl = list(difflib.unified_diff(self.diff_ignore(ref), self.diff_ignore(run), fromfile=reff, tofile=runf)) 130 | if len(diffl) > 0: 131 | wstring = "\n" 132 | for line in diffl: 133 | self.wstring += line 134 | 135 | def diff_ignore(self, dlist): 136 | outl = [] 137 | iglist = ["TheoDORE", "time", "rbkit", "openbabel", "capabilities", "cclib"] 138 | for line in dlist: 139 | for ig in iglist: 140 | if ig in line: 141 | break 142 | elif line.strip() == "": 143 | break 144 | else: 145 | outl.append(line) 146 | return outl 147 | 148 | def num_diff(self, rline, line): 149 | """ 150 | Run numerical diff for line. 151 | """ 152 | ierr = 0 153 | 154 | rwords = rline.split() 155 | words = line.split() 156 | 157 | if not len(rwords) == len(words): 158 | return 2 159 | 160 | for i, rword in enumerate(rwords): 161 | try: 162 | rval = float(rword) 163 | except ValueError: 164 | continue 165 | val = float(words[i]) 166 | if abs(rval-val) > self.thresh: 167 | ierr += 1 168 | 169 | return ierr 170 | 171 | class pytestDiffError(Exception): 172 | def __init__(self, errmsg): 173 | self.errmsg = errmsg 174 | 175 | def __str__(self): 176 | return "\n\n *** pytest detected difference to reference results: ***\n\n %s"%self.errmsg 177 | -------------------------------------------------------------------------------- /theodore/lib_util.py: -------------------------------------------------------------------------------- 1 | """ 2 | Library with some utilities that do not fit anywhere else. 3 | """ 4 | 5 | import numpy 6 | 7 | class cube_file: 8 | """ 9 | Analyse a cube file and compute isovalues corresponding to volume integrals. 10 | """ 11 | def __init__(self, fname, header=None, vals=None, inc=None): 12 | self.fname = fname 13 | self.header = header 14 | self.vals = vals 15 | self.inc = inc 16 | 17 | if self.vals is None: 18 | self.avals = None 19 | else: 20 | self.avals = [abs(val) for val in self.vals] 21 | 22 | def read(self, lvprt=0): 23 | if lvprt >= 1: 24 | print('Analysing %s ...'%self.fname) 25 | with open(self.fname, 'r') as f: 26 | line = next(f) 27 | line = next(f) 28 | line = next(f) 29 | natom = int(line.split()[0]) 30 | words = next(f).split() 31 | x = float(words[1]) 32 | words = next(f).split() 33 | y = float(words[2]) 34 | words = next(f).split() 35 | self.inc = int(words[0]) 36 | z = float(words[3]) 37 | self.V = x * y * z 38 | for iat in range(natom): 39 | line = next(f) 40 | 41 | self.vals = [] 42 | while True: # loop over all lines 43 | try: 44 | line = next(f) 45 | except StopIteration: 46 | if lvprt >= 1: 47 | print("Reached end of file %s"%f.name) 48 | break 49 | 50 | self.vals += map(float, line.split()) 51 | 52 | # save the header separately 53 | self.header = '' 54 | with open(self.fname, 'r') as f: 55 | for i in range(natom + 6): 56 | self.header += next(f) 57 | 58 | self.s = sum(self.vals) 59 | self.avals = [abs(val) for val in self.vals] 60 | self.abss = sum(self.avals) 61 | self.sqs = sum(val*val for val in self.vals) 62 | self.minval = min(self.vals) 63 | self.maxval = max(self.vals) 64 | if lvprt >= 1: 65 | print('Integral: % .6f, Abs. Int.: % .6f, Squ. Int. % .6f:'%(self.s * self.V, self.abss * self.V, self.sqs * self.V)) 66 | print('Min: % .6f, Max % .6f'%(self.minval, self.maxval)) 67 | self.avals.sort(reverse=True) 68 | 69 | def write(self): 70 | """ 71 | Write cube file to fname. 72 | """ 73 | with open(self.fname, 'w') as f: 74 | f.write(self.header) 75 | i = 0 76 | for val in self.vals: 77 | f.write("% 14.6e"%val) 78 | i += 1 79 | if i==self.inc: 80 | f.write('\n') 81 | i = 0 82 | elif i%6 == 0: 83 | f.write('\n') 84 | 85 | def ret_isovals(self, frac=[0.1, 0.5, 0.75, 0.9, 0.95, 0.99], lvprt=0): 86 | """ 87 | Return the isovalues that correspond to a specific fraction of the density. 88 | """ 89 | if self.vals is None: 90 | self.read(lvprt) 91 | 92 | retvals = [] 93 | 94 | frac.sort() 95 | ifrac = 0 96 | ps = 0. 97 | thres = frac[ifrac] * self.abss 98 | for val in self.avals: 99 | ps += val 100 | if ps > thres: 101 | retvals.append(val) 102 | if lvprt >= 1: 103 | print("isoval: %.6f at %.4f (%.6f)"%(val, frac[ifrac], ps/self.abss)) 104 | ifrac += 1 105 | try: 106 | thres = frac[ifrac] * self.abss 107 | except IndexError: 108 | break 109 | 110 | return retvals 111 | 112 | def ret_volume(self, iso, lvprt=0): 113 | """ 114 | Return the volume (in Bohr^3) associated to a specific isovalue 115 | by counting the number of elements above this isovalue. 116 | """ 117 | if self.vals is None: 118 | self.read(lvprt=lvprt) 119 | nval = numpy.count_nonzero(numpy.array(self.avals) > iso) 120 | 121 | return nval * self.V 122 | 123 | def prep(self, other, lvprt=0): 124 | """ 125 | Prepare for mathematical operations. 126 | """ 127 | if self.vals is None: 128 | self.read(lvprt=lvprt) 129 | if other.vals is None: 130 | other.read(lvprt=lvprt) 131 | assert self.V == other.V 132 | 133 | def dot(self, other, lvprt=0): 134 | """ 135 | Compute the dot product / overlap between two cube files. 136 | """ 137 | self.prep(other, lvprt) 138 | 139 | dot = sum(val * other.vals[ival] for ival, val in enumerate(self.vals)) * self.V 140 | if lvprt >= 1: 141 | print("Computing dot product between %s and %s"%(self.fname, other.fname)) 142 | print("Dot: % .6f"%dot) 143 | 144 | return dot 145 | 146 | def dot_power(self, other, pow, lvprt=0): 147 | """ 148 | Compute the dot product between two cube files. 149 | Values are raised to the power of pow. 150 | This can be used to compute the S_r index (pow=0.5) 151 | """ 152 | self.prep(other, lvprt) 153 | 154 | dot = sum( abs(val * other.vals[ival])**pow for ival, val in enumerate(self.vals)) * self.V 155 | if lvprt >= 1: 156 | print("Computing dot product (power: %.3f) between %s and %s"%(powe, self.fname, other.fname)) 157 | print("Dot: % .6f"%dot) 158 | 159 | return dot 160 | 161 | def lin_comb(self, other, c, d, outfile, lvprt=0): 162 | """ 163 | Create linear combination c*self + d*other 164 | """ 165 | self.prep(other, lvprt) 166 | 167 | lc = [c * val + d * other.vals[ival] for ival, val in enumerate(self.vals)] 168 | 169 | return cube_file(outfile, self.header, lc, self.inc) 170 | 171 | def mult(self, other, outfile, lvprt=0): 172 | """ 173 | Multiply self * other 174 | for transition densities 175 | """ 176 | self.prep(other, lvprt) 177 | 178 | prod = [val * other.vals[ival] for ival, val in enumerate(self.vals)] 179 | 180 | return cube_file(outfile, self.header, prod, self.inc) 181 | -------------------------------------------------------------------------------- /theodore/orbkit_interface.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is an interface to the orbkit, an external post-processing toolbox. 3 | https://orbkit.github.io/ 4 | Download and install orbkit if you want to use the functions. 5 | """ 6 | from __future__ import print_function, division 7 | 8 | orbkit_avail = True 9 | try: 10 | import orbkit 11 | except ImportError: 12 | orbkit_avail = False 13 | print(" *** Orbkit installation not found. ***") 14 | print(" Install orbkit for extended plotting capabilities.\n") 15 | 16 | if orbkit_avail: 17 | from .orbkit_full import lib_orbkit 18 | else: 19 | class lib_orbkit: 20 | """ 21 | This is a fake class just to make sure that all the calls are defined. 22 | """ 23 | def __init__(self): 24 | print("\n*** WARNING: orbkit not available! ***\n Plotting not possible as specified.\n") 25 | def orbkit_geo_ao_conversion(self,mos): 26 | pass 27 | def orbkit_nto_conversion(self,U,lam,Vt,mos,qc,minlam=1e-3): 28 | pass 29 | def orbkit_mo_conversion(self,mos,qc): 30 | pass 31 | def orbkit_grid(self,qc): 32 | pass 33 | def compute_MOs(self,qc,numproc=4): 34 | pass 35 | def compute_p_h_dens(self,state, U, lam, Vt, mos, minlam=1e-3,numproc=4): 36 | pass 37 | def compute_rho_0_n(self,state_list,mos,numproc=4): 38 | pass 39 | def cube_file_creator(self,state, U, lam, Vt, mos, minlam=1e-3, numproc=4): 40 | pass 41 | def vmd_network_creator(self,filename='',cube_ids=[],isovalue=0.01): 42 | pass 43 | -------------------------------------------------------------------------------- /theodore/pop_ana.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for population analysis. 3 | Currently only Mulliken style analysis is supported. 4 | """ 5 | 6 | from __future__ import print_function, division 7 | 8 | from . import error_handler, lib_struc 9 | import numpy 10 | 11 | class pop_ana: 12 | """ 13 | Base class for population analysis. 14 | """ 15 | def ret_Deff(self, dens, mos): 16 | """ 17 | Compute the effective density. 18 | """ 19 | raise error_handler.PureVirtualError() 20 | 21 | def ret_pop(self, dens, mos, Deff=None): 22 | """ 23 | Return the population. 24 | Effective density (Deff) can be specified externally. 25 | """ 26 | if Deff is None: 27 | Deff = self.ret_Deff(dens, mos) 28 | 29 | mp = numpy.zeros(mos.num_at) 30 | 31 | for ibas in range(mos.ret_num_bas()): 32 | iat = mos.basis_fcts[ibas].at_ind - 1 33 | mp[iat] += Deff[ibas, ibas] 34 | 35 | return mp 36 | 37 | class mullpop_ana(pop_ana): 38 | """ 39 | Mulliken population analysis. 40 | """ 41 | def ret_Deff(self, dens, mos): 42 | """ 43 | Compute and return the Mulliken orthogonalized DM. 44 | """ 45 | temp = mos.CdotD(dens, trnsp=False, inv=False) # C.DAO 46 | DS = mos.MdotC(temp, trnsp=False, inv=True) # DAO.S = C.D.C^(-1) 47 | 48 | return DS 49 | 50 | class lowdin_ana(pop_ana): 51 | """ 52 | Lowdin population analysis. 53 | """ 54 | def ret_Deff(self, dens, mos): 55 | """ 56 | Compute and return the Lowdin orthogonalized DM. 57 | """ 58 | return mos.lowdin_trans(dens) 59 | 60 | class pop_printer: 61 | """ 62 | Printer for population analysis data. 63 | """ 64 | def __init__(self, struc=None): 65 | self.pop_types = [] 66 | self.pops = [] 67 | 68 | self.struc = struc 69 | 70 | def clear(self): 71 | self.pop_types = [] 72 | self.pops = [] 73 | 74 | ## \brief Add population data 75 | # \param pop_type name to be printed 76 | # \param pop numpy.array with data 77 | def add_pop(self, pop_type, pop): 78 | """ 79 | Add population data to be stored in the printer class. 80 | """ 81 | if pop is None: return 82 | 83 | self.pop_types.append(pop_type) 84 | self.pops.append(pop) 85 | 86 | def header(self, inp): 87 | hstr = inp 88 | for pop_type in self.pop_types: 89 | hstr += '%10s'%pop_type 90 | 91 | retstr = len(hstr) * '-' + "\n" 92 | retstr += hstr 93 | retstr += "\n" + len(hstr) * '-' + "\n" 94 | 95 | return hstr, retstr 96 | 97 | def ret_table(self, labels=[]): 98 | """ 99 | Return a table containing all the populations of interest. 100 | """ 101 | if len(self.pop_types) == 0: 102 | return " ... no population analysis data available." 103 | 104 | hstr, retstr = self.header('%6s'%'Atom') 105 | 106 | # main part 107 | for iat in range(len(self.pops[0])): 108 | if labels != []: 109 | retstr += '%6s'%labels[iat] 110 | elif self.struc is None: 111 | retstr += '%6i'%(iat+1) 112 | else: 113 | retstr += '%3s%3i'%(self.struc.ret_symbol(iat+1), iat+1) 114 | 115 | for pop in self.pops: 116 | retstr += '% 10.5f'%pop[iat] 117 | retstr += '\n' 118 | 119 | # sums 120 | retstr += len(hstr) * '-' + "\n" 121 | 122 | retstr += '%6s'%'' 123 | for pop in self.pops: 124 | retstr += '% 10.5f'%pop.sum() 125 | 126 | retstr += "\n" + len(hstr) * '-' + "\n" 127 | 128 | return retstr 129 | 130 | def ret_table_Frag(self, at_lists): 131 | """ 132 | Return a table over fragments. 133 | """ 134 | if len(self.pop_types) == 0: 135 | return " ... no population analysis data available." 136 | 137 | hstr, retstr = self.header('%15s'%'Fragment') 138 | 139 | # main part 140 | for i in range(len(self.pops[0])): 141 | if self.struc is None: 142 | retstr += '%15i'%(i+1) 143 | else: 144 | retstr += '%15s'%(self.struc.ret_at_list_composition(at_lists[i])) 145 | for pop in self.pops: 146 | retstr += '% 10.5f'%pop[i] 147 | retstr += '\n' 148 | 149 | # sums 150 | retstr += len(hstr) * '-' + "\n" 151 | 152 | retstr += '%15s'%'' 153 | for pop in self.pops: 154 | retstr += '% 10.5f'%pop.sum() 155 | 156 | retstr += "\n" + len(hstr) * '-' + "\n" 157 | 158 | return retstr 159 | 160 | def ret_table_FCD(self, at_lists): 161 | """ 162 | Table for FCD. 163 | """ 164 | hstr, retstr = self.header('%15s'%'Fragment') 165 | 166 | # main part 167 | for i in range(len(self.pops[0])): 168 | if self.struc is None: 169 | retstr += '%15i'%(i+1) 170 | else: 171 | retstr += '%15s'%(self.struc.ret_at_list_composition(at_lists[i])) 172 | for pop in self.pops: 173 | retstr += '% 10.5f'%pop[i] 174 | retstr += '\n' 175 | 176 | # sums 177 | retstr += len(hstr) * '-' + "\n" 178 | 179 | retstr += '%15s'%'FCD' 180 | for pop in self.pops: 181 | retstr += '% 10.5f'%(pop[1]-pop[0]) 182 | 183 | retstr += "\n" + len(hstr) * '-' + "\n" 184 | 185 | return retstr 186 | 187 | class pop_printer_mo(pop_printer): 188 | """ 189 | Print Mulliken populations of MOs according to atoms. 190 | """ 191 | def print_mo_pops(self, mos, dosum=1, ncol=8): 192 | """ 193 | Print MO populations. 194 | dosum: 1 - sum over atoms 195 | 2 - sum over basis function types 196 | """ 197 | if dosum==1: 198 | labels = [] 199 | elif dosum==2: 200 | labels = mos.bf_labels 201 | else: 202 | raise error_handler.ElseError(dosum, 'dosum') 203 | 204 | for imo in range(mos.ret_num_mo()): 205 | mp = mos.ret_mo_pop(imo, dosum=dosum) 206 | self.add_pop('MO %i'%(imo+1), mp) 207 | 208 | if (imo+1) % ncol == 0: 209 | print(self.ret_table(labels)) 210 | self.clear() 211 | 212 | if (imo+1) % ncol != 0: 213 | print(self.ret_table(labels)) 214 | -------------------------------------------------------------------------------- /theodore/theo_header.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function, division 2 | import os 3 | 4 | width=80 5 | 6 | def print_header(*args, **kwargs): 7 | print((ret_header(*args, **kwargs))) 8 | 9 | def ret_header(title=None, ioptions=None, cfile=None, ver='3.3-pre'): 10 | hstr = width*'=' + '\n' 11 | 12 | hstr += addlinec("TheoDORE %s"%ver) 13 | hstr += addlinec("Theoretical Density, Orbital Relaxation and Exciton analysis") 14 | hstr += addlinec() 15 | hstr += addlinec("Author: Felix Plasser") 16 | hstr += addlinec("Contributions by: L. Stojanovic, G. Hermann, S. Mai,") 17 | hstr += addlinec(" M.F.S.J. Menger, P. Kimber, F. Dinkelbach") 18 | 19 | hstr += width*'-' + '\n' 20 | 21 | hstr += addlinec("References for the modules used") 22 | hstr += addlinec("(see also http://theodore-qc.sourceforge.net/literature.html)") 23 | 24 | hstr += add_stden(cfile) 25 | hstr += add_exciton(ioptions) 26 | hstr += add_extra(ioptions) 27 | hstr += add_cclib(ioptions) 28 | hstr += add_orbkit(ioptions) 29 | hstr += add_VIST(cfile) 30 | 31 | hstr += addlinec() 32 | hstr += addlinel("Program citation:", 3) 33 | hstr += addlinel("F. Plasser, J. Chem. Phys. (2020), 152, 084108.") 34 | # hstr += addlinel("F. Plasser \"TheoDORE %s: a package for theoretical density, orbital"%ver) 35 | # hstr += addlinel("relaxation, and exciton analysis\"; available from") 36 | # hstr += addlinel("http://theodore-qc.sourceforge.net") 37 | 38 | if not title==None: 39 | hstr += width*'-' + '\n' 40 | hstr += addlinec(title) 41 | 42 | hstr += width*'=' + '\n' 43 | 44 | return hstr 45 | 46 | def addlinec(line=""): 47 | return "|" + line.center(width-2) + "|\n" 48 | 49 | def addlinel(line="", lpad=5): 50 | return "|" + lpad*' ' + line.ljust(width-2-lpad) + "|\n" 51 | 52 | def add_stden(cfile): 53 | if not cfile is None: 54 | cfileb = os.path.basename(cfile) 55 | else: 56 | return '' 57 | 58 | rstr = '' 59 | if 'analyze' in cfileb: 60 | rstr += addlinec() 61 | rstr += addlinel("Transition density matrix analysis:", 3) 62 | rstr += addlinel("F. Plasser and H. Lischka") 63 | rstr += addlinel("J. Chem. Theory Comput. (2012), 8, 2777.") 64 | rstr += addlinec() 65 | rstr += addlinel("Transition and difference density matrix analysis:", 3) 66 | rstr += addlinel("F. Plasser, M. Wormit, A. Dreuw") 67 | rstr += addlinel("J. Chem. Phys. (2014), 141, 024106.") 68 | 69 | return rstr 70 | 71 | def add_exciton(ioptions): 72 | try: 73 | prop_list = ioptions['prop_list'] 74 | except TypeError: 75 | return '' 76 | 77 | rstr = '' 78 | 79 | if ('RMSeh' in prop_list) or ('dexc' in prop_list): 80 | rstr += addlinec() 81 | rstr += addlinel("Exciton analysis:", 3) 82 | rstr += addlinel("S. A. Baeppler, F. Plasser, M. Wormit, A. Dreuw") 83 | rstr += addlinel("Phys. Rev. A (2014), 90, 052521.") 84 | 85 | if 'RMSeh' in prop_list: 86 | rstr += addlinec() 87 | rstr += addlinel("Approximate RMSeh/dexc formula:", 3) 88 | rstr += addlinel("S. A. Mewes, J.-M. Mewes, A. Dreuw, F. Plasser") 89 | rstr += addlinel("Phys. Chem. Chem. Phys. (2016), 18, 2548.") 90 | 91 | if 'dH-E' in prop_list or 'Corr' in prop_list or 'sigH' in prop_list or 'sigE' in prop_list: 92 | rstr += addlinec() 93 | rstr += addlinel("Statistical analysis of excitations:", 3) 94 | rstr += addlinel("F. Plasser, B. Thomitzni, S. A. Baeppler et al.") 95 | rstr += addlinel("J. Comput. Chem. (2015), 36, 1609.") 96 | 97 | if ioptions['comp_dntos']: 98 | rstr += addlinec() 99 | rstr += addlinel("Conditional densities and DNTOs:", 3) 100 | rstr += addlinel("F. Plasser") 101 | rstr += addlinel("ChemPhotoChem (2019), DOI: 10.1002/cptc.201900014.") 102 | 103 | return rstr 104 | 105 | def add_extra(ioptions): 106 | try: 107 | prop_list = ioptions['prop_list'] 108 | except TypeError: 109 | return '' 110 | 111 | rstr = '' 112 | 113 | if ('S_HE' in prop_list) or ('Z_HE' in prop_list): 114 | rstr += addlinec() 115 | rstr += addlinel("Electron-hole entanglement:", 3) 116 | rstr += addlinel("F. Plasser") 117 | rstr += addlinel("J. Chem. Phys. (2016), 144, 194107.") 118 | 119 | if ('QTa' in prop_list) or ('LOC' in prop_list): 120 | rstr += addlinec() 121 | rstr += addlinel("Analysis of ionic states:", 3) 122 | rstr += addlinel("F. Plasser et al.") 123 | rstr += addlinel("in preparation") 124 | 125 | return rstr 126 | 127 | def add_cclib(ioptions): 128 | try: 129 | rtype = ioptions['rtype'].lower() 130 | except TypeError: 131 | return '' 132 | 133 | rstr = '' 134 | 135 | if rtype in ['cclib', 'gamess', 'orca']: 136 | rstr += addlinec() 137 | rstr += addlinel("cclib for structure parsing (http://cclib.github.io):", 3) 138 | rstr += addlinel("N. M. O'Boyle, A. L. Tenderholt, K. M. Langner") 139 | rstr += addlinel("J. Comput. Chem. (2008), 29, 839.") 140 | 141 | return rstr 142 | 143 | def add_orbkit(ioptions): 144 | try: 145 | ok_use = ioptions['cube_orbitals'] or ioptions['comp_p_h_dens'] or ioptions['comp_rho0n'] 146 | except TypeError: 147 | return '' 148 | 149 | rstr = '' 150 | if ok_use: 151 | rstr += addlinec() 152 | rstr += addlinel("orbkit for orbital/density plotting (http://orbkit.github.io):", 3) 153 | rstr += addlinel("G. Hermann, V. Pohl, J. C. Tremblay, B. Paulus, H.-C. Hege, A. Schild") 154 | rstr += addlinel("J. Comput. Chem. (2016), 37, 1511.") 155 | 156 | return rstr 157 | 158 | def add_VIST(cfile): 159 | if not cfile is None: 160 | cfileb = os.path.basename(cfile) 161 | else: 162 | return '' 163 | 164 | rstr = '' 165 | if cfileb in ['plot_VIST.py']: 166 | rstr += addlinec() 167 | rstr += addlinel("Visualization of chemical shielding tensors (VIST):", 3) 168 | rstr += addlinel("F. Plasser, F. Gloecklhofer") 169 | rstr += addlinel("Eur. J. Org. Chem. (2021), DOI: 10.1002/ejoc.202100352.") 170 | 171 | return rstr 172 | -------------------------------------------------------------------------------- /theodore/units.py: -------------------------------------------------------------------------------- 1 | """ 2 | version 1.0 3 | author: Felix Plasser 4 | Library containing unit conversion factors. Magnitudes correspond to 1 atomic unit, arranged in dictionaries. 5 | For example, 'eV':27.2113961 can be understood as 27.211 eV/au 6 | """ 7 | 8 | from __future__ import print_function, division 9 | 10 | energy={'au':1.0, 11 | 'eV':27.2113961, 12 | 'kJ/mol':2625.49963, 13 | 'J':4.359744E-18, 14 | 'kcal/mol':627.50947, 15 | 'rcm':219474.631, 16 | 'nm':45.5633515, 17 | 'Hz':6.579684E15, 18 | 'K':3.157746E+05, 19 | 'RT':3.157746E+05/298. 20 | } 21 | length={'au':1.0, 22 | 'A':0.529177249, 23 | 'm':0.529177249E-10, 24 | 'cm':0.529177249E-8 25 | } 26 | time={'au':1.0, 27 | 'fs':0.0241888432, 28 | 's':0.0241888432E-15 29 | } 30 | 31 | mass={'au':1.0, 32 | 'kg':9.10938188E-31, 33 | 'amu':1822.889 # atomic mass unit in a.u. = 1/constants['Nl']/mass['kg']/1000 34 | } 35 | dipole={'D':2.54174619, 36 | 'Cm':8.47835267E-30 37 | } 38 | constants={'Nl':6.02214179E23, 39 | 'c0':137.035999 # speed of light in a.u., 1/alpha 40 | } 41 | 42 | # derived quantities 43 | tpa={} 44 | tpa['GM']=10**50 * length['cm']**4 * time['s'] 45 | 46 | # shortcuts 47 | 48 | def eV2nm(val): 49 | """ 50 | Convert eV to nanometers. 51 | """ 52 | return energy['eV']*energy['nm']/val 53 | 54 | def nm2eV(val): 55 | """ 56 | Convert nanometers to eV. 57 | """ 58 | return eV2nm(val) 59 | 60 | def eVdiff(au1,au2): 61 | """ 62 | Energy difference in eV. 63 | """ 64 | print("%.5f eV"%((au2-au1)*energy['eV'])) 65 | 66 | def print_units(pformat='%15s : %E'): 67 | """ 68 | Print information about all the units. 69 | """ 70 | print(' *** Conversion from atomic units ***') 71 | print(' Energy') 72 | for att, val in energy.items(): 73 | print(pformat%(att, val)) 74 | print(' Length') 75 | for att, val in length.items(): 76 | print(pformat%(att, val)) 77 | print(' Time') 78 | for att, val in time.items(): 79 | print(pformat%(att, val)) 80 | print(' Mass') 81 | for att, val in mass.items(): 82 | print(pformat%(att, val)) 83 | print(' Dipole') 84 | for att, val in dipole.items(): 85 | print(pformat%(att, val)) 86 | print(' Constants') 87 | for att, val in constants.items(): 88 | print(pformat%(att, val)) 89 | print(' Two-photon absorption') 90 | for att, val in tpa.items(): 91 | print(pformat%(att, val)) 92 | 93 | class converter: 94 | def __init__(self): 95 | for att, val in energy.items(): 96 | setattr(self, att, val) 97 | for att, val in length.items(): 98 | setattr(self, att, val) 99 | for att, val in time.items(): 100 | setattr(self, att, val) 101 | for att, val in mass.items(): 102 | setattr(self, att, val) 103 | for att, val in dipole.items(): 104 | setattr(self, att, val) 105 | for att, val in constants.items(): 106 | setattr(self, att, val) 107 | for att, val in tpa.items(): 108 | setattr(self, att, val) 109 | 110 | u = converter() 111 | 112 | if __name__=='__main__': 113 | print_units() 114 | --------------------------------------------------------------------------------