|
|
|
@ -456,7 +456,7 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
|
|
|
|
|
|
|
|
|
|
RetVal<std::shared_ptr<Data3D>> CF::TEOS103DReader(Adapter& ad, const Adapter::VInfoBase* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it) |
|
|
|
|
{ |
|
|
|
|
static const MString pref = "CF::TempSalDer3DReader"; |
|
|
|
|
static const MString pref = "CF::Teos103DReader"; |
|
|
|
|
|
|
|
|
|
const auto* v = dynamic_cast<const struct VInfoTEOS10*>(vinfo); |
|
|
|
|
if(v == nullptr) return {pref, "Incorrect argument type"}; |
|
|
|
@ -550,9 +550,119 @@ RetVal<std::shared_ptr<Data3D>> CF::TEOS103DReader(Adapter& ad, const Adapter::V
|
|
|
|
|
return out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RetVal<std::shared_ptr<Data2D>> CF::Geostrophic2DReader(Adapter& ad, const Adapter::VInfoBase* vinfo, std::shared_ptr<Projection> proj, size_t it) |
|
|
|
|
{ |
|
|
|
|
static const MString pref = "CF::Geostrophic2DReader"; |
|
|
|
|
|
|
|
|
|
const auto* v = dynamic_cast<const struct VInfoGeostrophic*>(vinfo); |
|
|
|
|
if(v == nullptr) return {pref, "Incorrect argument type"}; |
|
|
|
|
|
|
|
|
|
std::shared_ptr<Data2D> out(new Data2D(proj, {.unit = v->targetunit, .stname = v->stname, .lname = v->lname, .comment = v->comment})); |
|
|
|
|
|
|
|
|
|
std::shared_ptr<Data2D> ssh; |
|
|
|
|
{ |
|
|
|
|
auto retssh = ad.Read2D(v->sshvar, ad.CurrentTime()); |
|
|
|
|
if(!retssh) return {pref, "Can't read ssh variable " + v->sshvar}; |
|
|
|
|
ssh = retssh.Value(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(ssh->Ny() != out->Ny()) return {pref, MString("For ssh variable Ny=") + ssh->Ny() + ", for output variable Ny=" + out->Ny()}; |
|
|
|
|
if(ssh->Nx() != out->Nx()) return {pref, MString("For ssh variable Nx=") + ssh->Nx() + ", for output variable Nx=" + out->Nx()}; |
|
|
|
|
|
|
|
|
|
const UtUnit infr(ssh->Unit()), into("cm"); |
|
|
|
|
const UtUnit outfr("cm/s"), outto(out->Unit()); |
|
|
|
|
const auto cnvin = Converter(infr, into); |
|
|
|
|
const auto cnvout = Converter(outfr, outto); |
|
|
|
|
|
|
|
|
|
if(!cnvin) return {pref, "Can't convert units from \"" + ssh->Unit() + "\" to \"cm\""}; |
|
|
|
|
if(!cnvout) return {pref, "Can't convert units from \"cm/s\" to \"" + ssh->Unit() + "\""}; |
|
|
|
|
|
|
|
|
|
const bool needsconvertin = infr != into; |
|
|
|
|
const bool needsconvertout = outfr != outto; |
|
|
|
|
|
|
|
|
|
auto In = [needsconvertin, &cnvin = cnvin](real r) -> real { return needsconvertin ? cnvin(r) : r; }; |
|
|
|
|
auto Out = [needsconvertout, &cnvout = cnvout](real r) -> real { return needsconvertout ? cnvout(r) : r; }; |
|
|
|
|
|
|
|
|
|
switch(v->op) |
|
|
|
|
{ |
|
|
|
|
case(VInfoGeostrophic::U): |
|
|
|
|
{ |
|
|
|
|
for(size_t iy = 0; iy < ssh->Ny(); iy++) |
|
|
|
|
{ |
|
|
|
|
const real phi = michlib::M_PI * ssh->Lat(iy) / 180.0; |
|
|
|
|
const real sphi = michlib::Sin(phi); |
|
|
|
|
const real s2phi = michlib::Sin(2.0 * phi); |
|
|
|
|
const real g = 978.0318 * (1.0 + 0.005302 * sphi * sphi - 0.000006 * s2phi * s2phi); // g in cm/s
|
|
|
|
|
const real f = 2.0 * 7.29211 * sphi; // Coriolis parameter multiplied by 100'000
|
|
|
|
|
const real db = (iy == 0) ? 0.0 : (michlib::M_PI * 6371.0 * (ssh->Lat(iy) - ssh->Lat(iy - 1)) / 180.0); // Distance in km, compensated by multiplier in Coriolis parameter
|
|
|
|
|
const real du = |
|
|
|
|
(iy == ssh->Ny() - 1) ? 0.0 : (michlib::M_PI * 6371.0 * (ssh->Lat(iy + 1) - ssh->Lat(iy)) / 180.0); // Distance in km, compensated by multiplier in Coriolis parameter
|
|
|
|
|
|
|
|
|
|
for(size_t ix = 0; ix < ssh->Nx(); ix++) |
|
|
|
|
{ |
|
|
|
|
const bool bok = iy != 0 && !ssh->IsFill(ix, iy - 1) && !ssh->IsFill(ix, iy); |
|
|
|
|
const bool uok = iy != ssh->Ny() - 1 && !ssh->IsFill(ix, iy + 1) && !ssh->IsFill(ix, iy); |
|
|
|
|
if(!(bok || uok)) |
|
|
|
|
(*out)(ix, iy) = out->Fillval(); |
|
|
|
|
else if(!bok) |
|
|
|
|
(*out)(ix, iy) = Out(-g * (In((*ssh)(ix, iy + 1)) - In((*ssh)(ix, iy))) / (f * du)); |
|
|
|
|
else if(!uok) |
|
|
|
|
(*out)(ix, iy) = Out(-g * (In((*ssh)(ix, iy)) - In((*ssh)(ix, iy - 1))) / (f * db)); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
const real bder = -g * (In((*ssh)(ix, iy)) - In((*ssh)(ix, iy - 1))) / (f * db); |
|
|
|
|
const real uder = -g * (In((*ssh)(ix, iy + 1)) - In((*ssh)(ix, iy))) / (f * du); |
|
|
|
|
(*out)(ix, iy) = Out(0.5 * (bder + uder)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case(VInfoGeostrophic::V): |
|
|
|
|
{ |
|
|
|
|
for(size_t iy = 0; iy < ssh->Ny(); iy++) |
|
|
|
|
{ |
|
|
|
|
const real phi = michlib::M_PI * ssh->Lat(iy) / 180.0; |
|
|
|
|
const real sphi = michlib::Sin(phi); |
|
|
|
|
const real cphi = michlib::Cos(phi); |
|
|
|
|
const real s2phi = michlib::Sin(2.0 * phi); |
|
|
|
|
const real g = 978.0318 * (1.0 + 0.005302 * sphi * sphi - 0.000006 * s2phi * s2phi); // g in cm/s
|
|
|
|
|
const real f = 2.0 * 7.29211 * sphi; // Coriolis parameter multiplied by 100'000
|
|
|
|
|
|
|
|
|
|
for(size_t ix = 0; ix < ssh->Nx(); ix++) |
|
|
|
|
{ |
|
|
|
|
const real dl = |
|
|
|
|
(ix == 0) ? 0.0 : (michlib::M_PI * 6371.0 * (ssh->Lon(ix) - ssh->Lon(ix - 1)) / 180.0) * cphi; // Distance in km, compensated by multiplier in Coriolis parameter
|
|
|
|
|
const real dr = (ix == ssh->Nx() - 1) |
|
|
|
|
? 0.0 |
|
|
|
|
: (michlib::M_PI * 6371.0 * (ssh->Lon(ix + 1) - ssh->Lon(ix)) / 180.0) * cphi; // Distance in km, compensated by multiplier in Coriolis parameter
|
|
|
|
|
|
|
|
|
|
const bool lok = ix != 0 && !ssh->IsFill(ix - 1, iy) && !ssh->IsFill(ix, iy); |
|
|
|
|
const bool rok = ix != ssh->Nx() - 1 && !ssh->IsFill(ix + 1, iy) && !ssh->IsFill(ix, iy); |
|
|
|
|
if(!(lok || rok)) |
|
|
|
|
(*out)(ix, iy) = out->Fillval(); |
|
|
|
|
else if(!lok) |
|
|
|
|
(*out)(ix, iy) = Out(g * (In((*ssh)(ix + 1, iy)) - In((*ssh)(ix, iy))) / (f * dr)); |
|
|
|
|
else if(!rok) |
|
|
|
|
(*out)(ix, iy) = Out(g * (In((*ssh)(ix, iy)) - In((*ssh)(ix - 1, iy))) / (f * dl)); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
const real lder = g * (In((*ssh)(ix, iy)) - In((*ssh)(ix - 1, iy))) / (f * dl); |
|
|
|
|
const real rder = g * (In((*ssh)(ix + 1, iy)) - In((*ssh)(ix, iy))) / (f * dr); |
|
|
|
|
(*out)(ix, iy) = Out(0.5 * (lder + rder)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Error CF::TEOS10Module(const CLArgs& args, michlib_internal::ParameterListEx& pars, Adapter& ad) |
|
|
|
|
{ |
|
|
|
|
static const MString pref = "TempSalDerModule"; |
|
|
|
|
static const MString pref = "TEOS10Module"; |
|
|
|
|
|
|
|
|
|
MString sal, temp, ptemp; |
|
|
|
|
|
|
|
|
@ -708,3 +818,62 @@ Error CF::TEOS10Module(const CLArgs& args, michlib_internal::ParameterListEx& pa
|
|
|
|
|
|
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Error CF::GeostrophicModule(const CLArgs& args, michlib_internal::ParameterListEx& pars, Adapter& ad) |
|
|
|
|
{ |
|
|
|
|
static const MString pref = "GeostrophicModule"; |
|
|
|
|
|
|
|
|
|
MString ssh; |
|
|
|
|
|
|
|
|
|
for(const auto& v: ad.Vars()) |
|
|
|
|
{ |
|
|
|
|
if(!ad.Is2D(v.first)) continue; |
|
|
|
|
const auto& info = v.second.info; |
|
|
|
|
if(!ssh.Exist() && info->stname == "sea_surface_height_above_geoid") ssh = v.first; |
|
|
|
|
if(!ssh.Exist() && info->stname == "sea_surface_elevation") ssh = v.first; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(!ssh.Exist()) return {}; |
|
|
|
|
|
|
|
|
|
const auto& svar = ad.Vars().at(ssh); |
|
|
|
|
const auto& sproj = svar.proj; |
|
|
|
|
const auto& rinfo = svar.info->rinfo; |
|
|
|
|
|
|
|
|
|
if(!sproj->IsRectangular()) return {}; // We deal only with rectangular grids for now
|
|
|
|
|
|
|
|
|
|
{ // U-component
|
|
|
|
|
auto vinfo = new VInfoGeostrophic(); |
|
|
|
|
|
|
|
|
|
vinfo->sshvar = ssh; |
|
|
|
|
vinfo->op = VInfoGeostrophic::U; |
|
|
|
|
|
|
|
|
|
vinfo->stname = "surface_geostrophic_eastward_sea_water_velocity"; |
|
|
|
|
vinfo->lname = "Geostrophic eastward velocity"; |
|
|
|
|
vinfo->comment = "Module Geostrophic: Geostrophic eastward velocity calculated from sea surface height (" + ssh + ")"; |
|
|
|
|
vinfo->targetunit = "cm/s"; |
|
|
|
|
vinfo->rinfo = rinfo; |
|
|
|
|
vinfo->fillval = NAN; |
|
|
|
|
|
|
|
|
|
const bool addsuc = ad.Add2DVariable("ugs", Adapter::VInfo(vinfo), sproj, Geostrophic2DReader); |
|
|
|
|
if(!addsuc) return {pref, "Variable with name ugs already exist"}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
{ // V-component
|
|
|
|
|
auto vinfo = new VInfoGeostrophic(); |
|
|
|
|
|
|
|
|
|
vinfo->sshvar = ssh; |
|
|
|
|
vinfo->op = VInfoGeostrophic::V; |
|
|
|
|
|
|
|
|
|
vinfo->stname = "surface_geostrophic_northward_sea_water_velocity"; |
|
|
|
|
vinfo->lname = "Geostrophic northward velocity"; |
|
|
|
|
vinfo->comment = "Module Geostrophic: Geostrophic northward velocity calculated from sea surface height (" + ssh + ")"; |
|
|
|
|
vinfo->targetunit = "cm/s"; |
|
|
|
|
vinfo->rinfo = rinfo; |
|
|
|
|
vinfo->fillval = NAN; |
|
|
|
|
|
|
|
|
|
const bool addsuc = ad.Add2DVariable("vgs", Adapter::VInfo(vinfo), sproj, Geostrophic2DReader); |
|
|
|
|
if(!addsuc) return {pref, "Variable with name vgs already exist"}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|