예제 #1
0
 static void propagate (Treelog& msg, int nest, const std::string& text)
 {
   switch (nest)
     {
     case is_unknown:
       msg.entry (text);
       break;
     case is_debug:
       msg.debug (text);
       break;
     case is_plain:
       msg.message (text);
       break;
     case is_warning:
       msg.warning (text);
       break;
     case is_error:
       msg.error (text);
       break;
     case is_bug:
       msg.bug (text);
       break;
     case is_close:
       msg.close ();
       break;
     case is_touch:
       msg.touch ();
       break;
     case is_flush:
       msg.flush ();
       break;
     default:
       msg.open (text);
     }
 }
예제 #2
0
void
MovementSolute::solute (const Soil& soil, const SoilWater& soil_water,
                        const double J_above, Chemical& chemical, 
                        const double dt,
                        const Scope& scope, Treelog& msg)
{
  daisy_assert (std::isfinite (J_above));
  const size_t cell_size = geometry ().cell_size ();
  const size_t edge_size = geometry ().edge_size ();

  // Source term transfered from secondary to primary domain.
  std::vector<double> S_extra (cell_size, 0.0);

  // Divide top solute flux according to water.
  std::map<size_t, double> J_tertiary;
  std::map<size_t, double> J_secondary; 
  std::map<size_t, double> J_primary;

  if (J_above > 0.0)
    // Outgoing, divide according to content in primary domain only.
    divide_top_outgoing (geometry (), chemical, J_above, 
                         J_primary, J_secondary, J_tertiary);
  else if (J_above < 0.0)
    // Incomming, divide according to all incomming water.
    divide_top_incomming (geometry (), soil_water, J_above, 
                          J_primary, J_secondary, J_tertiary);
  else
    // No flux.
    zero_top (geometry (), J_primary, J_secondary, J_tertiary);

  // Check result.
  {
    const std::vector<size_t>& edge_above 
      = geometry ().cell_edges (Geometry::cell_above);
    const size_t edge_above_size = edge_above.size ();
    double J_sum = 0.0;
    for (size_t i = 0; i < edge_above_size; i++)
      {
        const size_t edge = edge_above[i];
        const double in_sign 
          = geometry ().cell_is_internal (geometry ().edge_to (edge)) 
          ? 1.0 : -1.0;
        const double area = geometry ().edge_area (edge); // [cm^2 S]
        const double J_edge       // [g/cm^2 S/h]
          = J_tertiary[edge] + J_secondary[edge] + J_primary[edge];
        J_sum += in_sign * J_edge * area; // [g/h]
        if (in_sign * J_tertiary[edge] < 0.0)
          {
            std::ostringstream tmp;
            tmp << "J_tertiary[" << edge << "] = " << J_tertiary[edge]
                << ", in_sign = " << in_sign << ", J_above = " << J_above;
            msg.bug (tmp.str ());
          }
        if (in_sign * J_secondary[edge] < 0.0)
          {
            std::ostringstream tmp;
            tmp << "J_secondary[" << edge << "] = " << J_secondary[edge]
                << ", in_sign = " << in_sign << ", J_above = " << J_above;
            msg.bug (tmp.str ());
          }
      }
    J_sum /= geometry ().surface_area (); // [g/cm^2 S/h]
    daisy_approximate (-J_above, J_sum);
  }

  // We set a fixed concentration below lower boundary, if specified.
  std::map<size_t, double> C_border;

  const double C_below = chemical.C_below ();
  if (C_below >= 0.0)
    {
      const std::vector<size_t>& edge_below 
        = geometry ().cell_edges (Geometry::cell_below);
      const size_t edge_below_size = edge_below.size ();

      for (size_t i = 0; i < edge_below_size; i++)
        {
          const size_t edge = edge_below[i];
          C_border[edge] = C_below;
        }
    }

  // Tertiary transport.
  tertiary->solute (geometry (), soil_water, J_tertiary, dt, chemical, msg);

  // Fully adsorbed.
  if (chemical.adsorption ().full ())
    {
      static const symbol solid_name ("immobile transport");
      Treelog::Open nest (msg, solid_name);
      if (!iszero (J_above))
        {
          std::ostringstream tmp;
          tmp << "J_above = " << J_above << ", expected 0 for full sorbtion";
          msg.error (tmp.str ());
        }

      // Secondary "transport".
      std::vector<double> J2 (edge_size, 0.0); // Flux delivered by flow.
      std::vector<double> Mn (cell_size); // New content.
      for (size_t c = 0; c < cell_size; c++)
        {
          Mn[c] = chemical.M_secondary (c) + chemical.S_secondary (c) * dt;
          if (Mn[c] < 0.0)
            {
              S_extra[c] = Mn[c] / dt;
              Mn[c] = 0.0;
            }
          else
            S_extra[c] = 0.0;
        }
      chemical.set_secondary (soil, soil_water, Mn, J2);

      // Primary "transport".
      primary_transport (geometry (), soil, soil_water,
                         *matrix_solid, sink_sorbed, 0, J_primary, C_border,
                         chemical, S_extra, dt, scope, msg);
      return;
    }

  // Secondary transport activated.
  secondary_transport (geometry (), soil, soil_water, J_secondary, C_border,
                       chemical, S_extra, dt, scope, msg);

  // Solute primary transport.
  for (size_t transport_iteration = 0; 
       transport_iteration < 2; 
       transport_iteration++)
    for (size_t i = 0; i < matrix_solute.size (); i++)
      {
        solute_attempt (i);
        static const symbol solute_name ("solute");
        Treelog::Open nest (msg, solute_name, i, matrix_solute[i]->objid);
        try
          {
            primary_transport (geometry (), soil, soil_water, 
                               *matrix_solute[i], sink_sorbed, 
                               transport_iteration,
                               J_primary, C_border,
                               chemical, S_extra, dt, scope, msg);
            if (i > 0)
              msg.debug ("Succeeded");
            return;
          }
        catch (const char* error)
          {
            msg.debug (std::string ("Solute problem: ") + error);
          }
        catch (const std::string& error)
          {
            msg.debug(std::string ("Solute trouble: ") + error);
          }
        solute_failure (i);
      }
  throw "Matrix solute transport failed";
}
예제 #3
0
void
SoilWater::tick_after (const Geometry& geo,
                       const Soil& soil, const SoilHeat& soil_heat, 
                       const bool initial, 
                       Treelog& msg)
{
  TREELOG_SUBMODEL (msg, "SoilWater");

  // We need old K for primary/secondary flux division.
  std::vector<double> K_old = K_cell_;

  // Update cells.
  const size_t cell_size = geo.cell_size ();
  daisy_assert (K_cell_.size () == cell_size);
  daisy_assert (Cw2_.size () == cell_size);
  daisy_assert (h_.size () == cell_size);
  daisy_assert (h_ice_.size () == cell_size);
  daisy_assert (K_old.size () == cell_size);
  daisy_assert (Theta_.size () == cell_size);
  daisy_assert (Theta_primary_.size () == cell_size);
  daisy_assert (Theta_secondary_.size () == cell_size);
  daisy_assert (Theta_tertiary_.size () == cell_size);

  double z_low = geo.top ();
  table_low = NAN;
  double z_high = geo.bottom ();
  table_high = NAN;

  for (size_t c = 0; c < cell_size; c++)
    {
      // Groundwater table.
      const double z = geo.cell_top (c);
      const double h = h_[c];
      const double table = z + h;
      if (h < 0)
        {
          if (approximate (z, z_low))
            {
              if (!std::isnormal (table_low)
                  || table < table_low)
                table_low = table;
            }
          else if (z < z_low)
            table_low = table;
        }
      else if (approximate (z, z_high))
        {
          if (!std::isnormal (table_high)
              || table > table_high)
            table_high = table;
        }
      else if (z > z_high)
        table_high = table;

      // Conductivity.
      K_cell_[c] = soil.K (c, h_[c], h_ice_[c], soil_heat.T (c));
      
      // Specific water capacity.
      Cw2_[c] = soil.Cw2 (c, h_[c]);

      // Primary and secondary water.
      if (Theta_[c] <= 0.0)
        {
          std::ostringstream tmp;
          tmp << "Theta[" << c << "] = " << Theta_[c];
          daisy_bug (tmp.str ());
          Theta_[c] = 1e-9;
        }
      const double h_lim = soil.h_secondary (c);
      if (h_lim >= 0.0 || h_[c] <= h_lim)
        {
          // No active secondary domain.
          Theta_primary_[c] = Theta_[c];
          Theta_secondary_[c] = 0.0;
        }
      else 
        {
          // Secondary domain activated.
          const double Theta_lim = soil.Theta (c, h_lim, h_ice_[c]);
          daisy_assert (Theta_lim > 0.0);
          if (Theta_[c] >= Theta_lim)
            {
              Theta_primary_[c] = Theta_lim;
              Theta_secondary_[c] = Theta_[c] - Theta_lim;
            }
          else
            { 
              std::ostringstream tmp;
              tmp << "h[" << c << "] = " << h_[c] 
                  << "; Theta[" << c << "] = " << Theta_[c] 
                  << "\nh_lim = " << h_lim << "; Theta_lim = " << Theta_lim
                  << "\nStrenge h > h_lim, yet Theta <= Theta_lim";
              msg.bug (tmp.str ());
              Theta_primary_[c] = Theta_[c];
              Theta_secondary_[c] = 0.0;
            }
        }
    }

  if (!std::isnormal (table_high))
    {
      // No saturated cell, use lowest unsaturated.
      daisy_assert (std::isnormal (table_low));
      table_high = table_low;
    }
  else if (!std::isnormal (table_low))
    {
      // No unsaturated cell, use highest saturated.
      daisy_assert (std::isnormal (table_high));
      table_low = table_high;
    }

  // Initialize
  if (initial)
    {
      K_old = K_cell_;
      Theta_primary_old_ = Theta_primary_;
      Theta_secondary_old_ = Theta_secondary_;
    }
  daisy_assert (K_old.size () == cell_size);
  daisy_assert (Theta_primary_old_.size () == cell_size);
  daisy_assert (Theta_secondary_old_.size () == cell_size);

  // Update edges.
  const size_t edge_size = geo.edge_size ();
  daisy_assert (q_matrix_.size () == edge_size);
  daisy_assert (q_primary_.size () == edge_size);
  daisy_assert (q_secondary_.size () == edge_size);
  daisy_assert (q_matrix_.size () == edge_size);
  daisy_assert (q_matrix_.size () == edge_size);
  for (size_t e = 0; e < edge_size; e++)
    {
      // By default, all flux is in primary domain.
      q_primary_[e] = q_matrix_[e];
      q_secondary_[e] = 0.0;
      
      // Find average K.
      double K_edge = 0.0;
      double K_lim = 0.0;
      
      // K may be discontinious at h_lim in case of cracks.
      const double h_fudge = 0.01;

      // Contributions from target.
      const int to = geo.edge_to (e);
      if (geo.cell_is_internal (to))
        {
          if (iszero (Theta_secondary_old (to)) || 
              iszero (Theta_secondary (to)))
            continue;
          K_edge += 0.5 * (K_old[to] + K_cell (to));
          const double h_lim = soil.h_secondary (to) - h_fudge;
          K_lim += soil.K (to, h_lim, h_ice (to), soil_heat.T (to));
        }
      
      // Contributions from source.
      const int from = geo.edge_from (e);
      if (geo.cell_is_internal (from))
        {
          
          if (iszero (Theta_secondary_old (from)) || 
              iszero (Theta_secondary (from)))
            continue;
          K_edge += 0.5 * (K_old[from] + K_cell (from));
          
          const double h_lim = soil.h_secondary (from) - h_fudge;
          K_lim += soil.K (from, h_lim, h_ice (from), soil_heat.T (from));
        }
      
      daisy_assert (K_lim > 0.0);
      daisy_assert (K_edge > 0.0);
      
      // BUGLET:  We use in effect arithmetic average here for K.
      daisy_assert (std::isnormal (K_edge));
      // This may not have been what was used for calculating q matrix.
      const double K_factor = K_lim / K_edge;
      daisy_assert (std::isfinite (K_factor));
      if (K_factor < 0.99999)
        {
          q_primary_[e] = q_matrix_[e] * K_factor;
          q_secondary_[e] = q_matrix_[e] - q_primary_[e];
        }
    }
}