From 0880537405a27248ed22b4aa8a953a17eb06e707 Mon Sep 17 00:00:00 2001 From: dstuck Date: Wed, 11 Mar 2015 11:46:26 -0700 Subject: [PATCH] Added internals using modified library. --- CoordUtil.cpp | 921 +++++++- CoordUtil.h | 27 +- Est_AutoCorr.cpp | 132 ++ Est_AutoCorr.h | 36 + Makefile | 14 +- PhysicsUtil.cpp | 3 +- PhysicsUtil.h | 3 +- Rho_HO.cpp | 11 +- Rho_HO.h | 5 +- Simulation.cpp | 121 +- Simulation.h | 91 +- System.h | 2 +- TestSystem.cpp | 244 ++- TestSystem.h | 6 +- V_QChem.cpp | 193 +- V_QChem.h | 3 + V_Tinker.cpp | 13 +- V_TinkerExecutable.cpp | 4 +- optking/atom_data.cpp | 3466 ++++++++++++++++++++++++++++++ optking/atom_data.h | 30 + optking/bend.cpp | 304 +++ optking/bend.h | 47 + optking/cov_radii.h | 121 ++ optking/efp_frag.C | 66 + optking/efp_frag.h | 79 + optking/frag.cpp | 720 +++++++ optking/frag.h | 200 ++ optking/frag_H_guess.cpp | 168 ++ optking/frag_disp.cpp | 163 ++ optking/geom_gradients_io.C | 326 +++ optking/getIntcoFileName.C | 25 + optking/globals.h | 57 + optking/intcos.h | 14 + optking/interfrag.cpp | 762 +++++++ optking/interfrag.cppOld | 673 ++++++ optking/interfrag.h | 168 ++ optking/interfrag.hOld | 145 ++ optking/interfrag_orient.cpp | 361 ++++ optking/interfrag_orient.cppOld | 305 +++ optking/io.h | 27 + optking/linear_algebra.cpp | 209 ++ optking/linear_algebra.h | 41 + optking/mem.cpp | 204 ++ optking/mem.h | 49 + optking/molecule.h | 344 +++ optking/molecule_backstep.cpp | 126 ++ optking/molecule_fragments.cpp | 429 ++++ optking/molecule_irc_step.cpp | 160 ++ optking/molecule_nr_step.cpp | 114 + optking/molecule_opt2.cpp | 597 +++++ optking/molecule_prfo_step.cpp | 273 +++ optking/molecule_read_intcos.cpp | 413 ++++ optking/molecule_rfo_step.cpp | 185 ++ optking/molecule_tests.cpp | 209 ++ optking/opt2man.main | 20 + optking/opt_data.cpp | 495 +++++ optking/opt_data.h | 188 ++ optking/opt_data_io.cpp | 154 ++ optking/opt_except.h | 52 + optking/opt_params.h | 118 + optking/optking.C | 374 ++++ optking/package.h | 5 + optking/physconst.h | 15 + optking/print.cpp | 51 + optking/print.h | 21 + optking/set_params.cpp | 461 ++++ optking/simple.h | 96 + optking/stre.cpp | 188 ++ optking/stre.h | 51 + optking/tors.cpp | 302 +++ optking/tors.h | 48 + optking/v3d.cpp | 108 + optking/v3d.h | 91 + 73 files changed, 15953 insertions(+), 294 deletions(-) create mode 100644 Est_AutoCorr.cpp create mode 100644 Est_AutoCorr.h create mode 100644 optking/atom_data.cpp create mode 100644 optking/atom_data.h create mode 100644 optking/bend.cpp create mode 100644 optking/bend.h create mode 100644 optking/cov_radii.h create mode 100644 optking/efp_frag.C create mode 100644 optking/efp_frag.h create mode 100644 optking/frag.cpp create mode 100644 optking/frag.h create mode 100644 optking/frag_H_guess.cpp create mode 100644 optking/frag_disp.cpp create mode 100644 optking/geom_gradients_io.C create mode 100644 optking/getIntcoFileName.C create mode 100644 optking/globals.h create mode 100644 optking/intcos.h create mode 100644 optking/interfrag.cpp create mode 100644 optking/interfrag.cppOld create mode 100644 optking/interfrag.h create mode 100644 optking/interfrag.hOld create mode 100644 optking/interfrag_orient.cpp create mode 100644 optking/interfrag_orient.cppOld create mode 100644 optking/io.h create mode 100644 optking/linear_algebra.cpp create mode 100644 optking/linear_algebra.h create mode 100644 optking/mem.cpp create mode 100644 optking/mem.h create mode 100644 optking/molecule.h create mode 100644 optking/molecule_backstep.cpp create mode 100644 optking/molecule_fragments.cpp create mode 100644 optking/molecule_irc_step.cpp create mode 100644 optking/molecule_nr_step.cpp create mode 100644 optking/molecule_opt2.cpp create mode 100644 optking/molecule_prfo_step.cpp create mode 100644 optking/molecule_read_intcos.cpp create mode 100644 optking/molecule_rfo_step.cpp create mode 100644 optking/molecule_tests.cpp create mode 100644 optking/opt2man.main create mode 100644 optking/opt_data.cpp create mode 100644 optking/opt_data.h create mode 100644 optking/opt_data_io.cpp create mode 100644 optking/opt_except.h create mode 100644 optking/opt_params.h create mode 100644 optking/optking.C create mode 100644 optking/package.h create mode 100644 optking/physconst.h create mode 100644 optking/print.cpp create mode 100644 optking/print.h create mode 100644 optking/set_params.cpp create mode 100644 optking/simple.h create mode 100644 optking/stre.cpp create mode 100644 optking/stre.h create mode 100644 optking/tors.cpp create mode 100644 optking/tors.h create mode 100644 optking/v3d.cpp create mode 100644 optking/v3d.h diff --git a/CoordUtil.cpp b/CoordUtil.cpp index e55eeaf..f749fbf 100644 --- a/CoordUtil.cpp +++ b/CoordUtil.cpp @@ -7,124 +7,643 @@ #include "CoordUtil.h" #include +//#include "optking/molecule.h" +#include "optking/globals.h" + +namespace opt { + void set_params(void); +} CoordUtil::CoordUtil() { } -CoordUtil::CoordUtil(int nMode, int nPart, vector > > modes, vector freqs, vector m, vector > initPos, vector atomicSymbols, vector params, vector< vector > conn, string tinkName, string prmFile, bool readG, bool readW) : numModes(nMode), numPart(nPart), normModes(modes), omega(freqs), reducedMass(m), initCart(initPos), atomType(atomicSymbols), paramType(params), connectivity(conn), tinkerName(tinkName), prmName(prmFile), readGeom(readG), readOmega(readW) { +//CoordUtil::CoordUtil(int nMode, int nPart, bool internalCoords, vector > > modes, vector freqs, vector m, vector > initPos, vector atomicSymbols, vector params, vector< vector > conn, string tinkName, string prmFile, bool readG, bool readW) : numModes(nMode), numPart(nPart), internals(internalCoords), normModes(modes), omega(freqs), reducedMass(m), initCart(initPos), atomType(atomicSymbols), paramType(params), connectivity(conn), outFileName(tinkName), prmName(prmFile), readGeom(readG), readOmega(readW) { +CoordUtil::CoordUtil(int nMode, int nPart, bool internalCoords, vector > > modes, vector freqs, vector m, vector > initPos, vector atomicSymbols, vector params, vector< vector > conn, string tinkName, string prmFile, bool readG, bool readW) { + numModes=nMode; + numPart=nPart; + internals=internalCoords; + normModes=modes; + omega=freqs; + reducedMass=m; + initCart=initPos; + atomType=atomicSymbols; + paramType=params; + connectivity=conn; + outFileName=tinkName; + prmName=prmFile; + readGeom=readG; + readOmega=readW; + + useGuess = false; + guessCarts = initCart; + Particle part; + for(int i=0; i > CoordUtil::normalModeToCart(vector part) { -// Really converts any part to cartesians (normal or already cartesian) - vector< vector > carts(initCart); -// for(int i=0; i<(int)initCart.size(); i++) { -// carts.push_back(initCart[i]); -// } -//DES Temp: -/* - cout << "DES: normConst" << endl; - for(int i=0; i overlap; - double dot = 0.0; - for(int n=0; nfragments.size(); ++f) { //TODO: remove fragment loop here... + double *Z = workingMol->fragments[f]->g_Z_pointer(); + double **geom = workingMol->fragments[f]->g_geom_pointer(); + + for (int i=0; ifragments[f]->g_natom(); ++i) { + Z[i] = atomStrToInt(atomType[cnt]); + for (int xyz=0; xyz<3; ++xyz) { + geom[i][xyz] = initCart[i][xyz]; + } + ++cnt; + } + //workingMol->fragments[f]->set_default_masses(); +// for(int i=0; i<3; i++) { +// cout << "DES: test mass = " << workingMol->fragments[f]->mass[i] << endl; +// } + } + opt::outfile=stdout; + //workingMol->update_connectivity_by_distances(); +// DES: set connectivity ourselves! + for(int i=0; ifragments[0]->connectivity[i][j] = false; + } + } + for(int i=0; ifragments[0]->connectivity[i][connectivity[i][j]-1] = true; + } + } +// for(int i=0; ifragments[0]->connectivity[i][j] << "\t"; +// } +// cout << endl; +// } + workingMol->fragmentize(); +// DES TODO: get rid of this if not using inertia_tensor + for (int f=0; ffragments.size(); ++f) { + workingMol->fragments[f]->set_default_masses(); + workingMol->fragments[f]->print_geom(stdout); + } +// DES: fragment_mode=simple: + //workingMol->add_intrafragment_simples_by_connectivity(); +// DES: fragment_mode=multi: + //workingMol->update_connectivity_by_distances(); + workingMol->add_intrafragment_simples_by_connectivity(); + //workingMol->add_interfragment(); + workingMol->print_connectivity(stdout); + //workingMol->print_intcos(stdout); //Fuller report + //workingMol->print_intco_dat(stdout); + if(workingMol->g_nfragment() > 1) { + cout << "---Interfragment Internal---" << endl; + cout << "Adding " << (workingMol->g_nfragment()-1)*3 << " fragment translations" << endl; + cout << "Adding " << workingMol->g_nfragment()*3 << " fragment rotations" << endl; + } + //double ** bArray = workingMol->fragments[0]->compute_B(); + double ** bArray = workingMol->compute_B(); + int nPrimInt = workingMol->g_nintco(); + equibBMat = arma::mat(nPrimInt,numPart*3); + for(int i=0; i< nPrimInt; i++) { + for(int j=0; jg_nfragment() +// workingMol->fragments[f]->globalIndex[i] gets index of ith atom in fth frag + + arma::vec bCol; + //equibBMat.print("preB"); + double alpha, sinT, cosT, massAB; + //fragExtraB = arma::mat(0,nPart*3); +//Add cartessians 3*nfrag displacements +/* Non COM preserving + for(int f=0; fg_nfragment(); f++) { + alpha = 1/sqrt(double(workingMol->g_nfragment())); + for(int j=0; j<3; j++) { + bCol = arma::vec(3*numPart,arma::fill::zeros); + for(int i=0; ifragments[f]->g_natom(); i++) { + bCol(3*workingMol->fragments[f]->globalIndex[i] + j) += alpha; } + fragExtraB = arma::join_cols(fragExtraB,bCol.t()); } - overlap.push_back(dot); - dot = 0.0; } - } - cout << "DES: Overlap matrix" << endl; - for(int n=0; ng_nfragment()-1; f++) { + //for(int f=0; fg_nfragment(); f++) { + massAB=0.0; + for(int i=0; ifragments[f]->g_natom(); i++) { + massAB += atomMass(workingMol->fragments[f]->globalIndex[i]); + } + alpha = totalMass - massAB; + massAB /= alpha; + alpha=1/sqrt(workingMol->fragments[f]->g_natom()+massAB*massAB*(numPart-workingMol->fragments[f]->g_natom())); + for(int j=0; j<3; j++) { + bCol = arma::vec(3*numPart,arma::fill::zeros); + for(int i=0; ifragments[f]->g_natom(); i++) { + bCol(3*workingMol->fragments[f]->globalIndex[i] + j) = alpha * atomMass(workingMol->fragments[f]->globalIndex[i]); + //bCol(3*workingMol->fragments[f]->globalIndex[i] + j) = alpha; + } + fragExtraB = arma::join_cols(fragExtraB,bCol.t()); + } } - cout << endl; - } - exit(-1); +//Add 3*nfrag rotations +// alpha is set to norm of + if(workingMol->g_nfragment()>1) { + double * fragCOM; + for(int f=0; fg_nfragment(); f++) { + fragCOM = workingMol->fragments[f]->com(); + //for(int j=0;j<3;j++) fragCOM[j] = 0.0; + //for(int j=0;j<3;j++) cout << "DES: COM = " << fragCOM[j] << endl; + for(int j=0; j<3; j++) { + bCol = arma::vec(3*numPart,arma::fill::zeros); +/* Old angle based (rather than tangent) + alpha=0; + for(int k=0; k<2; k++) { + int tempk = (k+j)%3; + for(int i=0; ifragments[f]->g_natom(); i++) { + alpha += (initCart[workingMol->fragments[f]->globalIndex[i]][tempk]-fragCOM[tempk])*(initCart[workingMol->fragments[f]->globalIndex[i]][tempk]-fragCOM[tempk]); + } + } + cosT = 1.0/alpha; + sinT = sqrt(2.0*alpha-1.0)/alpha; + for(int i=0; ifragments[f]->g_natom(); i++) { + bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+1)%3) = cosT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) - sinT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]) * atomMass(workingMol->fragments[f]->globalIndex[i]); + bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+2)%3) = sinT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) + cosT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]) * atomMass(workingMol->fragments[f]->globalIndex[i]); + //bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+1)%3) = cosT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) - sinT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]) / atomMass(workingMol->fragments[f]->globalIndex[i]); + //bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+2)%3) = sinT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) + cosT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]) / atomMass(workingMol->fragments[f]->globalIndex[i]); + //bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+1)%3) = cosT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) - sinT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]); + //bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+2)%3) = sinT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) + cosT*(initCart[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]); + } + //fragExtraB = arma::join_cols(fragExtraB,bCol.t()); */ + for(int i=0; ifragments[f]->g_natom(); i++) { + bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+1)%3) = (initCart[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]) * atomMass(workingMol->fragments[f]->globalIndex[i]); + bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+2)%3) = -(initCart[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) * atomMass(workingMol->fragments[f]->globalIndex[i]); + } + //DES Temp prim: + equibBMat = arma::join_cols(equibBMat,bCol.t()); + nPrimInt++; + } + opt::free_array(fragCOM); + } + } + +//DES Temp prim: + equibBMat = arma::join_cols(equibBMat,fragExtraB); + nPrimInt += 3*(workingMol->g_nfragment()-1); + //nPrimInt += 3*workingMol->g_nfragment(); + //equibBMat.print("postB"); -// For Normal modes into Cartesians in Angstroms - if(part[0].pos.size()==1) { +//DES: Project out global rotations/translations because of fragment motions +//TODO: This will crash on linear molecules! + //arma::mat projector(3*numPart,3*numPart,arma::fill::zeros); + arma::mat projector,projVecs,tempMat; + arma::vec tempVec; + arma::vec totalCOM(3,arma::fill::zeros); + for(int i=0; i > carts(initCart); + //arma::vec step(nPrimInt); + vector step(numModes,0.0); + for(int n=0; n<21; n++) { + //for(int n=0; n<10; n++) { + //step[6] = 0.04*double(n+1)/0.52918; + step[61] = 0.04*double(-10+n)/0.52918; + //cout << "Step is " << step[0] << endl; + carts = normalModeToCart(step); + cout << numPart << endl; + cout << endl; + for(int k=0; k > CoordUtil::normalModeToCart(vector modes) { + vector partVec; + Particle part; + for(int i=0; i< modes.size(); i++) { + part = Particle(modes[i],1); + partVec.push_back(part); + } + return normalModeToCart(partVec); +} + +vector< vector > CoordUtil::normalModeToCart(vector part) { +// Really converts any part to cartesians (normal or already cartesian) + vector< vector > carts; + //vector< vector > carts(initCart); + +// For Normal modes into Cartesians in Angstroms + if(part[0].pos.size()==1 && !internals) { + carts = initCart; for(int j=0; jset_geom_array(geomArray); + + for(int i=0; ig_nintco(); + arma::mat bTemp(nPrimInt,numPart*3); + double ** bArray = workingMol->compute_B(); + for(int i=0; i< nPrimInt; i++) { + for(int j=0; jg_nfragment()>1) { + arma::vec bCol; + //double alpha,sinT,cosT; + double * fragCOM; + for(int f=0; fg_nfragment(); f++) { + fragCOM = workingMol->fragments[f]->com(); + //for(int j=0;j<3;j++) cout << "DES: COM = " << fragCOM[j] << endl;; + for(int j=0; j<3; j++) { + //alpha=0; + bCol = arma::vec(3*numPart,arma::fill::zeros); + for(int i=0; ifragments[f]->g_natom(); i++) { + bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+1)%3) = (carts[workingMol->fragments[f]->globalIndex[i]][(j+2)%3]-fragCOM[(j+2)%3]) * atomMass(workingMol->fragments[f]->globalIndex[i]); + bCol(3*workingMol->fragments[f]->globalIndex[i] + (j+2)%3) = -(carts[workingMol->fragments[f]->globalIndex[i]][(j+1)%3]-fragCOM[(j+1)%3]) * atomMass(workingMol->fragments[f]->globalIndex[i]); + } + //DES Temp prim: + bTemp = arma::join_cols(bTemp,bCol.t()); + nPrimInt++; + } + opt::free_array(fragCOM); + } + } +// TODO: recalculate translations here +//DES Temp prim: + bTemp = arma::join_cols(bTemp,fragExtraB); + nPrimInt += 3*(workingMol->g_nfragment()-1); + //nPrimInt += 3*(workingMol->g_nfragment()); + //bTemp.print("bTemp in step"); + + bTemp -= bTemp * projector; + + bTemp = delocIntCos.t()*arma::normalise(bTemp,2,1); + //bTemp = arma::normalise(sqrtInvMass*arma::pinv(bTemp*sqrtInvMass)); + bTemp = sqrtInvMass*arma::pinv(bTemp*sqrtInvMass); + //Overwriting bTemp with deltaCart +//DES Temp prim: + bTemp = arma::normalise(bTemp*equibBMat*internalModes)*step / double(numSteps) * 0.52918; + //bTemp = arma::normalise(bTemp)*step / double(numSteps) * 0.52918; //For primitives only + //bTemp = internalModes*step / double(numSteps) * 0.52918; + //bTemp = equibBInv*arma::diagmat(wMat)*bTemp*internalModes*step / double(numSteps) * 0.52918; + //bTemp = internalModes*arma::diagmat(wMat)*bTemp*equibBInv*step / double(numSteps) * 0.52918; + for(int j=0; jset_geom_array(geomArray); + +// DES Temp: stepCheck +// stepCheck += arma::norm(bTemp,"fro"); +// cout << "DES: step " << n+1 << " =" << arma::norm(bTemp,"fro") << endl; + + } +// DES Temp: stepCheck +// cout << "DES: stepCheck = " << stepCheck << endl; + } +// DES: Save coords for reading in next time + guessCarts = carts; + guessPart = part; + useGuess=false; + } // For cartesian coordinates - else if(part[0].pos.size()==3) { - cout << "I shouldn't be here in CoordUtil" << endl; - for(int j=0; j > CoordUtil::normalModeToCart(vector part) { } vector CoordUtil::cartToNormalMode(vector< vector > cart) { - vector nmodes; + vector nmodes; // *** Should only be called by V_QChem at the moment *** // For cartesians in Angstroms into normal modes /* Old way needed normConstant and masses @@ -159,34 +678,196 @@ vector CoordUtil::cartToNormalMode(vector< vector > cart) { //arma::cube armaModes = arma::conv_to::from(normModes); arma::vec armaCart(numPart*dim); arma::vec armaVecs(numModes); - if(armaInvModes.is_empty()) { - arma::mat armaModes(numPart*dim,numModes); + if(internalModes.is_empty()) { + internalModes = arma::mat(numPart*dim,numModes); for(int j=0; j >::from(armaVecs); return nmodes; } +void CoordUtil::MakeScalingVec (CoordUtil* otherCoords) { + arma::mat alpha; + if(armaInvModes.is_empty()) { + armaInvModes = pinv(internalModes); + } + if(otherCoords->internalModes.is_empty()) { + otherCoords->internalModes=arma::mat(dim*numPart,numModes); + for(int j=0; jinternalModes(dim*j+k,i) = otherCoords->normModes[i][j][k]; + } + } + } + } + +// (internalModes.t()*internalModes).print("mode.T*modes"); +// (otherCoords->internalModes.t()*otherCoords->internalModes).print("mode.T*modes"); +// (internalModes.t()*sqrtInvMass*sqrtInvMass*internalModes).print("mode.T*mass-1*modes"); +// (otherCoords->internalModes.t()*otherCoords->sqrtInvMass*otherCoords->sqrtInvMass*otherCoords->internalModes).print("otherMode mode.T*mass-1*modes"); +// (internalModes*internalModes.t()).print("mode*modes.T"); +// exit(-1); + +//DES: Project out global rotations/translations +//TODO: This will crash on linear fragments! + //arma::mat projector(3*numPart,3*numPart,arma::fill::zeros); + arma::mat projector,projVecs,tempMat; + arma::vec tempVec; + arma::vec totalCOM(3,arma::fill::zeros); + for(int i=0; iinternalModes; + //alpha.print("alphaMat"); + //(alpha.t()*alpha).print("aT.a"); + alpha = arma::square(alpha); + arma::vec tempOmega(numModes,arma::fill::zeros); + for(int i=0; ireducedMass[i] * otherCoords->omega[i] * otherCoords->omega[i]; + } + scalingVec = arma::sqrt(tempOmega/alpha.t()); + + scalingVec.print("ScalingVec"); + //exit(-1); +} + +void CoordUtil::MatchModes (CoordUtil* matchCoords) { + arma::mat S(numModes,numModes,arma::fill::zeros); + arma::mat absS(numModes,numModes); + for(int i=0; inormModes[ip][j][k]; + } + } + } + } + //S.print("S"); + arma::uword row; + arma::uword col; + arma::vec overlap(numModes,arma::fill::zeros); + arma::uvec order(numModes,arma::fill::zeros); + for(int i=0; iomega[i] << endl; + } + if(overlap(i) < 0.0) { + for(int j=0; jscaleGeom = scaleGeom; return newCoords; } @@ -247,3 +928,61 @@ void CoordUtil::initMass() { atomToMass["Xe"] = 131.293; atomToMass["Cs"] = 132.9055; } + +int CoordUtil::atomStrToInt(string atomStr) { +if ("H"==atomStr) return 1 ; +if ("He"==atomStr) return 2 ; +if ("Li"==atomStr) return 3 ; +if ("Be"==atomStr) return 4 ; +if ("B"==atomStr) return 5 ; +if ("C"==atomStr) return 6 ; +if ("N"==atomStr) return 7 ; +if ("O"==atomStr) return 8 ; +if ("F"==atomStr) return 9 ; +if ("Ne"==atomStr) return 10 ; +if ("Na"==atomStr) return 11 ; +if ("Mg"==atomStr) return 12 ; +if ("Al"==atomStr) return 13 ; +if ("Si"==atomStr) return 14 ; +if ("P"==atomStr) return 15 ; +if ("S"==atomStr) return 16 ; +if ("Cl"==atomStr) return 17 ; +if ("K"==atomStr) return 18 ; +if ("Ar"==atomStr) return 19 ; +if ("Ca"==atomStr) return 20 ; +if ("Sc"==atomStr) return 21 ; +if ("Ti"==atomStr) return 22 ; +if ("V"==atomStr) return 23 ; +if ("Cr"==atomStr) return 24 ; +if ("Mn"==atomStr) return 25 ; +if ("Fe"==atomStr) return 26 ; +if ("Ni"==atomStr) return 27 ; +if ("Co"==atomStr) return 28 ; +if ("Cu"==atomStr) return 29 ; +if ("Zn"==atomStr) return 30 ; +if ("Ga"==atomStr) return 31 ; +if ("Ge"==atomStr) return 32 ; +if ("As"==atomStr) return 33 ; +if ("Se"==atomStr) return 34 ; +if ("Br"==atomStr) return 35 ; +if ("Kr"==atomStr) return 36 ; +if ("Rb"==atomStr) return 37 ; +if ("Sr"==atomStr) return 38 ; +if ("Y"==atomStr) return 39 ; +if ("Zr"==atomStr) return 40 ; +if ("Nb"==atomStr) return 41 ; +if ("Mo"==atomStr) return 42 ; +if ("Tc"==atomStr) return 43 ; +if ("Ru"==atomStr) return 44 ; +if ("Rh"==atomStr) return 45 ; +if ("Pd"==atomStr) return 46 ; +if ("Ag"==atomStr) return 47 ; +if ("Cd"==atomStr) return 48 ; +if ("In"==atomStr) return 49 ; +if ("Sn"==atomStr) return 50 ; +if ("Sb"==atomStr) return 51 ; +if ("I"==atomStr) return 52 ; +if ("Te"==atomStr) return 53 ; +if ("Xe"==atomStr) return 54 ; +if ("Cs"==atomStr) return 55 ; +} diff --git a/CoordUtil.h b/CoordUtil.h index 9a42b13..15f4610 100644 --- a/CoordUtil.h +++ b/CoordUtil.h @@ -15,25 +15,34 @@ #include #include #include "armadillo" +#include "optking/molecule.h" using namespace std; class CoordUtil { public: CoordUtil(); - CoordUtil(int, int, vector< vector< vector > >, vector, vector, vector< vector >, vector, vector, vector< vector >, string, string,bool,bool); + CoordUtil(int, int, bool, vector< vector< vector > >, vector, vector, vector< vector >, vector, vector, vector< vector >, string, string,bool,bool); virtual ~CoordUtil(); + void initInternals(); vector< vector > normalModeToCart(vector); + vector< vector > normalModeToCart(vector); //Inefficient, for debug vector cartToNormalMode(vector< vector >); + void MatchModes(CoordUtil*); + void MakeScalingVec(CoordUtil*); void initMass(); + int atomStrToInt(string); CoordUtil* Clone(); + bool useGuess; + bool internals; bool readOmega; bool readGeom; + bool scaleGeom; int numModes; int numPart; int dim; - std::string tinkerName; + std::string outFileName; std::string prmName; map atomToMass; vector atomType; @@ -43,8 +52,20 @@ class CoordUtil { vector omega; vector< vector > connectivity; vector< vector > initCart; - vector< vector< vector > > normModes; + vector< vector > guessCarts; + vector guessPart; + vector< vector< vector > > normModes; //TODO: remove this in favor of armaModes + arma::vec scalingVec; + arma::vec atomMass; + arma::mat fragExtraB; + arma::mat internalModes; arma::mat armaInvModes; + arma::mat sqrtInvMass; //TODO: Don't really need this as class data + //arma::mat equibBInv; + arma::mat equibBMat; + arma::mat delocIntCos; + //arma::mat wMat; // Weight matrix to normalize equibBInv, not sure if this is right... + opt::MOLECULE * workingMol; }; #endif /* COORDUTIL_H_ */ diff --git a/Est_AutoCorr.cpp b/Est_AutoCorr.cpp new file mode 100644 index 0000000..4af7268 --- /dev/null +++ b/Est_AutoCorr.cpp @@ -0,0 +1,132 @@ +/* + * Est_AutoCorr.cpp + * + * Created on: March 3, 2015 + * Author: dstuck + */ + +#include "Est_AutoCorr.h" +#include "armadillo" + +Est_AutoCorr::Est_AutoCorr() { +} + +Est_AutoCorr::Est_AutoCorr(int maxH) : maxHist(maxH) { + //hist = new deque(); + //totalStats = Stats(); + Stats tempStats = Stats(); + for(int i=0; i(); + hist.clear(); + nSamples = 0; + +} + +void Est_AutoCorr::AddVal(double newVal) { +//Add val to history + hist.push_front(newVal); + if(hist.size()>maxHist) { + hist.pop_back(); + } + nSamples++; + + totalStats.AddVal(newVal); + double newMean = totalStats.GetMean(); + newVal -= newMean; + int count=0; + for(deque::iterator iter=hist.begin(); iter!=hist.end(); iter++) { + corrStats[count].AddVal((*iter-newMean) * newVal); + count++; + } +} + +vector Est_AutoCorr::GetCorr() { + if(nSamples corrFunc (maxHist, 0.0); + //double var = totalStats.GetVariance(); + double var = corrStats[0].GetMean()/double(nSamples); + //var /= min(maxHist,nSamples); +// cout << "totalStats.GetVariance() =" << totalStats.GetVariance() << endl; +// cout << "corrStats[0].GetVariance() = " << corrStats[0].GetVariance() << endl; +// cout << "var = " << var << endl; +// cout << "corrStats[0] mean = " << corrStats[0].GetMean() << endl;; + for(int i=0; i GetCorr(); + double GetTau(); + + int maxHist; + int nSamples; + deque hist; + Stats totalStats; + vector corrStats; +}; + +#endif /* EST_AUTOCORR_H_ */ diff --git a/Makefile b/Makefile index 8588271..82918a5 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,17 @@ #CXX=icpc #CXX=g++ #CXXFLAGS=-O0 -g $(INCLUDES) -CXXFLAGS=-O0 -g -DDEBUG -F77FLAGS=-cxxlib -nofor-main -CSOURCES := $(wildcard *.cpp) +ARMAFLAGS=-L/Users/dstuck/tools/armadillo -I/Users/dstuck/tools/armadillo/include -larmadillo -framework Accelerate +#CXXFLAGS=-O0 -g -DDEBUG +#F77FLAGS=-cxxlib -nofor-main +CXXFLAGS=-O0 -g -DDEBUG $(ARMAFLAGS) +F77FLAGS=-cxxlib -nofor-main -Xlinker -no_compact_unwind -framework Accelerate +#CSOURCES := $(wildcard *.cpp) +CSOURCES := $(wildcard *.cpp,optking/*.cpp) COBJECTS := $(patsubst %.cpp,%.o,$(CSOURCES)) CDEPFILES := $(patsubst %.cpp,%.d,$(CSOURCES)) #LIBTINKER := -L tinker/libtinker.a -LIBTINKER := tinker/active.o tinker/analysis.o tinker/angles.o tinker/attach.o tinker/basefile.o tinker/beeman.o tinker/bicubic.o tinker/bitors.o tinker/bonds.o tinker/born.o tinker/bounds.o tinker/bussi.o tinker/calendar.o tinker/center.o tinker/chkpole.o tinker/chkring.o tinker/chkxyz.o tinker/cholesky.o tinker/clock.o tinker/cluster.o tinker/column.o tinker/command.o tinker/connect.o tinker/connolly.o tinker/control.o tinker/cspline.o tinker/cutoffs.o tinker/deflate.o tinker/delete.o tinker/diagq.o tinker/diffeq.o tinker/eangang.o tinker/eangang1.o tinker/eangang2.o tinker/eangang3.o tinker/eangle.o tinker/eangle1.o tinker/eangle2.o tinker/eangle3.o tinker/ebond.o tinker/ebond1.o tinker/ebond2.o tinker/ebond3.o tinker/ebuck.o tinker/ebuck1.o tinker/ebuck2.o tinker/ebuck3.o tinker/echarge.o tinker/echarge1.o tinker/echarge2.o tinker/echarge3.o tinker/echgdpl.o tinker/echgdpl1.o tinker/echgdpl2.o tinker/echgdpl3.o tinker/edipole.o tinker/edipole1.o tinker/edipole2.o tinker/edipole3.o tinker/egauss.o tinker/egauss1.o tinker/egauss2.o tinker/egauss3.o tinker/egeom.o tinker/egeom1.o tinker/egeom2.o tinker/egeom3.o tinker/ehal.o tinker/ehal1.o tinker/ehal2.o tinker/ehal3.o tinker/eimprop.o tinker/eimprop1.o tinker/eimprop2.o tinker/eimprop3.o tinker/eimptor.o tinker/eimptor1.o tinker/eimptor2.o tinker/eimptor3.o tinker/elj.o tinker/elj1.o tinker/elj2.o tinker/elj3.o tinker/embed.o tinker/emetal.o tinker/emetal1.o tinker/emetal2.o tinker/emetal3.o tinker/emm3hb.o tinker/emm3hb1.o tinker/emm3hb2.o tinker/emm3hb3.o tinker/empole.o tinker/empole1.o tinker/empole2.o tinker/empole3.o tinker/energy.o tinker/dstuckVibrate.o tinker/dstuckEnergy.o tinker/eopbend.o tinker/eopbend1.o tinker/eopbend2.o tinker/eopbend3.o tinker/eopdist.o tinker/eopdist1.o tinker/eopdist2.o tinker/eopdist3.o tinker/epitors.o tinker/epitors1.o tinker/epitors2.o tinker/epitors3.o tinker/erf.o tinker/erxnfld.o tinker/erxnfld1.o tinker/erxnfld2.o tinker/erxnfld3.o tinker/esolv.o tinker/esolv1.o tinker/esolv2.o tinker/esolv3.o tinker/estrbnd.o tinker/estrbnd1.o tinker/estrbnd2.o tinker/estrbnd3.o tinker/estrtor.o tinker/estrtor1.o tinker/estrtor2.o tinker/estrtor3.o tinker/etors.o tinker/etors1.o tinker/etors2.o tinker/etors3.o tinker/etortor.o tinker/etortor1.o tinker/etortor2.o tinker/etortor3.o tinker/eurey.o tinker/eurey1.o tinker/eurey2.o tinker/eurey3.o tinker/evcorr.o tinker/extra.o tinker/extra1.o tinker/extra2.o tinker/extra3.o tinker/fatal.o tinker/fft3d.o tinker/fftpack.o tinker/field.o tinker/final.o tinker/flatten.o tinker/freeunit.o tinker/geometry.o tinker/getint.o tinker/getkey.o tinker/getmol.o tinker/getmol2.o tinker/getnumb.o tinker/getpdb.o tinker/getprm.o tinker/getref.o tinker/getstring.o tinker/gettext.o tinker/getword.o tinker/getxyz.o tinker/ghmcstep.o tinker/gradient.o tinker/gradrgd.o tinker/gradrot.o tinker/groups.o tinker/grpline.o tinker/gyrate.o tinker/hessian.o tinker/hessrgd.o tinker/hessrot.o tinker/hybrid.o tinker/image.o tinker/impose.o tinker/induce.o tinker/inertia.o tinker/initatom.o tinker/initial.o tinker/initprm.o tinker/initres.o tinker/initrot.o tinker/insert.o tinker/invbeta.o tinker/invert.o tinker/jacobi.o tinker/kangang.o tinker/kangle.o tinker/katom.o tinker/kbond.o tinker/kcharge.o tinker/kdipole.o tinker/kewald.o tinker/kgeom.o tinker/kimprop.o tinker/kimptor.o tinker/kinetic.o tinker/kmetal.o tinker/kmpole.o tinker/kopbend.o tinker/kopdist.o tinker/korbit.o tinker/kpitors.o tinker/kpolar.o tinker/ksolv.o tinker/kstrbnd.o tinker/kstrtor.o tinker/ktors.o tinker/ktortor.o tinker/kurey.o tinker/kvdw.o tinker/lattice.o tinker/lbfgs.o tinker/lights.o tinker/makeint.o tinker/makeref.o tinker/makexyz.o tinker/maxwell.o tinker/mdinit.o tinker/mdrest.o tinker/mdsave.o tinker/mdstat.o tinker/mechanic.o tinker/merge.o tinker/molecule.o tinker/moments.o tinker/mutate.o tinker/nblist.o tinker/nextarg.o tinker/nexttext.o tinker/nose.o tinker/nspline.o tinker/number.o tinker/numeral.o tinker/numgrad.o tinker/ocvm.o tinker/openend.o tinker/optsave.o tinker/orbital.o tinker/orient.o tinker/orthog.o tinker/overlap.o tinker/picalc.o tinker/pmestuff.o tinker/pmpb.o tinker/polymer.o tinker/precise.o tinker/pressure.o tinker/prmkey.o tinker/promo.o tinker/prtdyn.o tinker/prterr.o tinker/prtint.o tinker/prtmol2.o tinker/prtpdb.o tinker/prtprm.o tinker/prtseq.o tinker/prtxyz.o tinker/quatfit.o tinker/random.o tinker/rattle.o tinker/readdyn.o tinker/readgau.o tinker/readint.o tinker/readmol.o tinker/readmol2.o tinker/readpdb.o tinker/readprm.o tinker/readseq.o tinker/readxyz.o tinker/replica.o tinker/respa.o tinker/rgdstep.o tinker/rings.o tinker/rmsfit.o tinker/rotlist.o tinker/rotpole.o tinker/sdstep.o tinker/search.o tinker/server.o tinker/shakeup.o tinker/sigmoid.o tinker/sktstuff.o tinker/sort.o tinker/square.o tinker/suffix.o tinker/surface.o tinker/surfatom.o tinker/switch.o tinker/temper.o tinker/tncg.o tinker/torphase.o tinker/torque.o tinker/torsions.o tinker/trimtext.o tinker/unitcell.o tinker/verlet.o tinker/version.o tinker/volume.o tinker/xyzatm.o tinker/zatom.o +LIBTINKER := tinker/active.o tinker/analysis.o tinker/angles.o tinker/attach.o tinker/basefile.o tinker/beeman.o tinker/bicubic.o tinker/bitors.o tinker/bonds.o tinker/born.o tinker/bounds.o tinker/bussi.o tinker/calendar.o tinker/center.o tinker/chkpole.o tinker/chkring.o tinker/chkxyz.o tinker/cholesky.o tinker/clock.o tinker/cluster.o tinker/column.o tinker/command.o tinker/connect.o tinker/connolly.o tinker/control.o tinker/cspline.o tinker/cutoffs.o tinker/deflate.o tinker/delete.o tinker/diagq.o tinker/diffeq.o tinker/eangang.o tinker/eangang1.o tinker/eangang2.o tinker/eangang3.o tinker/eangle.o tinker/eangle1.o tinker/eangle2.o tinker/eangle3.o tinker/ebond.o tinker/ebond1.o tinker/ebond2.o tinker/ebond3.o tinker/ebuck.o tinker/ebuck1.o tinker/ebuck2.o tinker/ebuck3.o tinker/echarge.o tinker/echarge1.o tinker/echarge2.o tinker/echarge3.o tinker/echgdpl.o tinker/echgdpl1.o tinker/echgdpl2.o tinker/echgdpl3.o tinker/edipole.o tinker/edipole1.o tinker/edipole2.o tinker/edipole3.o tinker/egauss.o tinker/egauss1.o tinker/egauss2.o tinker/egauss3.o tinker/egeom.o tinker/egeom1.o tinker/egeom2.o tinker/egeom3.o tinker/ehal.o tinker/ehal1.o tinker/ehal2.o tinker/ehal3.o tinker/eimprop.o tinker/eimprop1.o tinker/eimprop2.o tinker/eimprop3.o tinker/eimptor.o tinker/eimptor1.o tinker/eimptor2.o tinker/eimptor3.o tinker/elj.o tinker/elj1.o tinker/elj2.o tinker/elj3.o tinker/embed.o tinker/emetal.o tinker/emetal1.o tinker/emetal2.o tinker/emetal3.o tinker/emm3hb.o tinker/emm3hb1.o tinker/emm3hb2.o tinker/emm3hb3.o tinker/empole.o tinker/empole1.o tinker/empole2.o tinker/empole3.o tinker/energy.o tinker/dstuckVibrate.o tinker/dstuckOptimize.o tinker/dstuckEnergy.o tinker/eopbend.o tinker/eopbend1.o tinker/eopbend2.o tinker/eopbend3.o tinker/eopdist.o tinker/eopdist1.o tinker/eopdist2.o tinker/eopdist3.o tinker/epitors.o tinker/epitors1.o tinker/epitors2.o tinker/epitors3.o tinker/erf.o tinker/erxnfld.o tinker/erxnfld1.o tinker/erxnfld2.o tinker/erxnfld3.o tinker/esolv.o tinker/esolv1.o tinker/esolv2.o tinker/esolv3.o tinker/estrbnd.o tinker/estrbnd1.o tinker/estrbnd2.o tinker/estrbnd3.o tinker/estrtor.o tinker/estrtor1.o tinker/estrtor2.o tinker/estrtor3.o tinker/etors.o tinker/etors1.o tinker/etors2.o tinker/etors3.o tinker/etortor.o tinker/etortor1.o tinker/etortor2.o tinker/etortor3.o tinker/eurey.o tinker/eurey1.o tinker/eurey2.o tinker/eurey3.o tinker/evcorr.o tinker/extra.o tinker/extra1.o tinker/extra2.o tinker/extra3.o tinker/fatal.o tinker/fft3d.o tinker/fftpack.o tinker/field.o tinker/final.o tinker/flatten.o tinker/freeunit.o tinker/geometry.o tinker/getint.o tinker/getkey.o tinker/getmol.o tinker/getmol2.o tinker/getnumb.o tinker/getpdb.o tinker/getprm.o tinker/getref.o tinker/getstring.o tinker/gettext.o tinker/getword.o tinker/getxyz.o tinker/ghmcstep.o tinker/gradient.o tinker/gradrgd.o tinker/gradrot.o tinker/groups.o tinker/grpline.o tinker/gyrate.o tinker/hessian.o tinker/hessrgd.o tinker/hessrot.o tinker/hybrid.o tinker/image.o tinker/impose.o tinker/induce.o tinker/inertia.o tinker/initatom.o tinker/initial.o tinker/initprm.o tinker/initres.o tinker/initrot.o tinker/insert.o tinker/invbeta.o tinker/invert.o tinker/jacobi.o tinker/kangang.o tinker/kangle.o tinker/katom.o tinker/kbond.o tinker/kcharge.o tinker/kdipole.o tinker/kewald.o tinker/kgeom.o tinker/kimprop.o tinker/kimptor.o tinker/kinetic.o tinker/kmetal.o tinker/kmpole.o tinker/kopbend.o tinker/kopdist.o tinker/korbit.o tinker/kpitors.o tinker/kpolar.o tinker/ksolv.o tinker/kstrbnd.o tinker/kstrtor.o tinker/ktors.o tinker/ktortor.o tinker/kurey.o tinker/kvdw.o tinker/lattice.o tinker/lbfgs.o tinker/lights.o tinker/makeint.o tinker/makeref.o tinker/makexyz.o tinker/maxwell.o tinker/mdinit.o tinker/mdrest.o tinker/mdsave.o tinker/mdstat.o tinker/mechanic.o tinker/merge.o tinker/molecule.o tinker/moments.o tinker/mutate.o tinker/nblist.o tinker/nextarg.o tinker/nexttext.o tinker/nose.o tinker/nspline.o tinker/number.o tinker/numeral.o tinker/numgrad.o tinker/ocvm.o tinker/openend.o tinker/optsave.o tinker/orbital.o tinker/orient.o tinker/orthog.o tinker/overlap.o tinker/picalc.o tinker/pmestuff.o tinker/pmpb.o tinker/polymer.o tinker/precise.o tinker/pressure.o tinker/prmkey.o tinker/promo.o tinker/prtdyn.o tinker/prterr.o tinker/prtint.o tinker/prtmol2.o tinker/prtpdb.o tinker/prtprm.o tinker/prtseq.o tinker/prtxyz.o tinker/quatfit.o tinker/random.o tinker/rattle.o tinker/readdyn.o tinker/readgau.o tinker/readint.o tinker/readmol.o tinker/readmol2.o tinker/readpdb.o tinker/readprm.o tinker/readseq.o tinker/readxyz.o tinker/replica.o tinker/respa.o tinker/rgdstep.o tinker/rings.o tinker/rmsfit.o tinker/rotlist.o tinker/rotpole.o tinker/sdstep.o tinker/search.o tinker/server.o tinker/shakeup.o tinker/sigmoid.o tinker/sktstuff.o tinker/sort.o tinker/square.o tinker/suffix.o tinker/surface.o tinker/surfatom.o tinker/switch.o tinker/temper.o tinker/tncg.o tinker/torphase.o tinker/torque.o tinker/torsions.o tinker/trimtext.o tinker/unitcell.o tinker/verlet.o tinker/version.o tinker/volume.o tinker/xyzatm.o tinker/zatom.o # LDFLAGS=-L/opt/intel/Compiler/11.1/080/Frameworks/mkl/lib/em64t/ -lblas -L/usr/lib/libshell/ -lshell .PHONY: clean @@ -27,6 +31,6 @@ clean: $(CDEPFILES): %.d: %.cpp set -e; rm -f $@; \ - $(CXX) -M $< > $@.$$$$; \ + $(CXX) -M $(ARMAFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ diff --git a/PhysicsUtil.cpp b/PhysicsUtil.cpp index 5e3d23c..853f840 100644 --- a/PhysicsUtil.cpp +++ b/PhysicsUtil.cpp @@ -10,7 +10,8 @@ PhysicsUtil::PhysicsUtil() { // Makes sure it gets set numInit = -1; - numFrozModes = 0; + lowFrozModes = 0; + highFrozModes = 0; lambdaTI = 1.0; deltaAbInit = false; charge = 0; diff --git a/PhysicsUtil.h b/PhysicsUtil.h index 8a98013..afadd97 100644 --- a/PhysicsUtil.h +++ b/PhysicsUtil.h @@ -28,7 +28,8 @@ class PhysicsUtil { double morseDE; double morseAlpha; int numInit; - int numFrozModes; + int lowFrozModes; + int highFrozModes; double lambdaTI; bool deltaAbInit; int charge; diff --git a/Rho_HO.cpp b/Rho_HO.cpp index a9c910c..de5be04 100644 --- a/Rho_HO.cpp +++ b/Rho_HO.cpp @@ -7,7 +7,7 @@ #include "Rho_HO.h" -Rho_HO::Rho_HO(vector w, int nFrozModes) : omega(w), numFrozModes(nFrozModes) { +Rho_HO::Rho_HO(vector w, int nFrozModes, int hFrozModes) : omega(w), lowFrozModes(nFrozModes), highFrozModes(hFrozModes) { } Rho_HO::Rho_HO(double w, int N) { @@ -62,12 +62,17 @@ double Rho_HO::Estimate(vector slice1, vector slice2, double } double est = 0; - for(int j=0; j< numFrozModes; j++) { + for(int j=0; j< lowFrozModes; j++) { for(int k=0; k<(int)slice1[j].pos.size(); k++) { est += omega[j]/2.0/tanh(eps*(double)P*omega[j]); } } - for(int j=numFrozModes; j<(int)slice1.size(); j++) { + for(int j=(int)slice1.size()-highFrozModes; j<(int)slice1.size(); j++) { + for(int k=0; k<(int)slice1[j].pos.size(); k++) { + est += omega[j]/2.0/tanh(eps*(double)P*omega[j]); + } + } + for(int j=lowFrozModes; j<(int)slice1.size()-highFrozModes; j++) { for(int k=0; k<(int)slice1[j].pos.size(); k++) { est += omega[j]/2.0/tanh(eps*omega[j]); est += -slice1[j].mass*omega[j]*omega[j]/2.0/tanh(eps*omega[j])/sinh(eps*omega[j])*(slice1[j].pos[k]-slice2[j].pos[k])*(slice1[j].pos[k]-slice2[j].pos[k]); diff --git a/Rho_HO.h b/Rho_HO.h index 55ac530..c58089a 100644 --- a/Rho_HO.h +++ b/Rho_HO.h @@ -16,7 +16,7 @@ using namespace std; class Rho_HO: public Propagator { public: - Rho_HO(vector, int); + Rho_HO(vector, int, int=0); Rho_HO(double, int); virtual ~Rho_HO(); @@ -29,7 +29,8 @@ class Rho_HO: public Propagator { string GetType(); vector omega; - int numFrozModes; + int lowFrozModes; + int highFrozModes; }; #endif /* RHOHO_H_ */ diff --git a/Simulation.cpp b/Simulation.cpp index 11a21a4..0b6cb62 100644 --- a/Simulation.cpp +++ b/Simulation.cpp @@ -7,10 +7,10 @@ #include "Simulation.h" -Simulation::Simulation(string inFileName, string logFileName, string prmFile) { +Simulation::Simulation(string inFileName, string logFileName, string prmFile) : autoCorr(1000) { //******************************************************* -//* Default Parameters * +//* Default Parameters * //******************************************************* /* stepNum = 0; @@ -28,6 +28,8 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { maxSim = 1; bool readOmega = false; bool readGeom = false; + bool internalCoords = false; + bool scaleGeom = false; int nPart = 0; int pSlice = 0; int nMode; @@ -44,6 +46,7 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { // } // int a = 1; // Atomic number levyNum = 30; + levyModes = 0; numTI = 0; vector mass; vector atomType; @@ -143,6 +146,9 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { else if(lineTokens[0].find("levyNum") != std::string::npos) { levyNum = atoi(lineTokens[1].c_str()); } + else if(lineTokens[0].find("levyModes") != std::string::npos) { + levyModes = atoi(lineTokens[1].c_str()); + } else if(lineTokens[0].find("levyInit") != std::string::npos) { physicsParams->numInit = atoi(lineTokens[1].c_str()); } @@ -159,7 +165,13 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { physicsParams->morseAlpha = atof(lineTokens[1].c_str()); } else if(lineTokens[0].find("numFrozModes") != std::string::npos) { - physicsParams->numFrozModes = atof(lineTokens[1].c_str()); + physicsParams->lowFrozModes = atof(lineTokens[1].c_str()); + } + else if(lineTokens[0].find("lowFrozModes") != std::string::npos) { + physicsParams->lowFrozModes = atof(lineTokens[1].c_str()); + } + else if(lineTokens[0].find("highFrozModes") != std::string::npos) { + physicsParams->highFrozModes = atof(lineTokens[1].c_str()); } else if(lineTokens[0].find("numTI") != std::string::npos) { numTI=atoi(lineTokens[1].c_str()); @@ -180,6 +192,16 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { readGeom = true; } } + else if(lineTokens[0].find("internalCoords") != std::string::npos) { + if(atof(lineTokens[1].c_str())>0) { + internalCoords = true; + } + } + else if(lineTokens[0].find("scaleGeom") != std::string::npos) { + if(atof(lineTokens[1].c_str())>0) { + scaleGeom = true; + } + } else if(lineTokens[0].find("readOmega") != std::string::npos) { if(atof(lineTokens[1].c_str())>0) { readOmega = true; @@ -318,7 +340,10 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { cout << "omega dim = " << omega.size() << " but mass dim = " << mass.size() << endl; exit (-1); } - if(int(connectivity.size()) != nPart) { + if(nPart == 0) { + nPart = connectivity.size(); + } + else if(int(connectivity.size()) != nPart) { cout << "Error, number of atoms not equal to number of coordinates" << endl; cout << "connectivity dim = " << connectivity.size() << " but nPart = " << nPart << endl; exit (-1); @@ -330,6 +355,17 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { // TODO: Doesn't work for linear molecules! nMode = nPart*3-6; } + if(levyModes==0) { + levyModes = nMode - (physicsParams->lowFrozModes+physicsParams->highFrozModes); + } + else if(levyModes>nMode - (physicsParams->lowFrozModes+physicsParams->highFrozModes)) { + cout << "Error, total modes moved > number of modes!" << endl; + exit(-1); + } + if(physicsParams->lowFrozModes+physicsParams->highFrozModes > nMode) { + cout << "Error, total frozen modes > number of modes!" << endl; + exit(-1); + } coorDim = 1; // nMode = nPart; // coorDim = 3; @@ -380,7 +416,8 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { } */ - CoordUtil * coords = new CoordUtil(nMode, nPart, modes, omega, mass, initPos, atomType, paramType, connectivity, outName, prmFile, readGeom, readOmega); + CoordUtil * coords = new CoordUtil(nMode, nPart, internalCoords, modes, omega, mass, initPos, atomType, paramType, connectivity, outName, prmFile, readGeom, readOmega); + coords->scaleGeom = scaleGeom; sys = new TestSystem(pSlice, beta, coords, physicsParams); simStats = new Stats(); simPotStats = new Stats(); @@ -405,28 +442,42 @@ Simulation::Simulation(string inFileName, string logFileName, string prmFile) { logFile << (current->tm_mon+1) << "/" << (current->tm_mday) << "/" << (current->tm_year+1900) << " " << current->tm_hour << ":" << current->tm_min << ":" << current->tm_sec << endl; logFile << inFileName << endl; logFile << "Potential: " << sys->GetVType() << "\t Propagator: " << sys->GetRhoType() << endl; - logFile << "P: "<< pSlice << ", N: "<< nPart << ", Beta: " << beta << ", levyNum: " << levyNum << "\n" << "maxSim: " << maxSim << ", maxStep: " << maxStep << ", sampleFreq: " << sampleFreq << ", convFreq: " << convFreq << ", storeFreq: " << storeFreq << endl; -// TODO: check numfrozmodes <= modes - if(physicsParams->numFrozModes>0) { + logFile << "P: "<< pSlice << ", N: "<< nPart << ", Beta: " << beta << ", levyModes: " << levyModes << ", levyNum: " << levyNum << "\n" << "maxSim: " << maxSim << ", maxStep: " << maxStep << ", sampleFreq: " << sampleFreq << ", convFreq: " << convFreq << ", storeFreq: " << storeFreq << endl; + if(physicsParams->lowFrozModes+physicsParams->highFrozModes>0) { logFile << "Frozen Modes:" << endl; } - for(int i=0; inumFrozModes; i++) { + for(int i=0; ilowFrozModes; i++) { + logFile << coords->omega[i]/0.00000455633 << "\t"; + if((i)%10==9) { + logFile << "\n"; + } + } + for(int i=(int)coords->omega.size()-physicsParams->highFrozModes; i<(int)coords->omega.size(); i++) { logFile << coords->omega[i]/0.00000455633 << "\t"; if((i)%10==9) { logFile << "\n"; } } - if(physicsParams->numFrozModes>0) { + if(physicsParams->lowFrozModes+physicsParams->highFrozModes>0) { logFile << endl; } logFile << "Active Modes:" << endl; - for(int i=physicsParams->numFrozModes; i<(int)coords->omega.size(); i++) { + for(int i=physicsParams->lowFrozModes; i<(int)coords->omega.size()-physicsParams->highFrozModes; i++) { logFile << coords->omega[i]/0.00000455633 << "\t"; - if((i-physicsParams->numFrozModes)%10==9) { + if((i-physicsParams->lowFrozModes)%10==9) { logFile << "\n"; } } logFile << endl; + if(!coords->readGeom) { + logFile << "DES: Coords after opt" << endl; + for(int j=0; jnumPart; j++) { + for(int k=0; k<3; k++) { + logFile << coords->initCart[j][k] << "\t"; + } + logFile << endl; + } + } // srand(time(NULL)); idum = new int; @@ -457,11 +508,12 @@ void Simulation::TakeStep(){ // rand(); vector x; // x.push_back(RandomNum::rangau(0,1,idum)); -// for(int n = 0; n < 2; n++){ - for(int n = 0; n < 4; n++){ +// for(int n = 0; n < 4; n++){ +// for(int n = 0; n < 3+levyModes; n++){ + for(int n = 0; n < levyModes+1; n++){ x.push_back(RandomNum::rand3(idum)); } - sys->Move(x, levyNum); + sys->Move(x, levyNum, levyModes); } bool Simulation::Check(){ @@ -492,13 +544,33 @@ void Simulation::Revert(){ } void Simulation::Sample(){ + if(stepNum < sampleStart) { + if(numTI==0) { +// If not TI use E + autoCorr.AddVal(sys->EstimatorE()); + } + else { + autoCorr.AddVal(sys->EstimatorV()); + } + } + if(stepNum == sampleStart/5) { + autoCorr.Reset(); + } + if(stepNum == sampleStart) { + autoCorr.GetTau(); +// vector corrFunc = autoCorr.GetCorr(); +// for(int i=0; i< corrFunc.size(); i++) { +// cout << i << "\t" << corrFunc[i] << endl; +// } +// exit(-1); + } if((stepNum > sampleStart)&&(stepNum%convFreq==0)){ convergenceStats->AddVal(sys->EstimatorE()); // cout << "Energy: " << sys->EstimatorE() << endl; } +// DES TODO: Don't estimate E if doing TI if((stepNum > sampleStart)&&(stepNum%sampleFreq==0)) { energyStats->AddVal(sys->EstimatorE()); -//DES Temp: if(!sys->GetPhysics()->isDeltaAI()) { potentialStats->AddVal(sys->EstimatorV()); } @@ -511,11 +583,14 @@ void Simulation::Sample(){ // comboStats->AddVal(sys->EstimatorV()*sys->EstimatorE()); vector< vector > part = sys->GetParticle(); /* xstats + double tempX = 0.0; for(int i=0; i<(int)part.size(); i++) { for(int j=0; j<(int)part[0].size(); j++) { - xStats->AddVal(part[i][j].pos[0]-part[(i+1)%part.size()][j].pos[0]); + tempX += part[i][j].pos[0]; + //xStats->AddVal(part[i][j].pos[0]-part[(i+1)%part.size()][j].pos[0]); } } + xStats->AddVal(tempX/part.size()/part[0].size()); */ // To restore function uncomment posFile above // if((stepNum-sampleStart)/(double)sampleFreq < 5000) { @@ -771,6 +846,18 @@ void Simulation::GetGaussianQuad(int nti, vector& points, vector points.push_back(0.861136); weights.push_back(0.34785); } + else if(nti==5) { + weights.push_back(0.2369268850561891); + points.push_back(-0.9061798459386640); + weights.push_back(0.4786286704993665); + points.push_back(-0.5384693101056831); + weights.push_back(0.5688888888888889); + points.push_back(0.0000000000000000); + weights.push_back(0.4786286704993665); + points.push_back(0.5384693101056831); + weights.push_back(0.2369268850561891); + points.push_back(0.9061798459386640); + } else { cout << "ERROR: nti > 4 not implemented yet in Simulation::GetGaussianQuad" << endl; exit(-1); diff --git a/Simulation.h b/Simulation.h index 53f7743..24e8f8b 100644 --- a/Simulation.h +++ b/Simulation.h @@ -15,6 +15,7 @@ #include #include "System.h" #include "Stats.h" +#include "Est_AutoCorr.h" #include "TestSystem.h" #include "Random.h" #include "CoordUtil.h" @@ -22,54 +23,56 @@ using namespace std; class Simulation { - public: - Simulation(string, string, string); - virtual ~Simulation(); - void TakeStep(); - bool Check(); - void Update(); - void Revert(); - void Sample(); - void Run(); - void FinalPrint(); //TODO: Remove - void WritePosToFile(); - void Log(); - void FinalLog(); - void TILog(double,double); - void Store(); - void Tokenize(const string&, vector&, const string& = " "); - void GetGaussianQuad(int, vector&, vector&); - void GetLobattoQuad(int, vector&, vector&); - void GetLinearQuad(int, vector&, vector&); + public: + Simulation(string, string, string); + virtual ~Simulation(); + void TakeStep(); + bool Check(); + void Update(); + void Revert(); + void Sample(); + void Run(); + void FinalPrint(); //TODO: Remove + void WritePosToFile(); + void Log(); + void FinalLog(); + void TILog(double,double); + void Store(); + void Tokenize(const string&, vector&, const string& = " "); + void GetGaussianQuad(int, vector&, vector&); + void GetLobattoQuad(int, vector&, vector&); + void GetLinearQuad(int, vector&, vector&); - int maxSim; - int stepNum; //TODO: Remove - int maxStep; - int sampleStart; - int sampleFreq; - int convFreq; - int storeFreq; - int levyNum; - int numTI; - int * idum; + int maxSim; + int stepNum; //TODO: Remove + int maxStep; + int sampleStart; + int sampleFreq; + int convFreq; + int storeFreq; + int levyNum; + int levyModes; + int numTI; + int * idum; // int * idum2; - double beta; //TODO: Remove - double epsTemp; - double stepSize; - std::string posFileName; - std::string outFileName; - ofstream posFile; - ofstream logFile; - Stats * simStats; - Stats * simPotStats; + double beta; //TODO: Remove + double epsTemp; + double stepSize; + std::string posFileName; + std::string outFileName; + ofstream posFile; + ofstream logFile; + Est_AutoCorr autoCorr; + Stats * simStats; + Stats * simPotStats; // Stats * simComboStats; //TODO: Remove - Stats * energyStats; - Stats * potentialStats; + Stats * energyStats; + Stats * potentialStats; // Stats * comboStats; - Stats * convergenceStats; - Stats * acceptanceStats; -// Stats * xStats; //TODO: Remove - System * sys; + Stats * convergenceStats; + Stats * acceptanceStats; + Stats * xStats; //TODO: Remove + System * sys; //DES Temp: // ofstream vFile; //TODO: Remove diff --git a/System.h b/System.h index 3f2f359..09ab26a 100644 --- a/System.h +++ b/System.h @@ -17,7 +17,7 @@ class System { virtual ~System(); // virtual void CalcEnergy() = 0; //Used internally // virtual void CalcPotential() = 0; //Used internally - virtual void Move(vector, int) = 0; + virtual void Move(vector, int, int levyPart = 1) = 0; virtual void Forget() = 0; virtual void Undo() = 0; virtual void Reset() = 0; diff --git a/TestSystem.cpp b/TestSystem.cpp index 2cbf2b5..93a386b 100644 --- a/TestSystem.cpp +++ b/TestSystem.cpp @@ -22,6 +22,7 @@ TestSystem::TestSystem(int pSlice, double beta, CoordUtil* coords, PhysicsUtil * vector< vector > part_init(P,vector(N)); part = part_init; oldPart = part_init; + upToDate.resize(P, true); sliceV.resize(P, 0.0); oldSliceV.resize(P, 0.0); @@ -72,13 +73,18 @@ TestSystem::TestSystem(int pSlice, double beta, CoordUtil* coords, PhysicsUtil * cout << "Error in selecing V" << endl; exit(-1); } + coords->initInternals(); if(phys->isDeltaAI()) { V2 = new V_QChem(qchemCoords,coords,eps,beta,physics->charge,physics->multiplicity); + qchemCoords->initInternals(); + if(coords->scaleGeom) { + qchemCoords->MakeScalingVec(coords); + } } if(!physics->rhoType.compare("Rho_HO")) { - rho = new Rho_HO(coords->omega,physics->numFrozModes); + rho = new Rho_HO(coords->omega,physics->lowFrozModes,physics->highFrozModes); } else if(!physics->rhoType.compare("Rho_Free")) { rho = new Rho_Free(); @@ -98,6 +104,14 @@ TestSystem::TestSystem(int pSlice, double beta, CoordUtil* coords, PhysicsUtil * oldPart[i][j].mass = coords->reducedMass[j]; } } + vector< vector > cart0; + cart0 = V->GetCoordUtil()->initCart; + for(int i=0; iGetCoordUtil()->initCart; + newCarts[i] = oldCarts[i]; + } + +//// DES Test( PES Scan +// //double scanBegin = -0.2; +// //double scanEnd = 0.2; +// double scanBegin = -0.2; //Bohr, so twice that in Angrstrom +// double scanEnd = 0.2; +// int scanSteps = 400; +// double curX = 0.0; +// int pickedMode = 0; +// //int pickedMode2 = 3; +//// Print out frequencies +// cout << " \tw_Tinker\t\tw_QChem" << endl; +// for(int i=0;iGetCoordUtil()->omega[i] << "\t" << V2->GetCoordUtil()->omega[i] << endl; +// } +//// Print out masses +// cout << " \tm_Tinker\tm_QChem" << endl; +// for(int i=0;iGetCoordUtil()->reducedMass[i] << "\t" << V2->GetCoordUtil()->reducedMass[i] << endl; +// } +// //V2->GetCoordUtil()->MakeScalingVec(V->GetCoordUtil()); +// +// cout << "x\tV_full\tV_HO" << endl; +/////* +// for(int n=0; nGetV(part[0]) << "\t" << -rho->ModifyPotential(part[0]) << endl; +// V2->GetV(part[0]); +// } +////*/ +// exit(-1); +//// DES) + +// DES ( independent mode deltaAI + if(physics->isDeltaAI()) { + vector scanEnd; + for(int i=0; iGetCoordUtil()->omega[i],V2->GetCoordUtil()->omega[i]); + scanEnd.push_back(sqrt(2.0/minW/V->GetCoordUtil()->reducedMass[i]*(5.0+0.5))); + //Bohr, so twice that in Angrstrom + } + int scanSteps = 20; + double curX = 0.0; + string filepref = V->GetCoordUtil()->outFileName; + ofstream theFile; + ofstream theFile2; + ofstream theFile3; + theFile.open((filepref+".nGrid").c_str()); + theFile << "400" << endl; + theFile.close(); + theFile.open((filepref+".omegaMM").c_str()); + theFile2.open((filepref+".omegaQM").c_str()); + theFile3.open((filepref+".xMax").c_str()); + for(int i=0; iGetCoordUtil()->omega[i] << "\t"; + theFile2 << V2->GetCoordUtil()->omega[i] << "\t"; + theFile3 << scanEnd[i] << "\t"; + } + theFile << endl; + theFile2 << endl; + theFile3 << endl; + theFile.close(); + theFile2.close(); + theFile3.close(); + theFile.open((filepref+".massMM").c_str()); + theFile2.open((filepref+".massQM").c_str()); + for(int i=0; iGetCoordUtil()->reducedMass[i] << "\t"; + theFile2<< V2->GetCoordUtil()->reducedMass[i] << "\t"; + } + theFile << endl; + theFile2 << endl; + theFile.close(); + theFile2.close(); + theFile.open((filepref+".beta").c_str()); + theFile << eps*P << endl; + theFile.close(); + + theFile.open((filepref+".fullMM").c_str()); + theFile2.open((filepref+".hoMM").c_str()); + theFile3.open((filepref+".hoQM").c_str()); + V2->GetV(part[0]); + if(rename("0_pimc.in","equib.in") != 0) { + cout << "Error writing qchem file in TestSystem!" << endl; + } + + for(int n=0; nGetV(part[0]) << "\t"; + theFile2 << -rho->ModifyPotential(part[0]) << "\t"; + theFile3 << static_cast(V2)->GetVHO(part[0]) << "\t"; + V2->GetV(part[0]); + //cout << "mv: " +toString(n)+"_pimc.in" << endl; + //cout << "to: "+ toString(n)+"_"+toString(i)+"_"+filepref+".in" << endl; + if(rename((toString(i+n*N+1)+"_pimc.in").c_str(),(toString(n)+"_"+toString(i)+"_"+filepref+".in").c_str()) != 0) { + cout << "Error writing qchem file in TestSystem!" << endl; + } + part[0][i].pos[0]=0.0; + } + theFile << endl; + theFile2 << endl; + theFile3 << endl; + } + theFile.close(); + theFile2.close(); + theFile3.close(); + exit(-1); + } +// DES) + static int initRanSeed = -time(0); int bead, beadm1; @@ -142,7 +275,7 @@ void TestSystem::Reset() { int snipBegin; int snipEnd; // for (int j=0; jnumFrozModes; jlowFrozModes; jhighFrozModes; j++) { for(int round=0; round

1 + vFile << tempNum << "\t" << harmV << "\t" << pickedV << endl; // DES Temp!!!! //vFile << tempNum << "\t" << part[pickedSlice][0].pos[0] << "\t" << harmV << "\t" << pickedV << "\t" << endl; tempNum++; - /* -// DES Temp: Just print a .in file with geometry - ostringstream convert; - convert << tempNum; - string qchemName = convert.str() + "_pimc.in"; -//string qchemName = std::to_string(tempNum) + "_pimc.in"; - qchemFile.open(qchemName.c_str()); - int N = V->GetCoordUtil()->numPart; -// Get cartesians from normal modes - vector< vector > cartPos = V->GetCoordUtil()->normalModeToCart(part[pickedSlice]); -// Write qchem inputfile - qchemFile << "$comments\nDES: deltaPIMC job\n$end\n" << endl; - qchemFile << "$molecule\n 0 1" << endl; - for(int i=0; iGetCoordUtil()->atomType[i] << "\t" << cartPos[i][0] << "\t" << cartPos[i][1] << "\t" << cartPos[i][2]; - qchemFile << endl; - } - qchemFile << "$end\n" << endl; -// B3LYP - qchemFile << "$rem\n JOBTYPE sp\n EXCHANGE B3LYP\n BASIS cc-pVTZ\n SCF_GUESS SAD\n SCF_ALGORITHM DIIS\n MAX_SCF_CYCLES 200\n SYM_IGNORE TRUE\n SYMMETRY FALSE\n UNRESTRICTED TRUE\n SCF_CONVERGENCE 8\n THRESH 9\n MEM_STATIC 1000 \n MEM_TOTAL 4000\n$end" << endl; -// qchemFile << "$rem\n JOBTYPE sp\n EXCHANGE HF\n CORRELATION MP2\n BASIS cc-pVTZ\n MP2_RESTART_NO_SCF TRUE\n purecart 2222\n SCF_GUESS READ\n SCF_ALGORITHM DIIS\n THRESH_DIIS_SWITCH 4\n MAX_SCF_CYCLES 200\n SYM_IGNORE TRUE\n SYMMETRY FALSE\n UNRESTRICTED TRUE\n SCF_CONVERGENCE 8\n DO_O2 0\n THRESH 14\n MEM_STATIC 1000 \n MEM_TOTAL 4000\n$end" << endl; - - qchemFile.close(); - tempNum++; - */ return pickedV; } // return exp(double(-eps)*(potE)); @@ -299,7 +405,14 @@ void TestSystem::CalcPotential(){ potE = 0; for(int i=0; iGetCoordUtil()->guessCarts = oldCarts[i]; + V->GetCoordUtil()->guessPart = oldPart[i]; sliceV[i] = V->GetV(part[i], rho); + //V->GetCoordUtil()->useGuess = true; + V->GetCoordUtil()->useGuess = false; +//DES: Read out new carts from guessCarts + newCarts[i] = V->GetCoordUtil()->guessCarts; } upToDate[i] = true; potE += sliceV[i]; @@ -307,7 +420,7 @@ void TestSystem::CalcPotential(){ } -void TestSystem::Move(vector prob, int levyNum){ +void TestSystem::Move(vector prob, int levyNum, int levyModes){ // cout << "Take a step" << endl; /* // Random Walks @@ -338,30 +451,50 @@ void TestSystem::Move(vector prob, int levyNum){ vector levyMean; double levySigma; int bead, beadm1; -// Snip length must be at least 3 and shouldn't be more than P/2+1 (or 20) or else you'll just collapse it + vector remainingPart; + for(int i=0; i(prob[0]*(P-2)/2+1), maxLevy); // ******************************************************* levyLength = levyNum; // ******************************************************* - int iPart = static_cast((N-physics->numFrozModes)*P*prob[1]); -// int iCoor = static_cast(coorDim*prob[2]); - int pickedPart = int(iPart/P)+physics->numFrozModes; - int snipBegin = iPart%P; + int snipBegin = static_cast(prob[levyModes]*P); int snipEnd = (snipBegin+levyLength+1)%P; - -// cout << "SnipBegin: " << snipBegin << "\tSnipEnd" << snipEnd << "\tSnipLength:" << snipLength << endl; - if(N > physics->numFrozModes) { - for (int s=0; sGetLevyMean(part[beadm1][pickedPart], part[snipEnd][pickedPart], (double)(levyLength-s), eps, pickedPart); - levySigma = rho->GetLevySigma((double)(levyLength-s), eps, pickedPart) / sqrt(part[0][pickedPart].mass); - for(int k=0; k((N-i-physics->lowFrozModes-physics->highFrozModes)*prob[i]); + //int pickedPart = int(iPart/P)+physics->lowFrozModes; + pickedPart = remainingPart[iPart+physics->lowFrozModes]; + remainingPart.erase(remainingPart.begin()+iPart+physics->lowFrozModes); + //cout << "DES: PickedPart = " << pickedPart << endl; + /* + for(int i=0; i physics->lowFrozModes+physics->highFrozModes) { + for (int s=0; sGetLevyMean(part[beadm1][pickedPart], part[snipEnd][pickedPart], (double)(levyLength-s), eps, pickedPart); + levySigma = rho->GetLevySigma((double)(levyLength-s), eps, pickedPart) / sqrt(part[0][pickedPart].mass); + for(int k=0; k prob, int levyNum){ void TestSystem::Forget() { oldEnergy = energy; oldPotE = potE; + oldCarts = newCarts; for(int i=0; i #include +#include #include #include #include @@ -37,7 +38,7 @@ class TestSystem: public System { virtual ~TestSystem(); void CalcEnergy(); void CalcPotential(); - void Move(vector, int); + void Move(vector prob, int levyNum, int levyPart = 1); void Forget(); void Undo(); void Reset(); @@ -50,6 +51,7 @@ class TestSystem: public System { string GetRhoType(); PhysicsUtil* GetPhysics(); double Debug(); + string toString(int); bool ECheckFlag; int P; @@ -74,6 +76,8 @@ class TestSystem: public System { vector oldSliceV; vector< vector > part; vector< vector > oldPart; + vector< vector< vector > > oldCarts; + vector< vector< vector > > newCarts; //DES Temp ofstream vFile; //TODO: Remove diff --git a/V_QChem.cpp b/V_QChem.cpp index df26bbf..d6660ad 100644 --- a/V_QChem.cpp +++ b/V_QChem.cpp @@ -8,7 +8,11 @@ #include "V_QChem.h" +bool absMax(double x, double y) {return fabs(x)scaleGeom) { +// DES: Temp TODO: Make sure you want to comment this out! + //coordKeeper->MatchModes(tinkCoords); + //coordKeeper->MakeScalingVec(tinkCoords); + } + tempNum=0; // Save vEquib and wQChem and set normal modes @@ -45,9 +56,9 @@ V_QChem::V_QChem(CoordUtil* coords, CoordUtil* tinkCoords, double eps, double b // Set up harmonic V for later qharmFile.open("qPotential.txt"); harmV.omega = coordKeeper->omega; - } + V_QChem::~V_QChem() { delete coordKeeper; qharmFile.close(); @@ -64,26 +75,38 @@ double V_QChem::GetV(vector part, Propagator * rho){ double V_QChem::GetV(vector part){ double hartreeToKcal = 627.509469; //From http://en.wikipedia.org/wiki/Hartree 8/17/2012 - double V = 0.0; - double wScale; - double mScale; -// Scale normal modes so that sampling is in same harmonic potential as MM - for(int i=0; inumModes; i++) { - mScale = sqrt(tinkerCoords->reducedMass[i]) / sqrt(coordKeeper->reducedMass[i]); - wScale = tinkerCoords->omega[i] / coordKeeper->omega[i]; - part[i].pos[0] *= wScale * mScale; + vector< vector > cartPos; + if(doubleTI) { +//Old Junk + if(coordKeeper->scaleGeom) { + for(int i=0; inumModes; i++) { + part[i].pos[0] *= coordKeeper->scalingVec[i]; + } + //cartPos = coordKeeper->normalModeToCart(part); + cartPos = tinkerCoords->normalModeToCart(part); + for(int j=0; jinitCart[j][k] - tinkerCoords->initCart[j][k]; + } + } + } + else { + cout << "DES: I shouldn't be here!!" << endl; + // Get cartesians from normal modes + cartPos = tinkerCoords->normalModeToCart(part); + // DES: converting from tinker initCarts to qchem using cartesians + for(int j=0; jinitCart[j][k] - tinkerCoords->initCart[j][k]; + } + } + } + } + else { + cartPos = coordKeeper->normalModeToCart(part); } - -// Get cartesians from normal modes -// DES Temp: -// vector< vector > cartPos = tinkerCoords->normalModeToCart(part); - vector< vector > cartPos = coordKeeper->normalModeToCart(part); // DES: running ab initio thermodynamic integration correction to molecular mechanics -// int pickedSlice = 0; //TODO: Make this random -// Propagator * freerho = new Rho_Free; -// double pickedV = V->GetV(part[pickedSlice], freerho); -// delete freerho; // DES Temp: Just print a .in file with geometry ostringstream convert; convert << tempNum; @@ -92,38 +115,7 @@ double V_QChem::GetV(vector part){ qchemFile.open(qchemName.c_str()); int N = coordKeeper->numPart; // Get cartesians from normal modes - //vector< vector > cartPos = coordKeeper->normalModeToCart(part[pickedSlice]); -/* -//DES Temp Temp: - cout << "QC cartPos in V_QChem" << endl; - for(int j=0; jinitCart[j][k])/0.52918 << endl; - } - } - - cout <<"DES Temp: QC cton" << endl; - vector normMode = coordKeeper->cartToNormalMode(cartPos); - cout << "QC Normal modes" << endl; - for(int i=0; inormalModeToCart(part); - cout << "QC Cartesians2" << endl; - for(int i=0; i part){ qchemFile << "$rem\n JOBTYPE sp\n EXCHANGE B3LYP\n BASIS cc-pVTZ\n SCF_GUESS SAD\n SCF_ALGORITHM DIIS\n MAX_SCF_CYCLES 200\n SYM_IGNORE TRUE\n SYMMETRY FALSE\n UNRESTRICTED TRUE\n SCF_CONVERGENCE 6\n THRESH 9\n MEM_STATIC 1000 \n MEM_TOTAL 4000\n$end" << endl; // qchemFile << "$rem\n JOBTYPE sp\n EXCHANGE HF\n CORRELATION MP2\n BASIS cc-pVTZ\n MP2_RESTART_NO_SCF TRUE\n purecart 2222\n SCF_GUESS READ\n SCF_ALGORITHM DIIS\n THRESH_DIIS_SWITCH 4\n MAX_SCF_CYCLES 200\n SYM_IGNORE TRUE\n SYMMETRY FALSE\n UNRESTRICTED TRUE\n SCF_CONVERGENCE 8\n DO_O2 0\n THRESH 14\n MEM_STATIC 1000 \n MEM_TOTAL 4000\n$end" << endl; qchemFile.close(); - - vector modes = coordKeeper->cartToNormalMode(cartPos); -// cout << "QC Normal modes" << endl; -// for(int i=0; i tempPart; - for(int i=0; ireducedMass[i]; + + double potHarm; + if(doubleTI) { +//Old Junk + cout << "DES: I shouldn't be here!!" << endl; + vector tempPart; + vector modes; + + if(tinkerCoords->internals) { + tinkerCoords->internals=false; + cartPos = tinkerCoords->normalModeToCart(part); + for(int j=0; jinitCart[j][k] - tinkerCoords->initCart[j][k]; + } + } + modes = coordKeeper->cartToNormalMode(cartPos); + tinkerCoords->internals=true; + } + else { + modes = coordKeeper->cartToNormalMode(cartPos); + } + // cout << "QC Normal modes" << endl; + // for(int i=0; ireducedMass[i]; + } + potHarm = harmV.GetV(tempPart); + // for(int i=0; i part){ return 0.0; } +double V_QChem::GetVHO(vector part){ + + if(doubleTI) { +//Old Junk + cout << "DES: I shouldn't be here!!" << endl; + vector< vector > cartPos; + if(coordKeeper->scaleGeom) { + for(int i=0; inumModes; i++) { + part[i].pos[0] *= coordKeeper->scalingVec[i]; + } + //cartPos = coordKeeper->normalModeToCart(part); + cartPos = tinkerCoords->normalModeToCart(part); + for(int j=0; jinitCart[j][k] - tinkerCoords->initCart[j][k]; + } + } + } + else { + // Get cartesians from normal modes + cartPos = tinkerCoords->normalModeToCart(part); + // DES: converting from tinker initCarts to qchem using cartesians + for(int j=0; jinitCart[j][k] - tinkerCoords->initCart[j][k]; + } + } + } + vector tempPart; + vector modes; + + if(tinkerCoords->internals) { + tinkerCoords->internals=false; + cartPos = tinkerCoords->normalModeToCart(part); + for(int j=0; jinitCart[j][k] - tinkerCoords->initCart[j][k]; + } + } + modes = coordKeeper->cartToNormalMode(cartPos); + tinkerCoords->internals=true; + } + else { + modes = coordKeeper->cartToNormalMode(cartPos); + } + for(int i=0; ireducedMass[i]; + } + return harmV.GetV(tempPart); + } + return harmV.GetV(part); + +} + string V_QChem::GetType() { string name = "QChem"; return name; diff --git a/V_QChem.h b/V_QChem.h index b44c801..d821bc9 100644 --- a/V_QChem.h +++ b/V_QChem.h @@ -21,6 +21,7 @@ #include #include #include +//#include using namespace std; class V_QChem: public Potential { @@ -31,8 +32,10 @@ class V_QChem: public Potential { double GetV(vector); string GetType(); CoordUtil* GetCoordUtil(); + double GetVHO(vector); void Tokenize(const string&, vector&, const string& = " "); + bool doubleTI; double vEquib; //in kcal/mole CoordUtil* coordKeeper; CoordUtil* tinkerCoords; diff --git a/V_Tinker.cpp b/V_Tinker.cpp index cf7a3a0..10106dc 100644 --- a/V_Tinker.cpp +++ b/V_Tinker.cpp @@ -55,6 +55,7 @@ V_Tinker::V_Tinker(CoordUtil* coords, double eps, double beta) : coordKeeper(coo coordKeeper->initCart[j][k] = xyzCoord[k+j*3]; } } + coordKeeper->guessCarts = coordKeeper->initCart; cout << "DES: Coords after opt" << endl; for(int j=0; jreducedMass[i]/1822.8886 << endl; - cout << coordKeeper->omega[i]/0.00000455633 << endl; - for(int j=0; jnumPart; j++) { - for(int k=0; k<3; k++) { - cout << coordKeeper->normModes[i][j][k] << "\t"; - } - cout << endl; - } - } - */ } V_Tinker::~V_Tinker() { diff --git a/V_TinkerExecutable.cpp b/V_TinkerExecutable.cpp index 2cbce67..1b67e1c 100644 --- a/V_TinkerExecutable.cpp +++ b/V_TinkerExecutable.cpp @@ -11,8 +11,8 @@ V_TinkerExecutable::V_TinkerExecutable(CoordUtil * coords) { // tinkInFileName = "pimc.xyz"; // tinkOutFileName = "pimc.out"; - tinkInFileName = coords->tinkerName + ".xyz"; - tinkOutFileName = coords->tinkerName + ".outTinker"; + tinkInFileName = coords->outFileName + ".xyz"; + tinkOutFileName = coords->outFileName + ".outTinker"; tinkPrmFileName = coords->prmName; coordKeeper = coords; diff --git a/optking/atom_data.cpp b/optking/atom_data.cpp new file mode 100644 index 0000000..3e01da6 --- /dev/null +++ b/optking/atom_data.cpp @@ -0,0 +1,3466 @@ +/*! \file atom_data.cc + \ingroup optking + \brief atom_data.cc : initialize static class members in atom_data.h +*/ + +#include "atom_data.h" + +namespace opt { + +using std::string; + +#define LAST_Z_TO_SYMBOL (118) +const char *Z_to_symbol[] = { +"X","H","HE","LI","BE","B","C","N","O","F","NE","NA","MG","AL","SI", +"P","S","CL","AR","K","CA","SC","TI","V","CR","MN","FE","CO","NI", +"CU","ZN","GA","GE","AS","SE","BR","KR","RB","SR","Y","ZR","NB","MO", +"TC","RU","RH","PD","AG","CD","IN","SN","SB","TE","I","XE","CS","BA", +"LA","CE","PR","ND","PM","SM","EU","GD","TB","DY","HO","ER","TM","YB", +"LU","HF","TA","W","RE","OS","IR","PT","AU","HG","TL","PB","BI","PO", +"AT","RN","FR","RA","AC","TH","PA","U","NP","PU","AM","CM","BK","CF", +"ES","FM","MD","NO","LR","RF","DB","SG","BH","HS","MT","DS","RG", +"UUB","UUT","UUQ","UUP","UUH","UUS","UUO"}; + +#define LAST_Z_TO_MASS (118) +const double Z_to_mass[] = { +0.,1.00782503207,4.00260325415,7.016004548,9.012182201,11.009305406, +12,14.00307400478,15.99491461956,18.998403224,19.99244017542, +22.98976928087,23.985041699,26.981538627,27.97692653246,30.973761629, +31.972070999,34.968852682,39.96238312251,38.963706679,39.962590983, +44.955911909,47.947946281,50.943959507,51.940507472,54.938045141, +55.934937475,58.933195048,57.935342907,62.929597474,63.929142222, +68.925573587,73.921177767,74.921596478,79.916521271,78.918337087, +85.910610729,84.911789737,87.905612124,88.905848295,89.904704416, +92.906378058,97.905408169,98.906254747,101.904349312,102.905504292, +105.903485715,106.90509682,113.90335854,114.903878484,119.902194676, +120.903815686,129.906224399,126.904472681,131.904153457,132.905451932, +137.905247237,138.906353267,139.905438706,140.907652769,141.907723297, +144.912749023,151.919732425,152.921230339,157.924103912,158.925346757, +163.929174751,164.93032207,165.930293061,168.93421325,173.938862089, +174.940771819,179.946549953,180.947995763,183.950931188,186.955753109, +191.96148069,192.96292643,194.964791134,196.966568662,201.970643011, +204.974427541,207.976652071,208.980398734,208.982430435,210.987496271, +222.017577738,222.01755173,228.031070292,227.027752127,232.038055325, +231.03588399,238.050788247,237.048173444,242.058742611,243.06138108, +247.07035354,247.07030708,251.079586788,252.082978512,257.095104724, +258.098431319,255.093241131,260.105504,263.112547,255.107398,259.114500, +262.122892,263.128558,265.136151,281.162061,272.153615,283.171792,283.176451, +285.183698,287.191186,292.199786,291.206564,293.214670}; + +double Element_to_Z(std::string lbl) { + if (lbl == "G" || lbl == "GHOST") return 0.0; + if (lbl == "H" || lbl == "HYDROGEN") return 1.0; + if (lbl == "HE" || lbl == "HELIUM" ) return 2.0; + if (lbl == "LI" || lbl == "LITHIUM" ) return 3.0; + if (lbl == "BE" || lbl == "BERYLLIUM") return 4.0; + if (lbl == "B" || lbl == "BORON") return 5.0; + if (lbl == "C" || lbl == "CARBON") return 6.0; + if (lbl == "N" || lbl == "NITROGEN") return 7.0; + if (lbl == "O" || lbl == "OXYGEN") return 8.0; + if (lbl == "F" || lbl == "FLUORINE") return 9.0; + if (lbl == "NE" || lbl == "NEON") return 10.0; + if (lbl == "NA" || lbl == "SODIUM") return 11.0; + if (lbl == "MG" || lbl == "MAGNESIUM") return 12.0; + if (lbl == "AL" || lbl == "ALUMINUM") return 13.0; + if (lbl == "SI" || lbl == "SILICON") return 14.0; + if (lbl == "P" || lbl == "PHOSPHORUS") return 15.0; + if (lbl == "S" || lbl == "SULPHUR" || lbl == "SULFUR") return 16.0; + if (lbl == "CL" || lbl == "CHLORINE") return 17.0; + if (lbl == "AR" || lbl == "ARGON") return 18.0; + if (lbl == "K" || lbl == "POTASSIUM") return 19.0; + if (lbl == "CA" || lbl == "CALCIUM") return 20.0; + if (lbl == "SC" || lbl == "SCANDIUM") return 21.0; + if (lbl == "TI" || lbl == "TITANIUM") return 22.0; + if (lbl == "V" || lbl == "VANADIUM") return 23.00; + if (lbl == "CR" || lbl == "CHROMIUM") return 24.0; + if (lbl == "MN" || lbl == "MANGANESE") return 25.0; + if (lbl == "FE" || lbl == "IRON") return 26.0; + if (lbl == "CO" || lbl == "COBALT") return 27.0; + if (lbl == "NI" || lbl == "NICKEL") return 28.0; + if (lbl == "CU" || lbl == "COPPER") return 29.0; + if (lbl == "ZN" || lbl == "ZINC") return 30.0; + if (lbl == "GA" || lbl == "GALLIUM") return 31.0; + if (lbl == "GE" || lbl == "GERMANIUM") return 32.0; + if (lbl == "AS" || lbl == "ARSENIC" ) return 33.0; + if (lbl == "SE" || lbl == "SELENIUM" ) return 34.0; + if (lbl == "BR" || lbl == "BROMINE" ) return 35.0; + if (lbl == "KR" || lbl == "KRYPTON" ) return 36.0; + if (lbl == "RB" || lbl == "RUBIDIUM" ) return 37.0; + if (lbl == "SR" || lbl == "STRONTIUM") return 38.0; + if (lbl == "Y" || lbl == "YTTRIUM" ) return 39.0; + if (lbl == "ZR" || lbl == "ZIRCONIUM") return 40.0; + if (lbl == "NB" || lbl == "NIOBIUM" ) return 41.0; + if (lbl == "MO" || lbl == "MOLYBDENUM") return 42.0; + if (lbl == "TC" || lbl == "TECHNETIUM") return 43.0; + if (lbl == "RU" || lbl == "RUTHENIUM" ) return 44.0; + if (lbl == "RH" || lbl == "RHODIUM" ) return 45.0; + if (lbl == "PD" || lbl == "PALLADIUM" ) return 46.0; + if (lbl == "AG" || lbl == "SILVER" ) return 47.0; + if (lbl == "CD" || lbl == "CADMIUM" ) return 48.0; + if (lbl == "IN" || lbl == "INDIUM" ) return 49.0; + if (lbl == "SN" || lbl == "TIN" ) return 50.0; + if (lbl == "SB" || lbl == "ANTIMONY" ) return 51.0; + if (lbl == "TE" || lbl == "TELLURIUM") return 52.0; + if (lbl == "I" || lbl == "IODINE" ) return 53.0; + if (lbl == "XE" || lbl == "XENON" ) return 54.00; + if (lbl == "CS" || lbl == "CESIUM" ) return 55.00; + if (lbl == "BA" || lbl == "BARIUM" ) return 56.00; + if (lbl == "LA" || lbl == "LANTHANUM") return 57.00; + if (lbl == "CE" || lbl == "CERIUM" ) return 58.00; + if (lbl == "PR" || lbl == "PRASEODYMIUM") return 59.00; + if (lbl == "ND" || lbl == "NEODYMIUM" ) return 60.00; + if (lbl == "PM" || lbl == "PROMETHIUM" ) return 61.00; + if (lbl == "SM" || lbl == "SAMARIUM" ) return 62.00; + if (lbl == "EU" || lbl == "EUROPIUM" ) return 63.00; + if (lbl == "GD" || lbl == "GADOLINIUM" ) return 64.00; + if (lbl == "TB" || lbl == "TERBIUM" ) return 65.00; + if (lbl == "DY" || lbl == "DYSPROSIUM" ) return 66.00; + if (lbl == "HO" || lbl == "HOLMIUM" ) return 67.00; + if (lbl == "ER" || lbl == "ERBIUM" ) return 68.00; + if (lbl == "TM" || lbl == "THULIUM" ) return 69.00; + if (lbl == "YB" || lbl == "YTTERBIUM") return 70.00; + if (lbl == "LU" || lbl == "LUTETIUM" ) return 71.00; + if (lbl == "HF" || lbl == "HAFNIUM" ) return 72.00; + if (lbl == "TA" || lbl == "TANTALUM" ) return 73.00; + if (lbl == "W" || lbl == "TUNGSTEN" ) return 74.00; + if (lbl == "RE" || lbl == "RHENIUM" ) return 75.00; + if (lbl == "OS" || lbl == "OSMIUM" ) return 76.00; + if (lbl == "IR" || lbl == "IRIDIUM" ) return 77.00; + if (lbl == "PT" || lbl == "PLATINUM" ) return 78.00; + if (lbl == "AU" || lbl == "GOLD" ) return 79.00; + if (lbl == "HG" || lbl == "MERCURY" ) return 80.00; + if (lbl == "TL" || lbl == "THALLIUM" ) return 81.00; + if (lbl == "PB" || lbl == "LEAD" ) return 82.00; + if (lbl == "BI" || lbl == "BISMUTH" ) return 83.00; + if (lbl == "PO" || lbl == "POLONIUM" ) return 84.00; + if (lbl == "AT" || lbl == "ASTATINE" ) return 85.00; + if (lbl == "RN" || lbl == "RADON" ) return 86.00; + if (lbl == "FR" || lbl == "FRANCIUM" ) return 87.00; + if (lbl == "RA" || lbl == "RADIUM" ) return 88.00; + if (lbl == "AC" || lbl == "ACTINIUM" ) return 89.00; + if (lbl == "TH" || lbl == "THORIUM" ) return 90.00; + if (lbl == "PA" || lbl == "PROTACTINIUM" ) return 91.00; + if (lbl == "U" || lbl == "URANIUM" ) return 92.00; + if (lbl == "NP" || lbl == "NEPTUNIUM") return 93.00; + if (lbl == "PU" || lbl == "PLUTONIUM") return 94.00; + if (lbl == "AM" || lbl == "AMERICIUM") return 95.00; + if (lbl == "CM" || lbl == "CURIUM" ) return 96.00; + if (lbl == "BK" || lbl == "BERKELIUM" ) return 97.00; + if (lbl == "CF" || lbl == "CALIFORNIUM") return 98.00; + if (lbl == "ES" || lbl == "EINSTEINIUM") return 99.00; + if (lbl == "FM" || lbl == "FERMIUM" ) return 100.00; + if (lbl == "MD" || lbl == "MENDELEVIUM") return 101.00; + if (lbl == "NO" || lbl == "NOBELIUM" ) return 102.00; + if (lbl == "LR" || lbl == "LAWRENCIUM" ) return 103.00; + if (lbl == "UNQ") return 104.00; + if (lbl == "UNP") return 105.00; + if (lbl == "UNH") return 106.00; + if (lbl == "UNS") return 107.00; + return 0; +} + +double Isotope_to_mass(std::string lbl) { + if (lbl == "H") return 1.007825032 ; + if (lbl == "H1") return 1.007825032 ; + if (lbl == "H2") return 2.014101778 ; + if (lbl == "D") return 2.014101778 ; + if (lbl == "H3") return 3.016049278 ; + if (lbl == "T") return 3.016049278 ; + if (lbl == "H4") return 4.027806424 ; + if (lbl == "H5") return 5.035311488 ; + if (lbl == "H6") return 6.044942594 ; + if (lbl == "H7") return 7.052749 ; + if (lbl == "HE") return 4.002603254 ; + if (lbl == "HE3") return 3.016029319 ; + if (lbl == "HE4") return 4.002603254 ; + if (lbl == "HE5") return 5.012223624 ; + if (lbl == "HE6") return 6.018889124 ; + if (lbl == "HE7") return 7.028020618 ; + if (lbl == "HE8") return 8.033921897 ; + if (lbl == "HE9") return 9.043950286 ; + if (lbl == "HE10") return 10.05239884 ; + if (lbl == "LI") return 7.016004548 ; + if (lbl == "LI3") return 3.030775 ; + if (lbl == "LI4") return 4.027185558 ; + if (lbl == "LI5") return 5.0125378 ; + if (lbl == "LI6") return 6.015122794 ; + if (lbl == "LI7") return 7.016004548 ; + if (lbl == "LI8") return 8.022487362 ; + if (lbl == "LI9") return 9.026789505 ; + if (lbl == "LI10") return 10.03548126 ; + if (lbl == "LI11") return 11.04379772 ; + if (lbl == "LI12") return 12.05378 ; + if (lbl == "BE") return 9.012182201 ; + if (lbl == "BE5") return 5.04079 ; + if (lbl == "BE6") return 6.019726317 ; + if (lbl == "BE7") return 7.016929828 ; + if (lbl == "BE8") return 8.005305103 ; + if (lbl == "BE9") return 9.012182201 ; + if (lbl == "BE10") return 10.01353382 ; + if (lbl == "BE11") return 11.02165775 ; + if (lbl == "BE12") return 12.02692074 ; + if (lbl == "BE13") return 13.03569301 ; + if (lbl == "BE14") return 14.04289292 ; + if (lbl == "BE15") return 15.05346 ; + if (lbl == "BE16") return 16.06192 ; + if (lbl == "B") return 11.00930541 ; + if (lbl == "B6") return 6.04681 ; + if (lbl == "B7") return 7.029917901 ; + if (lbl == "B8") return 8.024607233 ; + if (lbl == "B9") return 9.013328782 ; + if (lbl == "B10") return 10.01293699 ; + if (lbl == "B11") return 11.00930541 ; + if (lbl == "B12") return 12.0143521 ; + if (lbl == "B13") return 13.01778022 ; + if (lbl == "B14") return 14.02540401 ; + if (lbl == "B15") return 15.03110302 ; + if (lbl == "B16") return 16.03980883 ; + if (lbl == "B17") return 17.04698991 ; + if (lbl == "B18") return 18.05617 ; + if (lbl == "B19") return 19.06373 ; + if (lbl == "C") return 12 ; + if (lbl == "C8") return 8.037675025 ; + if (lbl == "C9") return 9.031036689 ; + if (lbl == "C10") return 10.01685323 ; + if (lbl == "C11") return 11.01143361 ; + if (lbl == "C12") return 12 ; + if (lbl == "C13") return 13.00335484 ; + if (lbl == "C14") return 14.00324199 ; + if (lbl == "C15") return 15.01059926 ; + if (lbl == "C16") return 16.01470125 ; + if (lbl == "C17") return 17.02258612 ; + if (lbl == "C18") return 18.02675935 ; + if (lbl == "C19") return 19.03480502 ; + if (lbl == "C20") return 20.04031975 ; + if (lbl == "C21") return 21.04934 ; + if (lbl == "C22") return 22.0572 ; + if (lbl == "N") return 14.003074 ; + if (lbl == "N10") return 10.04165367 ; + if (lbl == "N11") return 11.02609096 ; + if (lbl == "N12") return 12.0186132 ; + if (lbl == "N13") return 13.00573861 ; + if (lbl == "N14") return 14.003074 ; + if (lbl == "N15") return 15.0001089 ; + if (lbl == "N16") return 16.00610166 ; + if (lbl == "N17") return 17.00845026 ; + if (lbl == "N18") return 18.01407896 ; + if (lbl == "N19") return 19.0170287 ; + if (lbl == "N20") return 20.02336581 ; + if (lbl == "N21") return 21.02710824 ; + if (lbl == "N22") return 22.03439493 ; + if (lbl == "N23") return 23.04122 ; + if (lbl == "N24") return 24.05104 ; + if (lbl == "N25") return 25.06066 ; + if (lbl == "O") return 15.99491462 ; + if (lbl == "O12") return 12.0344049 ; + if (lbl == "O13") return 13.02481221 ; + if (lbl == "O14") return 14.00859625 ; + if (lbl == "O15") return 15.00306562 ; + if (lbl == "O16") return 15.99491462 ; + if (lbl == "O17") return 16.9991317 ; + if (lbl == "O18") return 17.999161 ; + if (lbl == "O19") return 19.00358013 ; + if (lbl == "O20") return 20.00407674 ; + if (lbl == "O21") return 21.00865589 ; + if (lbl == "O22") return 22.00996695 ; + if (lbl == "O23") return 23.01568766 ; + if (lbl == "O24") return 24.02047292 ; + if (lbl == "O25") return 25.02946 ; + if (lbl == "O26") return 26.03834 ; + if (lbl == "O27") return 27.04826 ; + if (lbl == "O28") return 28.05781 ; + if (lbl == "F") return 18.99840322 ; + if (lbl == "F14") return 14.03506 ; + if (lbl == "F15") return 15.0180091 ; + if (lbl == "F16") return 16.01146572 ; + if (lbl == "F17") return 17.00209524 ; + if (lbl == "F18") return 18.00093796 ; + if (lbl == "F19") return 18.99840322 ; + if (lbl == "F20") return 19.99998132 ; + if (lbl == "F21") return 20.99994895 ; + if (lbl == "F22") return 22.00299882 ; + if (lbl == "F23") return 23.00357463 ; + if (lbl == "F24") return 24.00811549 ; + if (lbl == "F25") return 25.01210175 ; + if (lbl == "F26") return 26.01961556 ; + if (lbl == "F27") return 27.02676009 ; + if (lbl == "F28") return 28.03567 ; + if (lbl == "F29") return 29.04326 ; + if (lbl == "F30") return 30.0525 ; + if (lbl == "F31") return 31.060429 ; + if (lbl == "NE") return 19.99244018 ; + if (lbl == "NE16") return 16.02576126 ; + if (lbl == "NE17") return 17.0176715 ; + if (lbl == "NE18") return 18.00570821 ; + if (lbl == "NE19") return 19.00188025 ; + if (lbl == "NE20") return 19.99244018 ; + if (lbl == "NE21") return 20.99384668 ; + if (lbl == "NE22") return 21.99138511 ; + if (lbl == "NE23") return 22.9944669 ; + if (lbl == "NE24") return 23.99361078 ; + if (lbl == "NE25") return 24.99773689 ; + if (lbl == "NE26") return 26.00046121 ; + if (lbl == "NE27") return 27.0075899 ; + if (lbl == "NE28") return 28.01207158 ; + if (lbl == "NE29") return 29.01938593 ; + if (lbl == "NE30") return 30.02480105 ; + if (lbl == "NE31") return 31.03311 ; + if (lbl == "NE32") return 32.04002 ; + if (lbl == "NE33") return 33.04938 ; + if (lbl == "NE34") return 34.057028 ; + if (lbl == "NA") return 22.98976928 ; + if (lbl == "NA18") return 18.025969 ; + if (lbl == "NA19") return 19.0138775 ; + if (lbl == "NA20") return 20.00735133 ; + if (lbl == "NA21") return 20.99765521 ; + if (lbl == "NA22") return 21.99443643 ; + if (lbl == "NA23") return 22.98976928 ; + if (lbl == "NA24") return 23.99096278 ; + if (lbl == "NA25") return 24.98995397 ; + if (lbl == "NA26") return 25.992633 ; + if (lbl == "NA27") return 26.99407679 ; + if (lbl == "NA28") return 27.998938 ; + if (lbl == "NA29") return 29.002861 ; + if (lbl == "NA30") return 30.008976 ; + if (lbl == "NA31") return 31.01358545 ; + if (lbl == "NA32") return 32.02046656 ; + if (lbl == "NA33") return 33.02671976 ; + if (lbl == "NA34") return 34.03517 ; + if (lbl == "NA35") return 35.042493 ; + if (lbl == "NA36") return 36.05148 ; + if (lbl == "NA37") return 37.05934 ; + if (lbl == "MG") return 23.9850417 ; + if (lbl == "MG19") return 19.03547 ; + if (lbl == "MG20") return 20.01886255 ; + if (lbl == "MG21") return 21.01171291 ; + if (lbl == "MG22") return 21.99957384 ; + if (lbl == "MG23") return 22.99412367 ; + if (lbl == "MG24") return 23.9850417 ; + if (lbl == "MG25") return 24.98583692 ; + if (lbl == "MG26") return 25.98259293 ; + if (lbl == "MG27") return 26.98434059 ; + if (lbl == "MG28") return 27.98387683 ; + if (lbl == "MG29") return 28.9886 ; + if (lbl == "MG30") return 29.990434 ; + if (lbl == "MG31") return 30.996546 ; + if (lbl == "MG32") return 31.998975 ; + if (lbl == "MG33") return 33.005254 ; + if (lbl == "MG34") return 34.00945642 ; + if (lbl == "MG35") return 35.01734 ; + if (lbl == "MG36") return 36.023 ; + if (lbl == "MG37") return 37.0314 ; + if (lbl == "MG38") return 38.03757 ; + if (lbl == "MG39") return 39.046772 ; + if (lbl == "MG40") return 40.05393 ; + if (lbl == "AL") return 26.98153863 ; + if (lbl == "AL21") return 21.02804 ; + if (lbl == "AL22") return 22.01952 ; + if (lbl == "AL23") return 23.00726743 ; + if (lbl == "AL24") return 23.99993887 ; + if (lbl == "AL25") return 24.9904281 ; + if (lbl == "AL26") return 25.98689169 ; + if (lbl == "AL27") return 26.98153863 ; + if (lbl == "AL28") return 27.98191031 ; + if (lbl == "AL29") return 28.98044505 ; + if (lbl == "AL30") return 29.98296026 ; + if (lbl == "AL31") return 30.98394662 ; + if (lbl == "AL32") return 31.98812449 ; + if (lbl == "AL33") return 32.99084334 ; + if (lbl == "AL34") return 33.99685184 ; + if (lbl == "AL35") return 34.99986024 ; + if (lbl == "AL36") return 36.0062072 ; + if (lbl == "AL37") return 37.01067782 ; + if (lbl == "AL38") return 38.01723102 ; + if (lbl == "AL39") return 39.02297 ; + if (lbl == "AL40") return 40.03145 ; + if (lbl == "AL41") return 41.03833 ; + if (lbl == "AL42") return 42.04689 ; + if (lbl == "SI") return 27.97692653 ; + if (lbl == "SI22") return 22.03453 ; + if (lbl == "SI23") return 23.02552 ; + if (lbl == "SI24") return 24.01154562 ; + if (lbl == "SI25") return 25.00410557 ; + if (lbl == "SI26") return 25.99232992 ; + if (lbl == "SI27") return 26.98670491 ; + if (lbl == "SI28") return 27.97692653 ; + if (lbl == "SI29") return 28.9764947 ; + if (lbl == "SI30") return 29.97377017 ; + if (lbl == "SI31") return 30.97536323 ; + if (lbl == "SI32") return 31.97414808 ; + if (lbl == "SI33") return 32.97800022 ; + if (lbl == "SI34") return 33.97857552 ; + if (lbl == "SI35") return 34.98458358 ; + if (lbl == "SI36") return 35.98659948 ; + if (lbl == "SI37") return 36.99293608 ; + if (lbl == "SI38") return 37.9956336 ; + if (lbl == "SI39") return 39.00207001 ; + if (lbl == "SI40") return 40.00586912 ; + if (lbl == "SI41") return 41.01456 ; + if (lbl == "SI42") return 42.01979 ; + if (lbl == "SI43") return 43.02866 ; + if (lbl == "SI44") return 44.03526 ; + if (lbl == "P") return 30.97376163 ; + if (lbl == "P24") return 24.03435 ; + if (lbl == "P25") return 25.02026 ; + if (lbl == "P26") return 26.01178 ; + if (lbl == "P27") return 26.99923024 ; + if (lbl == "P28") return 27.99231476 ; + if (lbl == "P29") return 28.98180061 ; + if (lbl == "P30") return 29.97831379 ; + if (lbl == "P31") return 30.97376163 ; + if (lbl == "P32") return 31.97390727 ; + if (lbl == "P33") return 32.97172554 ; + if (lbl == "P34") return 33.97363626 ; + if (lbl == "P35") return 34.97331412 ; + if (lbl == "P36") return 35.97825968 ; + if (lbl == "P37") return 36.97960895 ; + if (lbl == "P38") return 37.98415683 ; + if (lbl == "P39") return 38.98617948 ; + if (lbl == "P40") return 39.99129695 ; + if (lbl == "P41") return 40.99433544 ; + if (lbl == "P42") return 42.00100791 ; + if (lbl == "P43") return 43.00619 ; + if (lbl == "P44") return 44.01299 ; + if (lbl == "P45") return 45.01922 ; + if (lbl == "P46") return 46.02738 ; + if (lbl == "S") return 31.972071 ; + if (lbl == "S26") return 26.02788 ; + if (lbl == "S27") return 27.018833 ; + if (lbl == "S28") return 28.00437276 ; + if (lbl == "S29") return 28.99660805 ; + if (lbl == "S30") return 29.98490325 ; + if (lbl == "S31") return 30.97955473 ; + if (lbl == "S32") return 31.972071 ; + if (lbl == "S33") return 32.97145876 ; + if (lbl == "S34") return 33.9678669 ; + if (lbl == "S35") return 34.96903216 ; + if (lbl == "S36") return 35.96708076 ; + if (lbl == "S37") return 36.97112557 ; + if (lbl == "S38") return 37.97116332 ; + if (lbl == "S39") return 38.97513431 ; + if (lbl == "S40") return 39.97545173 ; + if (lbl == "S41") return 40.97958215 ; + if (lbl == "S42") return 41.98102242 ; + if (lbl == "S43") return 42.98715479 ; + if (lbl == "S44") return 43.99021339 ; + if (lbl == "S45") return 44.99650811 ; + if (lbl == "S46") return 46.00075 ; + if (lbl == "S47") return 47.00859 ; + if (lbl == "S48") return 48.01417 ; + if (lbl == "S49") return 49.023619 ; + if (lbl == "CL") return 34.96885268 ; + if (lbl == "CL28") return 28.02851 ; + if (lbl == "CL29") return 29.01411 ; + if (lbl == "CL30") return 30.00477 ; + if (lbl == "CL31") return 30.99241309 ; + if (lbl == "CL32") return 31.9856899 ; + if (lbl == "CL33") return 32.97745189 ; + if (lbl == "CL34") return 33.97376282 ; + if (lbl == "CL35") return 34.96885268 ; + if (lbl == "CL36") return 35.96830698 ; + if (lbl == "CL37") return 36.96590259 ; + if (lbl == "CL38") return 37.96801043 ; + if (lbl == "CL39") return 38.96800816 ; + if (lbl == "CL40") return 39.97041547 ; + if (lbl == "CL41") return 40.97068453 ; + if (lbl == "CL42") return 41.9732548 ; + if (lbl == "CL43") return 42.9740544 ; + if (lbl == "CL44") return 43.97828107 ; + if (lbl == "CL45") return 44.98028689 ; + if (lbl == "CL46") return 45.98421004 ; + if (lbl == "CL47") return 46.98871 ; + if (lbl == "CL48") return 47.99495 ; + if (lbl == "CL49") return 49.00032 ; + if (lbl == "CL50") return 50.00784 ; + if (lbl == "CL51") return 51.01449 ; + if (lbl == "AR") return 39.96238312 ; + if (lbl == "AR30") return 30.02156 ; + if (lbl == "AR31") return 31.012123 ; + if (lbl == "AR32") return 31.99763798 ; + if (lbl == "AR33") return 32.98992571 ; + if (lbl == "AR34") return 33.98027124 ; + if (lbl == "AR35") return 34.97525759 ; + if (lbl == "AR36") return 35.96754511 ; + if (lbl == "AR37") return 36.96677632 ; + if (lbl == "AR38") return 37.96273239 ; + if (lbl == "AR39") return 38.96431323 ; + if (lbl == "AR40") return 39.96238312 ; + if (lbl == "AR41") return 40.96450061 ; + if (lbl == "AR42") return 41.96304574 ; + if (lbl == "AR43") return 42.96563606 ; + if (lbl == "AR44") return 43.96492403 ; + if (lbl == "AR45") return 44.96803996 ; + if (lbl == "AR46") return 45.96809413 ; + if (lbl == "AR47") return 46.97218679 ; + if (lbl == "AR48") return 47.97454 ; + if (lbl == "AR49") return 48.98052 ; + if (lbl == "AR50") return 49.98443 ; + if (lbl == "AR51") return 50.99163 ; + if (lbl == "AR52") return 51.99678 ; + if (lbl == "AR53") return 53.00494 ; + if (lbl == "K") return 38.96370668 ; + if (lbl == "K32") return 32.02192 ; + if (lbl == "K33") return 33.00726 ; + if (lbl == "K34") return 33.99841 ; + if (lbl == "K35") return 34.98800969 ; + if (lbl == "K36") return 35.98129224 ; + if (lbl == "K37") return 36.97337589 ; + if (lbl == "K38") return 37.96908118 ; + if (lbl == "K39") return 38.96370668 ; + if (lbl == "K40") return 39.96399848 ; + if (lbl == "K41") return 40.96182576 ; + if (lbl == "K42") return 41.96240281 ; + if (lbl == "K43") return 42.96071554 ; + if (lbl == "K44") return 43.9615568 ; + if (lbl == "K45") return 44.96069949 ; + if (lbl == "K46") return 45.96197686 ; + if (lbl == "K47") return 46.96167847 ; + if (lbl == "K48") return 47.96551354 ; + if (lbl == "K49") return 48.96745093 ; + if (lbl == "K50") return 49.97278336 ; + if (lbl == "K51") return 50.97638 ; + if (lbl == "K52") return 51.98261 ; + if (lbl == "K53") return 52.98712 ; + if (lbl == "K54") return 53.9942 ; + if (lbl == "K55") return 54.99971 ; + if (lbl == "CA") return 39.96259098 ; + if (lbl == "CA34") return 34.01412 ; + if (lbl == "CA35") return 35.00494 ; + if (lbl == "CA36") return 35.99308706 ; + if (lbl == "CA37") return 36.98587027 ; + if (lbl == "CA38") return 37.97631845 ; + if (lbl == "CA39") return 38.97071973 ; + if (lbl == "CA40") return 39.96259098 ; + if (lbl == "CA41") return 40.96227806 ; + if (lbl == "CA42") return 41.95861801 ; + if (lbl == "CA43") return 42.95876663 ; + if (lbl == "CA44") return 43.95548175 ; + if (lbl == "CA45") return 44.95618657 ; + if (lbl == "CA46") return 45.95369259 ; + if (lbl == "CA47") return 46.95454601 ; + if (lbl == "CA48") return 47.95253418 ; + if (lbl == "CA49") return 48.95567415 ; + if (lbl == "CA50") return 49.95751896 ; + if (lbl == "CA51") return 50.96149921 ; + if (lbl == "CA52") return 51.9651 ; + if (lbl == "CA53") return 52.97005 ; + if (lbl == "CA54") return 53.97435 ; + if (lbl == "CA55") return 54.98055 ; + if (lbl == "CA56") return 55.98557 ; + if (lbl == "CA57") return 56.992356 ; + if (lbl == "SC") return 44.95591191 ; + if (lbl == "SC36") return 36.01492 ; + if (lbl == "SC37") return 37.00305 ; + if (lbl == "SC38") return 37.9947 ; + if (lbl == "SC39") return 38.98479 ; + if (lbl == "SC40") return 39.97796741 ; + if (lbl == "SC41") return 40.96925113 ; + if (lbl == "SC42") return 41.96551643 ; + if (lbl == "SC43") return 42.96115066 ; + if (lbl == "SC44") return 43.95940275 ; + if (lbl == "SC45") return 44.95591191 ; + if (lbl == "SC46") return 45.95517189 ; + if (lbl == "SC47") return 46.95240751 ; + if (lbl == "SC48") return 47.95223147 ; + if (lbl == "SC49") return 48.95002398 ; + if (lbl == "SC50") return 49.95218769 ; + if (lbl == "SC51") return 50.95360337 ; + if (lbl == "SC52") return 51.95667547 ; + if (lbl == "SC53") return 52.95961 ; + if (lbl == "SC54") return 53.96326456 ; + if (lbl == "SC55") return 54.96824395 ; + if (lbl == "SC56") return 55.97287 ; + if (lbl == "SC57") return 56.97779 ; + if (lbl == "SC58") return 57.98371 ; + if (lbl == "SC59") return 58.98922 ; + if (lbl == "SC60") return 59.99571 ; + if (lbl == "TI") return 47.94794628 ; + if (lbl == "TI38") return 38.00977 ; + if (lbl == "TI39") return 39.00161 ; + if (lbl == "TI40") return 39.99049884 ; + if (lbl == "TI41") return 40.983145 ; + if (lbl == "TI42") return 41.9730309 ; + if (lbl == "TI43") return 42.9685225 ; + if (lbl == "TI44") return 43.95969007 ; + if (lbl == "TI45") return 44.95812562 ; + if (lbl == "TI46") return 45.95263156 ; + if (lbl == "TI47") return 46.95176309 ; + if (lbl == "TI48") return 47.94794628 ; + if (lbl == "TI49") return 48.94786998 ; + if (lbl == "TI50") return 49.94479119 ; + if (lbl == "TI51") return 50.94661496 ; + if (lbl == "TI52") return 51.94689731 ; + if (lbl == "TI53") return 52.94972717 ; + if (lbl == "TI54") return 53.9510524 ; + if (lbl == "TI55") return 54.95526506 ; + if (lbl == "TI56") return 55.95819964 ; + if (lbl == "TI57") return 56.96398914 ; + if (lbl == "TI58") return 57.96697 ; + if (lbl == "TI59") return 58.97293 ; + if (lbl == "TI60") return 59.97676 ; + if (lbl == "TI61") return 60.9832 ; + if (lbl == "TI62") return 61.98749 ; + if (lbl == "TI63") return 62.99442 ; + if (lbl == "V") return 50.94395951 ; + if (lbl == "V40") return 40.01109 ; + if (lbl == "V41") return 40.99978 ; + if (lbl == "V42") return 41.99123 ; + if (lbl == "V43") return 42.98065 ; + if (lbl == "V44") return 43.97411 ; + if (lbl == "V45") return 44.96577581 ; + if (lbl == "V46") return 45.96020048 ; + if (lbl == "V47") return 46.95490894 ; + if (lbl == "V48") return 47.95225371 ; + if (lbl == "V49") return 48.9485161 ; + if (lbl == "V50") return 49.94715849 ; + if (lbl == "V51") return 50.94395951 ; + if (lbl == "V52") return 51.94477548 ; + if (lbl == "V53") return 52.94433798 ; + if (lbl == "V54") return 53.94643985 ; + if (lbl == "V55") return 54.9472337 ; + if (lbl == "V56") return 55.95053097 ; + if (lbl == "V57") return 56.95256143 ; + if (lbl == "V58") return 57.95683414 ; + if (lbl == "V59") return 58.96020741 ; + if (lbl == "V60") return 59.96502686 ; + if (lbl == "V61") return 60.96848 ; + if (lbl == "V62") return 61.97378 ; + if (lbl == "V63") return 62.97755 ; + if (lbl == "V64") return 63.98347 ; + if (lbl == "V65") return 64.98792 ; + if (lbl == "CR") return 51.94050747 ; + if (lbl == "CR42") return 42.00643 ; + if (lbl == "CR43") return 42.99771 ; + if (lbl == "CR44") return 43.985549 ; + if (lbl == "CR45") return 44.97964 ; + if (lbl == "CR46") return 45.96835864 ; + if (lbl == "CR47") return 46.96290005 ; + if (lbl == "CR48") return 47.95403172 ; + if (lbl == "CR49") return 48.95133572 ; + if (lbl == "CR50") return 49.94604421 ; + if (lbl == "CR51") return 50.94476743 ; + if (lbl == "CR52") return 51.94050747 ; + if (lbl == "CR53") return 52.94064939 ; + if (lbl == "CR54") return 53.9388804 ; + if (lbl == "CR55") return 54.94083967 ; + if (lbl == "CR56") return 55.94065314 ; + if (lbl == "CR57") return 56.94361301 ; + if (lbl == "CR58") return 57.94435313 ; + if (lbl == "CR59") return 58.94858637 ; + if (lbl == "CR60") return 59.95007603 ; + if (lbl == "CR61") return 60.9547172 ; + if (lbl == "CR62") return 61.95661319 ; + if (lbl == "CR63") return 62.96186 ; + if (lbl == "CR64") return 63.96441 ; + if (lbl == "CR65") return 64.97016 ; + if (lbl == "CR66") return 65.97338 ; + if (lbl == "CR67") return 66.97955 ; + if (lbl == "MN") return 54.93804514 ; + if (lbl == "MN44") return 44.00687 ; + if (lbl == "MN45") return 44.99451 ; + if (lbl == "MN46") return 45.98672 ; + if (lbl == "MN47") return 46.9761 ; + if (lbl == "MN48") return 47.96852 ; + if (lbl == "MN49") return 48.95961801 ; + if (lbl == "MN50") return 49.95423823 ; + if (lbl == "MN51") return 50.94821079 ; + if (lbl == "MN52") return 51.94556546 ; + if (lbl == "MN53") return 52.94129012 ; + if (lbl == "MN54") return 53.94035885 ; + if (lbl == "MN55") return 54.93804514 ; + if (lbl == "MN56") return 55.93890491 ; + if (lbl == "MN57") return 56.93828538 ; + if (lbl == "MN58") return 57.93998155 ; + if (lbl == "MN59") return 58.94044024 ; + if (lbl == "MN60") return 59.94291125 ; + if (lbl == "MN61") return 60.94465264 ; + if (lbl == "MN62") return 61.94842822 ; + if (lbl == "MN63") return 62.95023999 ; + if (lbl == "MN64") return 63.95424909 ; + if (lbl == "MN65") return 64.95633607 ; + if (lbl == "MN66") return 65.96108 ; + if (lbl == "MN67") return 66.96414 ; + if (lbl == "MN68") return 67.9693 ; + if (lbl == "MN69") return 68.97284 ; + if (lbl == "FE") return 55.93493748 ; + if (lbl == "FE45") return 45.014578 ; + if (lbl == "FE46") return 46.00081 ; + if (lbl == "FE47") return 46.99289 ; + if (lbl == "FE48") return 47.980504 ; + if (lbl == "FE49") return 48.97361 ; + if (lbl == "FE50") return 49.96298898 ; + if (lbl == "FE51") return 50.95681954 ; + if (lbl == "FE52") return 51.94811388 ; + if (lbl == "FE53") return 52.94530794 ; + if (lbl == "FE54") return 53.9396105 ; + if (lbl == "FE55") return 54.93829336 ; + if (lbl == "FE56") return 55.93493748 ; + if (lbl == "FE57") return 56.93539397 ; + if (lbl == "FE58") return 57.93327556 ; + if (lbl == "FE59") return 58.93487546 ; + if (lbl == "FE60") return 59.93407168 ; + if (lbl == "FE61") return 60.93674528 ; + if (lbl == "FE62") return 61.93676744 ; + if (lbl == "FE63") return 62.94036909 ; + if (lbl == "FE64") return 63.94120127 ; + if (lbl == "FE65") return 64.94538027 ; + if (lbl == "FE66") return 65.94678064 ; + if (lbl == "FE67") return 66.95094724 ; + if (lbl == "FE68") return 67.9537 ; + if (lbl == "FE69") return 68.95878 ; + if (lbl == "FE70") return 69.96146 ; + if (lbl == "FE71") return 70.96672 ; + if (lbl == "FE72") return 71.96962 ; + if (lbl == "CO") return 58.93319505 ; + if (lbl == "CO47") return 47.01149 ; + if (lbl == "CO48") return 48.00176 ; + if (lbl == "CO49") return 48.98972 ; + if (lbl == "CO50") return 49.98154 ; + if (lbl == "CO51") return 50.97072 ; + if (lbl == "CO52") return 51.96359 ; + if (lbl == "CO53") return 52.9542189 ; + if (lbl == "CO54") return 53.94845964 ; + if (lbl == "CO55") return 54.94199903 ; + if (lbl == "CO56") return 55.93983928 ; + if (lbl == "CO57") return 56.93629137 ; + if (lbl == "CO58") return 57.93575281 ; + if (lbl == "CO59") return 58.93319505 ; + if (lbl == "CO60") return 59.93381706 ; + if (lbl == "CO61") return 60.93247576 ; + if (lbl == "CO62") return 61.93405056 ; + if (lbl == "CO63") return 62.93361161 ; + if (lbl == "CO64") return 63.93580991 ; + if (lbl == "CO65") return 64.93647846 ; + if (lbl == "CO66") return 65.939762 ; + if (lbl == "CO67") return 66.94088953 ; + if (lbl == "CO68") return 67.94487306 ; + if (lbl == "CO69") return 68.94632 ; + if (lbl == "CO70") return 69.951 ; + if (lbl == "CO71") return 70.9529 ; + if (lbl == "CO72") return 71.95781 ; + if (lbl == "CO73") return 72.96024 ; + if (lbl == "CO74") return 73.96538 ; + if (lbl == "CO75") return 74.96833 ; + if (lbl == "NI") return 57.93534291 ; + if (lbl == "NI48") return 48.01975 ; + if (lbl == "NI49") return 49.00966 ; + if (lbl == "NI50") return 49.99593 ; + if (lbl == "NI51") return 50.98772 ; + if (lbl == "NI52") return 51.97568 ; + if (lbl == "NI53") return 52.96847 ; + if (lbl == "NI54") return 53.9579055 ; + if (lbl == "NI55") return 54.95133025 ; + if (lbl == "NI56") return 55.94213202 ; + if (lbl == "NI57") return 56.93979353 ; + if (lbl == "NI58") return 57.93534291 ; + if (lbl == "NI59") return 58.93434671 ; + if (lbl == "NI60") return 59.93078637 ; + if (lbl == "NI61") return 60.93105603 ; + if (lbl == "NI62") return 61.92834512 ; + if (lbl == "NI63") return 62.92966937 ; + if (lbl == "NI64") return 63.92796596 ; + if (lbl == "NI65") return 64.9300843 ; + if (lbl == "NI66") return 65.92913933 ; + if (lbl == "NI67") return 66.93156941 ; + if (lbl == "NI68") return 67.93186879 ; + if (lbl == "NI69") return 68.93561027 ; + if (lbl == "NI70") return 69.9365 ; + if (lbl == "NI71") return 70.94073628 ; + if (lbl == "NI72") return 71.94209268 ; + if (lbl == "NI73") return 72.94647 ; + if (lbl == "NI74") return 73.94807 ; + if (lbl == "NI75") return 74.95287 ; + if (lbl == "NI76") return 75.95533 ; + if (lbl == "NI77") return 76.96055 ; + if (lbl == "NI78") return 77.96318 ; + if (lbl == "CU") return 62.92959747 ; + if (lbl == "CU52") return 51.99718 ; + if (lbl == "CU53") return 52.98555 ; + if (lbl == "CU54") return 53.97671 ; + if (lbl == "CU55") return 54.96605 ; + if (lbl == "CU56") return 55.95856 ; + if (lbl == "CU57") return 56.94921108 ; + if (lbl == "CU58") return 57.9445385 ; + if (lbl == "CU59") return 58.93949803 ; + if (lbl == "CU60") return 59.93736503 ; + if (lbl == "CU61") return 60.93345782 ; + if (lbl == "CU62") return 61.93258375 ; + if (lbl == "CU63") return 62.92959747 ; + if (lbl == "CU64") return 63.92976418 ; + if (lbl == "CU65") return 64.92778949 ; + if (lbl == "CU66") return 65.92886881 ; + if (lbl == "CU67") return 66.92773031 ; + if (lbl == "CU68") return 67.92961089 ; + if (lbl == "CU69") return 68.92942927 ; + if (lbl == "CU70") return 69.93239234 ; + if (lbl == "CU71") return 70.93267683 ; + if (lbl == "CU72") return 71.93582031 ; + if (lbl == "CU73") return 72.93667528 ; + if (lbl == "CU74") return 73.93987486 ; + if (lbl == "CU75") return 74.9419 ; + if (lbl == "CU76") return 75.94527503 ; + if (lbl == "CU77") return 76.94785 ; + if (lbl == "CU78") return 77.95196 ; + if (lbl == "CU79") return 78.95456 ; + if (lbl == "CU80") return 79.96087 ; + if (lbl == "ZN") return 63.92914222 ; + if (lbl == "ZN54") return 53.99295 ; + if (lbl == "ZN55") return 54.98398 ; + if (lbl == "ZN56") return 55.97238 ; + if (lbl == "ZN57") return 56.964788 ; + if (lbl == "ZN58") return 57.95459156 ; + if (lbl == "ZN59") return 58.94926376 ; + if (lbl == "ZN60") return 59.94182704 ; + if (lbl == "ZN61") return 60.93951064 ; + if (lbl == "ZN62") return 61.93432976 ; + if (lbl == "ZN63") return 62.93321157 ; + if (lbl == "ZN64") return 63.92914222 ; + if (lbl == "ZN65") return 64.92924098 ; + if (lbl == "ZN66") return 65.92603342 ; + if (lbl == "ZN67") return 66.92712735 ; + if (lbl == "ZN68") return 67.92484415 ; + if (lbl == "ZN69") return 68.92655028 ; + if (lbl == "ZN70") return 69.92531927 ; + if (lbl == "ZN71") return 70.9277216 ; + if (lbl == "ZN72") return 71.92685795 ; + if (lbl == "ZN73") return 72.9297791 ; + if (lbl == "ZN74") return 73.92945861 ; + if (lbl == "ZN75") return 74.93293674 ; + if (lbl == "ZN76") return 75.93329357 ; + if (lbl == "ZN77") return 76.93695897 ; + if (lbl == "ZN78") return 77.93844022 ; + if (lbl == "ZN79") return 78.942652 ; + if (lbl == "ZN80") return 79.94434235 ; + if (lbl == "ZN81") return 80.95048 ; + if (lbl == "ZN82") return 81.95442 ; + if (lbl == "ZN83") return 82.96103 ; + if (lbl == "GA") return 68.92557359 ; + if (lbl == "GA56") return 55.99491 ; + if (lbl == "GA57") return 56.98293 ; + if (lbl == "GA58") return 57.97425 ; + if (lbl == "GA59") return 58.96337 ; + if (lbl == "GA60") return 59.95706 ; + if (lbl == "GA61") return 60.94944629 ; + if (lbl == "GA62") return 61.94417524 ; + if (lbl == "GA63") return 62.9392942 ; + if (lbl == "GA64") return 63.93683875 ; + if (lbl == "GA65") return 64.93273475 ; + if (lbl == "GA66") return 65.93158901 ; + if (lbl == "GA67") return 66.9282017 ; + if (lbl == "GA68") return 67.92798008 ; + if (lbl == "GA69") return 68.92557359 ; + if (lbl == "GA70") return 69.92602197 ; + if (lbl == "GA71") return 70.92470135 ; + if (lbl == "GA72") return 71.92636627 ; + if (lbl == "GA73") return 72.92517468 ; + if (lbl == "GA74") return 73.92694576 ; + if (lbl == "GA75") return 74.92650025 ; + if (lbl == "GA76") return 75.92882763 ; + if (lbl == "GA77") return 76.9291543 ; + if (lbl == "GA78") return 77.93160818 ; + if (lbl == "GA79") return 78.93289326 ; + if (lbl == "GA80") return 79.93651578 ; + if (lbl == "GA81") return 80.93775236 ; + if (lbl == "GA82") return 81.94299 ; + if (lbl == "GA83") return 82.94698 ; + if (lbl == "GA84") return 83.95265 ; + if (lbl == "GA85") return 84.957 ; + if (lbl == "GA86") return 85.96312 ; + if (lbl == "GE") return 73.92117777 ; + if (lbl == "GE58") return 57.99101 ; + if (lbl == "GE59") return 58.98175 ; + if (lbl == "GE60") return 59.97019 ; + if (lbl == "GE61") return 60.96379 ; + if (lbl == "GE62") return 61.95465 ; + if (lbl == "GE63") return 62.94964 ; + if (lbl == "GE64") return 63.941653 ; + if (lbl == "GE65") return 64.93943641 ; + if (lbl == "GE66") return 65.93384345 ; + if (lbl == "GE67") return 66.93273407 ; + if (lbl == "GE68") return 67.92809424 ; + if (lbl == "GE69") return 68.92796453 ; + if (lbl == "GE70") return 69.92424738 ; + if (lbl == "GE71") return 70.92495095 ; + if (lbl == "GE72") return 71.92207582 ; + if (lbl == "GE73") return 72.92345895 ; + if (lbl == "GE74") return 73.92117777 ; + if (lbl == "GE75") return 74.92285895 ; + if (lbl == "GE76") return 75.92140256 ; + if (lbl == "GE77") return 76.92354859 ; + if (lbl == "GE78") return 77.92285274 ; + if (lbl == "GE79") return 78.925401 ; + if (lbl == "GE80") return 79.92537239 ; + if (lbl == "GE81") return 80.92882047 ; + if (lbl == "GE82") return 81.92954973 ; + if (lbl == "GE83") return 82.93462 ; + if (lbl == "GE84") return 83.93747 ; + if (lbl == "GE85") return 84.94303 ; + if (lbl == "GE86") return 85.94649 ; + if (lbl == "GE87") return 86.95251 ; + if (lbl == "GE88") return 87.95691 ; + if (lbl == "GE89") return 88.96383 ; + if (lbl == "AS") return 74.92159648 ; + if (lbl == "AS60") return 59.99313 ; + if (lbl == "AS61") return 60.98062 ; + if (lbl == "AS62") return 61.9732 ; + if (lbl == "AS63") return 62.96369 ; + if (lbl == "AS64") return 63.957572 ; + if (lbl == "AS65") return 64.949564 ; + if (lbl == "AS66") return 65.94471 ; + if (lbl == "AS67") return 66.93918607 ; + if (lbl == "AS68") return 67.93676907 ; + if (lbl == "AS69") return 68.93227368 ; + if (lbl == "AS70") return 69.93092483 ; + if (lbl == "AS71") return 70.92711243 ; + if (lbl == "AS72") return 71.92675228 ; + if (lbl == "AS73") return 72.92382484 ; + if (lbl == "AS74") return 73.92392869 ; + if (lbl == "AS75") return 74.92159648 ; + if (lbl == "AS76") return 75.92239402 ; + if (lbl == "AS77") return 76.92064729 ; + if (lbl == "AS78") return 77.92182728 ; + if (lbl == "AS79") return 78.92094793 ; + if (lbl == "AS80") return 79.92253382 ; + if (lbl == "AS81") return 80.92213229 ; + if (lbl == "AS82") return 81.92450407 ; + if (lbl == "AS83") return 82.92498002 ; + if (lbl == "AS84") return 83.929058 ; + if (lbl == "AS85") return 84.93202 ; + if (lbl == "AS86") return 85.9365 ; + if (lbl == "AS87") return 86.9399 ; + if (lbl == "AS88") return 87.94494 ; + if (lbl == "AS89") return 88.94939 ; + if (lbl == "AS90") return 89.9555 ; + if (lbl == "AS91") return 90.96043 ; + if (lbl == "AS92") return 91.9668 ; + if (lbl == "SE") return 79.91652127 ; + if (lbl == "SE65") return 64.96466 ; + if (lbl == "SE66") return 65.95521 ; + if (lbl == "SE67") return 66.95009 ; + if (lbl == "SE68") return 67.941798 ; + if (lbl == "SE69") return 68.93955782 ; + if (lbl == "SE70") return 69.93339064 ; + if (lbl == "SE71") return 70.93224182 ; + if (lbl == "SE72") return 71.92711235 ; + if (lbl == "SE73") return 72.92676535 ; + if (lbl == "SE74") return 73.92247644 ; + if (lbl == "SE75") return 74.92252337 ; + if (lbl == "SE76") return 75.9192136 ; + if (lbl == "SE77") return 76.91991404 ; + if (lbl == "SE78") return 77.91730909 ; + if (lbl == "SE79") return 78.9184991 ; + if (lbl == "SE80") return 79.91652127 ; + if (lbl == "SE81") return 80.91799247 ; + if (lbl == "SE82") return 81.9166994 ; + if (lbl == "SE83") return 82.91911847 ; + if (lbl == "SE84") return 83.91846235 ; + if (lbl == "SE85") return 84.92224505 ; + if (lbl == "SE86") return 85.92427158 ; + if (lbl == "SE87") return 86.92852136 ; + if (lbl == "SE88") return 87.931424 ; + if (lbl == "SE89") return 88.93645 ; + if (lbl == "SE90") return 89.93996 ; + if (lbl == "SE91") return 90.94596 ; + if (lbl == "SE92") return 91.94992 ; + if (lbl == "SE93") return 92.95629 ; + if (lbl == "SE94") return 93.96049 ; + if (lbl == "BR") return 78.91833709 ; + if (lbl == "BR67") return 66.96479 ; + if (lbl == "BR68") return 67.958516 ; + if (lbl == "BR69") return 68.950106 ; + if (lbl == "BR70") return 69.944792 ; + if (lbl == "BR71") return 70.93874 ; + if (lbl == "BR72") return 71.93664457 ; + if (lbl == "BR73") return 72.93169152 ; + if (lbl == "BR74") return 73.92989103 ; + if (lbl == "BR75") return 74.92577621 ; + if (lbl == "BR76") return 75.92454147 ; + if (lbl == "BR77") return 76.92137908 ; + if (lbl == "BR78") return 77.92114571 ; + if (lbl == "BR79") return 78.91833709 ; + if (lbl == "BR80") return 79.9185293 ; + if (lbl == "BR81") return 80.91629056 ; + if (lbl == "BR82") return 81.91680412 ; + if (lbl == "BR83") return 82.91518042 ; + if (lbl == "BR84") return 83.91647897 ; + if (lbl == "BR85") return 84.9156084 ; + if (lbl == "BR86") return 85.91879758 ; + if (lbl == "BR87") return 86.92071132 ; + if (lbl == "BR88") return 87.92406593 ; + if (lbl == "BR89") return 88.92638533 ; + if (lbl == "BR90") return 89.93062774 ; + if (lbl == "BR91") return 90.9339681 ; + if (lbl == "BR92") return 91.93925871 ; + if (lbl == "BR93") return 92.94305 ; + if (lbl == "BR94") return 93.94868 ; + if (lbl == "BR95") return 94.95287 ; + if (lbl == "BR96") return 95.95853 ; + if (lbl == "BR97") return 96.9628 ; + if (lbl == "KR") return 85.91061073 ; + if (lbl == "KR69") return 68.96518 ; + if (lbl == "KR70") return 69.955259 ; + if (lbl == "KR71") return 70.94962574 ; + if (lbl == "KR72") return 71.94209204 ; + if (lbl == "KR73") return 72.9392892 ; + if (lbl == "KR74") return 73.93308437 ; + if (lbl == "KR75") return 74.93094575 ; + if (lbl == "KR76") return 75.92591008 ; + if (lbl == "KR77") return 76.92467 ; + if (lbl == "KR78") return 77.92036478 ; + if (lbl == "KR79") return 78.92008243 ; + if (lbl == "KR80") return 79.91637897 ; + if (lbl == "KR81") return 80.91659202 ; + if (lbl == "KR82") return 81.9134836 ; + if (lbl == "KR83") return 82.9141361 ; + if (lbl == "KR84") return 83.91150669 ; + if (lbl == "KR85") return 84.91252733 ; + if (lbl == "KR86") return 85.91061073 ; + if (lbl == "KR87") return 86.91335486 ; + if (lbl == "KR88") return 87.91444697 ; + if (lbl == "KR89") return 88.91763058 ; + if (lbl == "KR90") return 89.91951656 ; + if (lbl == "KR91") return 90.92344522 ; + if (lbl == "KR92") return 91.92615621 ; + if (lbl == "KR93") return 92.93127436 ; + if (lbl == "KR94") return 93.93436 ; + if (lbl == "KR95") return 94.93984 ; + if (lbl == "KR96") return 95.94307 ; + if (lbl == "KR97") return 96.94856 ; + if (lbl == "KR98") return 97.95191 ; + if (lbl == "KR99") return 98.9576 ; + if (lbl == "KR100") return 99.96114 ; + if (lbl == "RB") return 84.91178974 ; + if (lbl == "RB71") return 70.96532 ; + if (lbl == "RB72") return 71.95908 ; + if (lbl == "RB73") return 72.950561 ; + if (lbl == "RB74") return 73.94426475 ; + if (lbl == "RB75") return 74.93857 ; + if (lbl == "RB76") return 75.93507223 ; + if (lbl == "RB77") return 76.930408 ; + if (lbl == "RB78") return 77.928141 ; + if (lbl == "RB79") return 78.92398946 ; + if (lbl == "RB80") return 79.92251925 ; + if (lbl == "RB81") return 80.91899591 ; + if (lbl == "RB82") return 81.9182086 ; + if (lbl == "RB83") return 82.9151097 ; + if (lbl == "RB84") return 83.91438482 ; + if (lbl == "RB85") return 84.91178974 ; + if (lbl == "RB86") return 85.91116742 ; + if (lbl == "RB87") return 86.90918053 ; + if (lbl == "RB88") return 87.91131559 ; + if (lbl == "RB89") return 88.91227802 ; + if (lbl == "RB90") return 89.91480169 ; + if (lbl == "RB91") return 90.91653696 ; + if (lbl == "RB92") return 91.9197289 ; + if (lbl == "RB93") return 92.92204188 ; + if (lbl == "RB94") return 93.92640495 ; + if (lbl == "RB95") return 94.92930289 ; + if (lbl == "RB96") return 95.93427264 ; + if (lbl == "RB97") return 96.93735192 ; + if (lbl == "RB98") return 97.94179067 ; + if (lbl == "RB99") return 98.94537928 ; + if (lbl == "RB100") return 99.94987 ; + if (lbl == "RB101") return 100.9531964 ; + if (lbl == "RB102") return 101.95887 ; + if (lbl == "SR") return 87.90561212 ; + if (lbl == "SR73") return 72.96597 ; + if (lbl == "SR74") return 73.95631 ; + if (lbl == "SR75") return 74.94994957 ; + if (lbl == "SR76") return 75.94176678 ; + if (lbl == "SR77") return 76.93794478 ; + if (lbl == "SR78") return 77.93218 ; + if (lbl == "SR79") return 78.929708 ; + if (lbl == "SR80") return 79.92452101 ; + if (lbl == "SR81") return 80.92321185 ; + if (lbl == "SR82") return 81.91840164 ; + if (lbl == "SR83") return 82.9175567 ; + if (lbl == "SR84") return 83.91342528 ; + if (lbl == "SR85") return 84.9129328 ; + if (lbl == "SR86") return 85.9092602 ; + if (lbl == "SR87") return 86.90887712 ; + if (lbl == "SR88") return 87.90561212 ; + if (lbl == "SR89") return 88.90745068 ; + if (lbl == "SR90") return 89.90773789 ; + if (lbl == "SR91") return 90.9102031 ; + if (lbl == "SR92") return 91.91103786 ; + if (lbl == "SR93") return 92.91402563 ; + if (lbl == "SR94") return 93.91536131 ; + if (lbl == "SR95") return 94.91935877 ; + if (lbl == "SR96") return 95.9216968 ; + if (lbl == "SR97") return 96.92615292 ; + if (lbl == "SR98") return 97.92845293 ; + if (lbl == "SR99") return 98.93324093 ; + if (lbl == "SR100") return 99.93535191 ; + if (lbl == "SR101") return 100.9405179 ; + if (lbl == "SR102") return 101.943019 ; + if (lbl == "SR103") return 102.94895 ; + if (lbl == "SR104") return 103.95233 ; + if (lbl == "SR105") return 104.95858 ; + if (lbl == "Y") return 88.9058483 ; + if (lbl == "Y76") return 75.95845 ; + if (lbl == "Y77") return 76.949645 ; + if (lbl == "Y78") return 77.94361 ; + if (lbl == "Y79") return 78.93735163 ; + if (lbl == "Y80") return 79.93428 ; + if (lbl == "Y81") return 80.92912747 ; + if (lbl == "Y82") return 81.92679245 ; + if (lbl == "Y83") return 82.92235424 ; + if (lbl == "Y84") return 83.92038826 ; + if (lbl == "Y85") return 84.91643304 ; + if (lbl == "Y86") return 85.91488558 ; + if (lbl == "Y87") return 86.91087573 ; + if (lbl == "Y88") return 87.90950115 ; + if (lbl == "Y89") return 88.9058483 ; + if (lbl == "Y90") return 89.90715189 ; + if (lbl == "Y91") return 90.90730479 ; + if (lbl == "Y92") return 91.90894914 ; + if (lbl == "Y93") return 92.90958271 ; + if (lbl == "Y94") return 93.91159525 ; + if (lbl == "Y95") return 94.91282062 ; + if (lbl == "Y96") return 95.91589134 ; + if (lbl == "Y97") return 96.918134 ; + if (lbl == "Y98") return 97.92220302 ; + if (lbl == "Y99") return 98.9246362 ; + if (lbl == "Y100") return 99.92775659 ; + if (lbl == "Y101") return 100.9303139 ; + if (lbl == "Y102") return 101.9335557 ; + if (lbl == "Y103") return 102.93673 ; + if (lbl == "Y104") return 103.94105 ; + if (lbl == "Y105") return 104.94487 ; + if (lbl == "Y106") return 105.94979 ; + if (lbl == "Y107") return 106.95414 ; + if (lbl == "Y108") return 107.95948 ; + if (lbl == "ZR") return 89.90470442 ; + if (lbl == "ZR78") return 77.95523 ; + if (lbl == "ZR79") return 78.94916 ; + if (lbl == "ZR80") return 79.9404 ; + if (lbl == "ZR81") return 80.93721003 ; + if (lbl == "ZR82") return 81.931087 ; + if (lbl == "ZR83") return 82.9286538 ; + if (lbl == "ZR84") return 83.92325 ; + if (lbl == "ZR85") return 84.92147118 ; + if (lbl == "ZR86") return 85.91647359 ; + if (lbl == "ZR87") return 86.91481625 ; + if (lbl == "ZR88") return 87.9102269 ; + if (lbl == "ZR89") return 88.9088895 ; + if (lbl == "ZR90") return 89.90470442 ; + if (lbl == "ZR91") return 90.90564577 ; + if (lbl == "ZR92") return 91.90504085 ; + if (lbl == "ZR93") return 92.90647601 ; + if (lbl == "ZR94") return 93.90631519 ; + if (lbl == "ZR95") return 94.9080426 ; + if (lbl == "ZR96") return 95.90827339 ; + if (lbl == "ZR97") return 96.91095311 ; + if (lbl == "ZR98") return 97.91273489 ; + if (lbl == "ZR99") return 98.91651211 ; + if (lbl == "ZR100") return 99.91776189 ; + if (lbl == "ZR101") return 100.9211404 ; + if (lbl == "ZR102") return 101.9229813 ; + if (lbl == "ZR103") return 102.9265996 ; + if (lbl == "ZR104") return 103.92878 ; + if (lbl == "ZR105") return 104.93305 ; + if (lbl == "ZR106") return 105.93591 ; + if (lbl == "ZR107") return 106.94075 ; + if (lbl == "ZR108") return 107.94396 ; + if (lbl == "ZR109") return 108.94924 ; + if (lbl == "ZR110") return 109.95287 ; + if (lbl == "NB") return 92.90637806 ; + if (lbl == "NB81") return 80.94903 ; + if (lbl == "NB82") return 81.94313 ; + if (lbl == "NB83") return 82.93670538 ; + if (lbl == "NB84") return 83.93357 ; + if (lbl == "NB85") return 84.92791245 ; + if (lbl == "NB86") return 85.92503833 ; + if (lbl == "NB87") return 86.92036111 ; + if (lbl == "NB88") return 87.91833216 ; + if (lbl == "NB89") return 88.91341825 ; + if (lbl == "NB90") return 89.91126485 ; + if (lbl == "NB91") return 90.90699624 ; + if (lbl == "NB92") return 91.90719389 ; + if (lbl == "NB93") return 92.90637806 ; + if (lbl == "NB94") return 93.90728389 ; + if (lbl == "NB95") return 94.90683579 ; + if (lbl == "NB96") return 95.90810065 ; + if (lbl == "NB97") return 96.90809856 ; + if (lbl == "NB98") return 97.91032841 ; + if (lbl == "NB99") return 98.91161838 ; + if (lbl == "NB100") return 99.91418162 ; + if (lbl == "NB101") return 100.915252 ; + if (lbl == "NB102") return 101.9180376 ; + if (lbl == "NB103") return 102.9191438 ; + if (lbl == "NB104") return 103.9224647 ; + if (lbl == "NB105") return 104.9239365 ; + if (lbl == "NB106") return 105.92797 ; + if (lbl == "NB107") return 106.93031 ; + if (lbl == "NB108") return 107.93484 ; + if (lbl == "NB109") return 108.93763 ; + if (lbl == "NB110") return 109.94244 ; + if (lbl == "NB111") return 110.94565 ; + if (lbl == "NB112") return 111.95083 ; + if (lbl == "NB113") return 112.9547 ; + if (lbl == "MO") return 97.90540817 ; + if (lbl == "MO83") return 82.94874 ; + if (lbl == "MO84") return 83.94009 ; + if (lbl == "MO85") return 84.93655 ; + if (lbl == "MO86") return 85.9306959 ; + if (lbl == "MO87") return 86.9273265 ; + if (lbl == "MO88") return 87.92195324 ; + if (lbl == "MO89") return 88.91948001 ; + if (lbl == "MO90") return 89.9139369 ; + if (lbl == "MO91") return 90.91175019 ; + if (lbl == "MO92") return 91.90681099 ; + if (lbl == "MO93") return 92.90681261 ; + if (lbl == "MO94") return 93.90508827 ; + if (lbl == "MO95") return 94.90584213 ; + if (lbl == "MO96") return 95.90467948 ; + if (lbl == "MO97") return 96.90602147 ; + if (lbl == "MO98") return 97.90540817 ; + if (lbl == "MO99") return 98.90771187 ; + if (lbl == "MO100") return 99.90747734 ; + if (lbl == "MO101") return 100.910347 ; + if (lbl == "MO102") return 101.9102974 ; + if (lbl == "MO103") return 102.9132071 ; + if (lbl == "MO104") return 103.9137636 ; + if (lbl == "MO105") return 104.9169746 ; + if (lbl == "MO106") return 105.9181368 ; + if (lbl == "MO107") return 106.9216926 ; + if (lbl == "MO108") return 107.923453 ; + if (lbl == "MO109") return 108.92781 ; + if (lbl == "MO110") return 109.92973 ; + if (lbl == "MO111") return 110.93441 ; + if (lbl == "MO112") return 111.93684 ; + if (lbl == "MO113") return 112.94188 ; + if (lbl == "MO114") return 113.94492 ; + if (lbl == "MO115") return 114.95029 ; + if (lbl == "TC") return 98.90625475 ; + if (lbl == "TC85") return 84.94883 ; + if (lbl == "TC86") return 85.94288 ; + if (lbl == "TC87") return 86.93653 ; + if (lbl == "TC88") return 87.932678 ; + if (lbl == "TC89") return 88.927167 ; + if (lbl == "TC90") return 89.92355656 ; + if (lbl == "TC91") return 90.91842764 ; + if (lbl == "TC92") return 91.91526017 ; + if (lbl == "TC93") return 92.91024898 ; + if (lbl == "TC94") return 93.909657 ; + if (lbl == "TC95") return 94.90765708 ; + if (lbl == "TC96") return 95.90787138 ; + if (lbl == "TC97") return 96.90636536 ; + if (lbl == "TC98") return 97.90721597 ; + if (lbl == "TC99") return 98.90625475 ; + if (lbl == "TC100") return 99.90765778 ; + if (lbl == "TC101") return 100.9073147 ; + if (lbl == "TC102") return 101.909215 ; + if (lbl == "TC103") return 102.9091814 ; + if (lbl == "TC104") return 103.9114475 ; + if (lbl == "TC105") return 104.9116606 ; + if (lbl == "TC106") return 105.9143579 ; + if (lbl == "TC107") return 106.9150796 ; + if (lbl == "TC108") return 107.9184612 ; + if (lbl == "TC109") return 108.9199827 ; + if (lbl == "TC110") return 109.9238205 ; + if (lbl == "TC111") return 110.9256928 ; + if (lbl == "TC112") return 111.9291465 ; + if (lbl == "TC113") return 112.93159 ; + if (lbl == "TC114") return 113.93588 ; + if (lbl == "TC115") return 114.93869 ; + if (lbl == "TC116") return 115.94337 ; + if (lbl == "TC117") return 116.94648 ; + if (lbl == "TC118") return 117.95148 ; + if (lbl == "RU") return 101.9043493 ; + if (lbl == "RU87") return 86.94918 ; + if (lbl == "RU88") return 87.94026 ; + if (lbl == "RU89") return 88.93611 ; + if (lbl == "RU90") return 89.92989 ; + if (lbl == "RU91") return 90.926292 ; + if (lbl == "RU92") return 91.92012 ; + if (lbl == "RU93") return 92.91705203 ; + if (lbl == "RU94") return 93.91135971 ; + if (lbl == "RU95") return 94.91041293 ; + if (lbl == "RU96") return 95.90759784 ; + if (lbl == "RU97") return 96.9075547 ; + if (lbl == "RU98") return 97.90528713 ; + if (lbl == "RU99") return 98.9059393 ; + if (lbl == "RU100") return 99.90421948 ; + if (lbl == "RU101") return 100.9055821 ; + if (lbl == "RU102") return 101.9043493 ; + if (lbl == "RU103") return 102.9063238 ; + if (lbl == "RU104") return 103.9054327 ; + if (lbl == "RU105") return 104.9077529 ; + if (lbl == "RU106") return 105.9073294 ; + if (lbl == "RU107") return 106.9099051 ; + if (lbl == "RU108") return 107.9101735 ; + if (lbl == "RU109") return 108.9132032 ; + if (lbl == "RU110") return 109.914136 ; + if (lbl == "RU111") return 110.917696 ; + if (lbl == "RU112") return 111.918965 ; + if (lbl == "RU113") return 112.9224872 ; + if (lbl == "RU114") return 113.924281 ; + if (lbl == "RU115") return 114.9286862 ; + if (lbl == "RU116") return 115.93081 ; + if (lbl == "RU117") return 116.93558 ; + if (lbl == "RU118") return 117.93782 ; + if (lbl == "RU119") return 118.94284 ; + if (lbl == "RU120") return 119.94531 ; + if (lbl == "RH") return 102.9055043 ; + if (lbl == "RH89") return 88.948837 ; + if (lbl == "RH90") return 89.94287 ; + if (lbl == "RH91") return 90.93655 ; + if (lbl == "RH92") return 91.93198 ; + if (lbl == "RH93") return 92.92574 ; + if (lbl == "RH94") return 93.921698 ; + if (lbl == "RH95") return 94.91589874 ; + if (lbl == "RH96") return 95.91446063 ; + if (lbl == "RH97") return 96.9113368 ; + if (lbl == "RH98") return 97.91070816 ; + if (lbl == "RH99") return 98.9081321 ; + if (lbl == "RH100") return 99.90812155 ; + if (lbl == "RH101") return 100.9061636 ; + if (lbl == "RH102") return 101.9068432 ; + if (lbl == "RH103") return 102.9055043 ; + if (lbl == "RH104") return 103.9066555 ; + if (lbl == "RH105") return 104.9056938 ; + if (lbl == "RH106") return 105.9072871 ; + if (lbl == "RH107") return 106.9067484 ; + if (lbl == "RH108") return 107.908728 ; + if (lbl == "RH109") return 108.9087373 ; + if (lbl == "RH110") return 109.9111364 ; + if (lbl == "RH111") return 110.9115859 ; + if (lbl == "RH112") return 111.9143942 ; + if (lbl == "RH113") return 112.9155306 ; + if (lbl == "RH114") return 113.918806 ; + if (lbl == "RH115") return 114.920334 ; + if (lbl == "RH116") return 115.924062 ; + if (lbl == "RH117") return 116.92598 ; + if (lbl == "RH118") return 117.93007 ; + if (lbl == "RH119") return 118.93211 ; + if (lbl == "RH120") return 119.93641 ; + if (lbl == "RH121") return 120.93872 ; + if (lbl == "RH122") return 121.94321 ; + if (lbl == "PD") return 105.9034857 ; + if (lbl == "PD91") return 90.94911 ; + if (lbl == "PD92") return 91.94042 ; + if (lbl == "PD93") return 92.93591 ; + if (lbl == "PD94") return 93.92877 ; + if (lbl == "PD95") return 94.92469 ; + if (lbl == "PD96") return 95.91816436 ; + if (lbl == "PD97") return 96.91647907 ; + if (lbl == "PD98") return 97.9127209 ; + if (lbl == "PD99") return 98.91176783 ; + if (lbl == "PD100") return 99.90850589 ; + if (lbl == "PD101") return 100.9082892 ; + if (lbl == "PD102") return 101.9056085 ; + if (lbl == "PD103") return 102.9060873 ; + if (lbl == "PD104") return 103.9040358 ; + if (lbl == "PD105") return 104.9050849 ; + if (lbl == "PD106") return 105.9034857 ; + if (lbl == "PD107") return 106.9051335 ; + if (lbl == "PD108") return 107.9038917 ; + if (lbl == "PD109") return 108.9059505 ; + if (lbl == "PD110") return 109.9051533 ; + if (lbl == "PD111") return 110.9076707 ; + if (lbl == "PD112") return 111.9073141 ; + if (lbl == "PD113") return 112.9101529 ; + if (lbl == "PD114") return 113.9103626 ; + if (lbl == "PD115") return 114.9136838 ; + if (lbl == "PD116") return 115.9141587 ; + if (lbl == "PD117") return 116.9178413 ; + if (lbl == "PD118") return 117.9189843 ; + if (lbl == "PD119") return 118.92311 ; + if (lbl == "PD120") return 119.9246919 ; + if (lbl == "PD121") return 120.92887 ; + if (lbl == "PD122") return 121.93055 ; + if (lbl == "PD123") return 122.93493 ; + if (lbl == "PD124") return 123.93688 ; + if (lbl == "AG") return 106.9050968 ; + if (lbl == "AG93") return 92.94978 ; + if (lbl == "AG94") return 93.94278 ; + if (lbl == "AG95") return 94.93548 ; + if (lbl == "AG96") return 95.93068 ; + if (lbl == "AG97") return 96.92397241 ; + if (lbl == "AG98") return 97.9215662 ; + if (lbl == "AG99") return 98.91759718 ; + if (lbl == "AG100") return 99.91610426 ; + if (lbl == "AG101") return 100.9128022 ; + if (lbl == "AG102") return 101.911685 ; + if (lbl == "AG103") return 102.9089727 ; + if (lbl == "AG104") return 103.9086292 ; + if (lbl == "AG105") return 104.9065287 ; + if (lbl == "AG106") return 105.9066689 ; + if (lbl == "AG107") return 106.9050968 ; + if (lbl == "AG108") return 107.9059556 ; + if (lbl == "AG109") return 108.9047523 ; + if (lbl == "AG110") return 109.9061072 ; + if (lbl == "AG111") return 110.9052912 ; + if (lbl == "AG112") return 111.9070048 ; + if (lbl == "AG113") return 112.9065666 ; + if (lbl == "AG114") return 113.9088037 ; + if (lbl == "AG115") return 114.9087627 ; + if (lbl == "AG116") return 115.9113599 ; + if (lbl == "AG117") return 116.9116846 ; + if (lbl == "AG118") return 117.9145828 ; + if (lbl == "AG119") return 118.9156651 ; + if (lbl == "AG120") return 119.9187874 ; + if (lbl == "AG121") return 120.919848 ; + if (lbl == "AG122") return 121.92353 ; + if (lbl == "AG123") return 122.9249 ; + if (lbl == "AG124") return 123.92864 ; + if (lbl == "AG125") return 124.93043 ; + if (lbl == "AG126") return 125.9345 ; + if (lbl == "AG127") return 126.93677 ; + if (lbl == "AG128") return 127.94117 ; + if (lbl == "AG129") return 128.94369 ; + if (lbl == "AG130") return 129.950448 ; + if (lbl == "CD") return 113.9033585 ; + if (lbl == "CD95") return 94.94987 ; + if (lbl == "CD96") return 95.93977 ; + if (lbl == "CD97") return 96.93494 ; + if (lbl == "CD98") return 97.92739555 ; + if (lbl == "CD99") return 98.92501 ; + if (lbl == "CD100") return 99.92028953 ; + if (lbl == "CD101") return 100.9186815 ; + if (lbl == "CD102") return 101.9144623 ; + if (lbl == "CD103") return 102.9134192 ; + if (lbl == "CD104") return 103.9098495 ; + if (lbl == "CD105") return 104.9094679 ; + if (lbl == "CD106") return 105.9064594 ; + if (lbl == "CD107") return 106.9066179 ; + if (lbl == "CD108") return 107.9041837 ; + if (lbl == "CD109") return 108.9049823 ; + if (lbl == "CD110") return 109.9030021 ; + if (lbl == "CD111") return 110.9041781 ; + if (lbl == "CD112") return 111.9027578 ; + if (lbl == "CD113") return 112.9044017 ; + if (lbl == "CD114") return 113.9033585 ; + if (lbl == "CD115") return 114.905431 ; + if (lbl == "CD116") return 115.9047558 ; + if (lbl == "CD117") return 116.9072186 ; + if (lbl == "CD118") return 117.9069145 ; + if (lbl == "CD119") return 118.9099216 ; + if (lbl == "CD120") return 119.9098501 ; + if (lbl == "CD121") return 120.9129774 ; + if (lbl == "CD122") return 121.9133324 ; + if (lbl == "CD123") return 122.917003 ; + if (lbl == "CD124") return 123.9176476 ; + if (lbl == "CD125") return 124.9212464 ; + if (lbl == "CD126") return 125.9223533 ; + if (lbl == "CD127") return 126.9264439 ; + if (lbl == "CD128") return 127.9277623 ; + if (lbl == "CD129") return 128.93215 ; + if (lbl == "CD130") return 129.9339019 ; + if (lbl == "CD131") return 130.94067 ; + if (lbl == "CD132") return 131.94555 ; + if (lbl == "IN") return 114.9038785 ; + if (lbl == "IN97") return 96.94954 ; + if (lbl == "IN98") return 97.94214 ; + if (lbl == "IN99") return 98.93422 ; + if (lbl == "IN100") return 99.93111085 ; + if (lbl == "IN101") return 100.92634 ; + if (lbl == "IN102") return 101.9240902 ; + if (lbl == "IN103") return 102.9199142 ; + if (lbl == "IN104") return 103.9182962 ; + if (lbl == "IN105") return 104.9146735 ; + if (lbl == "IN106") return 105.9134654 ; + if (lbl == "IN107") return 106.9102951 ; + if (lbl == "IN108") return 107.9096982 ; + if (lbl == "IN109") return 108.9071505 ; + if (lbl == "IN110") return 109.9071653 ; + if (lbl == "IN111") return 110.9051033 ; + if (lbl == "IN112") return 111.9055323 ; + if (lbl == "IN113") return 112.9040578 ; + if (lbl == "IN114") return 113.9049139 ; + if (lbl == "IN115") return 114.9038785 ; + if (lbl == "IN116") return 115.9052597 ; + if (lbl == "IN117") return 116.9045136 ; + if (lbl == "IN118") return 117.9063544 ; + if (lbl == "IN119") return 118.9058454 ; + if (lbl == "IN120") return 119.9079596 ; + if (lbl == "IN121") return 120.9078458 ; + if (lbl == "IN122") return 121.910276 ; + if (lbl == "IN123") return 122.9104383 ; + if (lbl == "IN124") return 123.9131752 ; + if (lbl == "IN125") return 124.9136006 ; + if (lbl == "IN126") return 125.9164639 ; + if (lbl == "IN127") return 126.9173531 ; + if (lbl == "IN128") return 127.9201723 ; + if (lbl == "IN129") return 128.921697 ; + if (lbl == "IN130") return 129.92497 ; + if (lbl == "IN131") return 130.9268518 ; + if (lbl == "IN132") return 131.9329903 ; + if (lbl == "IN133") return 132.93781 ; + if (lbl == "IN134") return 133.94415 ; + if (lbl == "IN135") return 134.94933 ; + if (lbl == "SN") return 119.9021947 ; + if (lbl == "SN99") return 98.94933 ; + if (lbl == "SN100") return 99.93904434 ; + if (lbl == "SN101") return 100.93606 ; + if (lbl == "SN102") return 101.9302953 ; + if (lbl == "SN103") return 102.9281 ; + if (lbl == "SN104") return 103.9231432 ; + if (lbl == "SN105") return 104.9213494 ; + if (lbl == "SN106") return 105.9168806 ; + if (lbl == "SN107") return 106.9156443 ; + if (lbl == "SN108") return 107.9119254 ; + if (lbl == "SN109") return 108.9112832 ; + if (lbl == "SN110") return 109.9078428 ; + if (lbl == "SN111") return 110.9077345 ; + if (lbl == "SN112") return 111.9048182 ; + if (lbl == "SN113") return 112.9051706 ; + if (lbl == "SN114") return 113.9027789 ; + if (lbl == "SN115") return 114.9033424 ; + if (lbl == "SN116") return 115.9017405 ; + if (lbl == "SN117") return 116.9029517 ; + if (lbl == "SN118") return 117.9016032 ; + if (lbl == "SN119") return 118.9033076 ; + if (lbl == "SN120") return 119.9021947 ; + if (lbl == "SN121") return 120.9042355 ; + if (lbl == "SN122") return 121.903439 ; + if (lbl == "SN123") return 122.9057208 ; + if (lbl == "SN124") return 123.9052739 ; + if (lbl == "SN125") return 124.9077841 ; + if (lbl == "SN126") return 125.9076533 ; + if (lbl == "SN127") return 126.91036 ; + if (lbl == "SN128") return 127.9105366 ; + if (lbl == "SN129") return 128.913479 ; + if (lbl == "SN130") return 129.9139673 ; + if (lbl == "SN131") return 130.9169998 ; + if (lbl == "SN132") return 131.9178157 ; + if (lbl == "SN133") return 132.9238292 ; + if (lbl == "SN134") return 133.9282918 ; + if (lbl == "SN135") return 134.93473 ; + if (lbl == "SN136") return 135.93934 ; + if (lbl == "SN137") return 136.94599 ; + if (lbl == "SB") return 120.9038157 ; + if (lbl == "SB103") return 102.93969 ; + if (lbl == "SB104") return 103.936472 ; + if (lbl == "SB105") return 104.9314863 ; + if (lbl == "SB106") return 105.928791 ; + if (lbl == "SB107") return 106.92415 ; + if (lbl == "SB108") return 107.92216 ; + if (lbl == "SB109") return 108.9181324 ; + if (lbl == "SB110") return 109.916753 ; + if (lbl == "SB111") return 110.913163 ; + if (lbl == "SB112") return 111.912398 ; + if (lbl == "SB113") return 112.9093717 ; + if (lbl == "SB114") return 113.909269 ; + if (lbl == "SB115") return 114.906598 ; + if (lbl == "SB116") return 115.9067936 ; + if (lbl == "SB117") return 116.9048359 ; + if (lbl == "SB118") return 117.9055287 ; + if (lbl == "SB119") return 118.903942 ; + if (lbl == "SB120") return 119.9050724 ; + if (lbl == "SB121") return 120.9038157 ; + if (lbl == "SB122") return 121.9051737 ; + if (lbl == "SB123") return 122.904214 ; + if (lbl == "SB124") return 123.9059357 ; + if (lbl == "SB125") return 124.9052538 ; + if (lbl == "SB126") return 125.9072475 ; + if (lbl == "SB127") return 126.9069236 ; + if (lbl == "SB128") return 127.909169 ; + if (lbl == "SB129") return 128.9091484 ; + if (lbl == "SB130") return 129.9116563 ; + if (lbl == "SB131") return 130.9119823 ; + if (lbl == "SB132") return 131.9144669 ; + if (lbl == "SB133") return 132.9152516 ; + if (lbl == "SB134") return 133.9203797 ; + if (lbl == "SB135") return 134.9251658 ; + if (lbl == "SB136") return 135.93035 ; + if (lbl == "SB137") return 136.93531 ; + if (lbl == "SB138") return 137.94079 ; + if (lbl == "SB139") return 138.94598 ; + if (lbl == "TE") return 129.9062244 ; + if (lbl == "TE105") return 104.94364 ; + if (lbl == "TE106") return 5.937504237 ; + if (lbl == "TE107") return 106.935006 ; + if (lbl == "TE108") return 107.9294446 ; + if (lbl == "TE109") return 108.9274155 ; + if (lbl == "TE110") return 109.9224073 ; + if (lbl == "TE111") return 110.9211107 ; + if (lbl == "TE112") return 111.9170137 ; + if (lbl == "TE113") return 112.915891 ; + if (lbl == "TE114") return 113.912089 ; + if (lbl == "TE115") return 114.911902 ; + if (lbl == "TE116") return 115.90846 ; + if (lbl == "TE117") return 116.9086447 ; + if (lbl == "TE118") return 117.9058276 ; + if (lbl == "TE119") return 118.9064036 ; + if (lbl == "TE120") return 119.9040202 ; + if (lbl == "TE121") return 120.9049364 ; + if (lbl == "TE122") return 121.9030439 ; + if (lbl == "TE123") return 122.90427 ; + if (lbl == "TE124") return 123.9028179 ; + if (lbl == "TE125") return 124.9044307 ; + if (lbl == "TE126") return 125.9033117 ; + if (lbl == "TE127") return 126.9052263 ; + if (lbl == "TE128") return 127.9044631 ; + if (lbl == "TE129") return 128.9065982 ; + if (lbl == "TE130") return 129.9062244 ; + if (lbl == "TE131") return 130.9085239 ; + if (lbl == "TE132") return 131.9085532 ; + if (lbl == "TE133") return 132.9109553 ; + if (lbl == "TE134") return 133.9113687 ; + if (lbl == "TE135") return 134.9164486 ; + if (lbl == "TE136") return 135.9201012 ; + if (lbl == "TE137") return 136.925323 ; + if (lbl == "TE138") return 137.92922 ; + if (lbl == "TE139") return 138.93473 ; + if (lbl == "TE140") return 139.93885 ; + if (lbl == "TE141") return 140.94465 ; + if (lbl == "TE142") return 141.94908 ; + if (lbl == "I") return 126.9044727 ; + if (lbl == "I108") return 107.943475 ; + if (lbl == "I109") return 108.9381494 ; + if (lbl == "I110") return 109.935242 ; + if (lbl == "I111") return 110.930276 ; + if (lbl == "I112") return 111.92797 ; + if (lbl == "I113") return 112.9236406 ; + if (lbl == "I114") return 113.92185 ; + if (lbl == "I115") return 114.918048 ; + if (lbl == "I116") return 115.9168086 ; + if (lbl == "I117") return 116.91365 ; + if (lbl == "I118") return 117.913074 ; + if (lbl == "I119") return 118.910074 ; + if (lbl == "I120") return 119.9100482 ; + if (lbl == "I121") return 120.9073668 ; + if (lbl == "I122") return 121.9075893 ; + if (lbl == "I123") return 122.905589 ; + if (lbl == "I124") return 123.9062099 ; + if (lbl == "I125") return 124.9046302 ; + if (lbl == "I126") return 125.9056242 ; + if (lbl == "I127") return 126.9044727 ; + if (lbl == "I128") return 127.9058094 ; + if (lbl == "I129") return 128.9049877 ; + if (lbl == "I130") return 129.9066742 ; + if (lbl == "I131") return 130.9061246 ; + if (lbl == "I132") return 131.9079974 ; + if (lbl == "I133") return 132.9077969 ; + if (lbl == "I134") return 133.9097445 ; + if (lbl == "I135") return 134.9100481 ; + if (lbl == "I136") return 135.914654 ; + if (lbl == "I137") return 136.9178708 ; + if (lbl == "I138") return 137.9223496 ; + if (lbl == "I139") return 138.9260995 ; + if (lbl == "I140") return 139.931 ; + if (lbl == "I141") return 140.93503 ; + if (lbl == "I142") return 141.94018 ; + if (lbl == "I143") return 142.94456 ; + if (lbl == "I144") return 143.94999 ; + if (lbl == "XE") return 131.9041535 ; + if (lbl == "XE110") return 109.9442781 ; + if (lbl == "XE111") return 110.941602 ; + if (lbl == "XE112") return 111.9356231 ; + if (lbl == "XE113") return 112.9333412 ; + if (lbl == "XE114") return 113.9279803 ; + if (lbl == "XE115") return 114.9262939 ; + if (lbl == "XE116") return 115.9215811 ; + if (lbl == "XE117") return 116.9203587 ; + if (lbl == "XE118") return 117.9161787 ; + if (lbl == "XE119") return 118.9154107 ; + if (lbl == "XE120") return 119.9117842 ; + if (lbl == "XE121") return 120.9114618 ; + if (lbl == "XE122") return 121.9083676 ; + if (lbl == "XE123") return 122.9084819 ; + if (lbl == "XE124") return 123.905893 ; + if (lbl == "XE125") return 124.9063955 ; + if (lbl == "XE126") return 125.9042736 ; + if (lbl == "XE127") return 126.9051837 ; + if (lbl == "XE128") return 127.9035313 ; + if (lbl == "XE129") return 128.9047794 ; + if (lbl == "XE130") return 129.903508 ; + if (lbl == "XE131") return 130.9050824 ; + if (lbl == "XE132") return 131.9041535 ; + if (lbl == "XE133") return 132.9059107 ; + if (lbl == "XE134") return 133.9053945 ; + if (lbl == "XE135") return 134.9072275 ; + if (lbl == "XE136") return 135.9072188 ; + if (lbl == "XE137") return 136.9115621 ; + if (lbl == "XE138") return 137.9139545 ; + if (lbl == "XE139") return 138.9187929 ; + if (lbl == "XE140") return 139.9216409 ; + if (lbl == "XE141") return 140.926648 ; + if (lbl == "XE142") return 141.9297096 ; + if (lbl == "XE143") return 142.93511 ; + if (lbl == "XE144") return 143.93851 ; + if (lbl == "XE145") return 144.94407 ; + if (lbl == "XE146") return 145.94775 ; + if (lbl == "XE147") return 146.95356 ; + if (lbl == "CS") return 132.9054519 ; + if (lbl == "CS112") return 111.950301 ; + if (lbl == "CS113") return 112.9444933 ; + if (lbl == "CS114") return 113.94145 ; + if (lbl == "CS115") return 114.93591 ; + if (lbl == "CS116") return 115.933367 ; + if (lbl == "CS117") return 116.9286707 ; + if (lbl == "CS118") return 117.9265595 ; + if (lbl == "CS119") return 118.9223773 ; + if (lbl == "CS120") return 119.9206773 ; + if (lbl == "CS121") return 120.9172292 ; + if (lbl == "CS122") return 121.9161134 ; + if (lbl == "CS123") return 122.912996 ; + if (lbl == "CS124") return 123.9122578 ; + if (lbl == "CS125") return 124.9097283 ; + if (lbl == "CS126") return 125.909452 ; + if (lbl == "CS127") return 126.9074175 ; + if (lbl == "CS128") return 127.9077489 ; + if (lbl == "CS129") return 128.9060644 ; + if (lbl == "CS130") return 129.9067086 ; + if (lbl == "CS131") return 130.9054639 ; + if (lbl == "CS132") return 131.9064343 ; + if (lbl == "CS133") return 132.9054519 ; + if (lbl == "CS134") return 133.9067185 ; + if (lbl == "CS135") return 134.905977 ; + if (lbl == "CS136") return 135.9073116 ; + if (lbl == "CS137") return 136.9070895 ; + if (lbl == "CS138") return 137.9110167 ; + if (lbl == "CS139") return 138.913364 ; + if (lbl == "CS140") return 139.9172824 ; + if (lbl == "CS141") return 140.9200458 ; + if (lbl == "CS142") return 141.9242989 ; + if (lbl == "CS143") return 142.9273518 ; + if (lbl == "CS144") return 143.9320769 ; + if (lbl == "CS145") return 144.9355262 ; + if (lbl == "CS146") return 145.9402894 ; + if (lbl == "CS147") return 146.944155 ; + if (lbl == "CS148") return 147.9492182 ; + if (lbl == "CS149") return 148.95293 ; + if (lbl == "CS150") return 149.95817 ; + if (lbl == "CS151") return 150.96219 ; + if (lbl == "BA") return 137.9052472 ; + if (lbl == "BA114") return 113.9506754 ; + if (lbl == "BA115") return 114.94737 ; + if (lbl == "BA116") return 115.94138 ; + if (lbl == "BA117") return 116.938499 ; + if (lbl == "BA118") return 117.93304 ; + if (lbl == "BA119") return 118.9306597 ; + if (lbl == "BA120") return 119.926045 ; + if (lbl == "BA121") return 120.9240545 ; + if (lbl == "BA122") return 121.919904 ; + if (lbl == "BA123") return 122.918781 ; + if (lbl == "BA124") return 123.9150936 ; + if (lbl == "BA125") return 124.9144729 ; + if (lbl == "BA126") return 125.9112502 ; + if (lbl == "BA127") return 126.9110938 ; + if (lbl == "BA128") return 127.9083177 ; + if (lbl == "BA129") return 128.9086794 ; + if (lbl == "BA130") return 129.9063208 ; + if (lbl == "BA131") return 130.9069411 ; + if (lbl == "BA132") return 131.9050613 ; + if (lbl == "BA133") return 132.9060075 ; + if (lbl == "BA134") return 133.9045084 ; + if (lbl == "BA135") return 134.9056886 ; + if (lbl == "BA136") return 135.9045759 ; + if (lbl == "BA137") return 136.9058274 ; + if (lbl == "BA138") return 137.9052472 ; + if (lbl == "BA139") return 138.9088413 ; + if (lbl == "BA140") return 139.9106045 ; + if (lbl == "BA141") return 140.914411 ; + if (lbl == "BA142") return 141.9164534 ; + if (lbl == "BA143") return 142.9206267 ; + if (lbl == "BA144") return 143.9229529 ; + if (lbl == "BA145") return 144.927627 ; + if (lbl == "BA146") return 145.9302196 ; + if (lbl == "BA147") return 146.934945 ; + if (lbl == "BA148") return 147.93772 ; + if (lbl == "BA149") return 148.94258 ; + if (lbl == "BA150") return 149.94568 ; + if (lbl == "BA151") return 150.95081 ; + if (lbl == "BA152") return 151.95427 ; + if (lbl == "BA153") return 152.95961 ; + if (lbl == "LA") return 138.9063533 ; + if (lbl == "LA117") return 116.950068 ; + if (lbl == "LA118") return 117.94673 ; + if (lbl == "LA119") return 118.94099 ; + if (lbl == "LA120") return 119.93807 ; + if (lbl == "LA121") return 120.93301 ; + if (lbl == "LA122") return 121.93071 ; + if (lbl == "LA123") return 122.92624 ; + if (lbl == "LA124") return 123.9245743 ; + if (lbl == "LA125") return 124.920816 ; + if (lbl == "LA126") return 125.9195127 ; + if (lbl == "LA127") return 126.9163754 ; + if (lbl == "LA128") return 127.9155852 ; + if (lbl == "LA129") return 128.9126928 ; + if (lbl == "LA130") return 129.9123687 ; + if (lbl == "LA131") return 130.91007 ; + if (lbl == "LA132") return 131.9101011 ; + if (lbl == "LA133") return 132.908218 ; + if (lbl == "LA134") return 133.908514 ; + if (lbl == "LA135") return 134.9069768 ; + if (lbl == "LA136") return 135.9076355 ; + if (lbl == "LA137") return 136.9064936 ; + if (lbl == "LA138") return 137.9071119 ; + if (lbl == "LA139") return 138.9063533 ; + if (lbl == "LA140") return 139.9094776 ; + if (lbl == "LA141") return 140.9109622 ; + if (lbl == "LA142") return 141.9140791 ; + if (lbl == "LA143") return 142.9160627 ; + if (lbl == "LA144") return 143.9195996 ; + if (lbl == "LA145") return 144.9216454 ; + if (lbl == "LA146") return 145.9257935 ; + if (lbl == "LA147") return 146.9282353 ; + if (lbl == "LA148") return 147.9322289 ; + if (lbl == "LA149") return 148.934734 ; + if (lbl == "LA150") return 149.93877 ; + if (lbl == "LA151") return 150.94172 ; + if (lbl == "LA152") return 151.94625 ; + if (lbl == "LA153") return 152.94962 ; + if (lbl == "LA154") return 153.9545 ; + if (lbl == "LA155") return 154.95835 ; + if (lbl == "CE") return 139.9054387 ; + if (lbl == "CE119") return 118.95276 ; + if (lbl == "CE120") return 119.94664 ; + if (lbl == "CE121") return 120.94342 ; + if (lbl == "CE122") return 121.93791 ; + if (lbl == "CE123") return 122.9354 ; + if (lbl == "CE124") return 123.93041 ; + if (lbl == "CE125") return 124.92844 ; + if (lbl == "CE126") return 125.923971 ; + if (lbl == "CE127") return 126.922731 ; + if (lbl == "CE128") return 127.918911 ; + if (lbl == "CE129") return 128.918102 ; + if (lbl == "CE130") return 129.914736 ; + if (lbl == "CE131") return 130.914422 ; + if (lbl == "CE132") return 131.9114605 ; + if (lbl == "CE133") return 132.911515 ; + if (lbl == "CE134") return 133.9089248 ; + if (lbl == "CE135") return 134.9091514 ; + if (lbl == "CE136") return 135.9071724 ; + if (lbl == "CE137") return 136.9078056 ; + if (lbl == "CE138") return 137.9059913 ; + if (lbl == "CE139") return 138.9066527 ; + if (lbl == "CE140") return 139.9054387 ; + if (lbl == "CE141") return 140.9082763 ; + if (lbl == "CE142") return 141.9092442 ; + if (lbl == "CE143") return 142.9123859 ; + if (lbl == "CE144") return 143.9136473 ; + if (lbl == "CE145") return 144.9172331 ; + if (lbl == "CE146") return 145.918759 ; + if (lbl == "CE147") return 146.922674 ; + if (lbl == "CE148") return 147.9244324 ; + if (lbl == "CE149") return 148.9283999 ; + if (lbl == "CE150") return 149.9304089 ; + if (lbl == "CE151") return 150.9339762 ; + if (lbl == "CE152") return 151.93654 ; + if (lbl == "CE153") return 152.94058 ; + if (lbl == "CE154") return 153.94342 ; + if (lbl == "CE155") return 154.94804 ; + if (lbl == "CE156") return 155.95126 ; + if (lbl == "CE157") return 156.95634 ; + if (lbl == "PR") return 140.9076528 ; + if (lbl == "PR121") return 120.955364 ; + if (lbl == "PR122") return 121.95181 ; + if (lbl == "PR123") return 122.94596 ; + if (lbl == "PR124") return 123.94296 ; + if (lbl == "PR125") return 124.93783 ; + if (lbl == "PR126") return 125.93531 ; + if (lbl == "PR127") return 126.93083 ; + if (lbl == "PR128") return 127.928791 ; + if (lbl == "PR129") return 128.925095 ; + if (lbl == "PR130") return 129.92359 ; + if (lbl == "PR131") return 130.920259 ; + if (lbl == "PR132") return 131.919255 ; + if (lbl == "PR133") return 132.9163305 ; + if (lbl == "PR134") return 133.9157117 ; + if (lbl == "PR135") return 134.9131117 ; + if (lbl == "PR136") return 135.9126916 ; + if (lbl == "PR137") return 136.9107055 ; + if (lbl == "PR138") return 137.9107546 ; + if (lbl == "PR139") return 138.9089384 ; + if (lbl == "PR140") return 139.9090759 ; + if (lbl == "PR141") return 140.9076528 ; + if (lbl == "PR142") return 141.9100448 ; + if (lbl == "PR143") return 142.9108169 ; + if (lbl == "PR144") return 143.9133052 ; + if (lbl == "PR145") return 144.9145117 ; + if (lbl == "PR146") return 145.9176443 ; + if (lbl == "PR147") return 146.918996 ; + if (lbl == "PR148") return 147.922135 ; + if (lbl == "PR149") return 148.9237177 ; + if (lbl == "PR150") return 149.926673 ; + if (lbl == "PR151") return 150.9283186 ; + if (lbl == "PR152") return 151.9314992 ; + if (lbl == "PR153") return 152.9338389 ; + if (lbl == "PR154") return 153.9375182 ; + if (lbl == "PR155") return 154.94012 ; + if (lbl == "PR156") return 155.94427 ; + if (lbl == "PR157") return 156.94743 ; + if (lbl == "PR158") return 157.95198 ; + if (lbl == "PR159") return 158.9555 ; + if (lbl == "ND") return 141.9077233 ; + if (lbl == "ND124") return 123.95223 ; + if (lbl == "ND125") return 124.94888 ; + if (lbl == "ND126") return 125.94322 ; + if (lbl == "ND127") return 126.9405 ; + if (lbl == "ND128") return 127.93539 ; + if (lbl == "ND129") return 128.933188 ; + if (lbl == "ND130") return 129.928506 ; + if (lbl == "ND131") return 130.927247 ; + if (lbl == "ND132") return 131.9233212 ; + if (lbl == "ND133") return 132.922348 ; + if (lbl == "ND134") return 133.9187902 ; + if (lbl == "ND135") return 134.9181812 ; + if (lbl == "ND136") return 135.914976 ; + if (lbl == "ND137") return 136.9145671 ; + if (lbl == "ND138") return 137.91195 ; + if (lbl == "ND139") return 138.9119783 ; + if (lbl == "ND140") return 139.909552 ; + if (lbl == "ND141") return 140.9096099 ; + if (lbl == "ND142") return 141.9077233 ; + if (lbl == "ND143") return 142.9098143 ; + if (lbl == "ND144") return 143.9100873 ; + if (lbl == "ND145") return 144.9125736 ; + if (lbl == "ND146") return 145.9131169 ; + if (lbl == "ND147") return 146.9161004 ; + if (lbl == "ND148") return 147.9168933 ; + if (lbl == "ND149") return 148.9201488 ; + if (lbl == "ND150") return 149.9208909 ; + if (lbl == "ND151") return 150.9238289 ; + if (lbl == "ND152") return 151.9246822 ; + if (lbl == "ND153") return 152.9276982 ; + if (lbl == "ND154") return 153.9294773 ; + if (lbl == "ND155") return 154.932932 ; + if (lbl == "ND156") return 155.9350181 ; + if (lbl == "ND157") return 156.93903 ; + if (lbl == "ND158") return 157.9416 ; + if (lbl == "ND159") return 158.94609 ; + if (lbl == "ND160") return 159.94909 ; + if (lbl == "ND161") return 160.95388 ; + if (lbl == "PM") return 144.912749 ; + if (lbl == "PM126") return 125.95752 ; + if (lbl == "PM127") return 126.95163 ; + if (lbl == "PM128") return 127.94842 ; + if (lbl == "PM129") return 128.94316 ; + if (lbl == "PM130") return 129.94045 ; + if (lbl == "PM131") return 130.93587 ; + if (lbl == "PM132") return 131.93375 ; + if (lbl == "PM133") return 132.929782 ; + if (lbl == "PM134") return 133.928353 ; + if (lbl == "PM135") return 134.924876 ; + if (lbl == "PM136") return 135.9235658 ; + if (lbl == "PM137") return 136.9204795 ; + if (lbl == "PM138") return 137.9195483 ; + if (lbl == "PM139") return 138.9168041 ; + if (lbl == "PM140") return 139.9160418 ; + if (lbl == "PM141") return 140.9135551 ; + if (lbl == "PM142") return 141.9128745 ; + if (lbl == "PM143") return 142.9109326 ; + if (lbl == "PM144") return 143.9125908 ; + if (lbl == "PM145") return 144.912749 ; + if (lbl == "PM146") return 145.9146963 ; + if (lbl == "PM147") return 146.9151385 ; + if (lbl == "PM148") return 147.9174746 ; + if (lbl == "PM149") return 148.9183342 ; + if (lbl == "PM150") return 149.9209836 ; + if (lbl == "PM151") return 150.921207 ; + if (lbl == "PM152") return 151.9234968 ; + if (lbl == "PM153") return 152.9241169 ; + if (lbl == "PM154") return 153.9264639 ; + if (lbl == "PM155") return 154.9281013 ; + if (lbl == "PM156") return 155.9310567 ; + if (lbl == "PM157") return 156.9330394 ; + if (lbl == "PM158") return 157.9365614 ; + if (lbl == "PM159") return 158.93897 ; + if (lbl == "PM160") return 159.94299 ; + if (lbl == "PM161") return 160.94586 ; + if (lbl == "PM162") return 161.95029 ; + if (lbl == "PM163") return 162.95368 ; + if (lbl == "SM") return 151.9197324 ; + if (lbl == "SM128") return 127.95808 ; + if (lbl == "SM129") return 128.95464 ; + if (lbl == "SM130") return 129.94892 ; + if (lbl == "SM131") return 130.94611 ; + if (lbl == "SM132") return 131.94069 ; + if (lbl == "SM133") return 132.93867 ; + if (lbl == "SM134") return 133.93397 ; + if (lbl == "SM135") return 134.93252 ; + if (lbl == "SM136") return 135.9282755 ; + if (lbl == "SM137") return 136.9269717 ; + if (lbl == "SM138") return 137.923244 ; + if (lbl == "SM139") return 138.9222966 ; + if (lbl == "SM140") return 139.9189947 ; + if (lbl == "SM141") return 140.9184765 ; + if (lbl == "SM142") return 141.9151976 ; + if (lbl == "SM143") return 142.9146283 ; + if (lbl == "SM144") return 143.9119995 ; + if (lbl == "SM145") return 144.9134104 ; + if (lbl == "SM146") return 145.9130409 ; + if (lbl == "SM147") return 146.9148979 ; + if (lbl == "SM148") return 147.9148227 ; + if (lbl == "SM149") return 148.9171847 ; + if (lbl == "SM150") return 149.9172755 ; + if (lbl == "SM151") return 150.9199324 ; + if (lbl == "SM152") return 151.9197324 ; + if (lbl == "SM153") return 152.9220974 ; + if (lbl == "SM154") return 153.9222093 ; + if (lbl == "SM155") return 154.9246402 ; + if (lbl == "SM156") return 155.9255279 ; + if (lbl == "SM157") return 156.9283587 ; + if (lbl == "SM158") return 157.9299913 ; + if (lbl == "SM159") return 158.9332113 ; + if (lbl == "SM160") return 159.93514 ; + if (lbl == "SM161") return 160.93883 ; + if (lbl == "SM162") return 161.94122 ; + if (lbl == "SM163") return 162.94536 ; + if (lbl == "SM164") return 163.94828 ; + if (lbl == "SM165") return 164.95298 ; + if (lbl == "EU") return 152.9212303 ; + if (lbl == "EU130") return 129.963569 ; + if (lbl == "EU131") return 130.957753 ; + if (lbl == "EU132") return 131.95437 ; + if (lbl == "EU133") return 132.94924 ; + if (lbl == "EU134") return 133.94651 ; + if (lbl == "EU135") return 134.94182 ; + if (lbl == "EU136") return 135.9396 ; + if (lbl == "EU137") return 136.93557 ; + if (lbl == "EU138") return 137.933709 ; + if (lbl == "EU139") return 138.9297923 ; + if (lbl == "EU140") return 139.9280876 ; + if (lbl == "EU141") return 140.9249307 ; + if (lbl == "EU142") return 141.9234349 ; + if (lbl == "EU143") return 142.9202975 ; + if (lbl == "EU144") return 143.9188168 ; + if (lbl == "EU145") return 144.9162652 ; + if (lbl == "EU146") return 145.9172058 ; + if (lbl == "EU147") return 146.9167461 ; + if (lbl == "EU148") return 147.9180859 ; + if (lbl == "EU149") return 148.9179312 ; + if (lbl == "EU150") return 149.9197018 ; + if (lbl == "EU151") return 150.9198502 ; + if (lbl == "EU152") return 151.9217445 ; + if (lbl == "EU153") return 152.9212303 ; + if (lbl == "EU154") return 153.9229792 ; + if (lbl == "EU155") return 154.9228933 ; + if (lbl == "EU156") return 155.9247522 ; + if (lbl == "EU157") return 156.9254236 ; + if (lbl == "EU158") return 157.9278453 ; + if (lbl == "EU159") return 158.9290889 ; + if (lbl == "EU160") return 159.931971 ; + if (lbl == "EU161") return 160.93368 ; + if (lbl == "EU162") return 161.93704 ; + if (lbl == "EU163") return 162.93921 ; + if (lbl == "EU164") return 163.94299 ; + if (lbl == "EU165") return 164.94572 ; + if (lbl == "EU166") return 165.94997 ; + if (lbl == "EU167") return 166.95321 ; + if (lbl == "GD") return 157.9241039 ; + if (lbl == "GD134") return 133.95537 ; + if (lbl == "GD135") return 134.95257 ; + if (lbl == "GD136") return 135.94734 ; + if (lbl == "GD137") return 136.94502 ; + if (lbl == "GD138") return 137.94012 ; + if (lbl == "GD139") return 138.93824 ; + if (lbl == "GD140") return 139.933674 ; + if (lbl == "GD141") return 140.932126 ; + if (lbl == "GD142") return 141.928116 ; + if (lbl == "GD143") return 142.9267495 ; + if (lbl == "GD144") return 143.922963 ; + if (lbl == "GD145") return 144.9217093 ; + if (lbl == "GD146") return 145.9183106 ; + if (lbl == "GD147") return 146.9190944 ; + if (lbl == "GD148") return 147.9181145 ; + if (lbl == "GD149") return 148.9193409 ; + if (lbl == "GD150") return 149.9186589 ; + if (lbl == "GD151") return 150.9203485 ; + if (lbl == "GD152") return 151.919791 ; + if (lbl == "GD153") return 152.9217495 ; + if (lbl == "GD154") return 153.9208656 ; + if (lbl == "GD155") return 154.922622 ; + if (lbl == "GD156") return 155.9221227 ; + if (lbl == "GD157") return 156.9239601 ; + if (lbl == "GD158") return 157.9241039 ; + if (lbl == "GD159") return 158.9263887 ; + if (lbl == "GD160") return 159.9270541 ; + if (lbl == "GD161") return 160.9296692 ; + if (lbl == "GD162") return 161.9309848 ; + if (lbl == "GD163") return 162.93399 ; + if (lbl == "GD164") return 163.93586 ; + if (lbl == "GD165") return 164.93938 ; + if (lbl == "GD166") return 165.9416 ; + if (lbl == "GD167") return 166.94557 ; + if (lbl == "GD168") return 167.94836 ; + if (lbl == "GD169") return 168.95287 ; + if (lbl == "TB") return 158.9253468 ; + if (lbl == "TB136") return 135.96138 ; + if (lbl == "TB137") return 136.95598 ; + if (lbl == "TB138") return 137.95316 ; + if (lbl == "TB139") return 138.94829 ; + if (lbl == "TB140") return 139.945805 ; + if (lbl == "TB141") return 140.941448 ; + if (lbl == "TB142") return 141.938744 ; + if (lbl == "TB143") return 142.935121 ; + if (lbl == "TB144") return 143.933045 ; + if (lbl == "TB145") return 144.929274 ; + if (lbl == "TB146") return 145.9272466 ; + if (lbl == "TB147") return 146.9240446 ; + if (lbl == "TB148") return 147.9242717 ; + if (lbl == "TB149") return 148.9232459 ; + if (lbl == "TB150") return 149.9236597 ; + if (lbl == "TB151") return 150.9231025 ; + if (lbl == "TB152") return 151.9240744 ; + if (lbl == "TB153") return 152.9234346 ; + if (lbl == "TB154") return 153.924678 ; + if (lbl == "TB155") return 154.9235052 ; + if (lbl == "TB156") return 155.9247472 ; + if (lbl == "TB157") return 156.9240246 ; + if (lbl == "TB158") return 157.9254131 ; + if (lbl == "TB159") return 158.9253468 ; + if (lbl == "TB160") return 159.9271676 ; + if (lbl == "TB161") return 160.9275699 ; + if (lbl == "TB162") return 161.9294882 ; + if (lbl == "TB163") return 162.9306475 ; + if (lbl == "TB164") return 163.9333508 ; + if (lbl == "TB165") return 164.93488 ; + if (lbl == "TB166") return 165.937992 ; + if (lbl == "TB167") return 166.94005 ; + if (lbl == "TB168") return 167.94364 ; + if (lbl == "TB169") return 168.94622 ; + if (lbl == "TB170") return 169.95025 ; + if (lbl == "TB171") return 170.9533 ; + if (lbl == "DY") return 163.9291748 ; + if (lbl == "DY138") return 137.96249 ; + if (lbl == "DY139") return 138.95954 ; + if (lbl == "DY140") return 139.95401 ; + if (lbl == "DY141") return 140.95135 ; + if (lbl == "DY142") return 141.946366 ; + if (lbl == "DY143") return 142.94383 ; + if (lbl == "DY144") return 143.939254 ; + if (lbl == "DY145") return 144.937425 ; + if (lbl == "DY146") return 145.9328454 ; + if (lbl == "DY147") return 146.9310915 ; + if (lbl == "DY148") return 147.9271498 ; + if (lbl == "DY149") return 148.9273048 ; + if (lbl == "DY150") return 149.9255852 ; + if (lbl == "DY151") return 150.9261846 ; + if (lbl == "DY152") return 151.9247183 ; + if (lbl == "DY153") return 152.9257647 ; + if (lbl == "DY154") return 153.9244245 ; + if (lbl == "DY155") return 154.9257538 ; + if (lbl == "DY156") return 155.9242831 ; + if (lbl == "DY157") return 156.9254661 ; + if (lbl == "DY158") return 157.9244095 ; + if (lbl == "DY159") return 158.9257392 ; + if (lbl == "DY160") return 159.9251975 ; + if (lbl == "DY161") return 160.9269334 ; + if (lbl == "DY162") return 161.9267984 ; + if (lbl == "DY163") return 162.9287312 ; + if (lbl == "DY164") return 163.9291748 ; + if (lbl == "DY165") return 164.9317033 ; + if (lbl == "DY166") return 165.9328067 ; + if (lbl == "DY167") return 166.9356555 ; + if (lbl == "DY168") return 167.9371288 ; + if (lbl == "DY169") return 168.9403076 ; + if (lbl == "DY170") return 169.94239 ; + if (lbl == "DY171") return 170.9462 ; + if (lbl == "DY172") return 171.94876 ; + if (lbl == "DY173") return 172.953 ; + if (lbl == "HO") return 164.9303221 ; + if (lbl == "HO140") return 139.968539 ; + if (lbl == "HO141") return 140.963098 ; + if (lbl == "HO142") return 141.95977 ; + if (lbl == "HO143") return 142.95461 ; + if (lbl == "HO144") return 143.95148 ; + if (lbl == "HO145") return 144.9472 ; + if (lbl == "HO146") return 145.94464 ; + if (lbl == "HO147") return 146.940056 ; + if (lbl == "HO148") return 147.937718 ; + if (lbl == "HO149") return 148.9337748 ; + if (lbl == "HO150") return 149.9334962 ; + if (lbl == "HO151") return 150.9316881 ; + if (lbl == "HO152") return 151.9317137 ; + if (lbl == "HO153") return 152.9301988 ; + if (lbl == "HO154") return 153.9306016 ; + if (lbl == "HO155") return 154.9291035 ; + if (lbl == "HO156") return 155.929839 ; + if (lbl == "HO157") return 156.9282562 ; + if (lbl == "HO158") return 157.928941 ; + if (lbl == "HO159") return 158.927712 ; + if (lbl == "HO160") return 159.9287295 ; + if (lbl == "HO161") return 160.9278548 ; + if (lbl == "HO162") return 161.9290955 ; + if (lbl == "HO163") return 162.9287339 ; + if (lbl == "HO164") return 163.9302335 ; + if (lbl == "HO165") return 164.9303221 ; + if (lbl == "HO166") return 165.9322842 ; + if (lbl == "HO167") return 166.9331326 ; + if (lbl == "HO168") return 167.9355157 ; + if (lbl == "HO169") return 168.9368723 ; + if (lbl == "HO170") return 169.9396189 ; + if (lbl == "HO171") return 170.9414652 ; + if (lbl == "HO172") return 171.94482 ; + if (lbl == "HO173") return 172.94729 ; + if (lbl == "HO174") return 173.95115 ; + if (lbl == "HO175") return 174.95405 ; + if (lbl == "ER") return 165.9302931 ; + if (lbl == "ER143") return 142.96634 ; + if (lbl == "ER144") return 143.96038 ; + if (lbl == "ER145") return 144.95739 ; + if (lbl == "ER146") return 145.952 ; + if (lbl == "ER147") return 146.94949 ; + if (lbl == "ER148") return 147.94455 ; + if (lbl == "ER149") return 148.942306 ; + if (lbl == "ER150") return 149.9379138 ; + if (lbl == "ER151") return 150.9374489 ; + if (lbl == "ER152") return 151.9350504 ; + if (lbl == "ER153") return 152.9350635 ; + if (lbl == "ER154") return 153.9327831 ; + if (lbl == "ER155") return 154.9332089 ; + if (lbl == "ER156") return 155.9310647 ; + if (lbl == "ER157") return 156.931916 ; + if (lbl == "ER158") return 157.9298935 ; + if (lbl == "ER159") return 158.9306841 ; + if (lbl == "ER160") return 159.9290833 ; + if (lbl == "ER161") return 160.9299953 ; + if (lbl == "ER162") return 161.9287783 ; + if (lbl == "ER163") return 162.9300327 ; + if (lbl == "ER164") return 163.9292002 ; + if (lbl == "ER165") return 164.930726 ; + if (lbl == "ER166") return 165.9302931 ; + if (lbl == "ER167") return 166.9320482 ; + if (lbl == "ER168") return 167.9323702 ; + if (lbl == "ER169") return 168.9345904 ; + if (lbl == "ER170") return 169.9354643 ; + if (lbl == "ER171") return 170.9380298 ; + if (lbl == "ER172") return 171.9393561 ; + if (lbl == "ER173") return 172.9424 ; + if (lbl == "ER174") return 173.94423 ; + if (lbl == "ER175") return 174.94777 ; + if (lbl == "ER176") return 175.95008 ; + if (lbl == "ER177") return 176.95405 ; + if (lbl == "TM") return 168.9342133 ; + if (lbl == "TM145") return 144.970073 ; + if (lbl == "TM146") return 145.966425 ; + if (lbl == "TM147") return 146.960961 ; + if (lbl == "TM148") return 147.95784 ; + if (lbl == "TM149") return 148.95272 ; + if (lbl == "TM150") return 149.94996 ; + if (lbl == "TM151") return 150.9454835 ; + if (lbl == "TM152") return 151.944422 ; + if (lbl == "TM153") return 152.9420121 ; + if (lbl == "TM154") return 153.9415678 ; + if (lbl == "TM155") return 154.9391995 ; + if (lbl == "TM156") return 155.9389799 ; + if (lbl == "TM157") return 156.936973 ; + if (lbl == "TM158") return 157.9369795 ; + if (lbl == "TM159") return 158.934975 ; + if (lbl == "TM160") return 159.9352628 ; + if (lbl == "TM161") return 160.933549 ; + if (lbl == "TM162") return 161.9339947 ; + if (lbl == "TM163") return 162.9326511 ; + if (lbl == "TM164") return 163.93356 ; + if (lbl == "TM165") return 164.9324355 ; + if (lbl == "TM166") return 165.9335541 ; + if (lbl == "TM167") return 166.9328516 ; + if (lbl == "TM168") return 167.9341728 ; + if (lbl == "TM169") return 168.9342133 ; + if (lbl == "TM170") return 169.9358014 ; + if (lbl == "TM171") return 170.9364294 ; + if (lbl == "TM172") return 171.9384 ; + if (lbl == "TM173") return 172.9396036 ; + if (lbl == "TM174") return 173.9421686 ; + if (lbl == "TM175") return 174.9438369 ; + if (lbl == "TM176") return 175.9469947 ; + if (lbl == "TM177") return 176.94904 ; + if (lbl == "TM178") return 177.95264 ; + if (lbl == "TM179") return 178.95534 ; + if (lbl == "YB") return 173.9388621 ; + if (lbl == "YB148") return 147.96742 ; + if (lbl == "YB149") return 148.96404 ; + if (lbl == "YB150") return 149.95842 ; + if (lbl == "YB151") return 150.9554008 ; + if (lbl == "YB152") return 151.9502889 ; + if (lbl == "YB153") return 152.94948 ; + if (lbl == "YB154") return 153.9463939 ; + if (lbl == "YB155") return 154.9457823 ; + if (lbl == "YB156") return 155.9428182 ; + if (lbl == "YB157") return 156.9426278 ; + if (lbl == "YB158") return 157.9398656 ; + if (lbl == "YB159") return 158.9400501 ; + if (lbl == "YB160") return 159.9375523 ; + if (lbl == "YB161") return 160.9379017 ; + if (lbl == "YB162") return 161.9357682 ; + if (lbl == "YB163") return 162.9363343 ; + if (lbl == "YB164") return 163.9344894 ; + if (lbl == "YB165") return 164.935279 ; + if (lbl == "YB166") return 165.933882 ; + if (lbl == "YB167") return 166.9349496 ; + if (lbl == "YB168") return 167.9338969 ; + if (lbl == "YB169") return 168.9351898 ; + if (lbl == "YB170") return 169.9347618 ; + if (lbl == "YB171") return 170.9363258 ; + if (lbl == "YB172") return 171.9363815 ; + if (lbl == "YB173") return 172.9382108 ; + if (lbl == "YB174") return 173.9388621 ; + if (lbl == "YB175") return 174.9412765 ; + if (lbl == "YB176") return 175.9425717 ; + if (lbl == "YB177") return 176.9452608 ; + if (lbl == "YB178") return 177.9466467 ; + if (lbl == "YB179") return 178.95017 ; + if (lbl == "YB180") return 179.95233 ; + if (lbl == "YB181") return 180.95615 ; + if (lbl == "LU") return 174.9407718 ; + if (lbl == "LU150") return 149.973228 ; + if (lbl == "LU151") return 150.967577 ; + if (lbl == "LU152") return 151.96412 ; + if (lbl == "LU153") return 152.9587673 ; + if (lbl == "LU154") return 153.957522 ; + if (lbl == "LU155") return 154.9543162 ; + if (lbl == "LU156") return 155.9530325 ; + if (lbl == "LU157") return 156.9500983 ; + if (lbl == "LU158") return 157.9493133 ; + if (lbl == "LU159") return 158.9466288 ; + if (lbl == "LU160") return 159.946033 ; + if (lbl == "LU161") return 160.943572 ; + if (lbl == "LU162") return 161.9432773 ; + if (lbl == "LU163") return 162.941179 ; + if (lbl == "LU164") return 163.941339 ; + if (lbl == "LU165") return 164.9394067 ; + if (lbl == "LU166") return 165.939859 ; + if (lbl == "LU167") return 166.93827 ; + if (lbl == "LU168") return 167.9387391 ; + if (lbl == "LU169") return 168.9376514 ; + if (lbl == "LU170") return 169.938475 ; + if (lbl == "LU171") return 170.9379131 ; + if (lbl == "LU172") return 171.9390857 ; + if (lbl == "LU173") return 172.9389306 ; + if (lbl == "LU174") return 173.9403375 ; + if (lbl == "LU175") return 174.9407718 ; + if (lbl == "LU176") return 175.9426863 ; + if (lbl == "LU177") return 176.9437581 ; + if (lbl == "LU178") return 177.9459546 ; + if (lbl == "LU179") return 178.9473274 ; + if (lbl == "LU180") return 179.9498812 ; + if (lbl == "LU181") return 180.95197 ; + if (lbl == "LU182") return 181.95504 ; + if (lbl == "LU183") return 182.95757 ; + if (lbl == "LU184") return 183.96091 ; + if (lbl == "HF") return 179.94655 ; + if (lbl == "HF153") return 152.97069 ; + if (lbl == "HF154") return 153.96486 ; + if (lbl == "HF155") return 154.96339 ; + if (lbl == "HF156") return 155.959364 ; + if (lbl == "HF157") return 156.958396 ; + if (lbl == "HF158") return 157.9547994 ; + if (lbl == "HF159") return 158.9539949 ; + if (lbl == "HF160") return 159.9506844 ; + if (lbl == "HF161") return 160.9502748 ; + if (lbl == "HF162") return 161.9472105 ; + if (lbl == "HF163") return 162.947089 ; + if (lbl == "HF164") return 163.9443673 ; + if (lbl == "HF165") return 164.944567 ; + if (lbl == "HF166") return 165.94218 ; + if (lbl == "HF167") return 166.9426 ; + if (lbl == "HF168") return 167.940568 ; + if (lbl == "HF169") return 168.941259 ; + if (lbl == "HF170") return 169.939609 ; + if (lbl == "HF171") return 170.940492 ; + if (lbl == "HF172") return 171.9394483 ; + if (lbl == "HF173") return 172.940513 ; + if (lbl == "HF174") return 173.9400462 ; + if (lbl == "HF175") return 174.9415092 ; + if (lbl == "HF176") return 175.9414086 ; + if (lbl == "HF177") return 176.9432207 ; + if (lbl == "HF178") return 177.9436988 ; + if (lbl == "HF179") return 178.9458161 ; + if (lbl == "HF180") return 179.94655 ; + if (lbl == "HF181") return 180.9491012 ; + if (lbl == "HF182") return 181.9505541 ; + if (lbl == "HF183") return 182.9535304 ; + if (lbl == "HF184") return 183.9554465 ; + if (lbl == "HF185") return 184.95882 ; + if (lbl == "HF186") return 185.96089 ; + if (lbl == "HF187") return 186.96459 ; + if (lbl == "HF188") return 187.96685 ; + if (lbl == "TA") return 180.9479958 ; + if (lbl == "TA155") return 154.974592 ; + if (lbl == "TA156") return 155.972303 ; + if (lbl == "TA157") return 156.9681924 ; + if (lbl == "TA158") return 157.966699 ; + if (lbl == "TA159") return 158.9630182 ; + if (lbl == "TA160") return 159.9614861 ; + if (lbl == "TA161") return 160.958417 ; + if (lbl == "TA162") return 161.9572919 ; + if (lbl == "TA163") return 162.9543303 ; + if (lbl == "TA164") return 163.953534 ; + if (lbl == "TA165") return 164.9507725 ; + if (lbl == "TA166") return 165.950512 ; + if (lbl == "TA167") return 166.948093 ; + if (lbl == "TA168") return 167.948047 ; + if (lbl == "TA169") return 168.946011 ; + if (lbl == "TA170") return 169.946175 ; + if (lbl == "TA171") return 170.944476 ; + if (lbl == "TA172") return 171.944895 ; + if (lbl == "TA173") return 172.94375 ; + if (lbl == "TA174") return 173.944454 ; + if (lbl == "TA175") return 174.943737 ; + if (lbl == "TA176") return 175.944857 ; + if (lbl == "TA177") return 176.9444724 ; + if (lbl == "TA178") return 177.9457782 ; + if (lbl == "TA179") return 178.9459295 ; + if (lbl == "TA180") return 179.9474648 ; + if (lbl == "TA181") return 180.9479958 ; + if (lbl == "TA182") return 181.9501518 ; + if (lbl == "TA183") return 182.9513726 ; + if (lbl == "TA184") return 183.954008 ; + if (lbl == "TA185") return 184.9555594 ; + if (lbl == "TA186") return 185.958552 ; + if (lbl == "TA187") return 186.96053 ; + if (lbl == "TA188") return 187.9637 ; + if (lbl == "TA189") return 188.96583 ; + if (lbl == "TA190") return 189.96923 ; + if (lbl == "W") return 183.9509312 ; + if (lbl == "W158") return 157.974562 ; + if (lbl == "W159") return 158.972918 ; + if (lbl == "W160") return 159.9684788 ; + if (lbl == "W161") return 160.967357 ; + if (lbl == "W162") return 161.9634974 ; + if (lbl == "W163") return 162.9625235 ; + if (lbl == "W164") return 163.9589544 ; + if (lbl == "W165") return 164.9582799 ; + if (lbl == "W166") return 165.9550273 ; + if (lbl == "W167") return 166.954816 ; + if (lbl == "W168") return 167.9518084 ; + if (lbl == "W169") return 168.9517788 ; + if (lbl == "W170") return 169.9492285 ; + if (lbl == "W171") return 170.949451 ; + if (lbl == "W172") return 171.947292 ; + if (lbl == "W173") return 172.947689 ; + if (lbl == "W174") return 173.946079 ; + if (lbl == "W175") return 174.946717 ; + if (lbl == "W176") return 175.945634 ; + if (lbl == "W177") return 176.946643 ; + if (lbl == "W178") return 177.9458762 ; + if (lbl == "W179") return 178.9470704 ; + if (lbl == "W180") return 179.9467045 ; + if (lbl == "W181") return 180.9481972 ; + if (lbl == "W182") return 181.9482042 ; + if (lbl == "W183") return 182.950223 ; + if (lbl == "W184") return 183.9509312 ; + if (lbl == "W185") return 184.9534193 ; + if (lbl == "W186") return 185.9543641 ; + if (lbl == "W187") return 186.9571605 ; + if (lbl == "W188") return 187.9584891 ; + if (lbl == "W189") return 188.9619129 ; + if (lbl == "W190") return 189.9631814 ; + if (lbl == "W191") return 190.9666 ; + if (lbl == "W192") return 191.96817 ; + if (lbl == "RE") return 186.9557531 ; + if (lbl == "RE160") return 159.982115 ; + if (lbl == "RE161") return 160.9775891 ; + if (lbl == "RE162") return 161.976002 ; + if (lbl == "RE163") return 162.9720805 ; + if (lbl == "RE164") return 163.970323 ; + if (lbl == "RE165") return 164.9670886 ; + if (lbl == "RE166") return 165.965808 ; + if (lbl == "RE167") return 166.962601 ; + if (lbl == "RE168") return 167.9615726 ; + if (lbl == "RE169") return 168.9587911 ; + if (lbl == "RE170") return 169.9582201 ; + if (lbl == "RE171") return 170.955716 ; + if (lbl == "RE172") return 171.955423 ; + if (lbl == "RE173") return 172.953243 ; + if (lbl == "RE174") return 173.953115 ; + if (lbl == "RE175") return 174.951381 ; + if (lbl == "RE176") return 175.951623 ; + if (lbl == "RE177") return 176.950328 ; + if (lbl == "RE178") return 177.950989 ; + if (lbl == "RE179") return 178.9499876 ; + if (lbl == "RE180") return 179.9507891 ; + if (lbl == "RE181") return 180.9500679 ; + if (lbl == "RE182") return 181.9512101 ; + if (lbl == "RE183") return 182.9508198 ; + if (lbl == "RE184") return 183.9525208 ; + if (lbl == "RE185") return 184.952955 ; + if (lbl == "RE186") return 185.9549861 ; + if (lbl == "RE187") return 186.9557531 ; + if (lbl == "RE188") return 187.9581144 ; + if (lbl == "RE189") return 188.959229 ; + if (lbl == "RE190") return 189.961818 ; + if (lbl == "RE191") return 190.9631252 ; + if (lbl == "RE192") return 191.96596 ; + if (lbl == "RE193") return 192.96747 ; + if (lbl == "RE194") return 193.97042 ; + if (lbl == "OS") return 191.9614807 ; + if (lbl == "OS162") return 161.984431 ; + if (lbl == "OS163") return 162.98269 ; + if (lbl == "OS164") return 163.9780356 ; + if (lbl == "OS165") return 164.976762 ; + if (lbl == "OS166") return 165.9726908 ; + if (lbl == "OS167") return 166.971548 ; + if (lbl == "OS168") return 167.9678037 ; + if (lbl == "OS169") return 168.9670193 ; + if (lbl == "OS170") return 169.963577 ; + if (lbl == "OS171") return 170.9631848 ; + if (lbl == "OS172") return 171.9600233 ; + if (lbl == "OS173") return 172.9598084 ; + if (lbl == "OS174") return 173.9570622 ; + if (lbl == "OS175") return 174.9569458 ; + if (lbl == "OS176") return 175.954806 ; + if (lbl == "OS177") return 176.9549653 ; + if (lbl == "OS178") return 177.9532512 ; + if (lbl == "OS179") return 178.953816 ; + if (lbl == "OS180") return 179.9523788 ; + if (lbl == "OS181") return 180.953244 ; + if (lbl == "OS182") return 181.9521102 ; + if (lbl == "OS183") return 182.9531261 ; + if (lbl == "OS184") return 183.9524891 ; + if (lbl == "OS185") return 184.9540423 ; + if (lbl == "OS186") return 185.9538382 ; + if (lbl == "OS187") return 186.9557505 ; + if (lbl == "OS188") return 187.9558382 ; + if (lbl == "OS189") return 188.9581475 ; + if (lbl == "OS190") return 189.958447 ; + if (lbl == "OS191") return 190.9609297 ; + if (lbl == "OS192") return 191.9614807 ; + if (lbl == "OS193") return 192.9641516 ; + if (lbl == "OS194") return 193.9651821 ; + if (lbl == "OS195") return 194.9681267 ; + if (lbl == "OS196") return 195.9696393 ; + if (lbl == "IR") return 192.9629264 ; + if (lbl == "IR164") return 163.992201 ; + if (lbl == "IR165") return 164.98752 ; + if (lbl == "IR166") return 165.985824 ; + if (lbl == "IR167") return 166.9816652 ; + if (lbl == "IR168") return 167.979881 ; + if (lbl == "IR169") return 168.9762949 ; + if (lbl == "IR170") return 169.974965 ; + if (lbl == "IR171") return 170.971626 ; + if (lbl == "IR172") return 171.970456 ; + if (lbl == "IR173") return 172.9675017 ; + if (lbl == "IR174") return 173.966861 ; + if (lbl == "IR175") return 174.9641129 ; + if (lbl == "IR176") return 175.9636487 ; + if (lbl == "IR177") return 176.9613015 ; + if (lbl == "IR178") return 177.961082 ; + if (lbl == "IR179") return 178.9591223 ; + if (lbl == "IR180") return 179.9592294 ; + if (lbl == "IR181") return 180.9576253 ; + if (lbl == "IR182") return 181.9580763 ; + if (lbl == "IR183") return 182.9568465 ; + if (lbl == "IR184") return 183.957476 ; + if (lbl == "IR185") return 184.956698 ; + if (lbl == "IR186") return 185.9579461 ; + if (lbl == "IR187") return 186.9573634 ; + if (lbl == "IR188") return 187.9588531 ; + if (lbl == "IR189") return 188.9587189 ; + if (lbl == "IR190") return 189.960546 ; + if (lbl == "IR191") return 190.960594 ; + if (lbl == "IR192") return 191.962605 ; + if (lbl == "IR193") return 192.9629264 ; + if (lbl == "IR194") return 193.9650784 ; + if (lbl == "IR195") return 194.9659796 ; + if (lbl == "IR196") return 195.9683965 ; + if (lbl == "IR197") return 196.9696533 ; + if (lbl == "IR198") return 197.97228 ; + if (lbl == "IR199") return 198.9738046 ; + if (lbl == "PT") return 194.9647911 ; + if (lbl == "PT166") return 165.994855 ; + if (lbl == "PT167") return 166.992979 ; + if (lbl == "PT168") return 167.9881507 ; + if (lbl == "PT169") return 168.986715 ; + if (lbl == "PT170") return 169.9824953 ; + if (lbl == "PT171") return 170.9812445 ; + if (lbl == "PT172") return 171.9773471 ; + if (lbl == "PT173") return 172.9764448 ; + if (lbl == "PT174") return 173.9728188 ; + if (lbl == "PT175") return 174.9724206 ; + if (lbl == "PT176") return 175.9689446 ; + if (lbl == "PT177") return 176.9684695 ; + if (lbl == "PT178") return 177.9656487 ; + if (lbl == "PT179") return 178.9653634 ; + if (lbl == "PT180") return 179.9630315 ; + if (lbl == "PT181") return 180.9630973 ; + if (lbl == "PT182") return 181.9611707 ; + if (lbl == "PT183") return 182.9615967 ; + if (lbl == "PT184") return 183.9599223 ; + if (lbl == "PT185") return 184.960619 ; + if (lbl == "PT186") return 185.9593508 ; + if (lbl == "PT187") return 186.960587 ; + if (lbl == "PT188") return 187.9593954 ; + if (lbl == "PT189") return 188.9608337 ; + if (lbl == "PT190") return 189.9599317 ; + if (lbl == "PT191") return 190.9616767 ; + if (lbl == "PT192") return 191.961038 ; + if (lbl == "PT193") return 192.9629874 ; + if (lbl == "PT194") return 193.9626803 ; + if (lbl == "PT195") return 194.9647911 ; + if (lbl == "PT196") return 195.9649515 ; + if (lbl == "PT197") return 196.9673402 ; + if (lbl == "PT198") return 197.9678928 ; + if (lbl == "PT199") return 198.9705931 ; + if (lbl == "PT200") return 199.9714407 ; + if (lbl == "PT201") return 200.9745129 ; + if (lbl == "PT202") return 201.97574 ; + if (lbl == "AU") return 196.9665687 ; + if (lbl == "AU169") return 168.99808 ; + if (lbl == "AU170") return 169.996122 ; + if (lbl == "AU171") return 170.9918789 ; + if (lbl == "AU172") return 171.990035 ; + if (lbl == "AU173") return 172.9862374 ; + if (lbl == "AU174") return 173.984761 ; + if (lbl == "AU175") return 174.9812741 ; + if (lbl == "AU176") return 175.980099 ; + if (lbl == "AU177") return 176.9768649 ; + if (lbl == "AU178") return 177.9760319 ; + if (lbl == "AU179") return 178.9732128 ; + if (lbl == "AU180") return 179.9725211 ; + if (lbl == "AU181") return 180.970079 ; + if (lbl == "AU182") return 181.9696179 ; + if (lbl == "AU183") return 182.967593 ; + if (lbl == "AU184") return 183.9674515 ; + if (lbl == "AU185") return 184.9657894 ; + if (lbl == "AU186") return 185.9659527 ; + if (lbl == "AU187") return 186.9645675 ; + if (lbl == "AU188") return 187.9653237 ; + if (lbl == "AU189") return 188.9639483 ; + if (lbl == "AU190") return 189.9647003 ; + if (lbl == "AU191") return 190.9637042 ; + if (lbl == "AU192") return 191.964813 ; + if (lbl == "AU193") return 192.9641497 ; + if (lbl == "AU194") return 193.9653653 ; + if (lbl == "AU195") return 194.9650346 ; + if (lbl == "AU196") return 195.9665698 ; + if (lbl == "AU197") return 196.9665687 ; + if (lbl == "AU198") return 197.9682423 ; + if (lbl == "AU199") return 198.9687652 ; + if (lbl == "AU200") return 199.9707256 ; + if (lbl == "AU201") return 200.9716572 ; + if (lbl == "AU202") return 201.9738058 ; + if (lbl == "AU203") return 202.9751545 ; + if (lbl == "AU204") return 203.977724 ; + if (lbl == "AU205") return 204.97987 ; + if (lbl == "HG") return 201.970643 ; + if (lbl == "HG171") return 171.00376 ; + if (lbl == "HG172") return 171.9988327 ; + if (lbl == "HG173") return 172.997242 ; + if (lbl == "HG174") return 173.9928637 ; + if (lbl == "HG175") return 174.9914233 ; + if (lbl == "HG176") return 175.9873546 ; + if (lbl == "HG177") return 176.9862792 ; + if (lbl == "HG178") return 177.9824831 ; + if (lbl == "HG179") return 178.9818339 ; + if (lbl == "HG180") return 179.9782664 ; + if (lbl == "HG181") return 180.9778193 ; + if (lbl == "HG182") return 181.97469 ; + if (lbl == "HG183") return 182.9744498 ; + if (lbl == "HG184") return 183.9717131 ; + if (lbl == "HG185") return 184.9718991 ; + if (lbl == "HG186") return 185.9693618 ; + if (lbl == "HG187") return 186.9698142 ; + if (lbl == "HG188") return 187.967577 ; + if (lbl == "HG189") return 188.96819 ; + if (lbl == "HG190") return 189.9663224 ; + if (lbl == "HG191") return 190.9671571 ; + if (lbl == "HG192") return 191.9656343 ; + if (lbl == "HG193") return 192.9666654 ; + if (lbl == "HG194") return 193.9654394 ; + if (lbl == "HG195") return 194.9667201 ; + if (lbl == "HG196") return 195.9658326 ; + if (lbl == "HG197") return 196.9672129 ; + if (lbl == "HG198") return 197.966769 ; + if (lbl == "HG199") return 198.9682799 ; + if (lbl == "HG200") return 199.968326 ; + if (lbl == "HG201") return 200.9703023 ; + if (lbl == "HG202") return 201.970643 ; + if (lbl == "HG203") return 202.9728725 ; + if (lbl == "HG204") return 203.9734939 ; + if (lbl == "HG205") return 204.9760734 ; + if (lbl == "HG206") return 205.9775141 ; + if (lbl == "HG207") return 206.9825885 ; + if (lbl == "HG208") return 207.98594 ; + if (lbl == "HG209") return 208.99104 ; + if (lbl == "HG210") return 209.99451 ; + if (lbl == "TL") return 204.9744275 ; + if (lbl == "TL176") return 176.00059 ; + if (lbl == "TL177") return 176.9964273 ; + if (lbl == "TL178") return 177.994897 ; + if (lbl == "TL179") return 178.9910891 ; + if (lbl == "TL180") return 179.989906 ; + if (lbl == "TL181") return 180.9862574 ; + if (lbl == "TL182") return 181.9856671 ; + if (lbl == "TL183") return 182.9821928 ; + if (lbl == "TL184") return 183.9818731 ; + if (lbl == "TL185") return 184.9787913 ; + if (lbl == "TL186") return 185.978325 ; + if (lbl == "TL187") return 186.9759059 ; + if (lbl == "TL188") return 187.9760098 ; + if (lbl == "TL189") return 188.9735884 ; + if (lbl == "TL190") return 189.9738771 ; + if (lbl == "TL191") return 190.9717862 ; + if (lbl == "TL192") return 191.972225 ; + if (lbl == "TL193") return 192.970672 ; + if (lbl == "TL194") return 193.9712 ; + if (lbl == "TL195") return 194.9697743 ; + if (lbl == "TL196") return 195.9704812 ; + if (lbl == "TL197") return 196.9695745 ; + if (lbl == "TL198") return 197.9704835 ; + if (lbl == "TL199") return 198.969877 ; + if (lbl == "TL200") return 199.9709627 ; + if (lbl == "TL201") return 200.9708189 ; + if (lbl == "TL202") return 201.9721058 ; + if (lbl == "TL203") return 202.9723442 ; + if (lbl == "TL204") return 203.9738635 ; + if (lbl == "TL205") return 204.9744275 ; + if (lbl == "TL206") return 205.9761103 ; + if (lbl == "TL207") return 206.9774194 ; + if (lbl == "TL208") return 207.9820187 ; + if (lbl == "TL209") return 208.985359 ; + if (lbl == "TL210") return 209.9900737 ; + if (lbl == "TL211") return 210.993477 ; + if (lbl == "TL212") return 211.998228 ; + if (lbl == "PB") return 207.9766521 ; + if (lbl == "PB178") return 178.0038302 ; + if (lbl == "PB179") return 179.00215 ; + if (lbl == "PB180") return 179.9979182 ; + if (lbl == "PB181") return 180.996624 ; + if (lbl == "PB182") return 181.9926718 ; + if (lbl == "PB183") return 182.9918746 ; + if (lbl == "PB184") return 183.9881423 ; + if (lbl == "PB185") return 184.9876099 ; + if (lbl == "PB186") return 185.9842389 ; + if (lbl == "PB187") return 186.9839184 ; + if (lbl == "PB188") return 187.9808743 ; + if (lbl == "PB189") return 188.980807 ; + if (lbl == "PB190") return 189.9780815 ; + if (lbl == "PB191") return 190.978265 ; + if (lbl == "PB192") return 191.9757852 ; + if (lbl == "PB193") return 192.9761732 ; + if (lbl == "PB194") return 193.9740121 ; + if (lbl == "PB195") return 194.9745421 ; + if (lbl == "PB196") return 195.9727741 ; + if (lbl == "PB197") return 196.9734311 ; + if (lbl == "PB198") return 197.972034 ; + if (lbl == "PB199") return 198.9729167 ; + if (lbl == "PB200") return 199.9718267 ; + if (lbl == "PB201") return 200.9728845 ; + if (lbl == "PB202") return 201.9721591 ; + if (lbl == "PB203") return 202.9733905 ; + if (lbl == "PB204") return 203.9730436 ; + if (lbl == "PB205") return 204.9744818 ; + if (lbl == "PB206") return 205.9744653 ; + if (lbl == "PB207") return 206.9758969 ; + if (lbl == "PB208") return 207.9766521 ; + if (lbl == "PB209") return 208.9810901 ; + if (lbl == "PB210") return 209.9841885 ; + if (lbl == "PB211") return 210.988737 ; + if (lbl == "PB212") return 211.9918975 ; + if (lbl == "PB213") return 212.9965815 ; + if (lbl == "PB214") return 213.9998054 ; + if (lbl == "PB215") return 215.004807 ; + if (lbl == "BI") return 208.9803987 ; + if (lbl == "BI184") return 184.001124 ; + if (lbl == "BI185") return 184.997625 ; + if (lbl == "BI186") return 185.9965976 ; + if (lbl == "BI187") return 186.9931578 ; + if (lbl == "BI188") return 187.9922652 ; + if (lbl == "BI189") return 188.989199 ; + if (lbl == "BI190") return 189.9882951 ; + if (lbl == "BI191") return 190.9857861 ; + if (lbl == "BI192") return 191.985458 ; + if (lbl == "BI193") return 192.9829598 ; + if (lbl == "BI194") return 193.982834 ; + if (lbl == "BI195") return 194.9806507 ; + if (lbl == "BI196") return 195.9806665 ; + if (lbl == "BI197") return 196.9788645 ; + if (lbl == "BI198") return 197.979206 ; + if (lbl == "BI199") return 198.977672 ; + if (lbl == "BI200") return 199.9781318 ; + if (lbl == "BI201") return 200.977009 ; + if (lbl == "BI202") return 201.9777423 ; + if (lbl == "BI203") return 202.976876 ; + if (lbl == "BI204") return 203.9778127 ; + if (lbl == "BI205") return 204.9773894 ; + if (lbl == "BI206") return 205.9784991 ; + if (lbl == "BI207") return 206.9784707 ; + if (lbl == "BI208") return 207.9797422 ; + if (lbl == "BI209") return 208.9803987 ; + if (lbl == "BI210") return 209.9841204 ; + if (lbl == "BI211") return 210.9872695 ; + if (lbl == "BI212") return 211.9912857 ; + if (lbl == "BI213") return 212.9943847 ; + if (lbl == "BI214") return 213.9987115 ; + if (lbl == "BI215") return 215.0017698 ; + if (lbl == "BI216") return 216.0063059 ; + if (lbl == "BI217") return 217.00947 ; + if (lbl == "BI218") return 218.014316 ; + if (lbl == "PO") return 208.9824304 ; + if (lbl == "PO188") return 187.999422 ; + if (lbl == "PO189") return 188.9984806 ; + if (lbl == "PO190") return 189.9951012 ; + if (lbl == "PO191") return 190.9945745 ; + if (lbl == "PO192") return 191.9913351 ; + if (lbl == "PO193") return 192.9910253 ; + if (lbl == "PO194") return 193.9881856 ; + if (lbl == "PO195") return 194.9881107 ; + if (lbl == "PO196") return 195.9855346 ; + if (lbl == "PO197") return 196.9856596 ; + if (lbl == "PO198") return 197.9833886 ; + if (lbl == "PO199") return 198.9836661 ; + if (lbl == "PO200") return 199.9817986 ; + if (lbl == "PO201") return 200.9822598 ; + if (lbl == "PO202") return 201.9807575 ; + if (lbl == "PO203") return 202.9814201 ; + if (lbl == "PO204") return 203.9803181 ; + if (lbl == "PO205") return 204.9812033 ; + if (lbl == "PO206") return 205.9804811 ; + if (lbl == "PO207") return 206.9815932 ; + if (lbl == "PO208") return 207.9812457 ; + if (lbl == "PO209") return 208.9824304 ; + if (lbl == "PO210") return 209.9828737 ; + if (lbl == "PO211") return 210.9866532 ; + if (lbl == "PO212") return 211.988868 ; + if (lbl == "PO213") return 212.9928573 ; + if (lbl == "PO214") return 213.9952014 ; + if (lbl == "PO215") return 214.99942 ; + if (lbl == "PO216") return 216.001915 ; + if (lbl == "PO217") return 217.0063348 ; + if (lbl == "PO218") return 218.008973 ; + if (lbl == "PO219") return 219.013744 ; + if (lbl == "PO220") return 220.016602 ; + if (lbl == "AT") return 210.9874963 ; + if (lbl == "AT193") return 192.9998431 ; + if (lbl == "AT194") return 193.9987251 ; + if (lbl == "AT195") return 194.9962681 ; + if (lbl == "AT196") return 195.9957881 ; + if (lbl == "AT197") return 196.9931892 ; + if (lbl == "AT198") return 197.9928372 ; + if (lbl == "AT199") return 198.9905323 ; + if (lbl == "AT200") return 199.9903513 ; + if (lbl == "AT201") return 200.988417 ; + if (lbl == "AT202") return 201.9886302 ; + if (lbl == "AT203") return 202.986942 ; + if (lbl == "AT204") return 203.9872513 ; + if (lbl == "AT205") return 204.9860745 ; + if (lbl == "AT206") return 205.986667 ; + if (lbl == "AT207") return 206.9857835 ; + if (lbl == "AT208") return 207.98659 ; + if (lbl == "AT209") return 208.9861731 ; + if (lbl == "AT210") return 209.9871477 ; + if (lbl == "AT211") return 210.9874963 ; + if (lbl == "AT212") return 211.9907448 ; + if (lbl == "AT213") return 212.9929366 ; + if (lbl == "AT214") return 213.9963717 ; + if (lbl == "AT215") return 214.9986526 ; + if (lbl == "AT216") return 216.0024233 ; + if (lbl == "AT217") return 217.0047188 ; + if (lbl == "AT218") return 218.0086943 ; + if (lbl == "AT219") return 219.0111617 ; + if (lbl == "AT220") return 220.0154077 ; + if (lbl == "AT221") return 221.01805 ; + if (lbl == "AT222") return 222.02233 ; + if (lbl == "AT223") return 223.02519 ; + if (lbl == "RN") return 222.0175777 ; + if (lbl == "RN195") return 195.0054377 ; + if (lbl == "RN196") return 196.0021152 ; + if (lbl == "RN197") return 197.0015844 ; + if (lbl == "RN198") return 197.9986787 ; + if (lbl == "RN199") return 198.9983703 ; + if (lbl == "RN200") return 199.9956993 ; + if (lbl == "RN201") return 200.9956283 ; + if (lbl == "RN202") return 201.9932635 ; + if (lbl == "RN203") return 202.9933867 ; + if (lbl == "RN204") return 203.9914287 ; + if (lbl == "RN205") return 204.9917188 ; + if (lbl == "RN206") return 205.9902141 ; + if (lbl == "RN207") return 206.9907342 ; + if (lbl == "RN208") return 207.9896425 ; + if (lbl == "RN209") return 208.9904147 ; + if (lbl == "RN210") return 209.9896962 ; + if (lbl == "RN211") return 210.9906005 ; + if (lbl == "RN212") return 211.9907035 ; + if (lbl == "RN213") return 212.9938827 ; + if (lbl == "RN214") return 213.9953626 ; + if (lbl == "RN215") return 214.9987455 ; + if (lbl == "RN216") return 216.0002744 ; + if (lbl == "RN217") return 217.0039277 ; + if (lbl == "RN218") return 218.0056013 ; + if (lbl == "RN219") return 219.0094802 ; + if (lbl == "RN220") return 220.011394 ; + if (lbl == "RN221") return 221.0155368 ; + if (lbl == "RN222") return 222.0175777 ; + if (lbl == "RN223") return 223.02179 ; + if (lbl == "RN224") return 224.02409 ; + if (lbl == "RN225") return 225.02844 ; + if (lbl == "RN226") return 226.03089 ; + if (lbl == "RN227") return 227.035407 ; + if (lbl == "RN228") return 228.037986 ; + if (lbl == "FR") return 222.0175517 ; + if (lbl == "FR199") return 199.0072581 ; + if (lbl == "FR200") return 200.0065725 ; + if (lbl == "FR201") return 201.0038609 ; + if (lbl == "FR202") return 202.0033728 ; + if (lbl == "FR203") return 203.0009246 ; + if (lbl == "FR204") return 204.0006532 ; + if (lbl == "FR205") return 204.998594 ; + if (lbl == "FR206") return 205.9986661 ; + if (lbl == "FR207") return 206.9969494 ; + if (lbl == "FR208") return 207.9971388 ; + if (lbl == "FR209") return 208.9959536 ; + if (lbl == "FR210") return 209.9964077 ; + if (lbl == "FR211") return 210.9955365 ; + if (lbl == "FR212") return 211.9962022 ; + if (lbl == "FR213") return 212.9961891 ; + if (lbl == "FR214") return 213.9989711 ; + if (lbl == "FR215") return 215.0003415 ; + if (lbl == "FR216") return 216.003198 ; + if (lbl == "FR217") return 217.004632 ; + if (lbl == "FR218") return 218.0075783 ; + if (lbl == "FR219") return 219.0092521 ; + if (lbl == "FR220") return 220.0123274 ; + if (lbl == "FR221") return 221.0142548 ; + if (lbl == "FR222") return 222.0175517 ; + if (lbl == "FR223") return 223.0197359 ; + if (lbl == "FR224") return 224.02325 ; + if (lbl == "FR225") return 225.0255654 ; + if (lbl == "FR226") return 226.0293862 ; + if (lbl == "FR227") return 227.0318359 ; + if (lbl == "FR228") return 228.035729 ; + if (lbl == "FR229") return 229.0384502 ; + if (lbl == "FR230") return 230.04251 ; + if (lbl == "FR231") return 231.04544 ; + if (lbl == "FR232") return 232.049772 ; + if (lbl == "RA") return 228.0310703 ; + if (lbl == "RA202") return 202.0098907 ; + if (lbl == "RA203") return 203.0092716 ; + if (lbl == "RA204") return 204.0064997 ; + if (lbl == "RA205") return 205.0062686 ; + if (lbl == "RA206") return 206.0038273 ; + if (lbl == "RA207") return 207.0037981 ; + if (lbl == "RA208") return 208.0018399 ; + if (lbl == "RA209") return 209.0019914 ; + if (lbl == "RA210") return 210.000495 ; + if (lbl == "RA211") return 211.000898 ; + if (lbl == "RA212") return 211.9997945 ; + if (lbl == "RA213") return 213.000384 ; + if (lbl == "RA214") return 214.0001079 ; + if (lbl == "RA215") return 215.0027198 ; + if (lbl == "RA216") return 216.003533 ; + if (lbl == "RA217") return 217.0063203 ; + if (lbl == "RA218") return 218.0071402 ; + if (lbl == "RA219") return 219.0100851 ; + if (lbl == "RA220") return 220.0110284 ; + if (lbl == "RA221") return 221.0139173 ; + if (lbl == "RA222") return 222.0153745 ; + if (lbl == "RA223") return 223.0185022 ; + if (lbl == "RA224") return 224.0202118 ; + if (lbl == "RA225") return 225.0236116 ; + if (lbl == "RA226") return 226.0254098 ; + if (lbl == "RA227") return 227.0291778 ; + if (lbl == "RA228") return 228.0310703 ; + if (lbl == "RA229") return 229.0349576 ; + if (lbl == "RA230") return 230.0370564 ; + if (lbl == "RA231") return 231.04122 ; + if (lbl == "RA232") return 232.043638 ; + if (lbl == "RA233") return 233.04806 ; + if (lbl == "RA234") return 234.050704 ; + if (lbl == "AC") return 227.0277521 ; + if (lbl == "AC206") return 206.014505 ; + if (lbl == "AC207") return 207.0119497 ; + if (lbl == "AC208") return 208.0115516 ; + if (lbl == "AC209") return 209.0094949 ; + if (lbl == "AC210") return 210.009436 ; + if (lbl == "AC211") return 211.0077348 ; + if (lbl == "AC212") return 212.0078138 ; + if (lbl == "AC213") return 213.0066076 ; + if (lbl == "AC214") return 214.0069018 ; + if (lbl == "AC215") return 215.0064536 ; + if (lbl == "AC216") return 216.0087201 ; + if (lbl == "AC217") return 217.0093469 ; + if (lbl == "AC218") return 218.0116415 ; + if (lbl == "AC219") return 219.0124204 ; + if (lbl == "AC220") return 220.014763 ; + if (lbl == "AC221") return 221.0155912 ; + if (lbl == "AC222") return 222.0178439 ; + if (lbl == "AC223") return 223.0191375 ; + if (lbl == "AC224") return 224.0217229 ; + if (lbl == "AC225") return 225.0232296 ; + if (lbl == "AC226") return 226.0260981 ; + if (lbl == "AC227") return 227.0277521 ; + if (lbl == "AC228") return 228.0310211 ; + if (lbl == "AC229") return 229.0330152 ; + if (lbl == "AC230") return 230.0362942 ; + if (lbl == "AC231") return 231.0385588 ; + if (lbl == "AC232") return 232.0420274 ; + if (lbl == "AC233") return 233.04455 ; + if (lbl == "AC234") return 234.04842 ; + if (lbl == "AC235") return 235.051232 ; + if (lbl == "AC236") return 236.055296 ; + if (lbl == "TH") return 232.0380553 ; + if (lbl == "TH209") return 209.0177157 ; + if (lbl == "TH210") return 210.0150753 ; + if (lbl == "TH211") return 211.0149284 ; + if (lbl == "TH212") return 212.0129803 ; + if (lbl == "TH213") return 213.0130101 ; + if (lbl == "TH214") return 214.0114998 ; + if (lbl == "TH215") return 215.0117303 ; + if (lbl == "TH216") return 216.0110621 ; + if (lbl == "TH217") return 217.0131143 ; + if (lbl == "TH218") return 218.0132845 ; + if (lbl == "TH219") return 219.0155369 ; + if (lbl == "TH220") return 220.0157478 ; + if (lbl == "TH221") return 221.0181837 ; + if (lbl == "TH222") return 222.0184681 ; + if (lbl == "TH223") return 223.0208114 ; + if (lbl == "TH224") return 224.0214669 ; + if (lbl == "TH225") return 225.023951 ; + if (lbl == "TH226") return 226.0249031 ; + if (lbl == "TH227") return 227.0277041 ; + if (lbl == "TH228") return 228.0287411 ; + if (lbl == "TH229") return 229.0317624 ; + if (lbl == "TH230") return 230.0331338 ; + if (lbl == "TH231") return 231.0363043 ; + if (lbl == "TH232") return 232.0380553 ; + if (lbl == "TH233") return 233.0415818 ; + if (lbl == "TH234") return 234.0436012 ; + if (lbl == "TH235") return 235.0475101 ; + if (lbl == "TH236") return 236.04987 ; + if (lbl == "TH237") return 237.053894 ; + if (lbl == "TH238") return 238.056496 ; + if (lbl == "PA") return 231.035884 ; + if (lbl == "PA212") return 212.0232041 ; + if (lbl == "PA213") return 213.0211093 ; + if (lbl == "PA214") return 214.0209184 ; + if (lbl == "PA215") return 215.0191859 ; + if (lbl == "PA216") return 216.0191096 ; + if (lbl == "PA217") return 217.018324 ; + if (lbl == "PA218") return 218.0200419 ; + if (lbl == "PA219") return 219.0198831 ; + if (lbl == "PA220") return 220.0218753 ; + if (lbl == "PA221") return 221.021878 ; + if (lbl == "PA222") return 222.023742 ; + if (lbl == "PA223") return 223.0239623 ; + if (lbl == "PA224") return 224.0256257 ; + if (lbl == "PA225") return 225.0261307 ; + if (lbl == "PA226") return 226.0279478 ; + if (lbl == "PA227") return 227.0288051 ; + if (lbl == "PA228") return 228.0310514 ; + if (lbl == "PA229") return 229.0320968 ; + if (lbl == "PA230") return 230.0345408 ; + if (lbl == "PA231") return 231.035884 ; + if (lbl == "PA232") return 232.0385916 ; + if (lbl == "PA233") return 233.0402473 ; + if (lbl == "PA234") return 234.0433081 ; + if (lbl == "PA235") return 235.0454436 ; + if (lbl == "PA236") return 236.0486813 ; + if (lbl == "PA237") return 237.0511457 ; + if (lbl == "PA238") return 238.0545027 ; + if (lbl == "PA239") return 239.05726 ; + if (lbl == "PA240") return 240.06098 ; + if (lbl == "U") return 238.0507882 ; + if (lbl == "U217") return 217.0243688 ; + if (lbl == "U218") return 218.0235357 ; + if (lbl == "U219") return 219.0249192 ; + if (lbl == "U220") return 220.024723 ; + if (lbl == "U221") return 221.026399 ; + if (lbl == "U222") return 222.026086 ; + if (lbl == "U223") return 223.0277386 ; + if (lbl == "U224") return 224.0276048 ; + if (lbl == "U225") return 225.0293907 ; + if (lbl == "U226") return 226.0293387 ; + if (lbl == "U227") return 227.0311564 ; + if (lbl == "U228") return 228.031374 ; + if (lbl == "U229") return 229.0335059 ; + if (lbl == "U230") return 230.0339398 ; + if (lbl == "U231") return 231.0362937 ; + if (lbl == "U232") return 232.0371562 ; + if (lbl == "U233") return 233.0396352 ; + if (lbl == "U234") return 234.0409521 ; + if (lbl == "U235") return 235.0439299 ; + if (lbl == "U236") return 236.045568 ; + if (lbl == "U237") return 237.0487302 ; + if (lbl == "U238") return 238.0507882 ; + if (lbl == "U239") return 239.0542933 ; + if (lbl == "U240") return 240.056592 ; + if (lbl == "U241") return 241.06033 ; + if (lbl == "U242") return 242.062931 ; + if (lbl == "NP") return 237.0481734 ; + if (lbl == "NP225") return 225.0339139 ; + if (lbl == "NP226") return 226.035145 ; + if (lbl == "NP227") return 227.0349568 ; + if (lbl == "NP228") return 228.03618 ; + if (lbl == "NP229") return 229.0362638 ; + if (lbl == "NP230") return 230.0378276 ; + if (lbl == "NP231") return 231.0382451 ; + if (lbl == "NP232") return 232.040108 ; + if (lbl == "NP233") return 233.0407405 ; + if (lbl == "NP234") return 234.042895 ; + if (lbl == "NP235") return 235.0440633 ; + if (lbl == "NP236") return 236.0465696 ; + if (lbl == "NP237") return 237.0481734 ; + if (lbl == "NP238") return 238.0509464 ; + if (lbl == "NP239") return 239.052939 ; + if (lbl == "NP240") return 240.0561622 ; + if (lbl == "NP241") return 241.0582524 ; + if (lbl == "NP242") return 242.0616412 ; + if (lbl == "NP243") return 243.064279 ; + if (lbl == "NP244") return 244.06785 ; + if (lbl == "PU") return 242.0587426 ; + if (lbl == "PU228") return 228.0387423 ; + if (lbl == "PU229") return 229.0401502 ; + if (lbl == "PU230") return 230.0396499 ; + if (lbl == "PU231") return 231.0411011 ; + if (lbl == "PU232") return 232.0411871 ; + if (lbl == "PU233") return 233.0429974 ; + if (lbl == "PU234") return 234.0433171 ; + if (lbl == "PU235") return 235.0452861 ; + if (lbl == "PU236") return 236.046058 ; + if (lbl == "PU237") return 237.0484097 ; + if (lbl == "PU238") return 238.0495599 ; + if (lbl == "PU239") return 239.0521634 ; + if (lbl == "PU240") return 240.0538135 ; + if (lbl == "PU241") return 241.0568515 ; + if (lbl == "PU242") return 242.0587426 ; + if (lbl == "PU243") return 243.0620031 ; + if (lbl == "PU244") return 244.0642039 ; + if (lbl == "PU245") return 245.0677472 ; + if (lbl == "PU246") return 246.0702046 ; + if (lbl == "PU247") return 247.07407 ; + if (lbl == "AM") return 243.0613811 ; + if (lbl == "AM231") return 231.04556 ; + if (lbl == "AM232") return 232.04659 ; + if (lbl == "AM233") return 233.046348 ; + if (lbl == "AM234") return 234.047809 ; + if (lbl == "AM235") return 235.047946 ; + if (lbl == "AM236") return 236.049579 ; + if (lbl == "AM237") return 237.049996 ; + if (lbl == "AM238") return 238.0519843 ; + if (lbl == "AM239") return 239.0530245 ; + if (lbl == "AM240") return 240.0553002 ; + if (lbl == "AM241") return 241.0568291 ; + if (lbl == "AM242") return 242.0595492 ; + if (lbl == "AM243") return 243.0613811 ; + if (lbl == "AM244") return 244.0642848 ; + if (lbl == "AM245") return 245.0664521 ; + if (lbl == "AM246") return 246.0697746 ; + if (lbl == "AM247") return 247.072093 ; + if (lbl == "AM248") return 248.075752 ; + if (lbl == "AM249") return 249.07848 ; + if (lbl == "CM") return 247.0703535 ; + if (lbl == "CM233") return 233.0507712 ; + if (lbl == "CM234") return 234.0501598 ; + if (lbl == "CM235") return 235.051434 ; + if (lbl == "CM236") return 236.051413 ; + if (lbl == "CM237") return 237.052901 ; + if (lbl == "CM238") return 238.0530287 ; + if (lbl == "CM239") return 239.054957 ; + if (lbl == "CM240") return 240.0555295 ; + if (lbl == "CM241") return 241.057653 ; + if (lbl == "CM242") return 242.0588358 ; + if (lbl == "CM243") return 243.0613891 ; + if (lbl == "CM244") return 244.0627526 ; + if (lbl == "CM245") return 245.0654912 ; + if (lbl == "CM246") return 246.0672237 ; + if (lbl == "CM247") return 247.0703535 ; + if (lbl == "CM248") return 248.0723485 ; + if (lbl == "CM249") return 249.0759534 ; + if (lbl == "CM250") return 250.078357 ; + if (lbl == "CM251") return 251.0822846 ; + if (lbl == "CM252") return 252.08487 ; + if (lbl == "BK") return 247.0703071 ; + if (lbl == "BK235") return 235.05658 ; + if (lbl == "BK236") return 236.05733 ; + if (lbl == "BK237") return 237.057003 ; + if (lbl == "BK238") return 238.058281 ; + if (lbl == "BK239") return 239.058279 ; + if (lbl == "BK240") return 240.059759 ; + if (lbl == "BK241") return 241.06023 ; + if (lbl == "BK242") return 242.061981 ; + if (lbl == "BK243") return 243.0630076 ; + if (lbl == "BK244") return 244.0651808 ; + if (lbl == "BK245") return 245.0663616 ; + if (lbl == "BK246") return 246.0686729 ; + if (lbl == "BK247") return 247.0703071 ; + if (lbl == "BK248") return 248.073086 ; + if (lbl == "BK249") return 249.0749867 ; + if (lbl == "BK250") return 250.0783165 ; + if (lbl == "BK251") return 251.0807602 ; + if (lbl == "BK252") return 252.08431 ; + if (lbl == "BK253") return 253.08688 ; + if (lbl == "BK254") return 254.0906 ; + if (lbl == "CF") return 251.0795868 ; + if (lbl == "CF237") return 237.06207 ; + if (lbl == "CF238") return 238.06141 ; + if (lbl == "CF239") return 239.062422 ; + if (lbl == "CF240") return 240.062302 ; + if (lbl == "CF241") return 241.063726 ; + if (lbl == "CF242") return 242.0637016 ; + if (lbl == "CF243") return 243.065427 ; + if (lbl == "CF244") return 244.0660007 ; + if (lbl == "CF245") return 245.0680486 ; + if (lbl == "CF246") return 246.0688053 ; + if (lbl == "CF247") return 247.0710006 ; + if (lbl == "CF248") return 248.0721849 ; + if (lbl == "CF249") return 249.0748535 ; + if (lbl == "CF250") return 250.0764061 ; + if (lbl == "CF251") return 251.0795868 ; + if (lbl == "CF252") return 252.0816258 ; + if (lbl == "CF253") return 253.0851331 ; + if (lbl == "CF254") return 254.0873229 ; + if (lbl == "CF255") return 255.091046 ; + if (lbl == "CF256") return 256.09344 ; + if (lbl == "ES") return 252.0829785 ; + if (lbl == "ES240") return 240.06892 ; + if (lbl == "ES241") return 241.068538 ; + if (lbl == "ES242") return 242.069745 ; + if (lbl == "ES243") return 243.069548 ; + if (lbl == "ES244") return 244.070883 ; + if (lbl == "ES245") return 245.071324 ; + if (lbl == "ES246") return 246.072896 ; + if (lbl == "ES247") return 247.073656 ; + if (lbl == "ES248") return 248.075471 ; + if (lbl == "ES249") return 249.076411 ; + if (lbl == "ES250") return 250.078612 ; + if (lbl == "ES251") return 251.0799921 ; + if (lbl == "ES252") return 252.0829785 ; + if (lbl == "ES253") return 253.0848247 ; + if (lbl == "ES254") return 254.088022 ; + if (lbl == "ES255") return 255.0902731 ; + if (lbl == "ES256") return 256.093598 ; + if (lbl == "ES257") return 257.095979 ; + if (lbl == "ES258") return 258.09952 ; + if (lbl == "FM") return 257.0951047 ; + if (lbl == "FM242") return 242.07343 ; + if (lbl == "FM243") return 243.074353 ; + if (lbl == "FM244") return 244.074084 ; + if (lbl == "FM245") return 245.075385 ; + if (lbl == "FM246") return 246.075299 ; + if (lbl == "FM247") return 247.076847 ; + if (lbl == "FM248") return 248.0771947 ; + if (lbl == "FM249") return 249.079034 ; + if (lbl == "FM250") return 250.0795213 ; + if (lbl == "FM251") return 251.081575 ; + if (lbl == "FM252") return 252.0824669 ; + if (lbl == "FM253") return 253.0851852 ; + if (lbl == "FM254") return 254.0868542 ; + if (lbl == "FM255") return 255.0899622 ; + if (lbl == "FM256") return 256.0917731 ; + if (lbl == "FM257") return 257.0951047 ; + if (lbl == "FM258") return 258.097076 ; + if (lbl == "FM259") return 259.100595 ; + if (lbl == "FM260") return 260.102678 ; + if (lbl == "MD") return 258.0984313 ; + if (lbl == "MD245") return 245.080829 ; + if (lbl == "MD246") return 246.081886 ; + if (lbl == "MD247") return 247.081635 ; + if (lbl == "MD248") return 248.082823 ; + if (lbl == "MD249") return 249.083013 ; + if (lbl == "MD250") return 250.08442 ; + if (lbl == "MD251") return 251.084839 ; + if (lbl == "MD252") return 252.08656 ; + if (lbl == "MD253") return 253.08728 ; + if (lbl == "MD254") return 254.089656 ; + if (lbl == "MD255") return 255.0910827 ; + if (lbl == "MD256") return 256.094059 ; + if (lbl == "MD257") return 257.0955414 ; + if (lbl == "MD258") return 258.0984313 ; + if (lbl == "MD259") return 259.100509 ; + if (lbl == "MD260") return 260.103652 ; + if (lbl == "MD261") return 261.105721 ; + if (lbl == "MD262") return 262.108865 ; + if (lbl == "NO") return 255.0932411 ; + if (lbl == "NO248") return 248.086596 ; + if (lbl == "NO249") return 249.087833 ; + if (lbl == "NO250") return 250.08751 ; + if (lbl == "NO251") return 251.089012 ; + if (lbl == "NO252") return 252.0889765 ; + if (lbl == "NO253") return 253.090678 ; + if (lbl == "NO254") return 254.0909553 ; + if (lbl == "NO255") return 255.0932411 ; + if (lbl == "NO256") return 256.0942827 ; + if (lbl == "NO257") return 257.0968772 ; + if (lbl == "NO258") return 258.098207 ; + if (lbl == "NO259") return 259.101031 ; + if (lbl == "NO260") return 260.102643 ; + if (lbl == "NO261") return 261.105749 ; + if (lbl == "NO262") return 262.107301 ; + if (lbl == "NO263") return 263.110552 ; + if (lbl == "NO264") return 264.112345 ; + if (lbl == "LR") return 260.105504 ; + if (lbl == "LR251") return 251.09436 ; + if (lbl == "LR252") return 252.095371 ; + if (lbl == "LR253") return 253.09521 ; + if (lbl == "LR254") return 254.096454 ; + if (lbl == "LR255") return 255.096681 ; + if (lbl == "LR256") return 256.098629 ; + if (lbl == "LR257") return 257.099555 ; + if (lbl == "LR258") return 258.101814 ; + if (lbl == "LR259") return 259.102901 ; + if (lbl == "LR260") return 260.105504 ; + if (lbl == "LR261") return 261.106883 ; + if (lbl == "LR262") return 262.109634 ; + if (lbl == "LR263") return 263.111293 ; + if (lbl == "LR264") return 264.114038 ; + if (lbl == "LR265") return 265.115839 ; + if (lbl == "LR266") return 266.119305 ; + if (lbl == "RF") return 263.112547 ; + if (lbl == "RF253") return 253.100689 ; + if (lbl == "RF254") return 254.100184 ; + if (lbl == "RF255") return 255.10134 ; + if (lbl == "RF256") return 256.1011662 ; + if (lbl == "RF257") return 257.10299 ; + if (lbl == "RF258") return 258.103489 ; + if (lbl == "RF259") return 259.105637 ; + if (lbl == "RF260") return 260.10644 ; + if (lbl == "RF261") return 261.1087666 ; + if (lbl == "RF262") return 262.109925 ; + if (lbl == "RF263") return 263.112547 ; + if (lbl == "RF264") return 264.113985 ; + if (lbl == "RF265") return 265.116704 ; + if (lbl == "RF266") return 266.117956 ; + if (lbl == "RF267") return 267.121529 ; + if (lbl == "RF268") return 268.123644 ; + if (lbl == "DB") return 255.107398 ; + if (lbl == "DB255") return 255.107398 ; + if (lbl == "DB256") return 256.108127 ; + if (lbl == "DB257") return 257.107722 ; + if (lbl == "DB258") return 258.109231 ; + if (lbl == "DB259") return 259.10961 ; + if (lbl == "DB260") return 260.1113 ; + if (lbl == "DB261") return 261.112056 ; + if (lbl == "DB262") return 262.114084 ; + if (lbl == "DB263") return 263.114988 ; + if (lbl == "DB264") return 264.117404 ; + if (lbl == "DB265") return 265.118601 ; + if (lbl == "DB266") return 266.121029 ; + if (lbl == "DB267") return 267.122377 ; + if (lbl == "DB268") return 268.125445 ; + if (lbl == "DB269") return 269.12746 ; + if (lbl == "DB270") return 270.130712 ; + if (lbl == "SG") return 259.1145 ; + if (lbl == "SG258") return 258.113168 ; + if (lbl == "SG259") return 259.1145 ; + if (lbl == "SG260") return 260.1144221 ; + if (lbl == "SG261") return 261.116117 ; + if (lbl == "SG262") return 262.116398 ; + if (lbl == "SG263") return 263.118322 ; + if (lbl == "SG264") return 264.118931 ; + if (lbl == "SG265") return 265.1211147 ; + if (lbl == "SG266") return 266.122065 ; + if (lbl == "SG267") return 267.124425 ; + if (lbl == "SG268") return 268.125606 ; + if (lbl == "SG269") return 269.128755 ; + if (lbl == "SG270") return 270.130329 ; + if (lbl == "SG271") return 271.133472 ; + if (lbl == "SG272") return 272.135158 ; + if (lbl == "SG273") return 273.13822 ; + if (lbl == "BH") return 262.122892 ; + if (lbl == "BH260") return 260.12197 ; + if (lbl == "BH261") return 261.121664 ; + if (lbl == "BH262") return 262.122892 ; + if (lbl == "BH263") return 263.123035 ; + if (lbl == "BH264") return 264.124604 ; + if (lbl == "BH265") return 265.125147 ; + if (lbl == "BH266") return 266.126942 ; + if (lbl == "BH267") return 267.12765 ; + if (lbl == "BH268") return 268.129755 ; + if (lbl == "BH269") return 269.130694 ; + if (lbl == "BH270") return 270.133616 ; + if (lbl == "BH271") return 271.135179 ; + if (lbl == "BH272") return 272.138032 ; + if (lbl == "BH273") return 273.139618 ; + if (lbl == "BH274") return 274.14244 ; + if (lbl == "BH275") return 275.14425 ; + if (lbl == "HS") return 263.128558 ; + if (lbl == "HS263") return 263.128558 ; + if (lbl == "HS264") return 264.1283949 ; + if (lbl == "HS265") return 265.130085 ; + if (lbl == "HS266") return 266.130097 ; + if (lbl == "HS267") return 267.131789 ; + if (lbl == "HS268") return 268.132162 ; + if (lbl == "HS269") return 269.134056 ; + if (lbl == "HS270") return 270.13465 ; + if (lbl == "HS271") return 271.137657 ; + if (lbl == "HS272") return 272.139052 ; + if (lbl == "HS273") return 273.141986 ; + if (lbl == "HS274") return 274.143131 ; + if (lbl == "HS275") return 275.145952 ; + if (lbl == "HS276") return 276.147208 ; + if (lbl == "HS277") return 277.149841 ; + if (lbl == "MT") return 265.136151 ; + if (lbl == "MT265") return 265.136151 ; + if (lbl == "MT266") return 266.137299 ; + if (lbl == "MT267") return 267.137307 ; + if (lbl == "MT268") return 268.138728 ; + if (lbl == "MT269") return 269.139055 ; + if (lbl == "MT270") return 270.140657 ; + if (lbl == "MT271") return 271.141139 ; + if (lbl == "MT272") return 272.143738 ; + if (lbl == "MT273") return 273.144913 ; + if (lbl == "MT274") return 274.147492 ; + if (lbl == "MT275") return 275.148647 ; + if (lbl == "MT276") return 276.151156 ; + if (lbl == "MT277") return 277.15242 ; + if (lbl == "MT278") return 278.154812 ; + if (lbl == "MT279") return 279.156193 ; + if (lbl == "DS") return 281.162061 ; + if (lbl == "DS267") return 267.144341 ; + if (lbl == "DS268") return 268.143795 ; + if (lbl == "DS269") return 269.145124 ; + if (lbl == "DS270") return 270.14472 ; + if (lbl == "DS271") return 271.146062 ; + if (lbl == "DS272") return 272.146317 ; + if (lbl == "DS273") return 273.148863 ; + if (lbl == "DS274") return 274.149492 ; + if (lbl == "DS275") return 275.152176 ; + if (lbl == "DS276") return 276.153034 ; + if (lbl == "DS277") return 277.155647 ; + if (lbl == "DS278") return 278.156469 ; + if (lbl == "DS279") return 279.158861 ; + if (lbl == "DS280") return 280.159795 ; + if (lbl == "DS281") return 281.162061 ; + if (lbl == "RG") return 272.153615 ; + if (lbl == "RG272") return 272.153615 ; + if (lbl == "RG273") return 273.153682 ; + if (lbl == "RG274") return 274.155713 ; + if (lbl == "RG275") return 275.156142 ; + if (lbl == "RG276") return 276.158493 ; + if (lbl == "RG277") return 277.159519 ; + if (lbl == "RG278") return 278.161604 ; + if (lbl == "RG279") return 279.162468 ; + if (lbl == "RG280") return 280.164473 ; + if (lbl == "RG281") return 281.165372 ; + if (lbl == "RG282") return 282.167486 ; + if (lbl == "RG283") return 283.168415 ; + if (lbl == "UUB") return 283.171792 ; + if (lbl == "UUB277") return 277.163943 ; + if (lbl == "UUB278") return 278.164312 ; + if (lbl == "UUB279") return 279.166546 ; + if (lbl == "UUB280") return 280.167039 ; + if (lbl == "UUB281") return 281.169286 ; + if (lbl == "UUB282") return 282.169765 ; + if (lbl == "UUB283") return 283.171792 ; + if (lbl == "UUB284") return 284.172384 ; + if (lbl == "UUB285") return 285.174105 ; + if (lbl == "UUT") return 283.176451 ; + if (lbl == "UUT283") return 283.176451 ; + if (lbl == "UUT284") return 284.17808 ; + if (lbl == "UUT285") return 285.178732 ; + if (lbl == "UUT286") return 286.180481 ; + if (lbl == "UUT287") return 287.181045 ; + if (lbl == "UUQ") return 285.183698 ; + if (lbl == "UUQ285") return 285.183698 ; + if (lbl == "UUQ286") return 286.183855 ; + if (lbl == "UUQ287") return 287.185599 ; + if (lbl == "UUQ288") return 288.185689 ; + if (lbl == "UUQ289") return 289.187279 ; + if (lbl == "UUP") return 287.191186 ; + if (lbl == "UUP287") return 287.191186 ; + if (lbl == "UUP288") return 288.192492 ; + if (lbl == "UUP289") return 289.192715 ; + if (lbl == "UUP290") return 290.194141 ; + if (lbl == "UUP291") return 291.194384 ; + if (lbl == "UUH") return 292.199786 ; + if (lbl == "UUH289") return 289.198862 ; + if (lbl == "UUH290") return 290.19859 ; + if (lbl == "UUH291") return 291.200011 ; + if (lbl == "UUH292") return 292.199786 ; + if (lbl == "UUS") return 291.206564 ; + if (lbl == "UUS291") return 291.206564 ; + if (lbl == "UUS292") return 292.207549 ; + if (lbl == "UUO") return 293.21467 ; + if (lbl == "UUO293") return 293.21467 ; + return 0; +} + +} + + diff --git a/optking/atom_data.h b/optking/atom_data.h new file mode 100644 index 0000000..0ffc760 --- /dev/null +++ b/optking/atom_data.h @@ -0,0 +1,30 @@ +/*! \file element_to_Z.h + \ingroup optking + \brief convert element name or symbol to atomic number +*/ + +#ifndef _element_to_Z_h_ +#define _element_to_Z_h_ + +#include +#include +#include + +namespace opt { + +// atomic number to the atomic symbol +extern const char *Z_to_symbol[]; + +// atomic number to default mass +extern const double Z_to_mass[]; + +// convert symbol or name to atomic number +extern double Element_to_Z(std::string lbl); + +// convert isotope name to mass +extern double Isotope_to_mass(std::string lbl); + +} + +#endif + diff --git a/optking/bend.cpp b/optking/bend.cpp new file mode 100644 index 0000000..cde81fc --- /dev/null +++ b/optking/bend.cpp @@ -0,0 +1,304 @@ +/*! \file bend.cc : Class for bending coordinate. + \ingroup OPTKING +*/ + +#include "bend.h" + +#include +#include "v3d.h" +#include "physconst.h" +#include +//#include "linear_algebra.h" + +#include "print.h" +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace v3d; +using namespace std; + +// constructor - makes sure AA + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[2]], v); // B->C + v3d_normalize(u); // eBA + v3d_normalize(v); // eBC + + // determine w' vector + if (!v3d_is_parallel(u,v)) + v3d_cross_product(u,v,w); + else { + tvect[0] = 1; tvect[1] = -1; tvect[2] = 1; + if (!v3d_is_parallel(u,tvect) && !v3d_is_parallel(v,tvect)) + v3d_cross_product(u,tvect,w); + else { + tvect[0] = -1; tvect[1] = 1; tvect[2] = 1; + v3d_cross_product(u,tvect,w); + } + } + v3d_normalize(w); + + double *origin = init_array(3); + // linear complement is sum of 2 angles, u.w + w.v + if (!v3d_angle(u, origin, w, phi)) + throw(INTCO_EXCEPT("BEND::value: could not compute linear bend",true)); + + if (!v3d_angle(w, origin, v, tval)) + throw(INTCO_EXCEPT("BEND::value: could not compute linear bend",true)); + phi += tval; + } + return phi; +} + +inline int zeta(const int a, const int m, const int n) { + if (a == m) return 1; + else if (a == n) return -1; + else return 0; +} + +inline int delta(const int i, const int j) { + if (i == j) return 1; + else return 0; +} + +double ** BEND::DqDx(GeomType geom) const { + double u[3], v[3], w[3]; + double tvect[3]; + double **dqdx = init_matrix(3,3); + + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[0]], u); // B->A + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[2]], v); // B->C + double Lu = v3d_norm(u); // RBA + double Lv = v3d_norm(v); // RBC + v3d_scm(1.0/Lu, u); // eBA + v3d_scm(1.0/Lv, v); // eBC + + // determine w vector + if (!v3d_is_parallel(u,v)) { + if (linear_bend) { // use (-1)*(angle bisector of u and v) for perpendicular w vector + v3d_axpy(1.0, geom[s_atom[0]], geom[s_atom[2]], tvect); + v3d_scm(0.5, tvect); + v3d_eAB(tvect, geom[s_atom[1]], w); + } + else + v3d_cross_product(u,v,w); // use w = uXv + } + else { // 0-1-2 is linear ; arbitrarily choose a direction + tvect[0] = 1; tvect[1] = -1; tvect[2] = 1; + if (!v3d_is_parallel(u,tvect) && !v3d_is_parallel(v,tvect)) { + v3d_cross_product(u,tvect,w); + } + else { + tvect[0] = -1; tvect[1] = 1; tvect[2] = 1; + v3d_cross_product(u,tvect,w); + } + if (linear_bend) { // use the complement vector w = w x u + v3d_cross_product(w,u,tvect); + array_copy(tvect, w, 3); + } + } + v3d_normalize(w); + + double uXw[3],wXv[3]; + v3d_cross_product(u, w, uXw); + v3d_cross_product(w, v, wXv); + + for (int a=0; a<3; ++a) + for (int i=0; i<3; ++i) + dqdx[a][i] = zeta(a,0,1)*uXw[i]/Lu + zeta(a,2,1)*wXv[i]/Lv; + + return dqdx; +} + +double ** BEND::Dq2Dx2(GeomType geom) const { + double u[3], v[3], w[3]; + double tvect[3]; + double **dq2dx2 = init_matrix(9,9); + + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[0]], u); // B->A + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[2]], v); // B->C + double Lu = v3d_norm(u); // RBA + double Lv = v3d_norm(v); // RBC + v3d_scm(1.0/Lu, u); // eBA + v3d_scm(1.0/Lv, v); // eBC + + // determine w' vector + if (!v3d_is_parallel(u,v)) { + if (linear_bend) { // use (-1)*(angle bisector of u and v) for perpendicular w vector + v3d_axpy(1.0, geom[s_atom[0]], geom[s_atom[2]], tvect); + v3d_scm(0.5, tvect); + v3d_eAB(tvect, geom[s_atom[1]], w); + } + else + v3d_cross_product(u,v,w); // use w = uXv + } + else { // 0-1-2 is linear ; arbitrarily choose a direction + tvect[0] = 1; tvect[1] = -1; tvect[2] = 1; + if (!v3d_is_parallel(u,tvect) && !v3d_is_parallel(v,tvect)) + v3d_cross_product(u,tvect,w); + else { + tvect[0] = -1; tvect[1] = 1; tvect[2] = 1; + v3d_cross_product(u,tvect,w); + } + if (linear_bend) { // use the complement vector w = w x u + v3d_cross_product(w,u,tvect); + array_copy(tvect, w, 3); + } + } + v3d_normalize(w); + + // compute first derivatives + double uXw[3],wXv[3]; + v3d_cross_product(u, w, uXw); + v3d_cross_product(w, v, wXv); + + double **dqdx = init_matrix(3,3); + for (int a=0; a<3; ++a) + for (int i=0; i<3; ++i) + dqdx[a][i] = zeta(a,0,1)*uXw[i]/Lu + zeta(a,2,1)*wXv[i]/Lv; + + double cos_q = v3d_dot(u,v); + if (1.0-cos_q*cos_q <= 1.0e-12) return dqdx; // leave 2nd derivatives empty - sin 0 = 0 in denominator + double sin_q = sqrt(1.0 - cos_q*cos_q); + + double tval; + for (int a=0; a<3; ++a) + for (int i=0; i<3; ++i) //i = a_xyz + for (int b=0; b<3; ++b) + for (int j=0; j<3; ++j) { //j=b_xyz + tval = zeta(a,0,1)*zeta(b,0,1)*(u[i]*v[j]+u[j]*v[i]-3*u[i]*u[j]*cos_q+delta(i,j)*cos_q) / (Lu*Lu*sin_q); + + tval +=zeta(a,2,1)*zeta(b,2,1)*(v[i]*u[j]+v[j]*u[i]-3*v[i]*v[j]*cos_q+delta(i,j)*cos_q) / (Lv*Lv*sin_q); + + tval +=zeta(a,0,1)*zeta(b,2,1)*(u[i]*u[j]+v[j]*v[i]-u[i]*v[j]*cos_q-delta(i,j)) / (Lu*Lv*sin_q); + + tval +=zeta(a,2,1)*zeta(b,0,1)*(v[i]*v[j]+u[j]*u[i]-v[i]*u[j]*cos_q-delta(i,j)) / (Lu*Lv*sin_q); + + tval -= cos_q / sin_q * dqdx[a][i] * dqdx[b][j]; + + dq2dx2[3*a+i][3*b+j] = tval; + } + + free_matrix(dqdx); + + return dq2dx2; +} + + +void BEND::print(FILE *fp, GeomType geom, int off) const { + ostringstream iss(ostringstream::out); // create stream; allow output to it + + if (linear_bend) + iss << "L("; + else + iss << "B("; + + iss << s_atom[0]+1+off << "," << s_atom[1]+1+off << "," << s_atom[2]+1+off << ")" << flush ; + + double val = value(geom); + if (!s_frozen) + fprintf(fp,"\t %-15s = %15.6lf\t%15.6lf\n", iss.str().c_str(), val, val/_pi*180.0); + else + fprintf(fp,"\t*%-15s = %15.6lf\t%15.6lf\n", iss.str().c_str(), val, val/_pi*180.0); + fflush(fp); +} + +void BEND::print_disp(FILE *fp, const double q_old, const double f_q, + const double dq, const double q_new, int atom_offset) const { + ostringstream iss(ostringstream::out); // create stream; allow output to it + if (s_frozen) iss << "*"; + + if (linear_bend) + iss << "L("; + else + iss << "B("; + + iss << s_atom[0]+atom_offset+1 << "," << s_atom[1]+atom_offset+1 << "," << s_atom[2]+atom_offset+1 << ")" << flush ; + + fprintf(fp,"\t %-15s = %13.6lf%13.6lf%13.6lf%13.6lf\n", + iss.str().c_str(), q_old/_pi*180.0, f_q*_hartree2aJ*_pi/180.0, + dq/_pi*180.0, q_new/_pi*180.0); + fflush(fp); +} + +void BEND::print_intco_dat(FILE *fp, int off) const { + if (linear_bend) { + if (s_frozen) + fprintf(fp, "L*%6d%6d%6d\n", s_atom[0]+1+off, s_atom[1]+1+off, s_atom[2]+1+off); + else + fprintf(fp, "L %6d%6d%6d\n", s_atom[0]+1+off, s_atom[1]+1+off, s_atom[2]+1+off); + } + else { + if (s_frozen) + fprintf(fp, "B*%6d%6d%6d\n", s_atom[0]+1+off, s_atom[1]+1+off, s_atom[2]+1+off); + else + fprintf(fp, "B %6d%6d%6d\n", s_atom[0]+1+off, s_atom[1]+1+off, s_atom[2]+1+off); + } + fflush(fp); +} + +void BEND::print_s(FILE *fp, GeomType geom) const { + + if (linear_bend) + fprintf(fp,"S vector for bend, L(%d %d %d): \n", s_atom[0]+1, s_atom[1]+1, s_atom[2]+1); + else + fprintf(fp,"S vector for bend, B(%d %d %d): \n", s_atom[0]+1, s_atom[1]+1, s_atom[2]+1); + + double **dqdx = DqDx(geom); + fprintf(fp, "Atom 1: %12.8f %12.8f,%12.8f\n", dqdx[0][0], dqdx[0][1], dqdx[0][2]); + fprintf(fp, "Atom 2: %12.8f %12.8f,%12.8f\n", dqdx[1][0], dqdx[1][1], dqdx[1][2]); + fprintf(fp, "Atom 3: %12.8f %12.8f,%12.8f\n", dqdx[2][0], dqdx[2][1], dqdx[2][2]); + free_matrix(dqdx); + fflush(fp); +} + +bool BEND::operator==(const SIMPLE & s2) const { + if (bend_type != s2.g_type()) + return false; + + if (this->s_atom[1] != s2.g_atom(1)) + return false; + + if (this->is_linear_bend() != s2.is_linear_bend()) + return false; + + if (this->s_atom[0] == s2.g_atom(0) && this->s_atom[2] == s2.g_atom(2)) + return true; + else if (this->s_atom[0] == s2.g_atom(2) && this->s_atom[2] == s2.g_atom(0)) + return true; + else + return false; +} + +} + diff --git a/optking/bend.h b/optking/bend.h new file mode 100644 index 0000000..762c530 --- /dev/null +++ b/optking/bend.h @@ -0,0 +1,47 @@ +/*! \file bend.h + \ingroup OPTKING + \brief BEND class declaration +*/ + +#ifndef _opt_bend_h_ +#define _opt_bend_h_ + +#include "simple.h" + +namespace opt { + +class BEND : public SIMPLE { + + // if true, this bend is a secondary complement to another linear bend + bool linear_bend; + + public: + + BEND(int A_in, int B_in, int C_in, bool freeze_in=false); + + ~BEND() { } // also calls ~SIMPLE() + + double value(GeomType geom) const; + + // compute and return array of first derivative (B marix elements) + double **DqDx(GeomType geom) const; + + // compute and return array of second derivative (B' matrix elements) + double **Dq2Dx2(GeomType geom) const; + + void print(FILE *fp, GeomType geom, int atom_offset=0) const; + void print_intco_dat(FILE *fp, int atom_offset=0) const; + void print_s(FILE *fp, GeomType geom) const; + void print_disp(FILE *fp, const double old_q, const double f_q, + const double dq, const double new_q, int atom_offset=0) const; + bool operator==(const SIMPLE & s2) const; + + void make_linear_bend(void) { linear_bend = true; } + bool is_linear_bend(void) const { return linear_bend; } + +}; + +} + +#endif + diff --git a/optking/cov_radii.h b/optking/cov_radii.h new file mode 100644 index 0000000..8f75e6d --- /dev/null +++ b/optking/cov_radii.h @@ -0,0 +1,121 @@ +/*! + \file cov_radii.h : covalent radii + \ingroup optking +*/ + +/* +* This header file contains the covalent radii of the atoms in Angstroms from: +* "Covalent radii revisited", Dalton Trans., 2008, 2832, by +* B. Cordero, V. Gómez, A. E. Platero-Prats, M. Revés, J. Echeverría, +* E. Cremades, F. Barragán and S. Alvarez +* +* The largest values have been chosen for C (sp3) and for +* Mn, Fe, and Co (high-spin). +* - RAK, May 2008 +*/ + +#ifndef _cov_radii_h_ +#define _cov_radii_h_ + +#define LAST_COV_RADII_INDEX 96 + +const double cov_radii[] = { 2.0, /* ghost ? */ +0.31, //H +0.28, //He +1.28, //Li +0.96, //Be +0.84, //B +0.76, //C +0.71, //N +0.66, //O +0.57, //F +0.58, //Ne +1.66, //Na +1.41, //Mg +1.21, //Al +1.11, //Si +1.07, //P +1.05, //S +1.02, //Cl +1.06, //Ar +2.03, //K +1.76, //Ca +1.70, //Sc +1.60, //Ti +1.53, //V +1.39, //Cr +1.61, //Mn +1.52, //Fe +1.50, //Co +1.24, //Ni +1.32, //Cu +1.22, //Zn +1.22, //Ga +1.20, //Ge +1.19, //As +1.20, //Se +1.20, //Br +1.16, //Kr +2.20, //Rb +1.95, //Sr +1.90, //Y +1.75, //Zr +1.64, //Nb +1.54, //Mo +1.47, //Tc +1.46, //Ru +1.42, //Rh +1.39, //Pd +1.45, //Ag +1.44, //Cd +1.42, //In +1.39, //Sn +1.39, //Sb +1.38, //Te +1.39, //I +1.40, //Xe +2.44, //Cs +2.15, //Ba +2.07, //La +2.04, //Ce +2.03, //Pr +2.01, //Nd +1.99, //Pm +1.98, //Sm +1.98, //Eu +1.96, //Gd +1.94, //Tb +1.92, //Dy +1.92, //Ho +1.89, //Er +1.90, //Tm +1.87, //Yb +1.87, //Lu +1.75, //Hf +1.70, //Ta +1.62, //W +1.51, //Re +1.44, //Os +1.41, //Ir +1.36, //Pt +1.36, //Au +1.32, //Hg +1.45, //Tl +1.46, //Pb +1.48, //Bi +1.40, //Po +1.50, //At +1.50, //Rn +2.60, //Fr +2.21, //Ra +2.15, //Ac +2.06, //Th +2.00, //Pa +1.96, //U +1.90, //Np +1.87, //Pu +1.80, //Am +1.69 //Cm +}; + +#endif /* header guard */ diff --git a/optking/efp_frag.C b/optking/efp_frag.C new file mode 100644 index 0000000..b76afb8 --- /dev/null +++ b/optking/efp_frag.C @@ -0,0 +1,66 @@ +/*! + \ingroup optking +*/ + +#include "efp_frag.h" + +#define EXTERN +#include "globals.h" + +#if defined (OPTKING_PACKAGE_QCHEM) + +#include "EFP.h" // QChem's header for calling displace function +namespace opt { + +void EFP_FRAG::set_values(double * values_in) { + for (int i=0; i<6; ++i) + values[i] = values_in[i]; +} + +void EFP_FRAG::set_forces(double * forces_in) { + for (int i=0; i<6; ++i) + forces[i] = forces_in[i]; +} + +// we don't have a valid B matrix for these +// add 6 bogus stretches +void EFP_FRAG::add_dummy_intcos(int ndummy) { + STRE *one_stre; + for (int i=0; idisplace(efp_frag_index, dq); +} + +} + +#endif + diff --git a/optking/efp_frag.h b/optking/efp_frag.h new file mode 100644 index 0000000..6994cc1 --- /dev/null +++ b/optking/efp_frag.h @@ -0,0 +1,79 @@ +#ifndef _opt_efp_frag_h_ +#define _opt_efp_frag_h_ + +/* This class will define a fragment for use in situations where a fragment +is defined by space-fixed coordinates: 3 center-of-mass and 3 Euler angle +coordinates. + +This class is intended to be used for fixed-body EFP optimizations in QChem. +In QChem, the gradient is already computed in these space-fixed coordinates. +Thus, it is not necessary to write the code for the B-matrix to do an +optimization. Eventually, a B-matrix will be necessary in order to, for +example, transform a cartesian analytic Hessian into internal coordinates for +these optimizations. + +Since the angular coodinates are be described as linear combinations of positions of +atoms, a new type of B-matrix will be necessary. We might be able to use +the principle axes to define the coordinates (derived by WDA), but we would +still have to relate these to the space-fixed coordinates of the gradient +computed by QChem. +*/ + +#include "package.h" + +#if defined(OPTKING_PACKAGE_QCHEM) + +#include "frag.h" +#include "mem.h" + +namespace opt { + +class EFP_FRAG : public FRAG { + + // values and forces are provided by QChem, not computed by optking + // they will be of dimension 6 + double *values; + double *forces; + + public: + // we will build a dummy fragment with no atoms + EFP_FRAG() : FRAG(0) { + values = init_array(6); + forces = init_array(6); + // Add 6 intcos just to act as placeholders. + // We read external forces and don't compute B matrix for these. + add_dummy_intcos(6); + } + + ~EFP_FRAG() { + free_array(values); + free_array(forces); + } + + void set_values(double * values_in); + void set_forces(double * forces_in); + + double * get_values_pointer(void) const { return values; } + double * get_forces_pointer(void) const { return forces; } + + // we don't have a valid B matrix for these + // add 6 bogus stretches + void add_dummy_intcos(int ndummy); + +// We will assign a value of 0 to these on the first iteration; subsequently, the +// values will be calculated as total Delta(q) from the start of the optimization + void print_intcos(FILE *fp); + + double **H_guess(void); + + // Tell QChem to update rotation matrix and com for EFP fragment + void displace (int efp_frag_index, double *dq); + +}; + +} + +#endif + +#endif + diff --git a/optking/frag.cpp b/optking/frag.cpp new file mode 100644 index 0000000..9902188 --- /dev/null +++ b/optking/frag.cpp @@ -0,0 +1,720 @@ +/*! + \file frag.cc + \ingroup optking + \brief fragment (molecule) class +*/ + +#include "frag.h" + +#include "cmath" +//#include "qcmath.h" + +#include "mem.h" +#include "v3d.h" +#include "atom_data.h" +#include "cov_radii.h" +#include "print.h" +#include "opt_data.h" +#include "physconst.h" +#include "linear_algebra.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace v3d; + +// Memory for Z and geom is provided by calling function +FRAG::FRAG(int natom_in, double *Z_in, double **geom_in) { + natom = natom_in; + Z = Z_in; + geom = geom_in; + + frozen = false; + + grad = init_matrix(natom,3); + connectivity = init_bool_matrix(natom,natom); + mass = init_array(natom); + globalIndex = init_int_array(natom); + //cout << "DES: init frag" << endl; + for(int i=0; i< natom; i++) { + globalIndex[i]=i; + } +} + +FRAG::FRAG(int natom_in) { + natom = natom_in; + + frozen = false; + + Z = init_array(natom); + geom = init_matrix(natom,3); + grad = init_matrix(natom,3); + connectivity = init_bool_matrix(natom,natom); + mass = init_array(natom); + globalIndex = init_int_array(natom); + for(int i=0; i< natom; i++) { + globalIndex[i]=i; + } +} + +FRAG::~FRAG() { + free_array(Z); + free_matrix(geom); + free_matrix(grad); + free_array(mass); + free_int_array(globalIndex); + free_bool_matrix(connectivity); + for (int i=0; iprint(fp,geom,atom_offset); + fprintf(fp, "\n"); + fflush(fp); +} + +void FRAG::print_intco_dat(FILE *fp, int atom_offset) { + //fprintf(fp,"\t---Fragment %d Intrafragment Coordinates---\n", id+1); +// for (int i=0; iprint_intco_dat(fp,atom_offset); + for (int i=0; iprint_intco_dat(fp,atom_offset); + } +} + +// automatically determine bond connectivity by comparison of interatomic distance +//with scale_connectivity * sum of covalent radii +void FRAG::update_connectivity_by_distances(void) { + int i, j, *Zint; + double Rij; + double scale = Opt_params.scale_connectivity; + + Zint = new int [natom]; + for (i=0; i LAST_COV_RADII_INDEX ) + throw(INTCO_EXCEPT("Warning: cannot automatically bond atom with strange atomic number")); + } + + for (i=0; ig_type() == stre_type) { + int a = intcos.at(i)->g_atom(0); + int b = intcos.at(i)->g_atom(1); + connectivity[a][b] = connectivity[b][a] = true; + } + } +} + +void FRAG::print_connectivity(FILE *fp, const int id, const int offset) const { + fprintf(fp,"\t---Fragment %d Bond Connectivity---\n", id+1); + int i,j; +// for (i=0; i pi/2) { + STRE *one_stre = new STRE(h,y); + one_stre->make_hbond(); + if (!present(one_stre)) { + intcos.push_back(one_stre); + ++nadded; + } + else delete one_stre; + } + } + } + } + } + } + } + } + } + return nadded; +} + +// angles for all bonds present; return number added +int FRAG::add_bend_by_connectivity(void) { + int nadded = 0; + double phi; + + for (int i=0; i Opt_params.linear_bend_threshold) { // ~175 degrees + one_bend = new BEND(i,j,k); + one_bend->make_linear_bend(); + if (!present(one_bend)) { + intcos.push_back(one_bend); + ++nadded; + } + else + delete one_bend; + } + } + } // ijk + + return nadded; +} + +// torsions for all bonds present; return number added +int FRAG::add_tors_by_connectivity(void) { + int nadded = 0; + int i,j,k,l; + double phi; + double const pi = acos(-1.0); + + // bonding i-j-k-l but i-j-k && j-k-l are not collinear + for (i=0; ivalue(geom); + return q; +} + +// returns values of internal coordinates - using given geometry +double * FRAG::intco_values(GeomType new_geom) const { + double * q = init_array(intcos.size()); + for (int i=0; ivalue(new_geom); + return q; +} + +// returns B' matrix for one internal coordinate +double ** FRAG::compute_derivative_B(int intco_index) const { + return compute_derivative_B(intco_index,geom); +} + +// returns B' matrix for one internal coordinate computed with given geometry +double ** FRAG::compute_derivative_B(int intco_index, GeomType new_geom) const { + double **frag_dq2dx2 = intcos.at(intco_index)->Dq2Dx2(new_geom); + return frag_dq2dx2; +} + +// returns B matrix of internal coordinates +double ** FRAG::compute_B(void) const { + double **Bintco; + double **B = init_matrix(intcos.size(), 3*natom); + + for (int i=0; iDqDx(geom); + + for (int j=0; j < intcos.at(i)->g_natom(); ++j) + for (int xyz=0; xyz<3; ++xyz) + B[i][3*intcos.at(i)->g_atom(j) + xyz] = Bintco[j][xyz]; + + free_matrix(Bintco); + } + return B; +} + +// returns matrix of constraints (for now, 1's on diagonals to be frozen) +double ** FRAG::compute_constraints(void) const { + double **C = init_matrix(intcos.size(), intcos.size()); + + for (int i=0; iis_frozen()) + C[i][i] = 1.0; + + return C; +} + + +// returns B matrix of internal coordinates; use previously allocated memory +void FRAG::compute_B(double **B) const { + double **Bintco; + + for (int i=0; iDqDx(geom); + + for (int j=0; j < intcos.at(i)->g_natom(); ++j) + for (int xyz=0; xyz<3; ++xyz) + B[i][3*intcos.at(i)->g_atom(j) + xyz] = Bintco[j][xyz]; + + free_matrix(Bintco); + } + return; +} + + +// computes and print B matrix +void FRAG::print_B(FILE *fp) const { + double **B = compute_B(); + fprintf(fp,"\t---B matrix---\n"); + print_matrix(fp, B, intcos.size(), 3*natom); + fprintf(fp,"\n"); + fflush(fp); + free_matrix(B); +} + +void FRAG::fix_tors_near_180(void) { + for (int i=0; ig_type() == tors_type) + intcos[i]->fix_tors_near_180(geom); + } +} + +void FRAG::set_geom_array(double * geom_array_in) { + int xyz, i; + for (i=0; ig_type() == bend_type) { + if (intcos[i]->value(geom) + dq[cnt++] < 0.0) + throw(INTCO_EXCEPT("Bond angle passing through zero", true)); + } + } +} + +bool ** FRAG::g_connectivity(void) const { + bool **c = init_bool_matrix(natom, natom); + for (int i=0; i 1.0e-14) { + cout << "DES: I_evals = " << I_evals[i] << endl; + evals[cnt] = I_evals[i]; + axes[cnt][0] = I[i][0]; + axes[cnt][1] = I[i][1]; + axes[cnt][2] = I[i][2]; + ++cnt; + } + } + free_array(I_evals); + free_matrix(I); + return cnt; +} + +/* +// calling program must allocate axes(3,3) and evals(3) +// evals returned in ascending order (descending rotational constants), but zeroes are removed +// from evals and evects; +// axes are rows ; +// return number of principal axes +// may have to order degenerate evals later +int FRAG::principal_axes(GeomType in_geom, double **axes, double *evals) { + + double **I = inertia_tensor(in_geom); + double *I_evals = init_array(3); + opt_symm_matrix_eig(I, 3, I_evals); + + int cnt = 0; + for (int i=0; i<3; ++i) { + if (fabs(I_evals[i]) > 1.0e-14) { + evals[cnt] = I_evals[i]; + axes[cnt][0] = I[i][0]; + axes[cnt][1] = I[i][1]; + axes[cnt][2] = I[i][2]; + ++cnt; + } + } + return cnt; +} +*/ + +} + diff --git a/optking/frag.h b/optking/frag.h new file mode 100644 index 0000000..2a3fb04 --- /dev/null +++ b/optking/frag.h @@ -0,0 +1,200 @@ +/*! + \ingroup optking + \file frag.h : header for fragment class +*/ +#ifndef _opt_frag_h_ +#define _opt_frag_h_ + +#include +#include +#include + +#include "intcos.h" + +namespace opt { + +class INTERFRAG; + +using std::vector; + +/*! + \ingroup optking + \class FRAG + \brief A group of atoms, its geometry, and its internal coordinates. + */ +class FRAG { + + protected: // private, except the efp derived class can access + int natom; //< number of atoms in fragment + double *Z; //< atomic numbers + double **geom; //< cartesian coordinates + double **grad; //< cartesian coordinates + //double *mass; //< nuclear masses + //bool **connectivity; //< connectivity matrix + vector intcos; + bool frozen; //< whether to optimize + + public: + bool **connectivity; //< connectivity matrix + double *mass; //< nuclear masses + int *globalIndex; + friend class INTERFRAG; + + /** Constructor to create fragment. + + There is one constructor to insert the atoms, and a different constructor available + just to allocate the memory. + \param natom_in number of atoms. + \param Z_in atomic charges + \param geom_in Cartesian coordinates (natom_in x 3) + */ + FRAG(int natom_in, double *Z_in, double **geom_in); // use if Z and geom are known + FRAG(int natom_in); + + ~FRAG(); // free memory + + /** Description + \returns number of atoms. + */ + int g_natom(void) const { return natom; }; + + void set_default_masses(void); + + void print_geom(FILE *fp, const int id, bool print_mass = false); + void print_geom_grad(FILE *fp, const int id, bool print_mass = false); + void print_intcos(FILE *fp, int atom_offset=0); + void print_intco_dat(FILE *fp, int atom_offset=0); + + void update_connectivity_by_distances(void); + void update_connectivity_by_bonds(void); + + void print_connectivity(FILE *fout, const int id, const int offset = 0) const ; + + // add simple internals based on connectivity; return number added + int add_stre_by_connectivity(void); + int add_bend_by_connectivity(void); + int add_tors_by_connectivity(void); + + int add_simples_by_connectivity(void) { + int n; + n = add_stre_by_connectivity(); + n += add_bend_by_connectivity(); + n += add_tors_by_connectivity(); // but check bond angles + return n; + } + + // add connectivity between two atoms; atom numbers are for fragment + void connect(int i, int j) { + connectivity[i][j] = connectivity[j][i] = true; + } + + // compute B matrix (intcos.size x 3*natom) + double ** compute_B(void) const ; + void compute_B(double **) const ; // use prevously allocated memory + + // compute B' matrix for one internal coordinate computed with member geometry + double ** compute_derivative_B(int intco_index) const; + + // compute B' matrix for one internal coordinate computed with given geometry + double ** compute_derivative_B(int intco_index, GeomType new_geom) const; + + // compute and print B matrix (for debugging) + void print_B(FILE *fp) const ; + + // check nearness to 180 and save value + void fix_tors_near_180(void); + + // return number of intrafragment coordinates + int g_nintco(void) const { return intcos.size(); }; + + // return natom in definition of intco # intco_index + int g_intco_natom(const int intco_index) const { + return intcos.at(intco_index)->g_natom(); + } + + // return atom i in definition of intco # intco_index + int g_intco_atom(const int intco_index, const int atom) const { + return intcos.at(intco_index)->g_atom(atom); + } + + // return array of atomic numbers + double *g_Z(void) const; + double *g_Z_pointer(void) { return Z; } + + // don't let angles pass through 0 + void check_zero_angles(double const * const dq); + + //print s vectors to output file + void print_s(FILE *fp, const double ** const geom) const { + fprintf(fp,"\t---S vectors for internals---\n"); + for(int i=0; iprint_s(fp, geom); + fflush(fp); + } + + // compute and return values of internal coordinates from member geometry + double * intco_values(void) const ; + + // compute and return values of internal coordinates from given geometry + double * intco_values(GeomType new_geom) const ; + + // is simple one already present? + bool present(const SIMPLE *one) const; + + int find(const SIMPLE *one) const; + + void displace(double *dq, bool print_disp = false, int atom_offset=0); + + double ** g_geom_pointer(void) { return geom; }; // returns pointer + double ** g_geom(void) const; // returns a copy + GeomType g_geom_const_pointer(void) const { return geom;}; // returns const pointer + + double ** g_grad(void); + double ** g_grad_pointer(void) {return grad;}; + + double * g_geom_array(void); + double * g_grad_array(void); + void set_geom_array(double * geom_array_in); + void set_geom(double ** geom_in); + void set_grad(double **grad_in); + + void print_geom(FILE *fp_geom); // write cartesian geometry out for next step + + double ** H_guess(void); + bool **g_connectivity(void) const; + const bool * const * g_connectivity_pointer(void) const; + + bool read_intco(std::vector & tokens, int first_atom_offset); + + // return matrix of constraints on coordinates + double ** compute_constraints(void) const; + + // add any missing hydrogen bonds within the fragment + // return number added + int add_hbonds(void); + + void intco_add(SIMPLE * i) { + intcos.push_back(i); + } + + // relating to frozen fragments + bool is_frozen(void) const { return frozen; } + void freeze(void) { frozen = true; } + void unfreeze(void) { frozen = false; } + + double **inertia_tensor (GeomType in_geom); + double *com(GeomType in_geom); + double **inertia_tensor(void) { return (inertia_tensor(geom)); } + double *com(void) { return (com(geom)); } + + int principal_axes(GeomType geom, double **axes, double *evals); + int principal_axes(double **axes, double *evals) { + return (principal_axes(geom, axes, evals)); + } + +}; + +} + +#endif + diff --git a/optking/frag_H_guess.cpp b/optking/frag_H_guess.cpp new file mode 100644 index 0000000..355d006 --- /dev/null +++ b/optking/frag_H_guess.cpp @@ -0,0 +1,168 @@ +/*! \file H_guess.cc + \ingroup optking + \brief generates empirical Hessian according to + Schlegel, Theor. Chim. Acta, 66, 333 (1984) or + Fischer and Almlof, J. Phys. Chem., 96, 9770 (1992). + currently returned in atomic units +*/ + +#include "frag.h" +#include "cov_radii.h" +#include "physconst.h" +//#include "qcmath.h" +#include "cmath" +#include "v3d.h" +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace v3d; + +// covalent bond length in bohr from atomic numbers +inline double Rcov(double ZA, double ZB) { + return (cov_radii[(int) ZA] + cov_radii[(int) ZB]) / _bohr2angstroms; +} + +// period from atomic number +int period(double ZA) { + int iZA; + iZA = (int) ZA; + if (iZA <= 2) return 1; + else if (iZA <= 10) return 2; + else if (iZA <= 18) return 3; + else if (iZA <= 36) return 4; + else return 5; +} + +double ** FRAG::H_guess(void) { + int i, j, atomA, atomB, atomC, cnt = 0, perA, perB; + double rAB, rBC, rABcov, rBCcov, rBDcov; + double A, B, C, D, L, E, val; + double *f; + + f = init_array(intcos.size()); + + // Form diagonal Hessian in simple internals + if (Opt_params.intrafragment_H == OPT_PARAMS::SCHLEGEL) { + for (i=0; ig_type()) { + + case (stre_type) : + if (intcos[i]->is_hbond()) f[cnt++] = 0.03; + else { + atomA = intcos[i]->g_atom(0); + atomB = intcos[i]->g_atom(1); + perA = period(Z[atomA]); + perB = period(Z[atomB]); + + if ( perA==1 && perB==1) B = -0.244; + else if ((perA==1 && perB==2) || (perB==1 && perA==2)) B = 0.352; + else if (perA==2 && perB==2) B = 1.085; + else if ((perA==1 && perB==3) || (perB==1 && perA==3)) B = 0.660; + else if ((perA==2 && perB==3) || (perB==2 && perA==3)) B = 1.522; + else B = 2.068; + + rAB = v3d_dist(geom[atomA], geom[atomB]); + + A = 1.734; + // force constants in au / bohr^2 + f[cnt++] = A/((rAB-B)*(rAB-B)*(rAB-B)); + // for aJ/Ang^2, * _hartree2aJ / SQR(_bohr2angstroms); + } + break; + + case (bend_type) : + atomA = intcos[i]->g_atom(0); + atomB = intcos[i]->g_atom(1); + atomC = intcos[i]->g_atom(2); + + if ( (((int) Z[atomA]) == 1) || (((int) Z[atomC]) == 1) ) + val = 0.160; + else + val = 0.250; + f[cnt++] = val; + break; + + case (tors_type) : + atomB = intcos[i]->g_atom(1); + atomC = intcos[i]->g_atom(2); + A = 0.0023; + B = 0.07; + rBCcov = Rcov(Z[atomB], Z[(atomC)]); + rBC = v3d_dist(geom[atomB], geom[atomC]); + if (rBC > (rBCcov + A/B)) B = 0.0; // keep > 0 + f[cnt++] = (A - (B*(rBC - rBCcov))); + break; + + } // end switch coordinate type + } // loop over intcos + } // end Schlegel + else if (Opt_params.intrafragment_H == OPT_PARAMS::FISCHER) { + for (i=0; ig_type()) { + + case (stre_type) : + if (intcos[i]->is_hbond()) f[cnt++] = 0.03; + else { + atomA = intcos[i]->g_atom(0); + atomB = intcos[i]->g_atom(1); + + rAB = v3d_dist(geom[atomA], geom[atomB]); + rABcov = Rcov(Z[atomA], Z[atomB]); + + A = 0.3601; B = 1.944; + f[cnt++] = A * exp(-B*(rAB - rABcov)); + } + break; + + case (bend_type) : + atomA = intcos[i]->g_atom(0); + atomB = intcos[i]->g_atom(1); + atomC = intcos[i]->g_atom(2); + + rABcov = Rcov(Z[atomA], Z[atomB]); + rBCcov = Rcov(Z[atomB], Z[atomC]); + rAB = v3d_dist(geom[atomA], geom[atomB]); + rBC = v3d_dist(geom[atomB], geom[atomC]); + + A = 0.089; B = 0.11; C = 0.44; D = -0.42; + f[cnt++] = A + B/(pow(rABcov*rBCcov, D)) * + exp(-C*( rAB + rBC - rABcov - rBCcov)); + break; + + case (tors_type) : + atomB = intcos[i]->g_atom(1); + atomC = intcos[i]->g_atom(2); + + rBCcov = Rcov(Z[atomB], Z[atomC]); + rBC = v3d_dist(geom[atomB], geom[atomC]); + + // count number of additional bonds on central atoms + L = 0; + for (j=0; j= 2) { + fprintf(outfile,"\t---------------------------------------------------\n"); + fprintf(outfile,"\t Iter RMS(dx) Max(dx) RMS(dq) \n"); + fprintf(outfile,"\t---------------------------------------------------\n"); + } + + //compute_intco_values(); // lock in orientation of torsions + fix_tors_near_180(); // subsequent computes will modify torsional values + double * q_orig = intco_values(); + if (Opt_params.print_lvl >= 3) { + fprintf(outfile,"\nOriginal q internal coordinates\n"); + for (i=0; i= 3) { + fprintf(outfile,"\nTarget q internal coordinates\n"); + for (i=0; i= Opt_params.bt_max_iter) { + bt_iter_done = true; + bt_converged = false; + } + + dx_rms_last = dx_rms; + + //compute_intco_values(); + set_geom_array(new_geom); + new_q = intco_values(); + for (i=0; i< Nints; ++i) + dq[i] = q_target[i] - new_q[i]; // calculate dq from _target_ + free_array(new_q); + + // save first try in case doesn't converge + if (bmat_iter_cnt == 0) { + for (i=0; i= 2) + fprintf (outfile,"\t%5d %14.1e %14.1e %14.1e\n", bmat_iter_cnt+1, dx_rms, dx_max, dq_rms); + + ++bmat_iter_cnt; + } + + if (Opt_params.print_lvl >= 2) + fprintf(outfile,"\t---------------------------------------------\n"); + + if (bt_converged) { + fprintf(outfile, "\tSuccessfully converged to displaced geometry.\n"); + if (dq_rms > first_dq_rms) { + fprintf(outfile,"\tFirst geometry is closer to target in internal coordinates, so am using that one.\n"); + set_geom_array(first_geom); + } + } + else { + fprintf(outfile,"\tCould not converge backtransformation.\n"); + fprintf(outfile,"\tUsing first guess instead.\n"); + set_geom_array(first_geom); + } + + /* Set dq to final, total displacement achieved */ + //compute_intco_values(); + new_q = intco_values(); + for (i=0; i< Nints; ++i) + dq[i] = new_q[i] - q_orig[i]; // calculate dq from _target_ + + if (print_disp) { + + double *f_q = p_Opt_data->g_forces_pointer(); // for printing + + fprintf(outfile,"\n\t---Internal Coordinate Step in ANG or DEG, aJ/ANG or AJ/DEG ---\n"); + fprintf(outfile, "\t ----------------------------------------------------------------------\n"); + fprintf(outfile, "\t Coordinate Previous Force Change New \n"); + fprintf(outfile, "\t ---------- -------- ------ ------ ------\n"); + for (i=0; iprint_disp(outfile, q_orig[i], f_q[i], dq[i], new_q[i], atom_offset); + fprintf(outfile, "\t ----------------------------------------------------------------------\n"); + } + free_array(new_q); + + free_matrix(G); + free_array(new_geom); + free_array(first_geom); + free_array(dx); + free_array(tmp_v_Nints); + free_matrix(B); + + free_array(q_target); + free_array(q_orig); + + fflush(outfile); + return; +} + +} + diff --git a/optking/geom_gradients_io.C b/optking/geom_gradients_io.C new file mode 100644 index 0000000..4486965 --- /dev/null +++ b/optking/geom_gradients_io.C @@ -0,0 +1,326 @@ +/*! \file geom_gradients_io.cc + \ingroup optking + \brief functions to read and write the geometry, the gradient and the Hessian +*/ + +#include +#include +#include "molecule.h" + +#define EXTERN +#include "globals.h" + +#include "io.h" + +#if defined(OPTKING_PACKAGE_PSI) + #include + #include + #include + #include +#elif defined(OPTKING_PACKAGE_QCHEM) + #include // typedefs INTEGER + #include "EFP.h" + void get_carts(double** Carts, double** A, INTEGER** AtNo, INTEGER* NAtoms, bool noghosts); +#endif + +namespace opt { + +using namespace std; + +bool is_integer(const char *check) { + for (int i=0; imolecule()->natom(); + +#elif defined(OPTKING_PACKAGE_QCHEM) + + // read number of atoms from QChem + natom = rem_read(REM_NATOMS); + + // now substract out EFP fragment atoms ? + if (Opt_params.efp_fragments) { + int n = ::EFP::GetInstance()->GetNumEFPatoms(); + natom -= n; + fprintf(outfile, "\nNumber of atoms besides EFP fragments %d\n", natom); + } + +#endif + return natom; +} + + +// Read geometry and gradient into a molecule object. +// The fragments must already exist with the number of atoms in each set +// and with allocated memory. +void MOLECULE::read_geom_grad(void) { + int nallatom = g_natom(); + +#if defined(OPTKING_PACKAGE_PSI) + // for now read from file 11 + std::ifstream fin; + + string lbl; + char cline[256]; + int junk; + + try { + fin.open(FILENAME_GEOM_GRAD_IN, ios_base::in); + fin.clear(); + fin.exceptions(ios_base::failbit); + fin.seekg(0); + + // rewind, determine number of geometries + int nlines = 0; + try { // ignore exceptions only here + while (fin.peek() != EOF) { + fin.getline(cline, 256); + ++nlines; + } + } + catch (std::ios_base::failure & bf) { } + + int ngeom = nlines / (2*nallatom+2); + + // rewind through old geometries + fin.clear(); + fin.seekg(0); + for (int i=0; i< (ngeom-1)*(2*nallatom+2); ++i) + fin.getline(cline, 256); + + // header line + fin.getline(cline, 256); + + fin >> junk; + if (junk != nallatom) throw(INTCO_EXCEPT("wrong number of atoms in text file")); + fin >> energy; + + for (int f=0; fg_Z_pointer(); + double **geom = fragments[f]->g_geom_pointer(); + + for (int i=0; ig_natom(); ++i) { + //// check to see if atomic number or symbol + //if ( isalpha((lbl.c_str())[0]) ) + //Z[i] = Element_to_Z(lbl); + //else + fin >> Z[i]; + + fin >> geom[i][0]; + fin >> geom[i][1]; + fin >> geom[i][2]; + } + } + + for (int f=0; fg_grad_pointer(); + for (int i=0; ig_natom(); ++i) { + fin >> grad[i][0]; + fin >> grad[i][1]; + fin >> grad[i][2]; + } + } + psi::Communicator::world->sync(); + fin.close(); + } // end try reading geometries + catch (std::ios_base::failure & bf) { + printf("Error reading molecular geometry and gradient\n"); + fprintf(outfile,"Error reading molecular geometry and gradient\n"); + throw(INTCO_EXCEPT("Error reading molecular geometry and gradient")); + } + +#elif defined(OPTKING_PACKAGE_QCHEM) + + int EFPfrag = 0; + int EFPatom = 0; + if (Opt_params.efp_fragments) { + EFPfrag = EFP::GetInstance()->NFragments(); + std::vector AtomsinEFP = EFP::GetInstance()->NEFPAtoms(); + for (int i = 0; i < EFPfrag; ++i) + EFPatom += AtomsinEFP[i]; + fprintf(outfile,"\t %d EFP fragments containing %d atoms.\n", EFPfrag, EFPatom); + } + + double *QX; + INTEGER *QZ, QNATOMS; + bool Qnoghosts = true; + + ::get_carts(NULL, &QX, &QZ, &QNATOMS, Qnoghosts); + + int QNATOMS_real = g_natom(); + if (QNATOMS_real != (QNATOMS-EFPatom)) + QCrash("Number of computed real atoms is inconsistent.\n"); + + fprintf(outfile, "\tNATOMS (total)=%d (minus EFP)=%d\n", QNATOMS, QNATOMS_real); + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile,"\tCartesian coordinates from ::get_carts().\n"); + print_array(outfile, QX, 3*QNATOMS); + } + + int Numgrad = QNATOMS_real*3 + 6*EFPfrag; + double* QGrad = init_array(Numgrad); + + ::FileMan_Open_Read(FILE_NUCLEAR_GRADIENT); + ::FileMan(FM_READ, FILE_NUCLEAR_GRADIENT, FM_DP, Numgrad, 0, FM_BEG, QGrad); + ::FileMan_Close(FILE_NUCLEAR_GRADIENT); + + // store geometry and gradient of real atoms in fragment objects + int cnt=0; + for (int f=0; fg_Z_pointer(); + double **geom = fragments[f]->g_geom_pointer(); + double **grad = fragments[f]->g_grad_pointer(); + + for (int i=0; ig_natom(); ++i) { + Z[i] = QZ[cnt]; + for (int xyz=0; xyz<3; ++xyz) { + geom[i][xyz] = QX[3*cnt+xyz]; + grad[i][xyz] = QGrad[3*cnt+xyz]; + } + ++cnt; + } + + } + // Now read in gradients for EFP fragments + for (int f=0; fset_forces(efp_f); + free_array(efp_f); + } + free_array(QGrad); + + if (Opt_params.efp_fragments) { + energy = EFP::GetInstance()->GetEnergy(); + } + else { + double E_tmp; + ::FileMan_Open_Read(FILE_ENERGY); + ::FileMan(FM_READ, FILE_ENERGY, FM_DP, 1, FILE_POS_CRNT_TOTAL_ENERGY, FM_BEG, &E_tmp); + ::FileMan_Close(FILE_ENERGY); + energy = E_tmp; + } + +#endif + + // update interfragment reference points if they exist + for (int i=0; iupdate_reference_points(); + + return; +} + +void MOLECULE::symmetrize_geom(void) { + +#if defined(OPTKING_PACKAGE_PSI) + + // put matrix into environment molecule and it will symmetrize it + double **geom_2D = g_geom_2D(); + psi::Process::environment.molecule()->set_geometry(geom_2D); + psi::Process::environment.molecule()->update_geometry(); + free_matrix(geom_2D); + + psi::SimpleMatrix geom = psi::Process::environment.molecule()->geometry(); + geom_2D = geom.pointer(); // don't free; it's shared + set_geom_array(geom_2D[0]); + +#elif defined(OPTKING_PACKAGE_QCHEM) + + // not implemented yet + +#endif +} + +void MOLECULE::write_geom(void) { + +#if defined(OPTKING_PACKAGE_PSI) + + double **geom_2D = g_geom_2D(); + psi::Process::environment.molecule()->set_geometry(geom_2D); + psi::Process::environment.molecule()->update_geometry(); + free_matrix(geom_2D); + +#elif defined(OPTKING_PACKAGE_QCHEM) + + // rotation matrix is already updated by displace() + double *geom = g_geom_array(); + if (!Opt_params.efp_fragments_only) { + int NoReor = rem_read(REM_NO_REORIENT); // save state + rem_write(1, REM_NO_REORIENT); // write cartesians ; do NOT reorient + ::set_carts(geom, true); + rem_write(NoReor, REM_NO_REORIENT); // replace to original state + } + +#endif +} + +double ** OPT_DATA::read_cartesian_H(void) const { + + double **H_cart = init_matrix(Ncart, Ncart); + +#if defined(OPTKING_PACKAGE_PSI) + std::ifstream if_Hcart; + try { + if_Hcart.open(FILENAME_CARTESIAN_H, ios_base::in); + int n; + if_Hcart >> n; // read natom + if_Hcart >> n; // read natom*6 (?) + + for (int i=0; i> H_cart[i][j]; + + psi::Communicator::world->sync(); + if_Hcart.close(); + } + catch (std::ios_base::failure & bf) { + printf("Error reading cartesian Hessian matrix\n"); + fprintf(outfile,"Error reading cartesian Hessian matrix\n"); + throw(INTCO_EXCEPT("Error reading cartesian Hessian matrix")); + } + +#elif defined(OPTKING_PACKAGE_QCHEM) + + double *Hess = init_array(Ncart*Ncart); + + FileMan_Open_Read(FILE_NUCLEAR_HESSIAN); + FileMan(FM_READ, FILE_NUCLEAR_HESSIAN, FM_DP, Ncart*Ncart, 0, FM_BEG, Hess); + FileMan_Close(FILE_NUCLEAR_HESSIAN); + //print_matrix(outfile, &Hess, 1, Ncart * Ncart); + +// instead read from $QCSCRATCH/scr_dir_name/HESS ? + + int cnt = 0; + for (int i=0; i= 3) { + fprintf(outfile,"\tCartesian Hessian matrix read: \n"); + print_matrix(outfile, H_cart, Ncart, Ncart); + fflush(outfile); + } + + return H_cart; +} + +} + diff --git a/optking/getIntcoFileName.C b/optking/getIntcoFileName.C new file mode 100644 index 0000000..0d9c484 --- /dev/null +++ b/optking/getIntcoFileName.C @@ -0,0 +1,25 @@ +#include "qcsys.h" +#include +extern void getPrefix(char*& pref); +const char* getIntcoFileName() +{ + static std::string strintco(""); + if (strintco.empty() ) { + char* pref=NULL; + getPrefix(pref); + strintco = std::string(pref) + "intco.dat"; + } + return strintco.c_str(); +} + +const char* getOptdataFileName() +{ + static std::string stroptdata(""); + if (stroptdata.empty() ) { + char* pref=NULL; + getPrefix(pref); + stroptdata = std::string(pref) + "opt_data.1"; + } + return stroptdata.c_str(); +} + diff --git a/optking/globals.h b/optking/globals.h new file mode 100644 index 0000000..f3f2466 --- /dev/null +++ b/optking/globals.h @@ -0,0 +1,57 @@ +/*! \file globals.h + \ingroup optking + \brief */ + +#ifndef _opt_globals_h_ +#define _opt_globals_h_ + +//const char* getIntcoFileName(); + +#define FILENAME_INTCO_DAT getIntcoFileName() +#define FILENAME_OUTPUT_DAT "output.dat" // not used by PSI +#define FILENAME_CARTESIAN_H "psi.file15.dat" // used by PSI +#define FILENAME_GEOM_GRAD_IN "psi.file11.dat" // used by PSI + +#include +#include "package.h" + +#ifdef EXTERN +#undef EXTERN +#define EXTERN extern +#else +#define EXTERN +#endif + +#if defined(OPTKING_PACKAGE_PSI) + #include +#endif + +namespace opt { + EXTERN FILE *outfile; + + //int read_natoms(void); +} + + +// symmetric matrix offset lookup array +#define IOFF_MAX 32641 +namespace opt { + EXTERN int *ioff; +} + +// struct holding options/parameters for optking execution +#include "opt_params.h" +namespace opt { + EXTERN OPT_PARAMS Opt_params; +} + +// class for storage and manipulation of optimization step data +#include "opt_data.h" +namespace opt { + EXTERN OPT_DATA *p_Opt_data; +} + +#include "opt_except.h" + +#endif + diff --git a/optking/intcos.h b/optking/intcos.h new file mode 100644 index 0000000..96cf160 --- /dev/null +++ b/optking/intcos.h @@ -0,0 +1,14 @@ +/*! \file intcos.h + \ingroup optking + \brief internal coordinate includes class declaration +*/ + +#ifndef _opt_intcos_h_ +#define _opt_intcos_h_ + +#include "simple.h" +#include "stre.h" +#include "bend.h" +#include "tors.h" + +#endif diff --git a/optking/interfrag.cpp b/optking/interfrag.cpp new file mode 100644 index 0000000..f2dbb1e --- /dev/null +++ b/optking/interfrag.cpp @@ -0,0 +1,762 @@ +/*! \file stre.h + \ingroup optking + \brief STRE class declaration +*/ + +#include "frag.h" +#include "interfrag.h" +#include "print.h" +#include "v3d.h" // for H_guess + +#include + +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace v3d; +using namespace std; + +// constructor for given weight linear combination reference points +INTERFRAG::INTERFRAG(FRAG *A_in, FRAG *B_in, int A_index_in, int B_index_in, + double **weightA_in, double **weightB_in, int ndA_in, int ndB_in, bool principal_axes) { + + A = A_in; + B = B_in; + A_index = A_index_in; + B_index = B_index_in; + weightA = weightA_in; + weightB = weightB_in; + ndA = ndA_in; + ndB = ndB_in; + + double **inter_geom = init_matrix(6,3); // some rows may be unused + + // Create pseudo-fragment with atomic numbers at 6 positions. + // The atomic numbers may affect Hessian guess routines at most. + double *Z = init_array(6); + for (int i=0; i<6; ++i) Z[i] = 6; // assume C for now + inter_frag = new FRAG(6, Z, inter_geom); + + update_reference_points(); + + add_coordinates_of_reference_pts(); +} + +// adds the coordinates connecting A2-A1-A0-B0-B1-B2 +// sets D_on to indicate which ones (of the 6) are unusued +void INTERFRAG::add_coordinates_of_reference_pts(void) { + STRE *one_stre = NULL; // RAB + BEND *one_bend = NULL; // theta_A + BEND *one_bend2 = NULL; // theta_B + TORS *one_tors = NULL; // tau + TORS *one_tors2 = NULL; // phi_A + TORS *one_tors3 = NULL; // phi_B + + // turn all coordinates on ; turn off unused ones below + for (int i=0; i<6; ++i) D_on[i] = true; + + if (ndA == 3 && ndB == 3) { + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + one_tors2 = new TORS(0, 1, 2, 3); // phi_A + one_tors3 = new TORS(2, 3, 4, 5); // phi_B + } + else if (ndA == 3 && ndB == 2) { + D_on[5] = false; // no phi_B + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + one_tors2 = new TORS(0, 1, 2, 3); // phi_A + } + else if (ndA == 2 && ndB == 3) { + D_on[4] = false; // no phi_A + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + one_tors3 = new TORS(2, 3, 4, 5); // phi_B + } + else if (ndA == 3 && ndB == 1) { + D_on[2] = D_on[3] = D_on[5] = false; // no theta_B, tau, phi_B + STRE *one_stre = new STRE(2, 3); // RAB + BEND *one_bend = new BEND(1, 2, 3); // theta_A + TORS *one_tors2 = new TORS(0, 1, 2, 3); // phi_A + } + else if (ndA == 1 && ndB == 3) { + D_on[1] = D_on[3] = D_on[4] = false; // no theta_A, tau, phi_A + one_stre = new STRE(2, 3); // RAB + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors3 = new TORS(2, 3, 4, 5); // phi_B + } + else if (ndA == 2 && ndB == 2) { + D_on[4] = D_on[5] = false; // no phi_A, phi_B + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + } + else if (ndA == 2 && ndB == 1) { + D_on[2] = D_on[4] = D_on[5] = false; // no theta_B, phi_A, phi_B + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_tors = new TORS(1, 2, 3, 4); // tau + } + else if (ndA == 1 && ndB == 2) { + D_on[1] = D_on[4] = D_on[5] = false; // no theta_A, phi_A, phi_B + one_stre = new STRE(2, 3); // RAB + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + } + else if (ndA == 1 && ndB == 1) { + D_on[1] = D_on[2] = D_on[3] = D_on[4] = D_on[5] = false; + one_stre = new STRE(2, 3); // RAB + } + else { + throw(INTCO_EXCEPT("INTERFRAG::INTERFRAG Num. reference points on each fragment must be at least 1.")); + } + + // check if stretch is a H-bond or includes something H-bond like (remember stretch is + // in general between linear combinations of atoms + double ang; + + bool *is_XA = init_bool_array(g_natom()); + for (int a=0; ag_natom(); ++a) + if (A->Z[a] == 7 || A->Z[a] == 8 || A->Z[a] == 9 || A->Z[a] == 17) + is_XA[a] = true; + + bool *is_XB = init_bool_array(g_natom()); + for (int b=0; bg_natom(); ++b) + if (B->Z[b] == 7 || B->Z[b] == 8 || B->Z[b] == 9 || B->Z[b] == 17) + is_XB[b] = true; + + // Look for A[X]-A[H] ... B[Y] + for (int h=0; hnatom; ++h) { + if (weightA[0][h] != 0.0 && A->Z[h] == 1.0) { // H atom is (part of) A[0] + for (int x=0; xnatom; ++x) { + if (A->connectivity[x][h] && is_XA[x]) { // electronegative X atom is present + for (int y=0; ynatom; ++y) { + if (weightB[0][y] != 0.0 && is_XB[y]) { // electronegative Y atom is part of B[0] + if (v3d_angle(A->geom[x], A->geom[h], B->geom[y], ang)) { //check angle + if (ang < _pi/2) + one_stre->make_hbond(); + } + } + } + } + } + } + } + + // Look for A[Y]...B[H]-B[X] + for (int h=0; hnatom; ++h) { + if (weightB[0][h] != 0.0 && B->Z[h] == 1.0) { // H atom is (part of) B[0] + for (int x=0; xnatom; ++x) { + if (B->connectivity[x][h] && is_XB[x]) { // electronegative X atom is present + for (int y=0; ynatom; ++y) { + if (weightA[0][y] != 0.0 && is_XA[y]) { // electronegative Y atom is part of A[0] + if (v3d_angle(B->geom[x], B->geom[h], A->geom[y], ang)) { //check angle + if (ang < _pi/2) + one_stre->make_hbond(); + } + } + } + } + } + } + } + + if (Opt_params.interfragment_distance_inverse) { + one_stre->make_inverse_stre(); + fprintf(outfile,"Using interfragment 1/R distance coordinate.\n"); + } + if (one_stre->is_hbond()) + fprintf(outfile,"Detected H-bonding interfragment coordinate.\n"); + + if (one_stre != NULL) inter_frag->intcos.push_back(one_stre); + if (one_bend != NULL) inter_frag->intcos.push_back(one_bend); + if (one_bend2 != NULL) inter_frag->intcos.push_back(one_bend2); + if (one_tors != NULL) inter_frag->intcos.push_back(one_tors); + if (one_tors2 != NULL) inter_frag->intcos.push_back(one_tors2); + if (one_tors3 != NULL) inter_frag->intcos.push_back(one_tors3); +} + +// update location of reference points using given geometries +void INTERFRAG::update_reference_points(GeomType new_geom_A, GeomType new_geom_B) { + + zero_matrix(inter_frag->geom, 6, 3); + + if (!principal_axes) { // use fixed weights + for (int xyz=0; xyz<3; ++xyz) { + for (int a=0; ag_natom(); ++a) { + inter_frag->geom[0][xyz] += weightA[2][a] * new_geom_A[a][xyz]; + inter_frag->geom[1][xyz] += weightA[1][a] * new_geom_A[a][xyz]; + inter_frag->geom[2][xyz] += weightA[0][a] * new_geom_A[a][xyz]; + } + for (int b=0; bg_natom(); ++b) { + inter_frag->geom[3][xyz] += weightB[0][b] * new_geom_B[b][xyz]; + inter_frag->geom[4][xyz] += weightB[1][b] * new_geom_B[b][xyz]; + inter_frag->geom[5][xyz] += weightB[2][b] * new_geom_B[b][xyz]; + } + } + } + else { // using principal axes + + // first reference point on each fragment is the COM of each + double *fragment_com = A->com(); + for (int xyz=0; xyz<3; ++xyz) + inter_frag->geom[2][xyz] = fragment_com[xyz]; + + double **axes=NULL, *moi=NULL; + int i = A->principal_axes(new_geom_A, axes, moi); + + fprintf(outfile,"Number of principal axes returned is %d\n", i); + + for (i=0; igeom[1-i][xyz] = fragment_com[xyz] + axes[i][xyz]; + + free_array(moi); + free_matrix(axes); + free_array(fragment_com); + + fragment_com = B->com(); + for (int xyz=0; xyz<3; ++xyz) + inter_frag->geom[3][xyz] = fragment_com[xyz]; + + i = B->principal_axes(new_geom_B, axes, moi); + + fprintf(outfile,"Number of principal axes returned is %d\n", i); + + for (i=0; igeom[4+i][xyz] = fragment_com[xyz] + axes[i][xyz]; + + free_array(moi); + free_matrix(axes); + free_array(fragment_com); + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile,"\tndA: %d ; ndB: %d\n", ndA, ndB); + fprintf(outfile,"\tReference points are at the following locations.\n"); + for (int i=2; i>2-ndA; --i) + fprintf(outfile,"%15.10lf %15.10lf %15.10lf\n", + inter_frag->geom[i][0], inter_frag->geom[i][1], inter_frag->geom[i][2]); + for (int i=0; igeom[3+i][0], inter_frag->geom[3+i][1], inter_frag->geom[3+i][2]); + } + } +} + +int INTERFRAG::g_nintco(void) const { + int dim = 0; + for (int i=0; i<6; ++i) + if (D_on[i]) ++dim; + return dim; +} + +// freeze coordinate i if D_freeze[i]; index runs 0->6 as does D_on +///* +void INTERFRAG::freeze(bool *D_freeze) { + int cnt = -1; + for (int i=0; i<6; ++i) { + if (D_on[i]) { + ++cnt; + if (D_freeze[i]) + inter_frag->intcos[cnt]->freeze(); + } + } +} +//*/ + +// freeze coordinate i; index is among the coordinates that are 'on' +void INTERFRAG::freeze(int index_to_freeze) { + if (index_to_freeze<0 || index_to_freeze>g_nintco()) { + fprintf(outfile,"INTERFRAG::freeze() : Invalid index %d\n", index_to_freeze); + return; + } + inter_frag->intcos[index_to_freeze]->freeze(); +} + +void INTERFRAG::freeze(void) { + inter_frag->freeze(); +} + +// is coordinate J frozen? J runs over only active coordinates. +bool INTERFRAG::is_frozen(int J) { + if (J < 0 || J >= g_nintco()) + throw(INTCO_EXCEPT("INTERFRAG::is_frozen() index J runs only over active coordinates")); + return inter_frag->intcos[J]->is_frozen(); +} + +// are all interfragment modes frozen? +bool INTERFRAG::is_frozen(void) { + return inter_frag->is_frozen(); +} + +// compute and return coordinate values - using given fragment geometries +double * INTERFRAG::intco_values(GeomType new_geom_A, GeomType new_geom_B) { + update_reference_points(new_geom_A, new_geom_B); + double *q = init_array(g_nintco()); + + for (int i=0; iintcos.at(i)->value(inter_frag->geom); + + return q; +} + +// returns B matrix (internals by 3*natomA + 3*natomB) +double ** INTERFRAG::compute_B(GeomType new_geom_A, GeomType new_geom_B) { + + update_reference_points(new_geom_A, new_geom_B); + int natomA = A->natom; + int natomB = B->natom; + + double **B = init_matrix(g_nintco(), 3*(natomA+natomB)); + + if (!principal_axes) { + + int cnt=0, xyz; + double **B_ref; // derivative of interfragment D wrt reference point position + + if (D_on[0]) { + B_ref = inter_frag->intcos.at(cnt)->DqDx(inter_frag->geom); // RAB, returns (2,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // theta_A, returns (3,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // theta_B, returns (3,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // tau, returns (4,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // phi_A, returns (4,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // phi_B, returns (4,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aprincipal_axes(A, A_u, A_lambda); + double A_mass = Afrag->masses(); + + double **B_u = init_matrix(3,3); + double *B_lambda = init_array(3); + int nB_lambda = Bfrag->principal_axes(B, B_u, B_lambda); + + // First reference points are the centers of mass. These are fixed weights. + if (D_on[0]) { + B_ref = inter_frag->intcos.at(cnt)->DqDx(inter_frag->geom); // RAB, returns (2,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; anatom; + int nB = B->natom; + + int cnt=0, xyz_a, xyz_b; + double **B2_ref; // 2nd derivative of interfragment D wrt reference point position + + int P, Pp; // P and P' are fragments 0 or 1 (A or B) + int P_nref, Pp_nref; // # of reference points of P and P' + int P_natom, Pp_natom; // # of atoms in fragments P and P' + int K, Kp; // reference atoms 0-2 on fragment P and P' + int P_off, Pp_off; // offset for 1st atom of fragment list for both fragments (0 or 3*nA) + int P_off_ref, Pp_off_ref; // offset for 1st reference atom for fragment (0 or 3*ndA); + double **P_weight, **Pp_weight; + + double **B2 = init_matrix(3*(nA+nB) , 3*(nA+nB)); // d^2(D)/d(r)^2 (sides are dA, then dB) + int i, i_xyz, j, j_xyz; + + B2_ref = inter_frag->intcos.at(J)->Dq2Dx2(inter_frag->geom); // d^2(D)/d(reference point)^2 + + for (i_xyz=0; i_xyz<3; ++i_xyz) { + for (j_xyz=0; j_xyz<3; ++j_xyz) { + + if (J == 0) { // RAB, A0-B0 + + for (i=0; iAB + for (j=0; j<3*nA; ++j) + B2[j][3*nA+i] = B2[3*nA+i][j]; + + free_matrix(B2_ref); + + return B2; +} + + +void INTERFRAG::print_intcos(FILE *fp, int off_A, int off_B) const { + fprintf(fp,"\t---Interfragment Coordinates Between Fragments %d and %d---\n", + A_index+1, B_index+1); + fprintf(fp,"\t * Reference Points *\n"); + int cnt=0; + for (int i=2; i>=0; --i, ++cnt) { + if (ig_natom(); ++j) + if (weightA[i][j] != 0.0) + fprintf(fp," %d/%5.3f", off_A+j+1, weightA[i][j]); + fprintf(fp,"\n"); + } + } + for (int i=0; i<3; ++i, ++cnt) { + if (i < ndB) { + fprintf(fp,"\t\t %d B%d :", cnt+1, i+1); + for (int j=0; jg_natom(); ++j) + if (weightB[i][j] != 0.0) + fprintf(fp," %d/%5.3f", off_B+j+1, weightB[i][j]); + fprintf(fp,"\n"); + } + } + fflush(fp); + inter_frag->print_intcos(fp); +} + +void INTERFRAG::print_intco_dat(FILE *fp, int off_A, int off_B) const { + for (int i=0; ig_natom(); ++j) + if (weightA[i][j] != 0.0) fprintf(fp," %d", j+1+off_A); + fprintf(fp,"\n"); + } + for (int i=0; ig_natom(); ++j) + if (weightB[i][j] != 0.0) fprintf(fp," %d", j+1+off_B); + fprintf(fp,"\n"); + } + fflush(fp); +} + +// TODO - fix this up later +std::string INTERFRAG::get_intco_definition(int coord_index, int off_A, int off_B) const { + ostringstream iss; + for (int i=0; ig_natom(); ++j) + if (weightA[i][j] != 0.0) + iss << j+1+off_A; + iss << "\n"; + } + for (int i=0; ig_natom(); ++j) + if (weightB[i][j] != 0.0) + iss << j+1+off_B; + iss << "\n"; + } + return iss.str(); +} + +// Make the initial Hessian guess for interfragment coordinates +double ** INTERFRAG::H_guess(void) { + double **H; + + // use formulas from Fischer et al - not designed for interfragment modes + if (Opt_params.interfragment_H == OPT_PARAMS::FISCHER_LIKE) { + // H_guess uses intrafragment_H on inter_frag, so set and restore value + OPT_PARAMS::INTRAFRAGMENT_HESSIAN i = Opt_params.intrafragment_H ; + Opt_params.intrafragment_H = OPT_PARAMS::FISCHER; + H = inter_frag->H_guess(); + Opt_params.intrafragment_H = i; + } + else { // DEFAULT + H = init_matrix(inter_frag->g_nintco(), inter_frag->g_nintco()); + int cnt=0; + double rAB; + + if (Opt_params.interfragment_distance_inverse) + rAB = inter_frag->intcos[0]->value(inter_frag->geom); + + if (inter_frag->intcos[0]->is_hbond()) { + + H[cnt][cnt] = 0.03; + if (Opt_params.interfragment_distance_inverse) + H[cnt][cnt] *= pow(rAB,4); + ++cnt; + + if (D_on[1]) { H[cnt][cnt] = 0.007; ++cnt; } + if (D_on[2]) { H[cnt][cnt] = 0.007; ++cnt; } + if (D_on[3]) { H[cnt][cnt] = 0.002; ++cnt; } + if (D_on[4]) { H[cnt][cnt] = 0.002; ++cnt; } + if (D_on[5]) { H[cnt][cnt] = 0.002; ++cnt; } + } + else { + + H[cnt][cnt] = 0.007; + if (Opt_params.interfragment_distance_inverse) + H[cnt][cnt] *= pow(rAB,4); + ++cnt; + + if (D_on[1]) { H[cnt][cnt] = 0.003; ++cnt; } + if (D_on[2]) { H[cnt][cnt] = 0.003; ++cnt; } + if (D_on[3]) { H[cnt][cnt] = 0.001; ++cnt; } + if (D_on[4]) { H[cnt][cnt] = 0.001; ++cnt; } + if (D_on[5]) { H[cnt][cnt] = 0.001; ++cnt; } + } + + } + return H; +} + +// return matrix with 1's on diagonal for frozen coordinates +double ** INTERFRAG::compute_constraints(void) const { + double **C = init_matrix(g_nintco(), g_nintco()); + int cnt = 0; + for (int i=0; i<6; ++i) { + if (D_on[i]) { + if (inter_frag->intcos[cnt++]->is_frozen()) + C[i][i] = 1.0; + } + } + return C; +} + +} // opt + diff --git a/optking/interfrag.cppOld b/optking/interfrag.cppOld new file mode 100644 index 0000000..ddc902b --- /dev/null +++ b/optking/interfrag.cppOld @@ -0,0 +1,673 @@ +/*! \file stre.h + \ingroup optking + \brief STRE class declaration +*/ + +#include "frag.h" +#include "interfrag.h" +#include "print.h" +#include "v3d.h" // for H_guess + +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace v3d; + +INTERFRAG::INTERFRAG(FRAG *A_in, FRAG *B_in, int A_index_in, int B_index_in, + double **weightA_in, double **weightB_in, int ndA_in, int ndB_in) { + + A = A_in; + B = B_in; + A_index = A_index_in; + B_index = B_index_in; + weightA = weightA_in; + weightB = weightB_in; + ndA = ndA_in; + ndB = ndB_in; + //use_principal_axes = false; // default, change with set_principal_axes + + double **inter_geom = init_matrix(6,3); // some rows may be unused + + // create pseudo-fragment with atomic numbers at 6 positions + // the atomic numbers may only affect Hessian guess routines + double *Z = init_array(6); + for (int i=0; i<6; ++i) Z[i] = 6; + inter_frag = new FRAG(6, Z, inter_geom); + + STRE *one_stre = NULL; // RAB + BEND *one_bend = NULL; // theta_A + BEND *one_bend2 = NULL; // theta_B + TORS *one_tors = NULL; // tau + TORS *one_tors2 = NULL; // phi_A + TORS *one_tors3 = NULL; // phi_B + + update_reference_points(); + + // turn unusued coordinates off below + for (int i=0; i<6; ++i) D_on[i] = true; + + if (ndA == 3 && ndB == 3) { + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + one_tors2 = new TORS(0, 1, 2, 3); // phi_A + one_tors3 = new TORS(2, 3, 4, 5); // phi_B + } + else if (ndA == 3 && ndB == 2) { + D_on[5] = false; // no phi_B + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + one_tors2 = new TORS(0, 1, 2, 3); // phi_A + } + else if (ndA == 2 && ndB == 3) { + D_on[4] = false; // no phi_A + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + one_tors3 = new TORS(2, 3, 4, 5); // phi_B + } + else if (ndA == 3 && ndB == 1) { + D_on[2] = D_on[3] = D_on[5] = false; // no theta_B, tau, phi_B + STRE *one_stre = new STRE(2, 3); // RAB + BEND *one_bend = new BEND(1, 2, 3); // theta_A + TORS *one_tors2 = new TORS(0, 1, 2, 3); // phi_A + } + else if (ndA == 1 && ndB == 3) { + D_on[1] = D_on[3] = D_on[4] = false; // no theta_A, tau, phi_A + one_stre = new STRE(2, 3); // RAB + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors3 = new TORS(2, 3, 4, 5); // phi_B + } + else if (ndA == 2 && ndB == 2) { + D_on[4] = D_on[5] = false; // no phi_A, phi_B + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + } + else if (ndA == 2 && ndB == 1) { + D_on[2] = D_on[4] = D_on[5] = false; // no theta_B, phi_A, phi_B + one_stre = new STRE(2, 3); // RAB + one_bend = new BEND(1, 2, 3); // theta_A + one_tors = new TORS(1, 2, 3, 4); // tau + } + else if (ndA == 1 && ndB == 2) { + D_on[1] = D_on[4] = D_on[5] = false; // no theta_A, phi_A, phi_B + one_stre = new STRE(2, 3); // RAB + one_bend2 = new BEND(2, 3, 4); // theta_B + one_tors = new TORS(1, 2, 3, 4); // tau + } + else if (ndA == 1 && ndB == 1) { + D_on[1] = D_on[2] = D_on[3] = D_on[4] = D_on[5] = false; + one_stre = new STRE(2, 3); // RAB + } + else { + throw(INTCO_EXCEPT("INTERFRAG::INTERFRAG Num. reference points on each fragment must be at least 1.")); + } + + //if (!use_principal_axes) { + + // check if stretch is a H-bond or includes something H-bond like (remember stretch is + // in general between linear combinations of atoms + double ang; + + bool *is_XA = init_bool_array(g_natom()); + for (int a=0; ag_natom(); ++a) + if (A->Z[a] == 7 || A->Z[a] == 8 || A->Z[a] == 9 || A->Z[a] == 17) + is_XA[a] = true; + + bool *is_XB = init_bool_array(g_natom()); + for (int b=0; bg_natom(); ++b) + if (B->Z[b] == 7 || B->Z[b] == 8 || B->Z[b] == 9 || B->Z[b] == 17) + is_XB[b] = true; + + // Look for A[X]-A[H] ... B[Y] + for (int h=0; hnatom; ++h) { + if (weightA[0][h] != 0.0 && A->Z[h] == 1.0) { // H atom is (part of) A[0] + for (int x=0; xnatom; ++x) { + if (A->connectivity[x][h] && is_XA[x]) { // electronegative X atom is present + for (int y=0; ynatom; ++y) { + if (weightB[0][y] != 0.0 && is_XB[y]) { // electronegative Y atom is part of B[0] + if (v3d_angle(A->geom[x], A->geom[h], B->geom[y], ang)) { //check angle + if (ang < _pi/2) + one_stre->make_hbond(); + } + } + } + } + } + } + } + + // Look for A[Y]...B[H]-B[X] + for (int h=0; hnatom; ++h) { + if (weightB[0][h] != 0.0 && B->Z[h] == 1.0) { // H atom is (part of) B[0] + for (int x=0; xnatom; ++x) { + if (B->connectivity[x][h] && is_XB[x]) { // electronegative X atom is present + for (int y=0; ynatom; ++y) { + if (weightA[0][y] != 0.0 && is_XA[y]) { // electronegative Y atom is part of A[0] + if (v3d_angle(B->geom[x], B->geom[h], A->geom[y], ang)) { //check angle + if (ang < _pi/2) + one_stre->make_hbond(); + } + } + } + } + } + } + } + + //} // !use_principal axes + + if (Opt_params.interfragment_distance_inverse) { + one_stre->make_inverse_stre(); + fprintf(outfile,"Using interfragment 1/R distance coordinate.\n"); + } + if (one_stre->is_hbond()) + fprintf(outfile,"Detected H-bonding interfragment coordinate.\n"); + + if (one_stre != NULL) inter_frag->intcos.push_back(one_stre); + if (one_bend != NULL) inter_frag->intcos.push_back(one_bend); + if (one_bend2 != NULL) inter_frag->intcos.push_back(one_bend2); + if (one_tors != NULL) inter_frag->intcos.push_back(one_tors); + if (one_tors2 != NULL) inter_frag->intcos.push_back(one_tors2); + if (one_tors3 != NULL) inter_frag->intcos.push_back(one_tors3); +} + +// update location of reference points using given geometries +void INTERFRAG::update_reference_points(GeomType new_geom_A, GeomType new_geom_B) { + + for (int i=0; i<6; ++i) + for (int xyz=0; xyz<3; ++xyz) + inter_frag->geom[i][xyz] = 0.0; + + //if (!use_principal_axes) { + for (int xyz=0; xyz<3; ++xyz) { + for (int a=0; ag_natom(); ++a) { + inter_frag->geom[0][xyz] += weightA[2][a] * new_geom_A[a][xyz]; + inter_frag->geom[1][xyz] += weightA[1][a] * new_geom_A[a][xyz]; + inter_frag->geom[2][xyz] += weightA[0][a] * new_geom_A[a][xyz]; + } + for (int b=0; bg_natom(); ++b) { + inter_frag->geom[3][xyz] += weightB[0][b] * new_geom_B[b][xyz]; + inter_frag->geom[4][xyz] += weightB[1][b] * new_geom_B[b][xyz]; + inter_frag->geom[5][xyz] += weightB[2][b] * new_geom_B[b][xyz]; + } + } + /* } else { // using principal axes + int i, xyz; + + double **A_u = init_matrix(3,3); + double *A_lambda = init_array(3); + i = A->principal_axes(new_geom_A, A_u, A_lambda); + + if (i != ndA) { + fprintf(outfile,"Number of unique principal axes for fragment has changed.\n"); + throw(INTCO_EXCEPT("Number of principal axes for fragment has changed.",true)); + } + + double *A_com = A->com(); + + for (int xyz=0; xyz<3; ++xyz) + for (int i=0; igeom[2-i][xyz] = A_u[i][xyz] + A_com[xyz]; + + free_array(A_lambda); + free_matrix(A_u); + + double **B_u = init_matrix(3,3); + double *B_lambda = init_array(3); + i = B->principal_axes(new_geom_B, B_u, B_lambda); + + if (i != ndB) { + fprintf(outfile,"Number of unique principal axes for fragment has changed.\n"); + throw(INTCO_EXCEPT("Number of principal axes for fragment has changed.", true)); + } + + double *B_com = B->com(); + + for (int xyz=0; xyz<3; ++xyz) + for (int i=0; igeom[3+i][xyz] = B_u[i][xyz] + B_com[xyz]; + + free_array(B_lambda); + free_matrix(B_u); + } + */ +} + +int INTERFRAG::g_nintco(void) const { + int dim = 0; + for (int i=0; i<6; ++i) + if (D_on[i]) ++dim; + return dim; +} + +// freeze coordinate i if D_freeze[i]; index runs 0->6 as does D_on +void INTERFRAG::freeze(bool *D_freeze) { + int cnt = -1; + for (int i=0; i<6; ++i) { + if (D_on[i]) { + ++cnt; + if (D_freeze[i]) + inter_frag->intcos[cnt]->freeze(); + } + } +} + +// is coordinate J frozen? J runs over only active coordinates. +bool INTERFRAG::is_frozen(int J) { + if (J < 0 || J > g_nintco()) + throw(INTCO_EXCEPT("INTERFRAG::is_frozen() index J runs only over active coordinates")); + return inter_frag->intcos[J]->is_frozen(); +} + +// compute and return coordinate values - using given fragment geometries +double * INTERFRAG::intco_values(GeomType new_geom_A, GeomType new_geom_B) { + update_reference_points(new_geom_A, new_geom_B); + double *q = init_array(g_nintco()); + + for (int i=0; iintcos.at(i)->value(inter_frag->geom); + + return q; +} + +// returns B matrix (internals by 3*natomA + 3*natomB) +double ** INTERFRAG::compute_B(GeomType new_geom_A, GeomType new_geom_B) { + + update_reference_points(new_geom_A, new_geom_B); + int natomA = A->natom; + int natomB = B->natom; + + double **B = init_matrix(g_nintco(), 3*(natomA+natomB)); + + int cnt=0, xyz; + double **B_ref; // derivative of interfragment D wrt reference point position + + if (D_on[0]) { + B_ref = inter_frag->intcos.at(cnt)->DqDx(inter_frag->geom); // RAB, returns (2,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // theta_A, returns (3,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // theta_B, returns (3,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // tau, returns (4,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // phi_A, returns (4,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; aintcos.at(cnt)->DqDx(inter_frag->geom); // phi_B, returns (4,3) + for (xyz=0; xyz<3; ++xyz) { + for (int a=0; anatom; + int nB = B->natom; + + int cnt=0, xyz_a, xyz_b; + double **B2_ref; // 2nd derivative of interfragment D wrt reference point position + + int P, Pp; // P and P' are fragments 0 or 1 (A or B) + int P_nref, Pp_nref; // # of reference points of P and P' + int P_natom, Pp_natom; // # of atoms in fragments P and P' + int K, Kp; // reference atoms 0-2 on fragment P and P' + int P_off, Pp_off; // offset for 1st atom of fragment list for both fragments (0 or 3*nA) + int P_off_ref, Pp_off_ref; // offset for 1st reference atom for fragment (0 or 3*ndA); + double **P_weight, **Pp_weight; + + double **B2 = init_matrix(3*(nA+nB) , 3*(nA+nB)); // d^2(D)/d(r)^2 (sides are dA, then dB) + int i, i_xyz, j, j_xyz; + + B2_ref = inter_frag->intcos.at(J)->Dq2Dx2(inter_frag->geom); // d^2(D)/d(reference point)^2 + + for (i_xyz=0; i_xyz<3; ++i_xyz) { + for (j_xyz=0; j_xyz<3; ++j_xyz) { + + if (J == 0) { // RAB, A0-B0 + + for (i=0; iAB + for (j=0; j<3*nA; ++j) + B2[j][3*nA+i] = B2[3*nA+i][j]; + + free_matrix(B2_ref); + + return B2; +} + + +void INTERFRAG::print_intcos(FILE *fp, int off_A, int off_B) const { + fprintf(fp,"\t---Interfragment Coordinates Between Fragments %d and %d---\n", + A_index+1, B_index+1); + fprintf(fp,"\t * Reference Points *\n"); + int cnt=0; + for (int i=2; i>=0; --i, ++cnt) { + if (ig_natom(); ++j) + if (weightA[i][j] != 0.0) + fprintf(fp," %d/%5.3f", off_A+j+1, weightA[i][j]); + fprintf(fp,"\n"); + } + } + for (int i=0; i<3; ++i, ++cnt) { + if (i < ndB) { + fprintf(fp,"\t\t %d B%d :", cnt+1, i+1); + for (int j=0; jg_natom(); ++j) + if (weightB[i][j] != 0.0) + fprintf(fp," %d/%5.3f", off_B+j+1, weightB[i][j]); + fprintf(fp,"\n"); + } + } + fflush(fp); + inter_frag->print_intcos(fp); +} + +void INTERFRAG::print_intco_dat(FILE *fp, int off_A, int off_B) const { + for (int i=0; ig_natom(); ++j) + if (weightA[i][j] != 0.0) fprintf(fp," %d", j+1+off_A); + fprintf(fp,"\n"); + } + for (int i=0; ig_natom(); ++j) + if (weightB[i][j] != 0.0) fprintf(fp," %d", j+1+off_B); + fprintf(fp,"\n"); + } + fflush(fp); +} + + +// Make the initial Hessian guess for interfragment coordinates +double ** INTERFRAG::H_guess(void) { + double **H; + + // use formulas from Fischer et al - not designed for interfragment modes + if (Opt_params.interfragment_H == OPT_PARAMS::FISCHER_LIKE) { + // H_guess uses intrafragment_H on inter_frag, so set and restore value + OPT_PARAMS::INTRAFRAGMENT_HESSIAN i = Opt_params.intrafragment_H ; + Opt_params.intrafragment_H = OPT_PARAMS::FISCHER; + H = inter_frag->H_guess(); + Opt_params.intrafragment_H = i; + } + else { // DEFAULT + H = init_matrix(inter_frag->g_nintco(), inter_frag->g_nintco()); + int cnt=0; + double rAB; + + if (Opt_params.interfragment_distance_inverse) + rAB = inter_frag->intcos[0]->value(inter_frag->geom); + + if (inter_frag->intcos[0]->is_hbond()) { + + H[cnt][cnt] = 0.03; + if (Opt_params.interfragment_distance_inverse) + H[cnt][cnt] *= pow(rAB,4); + ++cnt; + + if (D_on[1]) { H[cnt][cnt] = 0.007; ++cnt; } + if (D_on[2]) { H[cnt][cnt] = 0.007; ++cnt; } + if (D_on[3]) { H[cnt][cnt] = 0.002; ++cnt; } + if (D_on[4]) { H[cnt][cnt] = 0.002; ++cnt; } + if (D_on[5]) { H[cnt][cnt] = 0.002; ++cnt; } + } + else { + + H[cnt][cnt] = 0.007; + if (Opt_params.interfragment_distance_inverse) + H[cnt][cnt] *= pow(rAB,4); + ++cnt; + + if (D_on[1]) { H[cnt][cnt] = 0.003; ++cnt; } + if (D_on[2]) { H[cnt][cnt] = 0.003; ++cnt; } + if (D_on[3]) { H[cnt][cnt] = 0.001; ++cnt; } + if (D_on[4]) { H[cnt][cnt] = 0.001; ++cnt; } + if (D_on[5]) { H[cnt][cnt] = 0.001; ++cnt; } + } + + } + return H; +} + +// return matrix with 1's on diagonal for frozen coordinates +double ** INTERFRAG::compute_constraints(void) const { + double **C = init_matrix(g_nintco(), g_nintco()); + int cnt = 0; + for (int i=0; i<6; ++i) { + if (D_on[i]) { + if (inter_frag->intcos[cnt++]->is_frozen()) + C[i][i] = 1.0; + } + } + return C; +} + +} // opt + diff --git a/optking/interfrag.h b/optking/interfrag.h new file mode 100644 index 0000000..52adfda --- /dev/null +++ b/optking/interfrag.h @@ -0,0 +1,168 @@ +/*! \file stre.h + \ingroup optking + \brief STRE class declaration +*/ + +#ifndef _opt_interfrag_h_ +#define _opt_interfrag_h_ + +#include "linear_algebra.h" +#include "physconst.h" + +namespace opt { +/* +INTERFRAG is a set of coordinates between two fragments (A and B). +Up to 3 reference atoms on each fragment (dA[3] and dB[3]) are defined +as either + If INTERFRAGMENT_MODE == FIXED, + linear combinations of the atoms in A and B, using A_weight and B_weight, + or if INTERFRAGMENT_MODE == PRINCIPAL_AXES + 1. the center of mass + 2. a point a unit distance along the principal axis corresponding to the largest moment. + 3. a point a unit distance along the principal axis corresponding to the 2nd largest moment. + +For now, the six coordinates formed from the d_K^{A,B} sets are assumed to be the +following in this canonical order: +D[0], RAB = distance between dA[0] and dB[0] +D[1], theta_A = angle, dA[1]-dA[0]-dB[0] +D[2], theta_B = angle, dA[0]-dB[0]-dB[1] +D[3], tau = dihedral angle, dA[1]-dA[0]-dB[0]-dB[1] +D[4], phi_A = dihedral angle, dA[2]-dA[1]-dA[0]-dB[0] +D[5], phi_B = dihedral angle, dA[0]-dB[0]-dB[1]-dB[2] + +inter_geom[0] = dA[2]; // For simplicity, we sort the atoms in the 'inter_geom' +inter_geom[1] = dA[1]; // according to the assumed connectivity of the coordinates. +inter_geom[2] = dA[0]; // For A, this reverses the order in which weights are +inter_geom[3] = dB[0]; // provided to the constructor. +inter_geom[4] = dB[1]; +inter_geom[5] = dB[2]; +*/ + +class INTERFRAG { + + FRAG *A; // pointer to fragment A + FRAG *B; // pointer to fragment B + + int A_index; // index of fragment A in MOLECULE fragments, vector + int B_index; // index of fragment B in MOLECULE fragments, vector + + int ndA; // number of reference points used on A (<= 3) + int ndB; // number of reference points used on B (<= 3) + + // weights on the atoms of fragment A/B, defining the reference points + double **weightA; // dimension [ndA][A->natom] + double **weightB; // dimension [ndB][B->natom] + + FRAG *inter_frag; // pseudo-fragment that contains the 6 reference points as its atoms + + bool D_on[6]; // indicates which coordinates [0-5] are present; + // if ndA or ndB <3, then not all 6 coordinates are defined + + // whether to use COM, and 2 points on principal axes - instead of fixed weights + bool principal_axes; + + public: + + // Constructor for fixed, linear-combination reference points. + // Memory provided by calling function. + INTERFRAG(FRAG *A_in, FRAG *B_in, int A_index_in, int B_index_in, + double **weightA_in, double **weightB_in, int ndA_in=3, int ndB_in=3, + bool use_principal_axes=false); + + + ~INTERFRAG() { delete inter_frag; } + + // update location of reference points using fragment member geometries + void update_reference_points(void) { + update_reference_points(A->geom, B->geom); + } + + // update location of reference points using given geometries + void update_reference_points(GeomType new_geom_A, GeomType new_geom_B); + + int g_nintco(void) const; + + // return vector index of fragments in molecule vector + int g_A_index(void) const { return A_index; } + int g_B_index(void) const { return B_index; } + + int g_ndA(void) const { return ndA; } + int g_ndB(void) const { return ndB; } + + // compute and return coordinate values - using fragment member geometries + double *intco_values(void) { + double *q = intco_values(A->geom, B->geom); + return q; + } + + // freeze coordinate i if D_freeze[i]; index runs 0->6 as does D_on + void freeze(bool *D_freeze); + + // freeze coordinate i; index is among 'on' (well-defined) coordinates + void freeze(int J); + + // freeze all interfragment coordinates in this set + void freeze(void); + + // is coordinate J frozen? J runs over only active coordinates. + bool is_frozen(int J); + + // are all of these interfragment coordinates frozen? + bool is_frozen(void); + + // compute and return coordinate values - using given fragment geometries + double *intco_values(GeomType new_geom_A, GeomType new_geom_B); + + // check nearness to 180 and save value + void fix_tors_near_180(void) { + update_reference_points(); + inter_frag->fix_tors_near_180(); + } + + // returns B matrix from member geometries + double **compute_B(void) { + double **bmat = compute_B(A->geom, B->geom); + return bmat; + } + // returns B matrix (internals by 3*natomA + 3*natomB) + double **compute_B(GeomType new_geom_A, GeomType new_geom_B); + + // returns derivative B matrix from member geometries + double **compute_derivative_B(int intco_index) { + double **Bder = compute_derivative_B(intco_index, A->geom, B->geom); + return Bder; + } + // returns derivative B matrix for one internal, returns 3*natomA x 3*natomA + double **compute_derivative_B(int intco_index, GeomType new_geom_A, GeomType new_geom_B); + + // print reference point definitions and values of coordinates + void print_intcos(FILE *fp, int A_off=0, int B_off=0) const; + + // print coordinate definitions + void print_intco_dat(FILE *fp, int atom_offset_A=0, int atom_offset_B=0) const; + + // return string of intco definition + std::string get_intco_definition(int coord_index, int atom_offset_A=0, int atom_offset_B=0) const; + + // get number of atoms in the two fragments + int g_natom(void) const { return (A->g_natom() + B->g_natom()); } + int g_natom_A(void) const { return (A->g_natom()); } + int g_natom_B(void) const { return (B->g_natom()); } + + bool coordinate_on(int i) const { return D_on[i]; } + + double ** H_guess(void); // guess Hessian + + // orient fragments and displace by dq; forces are just for printing + bool orient_fragment(double *dq, double *f_q=NULL); + + double ** compute_constraints(void) const; + + void add_coordinates_of_reference_pts(void); + +}; // class INTERFRAG + +} // opt + +#endif + diff --git a/optking/interfrag.hOld b/optking/interfrag.hOld new file mode 100644 index 0000000..d9e7e0c --- /dev/null +++ b/optking/interfrag.hOld @@ -0,0 +1,145 @@ +/*! \file stre.h + \ingroup optking + \brief STRE class declaration +*/ + +#ifndef _opt_interfrag_h_ +#define _opt_interfrag_h_ + +#include "linear_algebra.h" +#include "physconst.h" + +namespace opt { +/* +INTERFRAG is a set of coordinates between two fragments (A and B). +Up to 3 reference atoms on each fragment (dA[3] and dB[3]) are defined +as linear combinations of the atoms in A and B, using A_weight and B_weight. + +The six coordinates in the set are in a canonical order: +D[0], RAB = distance between dA[0] and dB[0] +D[1], theta_A = angle, dA[1]-dA[0]-dB[0] +D[2], theta_B = angle, dA[0]-dB[0]-dB[1] +D[3], tau = dihedral angle, dA[1]-dA[0]-dB[0]-dB[1] +D[4], phi_A = dihedral angle, dA[2]-dA[1]-dA[0]-dB[0] +D[5], phi_B = dihedral angle, dA[0]-dB[0]-dB[1]-dB[2] + +inter_geom[0] = dA[2]; // atoms ordered by connectivity of coordinates +inter_geom[1] = dA[1]; // for A, this is reverse of order in which weights +inter_geom[2] = dA[0]; // are provided to the constructor +inter_geom[3] = dB[0]; +inter_geom[4] = dB[1]; +inter_geom[5] = dB[2]; +*/ + +class INTERFRAG { + + FRAG *A; // pointer to fragment A + FRAG *B; // pointer to fragment B + + int A_index; // index of fragment A in MOLECULE fragments, vector + int B_index; // index of fragment B in MOLECULE fragments, vector + + int ndA; // number of reference points used on A (<= 3) + int ndB; // number of reference points used on B (<= 3) + + // weights on the atoms of fragment A/B, defining the reference points + double **weightA; // dimension [ndA][A->natom] + double **weightB; // dimension [ndB][B->natom] + + FRAG *inter_frag; // pseudo-fragment that contains the 6 reference points as its atoms + + bool D_on[6]; // indicates which coordinates [0-5] are present; + // if ndA or ndB <3, then not all 6 coordinates are defined + + //bool use_principal_axes; + + public: + + // memory provided by calling function + INTERFRAG(FRAG *A_in, FRAG *B_in, int A_index_in, int B_index_in, + double **weightA_in, double **weightB_in, int ndA_in=3, int ndB_in=3); + + ~INTERFRAG() { delete inter_frag; } + + // update location of reference points using fragment member geometries + void update_reference_points(void) { + update_reference_points(A->geom, B->geom); + } + + // update location of reference points using given geometries + void update_reference_points(GeomType new_geom_A, GeomType new_geom_B); + + int g_nintco(void) const; + + // return vector index of fragments in molecule vector + int g_A_index(void) const { return A_index; } + int g_B_index(void) const { return B_index; } + + int g_ndA(void) const { return ndA; } + int g_ndB(void) const { return ndB; } + + // compute and return coordinate values - using fragment member geometries + double *intco_values(void) { + double *q = intco_values(A->geom, B->geom); + return q; + } + + // freeze coordinate i if D_freeze[i]; index runs 0->6 as does D_on + void freeze(bool *D_freeze); + + // is coordinate J frozen? J runs over only active coordinates. + bool is_frozen(int J); + + // compute and return coordinate values - using given fragment geometries + double *intco_values(GeomType new_geom_A, GeomType new_geom_B); + + // check nearness to 180 and save value + void fix_tors_near_180(void) { + update_reference_points(); + inter_frag->fix_tors_near_180(); + } + + // returns B matrix from member geometries + double **compute_B(void) { + double **bmat = compute_B(A->geom, B->geom); + return bmat; + } + // returns B matrix (internals by 3*natomA + 3*natomB) + double **compute_B(GeomType new_geom_A, GeomType new_geom_B); + + // returns derivative B matrix from member geometries + double **compute_derivative_B(int intco_index) { + double **Bder = compute_derivative_B(intco_index, A->geom, B->geom); + return Bder; + } + // returns derivative B matrix for one internal, returns 3*natomA x 3*natomA + double **compute_derivative_B(int intco_index, GeomType new_geom_A, GeomType new_geom_B); + + // print reference point definitions and values of coordinates + void print_intcos(FILE *fp, int A_off=0, int B_off=0) const; + + // print coordinate definitions + void print_intco_dat(FILE *fp, int atom_offset_A=0, int atom_offset_B=0) const; + + // get number of atoms in the two fragments + int g_natom(void) const { return (A->g_natom() + B->g_natom()); } + int g_natom_A(void) const { return (A->g_natom()); } + int g_natom_B(void) const { return (B->g_natom()); } + + bool coordinate_on(int i) const { return D_on[i]; } + + double ** H_guess(void); // guess Hessian + + bool orient_fragment(double *q_target); + + double ** compute_constraints(void) const; + + //void set_principal_axes(bool b) { use_principal_axes = b; } + //bool use_principal_axes(void) { return use_principal_axes; } + +}; // class INTERFRAG + +} // opt + +#endif + diff --git a/optking/interfrag_orient.cpp b/optking/interfrag_orient.cpp new file mode 100644 index 0000000..9a707ca --- /dev/null +++ b/optking/interfrag_orient.cpp @@ -0,0 +1,361 @@ +/*! \file interfrag_orient.cc + \ingroup optking + \brief function moves the geometry of fragment B so that the interfragment coordinates + have the given values + + ndA = # of ref pts on A to worry about + ndB = # of ref pts on B to worry about + + Value at least + ndA ndB + ------------ + 1 1 R_AB + 2 1 + theta_A + 1 2 + theta_B + 2 2 + theta_A + theta_B + fix tau + 3 2 + phi_A + 2 3 + phi_A + phi_B + ------------ + + returns true if successful, false if not +*/ + +#include "frag.h" +#include "interfrag.h" +#include "print.h" +#include "v3d.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace v3d; + +void zmat_point(double *A, double *B, double *C, double R_CD, double theta_BCD, + double phi_ABCD, double *D); + +void rotate_vecs(double *w, double phi, double **v, int num_v); + +// arguments specify the bond length and angle in radians desired for interfragment coordinates +bool INTERFRAG::orient_fragment(double *dq, double *fq) { + + int pts, i, xyz; + double tval, norm, B_angle, R_B1B2, R_B2B3, e12[3], e12b[3], e12c[3], e12d[3], erot[3]; + double **ref_A, **ref_B, **ref_B_final; + double sign, cross1[3], cross2[3], cross3[3], phi2, phi3; + + // fill-in unused values with defaults to make code below work + double R_AB, theta_A, theta_B, tau, phi_A, phi_B; + R_AB = 1.0; + theta_A = theta_B = tau = phi_A = phi_B = _pi/2; + + double *q_orig = intco_values(); + double *q_target = init_array(g_nintco()); + + for (i=0; i lbl(6); + for (i=0; i<6; ++i) + if (inter_frag->intcos[i]->is_frozen()) + lbl[i] = "*"; + + if (inter_frag->intcos[0]->is_inverse_stre()) + lbl[0] += "1/R_AB"; + else + lbl[0] += "R_AB"; + lbl[1] += "theta_A"; + lbl[2] += "theta_B"; + lbl[3] += "tau"; + lbl[4] += "phi_A"; + lbl[5] += "phi_B"; + + fprintf(outfile,"\t---Interfragment coordinates between fragments %d and %d\n", A_index+1, B_index+1); + fprintf(outfile,"\t---Internal Coordinate Step in ANG or DEG, aJ/ANG or AJ/DEG ---\n"); + fprintf(outfile,"\t ----------------------------------------------------------------------\n"); + fprintf(outfile,"\t Coordinate Previous Change New \n"); + fprintf(outfile,"\t ---------- -------- ------ ------\n"); + + cnt = 0; + for (i=0; i<6; ++i) { + double val, force, change, target; + if (D_on[i]) { + val = q_orig[cnt]; + //force = fq[cnt]; + change = dq[cnt]; + target = q_target[cnt]; + + if (i == 0) { // change units for bond length coordinate + if (inter_frag->intcos[0]->is_inverse_stre()) { // 1/R(AB) + val /= _bohr2angstroms; + //force /= _hartree2aJ/_bohr2angstroms; + change /= _bohr2angstroms; + target /= _bohr2angstroms; + } + else { // R(AB) + val *= _bohr2angstroms; + //force *= _hartree2aJ/_bohr2angstroms; + change *= _bohr2angstroms; + target *= _bohr2angstroms; + } + } else { // change units for angle in degrees + val *= 180.0/_pi; + //force *= _hartree2aJ*_pi/180.0; + change *= 180.0/_pi; + target *= 180.0/_pi; + } + fprintf(outfile,"\t%-20s%12.5f%13.5f%13.5f\n", lbl[i].c_str(), val, change, target); + //fprintf(outfile,"\t%-20s%12.5f%13.5f%13.5f%13.5f\n", lbl[i].c_str(), val, force, change, target); + ++cnt; + } + } + fprintf(outfile, "\t ----------------------------------------------------------------------\n"); + + // copy B->geom in case this fails + double **B_geom = B->g_geom(); + + ref_A = init_matrix(3,3); + ref_B = init_matrix(ndB,3); + ref_B_final = init_matrix(ndB,3); + + // stick SOMETHING in for non-specified reference atoms for zmat_point() function + if (ndA < 3) + for (xyz=0; xyz<3; ++xyz) + ref_A[2][xyz] = (xyz+1); + + if (ndA < 2) + for (xyz=0; xyz<3; ++xyz) + ref_A[1][xyz] = (xyz+2); + + // compute current location of reference points on A and B + for (pts=0; ptsnatom;++i) + for (xyz=0; xyz<3; ++xyz) + ref_A[pts][xyz] += weightA[pts][i] * A->geom[i][xyz]; + + for (pts=0; ptsnatom;++i) + for (xyz=0; xyz<3; ++xyz) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + + // compute B1-B2 distance, B2-B3 distance, and B1-B2-B3 angle + if (ndB>1) + R_B1B2 = v3d_dist(ref_B[1], ref_B[0]); + + if (ndB>2) { + R_B2B3 = v3d_dist(ref_B[2], ref_B[1]); + v3d_angle(ref_B[0], ref_B[1], ref_B[2], B_angle); + } + + // determine target location of reference pts for B in coordinate system of A + zmat_point(ref_A[2], ref_A[1], ref_A[0], R_AB, theta_A, phi_A, ref_B_final[0]); + if (ndB>1) + zmat_point(ref_A[1], ref_A[0], ref_B_final[0], R_B1B2, theta_B, tau, ref_B_final[1]); + if (ndB>2) + zmat_point(ref_A[0], ref_B_final[0], ref_B_final[1], R_B2B3, B_angle, phi_B, ref_B_final[2]); + + //fprintf(outfile,"ref_B original location\n"); + //print_matrix(outfile, ref_B, ndB, 3); + //fprintf(outfile,"ref_B_final target\n"); + //print_matrix(outfile, ref_B_final, ndB, 3); + + // translate B->geom to place B1 in correct location + for (xyz=0; xyz<3; ++xyz) { + tval = ref_B_final[0][xyz] - ref_B[0][xyz]; + for (i=0; inatom; ++i) + B_geom[i][xyz] += tval; + } + + // recompute B reference points + zero_matrix(ref_B, ndB, 3); + for (pts=0; ptsnatom;++i) + for (xyz=0; xyz<3; ++xyz) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + + //fprintf(outfile,"ref_B with B1 corrected\n"); + //print_matrix(outfile, ref_B, ndB, 3); + + if (ndB>1) { /* move fragment B to place reference point B2 in correct location */ + /* Determine rotational angle and axis */ + v3d_eAB(ref_B[0], ref_B[1], e12); /* v B1->B2 */ + v3d_eAB(ref_B[0], ref_B_final[1], e12b); /* v B1->B2_final */ + B_angle = acos(v3d_dot(e12b,e12)); + + if (fabs(B_angle) > 1.0e-7) { + v3d_cross_product(e12,e12b,erot); + + /* Move B to put B1 at origin */ + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] -= ref_B[0][xyz]; + + /* Rotate B */ + rotate_vecs(erot, B_angle, B_geom, B->natom); + + /* Move B back to coordinate system of A */ + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] += ref_B[0][xyz]; + + // recompute current B reference points + zero_matrix(ref_B, ndB, 3); + for (pts=0; ptsnatom;++i) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + } + //fprintf(outfile,"ref_B with B2 corrected\n"); + //print_matrix(outfile, ref_B, ndB, 3); + } + if (ndB==3) { // move fragment B to place reference point B3 in correct location + // Determine rotational angle and axis + v3d_eAB(ref_B[0], ref_B[1], erot); /* B1 -> B2 is rotation axis */ + + // Calculate B3-B1-B2-B3' torsion angle + v3d_tors(ref_B[2], ref_B[0], ref_B[1], ref_B_final[2], B_angle); + + //fprintf(outfile,"B_angle: %15.10lf\n",B_angle); + if (fabs(B_angle) > 1.0e-10) { + + // Move B to put B2 at origin + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] -= ref_B[1][xyz]; + + rotate_vecs(erot, B_angle, B_geom, B->natom); + + // Translate B1 back to coordinate system of A + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] += ref_B[1][xyz]; + + // update B reference points + zero_matrix(ref_B, ndB, 3); + for (pts=0; ptsnatom;++i) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + } + //fprintf(outfile,"ref_B with B3 corrected\n"); + //print_matrix(outfile, ref_B, ndB, 3); + } + + // check to see if desired reference points were obtained + tval = 0.0; + for (i=0; i 1.0e-8) { + fprintf(outfile,"\tUnsuccessful at orienting fragments!\n"); + fflush(outfile); + return false; + } + else { + fprintf(outfile,"\tSuccessfully oriented fragments.\n"); + fflush(outfile); + B->set_geom(B_geom); + free_matrix(B_geom); + return true; + } +} + +/* Given the xyz coordinates for three points and R, theta, and phi, returns the +coordinates of a fourth point; angles in radians */ +void zmat_point(double *A, double *B, double *C, double R_CD, double theta_BCD, + double phi_ABCD, double *D) { + + double eAB[3],eBC[3],eX[3],eY[3], cosABC, sinABC; + + v3d_eAB(A,B,eAB); /* vector B->A */ + v3d_eAB(B,C,eBC); /* vector C->B */ + cosABC = -v3d_dot(eBC,eAB); + + sinABC = sqrt(1 - (cosABC * cosABC) ); + if ( (sinABC - 1.0e-14) < 0.0 ) { + printf("Reference points cannot be colinear."); + throw(INTCO_EXCEPT("Reference points cannot be colinear.", true)); + } + + v3d_cross_product(eAB,eBC,eY); + for(int xyz=0;xyz<3;xyz++) + eY[xyz] /= sinABC; + v3d_cross_product(eY,eBC,eX); + for (int xyz=0;xyz<3;xyz++) + D[xyz] = C[xyz] + R_CD * ( - eBC[xyz] * cos(theta_BCD) + + eX[xyz] * sin(theta_BCD) * cos(phi_ABCD) + + eY[xyz] * sin(theta_BCD) * sin(phi_ABCD) ); + return; +} + +/*! +** rotate_vecs(): Rotate a set of vectors around an arbitrary axis +** +** \brief Rotate a set of vectors around an arbitrary axis +** Vectors are rows of input matrix +** +** \param w double * : axis to rotate around (wx, wy, wz) - gets normalized here +** \param phi double : magnitude of rotation +** \param v double ** : points to rotate - column dim is 3; overwritten on exit +** \param num_v int : +** +** Returns: none +** +** Rollin King, Feb. 2008 +** \ingroup OPT +*/ +void rotate_vecs(double *w, double phi, double **v, int num_v) { + double **R, **v_new, wx, wy, wz, cp, norm; + + norm = sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]); + + w[0] /= norm; w[1] /= norm; w[2] /= norm; + + wx = w[0]; wy = w[1]; wz = w[2]; + cp = 1.0 - cos(phi); + + R = init_matrix(3,3); + + R[0][0] = cos(phi) + wx*wx*cp; + R[0][1] = -wz*sin(phi) + wx*wy*cp; + R[0][2] = wy*sin(phi) + wx*wz*cp; + R[1][0] = wz*sin(phi) + wx*wy*cp; + R[1][1] = cos(phi) + wy*wy*cp; + R[1][2] = -wx*sin(phi) + wy*wz*cp; + R[2][0] = -wy*sin(phi) + wx*wz*cp; + R[2][1] = wx*sin(phi) + wy*wz*cp; + R[2][2] = cos(phi) + wz*wz*cp; + + v_new = init_matrix(num_v,3); + opt_matrix_mult(R, 0, v, 1, v_new, 1, 3, 3, num_v, 0); + + for (int i=0; igeom in case this fails + double **B_geom = B->g_geom(); + + ref_A = init_matrix(3,3); + ref_B = init_matrix(ndB,3); + ref_B_final = init_matrix(ndB,3); + + // stick SOMETHING in for non-specified reference atoms for zmat_point() function + if (ndA < 3) + for (xyz=0; xyz<3; ++xyz) + ref_A[2][xyz] = (xyz+1); + + if (ndA < 2) + for (xyz=0; xyz<3; ++xyz) + ref_A[1][xyz] = (xyz+2); + + // compute current location of reference points on A and B + for (pts=0; ptsnatom;++i) + for (xyz=0; xyz<3; ++xyz) + ref_A[pts][xyz] += weightA[pts][i] * A->geom[i][xyz]; + + for (pts=0; ptsnatom;++i) + for (xyz=0; xyz<3; ++xyz) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + + // compute B1-B2 distance, B2-B3 distance, and B1-B2-B3 angle + if (ndB>1) + R_B1B2 = v3d_dist(ref_B[1], ref_B[0]); + + if (ndB>2) { + R_B2B3 = v3d_dist(ref_B[2], ref_B[1]); + v3d_angle(ref_B[0], ref_B[1], ref_B[2], B_angle); + } + + // determine target location of reference pts for B in coordinate system of A + zmat_point(ref_A[2], ref_A[1], ref_A[0], R_AB, theta_A, phi_A, ref_B_final[0]); + if (ndB>1) + zmat_point(ref_A[1], ref_A[0], ref_B_final[0], R_B1B2, theta_B, tau, ref_B_final[1]); + if (ndB>2) + zmat_point(ref_A[0], ref_B_final[0], ref_B_final[1], R_B2B3, B_angle, phi_B, ref_B_final[2]); + + //fprintf(outfile,"ref_B original location\n"); + //print_matrix(outfile, ref_B, ndB, 3); + //fprintf(outfile,"ref_B_final target\n"); + //print_matrix(outfile, ref_B_final, ndB, 3); + + // translate B->geom to place B1 in correct location + for (xyz=0; xyz<3; ++xyz) { + tval = ref_B_final[0][xyz] - ref_B[0][xyz]; + for (i=0; inatom; ++i) + B_geom[i][xyz] += tval; + } + + // recompute B reference points + zero_matrix(ref_B, ndB, 3); + for (pts=0; ptsnatom;++i) + for (xyz=0; xyz<3; ++xyz) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + + //fprintf(outfile,"ref_B with B1 corrected\n"); + //print_matrix(outfile, ref_B, ndB, 3); + + if (ndB>1) { /* move fragment B to place reference point B2 in correct location */ + /* Determine rotational angle and axis */ + v3d_eAB(ref_B[0], ref_B[1], e12); /* v B1->B2 */ + v3d_eAB(ref_B[0], ref_B_final[1], e12b); /* v B1->B2_final */ + B_angle = acos(v3d_dot(e12b,e12)); + + if (fabs(B_angle) > 1.0e-7) { + v3d_cross_product(e12,e12b,erot); + + /* Move B to put B1 at origin */ + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] -= ref_B[0][xyz]; + + /* Rotate B */ + rotate_vecs(erot, B_angle, B_geom, B->natom); + + /* Move B back to coordinate system of A */ + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] += ref_B[0][xyz]; + + // recompute current B reference points + zero_matrix(ref_B, ndB, 3); + for (pts=0; ptsnatom;++i) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + } + //fprintf(outfile,"ref_B with B2 corrected\n"); + //print_matrix(outfile, ref_B, ndB, 3); + } + if (ndB==3) { // move fragment B to place reference point B3 in correct location + // Determine rotational angle and axis + v3d_eAB(ref_B[0], ref_B[1], erot); /* B1 -> B2 is rotation axis */ + + // Calculate B3-B1-B2-B3' torsion angle + v3d_tors(ref_B[2], ref_B[0], ref_B[1], ref_B_final[2], B_angle); + + //fprintf(outfile,"B_angle: %15.10lf\n",B_angle); + if (fabs(B_angle) > 1.0e-10) { + + // Move B to put B2 at origin + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] -= ref_B[1][xyz]; + + rotate_vecs(erot, B_angle, B_geom, B->natom); + + // Translate B1 back to coordinate system of A + for (xyz=0; xyz<3; ++xyz) + for (i=0; inatom;++i) + B_geom[i][xyz] += ref_B[1][xyz]; + + // update B reference points + zero_matrix(ref_B, ndB, 3); + for (pts=0; ptsnatom;++i) + ref_B[pts][xyz] += weightB[pts][i] * B_geom[i][xyz]; + } + //fprintf(outfile,"ref_B with B3 corrected\n"); + //print_matrix(outfile, ref_B, ndB, 3); + } + + // check to see if desired reference points were obtained + tval = 0.0; + for (i=0; i 1.0e-8) { + fprintf(outfile,"\tUnsuccessful at orienting fragments!\n"); + fflush(outfile); + return false; + } + else { + fprintf(outfile,"\tSuccessfully oriented fragments.\n"); + fflush(outfile); + B->set_geom(B_geom); + free_matrix(B_geom); + return true; + } +} + +/* Given the xyz coordinates for three points and R, theta, and phi, returns the +coordinates of a fourth point; angles in radians */ +void zmat_point(double *A, double *B, double *C, double R_CD, double theta_BCD, + double phi_ABCD, double *D) { + + double eAB[3],eBC[3],eX[3],eY[3], cosABC, sinABC; + + v3d_eAB(A,B,eAB); /* vector B->A */ + v3d_eAB(B,C,eBC); /* vector C->B */ + cosABC = -v3d_dot(eBC,eAB); + + sinABC = sqrt(1 - (cosABC * cosABC) ); + if ( (sinABC - 1.0e-14) < 0.0 ) { + printf("Reference points cannot be colinear."); + throw(INTCO_EXCEPT("Reference points cannot be colinear.", true)); + } + + v3d_cross_product(eAB,eBC,eY); + for(int xyz=0;xyz<3;xyz++) + eY[xyz] /= sinABC; + v3d_cross_product(eY,eBC,eX); + for (int xyz=0;xyz<3;xyz++) + D[xyz] = C[xyz] + R_CD * ( - eBC[xyz] * cos(theta_BCD) + + eX[xyz] * sin(theta_BCD) * cos(phi_ABCD) + + eY[xyz] * sin(theta_BCD) * sin(phi_ABCD) ); + return; +} + +/*! +** rotate_vecs(): Rotate a set of vectors around an arbitrary axis +** +** \brief Rotate a set of vectors around an arbitrary axis +** Vectors are rows of input matrix +** +** \param w double * : axis to rotate around (wx, wy, wz) - gets normalized here +** \param phi double : magnitude of rotation +** \param v double ** : points to rotate - column dim is 3; overwritten on exit +** \param num_v int : +** +** Returns: none +** +** Rollin King, Feb. 2008 +** \ingroup OPT +*/ +void rotate_vecs(double *w, double phi, double **v, int num_v) { + double **R, **v_new, wx, wy, wz, cp, norm; + + norm = sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]); + + w[0] /= norm; w[1] /= norm; w[2] /= norm; + + wx = w[0]; wy = w[1]; wz = w[2]; + cp = 1.0 - cos(phi); + + R = init_matrix(3,3); + + R[0][0] = cos(phi) + wx*wx*cp; + R[0][1] = -wz*sin(phi) + wx*wy*cp; + R[0][2] = wy*sin(phi) + wx*wz*cp; + R[1][0] = wz*sin(phi) + wx*wy*cp; + R[1][1] = cos(phi) + wy*wy*cp; + R[1][2] = -wx*sin(phi) + wy*wz*cp; + R[2][0] = -wy*sin(phi) + wx*wz*cp; + R[2][1] = wx*sin(phi) + wy*wz*cp; + R[2][2] = cos(phi) + wz*wz*cp; + + v_new = init_matrix(num_v,3); + opt_matrix_mult(R, 0, v, 1, v_new, 1, 3, 3, num_v, 0); + + for (int i=0; i +#include "cmath" +//#include "qcmath.h" +#include "mem.h" + +#define EXTERN +#include "globals.h" + +extern "C" { + +// defines correct format of BLAS/LAPACK functions +#define F_DGEMM dgemm_ +#define F_DSYEV dsyev_ +//#include "qccfg.h" +//#define F_DGEMM FTN_EXTNAME(dgemm,DGEMM) +//#define F_DSYEV FTN_EXTNAME(dsyev,DSYEV) + +// declations of BLAS/LAPACK routines +extern void F_DGEMM(char *transa, char *transb, int *m, int *n, int *k, + double *alpha, double *A, int *lda, double *B, int *ldb, + double *beta, double *C, int *ldc); + +extern int F_DSYEV(char *, char *, int *, double *, int *, double *, + double *, int *, int *); + +// C functions called from opt that use the BLAS/LAPACK routines + +/* + matrix multiplication using DGEMM : A * B += C + tA (tB) indicate if A (B) is transposed; + nr = num of rows + nl = num of links + nc = num of cols + add = indicates whether to add to C or overwrite +*/ +void opt_matrix_mult(double **A, bool tA, double **B, bool tB, double **C, bool tC, + int nr, int nl, int nc, bool add) { + double alpha = 1.0; + double beta = (add ? 1.0 : 0.0); + char FtA, FtB; + int nca, ncb; + + if (!nr || !nl || !nc) return; + + if (!tC) { // reverse A and B to account for different C/Fortran stride + FtA = (tA ? 'T' : 'N'); + FtB = (tB ? 'T' : 'N'); + nca = (tA ? nr : nl ); + ncb = (tB ? nl : nc ); + + //F_DGEMM(&FtB, &FtA, &nc, &nr, &nl, &alpha, B[0], &ncb, A[0], &nca, &beta, C[0], &nr); + F_DGEMM(&FtB, &FtA, &nc, &nr, &nl, &alpha, B[0], &ncb, A[0], &nca, &beta, C[0], &nc); + } + else { // C is transposed, so compute B^t * A^t = C^t + FtA = (tA ? 'N' : 'T'); + FtB = (tB ? 'N' : 'T'); + nca = (tA ? nr : nl ); + ncb = (tB ? nl : nc ); + + F_DGEMM(&FtA, &FtB, &nr, &nc, &nl, &alpha, A[0], &nca, B[0], &ncb, &beta, C[0], &nr); + } + return; +} + +/* + Compute eigenvectors and eigenvalues of a real, symmetric matrix. + Eigenvectors are stored as rows of A. + eigenvalues returned in ascending order. +*/ +bool opt_symm_matrix_eig(double **A, int dim, double *evals) { + char cv = 'V'; // compute evals and evects +// char cl = 'L'; // lower triangle (upper in C) is necessary + char cl = 'U'; // upper triangle (lower triangle in C) is necessary + int lwork = 3 * dim; + int rval, i, j; + double tval; + double * work = opt_init_array(lwork); + + F_DSYEV(&cv, &cl, &dim, A[0], &dim, evals, work, &lwork, &rval); + + opt_free_array(work); + if (rval != 0) return false; + return true; +} + +} + +namespace opt { + +/* + Invert a real, symmetric matrix. If "redundant" == true, then a + generalized inverse is permitted. A is preserved. Requires lower + triangle (in C) of matrix. +*/ +double ** symm_matrix_inv(double **A, int dim, bool redundant) { + int i, j; + double det = 1.0; + double * evals = init_array(dim); + double ** A_evects = matrix_return_copy(A, dim, dim); + + if (dim <= 0) return ( (double **) NULL); + + if (! opt_symm_matrix_eig(A_evects, dim, evals) ) + throw(INTCO_EXCEPT("symm_matrix_inv : opt_symm_matrix_eig could not diagonalize")); + //for (i=0; i Opt_params.redundant_eval_tol) + A_inv[i][i] = 1.0/evals[i]; + } + else { + for (i=0;i max) max = fabs(v1[i]); + return max; +} + +double array_rms(double *v1, int n) { + double rms = array_dot(v1, v1, n); + rms = rms / ((double) n); + return sqrt(rms); +} + +} // namespace:: opt + diff --git a/optking/linear_algebra.h b/optking/linear_algebra.h new file mode 100644 index 0000000..47956ab --- /dev/null +++ b/optking/linear_algebra.h @@ -0,0 +1,41 @@ +/*! \file linear algebra.h : linear algebra functions + \ingroup optking +*/ + +#ifndef _opt_linear_algebra_h_ +#define _opt_linear_algebra_h_ + +// C functions called by opt which use BLAS/LAPACK routines +extern "C" { + +// matrix multiplications +void opt_matrix_mult(double **A, bool tA, double **B, bool tB, double **C, bool tC, + int nr, int nl, int nc, bool add); + +// eigenvector/eigenvalues +bool opt_symm_matrix_eig(double **A, int dim, double *evals); + +} + +namespace opt { + +// invert a symmetric matrix +double ** symm_matrix_inv(double **A, int dim, bool redundant=true); + +// allocate memory and return a copy of a matrix +double ** matrix_return_copy(double **A, int nr, int nc); +bool ** matrix_return_copy(bool **A, int nr, int nc); + +void matrix_copy(double **from, double **to, int nr, int nc); + +void array_copy(double *from, double *to, int n); +double array_dot(double *v1, double *v2, int n); +void array_normalize(double *v1, int n); +void array_scm(double *v1, double a, int n); +double array_abs_max(double *v1, int n); +double array_rms(double *v1, int n); + +} + +#endif + diff --git a/optking/mem.cpp b/optking/mem.cpp new file mode 100644 index 0000000..690cdf1 --- /dev/null +++ b/optking/mem.cpp @@ -0,0 +1,204 @@ +/*! \file mem.cc : memory allocation + \ingroup optking +*/ + +#include +#include "mem.h" +#include "opt_except.h" + +namespace opt { + +void zero_array(double *A, long int n) { + for (int i=0; i + +namespace opt { + +class MOLECULE { + + public: + + vector fragments; // fragments with intrafragment coordinates + vector interfragments; // interfragment coordinates +#if defined(OPTKING_PACKAGE_QCHEM) +// vector efp_fragments; // EFP fixed-body fragment - does not actually + // store atoms (for now at least) +#endif + double energy; + + MOLECULE(int num_atoms); // allocate molecule with one fragment of this size + + ~MOLECULE() { + for (int i=0; ig_natom(); + return n; + } + + int g_nintco(void) const { + int n=0; + for (int f=0; fg_nintco(); + for (int i=0; ig_nintco(); +#if defined (OPTKING_PACKAGE_QCHEM) +// for (int e=0; eg_nintco(); +#endif + return n; + } + + int g_nintco_intrafragment(void) const { + int n=0; + for (int f=0; fg_nintco(); + return n; + } + + int g_nintco_interfragment(void) const { + int n=0; + for (int f=0; fg_nintco(); + return n; + } + +#if defined (OPTKING_PACKAGE_QCHEM) +// int g_nintco_efp_fragment(void) const { +// int n=0; +// for (int f=0; fg_nintco(); +// return n; +// } +#endif + + // given fragment index returns first atom in that fragment + int g_atom_offset(int index) const { + int n = 0; + for (int f=1; f<=index; ++f) + n += fragments[f-1]->g_natom(); + return n; + } + + // given fragment index, returns the absolute index + // for the first internal coordinate on that fragment + int g_intco_offset(int index) const { + int n = 0; + for (int f=0; fg_nintco(); + return n; + } + + // given interfragment index, returns the absolute index for the first + // internal coordinate of that interfragment set + int g_interfragment_intco_offset(int index) const { + int n = g_nintco_intrafragment(); + for (int f=0; fg_nintco(); + return n; + } + + // given efp_fragment index, returns the absolute index for the first + // internal coordinate of that efp set +#if defined (OPTKING_PACKAGE_QCHEM) +// int g_efp_fragment_intco_offset(int index) const { +// int n = g_nintco_intrafragment() + g_nintco_interfragment(); +// for (int f=0; fg_nintco(); +// return n; +// } +#endif + + double g_energy(void) const { return energy; } + + void update_connectivity_by_distances(void) { + for (int i=0; iupdate_connectivity_by_distances(); + } + + void update_connectivity_by_bonds(void) { + for (int i=0; iupdate_connectivity_by_bonds(); + } + + void print_connectivity(FILE *fout) const { + for (int i=0; iprint_connectivity(fout, i, g_atom_offset(i)); + } + + void print_geom(FILE *fout, bool print_mass = false) { + for (int i=0; iprint_geom(fout, i, print_mass); + } + + void print_geom_grad(FILE *fout, bool print_mass = false) { + for (int i=0; iprint_geom_grad(fout, i, print_mass); + } + + void print_intcos(FILE *fout) { + int a,b; + for (int i=0; iprint_intcos(fout, g_atom_offset(i)); + } + for (int i=0; ig_A_index(); + b = interfragments[i]->g_B_index(); + interfragments[i]->print_intcos(fout, g_atom_offset(a), g_atom_offset(b)); + } + +#if defined (OPTKING_PACKAGE_QCHEM) +// for (int i=0; iprint_intcos(fout); +// } +#endif + } + +#if defined (OPTKING_PACKAGE_QCHEM) +// void update_efp_values(void); +#endif + + void print_intco_dat(FILE *fp_intco); + + int add_intrafragment_simples_by_connectivity(void) { + int n=0; + for (int i=0; iadd_simples_by_connectivity(); + return n; + } + + // compute intco values from frag member geometries + double * intco_values(void) const { + GeomType x = g_geom_2D(); + double *q = intco_values(x); + return q; + } + + // compute intco values from given geometry ; empty space for EFP coordinates included + double * intco_values(GeomType new_geom) const { + double *q, *q_frag, *q_IF; + q = init_array(g_nintco()); + + for (int f=0; fintco_values( &(new_geom[g_atom_offset(f)]) ); + + for (int i=0; ig_nintco(); ++i) + q[g_intco_offset(f)+i] = q_frag[i]; + + free_array(q_frag); + } + + for (int I=0; Ig_A_index(); + int B_index = interfragments[I]->g_B_index(); + + q_IF = interfragments[I]->intco_values( &(new_geom[g_atom_offset(A_index)]), + &(new_geom[g_atom_offset(B_index)]) ); + + for (int i=0; ig_nintco(); ++i) + q[g_interfragment_intco_offset(I)+i] = q_IF[i]; + + free_array(q_IF); + } + + return q; + } + + //void write_geom(void); + //void symmetrize_geom(void); + void print_geom(void); + + double ** compute_B(void) const; + double ** compute_derivative_B(int intco_index) const ; + + double * g_grad_array(void) const { + int f, i; + double *g, *g_frag; + + g = init_array(3*g_natom()); + for (f=0; fg_grad_array(); + for (i=0; i<3*fragments[f]->g_natom(); ++i) + g[3*g_atom_offset(f)+i] = g_frag[i]; + free_array(g_frag); + } + return g; + } + + double * g_geom_array(void) { + double *g, *g_frag; + + g = init_array(3*g_natom()); + for (int f=0; fg_geom_array(); + for (int i=0; i<3*fragments[f]->g_natom(); ++i) + g[3*g_atom_offset(f)+i] = g_frag[i]; + free_array(g_frag); + } + return g; + } + + double ** g_geom_2D(void) const { + double **g_frag; + double **g = init_matrix(g_natom(),3); + + for (int f=0; fg_geom(); + for (int i=0; ig_natom(); ++i) + for (int xyz=0; xyz<3; ++xyz) + g[g_atom_offset(f)+i][xyz] = g_frag[i][xyz]; + free_matrix(g_frag); + } + return g; + } + + double ** g_grad_2D(void) { + double **g, *g_frag; + + g = init_matrix(g_natom(),3); + for (int f=0; fg_grad_array(); + int cnt=0; + for (int i=0; ig_natom(); ++i) + for (int xyz=0; xyz<3; ++xyz) + g[g_atom_offset(f)+i][xyz] = g_frag[cnt++]; + free_array(g_frag); + } + return g; + } + + void H_guess(void) const; + + void forces(void); + void project_f_and_H(void); + void irc_step(void); + void nr_step(void); + void rfo_step(void); + void prfo_step(void); + void backstep(void); + + void apply_intrafragment_step_limit(double * & dq); + void check_intrafragment_zero_angles(double const * const dq); + + void set_geom_array(double * array_in) { + for (int f=0; fset_geom_array( &(array_in[3*g_atom_offset(f)]) ); + fragments[f]->set_geom_array( &(array_in[0]) ); + } + } + + void fix_tors_near_180(void) { + for (int f=0; ffix_tors_near_180(); + for (int I=0; Ifix_tors_near_180(); + } + + void test_B(void); + void test_derivative_B(void); + + bool cartesian_H_to_internals(void) const; + + + bool read_intcos(std::ifstream & fin); + // function to obtain geometry and gradient + //void read_geom_grad(void); + + // tell whether internal coordinate is frozen + double ** compute_constraints(void); + +}; + +} + +#endif + diff --git a/optking/molecule_backstep.cpp b/optking/molecule_backstep.cpp new file mode 100644 index 0000000..0d6474e --- /dev/null +++ b/optking/molecule_backstep.cpp @@ -0,0 +1,126 @@ +/*! \file molecule.cc + \ingroup optking + \brief molecule class (really, molecular system class) +*/ + +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#include "linear_algebra.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +// Update OPT_DATA to go back one step and try again with a smaller step. +// The current step data is replaced. +// For now lets just divide the step size by one half. +// +// OPT_DATA contains: +// left unchanged : Nintco, Ncart +// left unchanged : Hessian (throw bypasses updating) +// left unchanged : rfo_eigenvector (a unit vector) +// +// decrease by 1 : iteration (iteration if number of stored steps in opt_data +// - at least for now +// increase by 1 : consecutive_backsteps +// +// std::vector steps; +// Modify steps[Nsteps-2]. Then erase steps[Nsteps-1] (current step). +// +// Last step data unchanged: +// f_q +// geom +// energy +// unit_step +// dq_gradient +// dq_hessian +// +// dq_norm = dq_norm (last) /2 +// DE_predicted : call DE_nr_energy or DE_rfo_energy (dq_norm) +// + +// compute change in energy according to quadratic approximation +inline double DE_nr_energy(double step, double grad, double hess) { + return (step * grad + 0.5 * step * step * hess); +} + +// compute change in energy according to RFO approximation +inline double DE_rfo_energy(double rfo_t, double rfo_g, double rfo_h) { + return (rfo_t * rfo_g + 0.5 * rfo_t * rfo_t * rfo_h)/(1 + rfo_t*rfo_t); +} + +void MOLECULE::backstep(void) { + + fprintf(outfile,"\tRe-doing last optimization step - smaller this time."); + p_Opt_data->erase_last_step(); + p_Opt_data->decrement_iteration(); + p_Opt_data->increment_consecutive_backsteps(); + + int Nsteps = p_Opt_data->nsteps(); + int Nintco = g_nintco(); + + double *dq = p_Opt_data->g_dq_pointer(Nsteps-1); + for (int i=0; ig_rfo_eigenvector_pointer(); + double dq_grad = p_Opt_data->g_dq_gradient(Nsteps-1); + double dq_hess = p_Opt_data->g_dq_hessian(Nsteps-1); + + double DE_projected; + if (Opt_params.step_type == OPT_PARAMS::NR) + DE_projected = DE_nr_energy(dq_norm, dq_grad, dq_hess); + else if (Opt_params.step_type == OPT_PARAMS::RFO) + DE_projected = DE_rfo_energy(dq_norm, dq_grad, dq_hess); + + fprintf(outfile, "\tNewly projected energy change : %20.10lf\n", DE_projected); + + // do displacements for each fragment separately + for (int f=0; fis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tDisplacements for frozen fragment %d skipped.\n", f+1); + continue; + } + fragments[f]->displace(&(dq[g_intco_offset(f)]), true, g_intco_offset(f)); + } + + // do displacements for interfragment coordinates + double *q_target; + for (int I=0; Iintco_values(); + for (int i=0; ig_nintco(); ++i) + q_target[i] += dq[g_interfragment_intco_offset(I) + i]; + + interfragments[I]->orient_fragment(q_target); + + free_array(q_target); + } + +#if defined(OPTKING_PACKAGE_QCHEM) +// // fix rotation matrix for rotations in QCHEM EFP code +// for (int I=0; Idisplace( I, &(dq[g_efp_fragment_intco_offset(I)]) ); +#endif + + //symmetrize_geom(); // now symmetrize the geometry for next step + + // save values in step data + p_Opt_data->save_step_info(DE_projected, rfo_u, dq_norm, dq_grad, dq_hess); + + free_array(rfo_u); + fflush(outfile); + +} // end take RFO step + +} diff --git a/optking/molecule_fragments.cpp b/optking/molecule_fragments.cpp new file mode 100644 index 0000000..994a212 --- /dev/null +++ b/optking/molecule_fragments.cpp @@ -0,0 +1,429 @@ +/*! \file molecule_fragments.cc + \ingroup optking + \brief functions to handle fragments +*/ + +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#include "linear_algebra.h" +#include "v3d.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace v3d; + +// This function manipulates a molecule containing a single fragment. +// +// If fragment_mode == SINGLE, then this function adds connectivity between the +// closest atom members of disconnected groups of atoms to form one superfragment. +// It does not itself add additional internal coordinates; these may be added by +// "add_simples_by_connectivity()" . +// +// If fragment_mode == MULTI, then this function splits one fragment into more +// than one, according to the connectivity previously established for the fragment. +void MOLECULE::fragmentize(void) { + //cout << "DES: in fragmentize" << endl; + int i, j, xyz; + + if (fragments.size() != 1) return; + + int natom = fragments[0]->g_natom(); + const bool * const * const connectivity = fragments[0]->g_connectivity_pointer(); + + // each row is (potentially) a fragment + bool **frag_atoms = init_bool_matrix(natom,natom); + int nfrag=0, ifrag=0; + bool completed_fragment; + int start_search = 0; // fragment includes this atom + bool more_fragments = true; + + for (ifrag=0; more_fragments==true; ++ifrag) { + ++nfrag; + frag_atoms[ifrag][start_search] = true; //connected to self + + do { + completed_fragment = true; + for (i=0; ig_geom_const_pointer(); + double tval, min; + + for (int f2=0; f2connect(i,j); + } + } + } + // create fragment objects for distinct atom groups + else if (Opt_params.fragment_mode == OPT_PARAMS::MULTI) { + //cout << "DES: Multi mode" << endl; + double **geom = fragments[0]->g_geom(); + double **grad = fragments[0]->g_grad(); + double *Z = fragments[0]->g_Z(); + + for (ifrag=0; ifragglobalIndex[counter] = j; + counter++; + } + } + //double * tempZ = one_frag->g_Z(); + //for(int i=0; ig_geom_const_pointer(); + nA = Afrag->g_natom(); + cA = Afrag->g_connectivity_pointer(); + + B = Bfrag->g_geom_const_pointer(); + nB = Bfrag->g_natom(); + cB = Bfrag->g_connectivity_pointer(); + + if (Opt_params.interfragment_mode == OPT_PARAMS::FIXED) { + + min = 1e9; + for (int iA=0; iA < nA; ++iA) { + for (int iB=0; iB < nB; ++iB) { + tval = v3d_dist(A[iA],B[iB]); + if (tval < min) { + min = tval; + A1 = iA; + B1 = iB; + } + } + } + ndA = ndB = 1; + + fprintf(outfile,"\tClosest atoms between fragments is A %d, B %d\n", A1, B1); + + // A2 is bonded to A1, but A2-A1-B1 must not be collinear + for (int iA=0; iA < nA; ++iA) { + if (cA[iA][A1]) { + if (v3d_angle(B[B1],A[A1],A[iA], tval)) { + if (tval > Opt_params.interfrag_collinear_tol*_pi && tval < (1-Opt_params.interfrag_collinear_tol)*_pi) { + A2 = iA; + ++ndA; + break; + } + } + } + } + if (ndA == 1 && nA > 1) { + fprintf(outfile, "Fragment A has >1 atoms but no non-collinear atom found bonded to %d", A1+1); + sprintf(error_msg, "Fragment A has >1 atoms but no non-collinear atom found bonded to %d", A1+1); + INTCO_EXCEPT(error_msg, true); + } + + // B2 is bonded to B1, but A1-B1-B2 must not be collinear + for (int iB=0; iB < nB; ++iB) { + if (cB[iB][B1]) { + if (v3d_angle(A[A1],B[B1],B[iB],tval)) { + if (tval > Opt_params.interfrag_collinear_tol*_pi && tval < (1-Opt_params.interfrag_collinear_tol)*_pi) { + B2 = iB; + ++ndB; + break; + } + } + } + } + if (ndB == 1 && nB > 1) { + fprintf(outfile, "Fragment B has >1 atoms but no non-collinear atom found bonded to %d", B1+1); + sprintf(error_msg, "Fragment B has >1 atoms but no non-collinear atom found bonded to %d", B1+1); + INTCO_EXCEPT(error_msg,true); + } + + if (ndA == 2) { // we were able to locate a suitable A2 + // A3 is bonded to A2, but A3-A2-A1 must not be collinear + for (int iA=0; iA < nA; ++iA) { + if (iA != A1 && cA[iA][A2]) { + if (v3d_angle(A[A1],A[A2],A[iA], tval)) { + if (tval > Opt_params.interfrag_collinear_tol*_pi && tval < (1-Opt_params.interfrag_collinear_tol)*_pi) { + A3 = iA; + ++ndA; + break; + } + } + } + } + // if we couldn't find a 3rd atom bonded to A2, then look for a 3rd atom bonded to A1 + if (ndA != 3) { + for (int iA=0; iA < nA; ++iA) { + if (iA != A2 && cA[iA][A1]) { + if (v3d_angle(A[A1],A[A2],A[iA], tval)) { + if (tval > Opt_params.interfrag_collinear_tol*_pi && tval < (1-Opt_params.interfrag_collinear_tol)*_pi) { + A3 = iA; + ++ndA; + break; + } + } + } + } + } + } + + if (ndB == 2) { // we were able to locate a suitable B2 + // B3 is bonded to B2, but B3-B2-B1 must not be collinear + for (int iB=0; iB < nB; ++iB) { + if (iB != B1 && cB[iB][B2]) { + if (v3d_angle(B[B1],B[B2],B[iB],tval)) { + if (tval > Opt_params.interfrag_collinear_tol*_pi && tval < (1-Opt_params.interfrag_collinear_tol)*_pi) { + B3 = iB; + ++ndB; + break; + } + } + } + } + // if we couldn't find a 3rd atom bonded to B2, then look for a 3rd atom bonded to B1 + if (ndB != 3) { + for (int iB=0; iB < nB; ++iB) { + if (iB != B2 && cB[iB][B1]) { + if (v3d_angle(B[B1],B[B2],B[iB], tval)) { + if (tval > Opt_params.interfrag_collinear_tol*_pi && tval < (1-Opt_params.interfrag_collinear_tol)*_pi) { + B3 = iB; + ++ndB; + break; + } + } + } + } + } + } + // default weights are simply 1 to produce the reference points A1, A2, etc. + weight_A = init_matrix(3, nA); + weight_A[0][A1] = 1.0; + weight_A[1][A2] = 1.0; + weight_A[2][A3] = 1.0; + + weight_B = init_matrix(3, nB); + weight_B[0][B1] = 1.0; + weight_B[1][B2] = 1.0; + weight_B[2][B3] = 1.0; + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile, "\tReference points are linear combination on fragment A\n"); + print_matrix(outfile, weight_A, 3, nA); + fprintf(outfile, "\tReference points are linear combination on fragment B\n"); + print_matrix(outfile, weight_B, 3, nB); + } + INTERFRAG * one_IF = new INTERFRAG(Afrag, Bfrag, frag_i, frag_i+1, weight_A, weight_B, ndA, ndB); + + interfragments.push_back(one_IF); + + } // fixed interfragment coordinates + else if (Opt_params.interfragment_mode == OPT_PARAMS::PRINCIPAL_AXES) { + + // ref point A[0] and B[0] will be the centers of mass + // ref points A[1/2] and B[1/2] will on on principal axes + // nothing to compute now + if (nA == 1) + ndA = 1; + else if (nA == 2) // TODO check linearity + ndA = 2; + else { + ndA = 3; + } + + if (nB == 1) + ndB = 1; + else if (nB == 2) + ndB = 2; + else + ndA = 3; + + weight_A = weight_B = NULL; + + INTERFRAG * one_IF = new INTERFRAG(Afrag, Bfrag, frag_i, frag_i+1, NULL, NULL, ndA, ndB, true); + interfragments.push_back(one_IF); + + } + + /*else if (Opt_params.interfragment_mode == OPT_PARAMS::PRINCIPAL_AXES) { + + double **A_u = init_matrix(3,3); + double *A_lambda = init_array(3); + nA_lambda = Afrag->principal_axes(A, A_u, A_lambda); + + double **B_u = init_matrix(3,3); + double *B_lambda = init_array(3); + nB_lambda = Bfrag->principal_axes(B, B_u, B_lambda); + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile, "\tPrincipal axes on A\n"); + print_matrix(outfile, A_u, ndA, 3); + fprintf(outfile, "\tPrincipal axes on B\n"); + print_matrix(outfile, B_u, ndB, 3); + } + + free_matrix(A_u); + free_matrix(B_u); + free_array(A_lambda); + free_array(B_lambda); + }*/ + +// INTERFRAG * one_IF = new INTERFRAG(Afrag, Bfrag, frag_i, frag_i+1, weight_A, weight_B, ndA, ndB); +// +// interfragments.push_back(one_IF); + } + + fflush(outfile); +} + +} // namespace opt + diff --git a/optking/molecule_irc_step.cpp b/optking/molecule_irc_step.cpp new file mode 100644 index 0000000..7488911 --- /dev/null +++ b/optking/molecule_irc_step.cpp @@ -0,0 +1,160 @@ +/*! \file molecule.cc + \ingroup optking + \brief molecule class (really, molecular system class) +*/ + +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#include "linear_algebra.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +// compute change in energy according to quadratic approximation +inline double DE_nr_energy(double step, double grad, double hess) { + return (step * grad + 0.5 * step * step * hess); +} + +// see molecule_nr_step.cc and molecule_rfo_step.cc for examples from basic step types + +// we will assume for now at the IRC implies cartesian coordinates + +// Gonzalez and Schlegel JCP 2154 (1989). + +void MOLECULE::irc_step(void) { + + fprintf(outfile, "Hello World!"); + // Development plan + // 1. implement Eqn (2) scheme first: fixed step size s ; step in direction of -1*gradient + // 2. Muller and Brown (Figure 2) + // 3. Gonzalez and Schlegel version (Figure 3,4 Eqn. 4-11) + // 4. Interpolated guess at next point (Eqn. 12-15) + + // add 'step_type = IRC' user keyword + // see opt_params.h set_params.cc and psi4/src/bin/psi4/read_options.cc (look at 'RFO') + + // modify optking() to execute irc_step if step_type=IRC + + // read gradient/forces something like + // double *f_q = p_Opt_data->g_forces_pointer(); + + // see if we have any keyword for stepsize. Don't think so. + + // compute displacements dq Eqn. 2 + + // compute back-transformation code to get new cartesians from nr_step + + // symmetrize and save new geometry (same as in nr_step) + + + + // Need Hessian in mass-weighted cartesian coordinates. ? + // Read Hessian from opt_data. + // Mass-weight as follows: H_ixyz_jxyz' = H_ixyz_jxyz/ (sqrt(mass_i) sqrt(mass_j)) + // OPT_DATA::OPT_DATA needs modified to allocate Ncart X Ncart (or 3N by 3N) for + // cartesian optimizations + // other functions that read/write/update H will also need modified + // lets create an H_dim member of optdata class that is dimension of H for functions to use + + // first step is along the eigenvector belonging to the lowest eigenvalue + + + +/* copied and pasted from nr_step + int i, f; + int Nintco = g_nintco(); + double **H_inv; + + double *f_q = p_Opt_data->g_forces_pointer(); + double **H = p_Opt_data->g_H_pointer(); + double *dq = p_Opt_data->g_dq_pointer(); + + double *nr_u; // unit vector in step direction + double nr_dqnorm; // norm of step + double nr_g; // gradient in step direction + double nr_h; // hessian in step direction + double DE_projected; // projected energy change by quadratic approximation + + // Hinv f_q = dq + H_inv = symm_matrix_inv(H, Nintco, 1); + opt_matrix_mult(H_inv, 0, &f_q, 1, &dq, 1, Nintco, Nintco, 1, 0); + free_matrix(H_inv); + + // Zero steps for frozen fragment + for (f=0; fis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tZero'ing out displacements for frozen fragment %d\n", f+1); + for (i=0; ig_nintco(); ++i) + dq[ g_intco_offset(f) + i ] = 0.0; + } + } + + // applies maximum internal coordinate change + apply_intrafragment_step_limit(dq); + + // get norm |q| and unit vector in the step direction + nr_dqnorm = sqrt( array_dot(dq, dq, Nintco) ); + nr_u = init_array(Nintco); + array_copy(dq, nr_u, Nintco); + array_normalize(nr_u, Nintco); + + // get gradient and hessian in step direction + nr_g = -1 * array_dot(f_q, nr_u, Nintco); // gradient, not force + + nr_h = 0; + for (i=0; iis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tDisplacements for frozen fragment %d skipped.\n", f+1); + continue; + } + fragments[f]->displace(&(dq[g_intco_offset(f)]), true, g_intco_offset(f)); + } + + // do displacements for interfragment coordinates + double *q_target; + for (int I=0; Iintco_values(); + for (i=0; ig_nintco(); ++i) + q_target[i] += dq[g_interfragment_intco_offset(I) + i]; + + interfragments[I]->orient_fragment(q_target); + + free_array(q_target); + } + +#if defined(OPTKING_PACKAGE_QCHEM) +// // fix rotation matrix for rotations in QCHEM EFP code +// for (int I=0; Idisplace( I, &(dq[g_efp_fragment_intco_offset(I)]) ); +#endif + + //symmetrize_geom(); // now symmetrize the geometry for next step + + // save values in step data + p_Opt_data->save_step_info(DE_projected, nr_u, nr_dqnorm, nr_g, nr_h); + + free_array(nr_u); + fflush(outfile); +*/ +} + +} + diff --git a/optking/molecule_nr_step.cpp b/optking/molecule_nr_step.cpp new file mode 100644 index 0000000..e6ab4a4 --- /dev/null +++ b/optking/molecule_nr_step.cpp @@ -0,0 +1,114 @@ +/*! \file molecule.cc + \ingroup optking + \brief molecule class (really, molecular system class) +*/ + +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#include "linear_algebra.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +// compute change in energy according to quadratic approximation +inline double DE_nr_energy(double step, double grad, double hess) { + return (step * grad + 0.5 * step * step * hess); +} + +void MOLECULE::nr_step(void) { + int i, f; + int Nintco = g_nintco(); + double **H_inv; + + double *f_q = p_Opt_data->g_forces_pointer(); + double **H = p_Opt_data->g_H_pointer(); + double *dq = p_Opt_data->g_dq_pointer(); + + double *nr_u; // unit vector in step direction + double nr_dqnorm; // norm of step + double nr_g; // gradient in step direction + double nr_h; // hessian in step direction + double DE_projected; // projected energy change by quadratic approximation + + // Hinv f_q = dq + H_inv = symm_matrix_inv(H, Nintco, 1); + opt_matrix_mult(H_inv, 0, &f_q, 1, &dq, 1, Nintco, Nintco, 1, 0); + free_matrix(H_inv); + + // Zero steps for frozen fragment + for (f=0; fis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tZero'ing out displacements for frozen fragment %d\n", f+1); + for (i=0; ig_nintco(); ++i) + dq[ g_intco_offset(f) + i ] = 0.0; + } + } + + // applies maximum internal coordinate change + apply_intrafragment_step_limit(dq); + + // get norm |q| and unit vector in the step direction + nr_dqnorm = sqrt( array_dot(dq, dq, Nintco) ); + nr_u = init_array(Nintco); + array_copy(dq, nr_u, Nintco); + array_normalize(nr_u, Nintco); + + // get gradient and hessian in step direction + nr_g = -1 * array_dot(f_q, nr_u, Nintco); // gradient, not force + + nr_h = 0; + for (i=0; iis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tDisplacements for frozen fragment %d skipped.\n", f+1); + continue; + } + fragments[f]->displace(&(dq[g_intco_offset(f)]), true, g_intco_offset(f)); + } + + // do displacements for interfragment coordinates + double *q_target; + for (int I=0; Iintco_values(); + for (i=0; ig_nintco(); ++i) + q_target[i] += dq[g_interfragment_intco_offset(I) + i]; + + interfragments[I]->orient_fragment(q_target); + + free_array(q_target); + } + +#if defined(OPTKING_PACKAGE_QCHEM) +// // fix rotation matrix for rotations in QCHEM EFP code +// for (int I=0; Idisplace( I, &(dq[g_efp_fragment_intco_offset(I)]) ); +#endif + + //symmetrize_geom(); // now symmetrize the geometry for next step + + // save values in step data + p_Opt_data->save_step_info(DE_projected, nr_u, nr_dqnorm, nr_g, nr_h); + + free_array(nr_u); + fflush(outfile); +} + +} + diff --git a/optking/molecule_opt2.cpp b/optking/molecule_opt2.cpp new file mode 100644 index 0000000..e2f98e1 --- /dev/null +++ b/optking/molecule_opt2.cpp @@ -0,0 +1,597 @@ +/*! \file molecule.cc + \ingroup optking + \brief molecule class (really, molecular system class) +*/ + +#include "molecule.h" + +#include +#include + +#include "linear_algebra.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +//#if defined(OPTKING_PACKAGE_PSI) +//#include +//#elif defined(OPTKING_PACKAGE_QCHEM) +#include "cmath" +//#include "qcmath.h" +//#include "EFP.h" +//#endif + +namespace opt { + +using namespace std; + +// Adds one fragment with memory to accommodate the given number of atoms. +// Add EFP fragments which contains no atoms. +MOLECULE::MOLECULE(int num_atoms) { + + if (num_atoms > 0) { + FRAG *one_frag = new FRAG(num_atoms); + fragments.push_back(one_frag); + } + +#if defined(OPTKING_PACKAGE_QCHEM) +// fprintf(outfile,"\tCreating molecule with %d real atoms.\n", num_atoms); +// if (REM_EFP) { +// int num_efp = EFP::GetInstance()->NFragments(); +// +// for (int i=0; i= 2) { + fprintf(outfile, "B matrix\n"); + print_matrix(outfile, B, Nintco, Ncart); + } + + f_x = g_grad_array(); // Hartree / bohr + array_scm(f_x, -1, Ncart); // switch gradient -> forces + + temp_arr = init_array(Nintco); + opt_matrix_mult(B, 0, &f_x, 1, &temp_arr, 1, Nintco, Ncart, 1, 0); + free_array(f_x); + + G = init_matrix(Nintco, Nintco); + opt_matrix_mult(B, 0, B, 1, G, 0, Nintco, Ncart, Nintco, 0); + free_matrix(B); + + G_inv = symm_matrix_inv(G, Nintco, 1); + free_matrix(G); + + double * f_q = p_Opt_data->g_forces_pointer(); + opt_matrix_mult(G_inv, 0, &temp_arr, 1, &f_q, 1, Nintco, Nintco, 1, 0); + free_matrix(G_inv); + free_array(temp_arr); + +#if defined(OPTKING_PACKAGE_QCHEM) +// // append exernally determiend efp forces +// double * efp_force; +// for (int f=0; fget_forces_pointer(); +// for (int i=0; ig_nintco(); ++i) +// f_q[ g_efp_fragment_intco_offset(f) + i ] = efp_force[i] ; +// } +#endif + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile,"Internal forces in au\n"); + print_matrix(outfile, &f_q, 1, g_nintco()); fflush(outfile); + } + +/* + // test by transforming f_q back to cartesian forces and compare + if (Opt_params.print_lvl > 3) { + B = compute_B(); + temp_arr = init_array(Ncart); + opt_matrix_mult(B, 1, &f_q, 1, &temp_arr, 1, Ncart, Nintco, 1, 0); + fprintf(outfile,"Recomputed forces in cartesian coordinates\n"); + print_matrix(outfile, &temp_arr, 1, Ncart); + free_array(temp_arr); + free_matrix(B); + } +*/ + + fflush(outfile); + return ; +} + +// project redundancies (and constraints) out of forces and Hessian matrix +// add constraints here later +void MOLECULE::project_f_and_H(void) { + int Nintco = g_nintco(); + int Ncart = 3*g_natom(); + + // compute G = B B^t + double **G = init_matrix(Nintco, Nintco); + double **B = compute_B(); + opt_matrix_mult(B, 0, B, 1, G, 0, Nintco, Ncart, Nintco, 0); + free_matrix(B); + +#if defined (OPTKING_PACKAGE_QCHEM) +// // Put 1's on diagonal for EFP coordinates +// for (int I=0; Ig_nintco(); ++i) +// G[g_efp_fragment_intco_offset(I) + i][g_efp_fragment_intco_offset(I) + i] = 1.0; +#endif + + // compute P = G G^-1 + double **G_inv = symm_matrix_inv(G, Nintco, 1); + double **P = init_matrix(Nintco, Nintco); + opt_matrix_mult(G, 0, G_inv, 0, P, 0, Nintco, Nintco, Nintco, 0); + free_matrix(G); + free_matrix(G_inv); + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile,"\tProjection matrix for redundancies.\n"); + print_matrix(outfile, P, Nintco, Nintco); fflush(outfile); + } + + // add constraints to projection matrix + double **C = compute_constraints(); + + // P = P' - P' C (CPC)^-1 C P' + double **T = init_matrix(Nintco,Nintco); + double **T2 = init_matrix(Nintco,Nintco); + opt_matrix_mult(P, 0, C, 0, T, 0, Nintco, Nintco, Nintco, 0); + opt_matrix_mult(C, 0, T, 0, T2, 0, Nintco, Nintco, Nintco, 0); + double **T3 = symm_matrix_inv(T2, Nintco, 1); + + opt_matrix_mult( C, 0, P, 0, T, 0, Nintco, Nintco, Nintco, 0); + opt_matrix_mult(T3, 0, T, 0, T2, 0, Nintco, Nintco, Nintco, 0); + opt_matrix_mult( C, 0, T2, 0, T3, 0, Nintco, Nintco, Nintco, 0); + opt_matrix_mult( P, 0, T3, 0, T2, 0, Nintco, Nintco, Nintco, 0); + for (int i=0; ig_forces_pointer(); + // f_q~ = P f_q + double * temp_arr = init_array(Nintco); + opt_matrix_mult(P, 0, &f_q, 1, &temp_arr, 1, Nintco, Nintco, 1, 0); + array_copy(temp_arr, f_q, g_nintco()); + free_array(temp_arr); + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile,"\tInternal forces in au, after projection of redundancies and constraints.\n"); + if (Opt_params.efp_fragments) + fprintf(outfile,"\tEFP external coordinates are not projected.\n"); + print_matrix(outfile, &f_q, 1, g_nintco()); + } + + // Project redundances and constraints out of Hessian matrix + // Peng, Ayala, Schlegel, JCC 1996 give H -> PHP + 1000(1-P) + // The second term appears unnecessary and sometimes messes up Hessian updating. + + double **H = p_Opt_data->g_H_pointer(); + double **temp_mat = init_matrix(Nintco, Nintco); + opt_matrix_mult(H, 0, P, 0, temp_mat, 0, Nintco, Nintco, Nintco, 0); + opt_matrix_mult(P, 0, temp_mat, 0, H, 0, Nintco, Nintco, Nintco, 0); + free_matrix(temp_mat); + +/* 2nd term unnecessary + for (int i=0; i= 2) { + fprintf(outfile,"Projected (PHP) Hessian matrix\n"); +// if (Opt_params.efp_fragments) +// fprintf(outfile,"EFP external coordinates are not projected.\n"); + print_matrix(outfile, H, g_nintco(), g_nintco()); + } + free_matrix(P); + fflush(outfile); +} + +void MOLECULE::print_geom(void) { + fprintf(outfile,"\tCartesian Geometry (au)\n"); + fflush(outfile); + for (int i=0; iprint_geom(outfile); +} + +void MOLECULE::apply_intrafragment_step_limit(double * & dq) { + int i, f; + double scale = 1.0; + double limit = Opt_params.intrafragment_step_limit; + + for (f=0; fg_nintco(); ++i) + if (scale * fabs(dq[g_intco_offset(f)+i]) > limit) + scale = limit / fabs(dq[g_intco_offset(f)+i]); + + if (scale != 1.0) { + fprintf(outfile,"\tChange in coordinate exceeds step limit of %10.5lf.\n", limit); + fprintf(outfile,"\tScaling displacements by %10.5lf\n", scale); + + for (f=0; fg_nintco(); ++i) + dq[g_intco_offset(f)+i] *= scale; + } + fflush(outfile); +} + +// don't let any angles get smaller than 0.0 +void MOLECULE::check_intrafragment_zero_angles(double const * const dq) { + for (int f=0; fcheck_zero_angles(&(dq[g_intco_offset(f)])); +} + +void MOLECULE::H_guess(void) const { + double **H = p_Opt_data->g_H_pointer(); + + if (Opt_params.intrafragment_H == OPT_PARAMS::SCHLEGEL) + fprintf(outfile,"\tGenerating empirical Hessian (Schlegel '84) for each fragment.\n"); + else if (Opt_params.intrafragment_H == OPT_PARAMS::FISCHER) + fprintf(outfile,"\tGenerating empirical Hessian (Fischer & Almlof '92) for each fragment.\n"); + + for (int f=0; fH_guess(); + + for (int i=0; ig_nintco(); ++i) + for (int j=0; jg_nintco(); ++j) + H[g_intco_offset(f) + i][g_intco_offset(f) + j] = H_frag[i][j]; + + free_matrix(H_frag); + } + + for (int I=0; IH_guess(); + + for (int i=0; ig_nintco(); ++i) + for (int j=0; jg_nintco(); ++j) + H[g_interfragment_intco_offset(I) + i][g_interfragment_intco_offset(I) + j] = + H_interfrag[i][j]; + + free_matrix(H_interfrag); + } + +#if defined(OPTKING_PACKAGE_QCHEM) +// for (int I=0; IH_guess(); +// +// for (int i=0; ig_nintco(); ++i) +// for (int j=0; jg_nintco(); ++j) +// H[g_efp_fragment_intco_offset(I) + i][g_efp_fragment_intco_offset(I) + j] = H_efp_frag[i][j]; +// +// free_matrix(H_efp_frag); +// } +#endif + + if (Opt_params.print_lvl >= 2) { + fprintf(outfile,"Initial Hessian guess\n"); + print_matrix(outfile, H, g_nintco(), g_nintco()); + } + fflush(outfile); + return; +} + +bool MOLECULE::cartesian_H_to_internals(void) const { + int Nintco = g_nintco(); + int Ncart = 3*g_natom(); + bool success = true; // to be dynamic later + + double **H_int = p_Opt_data->g_H_pointer(); + + // compute A = u B^t (B u B^t)^-1 where u=unit matrix and -1 is generalized inverse + double **B = compute_B(); + double **G = init_matrix(Nintco, Nintco); + opt_matrix_mult(B, 0, B, 1, G, 0, Nintco, Ncart, Nintco, 0); + + double **G_inv = symm_matrix_inv(G, Nintco, true); + free_matrix(G); + + double **A = init_matrix(Ncart, Nintco); + opt_matrix_mult(B, 1, G_inv, 0, A, 0, Ncart, Nintco, Nintco, 0); + free_matrix(G_inv); + free_matrix(B); + + // compute gradient in internal coordinates, A^t g_x = g_q + double *grad_x = g_grad_array(); + double *grad_q = init_array(Nintco); + opt_matrix_mult(A, 1, &grad_x, 1, &grad_q, 1, Nintco, Ncart, 1, 0); + free_array(grad_x); + + // read in cartesian H + //double **H_cart = p_Opt_data->read_cartesian_H(); + double **H_cart; + std::cout << "DES Error: Cant't read in hessian" << std::endl; + exit(-1); + + // transform cartesian H to internals; A^t (H_x - K) A + // K_ij = sum_q ( grad_q[q] d^2(q)/(dxi dxj) ) + double **dq2dx2; + + for (int q=0; q= 3) { + fprintf(outfile, "Hessian transformed to internal coordinates:\n"); + print_matrix(outfile, H_int, Nintco, Nintco); fflush(outfile); + } + + // Check by transforming internal coordinate Hessian back into cartesian coordinates: +/* + B = compute_B(); + temp_mat = init_matrix(Ncart, Nintco); + opt_matrix_mult(B, 1, H_int, 0, temp_mat, 0, Ncart, Nintco, Nintco, 0); + H_cart = init_matrix(Ncart, Ncart); + opt_matrix_mult(temp_mat, 0, B, 0, H_cart, 0, Ncart, Nintco, Ncart, 0); + free_matrix(temp_mat); + + for (int q=0; qcompute_B(); + + for (i=0; ig_nintco(); ++i) { + for (j=0; jg_natom(); ++j) { + for(int k=0;k<3;k++) { + B[g_intco_offset(f)+i][3*fragments[f]->globalIndex[j]+k] = B_frag[i][3*j+k]; + } + } + } + + free_matrix(B_frag); + } + + for (int I=0; Icompute_B(); // ->g_nintco() X (3*atom A)+3(natom_B) + + int iA = interfragments[I]->g_A_index(); + int iB = interfragments[I]->g_B_index(); + int nA = interfragments[I]->g_natom_A(); + int nB = interfragments[I]->g_natom_B(); + + for (i=0; ig_nintco(); ++i) { // for each of up to 6 coordinates + + for (j=0; j<3*nA; ++j) + B[g_interfragment_intco_offset(I)+i][3*g_atom_offset(iA)+j] = B_inter[i][j]; + + for (j=0; j<3*nB; ++j) + B[g_interfragment_intco_offset(I)+i][3*g_atom_offset(iB)+j] = B_inter[i][3*nA+j]; + + } + free_matrix(B_inter); + } + return B; +} + +double ** MOLECULE::compute_derivative_B(int intco_index) const { + int cnt_intcos = 0; + int fragment_index = -1; + int coordinate_index = 0; + bool is_interfragment = true; + int f; + + for (f=0; fg_nintco(); ++i) { + if (cnt_intcos++ == intco_index) { + fragment_index = f; + coordinate_index = i; + is_interfragment = false; + break; + } + } + } + + if (is_interfragment) { // intco_index not yet found + for (f=0; fg_nintco(); ++i) { + if (cnt_intcos++ == intco_index) { + fragment_index = f; + coordinate_index = i; + break; + } + } + } + } + + if (fragment_index == -1) + throw(INTCO_EXCEPT("MOLECULE::compute_derivative_B() could not find intco_index")); + + double **dq2dx2_frag; + + double **dq2dx2 = init_matrix(3*g_natom(), 3*g_natom()); + + if (!is_interfragment) { + dq2dx2_frag = fragments[fragment_index]->compute_derivative_B(coordinate_index); + // dimension is 2x2, 3x3 or 4x4 and given by natom_intco + int natom_intco = fragments[fragment_index]->g_intco_natom(coordinate_index); + int atom_a, atom_b; + + for (int a=0; ag_intco_atom(coordinate_index, a); + for (int b=0; bg_intco_atom(coordinate_index, b); + + for (int xyz_a=0; xyz_a<3; ++xyz_a) + for (int xyz_b=0; xyz_b<3; ++xyz_b) + dq2dx2[3*atom_a + xyz_a][3*atom_b + xyz_b] = dq2dx2_frag[3*a+xyz_a][3*b+xyz_b]; + + } + } + free_matrix(dq2dx2_frag); + } + else { // interfragment cordinate + dq2dx2_frag = interfragments[fragment_index]->compute_derivative_B(coordinate_index); + + // dimension is (3*natomA + 3*natomB) x (3*natomA + 3*natomB) -> 3*natom X 3*natom + int nA = interfragments[fragment_index]->g_natom_A(); + int nB = interfragments[fragment_index]->g_natom_B(); + int iA = 3*g_atom_offset(interfragments[fragment_index]->g_A_index()); + int iB = 3*g_atom_offset(interfragments[fragment_index]->g_B_index()); + + //print_matrix(outfile,dq2dx2_frag, 3*(nA+nB), 3*(nA+nB)); + for (int a=0; a<3*nA; ++a) // A-A block + for (int aa=0; aa<3*nA; ++aa) + dq2dx2[iA + a][iA + aa] = dq2dx2_frag[a][aa]; + + for (int a=0; a<3*nA; ++a) // A-B block + for (int bb=0; bb<3*nB; ++bb) + dq2dx2[iA + a][iB + bb] = dq2dx2_frag[a][3*nA + bb]; + + for (int b=0; b<3*nB; ++b) // B-A block + for (int aa=0; aa<3*nA; ++aa) + dq2dx2[iB + b][iA + aa] = dq2dx2_frag[3*nA + b][aa]; + + for (int b=0; b<3*nB; ++b) // B-B block + for (int bb=0; bb<3*nB; ++bb) + dq2dx2[iB + b][iB + bb] = dq2dx2_frag[3*nA + b][3*nA + bb]; + + free_matrix(dq2dx2_frag); + } + return dq2dx2; +} + +// print internal coordinates to text file +void MOLECULE::print_intco_dat(FILE *fp_intco) { + for (int i=0; ig_natom()); fflush(outfile); + fragments[i]->print_intco_dat(fp_intco, g_atom_offset(i)); + } + + for (int I=0; Ig_A_index(); + int frag_b = interfragments[I]->g_B_index(); + fprintf(fp_intco,"I %d %d\n", frag_a+1, frag_b+1); fflush(outfile); + + for (int i=0; i<6; ++i) + fprintf(fp_intco," %d", (int) interfragments[I]->coordinate_on(i)); + fprintf(fp_intco,"\n"); fflush(outfile); + + interfragments[I]->print_intco_dat(fp_intco, g_atom_offset(frag_a), g_atom_offset(frag_b)); + } +} + +// tell whether internal coordinate is frozen +double ** MOLECULE::compute_constraints(void) { + double **C, **C_frag, **C_inter; + int i, j; + + C = init_matrix(g_nintco(), g_nintco()); + + for (int f=0; fcompute_constraints(); + + for (i=0; ig_nintco(); ++i) + for (j=0; jg_nintco(); ++j) + C[g_intco_offset(f)+i][g_intco_offset(f)+j] = C_frag[i][j]; + + free_matrix(C_frag); + } + + for (int I=0; Icompute_constraints(); // g_nintco() X g_nintco + + for (i=0; ig_nintco(); ++i) + for (j=0; jg_nintco(); ++j) + C[g_interfragment_intco_offset(I)+i][g_interfragment_intco_offset(I)+j] = C_inter[i][j]; + + free_matrix(C_inter); + } + + if (Opt_params.print_lvl >= 2) { + fprintf(outfile,"Constraint matrix\n"); + print_matrix(outfile, C, g_nintco(), g_nintco()); fflush(outfile); + } + fflush(outfile); + return C; +} + +// The values of the EFP coordinates will be taken to be the total change +// since the beginning of the optimization. These values are determined +// from the data in opt_data after that data is read. +//void MOLECULE::update_efp_values(void) { +// for (int i=0; ig_iteration(); ++iter) { +// dq = p_Opt_data->g_dq_pointer(iter); +// for (int coord=0; coord < 6; ++coord) +// vals[coord] += dq[g_efp_fragment_intco_offset(i)+coord] ; +// } +// efp_fragments[i]->set_values(vals); +// free_array(vals); +// } +//} + +} + diff --git a/optking/molecule_prfo_step.cpp b/optking/molecule_prfo_step.cpp new file mode 100644 index 0000000..1211366 --- /dev/null +++ b/optking/molecule_prfo_step.cpp @@ -0,0 +1,273 @@ +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#include "linear_algebra.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +// compute change in energy according to P-RFO approximation +// see J. Phys. Chem. 1985, 89, 52-57 +inline double DE_rfo_energy(double rfo_t, double rfo_g, double rfo_h) { + return (rfo_t * rfo_g + 0.5 * rfo_t * rfo_t * rfo_h)/(1 + rfo_t*rfo_t); +} + +void MOLECULE::prfo_step(void) { + double **Horig = p_Opt_data->g_H_pointer(); + double *f_q = p_Opt_data->g_forces_pointer(); + double *dq = p_Opt_data->g_dq_pointer(); + int Nintco = g_nintco(); + int rfo_root; // ultimately, should be array of roots to maximize + int cnt_i, cnt_j; + + // don't use Horig anymore -it's the pointer to the good, original Hessian + double **H = matrix_return_copy(Horig, Nintco, Nintco); + + fprintf(outfile,"\nHessian matrix\n"); + print_matrix(outfile, H, Nintco, Nintco); + + // diagonalize H (technically, only have to semi-diagonalize) + double * lambda = init_array(Nintco); + opt_symm_matrix_eig(H, Nintco, lambda); + double **H_evects = H; // rename for clarity + + fprintf(outfile,"\n\tEigenvalues of Hessian \n"); + print_matrix(outfile, &lambda, 1, Nintco); + fprintf(outfile, "\n\tEigenvectors of Hessian (rows) \n"); + print_matrix(outfile, H_evects, Nintco, Nintco); + + // construct diagonalized Hessian with evals on diagonal + double **H_diag = init_matrix(Nintco,Nintco); + for (int i=0; ig_iteration() == 1) { + rfo_root = 0; + // in future change to allow user to specify + fprintf(outfile,"\tMaximizing along lowest eigenvalue of Hessian.\n"); + } + else { // do root following + double * rfo_old_evect = p_Opt_data->g_rfo_eigenvector_pointer(); + double max_overlap = 0; + for (int i=0; i max_overlap) { + max_overlap = tval; + rfo_root = i; + } + } + fprintf(outfile,"\tMaximizing along Hessian eigenvalue %d whose \ + eigenvector has maximal overlap with previous step.\n", rfo_root+1); + } + p_Opt_data->set_rfo_eigenvector(H_diag[rfo_root]); + + // transform gradient + double *f_q_Hevect_basis = init_array(Nintco); + opt_matrix_mult(H_evects, 0, &f_q, 1, &f_q_Hevect_basis, 1, Nintco, Nintco, 1, 0); + + // Build RFO-max. + double **rfo_max = init_matrix(mu+1, mu+1); + + rfo_max[0][0] = H_diag[rfo_root][rfo_root]; + + rfo_max[0][1] = -f_q_Hevect_basis[rfo_root]; + rfo_max[1][0] = -f_q_Hevect_basis[rfo_root]; + + fprintf(outfile,"\n RFO max \n"); + print_matrix(outfile,rfo_max,mu+1,mu+1); + + // Build RFO-min. + double **rfo_min = init_matrix(Nintco-mu+1,Nintco-mu+1); + cnt_i = 0; + for (int i=0; i Opt_params.rfo_normalization_min) { + for (int j=0; j= 3) { + fprintf(outfile,"\n RFO_max eigenvectors (rows)\n"); + print_matrix(outfile, rfo_max, mu+1, mu+1); + } + + //rfo_min contains normalized eigenvectors as rows + for (int i=0; i Opt_params.rfo_normalization_min) { + for (int j=0;j= 3) { + fprintf(outfile,"\nRFO_min eigenvectors (rows)\n"); + print_matrix(outfile, rfo_min, Nintco-mu+1, Nintco-mu+1); + } + + double * rfo_step_Hevect_basis = init_array(Nintco); + + // extract step with highest eigenvalue? + rfo_step_Hevect_basis[rfo_root] = rfo_max[mu][0]; // drop last (2nd) entry + + // extract step with lowest eigenvalue + cnt_i = 0; + for (int i=0; iis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tDisplacements for frozen fragment %d skipped.\n", f+1); + continue; + } + fragments[f]->displace(&(dq[g_intco_offset(f)]), true, g_intco_offset(f)); + } + + // do interfragment displaceements + double *q_target; + for (int I=0; Iintco_values(); + for (int i=0; ig_nintco(); ++i) + q_target[i] += dq[g_interfragment_intco_offset(I) + i]; + + interfragments[I]->orient_fragment(q_target); + + free_array(q_target); + } + +#if defined(OPTKING_PACKAGE_QCHEM) +// // fix rotation matrix for rotations in QCHEM EFP code +// for (int I=0; Idisplace( I, &(dq[g_efp_fragment_intco_offset(I)]) ); +#endif + + //symmetrize_geom(); // now symmetrize the geometry for next step + + // save values in step data + p_Opt_data->save_step_info(DE_projected, dq, rfo_dqnorm, rfo_g, rfo_h); + + fflush(outfile); + return; +} + +} + diff --git a/optking/molecule_read_intcos.cpp b/optking/molecule_read_intcos.cpp new file mode 100644 index 0000000..a52798a --- /dev/null +++ b/optking/molecule_read_intcos.cpp @@ -0,0 +1,413 @@ +/*! \file molecule_read_intcos.cc + \ingroup optking + \brief read internal coordinates from file + + MOLECULE::read_intcos(void) reads internal coordinates from text file + return false if coordinates cannot be read - possibly b/c they are not there +*/ + +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#define EXTERN +#include "globals.h" +// maximum number of atoms that can be used to define a referent point +#define MAX_REF_ATOM_INTCO (20) + +namespace opt { + +using namespace std; + +// convert string to integer +bool stoi(string s, int *a); + +// convert string to boolean +bool stob(string s, bool *a); + +// check string for trailing "*". If present, remove it and return true +bool has_asterisk(string & s); + +bool myline(ifstream & fin, vector & tokens, int & line_num); + +// clear tokens +// read line and tokenize it into tokens +// lines beginning with % or empty lines are skipped/ignored +// return false, if no more lines +bool myline(ifstream & fin, vector & tokens, int & line_num) { + string sline; + stringstream streamline; + bool read_next = true; + bool line_present = false; + + tokens.clear(); + + while (read_next && !fin.eof()) { + line_present = getline(fin, sline); + //printf("getline read: %s\n", sline.c_str()); + read_next = false; + + if (line_present) { + ++line_num; + streamline << sline; + while(streamline >> sline) + tokens.push_back(sline); + + if (tokens.empty()) { + tokens.clear(); + streamline.clear(); + read_next = true; + } + else if (tokens[0][0] == '%') { + tokens.clear(); + streamline.clear(); + read_next = true; + } + else + return true; + } + } + //printf("myline returns false\n"); + return false; +} + +bool MOLECULE::read_intcos(std::ifstream & fintco) { + stringstream error; + int a, b, natom, line_num=0; + bool D_on[6]; // interfragment coordinates active + bool D_frozen[6]; // interfragment coordinates frozen + FRAG * frag1; + int first_atom, last_atom; + int first_frag, second_frag; + vector vline; + vector A1; vector A2; vector A3; + vector B1; vector B2; vector B3; + int ndA=0, ndB=0; + + bool line_present = false; + + // read in line and tokenize + line_present = myline(fintco, vline, line_num); + + int cnt =0; + + while (line_present) { + + if ((vline[0] == "F") || (vline[0] == "F*")) { // read first and last atom for fragment + bool frozen = has_asterisk(vline[0]); + + if (vline.size() != 3) { + error << "Format of fragment line is \"F integer(1st_atom) integer(last_atom)\", line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + if ( !stoi(vline[1], &first_atom) || !stoi(vline[2], &last_atom)) { + error << "Format of fragment line is \"F integer(1st_atom) integer(last_atom)\", line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + --first_atom; // start at 0 internally + --last_atom; + if (first_atom > last_atom) { + error << "Last atom must be greater than first atom, line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + + // create fragment + frag1 = new FRAG(last_atom - first_atom + 1); + if (frozen) frag1->freeze(); + fragments.push_back(frag1); + + // now read all internal coordinates for that fragment + line_present = myline(fintco, vline, line_num); + bool end_of_fragment = false; + while(line_present && !end_of_fragment) { + if (fragments.back()->read_intco(vline, first_atom)) + line_present = myline(fintco, vline, line_num); + else + end_of_fragment = true; // break out of fragment reading lines + } + + if (!line_present) // no more lines + return true; + } + else if (vline[0] == "I" || vline[0] == "I*") { // read interfragment definition + bool frozen_I = has_asterisk(vline[0]); + if (vline.size() != 3) { + error << "Format of interfragment line is \"I integer(1st_frag) integer(2nd_frag)\" in line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + if ( !stoi(vline[1], &first_frag) || !stoi(vline[2], &second_frag) ) { + error << "Format of interfragment line is \"I integer(1st_frag) integer(2nd_frag)\" in line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + --first_frag; + --second_frag; + if ( first_frag >= fragments.size() || second_frag >= fragments.size()) { + error << "Fragments can only be referenced if already defined, error in line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + + // read mandatory line with 6 booleans + line_present = myline(fintco, vline, line_num); + if (!line_present) { + error << "Missing line " << line_num+1 << " to indicate with six 1/0's which coordinates are active.\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + if (vline.size() != 6 ) { + error << "Indicate with _six_ 1/0's which coordinates are active, error in line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + for (int i=0; i<6; ++i) { + D_frozen[i] = has_asterisk(vline[i]); + if (!stob(vline[i], &(D_on[i]))) { + error << "Indicate with six 1/0's which coordinates are active, error in line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + } + if (frozen_I) { // freeze fragment; override other + for (int i=0; i<6; ++i) D_frozen[i] = true; + } + + A1.clear(); A2.clear(); A3.clear(); + B1.clear(); B2.clear(); B3.clear(); + + line_present = myline(fintco, vline, line_num); + bool end_of_if = false; + + while (line_present && !end_of_if) { + + if (vline[0] == "A1" || vline[0] == "A2" || vline[0] == "A3" || + vline[0] == "B1" || vline[0] == "B2" || vline[0] == "B3") { + + if (vline.size() < 2) { + error << "Missing atoms list for reference atom, error in line" << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + + for (int i=1; ig_natom()); + double **weightB = init_matrix(ndB, fragments[second_frag]->g_natom()); + + if (ndA > 0) { + for (int i=0; i 1) { + for (int i=0; i 2) { + for (int i=0; i 0) { + for (int i=0; i 1) { + for (int i=0; i 2) { + for (int i=0; ifreeze(D_frozen); + } // end of if vline[0] == 'I' + else { + error << "Unknown initial character on line " << line_num << ".\n"; + throw(INTCO_EXCEPT(error.str().c_str())); + } + } + + return true; +} // end MOLECULE::read_intcos + + +// this function belongs to the FRAG class - not MOLECULE but the reading of the intco +// definitions is so linked with that above, I'll put the function here +// reads internal coordinate definition line +// offset is the first atom number in the fragment so fragment can store relative numbering +bool FRAG::read_intco(vector & s, int offset) { + int a, b, c, d; + std::string error; + + bool frozen=false; + frozen = has_asterisk(s[0]); // removes asterisk + + if ((s[0] == "R") || (s[0] == "H")) { + if (s.size() != 3) + throw(INTCO_EXCEPT("Format of stretch entry is \"R atom_1 atom_2\"")); + if ( !stoi(s[1], &a) || !stoi(s[2], &b) ) + throw(INTCO_EXCEPT("Format of stretch entry is \"R atom_1 atom_2\"")); + --a; --b; + + STRE *one_stre = new STRE(a-offset, b-offset, frozen); + if (s[0] == "H") one_stre->make_hbond(); + + if ( !present(one_stre) ) + intcos.push_back(one_stre); + else + delete one_stre; + + return true; + } + else if ((s[0] == "B") || (s[0] == "L")) { + if (s.size() != 4) + throw(INTCO_EXCEPT("Format of bend entry is \"B atom_1 atom_2 atom_3\"")); + if ( !stoi(s[1], &a) || !stoi(s[2], &b) || !stoi(s[3], &c) ) + throw(INTCO_EXCEPT("Format of bend entry is \"B atom_1 atom_2 atom_3\"")); + --a; --b; --c; + + BEND *one_bend = new BEND(a-offset, b-offset, c-offset, frozen); + if (s[0] == "L") one_bend->make_linear_bend(); + + if ( !present(one_bend) ) + intcos.push_back(one_bend); + else + delete one_bend; + + return true; + } + else if (s[0] == "D") { + if (s.size() != 5) + throw(INTCO_EXCEPT("Format of dihedral entry is \"D atom_1 atom_2 atom_3 atom_4\"")); + if ( !stoi(s[1], &a) || !stoi(s[2], &b) || !stoi(s[3], &c) || !stoi(s[4], &d) ) + throw(INTCO_EXCEPT("Format of dihedral entry is \"D atom_1 atom_2 atom_3 atom_4\"")); + --a; --b; --c; --d; + + TORS *one_tors = new TORS(a-offset, b-offset, c-offset, d-offset, frozen); + + if ( !present(one_tors) ) + intcos.push_back(one_tors); + else + delete one_tors; + + return true; + } + //printf("read_intco returning false\n"); + return false; +} + +// convert string to integer +bool stoi(string s, int *a) { + int i = atoi(s.c_str()); + if (i!=0) { + *a = i; + return true; + } + return false; +} + +// convert string to boolean +bool stob(string s, bool *a) { + if (s == "1") { + *a = true; + return true; + } + else if (s == "0") { + *a = false; + return true; + } + else + return false; +} + +// removes asterisk and returns true if it was present +bool has_asterisk(string & s) { + if (s[s.size()-1] == '*') { + s.erase(s.size()-1); + return true; + } + else + return false; +} + +} // namespace opt + diff --git a/optking/molecule_rfo_step.cpp b/optking/molecule_rfo_step.cpp new file mode 100644 index 0000000..6541977 --- /dev/null +++ b/optking/molecule_rfo_step.cpp @@ -0,0 +1,185 @@ +/*! \file molecule.cc + \ingroup optking + \brief molecule class (really, molecular system class) +*/ + +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#include "linear_algebra.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +// compute change in energy according to RFO approximation +inline double DE_rfo_energy(double rfo_t, double rfo_g, double rfo_h) { + return (rfo_t * rfo_g + 0.5 * rfo_t * rfo_t * rfo_h)/(1 + rfo_t*rfo_t); +} + +// Take Rational Function Optimization step +void MOLECULE::rfo_step(void) { + int i, j; + int dim = g_nintco(); + double tval, tval2; + double *f_q = p_Opt_data->g_forces_pointer(); + double **H = p_Opt_data->g_H_pointer(); + double *dq = p_Opt_data->g_dq_pointer(); +fprintf(outfile,"doing rfo_step\n"); fflush(outfile); + + // build (lower-triangle of) RFO matrix and diagonalize + double **rfo_mat = init_matrix(dim+1, dim+1); + for (i=0; i= 3) { + fprintf(outfile,"RFO mat\n"); + print_matrix(outfile, rfo_mat, dim+1, dim+1); + } + + double *lambda = init_array(dim+1); + opt_symm_matrix_eig(rfo_mat, dim+1, lambda); + if (Opt_params.print_lvl >= 2) { + fprintf(outfile,"RFO eigenvalues/lambdas\n"); + print_matrix(outfile, &(lambda), 1, dim+1); + } + + // Do intermediate normalization. + // RFO paper says to scale eigenvector to make the last element equal to 1. + // During the course of an optimization some evects may appear that are bogus leads + // - the root following can avoid them. + for (i=0; i Opt_params.rfo_normalization_min) { + for (j=0;j= 3) { + fprintf(outfile,"RFO eigenvectors (rows)\n"); + print_matrix(outfile, rfo_mat, dim+1, dim+1); + } + + int rfo_root, f; + double rfo_eval; + double *rfo_u; // unit vector in step direction + double rfo_dqnorm; // norm of step + double rfo_g; // gradient in step direction + double rfo_h; // hessian in step direction + double DE_projected; // projected energy change by quadratic approximation + + // *** choose which RFO eigenvector to use + // if not root following, then use rfo_root'th lowest eigenvalue; default is 0 (lowest) + if ( (!Opt_params.rfo_follow_root) || (p_Opt_data->g_iteration() == 1)) { + rfo_root = Opt_params.rfo_root; + fprintf(outfile,"\tFollowing RFO solution %d.\n", rfo_root); + } + else { // do root following + double * rfo_old_evect = p_Opt_data->g_rfo_eigenvector_pointer(); + tval = 0; + for (i=0; i tval) { + tval = tval2; + rfo_root = i; + } + } + fprintf(outfile,"RFO vector %d has maximal overlap with previous step\n", rfo_root+1); + } + p_Opt_data->set_rfo_eigenvector(rfo_mat[rfo_root]); + + // print out lowest energy evects + if (Opt_params.print_lvl >= 2) { + for (i=0; iis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tZero'ing out displacements for frozen fragment %d\n", f+1); + for (i=0; ig_nintco(); ++i) + dq[ g_intco_offset(f) + i ] = 0.0; + } + } + + apply_intrafragment_step_limit(dq); + //check_intrafragment_zero_angles(dq); + + // get norm |dq| and unit vector in the step direction + rfo_dqnorm = sqrt( array_dot(dq, dq, dim) ); + rfo_u = init_array(dim); + array_copy(rfo_mat[rfo_root], rfo_u, dim); + array_normalize(rfo_u, dim); + free_matrix(rfo_mat); + + // get gradient and hessian in step direction + rfo_g = -1 * array_dot(f_q, rfo_u, dim); + rfo_h = 0; + for (i=0; iis_frozen() || Opt_params.freeze_intrafragment) { + fprintf(outfile,"\tDisplacements for frozen fragment %d skipped.\n", f+1); + continue; + } + fragments[f]->displace(&(dq[g_intco_offset(f)]), true, g_intco_offset(f)); + } + + // do displacements for interfragment coordinates + double *q_target; + for (int I=0; Iintco_values(); + for (i=0; ig_nintco(); ++i) + q_target[i] += dq[g_interfragment_intco_offset(I) + i]; + + interfragments[I]->orient_fragment(q_target); + + free_array(q_target); + } + +#if defined(OPTKING_PACKAGE_QCHEM) +// // fix rotation matrix for rotations in QCHEM EFP code +// for (int I=0; Idisplace( I, &(dq[g_efp_fragment_intco_offset(I)]) ); +#endif + + //symmetrize_geom(); // now symmetrize the geometry for next step + + // save values in step data + p_Opt_data->save_step_info(DE_projected, rfo_u, rfo_dqnorm, rfo_g, rfo_h); + + free_array(rfo_u); + fflush(outfile); + +} // end take RFO step + +} + diff --git a/optking/molecule_tests.cpp b/optking/molecule_tests.cpp new file mode 100644 index 0000000..2a8f757 --- /dev/null +++ b/optking/molecule_tests.cpp @@ -0,0 +1,209 @@ +/*! \file molecule.cc + \ingroup optking + \brief molecule class (really, molecular system class) +*/ + +#include "molecule.h" + +#include "cmath" +//#include "qcmath.h" +#include +#include + +#include "linear_algebra.h" +#include "print.h" +#include "atom_data.h" +#include "physconst.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +using namespace std; + +// test the analytic B matrix (and displacement code) by comparing +// analytic DqDx to finite-difference DqDx +void MOLECULE::test_B(void) { + int Natom = g_natom(); + int Nintco = g_nintco(); + const double disp_size = 0.01; + // 5-point formula should be good to h^4; a few will be slightly worse + const double MAX_ERROR = 50*disp_size*disp_size*disp_size*disp_size; + + fprintf(outfile,"\n\tTesting B-matrix numerically...\n"); + + double **B_analytic = compute_B(); + + if (Opt_params.print_lvl >= 3) { + fprintf(outfile, "Analytic B matrix in au\n"); + print_matrix(outfile, B_analytic, Nintco, 3*Natom); + fflush(outfile); + } + + double **coord, *q_p, *q_m, **B_fd; + double *q_p2, *q_m2; + + B_fd = init_matrix(Nintco, 3*Natom); + coord = g_geom_2D(); // in au + + try { + + for (int atom=0; atom= 3) { + fprintf(outfile,"\nNumerical B matrix in au, disp_size = %lf\n",disp_size); + print_matrix(outfile, B_fd, Nintco, 3*Natom); + fflush(outfile); + } + + double max_error = -1.0; + int max_error_intco = -1; + for (int i=0; i max_error ) { + max_error = fabs(B_analytic[i][j] - B_fd[i][j]); + max_error_intco = i; + } + + fprintf(outfile,"\t\tMaximum difference is %.1e for internal coordinate %d.\n", + max_error, max_error_intco+1); + if (max_error > MAX_ERROR) { + fprintf(outfile, "\t\tB-matrix could be in error. However, numerical test will fail for "); + fprintf(outfile, "linear bond angles. This is OK.\n"); + } + else { + fprintf(outfile,"\t...Passed.\n"); + } + + free_matrix(B_analytic); + free_matrix(B_fd); + fflush(outfile); + return; +} + +void MOLECULE::test_derivative_B(void) { + int Natom = g_natom(); + int Nintco = g_nintco(); + const double disp_size = 0.01; + // 5-point formula should be good to h^4; a few will be slightly worse + const double MAX_ERROR = 10*disp_size*disp_size*disp_size*disp_size; + + bool warn; + double **coord, *q; + double **dq2dx2_analytic, **dq2dx2_fd; + + dq2dx2_fd = init_matrix(3*Natom, 3*Natom); + coord = g_geom_2D(); // in au + + q = intco_values(coord); // necesessary to set torsional near-180 variables? + + fprintf(outfile,"\n\tTesting Derivative B-matrix numerically...\n"); + for (int i=0; i= 3) { + fprintf(outfile, "Analytic B' (Dq2Dx2) matrix in au\n"); + print_matrix(outfile, dq2dx2_analytic, 3*Natom, 3*Natom); fflush(outfile); + } + + // compute B' matrix from B matrices + for (int atom_a=0; atom_a= 3) { + fprintf(outfile,"\nNumerical B' matrix by values in au, disp_size = %lf\n",disp_size); + print_matrix(outfile, dq2dx2_fd, 3*Natom, 3*Natom); + } + + double max_error = 0.0; + for (int ii=0; ii<3*Natom; ++ii) + for (int j=0; j<3*Natom; ++j) + if ( fabs(dq2dx2_analytic[ii][j] - dq2dx2_fd[ii][j]) > max_error ) + max_error = fabs(dq2dx2_analytic[ii][j] - dq2dx2_fd[ii][j]); + + fprintf(outfile,"Maximum difference is %.1e. ", max_error); + if (max_error > MAX_ERROR) { + fprintf(outfile, "Uh-Oh. See below\n"); + warn = true; + } + else { fprintf(outfile," Passed.\n"); } + + if (warn) { + fprintf(outfile, "\nWarning: Perhaps a bug or your angular coordinates are at a discontinuity.\n"); + fprintf(outfile, "Try restarting your optimization at a new or updated geometry.\n"); + fprintf(outfile, "Also, remove angular coordinates that are fixed by symmetry.\n"); + } + + free_matrix(dq2dx2_analytic); + fflush(outfile); + } + fprintf(outfile,"\n"); + free_matrix(dq2dx2_fd); + fflush(outfile); + return; +} + +} + diff --git a/optking/opt2man.main b/optking/opt2man.main new file mode 100644 index 0000000..c1a573c --- /dev/null +++ b/optking/opt2man.main @@ -0,0 +1,20 @@ +#include +#include "qchem.h" + +namespace optking { + void optking(void); +} + +int main(int argc, char* argv[]) +{ + + qink_init(argv,argc); + + terseOut(QINK_OPT2MAN); + + optking(); + + qink_exit(); + + return EXIT_SUCCESS; +} diff --git a/optking/opt_data.cpp b/optking/opt_data.cpp new file mode 100644 index 0000000..ace0f3e --- /dev/null +++ b/optking/opt_data.cpp @@ -0,0 +1,495 @@ +/*! \file opt_data.cc + \ingroup optking + \brief OPT_DATA associated functions that do not do i/o +*/ + +#include "opt_data.h" + +//#include "qcmath.h" +#include "cmath" + +#define EXTERN +#include "globals.h" + +namespace opt { + +//minimal constructor - just allocates memory +STEP_DATA::STEP_DATA(int Nintco, int Ncart) { + f_q = init_array(Nintco); + geom = init_array(Ncart); + energy = 0.0; + DE_predicted = 0.0; + unit_step = init_array(Nintco); + dq_norm = 0.0; + dq_gradient = 0.0; + dq_hessian = 0.0; + dq = init_array(Nintco); +} + +//free memory +STEP_DATA::~STEP_DATA() { + free_array(f_q); + free_array(geom); + free_array(unit_step); + free_array(dq); +} + +// save geometry and energy +void STEP_DATA::save_geom_energy(double *geom_in, double energy_in, int Ncart) { + array_copy(geom_in, geom, Ncart); + energy = energy_in; +} + +// save rest of stuff +void STEP_DATA::save_step_info(double DE_predicted_in, double *unit_step_in, double dq_norm_in, + double dq_gradient_in, double dq_hessian_in, int Nintco) { + DE_predicted = DE_predicted_in; + array_copy(unit_step_in, unit_step, Nintco); + dq_norm = dq_norm_in; + dq_gradient = dq_gradient_in; + dq_hessian = dq_hessian_in; +} + +OPT_DATA::~OPT_DATA() { + free_matrix(H); + free_array(rfo_eigenvector); + for (int i=0; i 1) DE = g_energy() - g_last_energy(); + else DE = g_energy(); + + fprintf(outfile, "\n\tConvergence Check Cycle %4d: (using internal coordinates in au)\n", iteration); + fprintf(outfile, "\t Actual Tolerance Converged?\n"); + fprintf(outfile, "\t----------------------------------------------------------\n"); + + if ( fabs(Opt_params.conv_max_force) < 1.0e-15 ) fprintf(outfile, "\tMAX Force %10.1e\n", max_force); + else fprintf(outfile, "\tMAX Force %10.1e %14.1e %11s\n", max_force, Opt_params.conv_max_force, + ((max_force < Opt_params.conv_max_force) ? "yes" : "no")); + + if ( fabs(Opt_params.conv_max_DE) < 1.0e-15 ) fprintf(outfile, "\tEnergy Change %10.1e\n", fabs(DE)); + else fprintf(outfile, "\tEnergy Change %10.1e %14.1e %11s\n", DE, Opt_params.conv_max_DE, + ((fabs(DE) < Opt_params.conv_max_DE) ? "yes" : "no")); + + if ( fabs(Opt_params.conv_max_disp) < 1.0e-15 ) fprintf(outfile, "\tMAX Displacement %10.1e\n", max_disp); + else fprintf(outfile, "\tMAX Displacement %10.1e %14.1e %11s\n", max_disp, Opt_params.conv_max_disp, + ((max_disp < Opt_params.conv_max_disp) ? "yes" : "no")); + + fprintf(outfile, "\t----------------------------------------------------------\n"); + printf("\tMAX Force %10.1e : Energy Change %10.1e : MAX Displacement %10.1e\n", max_force, DE, max_disp); + + if ((max_force < Opt_params.conv_max_force) && + ((fabs(DE) < Opt_params.conv_max_DE) || (max_disp < Opt_params.conv_max_disp))) { + return true; // structure is optimized! + } + else + return false; +} + +void OPT_DATA::summary(void) const { + double DE, *f, *dq, max_force, max_disp; + + fprintf(outfile,"\n\t **** Optimization Summary ****\n"); + fprintf(outfile,"\t----------------------------------------------------------------------------\n"); + fprintf(outfile,"\t Step Energy Delta(E) MAX force MAX Delta(q) \n"); + fprintf(outfile,"\t----------------------------------------------------------------------------\n"); + + for (int i=0; i0) return 1; + else if (d<0) return -1; + else return 0; +} + +// do hessian update +void OPT_DATA::H_update(opt::MOLECULE & mol) { + + if (Opt_params.H_update == OPT_PARAMS::BFGS) + fprintf(outfile,"\n\tPerforming BFGS update"); + else if (Opt_params.H_update == OPT_PARAMS::MS) + fprintf(outfile,"\n\tPerforming Murtagh/Sargent update"); + else if (Opt_params.H_update == OPT_PARAMS::POWELL) + fprintf(outfile,"\n\tPerforming Powell update"); + else if (Opt_params.H_update == OPT_PARAMS::BOFILL) + fprintf(outfile,"\n\tPerforming Bofill update"); + else if (Opt_params.H_update == OPT_PARAMS::NONE) { + fprintf(outfile,"\n\tNo Hessian update performed.\n"); + return; + } + + int i_step, step_start, i, j; + int step_this = steps.size()-1; + + /*** Read/compute current internals and forces ***/ + double *f, *x, *q; + f = steps[step_this]->g_forces_pointer(); + x = steps[step_this]->g_geom_const_pointer(); + + mol.set_geom_array(x); + q = mol.intco_values(); + + mol.fix_tors_near_180(); // fix configuration for torsions + + if (Opt_params.H_update_use_last == 0) { // use all available old gradients + step_start = 0; + } + else { + step_start = steps.size() - 1 - Opt_params.H_update_use_last; + if (step_start < 0) step_start = 0; + } + fprintf(outfile," with previous %d gradient(s).\n", step_this-step_start); + + double *f_old, *x_old, *q_old, *dq, *dg; + double gq, qq, qz, zz, phi; + + double **H = g_H_pointer(); + double **H_new = init_matrix(Nintco, Nintco); + + dq = init_array(Nintco); + dg = init_array(Nintco); + + for (i_step=step_start; i_step < step_this; ++i_step) { + + // Read/compute old internals and forces + f_old = g_forces_pointer(i_step); + x_old = g_geom_const_pointer(i_step); + + mol.set_geom_array(x_old); + q_old = mol.intco_values(); + + for (i=0;i Opt_params.H_update_dq_tol ) { + fprintf(outfile,"\tChange in internal coordinate exceeds limit.\n"); + fprintf(outfile,"\t Skipping Hessian update for step %d.\n", i_step + 1); + continue; + } + + // Schlegel 1987 Ab Initio Methods in Quantum Chemistry + // To make formulas work for Hessian, i.e., the 2nd derivatives switch dx and dg + if (Opt_params.H_update == OPT_PARAMS::BFGS) { + double **temp_mat, **X; + // Let a = dg^T.dq and X = (I - dg*dq^T) / a + // Then H = X * H_old * X^T + dg*dg^T/a . + X = unit_matrix(Nintco); + for (i=0; i 1.0) phi = 1.0; + + for (i=0; i max_limit) ? (scale_limit*val) : max_limit; + + if (fabs(H_new[i][j]) < max) + H[i][j] += H_new[i][j]; + else // limit change to max + H[i][j] += max * sign_of_double(H_new[i][j]); + } + } + } + else { // copy H_new into H + for (i=0; i= 2) { + fprintf(outfile, "Updated Hessian (in au)\n"); + print_matrix(outfile, H, Nintco, Nintco); + } + return; +} + +// read entry from binary file ; file pointer must be in right place for qchem code +void STEP_DATA::read(int istep, int Nintco, int Ncart) { + char lbl[80]; + sprintf(lbl, "f_q %d", istep); + opt_io_read_entry(lbl, (char *) f_q, Nintco*sizeof(double)); + sprintf(lbl, "geom %d", istep); + opt_io_read_entry(lbl, (char *) geom, Ncart*sizeof(double)); + sprintf(lbl, "energy %d", istep); + opt_io_read_entry(lbl, (char *) &energy, sizeof(double)); + sprintf(lbl, "DE_predicted %d", istep); + opt_io_read_entry(lbl, (char *) &DE_predicted, sizeof(double)); + sprintf(lbl, "unit_step %d", istep); + opt_io_read_entry(lbl, (char *) unit_step, Nintco*sizeof(double)); + sprintf(lbl, "dq_norm %d", istep); + opt_io_read_entry(lbl, (char *) &dq_norm, sizeof(double)); + sprintf(lbl, "dq_gradient %d", istep); + opt_io_read_entry(lbl, (char *) &dq_gradient, sizeof(double)); + sprintf(lbl, "dq_hessian %d", istep); + opt_io_read_entry(lbl, (char *) &dq_hessian, sizeof(double)); + sprintf(lbl, "dq %d", istep); + opt_io_read_entry(lbl, (char *) dq, Nintco*sizeof(double)); +} + +// read entry from binary file ; file pointer must be in right place for qchem code +//write entry to binary file +void STEP_DATA::write(int istep, int Nintco, int Ncart) { + char lbl[80]; + sprintf(lbl, "f_q %d", istep); + opt_io_write_entry(lbl, (char *) f_q, Nintco*sizeof(double)); + sprintf(lbl, "geom %d", istep); + opt_io_write_entry(lbl, (char *) geom, Ncart*sizeof(double)); + sprintf(lbl, "energy %d", istep); + opt_io_write_entry(lbl, (char *) &energy, sizeof(double)); + sprintf(lbl, "DE_predicted %d", istep); + opt_io_write_entry(lbl, (char *) &DE_predicted, sizeof(double)); + sprintf(lbl, "unit_step %d", istep); + opt_io_write_entry(lbl, (char *) unit_step, Nintco*sizeof(double)); + sprintf(lbl, "dq_norm %d", istep); + opt_io_write_entry(lbl, (char *) &dq_norm, sizeof(double)); + sprintf(lbl, "dq_gradient %d", istep); + opt_io_write_entry(lbl, (char *) &dq_gradient, sizeof(double)); + sprintf(lbl, "dq_hessian %d", istep); + opt_io_write_entry(lbl, (char *) &dq_hessian, sizeof(double)); + sprintf(lbl, "dq %d", istep); + opt_io_write_entry(lbl, (char *) dq, Nintco*sizeof(double)); +} + +// constructor function reads available data and allocates memory for current step +OPT_DATA::OPT_DATA(int Nintco_in, int Ncart_in) { + Nintco = Nintco_in; + Ncart = Ncart_in; + H = init_matrix(Nintco, Nintco); + rfo_eigenvector = init_array(Nintco+1); + + bool data_file_present = opt_io_is_present(); // determine if old data file is present + + if (!data_file_present) { + fprintf(outfile, "\tPrevious optimization step data not found. Starting new optimization.\n\n"); + iteration = 0; + consecutive_backsteps = 0; + } + else { + int Nintco_old, Ncart_old; + opt_io_open(opt::OPT_IO_OPEN_OLD); + opt_io_read_entry("Nintco", (char *) &Nintco_old, sizeof(int)); + opt_io_read_entry("Ncart", (char *) &Ncart_old, sizeof(int)); + + if (Nintco_old != Nintco) + fprintf(outfile, "\tThe number of coordinates has changed. Ignoring old data.\n"); + if (Ncart_old != Ncart) + fprintf(outfile, "\tThe number of atoms has changed. Ignoring old data.\n"); + + if ( (Nintco_old != Nintco) || (Ncart_old != Ncart) ) { + iteration = 0; + consecutive_backsteps = 0; + opt_io_close(0); // close and delete + } + else { // read in old optimization data + opt_io_read_entry("H", (char *) H[0], Nintco * Nintco * sizeof(double) ); + opt_io_read_entry("iteration", (char *) &iteration, sizeof(int)); + opt_io_read_entry("consecutive_backsteps", (char *) &consecutive_backsteps, sizeof(int)); + opt_io_read_entry("rfo_eigenvector", (char *) rfo_eigenvector, (Nintco+1)*sizeof(double)); + for (int i=0; iread(i+1, Nintco, Ncart); + steps.push_back(one_step); + } + opt_io_close(1); + } + } + + ++iteration; // increment for current step + // create memory for this, current step + STEP_DATA *one_step = new STEP_DATA(Nintco, Ncart); + steps.push_back(one_step); +} + +// write data to binary file +void OPT_DATA::write(void) { + opt_io_open(opt::OPT_IO_OPEN_OLD); + + fprintf(outfile,"\tWriting optimization data to binary file.\n"); + opt_io_write_entry("Nintco", (char *) &Nintco, sizeof(int)); + opt_io_write_entry("Ncart" , (char *) &Ncart , sizeof(int)); + opt_io_write_entry("H", (char *) H[0], Nintco * Nintco * sizeof(double) ); + opt_io_write_entry("iteration", (char *) &iteration, sizeof(int)); + opt_io_write_entry("consecutive_backsteps", (char *) &consecutive_backsteps, sizeof(int)); + opt_io_write_entry("rfo_eigenvector", (char *) rfo_eigenvector, (Nintco+1)*sizeof(double)); + + for (int i=0; iwrite(i+1, Nintco, Ncart); + opt_io_close(1); + + fflush(outfile); + return; +} + +// Report on performance of last step +// Eventually might have this function return false to reject a step +bool OPT_DATA::previous_step_report(void) const { + + fprintf(outfile, "\tCurrent energy : %20.10lf\n\n", p_Opt_data->g_energy()); + + if (steps.size() == 1) + return true; + + fprintf(outfile,"\tEnergy change for the previous step:\n"); + fprintf(outfile,"\t\tProjected : %20.10lf\n", p_Opt_data->g_last_DE_predicted()); + fprintf(outfile,"\t\tActual : %20.10lf\n", + p_Opt_data->g_energy() - p_Opt_data->g_last_energy()); + + double Energy_ratio = (p_Opt_data->g_energy() - p_Opt_data->g_last_energy()) / g_last_DE_predicted(); + + // Minimum search + if (Opt_params.rfo_root == 0 ) { + if (Energy_ratio < 0.0) { + throw(BAD_STEP_EXCEPT("Energy has increased in a minimization.")); + } + else if (Energy_ratio < 0.25) + { + Opt_params.intrafragment_step_limit /= 4; + fprintf(outfile,"\tEnergy ratio small: Trust radius decreased.\n\n"); + } + else if (Energy_ratio > 0.75) + { + Opt_params.intrafragment_step_limit *= 2; + fprintf(outfile,"\tEnergy ratio large: Trust radius increased.\n\n"); + } + } + + return true; +} + +} // end ::opt + + diff --git a/optking/opt_data.h b/optking/opt_data.h new file mode 100644 index 0000000..36b881c --- /dev/null +++ b/optking/opt_data.h @@ -0,0 +1,188 @@ +/*! + \ingroup optking + \file opt_data.h : header for structure that holds optimization data +*/ + +#ifndef _opt_opt_data_h_ +#define _opt_opt_data_h_ + +#include +#include + +#include "package.h" + +#include "linear_algebra.h" +#include "molecule.h" +#include "print.h" + +#include "io.h" + +namespace opt { + +using namespace std; + +// data for one optimization step +class STEP_DATA { + + double *f_q; // Internal coordinate forces + double *geom; // cartesian coordinate values + double energy; // total energy + double DE_predicted; // energy drop predicted for next step + double *unit_step; // unit vector in direction of step in the basis of internal coordinates + double dq_norm; // norm of step in internal coordinates + double dq_gradient; // gradient along step + double dq_hessian; // hessian along step + double *dq; // step in internal coordinates + + public: + //STEP_DATA(ifstream & fin, int Nintco, int Ncart); // read in date for one step + + STEP_DATA(int Nintco, int Ncart); // allocate memory only + + ~STEP_DATA(); // free memory + + // save geometry and energy + void save_geom_energy(double *geom_in, double energy_in, int Ncart); + + // save rest of stuff + void save_step_info(double DE_predicted_in, double *unit_step_in, double dq_norm_in, + double dq_gradient_in, double dq_hessian_in, int Nintco); + + // functions to read and write a step to the binary file + void write(int istep, int Nintco, int Ncart); + // read step from binary file + void read(int istep, int Nintco, int Ncart); + + // functions to retrieve data + double *g_forces_pointer(void) const { return f_q; } + double *g_geom_const_pointer(void) const { return geom; } + double *g_dq_pointer(void) const { return dq; } + double g_energy(void) const { return energy; } + double g_DE_predicted(void) const { return DE_predicted; } + double g_dq_norm(void) const { return dq_norm; } + double g_dq_gradient(void) const { return dq_norm; } + double g_dq_hessian(void) const { return dq_norm; } +}; + +// data for an optimization +class OPT_DATA { + int Nintco; // num. of internal coordinates + int Ncart; // num. of cartesian coordinates + double **H; // Hessian matrix + int iteration; // num. of current iteration, 0, 1, 2, ... + // # of previous steps of data stored should be == iteration + int consecutive_backsteps; // # of consecutive steps backwards, if any + double *rfo_eigenvector; // for RFO root-following + std::vector steps; + + public: + + // allocates memory for this step; reads in old steps from binary file + OPT_DATA(int Nintco_in, int Ncart_in); + + // free memory + ~OPT_DATA(); + + // write data to binary file + void write(void); + + // save geometry and energy to current (last) step + void save_geom_energy(double *geom_in, double energy_in) { + steps[steps.size()-1]->save_geom_energy(geom_in, energy_in, Ncart); + } + + // save rest of stuff to current (last) step + void save_step_info(double DE_predicted_in, double *unit_step_in, double dq_norm_in, + double dq_gradient_in, double dq_hessian_in) { + steps[steps.size()-1]->save_step_info(DE_predicted_in, unit_step_in, dq_norm_in, + dq_gradient_in, dq_hessian_in, Nintco); + } + + // return (pointers) to current-step data + int g_iteration(void) const { return iteration; } + double **g_H_pointer(void) { return H; } + double g_energy(void) const { return steps[steps.size()-1]->g_energy(); } + double *g_rfo_eigenvector_pointer(void) const { return rfo_eigenvector; } + // return dimension of Hessian matrix + int g_nintco(void) const { return Nintco; } + + void set_rfo_eigenvector(double *evect_in) { + for (int i=0; ig_forces_pointer(); + } + double *g_dq_pointer(void) const { + return steps[steps.size()-1]->g_dq_pointer(); + } + // return energy from the previous step (last entry - 1) + double g_last_energy(void) const { + if (steps.size() > 1) + return steps[steps.size()-2]->g_energy(); + else return 0.0; + } + + // return predicted energy change at the previous step (last entry - 1) + double g_last_DE_predicted(void) const { + if (steps.size() > 1) + return steps[steps.size()-2]->g_DE_predicted(); + else return 0.0; + } + + // return pointers to arbitrary-step data (pass in index starting at 0 ...) + double g_energy(int i) const { + return steps[i]->g_energy(); + } + double *g_forces_pointer(int i) const { + return steps.at(i)->g_forces_pointer(); + } + double *g_geom_const_pointer(int i) const { + return steps.at(i)->g_geom_const_pointer(); + } + double *g_dq_pointer(int i) const { + return steps.at(i)->g_dq_pointer(); + } + double g_dq_norm(int i) const { + return steps.at(i)->g_dq_norm(); + } + double g_dq_gradient(int i) const { + return steps.at(i)->g_dq_gradient(); + } + double g_dq_hessian(int i) const { + return steps.at(i)->g_dq_hessian(); + } + + bool previous_step_report(void) const; + + // check convergence of current step + bool conv_check(void) const; + + // summarize optimization up til now + void summary(void) const; + + // perform Hessian update + void H_update(opt::MOLECULE & mol); + + // read in cartesian Hessian + //double ** read_cartesian_H(void) const; + + // return number of steps present + int nsteps(void) const { return steps.size(); } + + void decrement_iteration(void) { --iteration; } + void increment_consecutive_backsteps(void) { ++consecutive_backsteps; } + + void erase_last_step(void) { + delete *(steps.end()); + steps.erase(steps.end()); + } + +}; + +} + +#endif + diff --git a/optking/opt_data_io.cpp b/optking/opt_data_io.cpp new file mode 100644 index 0000000..87567aa --- /dev/null +++ b/optking/opt_data_io.cpp @@ -0,0 +1,154 @@ +/*! \file binary_io.cc + \ingroup optking + \brief functions to read and write to optking's binary file +*/ + +#include "io.h" + +// PSI unit number for opt_data binary file +#if defined (OPTKING_PACKAGE_PSI) +#define PSI_OPTDATA_FILE_NUM 1 +#include +#endif + +#if defined (OPTKING_PACKAGE_PSI) +using namespace psi; +#endif + +// Name of opt_data file for QCHEM +//const char* getOptdataFileName(); +#define QCHEM_OPTDATA_FILENAME getOptdataFileName() + +// binary QCHEM data file +#if defined (OPTKING_PACKAGE_QCHEM) +#include +namespace opt_io { + std::fstream opt_data_stream; +} +#endif + +namespace opt { + +// returns true if the binary file exists and is not empty +bool opt_io_is_present(void) { + bool file_present = false; + +#if defined(OPTKING_PACKAGE_PSI) + psi::Communicator::world->sync(); + psio_open(PSI_OPTDATA_FILE_NUM, PSIO_OPEN_OLD); + if (psio_rd_toclen(PSI_OPTDATA_FILE_NUM) > 0) + file_present = true; + psio_close(PSI_OPTDATA_FILE_NUM, 1); + +#elif defined(OPTKING_PACKAGE_QCHEM) +// using opt_io::opt_data_stream; +// using namespace std; +// +// opt_data_stream.open(QCHEM_OPTDATA_FILENAME, fstream::in | fstream::binary); +// if (opt_data_stream.is_open()) { +// if (opt_data_stream.good()) +// file_present = true; +// opt_data_stream.close(); +// } +#endif + + return file_present; +} + + +void opt_io_remove(void) { +//#if defined(OPTKING_PACKAGE_PSI) +// psi::Communicator::world->sync(); +// if (!psio_open_check(PSI_OPTDATA_FILE_NUM)) // if not open, open it +// psio_open(PSI_OPTDATA_FILE_NUM, PSIO_OPEN_OLD); +// psio_close(PSI_OPTDATA_FILE_NUM, 0); // close and delete it +// +//#elif defined(OPTKING_PACKAGE_QCHEM) +//// using opt_io::opt_data_stream; +//// +//// if (opt_data_stream.is_open()) // if open, close it +//// opt_data_stream.close(); +//// std::remove(QCHEM_OPTDATA_FILENAME); // remove file +//#endif +} + + +// if OPT_IO_OPEN_OLD, open old file or new one +// if OPT_IO_OPEN_NEW, open new file, deleting any existing file +void opt_io_open(OPT_IO_FILE_STATUS status) { +//#if defined(OPTKING_PACKAGE_PSI) +// psi::Communicator::world->sync(); +// // if file is already open, then close it +// // delete it if NEW is requested +// if (psio_open_check(PSI_OPTDATA_FILE_NUM)) { +// if (status == OPT_IO_OPEN_OLD) +// psio_close(PSI_OPTDATA_FILE_NUM, 1); +// else if (status == OPT_IO_OPEN_NEW) +// psio_close(PSI_OPTDATA_FILE_NUM, 0); +// } +// +// psio_open(PSI_OPTDATA_FILE_NUM, PSIO_OPEN_OLD); +// +//#elif defined(OPTKING_PACKAGE_QCHEM) +// using opt_io::opt_data_stream; +// using namespace std; +// +// if ( opt_data_stream.is_open() && (status == OPT_IO_OPEN_OLD)) +// return; +// +// if ( opt_data_stream.is_open() && (status == OPT_IO_OPEN_NEW) ) +// opt_data_stream.close(); +// +// if (status == OPT_IO_OPEN_NEW) +// remove(QCHEM_OPTDATA_FILENAME); +// +// if (opt_io_is_present()) +// opt_data_stream.open(QCHEM_OPTDATA_FILENAME, fstream::in | fstream::out | fstream::binary); +// else +// opt_data_stream.open(QCHEM_OPTDATA_FILENAME, fstream::out | fstream::binary); +// +//#endif + return; +} + + +void opt_io_close(int keep) { +// +//#if defined(OPTKING_PACKAGE_PSI) +// psi::Communicator::world->sync(); +// psio_close(PSI_OPTDATA_FILE_NUM, 1); +//#elif defined(OPTKING_PACKAGE_QCHEM) +// opt_io::opt_data_stream.close(); +//#endif +// +// if (!keep) opt_io_remove(); + return; +} + + +// key = char * ; label for entry ; not used by QChem +// buffer = char * ; stream from which to read +// size = unsigned long int ; number of bytes to read +void opt_io_read_entry(const char *key, char *buffer, ULI size) { +#if defined(OPTKING_PACKAGE_PSI) + psio_read_entry(PSI_OPTDATA_FILE_NUM, key, buffer, size); +#elif defined(OPTKING_PACKAGE_QCHEM) + opt_io::opt_data_stream.read(buffer, size); +#endif +} + + +// key = char * ; label for entry ; not used by QChem +// buffer = char * ; stream from which to read +// size = unsigned long int ; number of bytes to read +void opt_io_write_entry(const char *key, char *buffer, ULI size) { +#if defined(OPTKING_PACKAGE_PSI) + psio_write_entry(PSI_OPTDATA_FILE_NUM, key, buffer, size); +#elif defined(OPTKING_PACKAGE_QCHEM) + opt_io::opt_data_stream.write(buffer,size); +#endif +} + + +} // namespace opt + diff --git a/optking/opt_except.h b/optking/opt_except.h new file mode 100644 index 0000000..fdb71c7 --- /dev/null +++ b/optking/opt_except.h @@ -0,0 +1,52 @@ +namespace opt { + +/** + \ingroup optking + \brief Exception class for problems with internal coordinates. + */ + +/* If they relate to values of the coordinates and derivatives, then try new + coordinates ; if it looks like user error in definition, then + quit right away. */ +class INTCO_EXCEPT { + private: + const char * message; + bool try_other_intcos; + + public: + + static bool already_tried_other_intcos; // defined in optking.cc + static bool override_fragment_mode; + + + INTCO_EXCEPT(const char * m) { + message = m; + try_other_intcos = false; + } + + INTCO_EXCEPT(const char * m, bool t) { + message = m; + try_other_intcos = t; + } + + ~INTCO_EXCEPT() {}; + + bool try_again() { return try_other_intcos; } + const char *g_message(void) { return message; } +}; + +class BAD_STEP_EXCEPT { + private: + const char * message; + + public: + BAD_STEP_EXCEPT(const char * m) { message = m; } + + ~BAD_STEP_EXCEPT() {}; + + const char *g_message(void) { return message; } +}; + + +} + diff --git a/optking/opt_params.h b/optking/opt_params.h new file mode 100644 index 0000000..879ab65 --- /dev/null +++ b/optking/opt_params.h @@ -0,0 +1,118 @@ +/*! \file opt-params.h + \ingroup optking + \brief header for optimization parameters + variable meanings are described in more detail in set_params.cc +*/ + +#ifndef _opt_opt_params_h_ +#define _opt_opt_params_h_ + +namespace opt { + +struct OPT_PARAMS { + + // convergence criteria + double conv_max_force; + double conv_max_DE; + double conv_max_disp; + + double scale_connectivity; + + enum FRAGMENT_MODE {SINGLE, MULTI} fragment_mode; + + enum INTERFRAGMENT_MODE {FIXED, PRINCIPAL_AXES} interfragment_mode; + + bool generate_intcos_only; + + bool rfo_follow_root; // whether to do root following + int rfo_root; // which root to follow + double rfo_normalization_min; // small threshold for rfo normalization + + enum OPT_TYPE {MIN, TS, IRC} opt_type; + enum STEP_TYPE {NR, RFO, P_RFO} step_type; // Newton-Raphson (NR) or RFO step + + // Hessian guess + + enum INTRAFRAGMENT_HESSIAN {FISCHER, SCHLEGEL} intrafragment_H; + enum INTERFRAGMENT_HESSIAN {DEFAULT, FISCHER_LIKE} interfragment_H; + + enum H_UPDATE {NONE, BFGS, MS, POWELL, BOFILL} H_update; + int H_update_use_last; + + bool freeze_intrafragment; // freeze all fragments + + // related to step taken + double intrafragment_step_limit; + + // whether to limit changes in Hessian due to update + bool H_update_limit; + // changes in H are limited to H_update_limit_scale * the previous value + // if they exceed that, then they are limited to H_update_limit_max + double H_update_limit_scale; + double H_update_limit_max; + + // whether to use 1/R as the distance coordinate in interfragment stretching modes + bool interfragment_distance_inverse; + + // By default, optking prints and saves the last (previous) geometry at the end of an + // optimization, i.e., the one at which a gradient was computed. + // If true, then the structure obtained from the last anticipated step is printed and saved instead. + bool write_final_step_geometry; + + double maximum_H_bond_distance; + + bool read_cartesian_H; + + bool efp_fragments; + bool efp_fragments_only; + +// ** Unlikely to need modified ** + + // how close to pi should a torsion be to assume it may have passed through 180 + double fix_tors_near_pi; + + // torsional angles will not be computed if the contained bond angles are within + // this fraction of pi from 0 or from pi + double tors_angle_lim; + + // as above, how fractionally close to 0 or pi counts as linear when deciding which + // atoms to avoid using in interfragment coordinates + double interfrag_collinear_tol; + + double tors_cos_tol; // cos(angle) must be this close to -1/+1 for angle to count as 0/pi + + double linear_bend_threshold; // if bend exceeds this value, then also add linear bend complement + + // threshold for which entries in diagonalized redundant matrix are kept and inverted + // while computing a generalized inverse of a matrix + double redundant_eval_tol; + + // maximum number of allowed iterations in backtransformation to cartesian coordinates + double bt_max_iter; + + // rms and max change in cartesian coordinates in backtransformation + double bt_dx_conv; + + // give up on backtransformation iterations if change rms from one iteration to the + // next is below this value + double bt_dx_conv_rms_change; + + //1=default; 2=medium; 3=lots + int print_lvl; + + // Hessian update is avoided if the denominators (Dq*Dq) or (Dq*Dg) are smaller than this + double H_update_den_tol; + // Hessian update is avoided if any internal coordinate has changed by more than this amount + // in radians / au + double H_update_dq_tol; + + + bool test_B; // whether to test B matrices + bool test_derivative_B; // whether to test derivative B matrices + +}; + +} + +#endif + diff --git a/optking/optking.C b/optking/optking.C new file mode 100644 index 0000000..99aaab2 --- /dev/null +++ b/optking/optking.C @@ -0,0 +1,374 @@ +/*! + \defgroup optking + \file optking.cc : main optimizer + \ingroup optking +*/ +#include +#include +#include "globals.h" +#include "molecule.h" +#include "print.h" +#include "io.h" + +#if defined(OPTKING_PACKAGE_PSI) +#include +#endif + +// Define the return types for optking. +#if defined(OPTKING_PACKAGE_PSI) + typedef psi::PsiReturnType OptReturnType; + #define OptReturnEndloop (psi::EndLoop) + #define OptReturnSuccess (psi::Success) + #define OptReturnFailure (psi::Failure) +#elif defined(OPTKING_PACKAGE_QCHEM) + typedef int OptReturnType; + #define OptReturnFailure 2 + #define OptReturnEndloop 1 + #define OptReturnSuccess 0 +#endif + +#if defined(OPTKING_PACKAGE_PSI) +namespace psi { void psiclean(void); } +#endif + +#if defined(OPTKING_PACKAGE_QCHEM) +// #include "qchem.h" +// namespace opt { +// OptReturnType optking(void); // declare optking +// } +// OptReturnType opt2man_main(void) { opt::optking(); } // QCHEM wrapper/alias +#endif + +namespace opt { + void open_output_dat(void); // open/link outfile to text output + void close_output_dat(void);// close above + void print_title(void); // print header + void print_end(void); // print footer + void init_ioff(void); + bool INTCO_EXCEPT::already_tried_other_intcos = false; + bool INTCO_EXCEPT::override_fragment_mode = false; // to override MULTI setting by exception algorithm + +#if defined(OPTKING_PACKAGE_PSI) +// void set_params(psi::Options & options); // set optimization parameters +#elif defined(OPTKING_PACKAGE_QCHEM) + void set_params(void); +#endif + +//#if defined(OPTKING_PACKAGE_PSI) +//OptReturnType optking(psi::Options & options) { +//#elif defined(OPTKING_PACKAGE_QCHEM) +OptReturnType optking(void) { +//#endif + + using namespace std; + using namespace opt; + + open_output_dat(); // assign output.dat file pointer + + MOLECULE *mol1; + bool newly_generated_coordinates; // Are internal coordinates produced or read-in? + + print_title(); // print header + + try { + +#if defined(OPTKING_PACKAGE_PSI) + set_params(options); +#else + set_params(); // set optimization parameters +#endif + if (INTCO_EXCEPT::override_fragment_mode && (Opt_params.fragment_mode == OPT_PARAMS::MULTI)) + Opt_params.fragment_mode = OPT_PARAMS::SINGLE; + + // try to open old internal coordinates + //std::ifstream if_intco(FILENAME_INTCO_DAT, ios_base::in); + std::ifstream if_intco; + + if (if_intco.is_open()) { // old internal coordinates are present + + fprintf(outfile,"\n\tPrevous internal coordinate definitions found.\n"); fflush(outfile); + newly_generated_coordinates = false; + + mol1 = new MOLECULE(0); // make an empty molecule + + // read internal coordinate and fragment definitions + // create, allocate, and add fragment objects + mol1->read_intcos(if_intco); +#if defined(OPTKING_PACKAGE_PSI) + psi::Communicator::world->sync(); +#endif + if_intco.close(); + + mol1->update_connectivity_by_bonds(); + + // read geometry and gradient into the existing fragments + //mol1->read_geom_grad(); + + } + else { // automatically generate coordinates + + fprintf(outfile,"\n\tInternal coordinates to be generated automatically.\n"); fflush(outfile); + newly_generated_coordinates = true; + + // read number of atoms ; make one fragment of that size ; + //mol1 = new MOLECULE( read_natoms() ); + + // read geometry and gradient into fragment + //mol1->read_geom_grad(); + + // use covalent radii to define bonds + mol1->update_connectivity_by_distances(); + + // if fragment_mode == SINGLE, connects all separated groups of atoms by modifying frag.connectivity + // if fragment_mode == MULTI, splits into fragments and makes interfragment coordinates + mol1->fragmentize(); + mol1->print_connectivity(outfile); + + if (Opt_params.fragment_mode == OPT_PARAMS::SINGLE) { + mol1->add_intrafragment_simples_by_connectivity(); + } + + // newly constructed fragments need connectivity generated + if (Opt_params.fragment_mode == OPT_PARAMS::MULTI) { + mol1->update_connectivity_by_distances(); + mol1->add_intrafragment_simples_by_connectivity(); + mol1->add_interfragment(); + } + +// // print out internal coordinates for future steps +// FILE *fp_intco = fopen(FILENAME_INTCO_DAT, "w"); +// mol1->print_intco_dat(fp_intco); +//#if defined(OPTKING_PACKAGE_PSI) +// psi::Communicator::world->sync(); +//#endif +// fclose(fp_intco); + + // only generate coordinates and print them out + if (Opt_params.generate_intcos_only) { + fprintf(outfile,"\tGenerating intcos and halting."); + close_output_dat(); +#if defined(OPTKING_PACKAGE_PSI) + psi::psiclean(); +#endif + return OptReturnEndloop; + } + + } + +/*#if defined(OPTKING_PACKAGE_QCHEM) + if (Opt_params.efp_fragments_only) + mol1 = new MOLECULE(0); // construct an empty molecule + if (Opt_params.efp_fragments) + mol1->add_efp_fragments(); // add EFP fragments +#endif */ + + // print geometry and gradient + mol1->print_geom_grad(outfile); + //mol1->print_connectivity(outfile); fflush(outfile); + + // read binary file for previous steps ; history needed to compute EFP values + p_Opt_data = new OPT_DATA(mol1->g_nintco(), 3*mol1->g_natom()); + +#if defined(OPTKING_PACKAGE_QCHEM) + //mol1->update_efp_values(); // EFP values calculated from old opt_data +#endif + + // print internal coordinate definitions and values + mol1->print_intcos(outfile); + + if (Opt_params.test_B) + mol1->test_B(); + + if (Opt_params.test_derivative_B) + mol1->test_derivative_B(); + + // save geometry and energy + double * x = mol1->g_geom_array(); + p_Opt_data->save_geom_energy(x, mol1->g_energy()); + if (x!=NULL) free_array(x); + + // print out report on progress + p_Opt_data->previous_step_report(); + + // compute forces in internal coordinates from cartesian gradient + mol1->forces(); // puts forces in p_Opt_data->step[last one] + + if (p_Opt_data->g_iteration() == 1) { // 1st iteration -> put initial Hessian in p_Opt_data + bool read_H_worked = false; + if (Opt_params.read_cartesian_H) { + read_H_worked = mol1->cartesian_H_to_internals(); // read and transform cartesian Hessian + if (read_H_worked) + fprintf(outfile,"\tRead in cartesian Hessian and transformed it.\n"); + else + fprintf(outfile,"\tUnable to read and transform Hessian.\n"); + } + + if ( (!Opt_params.read_cartesian_H) || (!read_H_worked) ) + mol1->H_guess(); // empirical model guess Hessian + } + else { // do Hessian update + try { + p_Opt_data->H_update(*mol1); + } catch (const char * str) { + fprintf(stderr, "%s\n", str); + fprintf(outfile, "H_update failed\n"); + fprintf(outfile, "%s\n", str); + return OptReturnFailure; + } + } + + mol1->project_f_and_H(); +fprintf(outfile,"done with projection\n"); fflush(outfile); + + if (Opt_params.opt_type == OPT_PARAMS::IRC) + mol1->irc_step(); + else {// puts dq in p_Opt_data->step + if (Opt_params.step_type == OPT_PARAMS::NR) + mol1->nr_step(); + else if (Opt_params.step_type == OPT_PARAMS::RFO) + mol1->rfo_step(); + else if (Opt_params.step_type == OPT_PARAMS::P_RFO) + mol1->prfo_step(); + } + + bool converged = p_Opt_data->conv_check(); + +#if defined(OPTKING_PACKAGE_QCHEM) +// rem_write((int) converged, REM_GEOM_OPT_CONVERGED); // tell QChem if converged (return value ignored for now) +// rem_write(p_Opt_data->g_iteration(), REM_GEOM_OPT_CYCLE); // tell QChem current iteration number +#endif + + if ( converged ) { + fprintf(outfile,"\n\t **** Optimization is complete! ****\n"); + p_Opt_data->summary(); + p_Opt_data->write(); // save data to optimization binary file + + fprintf(outfile,"\tFinal energy is %20.13lf\n", p_Opt_data->g_energy()); + + if (Opt_params.write_final_step_geometry) { + fprintf(outfile,"\tFinal (next step) structure:\n"); + mol1->print_geom(); // write geometry -> output file + fprintf(outfile,"\tSaving final (next step) structure.\n"); + } + else { // default - get last geometry and write that one + double *x = p_Opt_data->g_geom_const_pointer(p_Opt_data->nsteps()-1); + mol1->set_geom_array(x); + fprintf(outfile,"\tFinal (previous) structure:\n"); + mol1->print_geom(); // write geometry -> output file + fprintf(outfile,"\tSaving final (previous) structure.\n"); + } + + delete p_Opt_data; + //mol1->write_geom(); // write geometry -> chkpt file (also output for QChem) + print_end(); + + close_output_dat(); + return OptReturnEndloop; + } + + p_Opt_data->write(); + delete p_Opt_data; + +//#if defined(OPTKING_PACKAGE_PSI) + fprintf(outfile,"\tStructure for next step:\n"); + mol1->print_geom(); // write geometry for next step to output file +//#endif + + //mol1->write_geom(); // write geometry -> chkpt (also output for QChem) + print_end(); + + } // end big try + catch (INTCO_EXCEPT exc) { + + if (exc.try_again() && !exc.already_tried_other_intcos) { + + fprintf(outfile,"\tThe optimizer encountered the following error:\n\t%s\n", exc.g_message()); + fprintf(outfile,"\tWill attempt to restart optimization with redefined internal coordinates.\n"); + + //std::remove(FILENAME_INTCO_DAT); // rm intco definitions + opt_io_remove(); // rm optimization data + +#if defined(OPTKING_PACKAGE_QCHEM) + //rem_write(0, REM_GEOM_OPT_CYCLE); // reset iteration counter +#endif + // if multi mode has failed, for now try single mode. + if (Opt_params.fragment_mode == OPT_PARAMS::MULTI) + exc.override_fragment_mode = true; + + exc.already_tried_other_intcos = true; + close_output_dat(); + return OptReturnSuccess; + } + else { + fprintf(stderr, "%s\n", exc.g_message()); + fprintf(outfile, "%s\n", exc.g_message()); +#if defined (OPTKING_PACKAGE_QCHEM) + //QCrash(exc.g_message()); +#elif defined (OPTKING_PACKAGE_PSI) + abort(); +#endif + } + } + catch (BAD_STEP_EXCEPT exc) { + + fprintf(outfile,"\tA bad-step exception has been caught.\n"); + fprintf(outfile,"\t%s", exc.g_message()); + mol1->backstep(); + close_output_dat(); + return OptReturnSuccess; + } + + catch (...) { +//#if defined (OPTKING_PACKAGE_QCHEM) + //QCrash("Exception thrown in optking() leading to abort."); +//#elif defined (OPTKING_PACKAGE_PSI) + abort(); +//#endif + } + + close_output_dat(); + return OptReturnSuccess; +} + +// Functions to set and release (possibly open and close) the file pointer for +// the standard text output file +void open_output_dat(void) { +//#if defined (OPTKING_PACKAGE_PSI) +// outfile = psi::outfile; +//#elif defined (OPTKING_PACKAGE_QCHEM) + outfile = stdout; +//#endif +} + +void close_output_dat(void) { +#if defined(OPTKING_PACKAGE_QCHEM) + fflush(outfile); +#endif +} + +void print_title(void) { + fprintf(outfile, "\n\t\t\t----------------------------------\n"); + fprintf(outfile, "\t\t\t OPTKING: for geometry optimizations \n"); + fprintf(outfile, "\t\t\t - R.A. King, Bethel University \n"); + fprintf(outfile, "\t\t\t------------------------------------\n"); + fflush(outfile); +} + +void print_end(void) { +#if defined (OPTKING_PACKAGE_PSI) + fprintf(outfile, "\t\t\t--------------------------\n"); + fprintf(outfile, "\t\t\t OPTKING Finished Execution \n"); + fprintf(outfile, "\t\t\t--------------------------\n"); +#endif +} + +void init_ioff(void) +{ + int i; + ioff = init_int_array(IOFF_MAX); + ioff[0] = 0; + for(i=1; i < IOFF_MAX; i++) ioff[i] = ioff[i-1] + i; +} + +} + diff --git a/optking/package.h b/optking/package.h new file mode 100644 index 0000000..705c24f --- /dev/null +++ b/optking/package.h @@ -0,0 +1,5 @@ + +// select one quantum chemistry package +//#define OPTKING_PACKAGE_PSI 1 +#define OPTKING_PACKAGE_QCHEM 1 + diff --git a/optking/physconst.h b/optking/physconst.h new file mode 100644 index 0000000..791d239 --- /dev/null +++ b/optking/physconst.h @@ -0,0 +1,15 @@ +/*! \file physconst.h + \ingroup optking + \brief physical constants +*/ + +#ifndef _opt_physconst_h_ +#define _opt_physconst_h_ + +#define _pi 3.14159265358979323846264338327950288 +#define _bohr2angstroms 0.529177249 +#define _hartree2aJ 4.35974381 + + +#endif + diff --git a/optking/print.cpp b/optking/print.cpp new file mode 100644 index 0000000..374cbc0 --- /dev/null +++ b/optking/print.cpp @@ -0,0 +1,51 @@ +/*! \file print.cc + \ingroup optking + \brief memory allocation +*/ + +#include "print.h" + +namespace opt { + + +void print_matrix(const FILE *fp, double **A, const int nrow, const int ncol) { + int i,j,col=0; + + //const int max_col = 12; + const int max_col = 18; + + for (i=0; i(fp), "%13.8f", A[i][j]); + fprintf(const_cast(fp), "%10.6f", A[i][j]); + ++col; + if ((col == max_col) && (j != ncol-1)) { + fprintf(const_cast(fp), "\n"); + col = 0; + } + } + fprintf(const_cast(fp),"\n"); + col = 0; + } + fflush(const_cast(fp)); +} + +void print_array(const FILE *fp, double *A, const int ncol) { + int j,col=0; + + const int max_col = 9; + + for (j=0; j(fp), "%13.8f", A[j]); + ++col; + if ((col == max_col) && (j != ncol-1)) { + fprintf(const_cast(fp), "\n"); + col = 0; + } + } + fprintf(const_cast(fp),"\n"); + fflush(const_cast(fp)); +} + +} + diff --git a/optking/print.h b/optking/print.h new file mode 100644 index 0000000..7e7ea17 --- /dev/null +++ b/optking/print.h @@ -0,0 +1,21 @@ +/*! \file print.h + \ingroup optking + \brief header for print functions +*/ + +#ifndef _opt_print_h_ +#define _opt_print_h_ + +#include +#include + +namespace opt { + +void print_matrix(const FILE *fp, double **A, const int x, const int y); + +void print_array(const FILE *fp, double *A, const int x); + +} + +#endif + diff --git a/optking/set_params.cpp b/optking/set_params.cpp new file mode 100644 index 0000000..7e39e23 --- /dev/null +++ b/optking/set_params.cpp @@ -0,0 +1,461 @@ +/*! \file set_params.cc + \ingroup optking + \brief set optimization parameters +*/ + +#define EXTERN +#include "globals.h" +//DES Temp: +#include + +//#if defined(OPTKING_PACKAGE_PSI) +//#include +//#elif defined(OPTKING_PACKAGE_QCHEM) +//#include +//#endif + +namespace opt { + +void print_params(void); + +//#if defined(OPTKING_PACKAGE_PSI) +//void set_params(psi::Options & options) +//#else +void set_params(void) +//#endif +{ + + std::string s; + +//#if defined(OPTKING_PACKAGE_PSI) +// +//// optimization type +// s = options.get_str("OPT_TYPE"); +// if(s == "MIN") Opt_params.opt_type = OPT_PARAMS::MIN; +// else if (s == "TS") Opt_params.opt_type = OPT_PARAMS::TS; +// else if (s == "IRC") Opt_params.opt_type = OPT_PARAMS::IRC; +// +// if (options["OPT_TYPE"].has_changed()) { +// s = options.get_str("STEP_TYPE"); +// if (s == "RFO") { +// if (Opt_params.opt_type == OPT_PARAMS::MIN) +// Opt_params.step_type = OPT_PARAMS::RFO; +// else if (Opt_params.opt_type == OPT_PARAMS::TS) +// Opt_params.step_type = OPT_PARAMS::P_RFO; +// } +// else if (s == "NR") Opt_params.step_type = OPT_PARAMS::NR; +// } +// else { // set defaults for step type +// if (Opt_params.opt_type == OPT_PARAMS::MIN) +// Opt_params.step_type = OPT_PARAMS::RFO; +// else if (Opt_params.opt_type == OPT_PARAMS::TS) +// Opt_params.step_type = OPT_PARAMS::P_RFO; +// // else if (Opt_params.opt_type == OPT_PARAMS::IRC) options? +// } +// +//// Maximum step size in bohr or radian along an internal coordinate {double} +// Opt_params.intrafragment_step_limit = options.get_double("INTRAFRAGMENT_STEP_LIMIT"); +// +//// Whether to 'follow' the initial RFO vector after the first step {true, false} +// Opt_params.rfo_follow_root = options.get_bool("RFO_FOLLOW_ROOT"); +// +//// Which RFO root to follow; internally 0 (externally 1) indicates minimum; {integer} +// Opt_params.rfo_root = options.get_int("RFO_ROOT"); +// +//// When determining connectivity, a bond is assigned if interatomic distance +//// is less than (this number) * sum of covalent radii {double} +// Opt_params.scale_connectivity = options.get_double("SCALE_CONNECTIVITY"); +// +//// Whether to treat multiple molecule fragments as a single bonded molecule; +//// or via interfragment coordinates ; a primary difference is that in MULTI mode, +//// the interfragment coordinates are not redundant. {SINGLE, MULTI} +// s = options.get_str("FRAGMENT_MODE"); +// if (s == "SINGLE") Opt_params.fragment_mode = OPT_PARAMS::SINGLE; +// else if (s == "MULTI") Opt_params.fragment_mode = OPT_PARAMS::MULTI; +// +//// whether to use fixed linear combinations of atoms as reference points for +////interfragment coordinates or whether to use principal axes {FIXED, PRINCIPAL_AXES} +// s = options.get_str("INTERFRAGMENT_MODE"); +// if (s == "FIXED") Opt_params.interfragment_mode = OPT_PARAMS::FIXED; +// else if (s == "PRINCIPAL_AXES") Opt_params.interfragment_mode = OPT_PARAMS::PRINCIPAL_AXES; +// +//// Whether to only generate the internal coordinates and then stop {true, false} +// Opt_params.generate_intcos_only = options.get_bool("GENERATE_INTCOS_ONLY"); +// +//// What model Hessian to use to guess intrafragment force constants {SCHLEGEL, FISCHER} +// s = options.get_str("INTRAFRAGMENT_H"); +// if (s == "FISCHER") Opt_params.intrafragment_H = OPT_PARAMS::FISCHER; +// else if (s == "SCHLEGEL") Opt_params.intrafragment_H = OPT_PARAMS::SCHLEGEL; +// +//// Whether to use the default of FISCHER_LIKE force constants for the initial guess {DEFAULT, FISCHER_LIKE} +// s = options.get_str("INTERFRAGMENT_H"); +// if (s == "DEFAULT") Opt_params.interfragment_H = OPT_PARAMS::DEFAULT; +// else if (s == "FISCHER_LIKE") Opt_params.interfragment_H = OPT_PARAMS::FISCHER_LIKE; +// +//// Whether to freeze all fragments rigid +// Opt_params.freeze_intrafragment = options.get_bool("FREEZE_INTRAFRAGMENT"); +// +//// By default, optking prints and saves the last (previous) geometry at the end of an +//// optimization, i.e., the one at which a gradient was computed. If this keyword is +//// set to true, then the structure obtained from the last projected step is printed out and saved instead. +// Opt_params.write_final_step_geometry = options.get_bool("WRITE_FINAL_STEP_GEOMETRY"); +// +//// Choose from supported Hessian updates {NONE, BFGS, MS, POWELL, BOFILL} +// s = options.get_str("H_UPDATE"); +// if (s == "NONE") Opt_params.H_update = OPT_PARAMS::NONE; +// else if (s == "BFGS") Opt_params.H_update = OPT_PARAMS::BFGS; +// else if (s == "MS") Opt_params.H_update = OPT_PARAMS::MS; +// else if (s == "POWELL") Opt_params.H_update = OPT_PARAMS::POWELL; +// else if (s == "BOFILL") Opt_params.H_update = OPT_PARAMS::BOFILL; +// +//// How many previous steps' data to use in Hessian update; 0=use them all ; {integer} +// Opt_params.H_update_use_last = options.get_int("H_UPDATE_USE_LAST"); +// +//// Whether to limit the magnitutde of changes caused by the Hessian update {true, false} +// Opt_params.H_update_limit = options.get_bool("H_UPDATE_LIMIT"); +// +//// If the above is true, changes to the Hessian from the update are limited to the larger of +//// (H_update_limit_scale)*(the previous value) and H_update_limit_max (in au). +// Opt_params.H_update_limit_scale = options.get_double("H_UPDATE_LIMIT_SCALE"); +// Opt_params.H_update_limit_max = options.get_double("H_UPDATE_LIMIT_MAX"); +// +//// Whether to use 1/R(AB) for stretching coordinate between fragments (or just R(AB)) +// Opt_params.interfragment_distance_inverse = options.get_bool("INTERFRAGMENT_DISTANCE_INVERSE"); +// +//// For now, this is a general maximum distance for the definition of H-bonds +// Opt_params.maximum_H_bond_distance = options.get_double("MAXIMUM_H_BOND_DISTANCE"); +// +//// QCHEM optimization criteria +// Opt_params.conv_max_force = options.get_double("CONV_MAX_FORCE"); +// Opt_params.conv_max_DE = options.get_double("CONV_MAX_DE"); +// Opt_params.conv_max_disp = options.get_double("CONV_MAX_DISP"); +// +//// Whether to test B matrix and derivative B matrix numerically +// Opt_params.test_B = options.get_bool("TEST_B"); +// Opt_params.test_derivative_B = options.get_bool("TEST_DERIVATIVE_B"); +// +// Opt_params.print_lvl = options.get_int("PRINT"); +// +//// read cartesian Hessian +// Opt_params.read_cartesian_H = options.get_bool("READ_CARTESIAN_H"); +// +//// only treating "dummy fragments" +// // These are not found in psi4/read_options.cc +// // Not sure if we need these. +// Opt_params.efp_fragments = false; +// Opt_params.efp_fragments_only = false; +// +//#elif defined(OPTKING_PACKAGE_QCHEM) + + int i; + +// MIN = 0 ; TS = 1 ; IRC = 2 (default 0) +// i = rem_read(REM_GEOM_OPT2_OPT_TYPE); + i = 0; + if (i == 0) Opt_params.step_type = OPT_PARAMS::RFO; + else if (i == 1) Opt_params.step_type = OPT_PARAMS::NR; + else if (i == 2) Opt_params.step_type = OPT_PARAMS::P_RFO; + +// RFO = 0 ; NR = 1 ; P_RFO = 2 (default 0) + //i = rem_read(REM_GEOM_OPT2_STEP_TYPE); + i=0; + if (i == 0) Opt_params.step_type = OPT_PARAMS::RFO; + else if (i == 1) Opt_params.step_type = OPT_PARAMS::NR; + else if (i == 2) Opt_params.step_type = OPT_PARAMS::P_RFO; + +// max = i / 10 (default 4) + //i = rem_read(REM_GEOM_OPT2_INTRAFRAGMENT_STEP_LIMIT); + i=4; + Opt_params.intrafragment_step_limit = i / 10.0; + +// Whether to follow root (default 0 means 'no') + //Opt_params.rfo_follow_root = rem_read(REM_GEOM_OPT2_RFO_FOLLOW_ROOT); + +// Which root is desired (default 0 for minimum) + //Opt_params.rfo_root = rem_read(REM_GEOM_OPT2_RFO_ROOT); + +// scale = i / 10 (default 13) + //i = rem_read(REM_GEOM_OPT2_SCALE_CONNECTIVITY); +//DES: Set below default! + i=10; + Opt_params.scale_connectivity = i / 10.0; + +// multi-mode (0=single ; 1= multi) (default 0) + //i = rem_read(REM_GEOM_OPT2_FRAGMENT_MODE); + //i=0; + i=1; + if (i == 0) { + //std::cout << "DES: setting fragment_mode=SINGLE" << std::endl; + Opt_params.fragment_mode = OPT_PARAMS::SINGLE; + } + else if (i == 1) { + //std::cout << "DES: setting fragment_mode=MULTI" << std::endl; + Opt_params.fragment_mode = OPT_PARAMS::MULTI; + } + +// interfragment mode type (0=fixed; 1=principal axes) + //i = rem_read(REM_GEOM_OPT2_INTERFRAGMENT_MODE); + //i=1; + i=0; + if (i == 0) Opt_params.interfragment_mode = OPT_PARAMS::FIXED; + else if (i == 1) Opt_params.interfragment_mode = OPT_PARAMS::PRINCIPAL_AXES; + +// only generate intcos + //Opt_params.generate_intcos_only = rem_read(REM_GEOM_OPT2_GENERATE_INTCOS_ONLY); + +// model 0=FISCHER ; 1 = SCHLEGEL (default 0) + //i = rem_read(REM_GEOM_OPT2_INTRAFRAGMENT_H); + i=0; + if (i == 0) Opt_params.intrafragment_H = OPT_PARAMS::FISCHER; + else if (i == 1) Opt_params.intrafragment_H = OPT_PARAMS::SCHLEGEL; + +// interfragment 0=DEFAULT ; 1=FISCHER_LIKE + //i = rem_read(REM_GEOM_OPT2_INTERFRAGMENT_H); + i=0; + if (i == 0) Opt_params.interfragment_H = OPT_PARAMS::DEFAULT; + else if (i == 1) Opt_params.interfragment_H = OPT_PARAMS::FISCHER_LIKE; + +// Whether to freeze all fragments rigid (default 0); + //Opt_params.freeze_intrafragment = rem_read(REM_GEOM_OPT2_FREEZE_INTRAFRAGMENT); + Opt_params.freeze_intrafragment = 0; + +// write final step ; default (false); + //Opt_params.write_final_step_geometry = rem_read(REM_GEOM_OPT2_WRITE_FINAL_STEP_GEOMETRY); + Opt_params.write_final_step_geometry = false; + +// {NONE, BFGS, MS, POWELL, BOFILL} (default 1) + //i = rem_read(REM_GEOM_OPT2_H_UPDATE); + i=1; + if (i == 0) Opt_params.H_update = OPT_PARAMS::NONE; + else if (i == 1) Opt_params.H_update = OPT_PARAMS::BFGS; + else if (i == 2) Opt_params.H_update = OPT_PARAMS::MS; + else if (i == 3) Opt_params.H_update = OPT_PARAMS::POWELL; + else if (i == 4) Opt_params.H_update = OPT_PARAMS::BOFILL; + +// previous steps to use ; (0=all) ; default (6) + //Opt_params.H_update_use_last = rem_read(REM_GEOM_OPT2_H_UPDATE_USE_LAST); + Opt_params.H_update_use_last = 6; + +// limit hessian changes (default true) + //Opt_params.H_update_limit = rem_read(REM_GEOM_OPT2_H_UPDATE_LIMIT); + +// scale is i / 10 (default 5 -> 0.5) ; max is i / 10 (default 10 -> 1.0) +// i = rem_read(REM_GEOM_OPT2_H_UPDATE_LIMIT_SCALE); + i=5; + Opt_params.H_update_limit_scale = i / 10; + + //i = rem_read(REM_GEOM_OPT2_H_UPDATE_LIMIT_MAX); + i=10; + Opt_params.H_update_limit_max = i / 10; + +// use 1/R(AB) ; (default 0) + //Opt_params.interfragment_distance_inverse = rem_read(REM_GEOM_OPT2_INTERFRAGMENT_DISTANCE_INVERSE); + Opt_params.interfragment_distance_inverse = 0; + +// H-bond distance = i / 10 ; default (43 -> 4.3) + //i = rem_read(REM_GEOM_OPT2_MAXIMUM_H_BOND_DISTANCE); + i=43; + Opt_params.maximum_H_bond_distance = i / 10; + +// QCHEM optimization criteria ; names adapted from old QCHEM + //i = rem_read(REM_GEOM_OPT2_TOL_GRADIENT); + i=300; + Opt_params.conv_max_force = i / 1.0e6; // default (300 -> 3e-4) + + //i = rem_read(REM_GEOM_OPT2_TOL_DISPLACEMENT); + i = 1200; + Opt_params.conv_max_disp = i / 1.0e6; // default (1200 -> 1.2e-3) + + //i = rem_read(REM_GEOM_OPT2_TOL_ENERGY); + i=100; + Opt_params.conv_max_DE = i / 1.0e8; // default (100 -> 1.0e-6) + +// test B (default 0) + //Opt_params.test_B = rem_read(REM_GEOM_OPT2_TEST_B); + Opt_params.test_B = 0; + //Opt_params.test_derivative_B = rem_read(REM_GEOM_OPT2_TEST_DERIVATIVE_B); + Opt_params.test_derivative_B = 0; + +// (default 1) + //Opt_params.print_lvl = rem_read(REM_GEOM_OPT2_PRINT_LVL); + Opt_params.print_lvl = 1; + +// read Hessian (default 0) + //Opt_params.read_cartesian_H = rem_read(REM_GEOM_OPT2_READ_CARTESIAN_H); + Opt_params.read_cartesian_H = 0; + + Opt_params.efp_fragments = 0; + +// are ONLY EFP fragments present + if(Opt_params.efp_fragments) + Opt_params.efp_fragments_only = false; + else { + Opt_params.efp_fragments_only = false; + } + +//#endif + +// ** Items are below unlikely to need modified + +// For RFO step, eigenvectors of augmented Hessian are divided by the last +// element unless it is smaller than this value {double} + Opt_params.rfo_normalization_min = 1.0e-8; + +// how close to pi should a torsion be to assume it may have passed through 180 + Opt_params.fix_tors_near_pi = 2.618; // ~150 degrees + +// torsional angles will not be computed if the contained bond angles are within +// this fraction of pi from 0 or from pi + Opt_params.tors_angle_lim = 0.005; + +// only used for determining which atoms in a fragment are acceptable for use +// as reference atoms. We avoid collinear sets. +// angle is 0/pi if the bond angle is within this fraction of pi from 0/pi + Opt_params.interfrag_collinear_tol = 0.01; + +// cos(torsional angle) must be this close to -1/+1 for angle to count as 0/pi + Opt_params.tors_cos_tol = 1e-10; + +// if bend exceeds this value, then also create linear bend complement + Opt_params.linear_bend_threshold = 3.05; // about 175 degrees + +// threshold for which entries in diagonalized redundant matrix are kept and inverted +// while computing a generalized inverse of a matrix + Opt_params.redundant_eval_tol = 1.0e-10; + +// Parameters that control the backtransformation to cartesian coordinates + Opt_params.bt_max_iter = 25; + Opt_params.bt_dx_conv = 1.0e-6; + Opt_params.bt_dx_conv_rms_change = 1.0e-12; + +// Hessian update is avoided if the denominators (Dq*Dq) or (Dq*Dg) are smaller than this + Opt_params.H_update_den_tol = 1e-7; + +// Hessian update is avoided if any internal coordinate has changed by more than this in radians/au + Opt_params.H_update_dq_tol = 0.5; + +// Some parameter error-checking / modification + if (Opt_params.efp_fragments_only) { + Opt_params.test_B = false; + Opt_params.test_derivative_B = false; + } + + if (Opt_params.print_lvl > 1) print_params(); + +} + +void print_params(void) { + + if (Opt_params.opt_type == OPT_PARAMS::MIN) + fprintf(outfile, "opt_type = %18s\n", "Minimum-energy search"); + else if (Opt_params.opt_type == OPT_PARAMS::TS) + fprintf(outfile, "opt_type = %18s\n", "Transition-state search"); + else if (Opt_params.opt_type == OPT_PARAMS::IRC) + fprintf(outfile, "opt_type = %18s\n", "IRC path following"); + + if (Opt_params.step_type == OPT_PARAMS::NR) + fprintf(outfile, "step_type = %18s\n", "N-R"); + else if (Opt_params.step_type == OPT_PARAMS::RFO) + fprintf(outfile, "step_type = %18s\n", "RFO"); + else if (Opt_params.step_type == OPT_PARAMS::P_RFO) + fprintf(outfile, "step_type = %18s\n", "P_RFO"); + + fprintf(outfile, "conv_max_force = %18.2e\n", Opt_params.conv_max_force); + fprintf(outfile, "conv_max_DE = %18.2e\n", Opt_params.conv_max_DE); + fprintf(outfile, "conv_max_disp = %18.2e\n", Opt_params.conv_max_disp); + + fprintf(outfile, "scale_connectivity = %18.2e\n", Opt_params.scale_connectivity); + + if (Opt_params.fragment_mode == OPT_PARAMS::SINGLE) + fprintf(outfile, "fragment_mode = %18s\n", "single"); + else if (Opt_params.fragment_mode == OPT_PARAMS::MULTI) + fprintf(outfile, "fragment_mode = %18s\n", "multi"); + + if (Opt_params.interfragment_mode == OPT_PARAMS::FIXED) + fprintf(outfile, "interfragment_mode = %18s\n", "fixed"); + else if (Opt_params.interfragment_mode == OPT_PARAMS::PRINCIPAL_AXES) + fprintf(outfile, "interfragment_mode = %18s\n", "principal axes"); + + if (Opt_params.generate_intcos_only) + fprintf(outfile, "generate_intcos_only = %18s\n", "true"); + else + fprintf(outfile, "generate_intcos_only = %18s\n", "false"); + + if (Opt_params.rfo_follow_root) + fprintf(outfile, "rfo_follow_root = %18s\n", "true"); + else + fprintf(outfile, "rfo_follow_root = %18s\n", "false"); + + fprintf(outfile, "rfo_root = %18d\n", Opt_params.rfo_root); + + fprintf(outfile, "rfo_normalization_min = %18.2e\n", Opt_params.rfo_normalization_min); + + if (Opt_params.intrafragment_H == OPT_PARAMS::FISCHER) + fprintf(outfile, "intrafragment_H = %18s\n", "Fischer"); + else if (Opt_params.intrafragment_H == OPT_PARAMS::SCHLEGEL) + fprintf(outfile, "intrafragment_H = %18s\n", "Schlegel"); + + if (Opt_params.interfragment_H == OPT_PARAMS::DEFAULT) + fprintf(outfile, "interfragment_H = %18s\n", "Default"); + else if (Opt_params.interfragment_H == OPT_PARAMS::FISCHER_LIKE) + fprintf(outfile, "interfragment_H = %18s\n", "Fischer_like"); + + if (Opt_params.H_update == OPT_PARAMS::NONE) + fprintf(outfile, "H_update = %18s\n", "None"); + else if (Opt_params.H_update == OPT_PARAMS::BFGS) + fprintf(outfile, "H_update = %18s\n", "BFGS"); + else if (Opt_params.H_update == OPT_PARAMS::MS) + fprintf(outfile, "H_update = %18s\n", "MS"); + else if (Opt_params.H_update == OPT_PARAMS::POWELL) + fprintf(outfile, "H_update = %18s\n", "Powell"); + else if (Opt_params.H_update == OPT_PARAMS::BOFILL) + fprintf(outfile, "H_update = %18s\n", "Bofill"); + + fprintf(outfile, "H_update_use_last = %18d\n", Opt_params.H_update_use_last); + + if (Opt_params.freeze_intrafragment) + fprintf(outfile, "freeze_intrafragment = %18s\n", "true"); + else + fprintf(outfile, "freeze_intrafragment = %18s\n", "false"); + + fprintf(outfile, "intrafragment_step_limit=%18.2e\n", Opt_params.intrafragment_step_limit); + + if (Opt_params.H_update_limit == OPT_PARAMS::DEFAULT) + fprintf(outfile, "H_update_limit = %18s\n", "true"); + else if (Opt_params.H_update_limit == OPT_PARAMS::FISCHER_LIKE) + fprintf(outfile, "H_update_limit = %18s\n", "false"); + + fprintf(outfile, "H_update_limit_scale = %18.2e\n", Opt_params.H_update_limit_scale); + fprintf(outfile, "H_update_limit_max = %18.2e\n", Opt_params.H_update_limit_max); + + if (Opt_params.interfragment_distance_inverse) + fprintf(outfile, "interfragment_distance_inverse=%12s\n", "true"); + else + fprintf(outfile, "interfragment_distance_inverse=%12s\n", "false"); + + if (Opt_params.write_final_step_geometry) + fprintf(outfile, "write_final_step_geometry= %16s\n", "true"); + else + fprintf(outfile, "write_final_step_geometry= %16s\n", "false"); + + fprintf(outfile, "maximum_H_bond_distance= %18.2e\n", Opt_params.maximum_H_bond_distance); + + if (Opt_params.read_cartesian_H) + fprintf(outfile, "read_cartesian_H = %18s\n", "true"); + else + fprintf(outfile, "read_cartesian_H = %18s\n", "false"); + + if (Opt_params.efp_fragments) + fprintf(outfile, "efp_fragments = %18s\n", "true"); + else + fprintf(outfile, "efp_fragments = %18s\n", "false"); + + if (Opt_params.efp_fragments_only) + fprintf(outfile, "efp_fragments_only = %18s\n", "true"); + else + fprintf(outfile, "efp_fragments_only = %18s\n", "false"); + +} + +} + diff --git a/optking/simple.h b/optking/simple.h new file mode 100644 index 0000000..9cdb8fb --- /dev/null +++ b/optking/simple.h @@ -0,0 +1,96 @@ +/*! \file simple.h + \ingroup optking + \brief simple internal coordinate base class +*/ + +#ifndef _opt_simple_h_ +#define _opt_simple_h_ + +#include +#include "mem.h" + +namespace opt { + +enum INTCO_TYPE {min_type, stre_type, bend_type, tors_type, max_type}; + +typedef const double * const * const GeomType; + +class SIMPLE { + + protected: + + INTCO_TYPE s_type; // type of simple + int s_natom; // # of atoms in internal definition, i.e., # of + // atoms with non-zero s-vectors + int *s_atom; // atom indices in internal definition + + bool s_frozen; // is internal coordinate constrained frozen? + + public: + + SIMPLE (INTCO_TYPE s_type_in, int s_natom_in, bool freeze_in) { + s_type = s_type_in; + s_natom = s_natom_in; + s_atom = init_int_array(s_natom); + s_frozen = freeze_in; + }; + + virtual ~SIMPLE() { // derived class destructors called first; then this one + free_int_array(s_atom); + } + + INTCO_TYPE g_type(void) const { return s_type; } + int g_natom(void) const { return s_natom; } + int g_atom(int a) const { return s_atom[a]; } + + bool is_frozen(void) { return s_frozen; } + void freeze(void) { s_frozen = true; } + void unfreeze(void) { s_frozen = false; } + + // do-nothing function overridden only by torsion class + virtual void fix_tors_near_180(GeomType geom) { return; } + + // do-nothing function overridden by stretch class + virtual bool is_hbond(void) const { return false; } + + // do-nothing function overridden by stretch class + virtual bool is_inverse_stre(void) const { return false; } + + // do-nothing function overridden by bend class + virtual bool is_linear_bend(void) const { return false; } + + // each internal coordinate type must provide the following virtual functions: + + // function to print coordinate definitions to intco.dat + virtual void print_intco_dat(FILE *fp, int atom_offset=0) const = 0; + + // return value of internal coordinate + virtual double value(GeomType geom) const = 0; + + // compute s vector (dq/dx, dq/dy, dq/dz) + virtual double ** DqDx(GeomType geom) const = 0; + + // compute second derivative (B' matrix elements) + // dq_i dq_j / dx^2, dydx, dy^2, dzdx, dzdy, dz^2 + virtual double ** Dq2Dx2(GeomType geom) const = 0; + + // print coordinates and value to output file + virtual void print(FILE *fp, GeomType geom, int atom_offset=0) const = 0; + + // print coordinates and displacements + virtual void print_disp(FILE *fp, const double old_q, const double f_q, + const double dq, const double new_q, int atom_offset = 0) const = 0; + + // for debugging, print s vectors to output file + virtual void print_s(FILE *fp, GeomType geom) const = 0; + + // each derived class should have an equality operator of this type that + // first checks types with g_type() and then, if true, compares + // the internal coordinates + virtual bool operator==(const SIMPLE & s2) const = 0; + +}; + +} + +#endif diff --git a/optking/stre.cpp b/optking/stre.cpp new file mode 100644 index 0000000..b6f41f3 --- /dev/null +++ b/optking/stre.cpp @@ -0,0 +1,188 @@ +/*! \file stre.cc + \ingroup optking + \brief stretch class definition +*/ + +#include "stre.h" +#include +#include "opt_except.h" + +#include "v3d.h" +#include "physconst.h" + +namespace opt { + +using namespace v3d; +using std::ostringstream; + +// constructor - makes sure As_atom[0] == s2.g_atom(0)) && (this->s_atom[1] == s2.g_atom(1))) + return true; + else if ((this->s_atom[0] == s2.g_atom(1)) && (this->s_atom[1] == s2.g_atom(0))) + return true; + else + return false; +} + +} + diff --git a/optking/stre.h b/optking/stre.h new file mode 100644 index 0000000..61c85eb --- /dev/null +++ b/optking/stre.h @@ -0,0 +1,51 @@ +/*! \file stre.h + \ingroup optking + \brief STRE class declaration +*/ + +#ifndef _opt_stretch_h_ +#define _opt_stretch_h_ + +#include "simple.h" + +namespace opt { + +class STRE : public SIMPLE { + + bool hbond; // whether stretch is a hydrogen bond + bool inverse_stre; // whether stretch is really 1/R + + public: + + STRE(int A_in, int B_in, bool freeze_in=false); + + ~STRE() { } // also calls ~SIMPLE() + + double value(GeomType geom) const; + + // compute and return array of first derivative (B matrix elements) + // returned matrix is [atom][x,y,z] + double **DqDx(GeomType geom) const; + + // compute and return array of second derivative (B' matrix elements) + // returned matrix is order 3N cart by 3N cart + double **Dq2Dx2(GeomType geom) const; + + void print(FILE *fp, GeomType geom, int atom_offset=0) const; + void print_intco_dat(FILE *fp, int atom_offset=0) const; + void print_s(FILE *fp, GeomType geom) const; + void print_disp(FILE *fp, const double old_q, const double f_q, + const double dq, const double new_q, int atom_offset = 0) const; + bool operator==(const SIMPLE & s2) const; + + void make_hbond(void) { hbond = true; } + bool is_hbond(void) const { return hbond; } + void make_inverse_stre(void) { inverse_stre = true; } + bool is_inverse_stre(void) const { return inverse_stre; } + +}; + +} + +#endif + diff --git a/optking/tors.cpp b/optking/tors.cpp new file mode 100644 index 0000000..ec35608 --- /dev/null +++ b/optking/tors.cpp @@ -0,0 +1,302 @@ +/*! \file tors.cc + \ingroup optking + \brief tors class +*/ + +#include "tors.h" + +//#include +//#include +#include + +#include "print.h" +#include "v3d.h" +#include "physconst.h" +#include "opt_params.h" +#include "cmath" +//#include "qcmath.h" + +#define EXTERN +#include "globals.h" + +namespace opt { + +extern OPT_PARAMS Opt_params; +using namespace v3d; +using std::ostringstream; + +// constructor - canonical order is A < D +TORS::TORS(int A_in, int B_in, int C_in, int D_in, bool freeze_in) : SIMPLE(tors_type, 4, freeze_in) { + + // fprintf(stdout,"constructing TORS A_in:%d B_in:%d C_in:%d D_in: %d, frozen %d\n", + // A_in, B_in, C_in, D_in, freeze_in); + + if ( A_in==B_in || A_in==C_in || A_in==D_in || B_in==C_in || B_in==D_in || C_in==D_in) + throw(INTCO_EXCEPT("TORS::TORS() Atoms defining tors are not unique.")); + + if (A_in < D_in) { + s_atom[0] = A_in; + s_atom[1] = B_in; + s_atom[2] = C_in; + s_atom[3] = D_in; + } + else { + s_atom[0] = D_in; + s_atom[1] = C_in; + s_atom[2] = B_in; + s_atom[3] = A_in; + } + near_180 = 0; +} + +void TORS::fix_tors_near_180(GeomType geom) { + double tval = value(geom); + if ( tval > Opt_params.fix_tors_near_pi) + near_180 = +1; + else if ( tval < -1*Opt_params.fix_tors_near_pi) + near_180 = -1; + else + near_180 = 0; + return; +} + +// compute angle and return value in radians +double TORS::value(GeomType geom) const { + double tau; + + if (! v3d_tors(geom[s_atom[0]], geom[s_atom[1]], geom[s_atom[2]], geom[s_atom[3]], tau) ) + throw(INTCO_EXCEPT("TORS::compute_val: bond angles will not permit torsion computation",true)); + + // Extend domain of torsion angles by checking past + // extend domain of torsions so delta(vals) can be calculated + if (near_180 == -1 && tau > Opt_params.fix_tors_near_pi) + return (-_pi - (_pi - tau)); + else if (near_180 == +1 && tau < -1*Opt_params.fix_tors_near_pi) + return (+_pi + (_pi + tau)); + else + return tau; +} + +inline int zeta(const int a, const int m, const int n) { + if (a == m) return 1; + else if (a == n) return -1; + else return 0; +} + +inline int delta(const int i, const int j) { + if (i == j) return 1; + else return 0; +} + + +// torsion is m-o-p-n +double ** TORS::DqDx(GeomType geom) const { + double **dqdx = init_matrix(4,3); + + double u[3], v[3], w[3]; + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[0]], u); // u=m-o eBA + v3d_axpy(-1, geom[s_atom[2]], geom[s_atom[3]], v); // v=n-p eCD + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[2]], w); // w=p-o eBC + double Lu = v3d_norm(u); // RBA + double Lv = v3d_norm(v); // RCD + double Lw = v3d_norm(w); // RBC + v3d_scm(1.0/Lu, u); // eBA + v3d_scm(1.0/Lv, v); // eCD + v3d_scm(1.0/Lw, w); // eBC + + double cos_u = v3d_dot(u,w); + double cos_v = - v3d_dot(v,w); + if (1.0 - cos_u*cos_u <= 1.0e-12) return dqdx; // abort and leave zero if 0 or 180 angle + if (1.0 - cos_v*cos_v <= 1.0e-12) return dqdx; // abort and leave zero if 0 or 180 angle + double sin_u = sqrt(1.0 - cos_u*cos_u); + double sin_v = sqrt(1.0 - cos_v*cos_v); + + double uXw[3], vXw[3]; + v3d_cross_product(u, w, uXw); + v3d_cross_product(v, w, vXw); + + double tval1, tval2, tval3, tval4; + for (int a=0; a<4; ++a) // atoms + for (int i=0; i<3; ++i) { //i=a_xyz + tval1 = tval2 = tval3 = tval4 = 0.0; + + if ((a == 0) || (a == 1)) + tval1 = zeta(a,0,1) * uXw[i] / (Lu*sin_u*sin_u); + + if ((a == 2) || (a == 3)) + tval2 = zeta(a,2,3) * vXw[i] / (Lv*sin_v*sin_v); + + if ((a == 1) || (a == 2)) + tval3 = zeta(a,1,2) * uXw[i]*cos_u/(Lw*sin_u*sin_u); + + if ((a == 1) || (a == 2)) // "+" sign (or zeta(a,2,1)) differs from JCP, 117, 9164 (2002) + tval4 = - zeta(a,2,1) * vXw[i]*cos_v/(Lw*sin_v*sin_v); + + dqdx[a][i] = tval1 + tval2 + tval3 + tval4; + } + + return dqdx; +} + +// torsion is m-o-p-n +// There are several errors in JCP, 22, 9164, (2002) +// I identified incorrect signs by making the equations invariant to reversing the atom indices +// (0,1,2,3) -> (3,2,1,0) and checking terms against finite differences. Also, the last terms +// with sin^2 in the denominator are incorrectly given as only sin^1 in the paper. +// -RAK 2010 +double ** TORS::Dq2Dx2(GeomType geom) const { + double **dq2dx2 = init_matrix(12,12); + + double u[3], v[3], w[3]; + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[0]], u); // u=m-o eBA + v3d_axpy(-1, geom[s_atom[2]], geom[s_atom[3]], v); // v=n-p eCD + v3d_axpy(-1, geom[s_atom[1]], geom[s_atom[2]], w); // w=p-o eBC + double Lu = v3d_norm(u); // RBA + double Lv = v3d_norm(v); // RCD + double Lw = v3d_norm(w); // RBC + v3d_scm(1.0/Lu, u); // eBA + v3d_scm(1.0/Lv, v); // eCD + v3d_scm(1.0/Lw, w); // eBC + + double cos_u = v3d_dot(u,w); + double cos_v = -1.0 * v3d_dot(v,w); + if (1.0 - cos_u*cos_u <= 1.0e-12) return dq2dx2; // abort and leave zero if 0 or 180 angle + if (1.0 - cos_v*cos_v <= 1.0e-12) return dq2dx2; // abort and leave zero if 0 or 180 angle + double sin_u = sqrt(1.0 - cos_u*cos_u); + double sin_v = sqrt(1.0 - cos_v*cos_v); + + double uXw[3], vXw[3]; + v3d_cross_product(u, w, uXw); + v3d_cross_product(v, w, vXw); + + double sinu4 = sin_u*sin_u*sin_u*sin_u; + double sinv4 = sin_v*sin_v*sin_v*sin_v; + double cosu3 = cos_u*cos_u*cos_u; + double cosv3 = cos_v*cos_v*cos_v; + + double tval, tval1, tval1b, tval2, tval2b, tval3, tval3b, tval4, tval4b; + + int k; // cartesian ; not i or j + for (int a=0; a<4; ++a) { + for (int b=0; b<=a; ++b) { + for (int i=0; i<3; ++i) { //i = a_xyz + for (int j=0; j<3; ++j) { //j=b_xyz + tval = 0; + + if ((a==0 && b==0) || (a==1 && b==0) || (a==1 && b ==1)) + tval += zeta(a,0,1)*zeta(b,0,1)*(uXw[i]*(w[j]*cos_u-u[j]) + uXw[j]*(w[i]*cos_u-u[i])) / (Lu*Lu*sinu4); + + // above under reversal of atom indices, u->v ; w->(-w) ; uXw->(-uXw) + if ((a==3 && b==3) || (a==3 && b==2) || (a==2 && b==2)) + tval += zeta(a,3,2)*zeta(b,3,2)*(vXw[i]*(w[j]*cos_v+v[j]) + vXw[j]*(w[i]*cos_v+v[i])) / (Lv*Lv*sinv4); + + if ((a==1 && b==1) || (a==2 && b==1) || (a==2 && b==0) || (a==1 && b==0)) + tval += (zeta(a,0,1)*zeta(b,1,2)+zeta(a,2,1)*zeta(b,1,0)) * + (uXw[i] * (w[j] - 2*u[j]*cos_u + w[j]*cos_u*cos_u) + + uXw[j] * (w[i] - 2*u[i]*cos_u + w[i]*cos_u*cos_u)) / (2*Lu*Lw*sinu4); + + if ((a==3 && b==2) || (a==3 && b==1) || (a==2 && b==2) || (a==2 && b==1)) + tval += (zeta(a,3,2)*zeta(b,2,1)+zeta(a,1,2)*zeta(b,2,3)) * + (vXw[i] * (w[j] + 2*v[j]*cos_v + w[j]*cos_v*cos_v) + + vXw[j] * (w[i] + 2*v[i]*cos_v + w[i]*cos_v*cos_v)) / (2*Lv*Lw*sinv4); + + if ((a==1 && b==1) || (a==2 && b==2) || (a==2 && b==1)) + tval += zeta(a,1,2)*zeta(b,2,1)* + (uXw[i]*(u[j] + u[j]*cos_u*cos_u - 3*w[j]*cos_u + w[j]*cosu3) + + uXw[j]*(u[i] + u[i]*cos_u*cos_u - 3*w[i]*cos_u + w[i]*cosu3)) / (2*Lw*Lw*sinu4); + + if ((a==2 && b==1) || (a==2 && b==2) || (a==1 && b==1)) + tval += zeta(a,2,1)*zeta(b,1,2)* + (vXw[i]*(-v[j] - v[j]*cos_v*cos_v - 3*w[j]*cos_v + w[j]*cosv3) + + vXw[j]*(-v[i] - v[i]*cos_v*cos_v - 3*w[i]*cos_v + w[i]*cosv3)) / (2*Lw*Lw*sinv4); + + if ((a != b) && (i != j)) { + if ( i!=0 && j!=0 ) k = 0; // k is unique coordinate not i or j + else if ( i!=1 && j!=1 ) k = 1; + else k = 2; + + if (a==1 && b==1) + tval += zeta(a,0,1)*zeta(b,1,2) * (j-i) * + pow(-0.5, fabs((double)(j-i))) * (+w[k]*cos_u - u[k]) / (Lu*Lw*sin_u*sin_u); + + if ((a==3 && b==2) || (a==3 && b==1) || (a==2 && b==2) || (a==2 && b==1)) + tval += zeta(a,3,2)*zeta(b,2,1) * (j-i) * + pow(-0.5, fabs((double)(j-i))) * (-w[k]*cos_v - v[k]) / (Lv*Lw*sin_v*sin_v); + + if ((a==2 && b==1) || (a==2 && b==0) || (a==1 && b==1) || (a==1 && b==0)) + tval += zeta(a,2,1)*zeta(b,1,0) * (j-i) * + pow(-0.5, fabs((double)(j-i))) * (-w[k]*cos_u + u[k]) / (Lu*Lw*sin_u*sin_u); + + if (a==2 && b==2) + tval += zeta(a,1,2)*zeta(b,2,3) * (j-i) * + pow(-0.5, fabs((double)(j-i))) * (+w[k]*cos_v + v[k]) / (Lv*Lw*sin_v*sin_v); + } + dq2dx2[3*a+i][3*b+j] = dq2dx2[3*b+j][3*a+i] = tval; + } // j + } // i + } // atom b + } // atom a + return dq2dx2; +} + + +void TORS::print(FILE *fp, GeomType geom, int off) const { + ostringstream iss(ostringstream::out); // create stream; allow output to it + iss << "D(" << s_atom[0]+1+off << "," << s_atom[1]+1+off << "," << s_atom[2]+1+off << "," << s_atom[3]+1+off << ")" << std::flush; + double val = value(geom); + if (!s_frozen) + fprintf(fp,"\t %-15s = %15.6lf\t%15.6lf\n", iss.str().c_str(), val, val/_pi*180.0); + else + fprintf(fp,"\t*%-15s = %15.6lf\t%15.6lf\n", iss.str().c_str(), val, val/_pi*180.0); + fflush(fp); +} + +void TORS::print_disp(FILE *fp, const double q_old, const double f_q, + const double dq, const double q_new, int atom_offset) const { + ostringstream iss(ostringstream::out); // create stream; allow output to it + if (s_frozen) iss << "*"; + iss << "D(" << s_atom[0]+atom_offset+1 << "," << s_atom[1]+atom_offset+1 << "," + << s_atom[2]+atom_offset+1 << "," << s_atom[3]+atom_offset+1 << ")" << std::flush; + fprintf(fp,"\t %-15s = %13.6lf%13.6lf%13.6lf%13.6lf\n", + iss.str().c_str(), q_old/_pi*180.0, f_q*_pi/180.0,dq/_pi*180.0, q_new/_pi*180.0); + fflush(fp); +} + +void TORS::print_intco_dat(FILE *fp, int off) const { + if (s_frozen) + fprintf(fp, "D*%6d%6d%6d%6d\n", s_atom[0]+1+off, s_atom[1]+1+off, + s_atom[2]+1+off, s_atom[3]+1+off); + else + fprintf(fp, "D %6d%6d%6d%6d\n", s_atom[0]+1+off, s_atom[1]+1+off, + s_atom[2]+1+off, s_atom[3]+1+off); + fflush(fp); +} + +void TORS::print_s(FILE *fp, GeomType geom) const { + fprintf(fp,"S vector for tors, D(%d %d %d %d): \n", + s_atom[0]+1, s_atom[1]+1, s_atom[2]+1, s_atom[3]+1); + double **dqdx = DqDx(geom); + fprintf(fp, "Atom 1: %12.8f %12.8f,%12.8f\n", dqdx[0][0], dqdx[0][1], dqdx[0][2]); + fprintf(fp, "Atom 2: %12.8f %12.8f,%12.8f\n", dqdx[1][0], dqdx[1][1], dqdx[1][2]); + fprintf(fp, "Atom 3: %12.8f %12.8f,%12.8f\n", dqdx[2][0], dqdx[2][1], dqdx[2][2]); + fprintf(fp, "Atom 4: %12.8f %12.8f,%12.8f\n", dqdx[3][0], dqdx[3][1], dqdx[3][2]); + free_matrix(dqdx); + fflush(fp); +} + +bool TORS::operator==(const SIMPLE & s2) const { + if (tors_type != s2.g_type()) + return false; + + if (this->s_atom[0] == s2.g_atom(0) && this->s_atom[1] == s2.g_atom(1) && + this->s_atom[2] == s2.g_atom(2) && this->s_atom[3] == s2.g_atom(3) ) + return true; + else if (this->s_atom[0] == s2.g_atom(3) && this->s_atom[1] == s2.g_atom(2) && + this->s_atom[2] == s2.g_atom(1) && this->s_atom[3] == s2.g_atom(0) ) + return true; + else + return false; +} + +} + diff --git a/optking/tors.h b/optking/tors.h new file mode 100644 index 0000000..c40bbf8 --- /dev/null +++ b/optking/tors.h @@ -0,0 +1,48 @@ +/*! \file tors.h + \ingroup optking + \brief TORS class declaration +*/ + +#ifndef _opt_tors_h_ +#define _opt_tors_h_ + +#include "simple.h" + +namespace opt { + +class TORS : public SIMPLE { + + private: + int near_180; + // +1 if positive and approaching 180 + // -1 if negative and approaching -180 + // 0 otherwise + + public: + + TORS(int A_in, int B_in, int C_in, int D_in, bool freeze_in=false); + + ~TORS() { } // also calls ~SIMPLE + + double value(GeomType geom) const; + + // compute and return array of first derivative (B marix elements) + double ** DqDx(GeomType geom) const; + + // compute and return array of second derivative (B' matrix elements) + double ** Dq2Dx2(GeomType geom) const; + + void print(FILE *fp, GeomType geom, int atom_offset=0) const; + void print_intco_dat(FILE *fp, int atom_offset=0) const; + void print_s(FILE *fp, GeomType geom) const; + void print_disp(FILE *fp, const double old_q, const double f_q, + const double dq, const double new_q, int atom_offset=0) const; + bool operator==(const SIMPLE & s2) const; + + void fix_tors_near_180(GeomType geom); +}; + +} + +#endif + diff --git a/optking/v3d.cpp b/optking/v3d.cpp new file mode 100644 index 0000000..b6b6b33 --- /dev/null +++ b/optking/v3d.cpp @@ -0,0 +1,108 @@ +/*! \file v3d.cc + \ingroup optking + \brief v3d functions +*/ + +#include "v3d.h" + +#define EXTERN +#include "globals.h" + +namespace opt { namespace v3d { + +// Compute angle in radians A-B-C (between vector B->A and vector B->C) +// if points are absurdly close or far apart, returns false +// tol is closeness of cos to 1/-1 that will count as exactly 0/pi +bool v3d_angle(const double *A, const double *B, const double *C, double & phi, double tol) { + double dotprod, eBA[3], eBC[3]; + + // eBA + if (! v3d_eAB(B, A, eBA) ) { +fprintf(outfile, "could not normalize eBA, \n B:"); +for (int i=0; i<3; ++i) fprintf(outfile,"%15.10lf", B[i]); +fprintf(outfile,"\n A:"); +for (int i=0; i<3; ++i) fprintf(outfile,"%15.10lf", A[i]); +fprintf(outfile,"\n eBA:"); +for (int i=0; i<3; ++i) fprintf(outfile,"%15.10lf", eBA[i]); +fprintf(outfile,"\n"); + return false; + } + + // eBC + if (! v3d_eAB(B, C, eBC) ) { +fprintf(outfile, "could not normalize eBC, \n B:"); +for (int i=0; i<3; ++i) fprintf(outfile,"%15.10lf", B[i]); +fprintf(outfile,"\n C:"); +for (int i=0; i<3; ++i) fprintf(outfile,"%15.10lf", C[i]); +fprintf(outfile,"\n eBC:"); +for (int i=0; i<3; ++i) fprintf(outfile,"%15.10lf", eBC[i]); +fprintf(outfile,"\n"); + return false; + } + + dotprod = v3d_dot(eBA,eBC); + + if (dotprod > 1.0-tol) + phi = 0.0; + else if (dotprod < -1.0+tol) + phi = acos(-1.0); + else + phi = acos(dotprod); + + return true; +} + +// returns false if bond angles are too large for good torsion definition +bool v3d_tors(const double *A, const double *B, const double *C, const double *D, + double & tau) { + double tval, phi_123, phi_234, ulim, llim; + double eAB[3], eBC[3], eCD[3], tmp[3], tmp2[3]; + + tau = 0.0; + + // form e unit vectors + if ( !v3d_eAB(A,B,eAB) || !v3d_eAB(B,C,eBC) || !v3d_eAB(C,D,eCD) ) + throw(INTCO_EXCEPT("v3d_tors: distances are not reasonably normalized for e vectors.",true)); + + //printf("v3d_eAB : %15.10lf %15.10lf %15.10lf \n", eAB[0], eAB[1], eAB[2]); + //printf("v3d_eBC : %15.10lf %15.10lf %15.10lf \n", eBC[0], eBC[1], eBC[2]); + //printf("v3d_eCD : %15.10lf %15.10lf %15.10lf \n", eCD[0], eCD[1], eCD[2]); + + // compute bond angles + if ( !v3d_angle(A, B, C, phi_123) || !v3d_angle(B, C, D, phi_234) ) + throw(INTCO_EXCEPT("v3d_tors: distances are not reasonably normalized for angles.",true)); + + //printf("v3d_tors : phi123 = %15.10lf\n", phi_123); + //printf("v3d_tors : phi234 = %15.10lf\n", phi_234); + + // check bond angles; don't allow torsions with angles between 1.8 degrees of singularity + const double pi = acos(-1.0); + llim = Opt_params.tors_angle_lim * pi; + ulim = (1-Opt_params.tors_angle_lim) * pi; + if (phi_123 < llim || phi_123 > ulim) + return false; + else if (phi_234 < llim || phi_234 > ulim) + return false; + + v3d_cross_product(eAB,eBC,tmp); + v3d_cross_product(eBC,eCD,tmp2); + tval = v3d_dot(tmp,tmp2) / (sin(phi_123) * sin(phi_234) ); + + if (tval >= 1.0 - Opt_params.tors_cos_tol) + tau = 0.0; + else if (tval <= -1.0 + Opt_params.tors_cos_tol) + tau = pi; + else + tau = acos(tval); + + // determine sign of torsion ; this convention matches Wilson, Decius and Cross + v3d_cross_product(eBC,eCD,tmp); + tval = v3d_dot(eAB, tmp); + if (tval < 0) tau *= -1; + + return true; +} + + +}} + diff --git a/optking/v3d.h b/optking/v3d.h new file mode 100644 index 0000000..e763fe3 --- /dev/null +++ b/optking/v3d.h @@ -0,0 +1,91 @@ +/*! \file v3d.h + \ingroup optking + \brief Functions for real-space vectors of length 3 +*/ + +#ifndef _opt_v3d_h_ +#define _opt_v3d_h_ + +//#include "qcmath.h" +#include +#define V3D_SQR(x) ((x)*(x)) + +#define PARALLEL_LIMIT (1.0e-10) + +namespace opt { namespace v3d { + +// scalar multiply a vector +inline void v3d_scm(const double a, double *A) { + A[0] *= a; A[1] *= a; A[2] *= a; +} + +// compute norm of a vector +inline double v3d_norm(const double *A) { + return sqrt(A[0]*A[0] + A[1]*A[1] + A[2]*A[2]); +} + +// take dot product of two vectors +inline double v3d_dot(const double *A, const double *B) { + return (A[0]*B[0] + A[1]*B[1] + A[2]*B[2]); +} + +// returns distance between 2 points +inline double v3d_dist(const double *A, const double *B) { + return sqrt(V3D_SQR(B[0]-A[0]) + V3D_SQR(B[1]-A[1]) + V3D_SQR(B[2]-A[2])); +} + +// Compute a*X + Y -> Z +inline void v3d_axpy(const double a, const double *X, const double *Y, double *Z) { + Z[0] = a*X[0] + Y[0]; + Z[1] = a*X[1] + Y[1]; + Z[2] = a*X[2] + Y[2]; +} + +// normalize vector. Return "false and leave A unchanged if norm of A is +// less than min_norm or greater than max_norm +inline bool v3d_normalize(double *A, const double min_norm=1.0e-8, const double max_norm=1.0e8) { + double tval = v3d_norm(A); + if ( tval < min_norm || tval > max_norm) + return false; + else + v3d_scm(1.0/tval, A); + return true; +} + +// Compute cross product of two vectors +inline void v3d_cross_product(const double *u, const double *v, double *X) { + X[0] = u[1]*v[2]-u[2]*v[1]; + X[1] = -1.0*(u[0]*v[2]-u[2]*v[0]); + X[2] = u[0]*v[1]-u[1]*v[0]; + return; +} + +// check to see if two vectors are parallel, i.e., is |A.B| close to 1 +inline bool v3d_is_parallel(const double *A, const double *B) { + if ( fabs( fabs(v3d_dot(A,B)) - 1.0e0) > PARALLEL_LIMIT ) + return false; + else + return true; +} + +// Compute vector A->B. Normalize eAB. Return "false" and do not normalize +// eAB if points are too close or distant +inline bool v3d_eAB(const double *A, const double *B, double *eAB, +const double min_norm=1.0e-8, const double max_norm=1.0e15) { + v3d_axpy(-1, A, B, eAB); + return ( v3d_normalize(eAB, min_norm, max_norm) ); +} + +// Computed angle in radians A-B-C (between vector B->A and vector B->C) +// if points are absurdly close or far apart, returns false +// tol is nearness of cos to 1/-1 to make angle 0/pi +bool v3d_angle(const double *A, const double *B, const double *C, double & phi, double tol=1e-14); + +// Computed torsional angle in radians A-B-C-D +// Returns false if bond angles ABC or BCD are too close to 0 or 180 +bool v3d_tors(const double *A, const double *B, const double *C, const double *D, double & tau); + +}} + +#endif +