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::secondary_transport (const Geometry& geo, const Soil& soil, const SoilWater& soil_water, const std::map<size_t, double>& J_forced, const std::map<size_t, double>& C_border, Chemical& solute, 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, 0.0); // Flux delivered by flow. for (size_t e = 0; e < edge_size; e++) { q[e] = soil_water.q_secondary (e); daisy_assert (std::isfinite (q[e])); } // 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> A (cell_size); // Content ignored by flow. std::vector<double> Mf (cell_size); // Content 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_secondary_old (c); daisy_assert (Theta_old[c] >= 0.0); Theta_new[c] = soil_water.Theta_secondary (c); daisy_assert (Theta_new[c] >= 0.0); const double source = solute.S_secondary (c); daisy_assert (std::isfinite (source)); Mf[c] = solute.C_secondary (c) * Theta_old[c]; daisy_assert (Mf[c] >= 0.0); A[c] = solute.M_secondary (c) - Mf[c]; daisy_assert (std::isfinite (A[c])); if (Theta_new[c] > 0) { if (Theta_old[c] > 0) // Secondary water fully active. S[c] = source; else if (source > 0.0) // Fresh water and source. S[c] = source; else // Fresh water and sink. S[c] = 0.0; } else // No secondary water at end of timestep. S[c] = 0.0; // Put any remaining source in S_extra. S_extra[c] += source - S[c]; daisy_assert (std::isfinite (S_extra[c])); } // Flow. secondary_flow (geo, Theta_old, Theta_new, q, solute.objid, S, J_forced, C_border, Mf, J, dt, msg); // Check fluxes. for (size_t e = 0; e < edge_size; e++) daisy_assert (std::isfinite (J[e])); // Negative content should be handled by primary transport. std::vector<double> Mn (cell_size); // New content. std::vector<double> C (cell_size); for (size_t c = 0; c < cell_size; c++) { Mn[c] = A[c] + Mf[c] + S_extra[c] * dt; if (Mn[c] < 0.0 || Theta_new[c] < 1e-6) { S_extra[c] = Mn[c] / dt; Mn[c] = 0.0; } else S_extra[c] = 0.0; daisy_assert (std::isfinite (S_extra[c])); } solute.set_secondary (soil, soil_water, Mn, J); }