void MovementSolute::divide_top_incomming (const Geometry& geo, const SoilWater& soil_water, const double J_above, // [g/cm^2/h] std::map<size_t, double>& J_primary, std::map<size_t, double>& J_secondary, std::map<size_t, double>& J_tertiary) { daisy_assert (J_above < 0.0); // Negative upward flux. const std::vector<size_t>& edge_above = geo.cell_edges (Geometry::cell_above); const size_t edge_above_size = edge_above.size (); double total_water_in = 0.0; // [cm^3 W/h] double total_area = 0.0; // [cm^2 S] // Find incomming water in all domain. 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 area = geo.edge_area (edge); // [cm^2 S] total_area += area; const double in_sign = geo.cell_is_internal (geo.edge_to (edge)) ? 1.0 : -1.0; daisy_assert (in_sign < 0); // Tertiary domain. const double q_tertiary = soil_water.q_tertiary (edge); daisy_assert (std::isfinite (q_tertiary)); const double tertiary_in = q_tertiary * in_sign; // [cm^3 W/cm^2 S/h] if (tertiary_in > 0) { total_water_in += tertiary_in * area; J_tertiary[edge] = q_tertiary; // [cm^3 W/cm^2 S/h] } else J_tertiary[edge] = 0.0; // Secondary domain. const double q_secondary = soil_water.q_secondary (edge); const double secondary_in = q_secondary * in_sign; // [cm^3 W/cm^2 S/h] if (secondary_in > 0) { total_water_in += secondary_in * area; J_secondary[edge] = q_secondary; // [cm^3 W/cm^2 S/h] } else J_secondary[edge] = 0.0; // Primary domain. const double q_primary = soil_water.q_primary (edge); const double primary_in = q_primary * in_sign; // [cm^3 W/cm^2 S/h] if (primary_in > 0) { total_water_in += primary_in * area; J_primary[edge] = q_primary; // [cm^3 W/cm^2 S/h] } else J_primary[edge] = 0.0; } daisy_approximate (total_area, geo.surface_area ()); if (total_water_in > 1e-9 * total_area) // Scale with incomming solute. { // [g/cm^3 W] = [g/cm^2 S/h] * [cm^2 S] / [cm^3 W/h] const double C_above = -J_above * total_area / total_water_in; daisy_assert (std::isfinite (C_above)); for (size_t i = 0; i < edge_above_size; i++) { const size_t edge = edge_above[i]; // [g/cm^2 S/h] = [cm^3 W/cm^2 S/h] * [g/cm^3 W] J_tertiary[edge] *= C_above; J_secondary[edge] *= C_above; J_primary[edge] *= C_above; } } else { daisy_assert (total_water_in >= 0.0); for (size_t i = 0; i < edge_above_size; i++) { const size_t edge = edge_above[i]; const double in_sign = geo.cell_is_internal (geo.edge_to (edge)) ? 1.0 : -1.0; J_tertiary[edge] = 0.0; J_secondary[edge] = 0.0; J_primary[edge] = -J_above * in_sign; } } }
void MovementSolute::primary_transport (const Geometry& geo, const Soil& soil, const SoilWater& soil_water, const Transport& transport, const bool sink_sorbed, const size_t transport_iteration, const std::map<size_t, double>& J_forced, const std::map<size_t, double>& C_border, Chemical& solute, const std::vector<double>& S_extra, const double dt, const Scope& scope, Treelog& msg) { // Edges. const size_t edge_size = geo.edge_size (); std::vector<double> q (edge_size); // Water flux [cm]. std::vector<double> J (edge_size); // Flux delivered by flow. for (size_t e = 0; e < edge_size; e++) { q[e] = soil_water.q_primary (e); daisy_assert (std::isfinite (q[e])); J[e] = 0.0; } // Cells. const size_t cell_size = geo.cell_size (); std::vector<double> Theta_old (cell_size); // Water content at start... std::vector<double> Theta_new (cell_size); // ...and end of timestep. std::vector<double> C (cell_size); // Concentration given to flow. std::vector<double> A (cell_size); // Sorbed mass not given to flow. std::vector<double> S (cell_size); // Source given to flow. for (size_t c = 0; c < cell_size; c++) { Theta_old[c] = soil_water.Theta_primary_old (c); daisy_assert (Theta_old[c] > 0.0); Theta_new[c] = soil_water.Theta_primary (c); daisy_assert (Theta_new[c] > 0.0); C[c] = solute.C_primary (c); daisy_assert (C[c] >= 0.0); const double M = solute.M_primary (c); daisy_assert (M >= 0.0); A[c] = M - C[c] * Theta_old[c]; daisy_assert (std::isfinite (A[c])); if (A[c] < 0.0) { daisy_approximate (M, C[c] * Theta_old[c]); A[c] = 0.0; } daisy_assert (A[c] >= 0.0); S[c] = solute.S_primary (c) + S_extra[c]; if (sink_sorbed && S[c] < 0.0) { A[c] += S[c] * dt; S[c] = 0.0; if (A[c] < 0.0) { S[c] = A[c] / dt; A[c] = 0.0; } } daisy_assert (std::isfinite (S[c])); } // Flow. transport.flow (geo, soil, Theta_old, Theta_new, q, solute.objid, S, J_forced, C_border, C, J, solute.diffusion_coefficient (), dt, msg); // Check fluxes. for (size_t e = 0; e < edge_size; e++) daisy_assert (std::isfinite (J[e])); // Update with new content. std::vector<double> M (cell_size); for (size_t c = 0; c < cell_size; c++) { daisy_assert (std::isfinite (C[c])); M[c] = A[c] + C[c] * Theta_new[c]; if (M[c] < 0.0) { std::ostringstream tmp; tmp << "M[" << c << "] = " << M[c] << " @ " << geo.cell_name (c) << ", C = " << C[c] << ", A = " << A[c] << ", M_new = " << M[c] << ", M_old = " << solute.M_primary (c) << ", dt " << dt << ", S = " << S[c] << ", S_extra = " << S_extra[c]; solute.debug_cell (tmp, c); tmp << ", Theta_old " << Theta_old[c] << ", Theta_new " << Theta_new[c] << ", root " << soil_water.S_root (c) << ", drain " << soil_water.S_drain (c) << ", B2M " << soil_water.S_B2M (c) << ", M2B " << soil_water.S_M2B (c) << ", forward_total " << soil_water.S_forward_total (c) << ", forward_sink " << soil_water.S_forward_sink (c) << ", sum " << soil_water.S_sum (c) << ", v1 " << soil_water.velocity_cell_primary (geo, c) << ", v2 " << soil_water.velocity_cell_secondary (geo, c); const std::vector<size_t>& edges = geo.cell_edges (c); for (size_t i = 0; i < edges.size (); i++) { const size_t e = edges[i]; tmp << "\n" << geo.edge_name (e) << ": q = " << q[e] << ", J = " << J[e]; } msg.debug (tmp.str ()); if (transport_iteration == 0) throw "Negative concentration"; } } solute.set_primary (soil, soil_water, M, J); }