Program Listing for File ThermoIce0.cpp¶
↰ Return to documentation for file (src/ThermoIce0.cpp)
#include "include/ThermoIce0.hpp"
#include "include/ExternalData.hpp"
#include "include/NextsimPhysics.hpp"
#include "include/PhysicsData.hpp"
#include "include/PrognosticData.hpp"
#include "include/constants.hpp"
namespace Nextsim {
double ThermoIce0::k_s = 0;
bool ThermoIce0::doFlooding = true;
template <>
const std::map<int, std::string> Configured<ThermoIce0>::keyMap = {
{ ThermoIce0::KS_KEY, "thermoice0.ks" },
{ ThermoIce0::FLOODING_KEY, "thermoice0.flooding" },
};
void ThermoIce0::configure()
{
k_s = Configured::getConfiguration(keyMap.at(KS_KEY), 0.3096);
doFlooding = Configured::getConfiguration(keyMap.at(FLOODING_KEY), true);
}
void ThermoIce0::calculate(const PrognosticData& prog, const ExternalData& exter, PhysicsData& phys,
NextsimPhysics& nsphys)
{
// True constants
const double freezingPointIce = -Water::mu * Ice::s;
const double bulkLHFusionSnow = Water::Lf * Ice::rhoSnow;
const double bulkLHFusionIce = Water::Lf * Ice::rho;
if (prog.iceThickness() == 0 || prog.iceConcentration() == 0) {
phys.updatedIceTrueThickness() = 0;
phys.updatedSnowTrueThickness() = 0;
phys.updatedIceSurfaceTemperature() = freezingPointIce;
return;
}
double oldIceThickness = prog.iceTrueThickness();
double iceTemperature = prog.iceTemperatures()[0];
// Heat transfer coefficient
double k_lSlab = k_s * Ice::kappa
/ (k_s * prog.iceTrueThickness() + Ice::kappa * prog.snowTrueThickness());
double QIceConduction = k_lSlab * (exter.iceBottomTemperature() - iceTemperature);
double remainingFlux = QIceConduction - nsphys.QIceAtmosphere();
phys.updatedIceSurfaceTemperature()
= iceTemperature + remainingFlux / (k_lSlab + nsphys.QDerivativeWRTTemperature());
// Clamp the maximum temperature of the ice to the melting point of ice or snow
double meltingLimit = (prog.snowTrueThickness() > 0.) ? 0 : freezingPointIce;
phys.updatedIceSurfaceTemperature()
= std::min(meltingLimit, phys.updatedIceSurfaceTemperature());
// Top melt. Melting rate is non-positive.
double snowMeltRate = std::min(-remainingFlux, 0.) / bulkLHFusionSnow; // [m³ s⁻¹]
double snowSublRate = nsphys.sublimationRate() / Ice::rhoSnow; // [m³ s⁻¹]
phys.updatedSnowTrueThickness() += (snowMeltRate - snowSublRate) * prog.timestep();
// Use excess flux to melt ice. Non-positive value
double excessIceMelt
= std::min(phys.updatedSnowTrueThickness(), 0.) * bulkLHFusionSnow / bulkLHFusionIce;
// With the excess flux noted, clamp the snow thickness to a minimum of zero.
phys.updatedSnowTrueThickness() = std::max(phys.updatedSnowTrueThickness(), 0.);
// Then add snowfall back on top
phys.updatedSnowTrueThickness() += exter.snowfall() * prog.timestep() / Ice::rhoSnow;
// Bottom melt or growth
double iceBottomChange
= (QIceConduction - nsphys.QIceOceanHeat()) * prog.timestep() / bulkLHFusionIce;
// Total thickness change
double iceThicknessChange = excessIceMelt + iceBottomChange;
phys.updatedIceTrueThickness() += iceThicknessChange;
// Amount of melting (only) at the top and bottom of the ice
double topMelt = std::min(excessIceMelt, 0.);
double botMelt = std::min(iceBottomChange, 0.);
// Snow to ice conversion
double iceDraught = (phys.updatedIceTrueThickness() * Ice::rho
+ phys.updatedSnowTrueThickness() * Ice::rhoSnow)
/ Water::rhoOcean;
if (doFlooding && iceDraught > phys.updatedIceTrueThickness()) {
// Keep a running total of the ice formed from flooded snow
double newIce = iceDraught - phys.updatedIceTrueThickness();
nsphys.totalIceFromSnow() += newIce;
// Convert all the submerged snow to ice
phys.updatedIceTrueThickness() = iceDraught;
phys.updatedSnowTrueThickness() -= newIce * Ice::rho / Ice::rhoSnow;
}
if (phys.updatedIceTrueThickness() < NextsimPhysics::minimumIceThickness()) {
// Reduce the melting to reach zero thickness, while keeping the
// between top and bottom melting
if (iceThicknessChange < 0) {
double scaling = -oldIceThickness / iceThicknessChange;
topMelt *= scaling;
botMelt *= scaling;
}
// No snow was converted to ice
nsphys.totalIceFromSnow() = 0;
// Change in thickness is all of the old thickness
iceThicknessChange = -oldIceThickness;
// The ice-ocean flux includes all the latent heat
nsphys.QIceOceanHeat() += phys.updatedIceTrueThickness() * bulkLHFusionIce / prog.timestep()
+ phys.updatedSnowTrueThickness() * bulkLHFusionSnow / prog.timestep();
// No ice, no snow and the surface temperature is the melting point of ice
phys.updatedIceTrueThickness() = 0;
phys.updatedSnowTrueThickness() = 0;
phys.updatedIceSurfaceTemperature() = freezingPointIce;
}
}
} /* namespace Nextsim */