コード例 #1
0
      double value (const Iterative::Point& p) const
      {
        Treelog::Open nest (msg, "minimize");

        if (find_SoilDepth)
          daisy_assert (p.size () == 4);
        else
          daisy_assert (p.size () == 3);
        const double CropDepth = p[0];
        const double CropWidth = p[1];
        const double WRoot = p[2];
        const double SoilDepth = find_SoilDepth ? p[3] : fixed_SoilDepth;

        if (debug > 0)
          {
            std::ostringstream tmp;
            tmp << "CropDepth = " << CropDepth << " cm\n"
                << "CropWidth = " << CropWidth << " cm\n"
                << "WRoot = " << (0.01 * WRoot)  << " Mg DM/ha\n";
            if (find_SoilDepth)
              tmp << "SoilDepth = " << SoilDepth << " cm";
            msg.message (tmp.str ());
          }
       
        // Restrictions.
        const double LARGE_NUMBER = 42.42e42;
        if (CropDepth <= 0)
          return LARGE_NUMBER;
        if (CropWidth <= 0)
          return LARGE_NUMBER;
        if (WRoot <= 0)
          return LARGE_NUMBER;
        if (find_SoilDepth && SoilDepth <= 0)
          return LARGE_NUMBER;

        bool ok = fun.root.set_dynamic (SoilDepth, CropDepth, CropWidth, WRoot,
                                        debug, msg);
        if (!ok)
          return LARGE_NUMBER;

        const double Rsqr = Iterative::RSquared (obs, fun);
        if (debug > 0)
          {
            std::ostringstream tmp;
            tmp << "R^2 = " << Rsqr;
            msg.message (tmp.str ());
          }

        return -Rsqr;
      }
コード例 #2
0
void 
MovementSolute::element (const Soil& soil, const SoilWater& soil_water,
                         DOE& element, 
                         const double diffusion_coefficient, double dt, 
                         Treelog& msg)
{
  for (size_t i = 0; i < matrix_solute.size (); i++)
    {
      Treelog::Open nest (msg, "element", i, matrix_solute[i]->library_id ());
      try
        {
          matrix_solute[i]->element (geometry (), soil, soil_water, element, 
                                     diffusion_coefficient, dt, 
                                     msg);
          if (i > 0)
            msg.message ("Succeeded");
          return;
        }
      catch (const char* error)
        {
          msg.warning (std::string ("DOM problem: ") + error);
        }
      catch (const std::string& error)
        {
          msg.warning (std::string ("DOM trouble: ") + error);
        }
    }
  throw "Matrix element transport failed";
}
コード例 #3
0
ファイル: treelog_store.C プロジェクト: pamoakoy/daisy-model
 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);
     }
 }
コード例 #4
0
ファイル: program_GP2D.C プロジェクト: pamoakoy/daisy-model
  // Use.
  void table_center (const GeometryRect& geo, 
                     const std::vector<double>& Density, Treelog& msg)
  {
    // Print it.
    const size_t column_size = geo.cell_columns ();
    const size_t row_size = geo.cell_rows ();
    std::ostringstream tmp;

    // Top line
    tmp << "z\\x";
    for (size_t col = 0; col < column_size; col++)
      {
        daisy_assert (row_size > 0);
        tmp << "\t" << geo.cell_x (geo.cell_index (0, col));
      }

    // Rows.
    for (size_t row = 0; row < row_size; row++)
      {
        daisy_assert (column_size > 0);
        tmp << "\n" << geo.cell_z (geo.cell_index (row, 0));
        for (size_t col = 0; col < column_size; col++)
          {
            const size_t cell = geo.cell_index (row, col);
            daisy_assert (cell < Density.size ());
            tmp << "\t" << Density[cell];
          }
      }
    
    Treelog::Open nest (msg, "Root density table [(cm, cm) -> cm/cm^3]");
    msg.message (tmp.str ());
  }
コード例 #5
0
void 
ChemistryMulti::check_ignore (const symbol chem, Treelog& msg)
{
  if (ignored (chem))
    return;
  
  msg.message ("Fate of '" + chem.name () + "' will not be traced");
  ignore.push_back (chem);
}
コード例 #6
0
ファイル: units.C プロジェクト: pamoakoy/daisy-model
bool
Units::can_convert (const symbol from, const symbol to, Treelog& msg) const
{
  if (from == to)
    return true;

  // Defined?
  if (!has_unit(from) || !has_unit (to))
    {
      if (!allow_old ())
        {
          if (has_unit (from))
            msg.message ("Original dimension [" + from + "] known.");
          else
            msg.message ("Original dimension [" + from + "] not known.");
          if (has_unit (to))
            msg.message ("Target dimension [" + to + "] known.");
          else
            msg.message ("Target dimension [" + to + "] not known.");
          return false;
        }
      msg.message (std::string ("Trying old conversion of ") 
                   + (has_unit (from) ? "" : "unknown ") + "[" + from + "] to " 
                   + (has_unit (to) ? "" : "unknown ") + "[" + to + "]." );
      return Oldunits::can_convert (from, to);
    }

  const Unit& from_unit = get_unit (from);
  const Unit& to_unit = get_unit (to);

  if (compatible (from_unit, to_unit))
    return true;

  // Not compatible.
  std::ostringstream tmp;
  tmp << "Cannot convert [" << from 
      << "] with base [" << from_unit.base_name () << "] to [" << to
      << "] with base [" << to_unit.base_name () << "]";
  msg.message (tmp.str ());
  if (!allow_old ())
    return false;

  msg.message ("Trying old conversion.");
  return Oldunits::can_convert (from, to);
}
コード例 #7
0
ファイル: action_sow.C プロジェクト: pamoakoy/daisy-model
 void doIt (Daisy& daisy, const Scope&, Treelog& msg)
 { 
   msg.message ("Sowing " + crop->type_name ());      
   daisy.field ().sow (metalib, *crop, row_width, row_pos, seed, 
                     daisy.time (), msg); 
 }
コード例 #8
0
void 
UZRectMollerup::upperboundary (const GeometryRect& geo,
                               const Soil& soil,
                               const ublas::vector<double>& T,
			       const Surface& surface,
                               std::vector<top_state>& state,
			       const ublas::vector<double>& remaining_water,
			       const ublas::vector<double>& h,
			       const ublas::vector<double>& Kedge,
			       ublas::vector<double>& dq,
			       ublas::banded_matrix<double>& Dm_mat, 
			       ublas::vector<double>& Dm_vec, 
			       ublas::vector<double>& Gm, 
			       ublas::vector<double>& B,
			       const double ddt,
			       const int debug,
                               Treelog& msg, const double BIG_DT)
{
  const std::vector<size_t>& edge_above = geo.cell_edges (Geometry::cell_above);
  const size_t edge_above_size = edge_above.size ();

  for (size_t i = 0; i < edge_above_size; i++)
    {
      const size_t edge = edge_above[i];
      const int cell = geo.edge_other (edge, Geometry::cell_above);
      daisy_assert (geo.cell_is_internal (cell));
      const double in_sign 
        = geo.cell_is_internal (geo.edge_to (edge)) ? 1.0 : -1.0;
      daisy_assert (in_sign < 0);
      const double area = geo.edge_area (edge);
      const double sin_angle = geo.edge_sin_angle (edge);

      switch (surface.top_type (geo, edge))
	{
	case Surface::forced_flux: 
          {
            const double flux = -surface.q_top (geo, edge, BIG_DT);
            Neumann (edge, cell, area, in_sign, flux, dq, B);
          }
	  break;
	case Surface::forced_pressure:
          {
            const double value = -Kedge (edge) * geo.edge_area_per_length (edge);
            const double pressure = surface.h_top (geo, edge);
            Dirichlet (edge, cell, area, in_sign, sin_angle, 
                       Kedge (edge), 
                       h (cell), value, pressure, dq, Dm_mat, Dm_vec, Gm);
          }
	  break;
	case Surface::limited_water:
          {
            const double h_top = remaining_water (i);

            // We pretend that the surface is particlaly saturated.
            const double K_sat = soil.K (cell, 0.0, 0.0, T (cell));
            const double K_cell = Kedge (edge);
            const double K_edge = 0.5 * (K_cell + K_sat);
            
            const double dz = geo.edge_length (edge);
            daisy_assert (approximate (dz, -geo.cell_z (cell)));
            double q_in_avail = h_top / ddt;
            const double q_in_pot = K_edge * (h_top - h (cell) + dz) / dz;
            // Decide type.
            bool is_flux = h_top <= 0.0 || q_in_pot > q_in_avail;

            if (is_flux)
              {
                state[i] = top_flux;
                Neumann (edge, cell, area, in_sign, q_in_avail, dq, B);
              }
            else			// Pressure
              {
                state[i] = top_pressure;
                if (debug > 0 && q_in_pot < 0.0)
                  {
                    std::ostringstream tmp;
                    tmp << "q_in_pot = " << q_in_pot << ", q_avail = " 
                        << q_in_avail << ", h_top = " << h_top 
                        << ", h (cell) = " << h (cell) 
                        << " K (edge) = " << Kedge (edge) 
                        << ", K_sat = " << K_sat << ", K_edge = "
                        << K_edge <<", dz = " << dz << ", ddt = " << ddt
                        << ", is_flux = " << is_flux << "\n";
                    msg.message (tmp.str ());
                  }
                const double value = -K_edge * geo.edge_area_per_length (edge);
                const double pressure = h_top;
                Dirichlet (edge, cell, area, in_sign, sin_angle, 
                           K_edge, h (cell),
                           value, pressure, dq, Dm_mat, Dm_vec, Gm);
              }
            if (debug == 3)
              {
                std::ostringstream tmp;
                tmp << "edge = " << edge << ", K_edge = " << K_edge 
                    << ", h_top = "
                    << h_top << ", dz = " << dz << ", q_avail = " << q_in_avail
                    << ", q_pot = " << q_in_pot << ", is_flux = " << is_flux;
                msg.message (tmp.str ());
              }
          }
	  break;
	case Surface::soil:
	  throw "Don't know how to handle this surface type";
	default:
	  daisy_panic ("Unknown surface type");
	}
    }
}
コード例 #9
0
void 
UZRectMollerup::tick (const GeometryRect& geo,
		      const std::vector<size_t>& drain_cell,
		      const double drain_water_level,
		      const Soil& soil, 
		      SoilWater& soil_water, const SoilHeat& soil_heat,
		      const Surface& surface, const Groundwater& groundwater,
		      const double dt, Treelog& msg)

{
  daisy_assert (K_average.get ());
  const size_t edge_size = geo.edge_size (); // number of edges 
  const size_t cell_size = geo.cell_size (); // number of cells 

  // Insert magic here.
  
  ublas::vector<double> Theta (cell_size); // water content 
  ublas::vector<double> Theta_previous (cell_size); // at start of small t-step
  ublas::vector<double> h (cell_size); // matrix pressure
  ublas::vector<double> h_previous (cell_size); // at start of small timestep
  ublas::vector<double> h_ice (cell_size); // 
  ublas::vector<double> S (cell_size); // sink term
  ublas::vector<double> S_vol (cell_size); // sink term
#ifdef TEST_OM_DEN_ER_BRUGT
  ublas::vector<double> S_macro (cell_size);  // sink term
  std::vector<double> S_drain (cell_size, 0.0); // matrix-> macro -> drain flow 
  std::vector<double> S_drain_sum (cell_size, 0.0); // For large timestep
  const std::vector<double> S_matrix (cell_size, 0.0);  // matrix -> macro 
  std::vector<double> S_matrix_sum (cell_size, 0.0); // for large timestep
#endif
  ublas::vector<double> T (cell_size); // temperature 
  ublas::vector<double> Kold (edge_size); // old hydraulic conductivity
  ublas::vector<double> Ksum (edge_size); // Hansen hydraulic conductivity
  ublas::vector<double> Kcell (cell_size); // hydraulic conductivity
  ublas::vector<double> Kold_cell (cell_size); // old hydraulic conductivity
  ublas::vector<double> Ksum_cell (cell_size); // Hansen hydraulic conductivity
  ublas::vector<double> h_lysimeter (cell_size);
  std::vector<bool> active_lysimeter (cell_size);
  const std::vector<size_t>& edge_above = geo.cell_edges (Geometry::cell_above);
  const size_t edge_above_size = edge_above.size ();
  ublas::vector<double> remaining_water (edge_above_size);
  std::vector<bool> drain_cell_on (drain_cell.size (),false); 
  

  for (size_t i = 0; i < edge_above_size; i++)
    {
      const size_t edge = edge_above[i];
      remaining_water (i) = surface.h_top (geo, edge);
    }
  ublas::vector<double> q;	// Accumulated flux
  q = ublas::zero_vector<double> (edge_size);
  ublas::vector<double> dq (edge_size); // Flux in small timestep.
  dq = ublas::zero_vector<double> (edge_size);

  //Make Qmat area diagonal matrix 
  //Note: This only needs to be calculated once... 
  ublas::banded_matrix<double> Qmat (cell_size, cell_size, 0, 0);
  for (int c = 0; c < cell_size; c++)
    Qmat (c, c) = geo.cell_volume (c);
 
  // make vectors 
  for (size_t cell = 0; cell != cell_size ; ++cell) 
    {				
      Theta (cell) = soil_water.Theta (cell);
      h (cell) =  soil_water.h (cell);
      h_ice (cell) = soil_water.h_ice (cell);
      S (cell) =  soil_water.S_sum (cell);
      S_vol (cell) = S (cell) * geo.cell_volume (cell);
      if (use_forced_T)
	T (cell) = forced_T;
      else 
	T (cell) = soil_heat.T (cell); 
      h_lysimeter (cell) = geo.zplus (cell) - geo.cell_z (cell);
    }

  // Remember old value.
  Theta_error = Theta;

  // Start time loop 
  double time_left = dt;	// How much of the large time step left.
  double ddt = dt;		// We start with small == large time step.
  int number_of_time_step_reductions = 0;
  int iterations_with_this_time_step = 0;
  

  int n_small_time_steps = 0;
  
  while (time_left > 0.0)
    {
      if (ddt > time_left)
	ddt = time_left;

      std::ostringstream tmp_ddt;
      tmp_ddt << "Time t = " << (dt - time_left) 
              << "; ddt = " << ddt
              << "; steps " << n_small_time_steps 
              << "; time left = " << time_left;
      Treelog::Open nest (msg, tmp_ddt.str ());

      if (n_small_time_steps > 0
          && (n_small_time_steps%msg_number_of_small_time_steps) == 0)
        {
          msg.touch ();
          msg.flush ();
        }
      
      n_small_time_steps++;
      if (n_small_time_steps > max_number_of_small_time_steps) 
        {
          msg.debug ("Too many small timesteps");
          throw "Too many small timesteps";
        }
      
      // Initialization for each small time step.

      if (debug > 0)
	{
	  std::ostringstream tmp;
	  tmp << "h = " << h << "\n";
	  tmp << "Theta = " << Theta;
	  msg.message (tmp.str ());
	}

      int iterations_used = 0;
      h_previous = h;
      Theta_previous = Theta;

      if (debug == 5)
	{
	  std::ostringstream tmp;
	  tmp << "Remaining water at start: " << remaining_water;
	  msg.message (tmp.str ());
	}

      ublas::vector<double> h_conv;

      for (size_t cell = 0; cell != cell_size ; ++cell)
        active_lysimeter[cell] = h (cell) > h_lysimeter (cell);

      for (size_t edge = 0; edge != edge_size ; ++edge)
        {
          Kold[edge] = find_K_edge (soil, geo, edge, h, h_ice, h_previous, T);
          Ksum [edge] = 0.0;
        }

      std::vector<top_state> state (edge_above.size (), top_undecided);
      
      // We try harder with smaller timesteps.
      const int max_loop_iter 
        = max_iterations * (number_of_time_step_reductions 
                            * max_iterations_timestep_reduction_factor + 1);
      do // Start iteration loop
	{
	  h_conv = h;
	  iterations_used++;
          

          std::ostringstream tmp_conv;
          tmp_conv << "Convergence " << iterations_used; 
          Treelog::Open nest (msg, tmp_conv.str ());
          if (debug == 7)
            msg.touch ();

	  // Calculate conductivity - The Hansen method
	  for (size_t e = 0; e < edge_size; e++)
	    {
              Ksum[e] += find_K_edge (soil, geo, e, h, h_ice, h_previous, T);
              Kedge[e] = (Ksum[e] / (iterations_used  + 0.0)+ Kold[e]) / 2.0;
	    }

	  //Initialize diffusive matrix
	  Solver::Matrix diff (cell_size);
	  // diff = ublas::zero_matrix<double> (cell_size, cell_size);
	  diffusion (geo, Kedge, diff);

	  //Initialize gravitational matrix
	  ublas::vector<double> grav (cell_size); //ublass compatibility
	  grav = ublas::zero_vector<double> (cell_size);
	  gravitation (geo, Kedge, grav);

	  // Boundary matrices and vectors
	  ublas::banded_matrix<double>  Dm_mat (cell_size, cell_size, 
                                                0, 0); // Dir bc
	  Dm_mat = ublas::zero_matrix<double> (cell_size, cell_size);
	  ublas::vector<double>  Dm_vec (cell_size); // Dir bc
	  Dm_vec = ublas::zero_vector<double> (cell_size);
	  ublas::vector<double> Gm (cell_size); // Dir bc
	  Gm = ublas::zero_vector<double> (cell_size);
	  ublas::vector<double> B (cell_size); // Neu bc 
	  B = ublas::zero_vector<double> (cell_size);

	  lowerboundary (geo, groundwater, active_lysimeter, h,
                         Kedge,
                         dq, Dm_mat, Dm_vec, Gm, B, msg);
	  upperboundary (geo, soil, T, surface, state, remaining_water, h,
                         Kedge,
                         dq, Dm_mat, Dm_vec, Gm, B, ddt, debug, msg, dt);
          Darcy (geo, Kedge, h, dq); //for calculating drain fluxes 


	  //Initialize water capacity  matrix
	  ublas::banded_matrix<double> Cw (cell_size, cell_size, 0, 0);
	  for (size_t c = 0; c < cell_size; c++)
	    Cw (c, c) = soil.Cw2 (c, h[c]);
	  
          std::vector<double> h_std (cell_size);
          //ublas vector -> std vector 
          std::copy(h.begin (), h.end (), h_std.begin ());

#ifdef TEST_OM_DEN_ER_BRUGT
          for (size_t cell = 0; cell != cell_size ; ++cell) 
            {				
              S_macro (cell) = (S_matrix[cell] + S_drain[cell]) 
                * geo.cell_volume (cell);
            }
#endif

	  //Initialize sum matrix
	  Solver::Matrix summat (cell_size);  
	  noalias (summat) = diff + Dm_mat;

	  //Initialize sum vector
	  ublas::vector<double> sumvec (cell_size);  
	  sumvec = grav + B + Gm + Dm_vec - S_vol
#ifdef TEST_OM_DEN_ER_BRUGT
            - S_macro
#endif
            ; 

	  // QCw is shorthand for Qmatrix * Cw
	  Solver::Matrix Q_Cw (cell_size);
	  noalias (Q_Cw) = prod (Qmat, Cw);

	  //Initialize A-matrix
	  Solver::Matrix A (cell_size);  
	  noalias (A) = (1.0 / ddt) * Q_Cw - summat;  

	  // Q_Cw_h is shorthand for Qmatrix * Cw * h
	  const ublas::vector<double> Q_Cw_h = prod (Q_Cw, h);

	  //Initialize b-vector
	  ublas::vector<double> b (cell_size);  
	  //b = sumvec + (1.0 / ddt) * (Qmatrix * Cw * h + Qmatrix *(Wxx-Wyy));
	  b = sumvec + (1.0 / ddt) * (Q_Cw_h
				      + prod (Qmat, Theta_previous-Theta));

	  // Force active drains to zero h.
          drain (geo, drain_cell, drain_water_level,
		 h, Theta_previous, Theta, S_vol,
#ifdef TEST_OM_DEN_ER_BRUGT
                 S_macro,
#endif
                 dq, ddt, drain_cell_on, A, b, debug, msg);  
          
          try {
            solver->solve (A, b, h); // Solve Ah=b with regard to h.
          } catch (const char *const error) {
              std::ostringstream tmp;
              tmp << "Could not solve equation system: " << error;
              msg.warning (tmp.str ());
              // Try smaller timestep.
              iterations_used = max_loop_iter + 100;
              break;
          }

	  for (int c=0; c < cell_size; c++) // update Theta 
	    Theta (c) = soil.Theta (c, h (c), h_ice (c)); 

	  if (debug > 1)
	    {
	      std::ostringstream tmp;
	      tmp << "Time left = " << time_left << ", ddt = " << ddt 
		  << ", iteration = " << iterations_used << "\n";
	      tmp << "B = " << B << "\n";
	      tmp << "h = " << h << "\n";
	      tmp << "Theta = " << Theta;
	      msg.message (tmp.str ());
	    }
          
          for (int c=0; c < cell_size; c++)
            {
              if (h (c) < min_pressure_potential || h (c) > max_pressure_potential)
                {
                  std::ostringstream tmp;
                  tmp << "Pressure potential out of realistic range, h[" 
                      << c << "] = " << h (c);
                  msg.debug (tmp.str ());
                  iterations_used = max_loop_iter + 100;
                  break;
                } 
            }
        }

      while (!converges (h_conv, h) && iterations_used <= max_loop_iter);
      

      if (iterations_used > max_loop_iter)
	{
          number_of_time_step_reductions++;
          
	  if (number_of_time_step_reductions > max_time_step_reductions)
            {
              msg.debug ("Could not find solution");
              throw "Could not find solution";
            }

          iterations_with_this_time_step = 0;
	  ddt /= time_step_reduction;
	  h = h_previous;
	  Theta = Theta_previous;
	}
      else
	{
          // Update dq for new h.
	  ublas::banded_matrix<double>  Dm_mat (cell_size, cell_size, 
                                                0, 0); // Dir bc
	  Dm_mat = ublas::zero_matrix<double> (cell_size, cell_size);
	  ublas::vector<double>  Dm_vec (cell_size); // Dir bc
	  Dm_vec = ublas::zero_vector<double> (cell_size);
	  ublas::vector<double> Gm (cell_size); // Dir bc
	  Gm = ublas::zero_vector<double> (cell_size);
	  ublas::vector<double> B (cell_size); // Neu bc 
	  B = ublas::zero_vector<double> (cell_size);
	  lowerboundary (geo, groundwater, active_lysimeter, h,
                         Kedge,
                         dq, Dm_mat, Dm_vec, Gm, B, msg);
	  upperboundary (geo, soil, T, surface, state, remaining_water, h,
                         Kedge,
                         dq, Dm_mat, Dm_vec, Gm, B, ddt, debug, msg, dt);
          Darcy (geo, Kedge, h, dq);

#ifdef TEST_OM_DEN_ER_BRUGT
          // update macropore flow components 
          for (int c = 0; c < cell_size; c++)
            {
              S_drain_sum[c] += S_drain[c] * ddt/dt;
              S_matrix_sum[c] += S_matrix[c] * ddt/dt;
            }
#endif

          std::vector<double> h_std_new (cell_size);
          std::copy(h.begin (), h.end (), h_std_new.begin ());

	  // Update remaining_water.
	  for (size_t i = 0; i < edge_above.size (); i++)
	    {
	      const int edge = edge_above[i];
	      const int cell = geo.edge_other (edge, Geometry::cell_above);
	      const double out_sign = (cell == geo.edge_from (edge))
		? 1.0 : -1.0;
	      remaining_water[i] += out_sign * dq (edge) * ddt;
              daisy_assert (std::isfinite (dq (edge)));
	    }

	  if (debug == 5)
	    {
	      std::ostringstream tmp;
	      tmp << "Remaining water at end: " << remaining_water;
	      msg.message (tmp.str ());
	    }

	  // Contribution to large time step.
          daisy_assert (std::isnormal (dt));
          daisy_assert (std::isnormal (ddt));
	  q += dq * ddt / dt;
          for (size_t e = 0; e < edge_size; e++)
            {
              daisy_assert (std::isfinite (dq (e)));
              daisy_assert (std::isfinite (q (e)));
            }
          for (size_t e = 0; e < edge_size; e++)
            {
              daisy_assert (std::isfinite (dq (e)));
              daisy_assert (std::isfinite (q (e)));
            }

	  time_left -= ddt;
	  iterations_with_this_time_step++;

	  if (iterations_with_this_time_step > time_step_reduction)
	    {
	      number_of_time_step_reductions--;
	      iterations_with_this_time_step = 0;
	      ddt *= time_step_reduction;
	    }
	}
      // End of small time step.
    }

  // Mass balance.
  // New = Old - S * dt + q_in * dt - q_out * dt + Error =>
  // 0 = Old - New - S * dt + q_in * dt - q_out * dt + Error
  Theta_error -= Theta;         // Old - New
  Theta_error -= S * dt;
#ifdef TEST_OM_DEN_ER_BRUGT
  for (size_t c = 0; c < cell_size; c++)
    Theta_error (c) -= (S_matrix_sum[c] + S_drain_sum[c]) * dt;
#endif
  
  for (size_t edge = 0; edge != edge_size; ++edge) 
    {
      const int from = geo.edge_from (edge);
      const int to = geo.edge_to (edge);
      const double flux = q (edge) * geo.edge_area (edge) * dt;
      if (geo.cell_is_internal (from))
        Theta_error (from) -= flux / geo.cell_volume (from);
      if (geo.cell_is_internal (to))
        Theta_error (to) += flux / geo.cell_volume (to);
    }

  // Find drain sink from mass balance.
#ifdef TEST_OM_DEN_ER_BRUGT
  std::fill(S_drain.begin (), S_drain.end (), 0.0);
#else
  std::vector<double> S_drain (cell_size);
#endif
  for (size_t i = 0; i < drain_cell.size (); i++)
    {
      const size_t cell = drain_cell[i];
      S_drain[cell] = Theta_error (cell) / dt;
      Theta_error (cell) -= S_drain[cell] * dt;
    }

  if (debug == 2)
    {
      double total_error = 0.0;
      double total_abs_error = 0.0;
      double max_error = 0.0;
      int max_cell = -1;
      for (size_t cell = 0; cell != cell_size; ++cell) 
        {
          const double volume = geo.cell_volume (cell);
          const double error = Theta_error (cell);
          total_error += volume * error;
          total_abs_error += std::fabs (volume * error);
          if (std::fabs (error) > std::fabs (max_error))
            {
              max_error = error;
              max_cell = cell;
            }
        }
      std::ostringstream tmp;
      tmp << "Total error = " << total_error << " [cm^3], abs = " 
	  << total_abs_error << " [cm^3], max = " << max_error << " [] in cell " 
	  << max_cell;
      msg.message (tmp.str ());
    }
  
  // Make it official.
  for (size_t cell = 0; cell != cell_size; ++cell) 
    soil_water.set_content (cell, h (cell), Theta (cell));
  
#ifdef TEST_OM_DEN_ER_BRUGT
  soil_water.add_tertiary_sink (S_matrix_sum);
  soil_water.drain (S_drain_sum, msg);
#endif


  for (size_t edge = 0; edge != edge_size; ++edge) 
    {
      daisy_assert (std::isfinite (q[edge]));
      soil_water.set_flux (edge, q[edge]);
    }

  soil_water.drain (S_drain, msg);

  // End of large time step.
}
コード例 #10
0
ファイル: action_ridge.C プロジェクト: pamoakoy/daisy-model
 void doIt (Daisy& daisy, const Scope&, Treelog& out)
   { 
     out.message ("Ridging");      
     daisy.field ().ridge (ridge); 
   }
コード例 #11
0
 void doIt (Daisy&, const Scope&, Treelog& out)
 { 
   out.message (message.name ());
 }
コード例 #12
0
  double solve_1D (std::vector<Iterative::PointValue>& obs,
                   Treelog& msg)
  {
    // Find best fit.
    struct ToMinimize : Iterative::PointFunction
    {
      const std::vector<Iterative::PointValue>& obs;
      GP1Dfun& fun;
      const double fixed_SoilDepth; // [cm]
      const bool find_SoilDepth;
      const int debug;
      Treelog& msg;

      double value (const Iterative::Point& p) const
      {
        Treelog::Open nest (msg, "minimize");

        if (find_SoilDepth)
          daisy_assert (p.size () == 3);
        else
          daisy_assert (p.size () == 2);
        const double CropDepth = p[0];
        const double WRoot = p[1];
        const double SoilDepth = find_SoilDepth ? p[2] : fixed_SoilDepth;

        if (debug > 0)
          {
            std::ostringstream tmp;
            tmp << "CropDepth = " << CropDepth << " cm\n"
                << "WRoot = " << (0.01 * WRoot)  << " Mg DM/ha\n";
            if (find_SoilDepth)
              tmp << "SoilDepth = " << SoilDepth << " cm";
            msg.message (tmp.str ());
          }
       
        // Restrictions.
        const double LARGE_NUMBER = 42.42e42;
        if (CropDepth <= 0)
          return LARGE_NUMBER;
        if (WRoot <= 0)
          return LARGE_NUMBER;
        if (find_SoilDepth && SoilDepth <= 0)
          return LARGE_NUMBER;

        bool ok = fun.root.set_dynamic (SoilDepth, CropDepth, WRoot,
                                        debug, msg);
        if (!ok)
          return LARGE_NUMBER;

        const double Rsqr = Iterative::RSquared (obs, fun);
        if (debug > 0)
          {
            std::ostringstream tmp;
            tmp << "R^2 = " << Rsqr;
            msg.message (tmp.str ());
          }

        return -Rsqr;
      }

      ToMinimize (const std::vector<Iterative::PointValue>& o, GP1Dfun& f,
                  const double sd,
                  const int d, 
                  Treelog& m)
        : obs (o),
          fun (f),
          fixed_SoilDepth (sd),
          find_SoilDepth (!std::isfinite (fixed_SoilDepth)),
          debug (d),
          msg (m)
      { }
    };
    ToMinimize to_minimize (obs, gp1d, SoilDepth, debug, msg);

    // Initialial guess.
    const double default_CropDepth = 70;  // [cm]
    const double default_WRoot = 50; // 150 [g DM/m^2] = 1.5 [Mg DM/ha]
    const double default_SoilDepth = 150; // [cm]
    Iterative::Point start;
    start.push_back (default_CropDepth);
    start.push_back (default_WRoot);
    if (!std::isfinite (SoilDepth))
      start.push_back (default_SoilDepth);  // [cm]
    daisy_assert (start.size () == 3 || start.size () == 2);
    const double epsilon = 0.01;
    const size_t min_iter = 10000;
    const size_t max_iter = 300000;
    Iterative::Point result;
    const bool solved = Iterative::NelderMead (min_iter, max_iter, epsilon,
                                               to_minimize, start, result,
                                               Treelog::null ());
    const double Rsqr = -to_minimize.value (result);
    
    store ("1D R^2", Rsqr, solved ? "(solved)" : "(no solution)");
    store ("1D CropDepth", result[0], "cm");
    store ("1D WRoot", (0.01 * result[1]) , "Mg DM/ha");;
    if (result.size () == 3)
      store ("1D SoilDepth", result[2], "cm");;
        
    store ("1D L0", gp1d.root.L0, "cm/cm^3");
    store ("1D a", gp1d.root.a, "cm^-1");;
    if (gp1d.root.d_a > 0.0)
      {
        store ("1D d_a", gp1d.root.d_a, "cm");
        store ("1D k*", gp1d.root.kstar, "");
      }

    std::ostringstream out;
    if (show_data)
      out << "Z\tobs\tsim\n"
          << Units::cm () << "\t" << Units::cm () << "\t" 
          << dens_dim_to << "\t" << dens_dim_to;
    double RSS = 0.0;
    for (size_t i = 0; i < obs.size (); i++)
      {
        const double z = obs[i].point[0];
        const double o = obs[i].value;
        const double f = gp1d.root.density (z);
        RSS += sqr (o - f);
        if (show_data)
          out << "\n" << z << "\t" << o << "\t" << f;
      }
    if (show_data)
      msg.message (out.str ());
    return RSS;
  }
コード例 #13
0
  double solve_2D (std::vector<Iterative::PointValue>& obs,
                 Treelog& msg)
  {
    // Find best fit.
    struct ToMinimize : Iterative::PointFunction
    {
      const std::vector<Iterative::PointValue>& obs;
      GP2Dfun& fun;
      const double fixed_SoilDepth; // [cm]
      const bool find_SoilDepth;
      const int debug;
      Treelog& msg;

      double value (const Iterative::Point& p) const
      {
        Treelog::Open nest (msg, "minimize");

        if (find_SoilDepth)
          daisy_assert (p.size () == 4);
        else
          daisy_assert (p.size () == 3);
        const double CropDepth = p[0];
        const double CropWidth = p[1];
        const double WRoot = p[2];
        const double SoilDepth = find_SoilDepth ? p[3] : fixed_SoilDepth;

        if (debug > 0)
          {
            std::ostringstream tmp;
            tmp << "CropDepth = " << CropDepth << " cm\n"
                << "CropWidth = " << CropWidth << " cm\n"
                << "WRoot = " << (0.01 * WRoot)  << " Mg DM/ha\n";
            if (find_SoilDepth)
              tmp << "SoilDepth = " << SoilDepth << " cm";
            msg.message (tmp.str ());
          }
       
        // Restrictions.
        const double LARGE_NUMBER = 42.42e42;
        if (CropDepth <= 0)
          return LARGE_NUMBER;
        if (CropWidth <= 0)
          return LARGE_NUMBER;
        if (WRoot <= 0)
          return LARGE_NUMBER;
        if (find_SoilDepth && SoilDepth <= 0)
          return LARGE_NUMBER;

        bool ok = fun.root.set_dynamic (SoilDepth, CropDepth, CropWidth, WRoot,
                                        debug, msg);
        if (!ok)
          return LARGE_NUMBER;

        const double Rsqr = Iterative::RSquared (obs, fun);
        if (debug > 0)
          {
            std::ostringstream tmp;
            tmp << "R^2 = " << Rsqr;
            msg.message (tmp.str ());
          }

        return -Rsqr;
      }

      ToMinimize (const std::vector<Iterative::PointValue>& o, GP2Dfun& f,
                  const double sd,
                  const int d, 
                  Treelog& m)
        : obs (o),
          fun (f),
          fixed_SoilDepth (sd),
          find_SoilDepth (!std::isfinite (fixed_SoilDepth)),
          debug (d),
          msg (m)
      { }
    };
    ToMinimize to_minimize (obs, gp2d, SoilDepth, debug, msg);

    // Initialial guess.
    const double default_CropDepth = 70;  // [cm]
    const double default_CropWidth = 100; // [cm]
    const double default_WRoot = 50; // 150 [g DM/m^2] = 1.5 [Mg DM/ha]
    const double default_SoilDepth = 150; // [cm]
    Iterative::Point start;
    start.push_back (default_CropDepth);
    start.push_back (default_CropWidth);
    start.push_back (default_WRoot);
    if (!std::isfinite (SoilDepth))
      start.push_back (default_SoilDepth);  // [cm]
    daisy_assert (start.size () == 4 || start.size () == 3);
    const double epsilon = 0.01;
    const size_t min_iter = 10000;
    const size_t max_iter = 300000;
    Iterative::Point result;
    const bool solved = Iterative::NelderMead (min_iter, max_iter, epsilon,
                                               to_minimize, start, result,
                                               Treelog::null ());
    const double Rsqr = -to_minimize.value (result);
    
    store ("2D R^2", Rsqr, solved ? "(solved)" : "(no solution)");
    store ("2D CropDepth", result[0], "cm");
    store ("2D CropWidth", result[1], "cm");
    store ("2D WRoot", (0.01 * result[2]) , "Mg DM/ha");;
    if (result.size () == 4)
      store ("2D SoilDepth", result[3], "cm");;
        
    store ("2D L00", gp2d.root.L00, "cm/cm^3");
    store ("2D a_x", gp2d.root.a_x, "cm^-1");
    store ("2D a_z", gp2d.root.a_z, "cm^-1");;
    if (gp2d.root.d_a > 0.0)
      {
        store ("2D d_a", gp2d.root.d_a, "cm");
        store ("2D k*", gp2d.root.kstar , "");;
      }

    // Show data.
    if (show_data)
      {
        std::ostringstream out;
        out << "X\tZ\tobs\tsim\n"
            << Units::cm () << "\t" << Units::cm () << "\t" 
            << dens_dim_to << "\t" << dens_dim_to;
        for (size_t i = 0; i < obs.size (); i++)
          {
            const double x = obs[i].point[0];
            const double z = obs[i].point[1];
            const double o = obs[i].value;
            const double f = gp2d.root.density (x, z);
            out << "\n" << x << "\t" << z << "\t" << o << "\t" << f;
          }
        msg.message (out.str ());
      }
    
    // Show errorbars
    if (show_match)
      {
        std::ostringstream out;
        typedef std::map<double, std::map<double, double>/**/> ddmap ;
        ddmap sum;
        ddmap count;
        ddmap var;
        ddmap avg;

        // Clear all.
        for (size_t i = 0; i < obs.size (); i++)
          {
            const double x = std::fabs (obs[i].point[0] - x_offset);
            const double z = obs[i].point[1];
            
            sum[x][z] = 0.0;
            count[x][z] = 0.0;
            var[x][z] = 0.0;
          }

        // Count all.
        for (size_t i = 0; i < obs.size (); i++)
          {
            const double x = std::fabs (obs[i].point[0] - x_offset);
            const double z = obs[i].point[1];
            const double o = obs[i].value;
            
            sum[x][z] += o;
            count[x][z] += 1.0;
          }

        // Find mean.
        for (ddmap::iterator i = sum.begin (); i != sum.end (); i++)
          {
            const double x = (*i).first;
            std::map<double, double> zmap = (*i).second;
            for (std::map<double, double>::iterator j = zmap.begin ();
                 j != zmap.end ();
                 j++)
              {
                const double z = (*j).first;
                avg[x][z] = sum[x][z] / count[x][z];
              }
          }

        // Find variation
        for (size_t i = 0; i < obs.size (); i++)
          {
            const double x = std::fabs (obs[i].point[0] - x_offset);
            const double z = obs[i].point[1];
            const double o = obs[i].value;
            
            var[x][z] += sqr (avg[x][z] - o);
          }

        for (ddmap::iterator i = var.begin (); i != var.end (); i++)
          {
            const double x = (*i).first;
            out << "set output \"" << objid << "-" << x << ".tex\"\n\
plot '-' using 2:1:3 notitle with xerrorbars, '-' using 2:1 notitle with lines\n";
            std::map<double, double> zmap = (*i).second;
            for (std::map<double, double>::iterator j = zmap.begin ();
                 j != zmap.end ();
                 j++)
              {
                const double z = (*j).first;
                const double dev = sqrt (var[x][z] / count[x][z]);
                out << -z << "\t" << avg[x][z] << "\t" << dev << "\n";
              }
            out << "e\n\n";
            for (double z = 0.0; z < 100.1; z++)
              out << -z << "\t" << gp2d.root.density (x + x_offset, z) << "\n";
            out << "e\n\n";
          }
        msg.message (out.str ());
      }

    // Find RSS.
    double RSS = 0.0;
    for (size_t i = 0; i < obs.size (); i++)
      {
        const double x = obs[i].point[0];
        const double z = obs[i].point[1];
        const double o = obs[i].value;
        const double f = gp2d.root.density (x, z);
        RSS += sqr (o - f);
      }
    return RSS;
  }
コード例 #14
0
ファイル: action_surface.C プロジェクト: pamoakoy/daisy-model
 // Simulation.
 void doIt (Daisy& daisy, const Scope&, Treelog& out)
 {
   out.message ("Adjusting surface detention capacity");
   daisy.field ().set_surface_detention_capacity (height);
 }
コード例 #15
0
void 
SummaryBalance::summarize (Treelog& msg) const
{
  TREELOG_MODEL (msg);

  // We write the summary to a string at first.
  std::ostringstream tmp;
  tmp.precision (precision);
  tmp.flags (std::ios::right | std::ios::fixed);
  if (description.name () != default_description)
    tmp << description << "\n\n";

  // Find width of tags.
  const std::string total_title = "Balance (= In - Out - Increase)";
  const std::string content_title = "Total increase in content";
  size_t max_size = std::max (total_title.size (), content_title.size ());
  for (unsigned int i = 0; i < fetch.size (); i++)
    max_size = std::max (max_size, fetch[i]->name_size ());

  // Find width and total values
  int max_digits = 0;
  const double total_input = find_total (input, max_digits);
  const double total_output = find_total (output, max_digits);
  const double total_content = find_total (content, max_digits);
  const double total = total_input - total_output - total_content;
  max_digits = std::max (max_digits, FetchPretty::width (total_input));
  max_digits = std::max (max_digits, FetchPretty::width (total_output));
  max_digits = std::max (max_digits, FetchPretty::width (total_content));
  max_digits = std::max (max_digits, FetchPretty::width (total));

  // Find total width.
  const int width = max_digits + (precision > 0 ? 1 : 0) + precision;

  // Find width of dimensions.
  size_t dim_size = 0;
  for (unsigned int i = 0; i < fetch.size (); i++)
    dim_size = std::max (dim_size, fetch[i]->dimension ().name ().size ());

  // Print all entries.
  symbol shared_dim = Attribute::User ();
  if (input.size () > 0)
    {
      const symbol dim = print_entries (tmp, input, max_size, width);
      print_balance (tmp, "Total input", total_input, dim,
                     dim_size, max_size, width);
      shared_dim = dim;
      tmp << "\n";
    }

  if (output.size () > 0)
    {
      const symbol dim = print_entries (tmp, output, max_size, width);
      print_balance (tmp, "Total output", total_output, dim,
                     dim_size, max_size, width);
      if (shared_dim == Attribute::User ()) 
        shared_dim = dim;
      else if (dim != shared_dim)
        shared_dim = Attribute::Unknown ();
      tmp << "\n";
    }

  if (content.size () > 0)
    {
      const symbol dim = print_entries (tmp, content, max_size, width);
      print_balance (tmp, content_title, total_content, dim,
                     dim_size, max_size, width);
      if (shared_dim == Attribute::User ()) 
        shared_dim = dim;
      else if (dim != shared_dim)
        shared_dim = Attribute::Unknown ();
      tmp << "\n";
    }

  print_balance (tmp, total_title, total, 
                 shared_dim, dim_size, max_size, width);
  tmp << std::string (max_size + 3, ' ') << std::string (width, '=');

  // Where?
  if (file == "")
    msg.message (tmp.str ());
  else
    { 
      std::ofstream out (file.name ().c_str ());
      out << tmp.str ();
      if (! out.good ())
        msg.error ("Could not write to '" + file + "'");
    } 
}
コード例 #16
0
void
EquilibriumGoal_A::find (const Units& units, const Scope& scope, int cell, 
                         const double has_A, const double has_B, 
                         double& want_A, double& want_B, Treelog& msg) const
{
  daisy_assert (has_A >= 0.0);
  daisy_assert (has_B >= 0.0);
  const double M = has_A + has_B;

  double goal_A = 1.0;
  if (!goal_A_expr->tick_value (units, goal_A, goal_unit, scope, msg))
    msg.error ("Could not evaluate 'goal_A'");
  daisy_assert (std::isfinite (goal_A));
  if (goal_A < 0.0)
    {
      std::ostringstream tmp;
      tmp << "Goal A is " << goal_A << ", should be non-negative";
      msg.error (tmp.str ());
      goal_A = 0.0;
    }
  double min_B = 1.0;
  if (!min_B_expr->tick_value (units, min_B, goal_unit, scope, msg))
    msg.error ("Could not evaluate 'min_B'");
  daisy_assert (min_B >= 0.0);

  static const symbol Theta_name ("Theta");
  const double Theta = scope.number (Theta_name);
  daisy_assert (Theta > 0.0);
  daisy_assert (Theta < 1.0);

  const double goal_A_dry = goal_A * (A_solute ? Theta : 1.0);
  const double min_B_dry = min_B * (B_solute ? Theta : 1.0);

  std::ostringstream tmp;

  if (has_A > goal_A_dry)
    {
      tmp << "A->B";
      // We have too much A, convert surplus to B.
      want_A = goal_A_dry;
      want_B = M - want_A;
    }
  else if (has_B < min_B_dry)
    {
      tmp << "min_B";
      // We have too little A and too little B, do nothing.
      want_A = has_A;
      want_B = has_B;
    }
  else
    {
      tmp << "B->A";
      
      // We have too little A and too much B, convert just enough to fit one.
      want_B = std::max (min_B_dry, M - goal_A_dry);
      want_A = M - want_B;
    }
  tmp << "\t" << has_A << "\t" << goal_A_dry << "\t" << want_A << "\t"
      << has_B << "\t" << min_B_dry << "\t" << want_B << "\t" << M;
  if (cell == debug_cell)
    msg.message (tmp.str ());

  daisy_assert (want_A >= 0.0);
  daisy_assert (want_B >= 0.0);
  daisy_assert (approximate (want_A + want_B, M));
}