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; }
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"; }
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); } }
// 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 ()); }
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); }
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); }
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); }
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"); } } }
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. }
void doIt (Daisy& daisy, const Scope&, Treelog& out) { out.message ("Ridging"); daisy.field ().ridge (ridge); }
void doIt (Daisy&, const Scope&, Treelog& out) { out.message (message.name ()); }
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; }
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; }
// Simulation. void doIt (Daisy& daisy, const Scope&, Treelog& out) { out.message ("Adjusting surface detention capacity"); daisy.field ().set_surface_detention_capacity (height); }
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 + "'"); } }
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)); }