bool check (Treelog& msg)
  {
    if (!lex.good ())
      return false;
    
    bool ok = true;
    if (c_x_pos < 0)
      {
        msg.error ("Position X: tag missing");
        ok = false;
      }
    if (c_z_min < 0)
      {
        msg.error ("Position Z minimum: tag missing");
        ok = false;
      }
    if (c_z_max < 0)
      {
        msg.error ("Position Z maximum: tag missing");
        ok = false;
      }
    if (c_density < 0)
      {
        msg.error ("Root lenght density: tag missing");
        ok = false;
      }

    return ok; 
  }
Exemple #2
0
  bool valid (const PLF& plf, Treelog& msg) const
  {
    if (plf.size () < 1)
      {
        msg.error ("PLF must be non-empty");
        return false;
      }
    const size_t first = 0;
    const size_t last = plf.size () - 1;
    const double first_x = plf.x (first);
    const double first_y = plf.y (first); 
    const double last_x = plf.x (last);
    const double last_y = plf.y (last);

    if (first_x < 1 || last_x > 366)
      {
        msg.error ("Julian day must be between 1 and 366");
        return false;
      }
    if (!approximate (first_y, last_y))
      {
        std::ostringstream tmp;
        tmp << "First (" << first_y << ") and last (" << last_y
            << ") value must be identical";
        msg.error (tmp.str ());
        return false;
      }
    return true;
  }
Exemple #3
0
 bool verify (const Metalib&, const Frame& frame, const symbol key,
              Treelog& msg) const
 {
   daisy_assert (key == "SOM_fractions");
   daisy_assert (frame.check (key));
   daisy_assert (frame.lookup (key) == Attribute::Number);
   daisy_assert (frame.type_size (key) == Attribute::Variable);
   std::vector<double> fractions = frame.number_sequence ("SOM_fractions");
   bool has_negative = false;
   double sum = 0.0;
   for (unsigned int i = 0; i < fractions.size (); i++)
     {
       if (fractions[i] < 0)
         has_negative = true;
       else
         sum += fractions[i];
     }
   if (!has_negative && !approximate (sum, 1.0))
     {
       msg.error ("sum must be 1.0");
       return false;
     }
   if (sum > 1.0 && !approximate (sum, 1.0))
     {
       msg.error ("sum must be at most 1.0");
       return false;
     }
   return true;
 };
  void initialize (const Texture& texture,
                   double rho_b, const bool top_soil, const double CEC,
                   const double center_z, Treelog& msg)
  {
    TREELOG_MODEL (msg);
    std::ostringstream tmp;

    // Find Theta_sat.
    if (Theta_sat < 0.0)
      {
        if (rho_b < 0.0)
          {
            msg.error ("You must specify either dry bulk density or porosity");
            rho_b = 1.5;
            tmp << "Forcing rho_b = "  << rho_b << " g/cm^3\n";
          }
        Theta_sat = 1.0 - rho_b / texture.rho_soil_particles ();
        tmp << "(Theta_sat " << Theta_sat << " [])\n";
        daisy_assert (Theta_sat < 1.0);
      }
    if (Theta_sat <= Theta_fc)
      {
        msg.error ("Field capacity must be below saturation point");
        Theta_sat = (1.0 + 4.0 * Theta_fc) / 5.0;
        tmp << "Forcing Theta_sat = " << Theta_sat << " []\n";
      }

    // Find Theta_wp.
    if (Theta_wp < 0.0)
      {
        const double clay_lim // USDA Clay
          = texture.fraction_of_minerals_smaller_than ( 2.0 /* [um] */);
        const double silt_lim // USDA Silt 
          = texture.fraction_of_minerals_smaller_than (50.0 /* [um] */);
        daisy_assert (clay_lim >= 0.0);
        daisy_assert (silt_lim >= clay_lim);
        daisy_assert (silt_lim <= 1.0);
        const double mineral = texture.mineral ();
        const double clay = mineral * clay_lim * 100 /* [%] */;
        const double silt = mineral * (silt_lim - clay_lim) * 100 /* [%] */;
        const double humus = texture.humus * 100 /* [%] */;
        // Madsen and Platou (1983).
        Theta_wp = 0.758 * humus + 0.520 * clay + 0.075 * silt + 0.42;
        Theta_wp /= 100.0;      // [%] -> []
      }

    b = find_b (Theta_wp, Theta_fc);
    h_b = find_h_b (Theta_wp, Theta_fc, Theta_sat, b);
    tmp << "(b " << b << " [])\n"
        << "(h_b " << h_b << " [cm])";
    msg.debug (tmp.str ());

    // Must be called last (K_init depends on the other parameters).
    Hydraulic::initialize (texture, rho_b, top_soil, CEC, center_z, msg);
  }    
Exemple #5
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);
     }
 }
Exemple #6
0
bool
VCheck::MultiSize::verify (const Metalib&, const Frame& frame, 
                           const symbol key, Treelog& msg) const
{
  daisy_assert (frame.check (key));
  daisy_assert (!frame.is_log (key));
  daisy_assert (frame.type_size (key) != Attribute::Singleton);

  if (sizes.find (frame.value_size (key)) != sizes.end ())
    return true;

  std::ostringstream tmp;
  tmp << "'" << key << "' has " << frame.value_size (key)
      << " elements, expected one of { ";
  bool first = true;
  for (std::set<size_t>::const_iterator i = sizes.begin ();
       i != sizes.end ();
       i++)
    {
      if (first)
        first = false;
      else
        tmp << ", ";
      tmp << *i;
    }
  tmp << " } elements";
  msg.error (tmp.str ());
  return false;
}
bool 
ChemistryMulti::check (const Scope& scope, const Geometry& geo,
		       const Soil& soil, const SoilWater& soil_water,
		       const SoilHeat& soil_heat, const Chemistry& chemistry,
		       Treelog& msg) const
{ 
  bool ok = true; 
  for (size_t c = 0; c < combine.size (); c++)
    {
      Treelog::Open nest (msg, "Chemistry: '" + combine[c]->objid  + "'");
      if (!combine[c]->check (scope, geo, soil, soil_water, soil_heat,
                              chemistry, msg))
	ok = false;
    }

  // Check for duplicate chemicals.
  std::map<symbol, size_t> found;
  for (size_t i = 0; i < chemicals.size (); i++)
    {
      const symbol type = chemicals[i]->objid;
      std::map<symbol, size_t>::const_iterator f = found.find (type);
      if (f != found.end ())
	{
	  std::ostringstream tmp;
	  tmp << "Chemical '" << type << "' definded in multiple chemistries:";
	  for (size_t j = 0; j < combine.size (); j++)
	    if (combine[j]->know (type))
	      tmp << " '" << combine[j]->objid << "'";
	  msg.error (tmp.str ());
	  ok = false;
	}
      found[type] = i;
    }
  return ok;
}
Exemple #8
0
bool 
Frame::Implementation::check (const Metalib& metalib, const Frame& frame,
                              Treelog& msg) const
{
  bool ok = true;

  const FrameModel* model = dynamic_cast<const FrameModel*> (&frame);
  if (model && !model->buildable ())
    {
      msg.error ("'" + frame.type_name () 
                 + "' is a base model, for internal use only");
      ok = false;
    }

  for (type_map::const_iterator i = types.begin ();
       i != types.end ();
       i++)
    {
      const symbol key = (*i).first;
      const Type& type = *(*i).second;
      if (!frame.is_reference (key)
          && !check (metalib, frame, type, key, msg))
        ok = false;
    }

  if (!ok)
    return false;

  if (!frame.has_references ())
    for (size_t j = 0; j < checker.size (); j++)
      if (!checker[j] (metalib, frame, msg))
        return false;

  return true;
}
Exemple #9
0
bool 
VolumeBox::limit (const Volume& other, Treelog& msg)
{ 
  if (const VolumeBox* limit = dynamic_cast<const VolumeBox*> (&other))
    {
      for (size_t i = 0; i < bounds_size; i++)
        {
          Bound& bound = *(this->*(bounds[i].bound));
          if (bound.type () == Bound::none)
            {
              const Bound& lim = *(limit->*(bounds[i].bound));
              switch (lim.type ())
                {
                case Bound::none:
                  /* do nothing */;
                  break;
                case Bound::full:
                  bound.set_full ();
                  break;
                case Bound::finite:
                  bound.set_finite (lim.value ());
                  break;
                }
            }
        }
      return true;
    }
  msg.error ("Don't know how to limit a '" + objid 
             + "' to a '" + other.objid + "'");
  return false;
}
Exemple #10
0
bool
VCheck::Enum::valid (const symbol value, Treelog& msg) const
{
  if (ids.find (value) != ids.end ())
    return true;

  msg.error ("Invalid value '" + value + "'");
  return false;
}
Exemple #11
0
bool 
ReactionNitrification::check (const Units&, const Geometry&,
                              const Soil&, const SoilWater&, const SoilHeat&,
			      const Chemistry& chemistry, Treelog& msg) const
{ 
  bool ok = true;
  if (!chemistry.know (Chemical::NO3 ()))
    {
      msg.error ("Nitrification requires NO3 to be tracked");
      ok = false;
    }
  if (!chemistry.know (Chemical::NH4 ()))
    {
      msg.error ("Nitrification requires NH4 to be tracked");
      ok = false;
    }

  return ok;
}
Exemple #12
0
bool
VCheck::IRange::valid (const int value, Treelog& msg) const
{
  if (value < min)
    {
      std::ostringstream tmp;
      tmp << "Value is " << value << " but should be >= " << min;
      msg.error (tmp.str ());
      return false;
    }
  if (value > max)
    {
      std::ostringstream tmp;
      tmp << "Value is " << value << " but should be <= " << max;
      msg.error (tmp.str ());
      return false;
    }
  return true;
}
Exemple #13
0
  bool valid (double last, double next, Treelog& msg) const
  {
    if (last > next)
      return true;

    std::ostringstream tmp;
    tmp << last << " <= " << next << ", must be decreasing";
    msg.error (tmp.str ());
    return false;
  }
Exemple #14
0
bool
VCheck::SumEqual::valid (double value, Treelog& msg) const
{
  if (approximate (value, sum))
    return true;

  std::ostringstream tmp;
  tmp << "Sum is " << value << " but should be " << sum;
  msg.error (tmp.str ());
  return false;
}
Exemple #15
0
bool
VCheck::Compatible::valid (const Units& units, symbol value, Treelog& msg) const
{
  if (units.can_convert (dimension, value))
    return true;
  
  std::ostringstream tmp;
  tmp << "Cannot convert [" << dimension << "] to [" << value << "]";
  msg.error (tmp.str ());
  return false;
}
Exemple #16
0
bool
VCheck::EndValue::valid (double value, Treelog& msg) const
{
  if (approximate (value, fixed))
    return true;

  std::ostringstream tmp;
  tmp << "End value is " << value << " but should be " << fixed;
  msg.error (tmp.str ());
  return false;
}
Exemple #17
0
  static bool valid (int year, Treelog& msg)
  {
    if (!Time::valid (year, 1, 1, 1))
      {
	std::ostringstream tmp;
	tmp << year << " is not a valid year";
        msg.error (tmp.str ());
        return false;
      }
    return true;
  }
Exemple #18
0
 bool has_attribute (const symbol name, Treelog& msg) const
 { 
   bool missing = false;
   for (size_t i = 0; i < layers.size (); i++)
     if (!layers[i]->horizon->has_attribute (name))
       {
         msg.error ("Required attribute '" 
                    + name + "' is missing from the soil horizon '"
                    + layers[i]->horizon->objid + "'");
         missing = true;
       }
   for (size_t i = 0; i < zones.size (); i++)
     if (!zones[i]->horizon->has_attribute (name))
       {
         msg.error ("Required attribute '" 
                    + name + "' is missing from the soil zone '"
                    + zones[i]->horizon->objid + "'");
         missing = true;
       }
   return !missing;
 }
Exemple #19
0
bool
VCheck::InLibrary::valid (const Metalib& metalib, const symbol type, 
                          Treelog& msg) const
{
  daisy_assert (metalib.exist (lib_name));
  const Library& library = metalib.library (lib_name);
  
  if (!library.check (type))
    {
      msg.error ("Unknown '" + lib_name + "' type '" + type + "'");
      return false;
    }

  const FrameModel& frame = library.model (type);
  if (!frame.check (metalib, Treelog::null ()))
    {
      msg.error ("Incomplete type '" + type + "'");
      return false;
    }
  return true;
}
Exemple #20
0
bool
VCheck::FixedPoint::valid (const PLF& plf, Treelog& msg) const
{ 
  if (approximate (plf (fixed_x), fixed_y))
    return true;

  std::ostringstream tmp;
  tmp << "Value at " << fixed_x << " should be " << fixed_y 
      << " but is << " << plf (fixed_x);
  msg.error (tmp.str ());
  return false;
}
Exemple #21
0
bool
VCheck::SumEqual::valid (const PLF& plf, Treelog& msg) const
{
  const int end = plf.size () - 1;
  daisy_assert (end >= 0);
  bool ok = true;
  if (std::isnormal (plf.y (0)))
    {
      msg.error ("Value at start of PLF should be 0.0");
      ok = false;
    }
  if (std::isnormal (plf.y (end)))
    {
      msg.error ("Value at end of PLF should be 0.0");
      ok = false;
    }
  if (!valid (plf.integrate (plf.x (0), plf.x (end)), msg))
    ok = false;

  return ok;
}
Exemple #22
0
bool
VCheck::LargerThan::valid (const int value, Treelog& msg) const
{
  if (value <= below)
    {
      std::ostringstream tmp;
      tmp << "Value is " << value << " but should be > " << below;
      msg.error (tmp.str ());
      return false;
    }
  return true;
}
Exemple #23
0
bool
VCheck::SmallerThan::valid (const int value, Treelog& msg) const
{
  if (value >= above)
    {
      std::ostringstream tmp;
      tmp << "Value is " << value << " but should be < " << above;
      msg.error (tmp.str ());
      return false;
    }
  return true;
}
Exemple #24
0
bool 
SoilWater::check (const size_t n, Treelog& msg) const
{
  bool ok = true;

  if (Theta_.size () != n)
    {
      std::ostringstream tmp;
      tmp << "You have " << n 
          << " intervals but " << Theta_.size () << " Theta values";
      msg.error (tmp.str ());
      ok = false;
    }
  if (h_.size () != n)
    {
      std::ostringstream tmp;
      tmp << "You have " << n 
          << " intervals but " << h_.size () << " h values";
      msg.error (tmp.str ());
      ok = false;
    }
  if (X_ice_.size () != n)
    {
      std::ostringstream tmp;
      tmp << "You have " << n 
          << " intervals but " << X_ice_.size () << " X_ice values";
      msg.error (tmp.str ());
      ok = false;
    }
  if (X_ice_buffer_.size () != n)
    {
      std::ostringstream tmp;
      tmp << "You have " << n 
          << " intervals but " << X_ice_buffer_.size () 
          << " X_ice_buffer values";
      msg.error (tmp.str ());
      ok = false;
    }
  return ok;
}
 // Create.
 bool check (const Units&, const Geometry&, 
             const Soil&, const SoilWater&, const SoilHeat&,
             const Chemistry& chemistry, Treelog& msg) const
 { 
   bool ok = true;
   if (!chemistry.know (immobile))
     {
       msg.error ("'" + immobile + "' not traced");
       ok = false;
     }
   if (!chemistry.know (bound) && bound != Attribute::None ())
     {
       msg.error ("'" + bound + "' not traced");
       ok = false;
     }
   if (!chemistry.know (colloid))
     {
       msg.error ("'" + colloid + "' not traced");
       ok = false;
     }
   return ok;
 }
Exemple #26
0
void
SoilWater::mass_balance (const Geometry& geo, double dt, Treelog& msg)
{
  const size_t edge_size = geo.edge_size ();
  const double total_sink = 10 * geo.total_surface (S_sum_) * dt;
  const double total_old = 10 * geo.total_surface (Theta_old_);
  const double total_new = 10 * geo.total_surface (Theta_);
  double total_boundary_input = 0.0;
  for (size_t e = 0; e < edge_size; e++)
    {
      if (geo.edge_is_internal (e))
        continue;
      const double in_sign 
        = geo.cell_is_internal (geo.edge_to (e)) ? 1.0 : -1.0;
      const double q = q_primary_[e] + q_secondary_[e];
      const double area = geo.edge_area (e);
      total_boundary_input += q * area * in_sign * dt;
    }
  total_boundary_input /= geo.surface_area ();
  total_boundary_input *= 10;
  if (!balance (total_old, total_new, total_boundary_input - total_sink))
    {
      const double total_expected 
        = total_old - total_sink + total_boundary_input;
      const double total_diff = total_new - total_old;
      const double total_error = total_expected - total_new;
      static double accumulated_error = 0.0;
      accumulated_error += total_error;
      std::ostringstream tmp;
      tmp << "Water balance: old (" << total_old
          << ") - sink (" << total_sink 
          << ") + boundary input (" << total_boundary_input
          << ") != " << total_expected << " mm, got " << total_new 
          << " mm, difference is " << total_diff 
          << " mm, error is " << (total_expected - total_new) 
          << " mm, accumulated " << accumulated_error << " mm";
      for (size_t e = 0; e < edge_size; e++)
        {
          if (geo.edge_is_internal (e))
            continue;
          tmp << "\nedge " << geo.edge_name (e)
              << ": primary " << q_primary_[e]
              << ", secondary = " << q_secondary_[e];
          if (!approximate (q_primary_[e] + q_secondary_[e], q_matrix_[e]))
            tmp << ", NOT MATCHING matrix = " << q_matrix_[e];
          tmp << ", tertiary = " << q_tertiary_[e]
              << ", area = " << geo.edge_area (e);
        }
      msg.error (tmp.str ());
    }
}
Exemple #27
0
 // Create and Destroy.
 bool initialize (const Units& units, const Geometry& geo, const Scope& scope,
                  const Groundwater& groundwater, Treelog& msg)
 {
   bool ok = initialize_base (units, geo, scope, msg); 
   if (pipe_position > 0)
     {
       msg.error ("Unknown pipe position");
       ok = false;
     }
   const size_t cell_size = geo.cell_size ();
   S_from_drain.insert (S_from_drain.begin (), cell_size, 0.0);
   daisy_assert (S_from_drain.size () == cell_size);
   return ok;
 }
bool
GnuplotProfile::initialize (const Units& units, Treelog& msg)
{ 
  const Soil& soil = column->get_soil ();
  const Geometry& geo1 = column->get_geometry ();
  if (!dynamic_cast<const GeometryRect*> (&geo1))
    {
      msg.error ("Can only show profile for rectangular grid geometries");
      return false;
    }
  const GeometryRect& geo = dynamic_cast<const GeometryRect&> (geo1);
  
  std::map<symbol, int> all;
  int next = 0;
  for (size_t row = 0; row < geo.cell_rows (); row++)
    {
      for (size_t col = 0; col < geo.cell_columns (); col++)
        {
          const size_t cell = geo.cell_index (row, col);
          if (col == 0)
            zplus.push_back (geo.zplus (cell));
          if (row == 0)
            xplus.push_back (geo.xplus (cell));
          
          const Horizon& horizon = soil.horizon (cell);
          const symbol name = horizon.objid;
          std::map<symbol, int>::const_iterator i = all.find (name);
          if (i == all.end ())
            {
              value.push_back (next);
              all[name] = next;
              next++;
            }
          else
            {
              const int val = (*i).second;
              value.push_back (val);
            }
        }
    }
  daisy_assert (next > 0);
  max_value = next - 1;
  daisy_assert (value.size () == geo.cell_size ());
  daisy_assert (zplus.size () == geo.cell_rows ());
  daisy_assert (xplus.size () == geo.cell_columns ());
  
    // Done.
  return true;
}
Exemple #29
0
bool 
LogTable::check (const Border& border, Treelog& msg) const
{ 
  TREELOG_MODEL (msg);
  bool ok = LogSelect::check (border, msg);
  if (!destination.check (msg))
    {
      ok = false;
      std::ostringstream tmp;
      tmp << "Write error for '" << file << "'";
      msg.error (tmp.str ());
    }

  return ok; 
}
Exemple #30
0
bool
VCheck::MinSize::verify (const Metalib&, const Frame& frame, 
                         const symbol key, Treelog& msg) const
{
  daisy_assert (frame.check (key));
  daisy_assert (!frame.is_log (key));
  daisy_assert (Attribute::flexible_size (frame.type_size (key)));
  if (frame.value_size (key) >= min_size)
    return true;
  std::ostringstream tmp;
  tmp << "Need at least " << min_size << " elements, got " 
      << frame.value_size (key);
  msg.error (tmp.str ());
  return false;
}