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  }