Skip to content

File atm_field_manager.cpp

File List > components > emulator_comps > eatm > src > impl > atm_field_manager.cpp

Go to the documentation of this file

#include "atm_field_manager.hpp"

namespace emulator {
namespace impl {

void AtmFieldManager::init_field_map() {
  if (!m_field_map.empty())
    return;

  // Register hardcoded fields
  m_field_map["shf"] = &shf;
  m_field_map["cflx"] = &cflx;
  m_field_map["lhf"] = &lhf;
  m_field_map["wsx"] = &wsx;
  m_field_map["wsy"] = &wsy;
  m_field_map["lwup"] = &lwup;
  m_field_map["asdir"] = &asdir;
  m_field_map["aldir"] = &aldir;
  m_field_map["asdif"] = &asdif;
  m_field_map["aldif"] = &aldif;
  m_field_map["ts"] = &ts;
  m_field_map["surface_temperature"] = &ts; // Alias
  m_field_map["sst"] = &sst;
  m_field_map["snowhland"] = &snowhland;
  m_field_map["snowhice"] = &snowhice;
  m_field_map["tref"] = &tref;
  m_field_map["qref"] = &qref;
  m_field_map["Q2m"] = &qref; // Alias
  m_field_map["u10"] = &u10;
  m_field_map["UGRD10m"] = &u10; // Alias
  m_field_map["u10withgusts"] = &u10withgusts;
  m_field_map["icefrac"] = &icefrac;
  m_field_map["sea_ice_fraction"] = &icefrac; // Alias
  m_field_map["ocnfrac"] = &ocnfrac;
  m_field_map["ocean_fraction"] = &ocnfrac; // Alias
  m_field_map["lndfrac"] = &lndfrac;
  m_field_map["land_fraction"] = &lndfrac; // Alias

  m_field_map["zbot"] = &zbot;
  m_field_map["ubot"] = &ubot;
  m_field_map["vbot"] = &vbot;
  m_field_map["tbot"] = &tbot;
  m_field_map["ptem"] = &ptem;
  m_field_map["shum"] = &shum;
  m_field_map["dens"] = &dens;
  m_field_map["pbot"] = &pbot;
  m_field_map["PRESsfc"] = &pbot; // Alias
  m_field_map["pslv"] = &pslv;
  m_field_map["lwdn"] = &lwdn;
  m_field_map["DLWRFsfc"] = &lwdn; // Alias
  m_field_map["rainc"] = &rainc;
  m_field_map["rainl"] = &rainl;
  m_field_map["snowc"] = &snowc;
  m_field_map["snowl"] = &snowl;
  m_field_map["swndr"] = &swndr;
  m_field_map["swvdr"] = &swvdr;
  m_field_map["swndf"] = &swndf;
  m_field_map["swvdf"] = &swvdf;
  m_field_map["swnet"] = &swnet;
  m_field_map["DSWRFtoa"] =
      &swnet; // Use swnet as placeholder for solar? Or dynamic?
}

std::vector<double> *AtmFieldManager::get_field_ptr(const std::string &name) {
  init_field_map();

  // Check hardcoded map first
  auto it = m_field_map.find(name);
  if (it != m_field_map.end()) {
    return it->second;
  }

  // Check dynamic fields
  auto dyn_it = dynamic_fields.find(name);
  if (dyn_it != dynamic_fields.end()) {
    return &(dyn_it->second);
  }

  return nullptr;
}

void AtmFieldManager::register_dynamic_field(const std::string &name) {
  init_field_map();
  if (m_field_map.find(name) != m_field_map.end())
    return; // Already hardcoded

  if (dynamic_fields.find(name) == dynamic_fields.end()) {
    dynamic_fields[name] = std::vector<double>();
    if (m_allocated && m_ncols > 0) {
      dynamic_fields[name].resize(m_ncols);
    }
  }
}

void AtmFieldManager::allocate(int ncols) {
  if (m_allocated) {
    deallocate();
  }

  m_ncols = ncols;

  // AI model buffers - sized dynamically later if needed, but safe fast alloc
  // here net_inputs/outputs sizing moved to emulator_atm logic or just cleared
  net_inputs.clear();
  net_outputs.clear();

  // Import fields (x2a) - allocated only, no defaults
  shf.resize(ncols);
  cflx.resize(ncols);
  lhf.resize(ncols);
  wsx.resize(ncols);
  wsy.resize(ncols);
  lwup.resize(ncols);
  asdir.resize(ncols);
  aldir.resize(ncols);
  asdif.resize(ncols);
  aldif.resize(ncols);
  ts.resize(ncols);
  sst.resize(ncols);
  snowhland.resize(ncols);
  snowhice.resize(ncols);
  tref.resize(ncols);
  qref.resize(ncols);
  u10.resize(ncols);
  u10withgusts.resize(ncols);
  icefrac.resize(ncols);
  ocnfrac.resize(ncols);
  lndfrac.resize(ncols);

  // Export fields (a2x) - allocated only, filled from IC file
  zbot.resize(ncols);
  ubot.resize(ncols);
  vbot.resize(ncols);
  tbot.resize(ncols);
  ptem.resize(ncols);
  shum.resize(ncols);
  dens.resize(ncols);
  pbot.resize(ncols);
  pslv.resize(ncols);
  lwdn.resize(ncols);
  rainc.resize(ncols);
  rainl.resize(ncols);
  snowc.resize(ncols);
  snowl.resize(ncols);
  swndr.resize(ncols);
  swvdr.resize(ncols);
  swndf.resize(ncols);
  swvdf.resize(ncols);
  swnet.resize(ncols);

  // Allocate dynamic fields
  for (auto &kv : dynamic_fields) {
    kv.second.resize(ncols);
  }

  m_allocated = true;
}

void AtmFieldManager::deallocate() {
  net_inputs.clear();
  net_outputs.clear();

  shf.clear();
  cflx.clear();
  lhf.clear();
  wsx.clear();
  wsy.clear();
  lwup.clear();
  asdir.clear();
  aldir.clear();
  asdif.clear();
  aldif.clear();
  ts.clear();
  sst.clear();
  snowhland.clear();
  snowhice.clear();
  tref.clear();
  qref.clear();
  u10.clear();
  u10withgusts.clear();
  icefrac.clear();
  ocnfrac.clear();
  lndfrac.clear();

  zbot.clear();
  ubot.clear();
  vbot.clear();
  tbot.clear();
  ptem.clear();
  shum.clear();
  dens.clear();
  pbot.clear();
  pslv.clear();
  lwdn.clear();
  rainc.clear();
  rainl.clear();
  snowc.clear();
  snowl.clear();
  swndr.clear();
  swvdr.clear();
  swndf.clear();
  swvdf.clear();
  swnet.clear();

  for (auto &kv : dynamic_fields) {
    kv.second.clear();
  }

  m_allocated = false;
  m_ncols = 0;
}

void AtmFieldManager::set_defaults(int ncols) {
  for (int i = 0; i < ncols; ++i) {
    zbot[i] = 10.0;     // 10m reference height [m]
    ubot[i] = 5.0;      // Zonal wind [m/s]
    vbot[i] = 0.0;      // Meridional wind [m/s]
    tbot[i] = 288.0;    // ~15°C [K]
    ptem[i] = 288.0;    // Potential temp [K]
    shum[i] = 0.008;    // Specific humidity [kg/kg]
    dens[i] = 1.225;    // Air density [kg/m3]
    pbot[i] = 101325.0; // Surface pressure [Pa]
    pslv[i] = 101325.0; // Sea level pressure [Pa]
    lwdn[i] = 300.0;    // Downward LW [W/m2]
    rainc[i] = 0.0;     // Convective rain [kg/m2/s]
    rainl[i] = 0.0;     // Large-scale rain [kg/m2/s]
    snowc[i] = 0.0;     // Convective snow [kg/m2/s]
    snowl[i] = 0.0;     // Large-scale snow [kg/m2/s]
    swnet[i] = 200.0;   // Net SW [W/m2]

    // Partition swnet into components
    swvdr[i] = swnet[i] * 0.28; // Visible direct
    swndr[i] = swnet[i] * 0.31; // NIR direct
    swvdf[i] = swnet[i] * 0.24; // Visible diffuse
    swndf[i] = swnet[i] * 0.17; // NIR diffuse
  }
}

} // namespace impl
} // namespace emulator