github.com/rmera/gochem@v0.7.1/qm/qm.go (about) 1 /* 2 * qm.go, part of gochem. 3 * 4 * 5 * Copyright 2012 Raul Mera <rmera{at}chemDOThelsinkiDOTfi> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2.1 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General 18 * Public License along with this program. If not, see 19 * <http://www.gnu.org/licenses/>. 20 * 21 * Dedicated to the long life of the Ven. Khenpo Phuntzok Tenzin Rinpoche 22 * 23 */ 24 25 package qm 26 27 import ( 28 "fmt" 29 30 chem "github.com/rmera/gochem" 31 v3 "github.com/rmera/gochem/v3" 32 ) 33 34 // builds an input for a QM calculation 35 type InputBuilder interface { 36 //Sets the name for the job, used for input 37 //and output files. The extentions will depend on the program. 38 SetName(name string) 39 40 //BuildInput builds an input for the QM program based int the data in 41 //atoms, coords and C. returns only error. 42 BuildInput(coords *v3.Matrix, atoms chem.AtomMultiCharger, Q *Calc) error 43 } 44 45 // Runs a QM calculation 46 type Runner interface { 47 //Run runs the QM program for a calculation previously set. 48 //it waits or not for the result depending of the value of 49 //wait. 50 Run(wait bool) (err error) 51 } 52 53 // Builds inputs and runs a QM calculations 54 type BuilderRunner interface { 55 InputBuilder 56 Runner 57 } 58 59 // Allows to recover energy and optimized geometries from a QM calculation 60 type EnergyGeo interface { 61 62 //Energy gets the last energy for a calculation by parsing the 63 //QM program's output file. Return error if fail. Also returns 64 //Error ("Probable problem in calculation") 65 //if there is a energy but the calculation didnt end properly. 66 Energy() (float64, error) 67 68 //OptimizedGeometry reads the optimized geometry from a calculation 69 //output. Returns error if fail. Returns Error ("Probable problem 70 //in calculation") if there is a geometry but the calculation didnt 71 //end properly* 72 OptimizedGeometry(atoms chem.Atomer) (*v3.Matrix, error) 73 } 74 75 // Handle is an interface for a mostly-full functionality QM program 76 // where "functionality" reflects it's degree of support in goChem 77 type Handle interface { 78 BuilderRunner 79 EnergyGeo 80 } 81 82 const ( 83 ErrProbableProblem = "goChem/QM: Probable problem with calculations" //this is never to be used for fatal errors 84 ErrMissingCharges = "goChem/QM: Missing charges or coordinates" 85 ErrCantValue = "goChem/QM: Can't obtain requested value" //for whatever doesn't match anything else 86 ErrNoEnergy = "goChem/QM: No energy in output" 87 ErrNoFreeEnergy = "goChem/QM: No free energy in output. Forces calculation might have not been performed" 88 ErrNoCharges = "goChem/QM: Unable to read charges from output" 89 ErrNoGeometry = "gochem/QM: Unable to read geometry from output" 90 ErrNotRunning = "gochem/QM: Couldn't run calculation" 91 ErrCantInput = "goChem/QM: Can't build input file" 92 ) 93 94 const ( 95 Orca = "Orca" 96 Mopac = "Mopac" 97 Turbomole = "Turbomole" 98 NWChem = "NWChem" 99 Fermions = "Fermions++" 100 XTB = "XTB" //this may go away if Orca starts supporting XTB. 101 ) 102 103 //errors 104 105 // Error represents a decorable QM error. 106 type Error struct { 107 message string 108 code string //the name of the QM program giving the problem, or empty string if none 109 inputname string //the input file that has problems, or empty string if none. 110 additional string 111 deco []string 112 critical bool 113 } 114 115 // Error returns a string with an error message. 116 func (err Error) Error() string { 117 return fmt.Sprintf("%s (%s/%s) Message: %s", err.message, err.inputname, err.code, err.additional) 118 } 119 120 // Decorate will add the dec string to the decoration slice of strings of the error, 121 // and return the resulting slice. 122 func (err Error) Decorate(dec string) []string { 123 err.deco = append(err.deco, dec) 124 return err.deco 125 } 126 127 // Code returns the name of the program that ran/was meant to run the 128 // calculation that caused the error. 129 func (err Error) Code() string { return err.code } //May not be needed 130 131 // InputName returns the name of the input file which processing caused the error 132 func (err Error) InputName() string { return err.inputname } 133 134 // Critical return whether the error is critical or it can be ifnored 135 func (err Error) Critical() bool { return err.critical } 136 137 // errDecorate is a helper function that asserts that the error is 138 // implements chem.Error and decorates the error with the caller's name before returning it. 139 // if used with a non-chem.Error error, it will cause a panic. 140 func errDecorate(err error, caller string) error { 141 err2 := err.(chem.Error) //I know that is the type returned byt initRead 142 err2.Decorate(caller) 143 return err2 144 } 145 146 //end errors 147 148 // jobChoose is a structure where each QM handler has to provide a closure that makes the proper arrangements for each supported case. 149 type jobChoose struct { 150 opti func() 151 forces func() 152 sp func() 153 md func() 154 charges func() 155 } 156 157 // Job is a structure that define a type of calculations. 158 // The user should set one of these to true, 159 // and goChem will see that the proper actions are taken. If the user sets more than one of the 160 // fields to true, the priority will be Opti>Forces>SP (i.e. if Forces and SP are true, 161 // only the function handling forces will be called). 162 type Job struct { 163 Opti bool 164 Forces bool 165 SP bool 166 MD bool 167 Charges bool 168 } 169 170 // Do sets the job set to true in J, according to the corresponding function in plan. A "nil" plan 171 // means that the corresponding job is not supported by the QM handle and we will default to single point. 172 func (J *Job) Do(plan jobChoose) { 173 if J == nil { 174 return 175 } 176 //now the actual options 177 if J.Opti { 178 plan.opti() 179 return 180 } 181 if J.Forces && plan.forces != nil { 182 plan.forces() 183 return 184 } 185 if J.MD && plan.md != nil { 186 plan.md() 187 return 188 } 189 if J.Charges && plan.charges != nil { //the default option is a single-point 190 plan.charges() 191 return 192 } 193 194 if plan.sp != nil { //the default option is a single-point 195 plan.sp() 196 return 197 } 198 199 } 200 201 //Container for constraints to internal coordinates 202 //type IntConstraint struct { 203 // Kind byte 204 // Atoms []int 205 //} 206 207 // PointCharge is a container for a point charge, such as those used in QM/MM 208 // calculations 209 type PointCharge struct { 210 Charge float64 211 Coords *v3.Matrix 212 } 213 214 // IConstraint is a container for a constraint to internal coordinates 215 type IConstraint struct { 216 CAtoms []int 217 Val float64 218 Class byte // B: distance, A: angle, D: Dihedral 219 UseVal bool //if false, don't add any value to the constraint (which should leave it at the value in the starting structure. This migth not work on every program, but it works in ORCA. 220 } 221 222 // Calc is a structure for the general representation of a calculation 223 // mostly independent of the QM program (although, of course, some methods will not work in some programs) 224 type Calc struct { 225 Method string 226 Basis string 227 RI bool 228 RIJ bool 229 CartesianOpt bool //Do the optimization in cartesian coordinates. 230 BSSE string //Correction for BSSE 231 auxBasis string //for RI calculations 232 auxColBasis string //for RICOSX or similar calculations 233 HighBasis string //a bigger basis for certain atoms 234 LowBasis string //lower basis for certain atoms 235 HBAtoms []int 236 LBAtoms []int 237 HBElements []string 238 LBElements []string 239 CConstraints []int //cartesian contraints 240 IConstraints []*IConstraint 241 ECPElements []string //list of elements with ECP. 242 // IConstraints []IntConstraint //internal constraints 243 Dielectric float64 244 // Solventmethod string 245 Dispersion string //D2, D3, etc. 246 Others string //analysis methods, etc 247 // PCharges []PointCharge 248 Guess string //initial guess 249 Grid int 250 OldMO bool //Try to look for a file with MO. 251 Job *Job //NOTE: This should probably be a pointer: FIX! NOTE2: Fixed it, but must check and fix whatever is now broken. 252 //The following 3 are only for MD simulations, will be ignored in every other case. 253 MDTime int //simulation time (whatever unit the program uses!) 254 MDTemp float64 //simulation temperature (K) 255 MDPressure int //simulation pressure (whatever unit the program uses!) 256 SCFTightness int //1,2 and 3. 0 means the default 257 OptTightness int 258 SCFConvHelp int 259 ECP string //The ECP to be used. It is the programmers responsibility to use a supported ECP (for instance, trying to use 10-electron core ECP for Carbon will fail) 260 Gimic bool 261 Memory int //Max memory to be used in MB (the effect depends on the QM program) 262 } 263 264 // Utilities here 265 func (Q *Calc) SetDefaults() { 266 Q.RI = true 267 // Q.BSSE = "gcp" 268 Q.Dispersion = "D3" 269 } 270 271 // isIn is a helper for the RamaList function, 272 // returns true if test is in container, false otherwise. 273 func isInInt(container []int, test int) bool { 274 if container == nil { 275 return false 276 } 277 for _, i := range container { 278 if test == i { 279 return true 280 } 281 } 282 return false 283 } 284 285 // Same as the previous, but with strings. 286 func isInString(container []string, test string) bool { 287 if container == nil { 288 return false 289 } 290 for _, i := range container { 291 if test == i { 292 return true 293 } 294 } 295 return false 296 }