///	<summary>
	///		Evaluate the reference state at the given point.
	///	</summary>
	virtual void EvaluateReferenceState(
		const PhysicalConstants & phys,
		double dZ,
		double dLon,
		double dLat,
		double * dState
	) const {

		// 3D temperature
		double dT = m_dT0 - m_dGamma * dZ;

		// 3D pressure
		double dPressure = phys.GetP0()
			* pow(1.0 - m_dGamma / m_dT0 * dZ,
				phys.GetG() / (phys.GetR() * m_dGamma));

		// 3D density
		double dRho = dPressure / (phys.GetR() * dT);

		// Store the state
		dState[0] = 0.0;
		dState[1] = 0.0;
		dState[2] = phys.RhoThetaFromPressure(dPressure) / dRho;
		dState[3] = 0.0;
		dState[4] = dRho;
	}
	///	<summary>
	///		Evaluate the state vector at the given point.
	///	</summary>
	virtual void EvaluatePointwiseState(
		const PhysicalConstants & phys,
		const Time & time,
		double dZp,
		double dXp,
		double dYp,
		double * dState,
		double * dTracer
	) const {
		const double dG = phys.GetG();
		const double dCv = phys.GetCv();
		const double dCp = phys.GetCp();
		const double dRd = phys.GetR();
		const double dP0 = phys.GetP0();

		// The Brunt-Vaisala frequency
		const double dNbar = dG / sqrt(dCp * m_dT0);

		// Base potential temperature field
		const double dTheta0 = m_dT0;
		double dThetaBar = dTheta0 * exp(dNbar * dNbar / dG * dZp);

		// Set the uniform U, V, W field for all time
		dState[0] = m_dU0;
		dState[1] = 0.0;
		dState[3] = 0.0;

		// Set the initial potential temperature field
		dState[2] = dThetaBar;

		// Set the initial density based on the Exner pressure
		double dExnerP = exp(-dG / (dCp * m_dT0) * dZp);
		double dRho = dP0 / (dRd * dThetaBar) * pow(dExnerP,(dCv / dRd));
		dState[4] = dRho;
	}
	///	<summary>
	///		Calculate eta at the given point via Newton iteration.  The
	///		geopotential and temperature at this point are also returned via
	///		command-line parameters.
	///	</summary>
	double EtaFromRLL(
		const PhysicalConstants &phys,
		double dZp,
		double dXp,
		double dYp,
		double & dGeopotential,
		double & dTemperature
	) const {
		const int MaxIterations  = 50;
		const double InitialEta  = 1.0e-5;
		const double Convergence = 1.0e-13;

		// Buffer variables
		double dEta = InitialEta;
		double dNewEta;

		double dF;
		double dDiffF;

		// Iterate until convergence is achieved
		int i = 0;
		for (; i < MaxIterations; i++) {

			CalculateGeopotentialTemperature(
				phys, dEta, dXp, dYp, dGeopotential, dTemperature);

			dF     = - phys.GetG() * dZp + dGeopotential;
			dDiffF = - phys.GetR() / dEta * dTemperature;

			dNewEta = dEta - dF / dDiffF;

			if (fabs(dEta - dNewEta) < Convergence) {
				return dNewEta;
			}

			dEta = dNewEta;
		}

		// Check for convergence failure
		if (i == MaxIterations) {
			_EXCEPTIONT("Maximum number of iterations exceeded.");
		}

		if ((dEta > 1.0) || (dEta < 0.0)) {
			_EXCEPTIONT("Invalid Eta value");
		}
		return dEta;
	}
	///	<summary>
	///		Evaluate the reference state at the given point.
	///	</summary>
	virtual void EvaluateReferenceState(
		const PhysicalConstants & phys,
		double dZp,
		double dXp,
		double dYp,
		double * dState
	) const {
		const double dG = phys.GetG();
		const double dCv = phys.GetCv();
		const double dCp = phys.GetCp();
		const double dRd = phys.GetR();
		const double dP0 = phys.GetP0();

		// Base potential temperature field
		double dThetaBar = m_dTheta0 * exp(m_dNbar * m_dNbar / dG * dZp);

		// Set the uniform U, V, W field for all time
		dState[0] = m_dU0;
		dState[1] = 0.0;
		dState[3] = 0.0;

		// Zero gravity case
		if (dG == 0.0) {
			static double dT0 = 300.0;

			dState[2] = dT0 * pow(dP0, (dRd / dCp));
			dState[4] = dP0 / (dRd * dT0);

		// Stratification with gravity
		} else {
			// Set the initial density based on the Exner pressure
			double dExnerP = (dG * dG) / (dCp * m_dTheta0 * m_dNbar * m_dNbar);
			dExnerP *= (exp(-m_dNbar * m_dNbar / dG * dZp) - 1.0);
			dExnerP += 1.0;
			double dRho = dP0 / (dRd * dThetaBar) * pow(dExnerP,(dCv / dRd));
			dState[4] = dRho;

			// Set the initial potential temperature field
			//dState[2] = phys.PressureFromRhoTheta(dThetaBar * dRho);
			//dState[2] = (dThetaBar * dRho);
			dState[2] = dThetaBar;
		}
	}
	///	<summary>
	///		Calculate the geopotential and temperature at the given point.
	///	</summary>
	void CalculateGeopotentialTemperature(
		const PhysicalConstants & phys,
		double dEta,
		double dXp,
		double dYp,
		double & dGeopotential,
		double & dTemperature
	) const {
		// Get some constants
		const double dG = phys.GetG();
		const double dCv = phys.GetCv();
		const double dCp = phys.GetCp();
		const double dRd = phys.GetR();
		const double dP0 = phys.GetP0();
		const double dae = phys.GetEarthRadius();
		const double df0 = 2 * phys.GetOmega() * sin(m_dRefLat);
		//const double df0 = 0.0;
		const double dbeta0 = 2 * phys.GetOmega() * cos(m_dRefLat) / dae;
		//const double dbeta0 = 0.0;
		const double dLy = m_dGDim[3] - m_dGDim[2];

		// Horizontally averaged temperature
		double dAvgTemperature =
			m_dT0 * pow(dEta, dRd * m_ddTdz / dG);

		// Horizontally averaged geopotential
		double dAvgGeopotential =
			m_dT0 * dG / m_ddTdz * 
			(1.0 - pow(dEta, dRd * m_ddTdz / dG));

		// Horizontal variation geopotential function
		double dXYGeopotential = 0.5 * m_dU0 * 
			((df0 - dbeta0 * m_dY0) * (dYp - m_dY0 - 
			m_dY0 / m_dpiC * sin(2 * m_dpiC * dYp / dLy)) + 
			0.5 * dbeta0 * 
			(dYp * dYp - dLy * dYp / m_dpiC * sin(2 * m_dpiC * dYp / dLy) - 
			0.5 * dLy * dLy / (m_dpiC * m_dpiC) * cos(2 * m_dpiC * dYp / dLy) -
			dLy * dLy / 3 - 0.5 * dLy * dLy / (m_dpiC * m_dpiC)));

		double dExpDecay = exp(-(log(dEta) / m_dbC) * (log(dEta) / m_dbC));
		double dRefProfile1 = log(dEta);
		double dRefProfile2 = 2 / (m_dbC * m_dbC) * log(dEta) * log(dEta) - 1.0;

		// Total geopotential distribution
		dGeopotential = dAvgGeopotential + dXYGeopotential*
			dRefProfile1 * dExpDecay;
		
		// Total temperature distribution
		dTemperature = dAvgTemperature + dXYGeopotential / dRd *
			dRefProfile2 * dExpDecay;
	}
Пример #6
0
Material::ChemicalFormula
Material::parseChemicalFormula(const std::string chemicalSymbol) {
  Material::ChemicalFormula CF;

  tokenizer tokens(chemicalSymbol, " -",
                   Mantid::Kernel::StringTokenizer::TOK_IGNORE_EMPTY);
  for (auto atom = tokens.begin(); atom != tokens.end(); ++atom) {
    try {
      std::string name(*atom);
      float numberAtoms = 1;
      uint16_t aNumber = 0;

      // split out the isotope bit
      if (atom->find('(') != std::string::npos) {
        // error check
        size_t end = atom->find(')');
        if (end == std::string::npos) {
          std::stringstream msg;
          msg << "Failed to parse isotope \"" << name << "\"";
          throw std::runtime_error(msg.str());
        }

        // get the number of atoms
        std::string numberAtomsStr = name.substr(end + 1);
        if (!numberAtomsStr.empty())
          numberAtoms = boost::lexical_cast<float>(numberAtomsStr);

        // split up the atom and isotope number
        name = name.substr(1, end - 1);
        str_pair temp = getAtomName(name);

        name = temp.first;
        aNumber = boost::lexical_cast<uint16_t>(temp.second);
      } else // for non-isotopes
      {
        str_pair temp = getAtomName(name);
        name = temp.first;
        if (!temp.second.empty())
          numberAtoms = boost::lexical_cast<float>(temp.second);
      }

      CF.atoms.push_back(boost::make_shared<Atom>(getAtom(name, aNumber)));
      CF.numberAtoms.push_back(numberAtoms);
    } catch (boost::bad_lexical_cast &e) {
      std::stringstream msg;
      msg << "While trying to parse atom \"" << (*atom)
          << "\" encountered bad_lexical_cast: " << e.what();
      throw std::runtime_error(msg.str());
    }
  }

  return CF;
}
	///	<summary>
	///		Evaluate the reference state at the given point.
	///	</summary>
	virtual void EvaluateReferenceState(
		const PhysicalConstants & phys,
		double dZp,
		double dXp,
		double dYp,
		double * dState
	) const {
		const double dLy = m_dGDim[3] - m_dGDim[2];

		// Pressure coordinate
		double dGeopotential;
		double dTemperature;

		double dEta = EtaFromRLL(
			phys, dZp, dXp, dYp, dGeopotential, dTemperature);

		// Calculate zonal velocity and set other velocity components
		double dExpDecay = exp(-(log(dEta) / m_dbC) * (log(dEta) / m_dbC));
		double dUlon =
			-m_dU0 * sin(m_dpiC * dYp / dLy) * sin(m_dpiC * dYp / dLy) *
			 log(dEta) * dExpDecay;

		dState[0] = dUlon;
		dState[1] = 0.0;
		dState[3] = 0.0;

		// Calculate rho and theta
		double dPressure = phys.GetP0() * dEta;
		//std::cout << std::setprecision(16) << "Z = " << dZp << " Eta = " << dEta << "\n";

		double dRho = dPressure / (phys.GetR() * dTemperature);

		double dRhoTheta = phys.RhoThetaFromPressure(dPressure);

		dState[2] = dRhoTheta / dRho;
		dState[4] = dRho;
	}
	///	<summary>
	///		Evaluate the state vector at the given point.
	///	</summary>
	virtual void EvaluatePointwiseState(
		const PhysicalConstants & phys,
		const Time & time,
		double dZp,
		double dXp,
		double dYp,
		double * dState,
		double * dTracer
	) const {
		const double dG = phys.GetG();
		const double dCv = phys.GetCv();
		const double dCp = phys.GetCp();
		const double dRd = phys.GetR();
		const double dP0 = phys.GetP0();

		// Base potential temperature field
		double dThetaBar = m_dTheta0 * exp(m_dNbar * m_dNbar / dG * dZp);

		// Set the uniform U, V, W field for all time
		dState[0] = m_dU0;
		dState[1] = 0.0;
		dState[3] = 0.0;
		dState[3] = sin(M_PI * dZp / m_dGDim[5]);

		// Set the initial density based on the Exner pressure
		double dExnerP = (dG * dG) / (dCp * m_dTheta0 * m_dNbar * m_dNbar);
		dExnerP *= (exp(-m_dNbar * m_dNbar / dG * dZp) - 1.0);
		dExnerP += 1.0;
		double dRho = dP0 / (dRd * dThetaBar) * pow(dExnerP,(dCv / dRd));
		dState[4] = dRho;

		// Set the initial theta field
		//dState[2] = phys.PressureFromRhoTheta(dThetaBar * dRho);
		//dState[2] = (dThetaBar * dRho);
		dState[2] = dThetaBar;
	}
	///	<summary>
	///		Obtain test case specific physical constants.
	///	</summary>
	virtual void EvaluatePhysicalConstants(
		PhysicalConstants & phys
	) const {
		// No Coriolis
		phys.SetOmega(0.0);
	}
	///	<summary>
	///		Evaluate the state vector at the given point.
	///	</summary>
	virtual void EvaluatePointwiseState(
		const PhysicalConstants & phys,
		const Time & time,
		double dZ,
		double dLon,
		double dLat,
		double * dState,
		double * dTracer
	) const {

		// Radius
		double dR = dZ + phys.GetEarthRadius();

		// Calculate parameters
		double dT0 = 0.5 * (ParamT0E + ParamT0P);

		double dConstA = 1.0 / ParamLapseRate;

		double dConstB = (dT0 - ParamT0P) / (dT0 * ParamT0P);

		double dConstC = 0.5 * (ParamK + 2.0)
			* (ParamT0E - ParamT0P) / (ParamT0E * ParamT0P);

		double dConstH = phys.GetR() * dT0 / phys.GetG();

		// Computed quantities
		double dScaledZ = dZ / (ParamB * dConstH);

		// Calculate tau values
		double dTau1 =
			dConstA * ParamLapseRate / dT0
				* exp(ParamLapseRate / dT0 * dZ)
			+ dConstB
				* (1.0 - 2.0 * dScaledZ * dScaledZ)
				* exp(- dScaledZ * dScaledZ);

		double dTau2 =
			dConstC * (1.0 - 2.0 * dScaledZ * dScaledZ)
				* exp(- dScaledZ * dScaledZ);

		double dIntTau1 =
			dConstA * (exp(ParamLapseRate / dT0 * dZ) - 1.0)
			+ dConstB * dZ * exp(- dScaledZ * dScaledZ);

		double dIntTau2 =
			dConstC * dZ * exp(- dScaledZ * dScaledZ);

		// Calculate utility terms
		double dRRatio;
		if (m_fDeepAtmosphere) {
			dRRatio = dR / phys.GetEarthRadius();
		} else {
			dRRatio = 1.0;
		}

		double dInteriorTerm = pow(dRRatio * cos(dLat), ParamK)
			- ParamK / (ParamK + 2.0) * pow(dRRatio * cos(dLat), ParamK + 2.0);

		// Calculate temperature
		double dTemperature = 1.0
			/ (dRRatio * dRRatio)
			/ (dTau1 - dTau2 * dInteriorTerm);

		// Calculate hydrostatic pressure
		double dPressure = phys.GetP0() * exp(
			- phys.GetG() / phys.GetR()
				* (dIntTau1 - dIntTau2 * dInteriorTerm));

		// Calculate hydrostatic density
		double dRho = dPressure / (phys.GetR() * dTemperature);

		// Velocity field
		double dInteriorTermU =
			  pow(dRRatio * cos(dLat), ParamK - 1.0)
			- pow(dRRatio * cos(dLat), ParamK + 1.0);

		double dBigU = phys.GetG() / phys.GetEarthRadius() * ParamK
			* dIntTau2 * dInteriorTermU * dTemperature;

		double dRCosLat;
		if (m_fDeepAtmosphere) {
			dRCosLat = dR * cos(dLat);
		} else {
			dRCosLat = phys.GetEarthRadius() * cos(dLat);
		}

		double dOmegaRCosLat = phys.GetOmega() * dRCosLat;

		if (dOmegaRCosLat * dOmegaRCosLat + dRCosLat * dBigU < 0.0) {
			_EXCEPTIONT("Negative discriminant detected.");
		}

		double dUlon = - dOmegaRCosLat +
			sqrt(dOmegaRCosLat * dOmegaRCosLat + dRCosLat * dBigU);

		double dUlat = 0.0;

		// Calculate velocity perturbation
		double dUlonPert;
		double dUlatPert;

		EvaluatePointwisePerturbation(
			phys, dZ, dLon, dLat,
			dUlonPert, dUlatPert);

		dUlon += dUlonPert;
		dUlat += dUlatPert;

		// Store the state
		dState[0] = dUlon;
		dState[1] = dUlat;
		dState[2] = phys.RhoThetaFromPressure(dPressure) / dRho;
		dState[3] = 0.0;
		dState[4] = dRho;

	}
	///	<summary>
	///		Evaluate the reference state at the given point.
	///	</summary>
	virtual void EvaluateReferenceState(
		const PhysicalConstants & phys,
		double dZ,
		double dLon,
		double dLat,
		double * dState
	) const {

		// Radius
		double dR = dZ + phys.GetEarthRadius();

		// Calculate parameters
		double dT0 = 0.5 * (ParamT0E + ParamT0P);

		double dConstA = 1.0 / ParamLapseRate;

		double dConstB = (dT0 - ParamT0P) / (dT0 * ParamT0P);

		double dConstC = 0.5 * (ParamK + 2.0)
			* (ParamT0E - ParamT0P) / (ParamT0E * ParamT0P);

		double dConstH = phys.GetR() * dT0 / phys.GetG();

		// Computed quantities
		double dScaledZ = dZ / (ParamB * dConstH);

		// Calculate tau values
		double dTau1 =
			dConstA * ParamLapseRate / dT0
				* exp(ParamLapseRate / dT0 * dZ)
			+ dConstB
				* (1.0 - 2.0 * dScaledZ * dScaledZ)
				* exp(- dScaledZ * dScaledZ);

		double dTau2 =
			dConstC * (1.0 - 2.0 * dScaledZ * dScaledZ)
				* exp(- dScaledZ * dScaledZ);

		double dIntTau1 =
			dConstA * (exp(ParamLapseRate / dT0 * dZ) - 1.0)
			+ dConstB * dZ * exp(- dScaledZ * dScaledZ);

		double dIntTau2 =
			dConstC * dZ * exp(- dScaledZ * dScaledZ);

		// Calculate utility terms
		double dRRatio;
		if (m_fDeepAtmosphere) {
			dRRatio = dR / phys.GetEarthRadius();
		} else {
			dRRatio = 1.0;
		}

		double dInteriorTerm = pow(dRRatio * cos(dLat), ParamK)
			- ParamK / (ParamK + 2.0) * pow(dRRatio * cos(dLat), ParamK + 2.0);

		// Calculate temperature
		double dTemperature = 1.0
			/ (dRRatio * dRRatio)
			/ (dTau1 - dTau2 * dInteriorTerm);

		// Calculate hydrostatic pressure
		double dPressure = phys.GetP0() * exp(
			- phys.GetG() / phys.GetR()
				* (dIntTau1 - dIntTau2 * dInteriorTerm));
/*
		// Calculate pressure derivative
		double dDrPressure;
		if (m_fDeepAtmosphere) {
			dDrPressure =
				dPressure * phys.GetG() / phys.GetR() * (
					- dTau1 + dTau2 * dInteriorTerm
					+ dIntTau2 * ParamK / dR
						* (pow(dRRatio * cos(dLat), ParamK)
							- pow(dRRatio * cos(dLat), ParamK + 2.0)));

		} else {
			dDrPressure =
				dPressure * phys.GetG() / phys.GetR() * (
					- dTau1 + dTau2 * dInteriorTerm);
		}

		// Calculate hydrostatic density
		double dHydroRho = - dRRatio * dRRatio / phys.GetG() * dDrPressure;
*/
		// Calculate exact density
		double dRho = dPressure / (phys.GetR() * dTemperature);

		// Store the state
		dState[0] = 0.0;
		dState[1] = 0.0;
		dState[2] = phys.RhoThetaFromPressure(dPressure) / dRho;
		dState[3] = 0.0;
		dState[4] = dRho;
	}
	///	<summary>
	///		Obtain test case specific physical constants.
	///	</summary>
	virtual void EvaluatePhysicalConstants(
		PhysicalConstants & phys
	) const {
		// Set the alpha parameter
		phys.SetAlpha(m_dAlpha);
	}
	///	<summary>
	///		Obtain test case specific physical constants.
	///	</summary>
	virtual void EvaluatePhysicalConstants(
		PhysicalConstants & phys
	) const {
		phys.SetOmega(m_dOmega * m_dEarthScaling);
		phys.SetEarthRadius(phys.GetEarthRadius() / m_dEarthScaling);
	}