void MulMat (real *a, real *b, real *c, int n) { int i, j, k; for (i = 0; i < n; i ++) { for (j = 0; j < n; j ++) { Mn (a, i, j) = 0.; for (k = 0; k < n; k ++) Mn (a, i, j) += Mn (b, i, k) * Mn (c, k, j); } } }
void compute() { for (int m=-level; m<=level; ++m) { for (int n=-level; n<=level; ++n) { Float uVal = u(level, m, n), vVal = v(level, m, n), wVal = w(level, m, n); Mn(m+level, n+level) = (uVal != 0 ? (uVal * U(level, m, n)) : (Float) 0) + (vVal != 0 ? (vVal * V(level, m, n)) : (Float) 0) + (wVal != 0 ? (wVal * W(level, m, n)) : (Float) 0); } } }
double RkPdf::MfRk(const double& x, const double& tau, const double& dm){ const double r_ckak = ck/ak; const double inv_ak = 1.0/ak; const double ndmtau = r_ckak*dm*tau; const double fact = 1.0/(1.0+ndmtau*ndmtau); double Li = 0.0; if(x<0.0){ const double ndm = dm/(ak-ck); const double ntau = tau*(ak-ck); Li = inv_ak*fact*(Mn(x,ntau,ndm)+ndmtau*An(x,ntau,ndm)); }else{ const double ndm = dm/(ak+ck); const double ntau = tau*(ak+ck); Li = inv_ak*fact*(Mp(x,ntau,ndm)+ndmtau*Ap(x,ntau,ndm)); } return Li; }
/* последовательное применение полуочистителей Bn, Bn / 2, …, B2 сортирует произвольную битоническую последовательность.Эту операцию называют битоническим слиянием и обозначают Mn */ void Mn(long *elements, int k, int direction,int myrank,int nrank,int shift) { MPI_Status status; Bn(elements, k, direction); int child = myrank + shift; if (k>0 && child < nrank) { /* Запрашиваем первый свободный процесс */ /* Поскольку здесь не реализован диспечер задач, то это будет следующий по номеру */ shift <<= 1; /* Отдаём половину массива на обработку этому процессу */ MPI_Send(&k, 1, MPI_INT, child, DATA_TAG, MPI_COMM_WORLD); MPI_Send(&direction, 1, MPI_INT, child, DATA_TAG, MPI_COMM_WORLD); MPI_Send(&elements[1<<k], 1<<k, MPI_LONG, child, DATA_TAG, MPI_COMM_WORLD); MPI_Send(&shift, 1, MPI_INT, child, DATA_TAG, MPI_COMM_WORLD); /* Сами продолжим обработку */ Mn(elements,k-1,direction,myrank,nrank,shift); /* Получим обработанные элементы обратно */ MPI_Recv(&elements[1<<k], 1<<k, MPI_LONG, child, DATA_TAG, MPI_COMM_WORLD, &status); shift >>= 1; } else if (k>0) {
void MovementSolute::solute (const Soil& soil, const SoilWater& soil_water, const double J_above, Chemical& chemical, const double dt, const Scope& scope, Treelog& msg) { daisy_assert (std::isfinite (J_above)); const size_t cell_size = geometry ().cell_size (); const size_t edge_size = geometry ().edge_size (); // Source term transfered from secondary to primary domain. std::vector<double> S_extra (cell_size, 0.0); // Divide top solute flux according to water. std::map<size_t, double> J_tertiary; std::map<size_t, double> J_secondary; std::map<size_t, double> J_primary; if (J_above > 0.0) // Outgoing, divide according to content in primary domain only. divide_top_outgoing (geometry (), chemical, J_above, J_primary, J_secondary, J_tertiary); else if (J_above < 0.0) // Incomming, divide according to all incomming water. divide_top_incomming (geometry (), soil_water, J_above, J_primary, J_secondary, J_tertiary); else // No flux. zero_top (geometry (), J_primary, J_secondary, J_tertiary); // Check result. { const std::vector<size_t>& edge_above = geometry ().cell_edges (Geometry::cell_above); const size_t edge_above_size = edge_above.size (); double J_sum = 0.0; for (size_t i = 0; i < edge_above_size; i++) { const size_t edge = edge_above[i]; const double in_sign = geometry ().cell_is_internal (geometry ().edge_to (edge)) ? 1.0 : -1.0; const double area = geometry ().edge_area (edge); // [cm^2 S] const double J_edge // [g/cm^2 S/h] = J_tertiary[edge] + J_secondary[edge] + J_primary[edge]; J_sum += in_sign * J_edge * area; // [g/h] if (in_sign * J_tertiary[edge] < 0.0) { std::ostringstream tmp; tmp << "J_tertiary[" << edge << "] = " << J_tertiary[edge] << ", in_sign = " << in_sign << ", J_above = " << J_above; msg.bug (tmp.str ()); } if (in_sign * J_secondary[edge] < 0.0) { std::ostringstream tmp; tmp << "J_secondary[" << edge << "] = " << J_secondary[edge] << ", in_sign = " << in_sign << ", J_above = " << J_above; msg.bug (tmp.str ()); } } J_sum /= geometry ().surface_area (); // [g/cm^2 S/h] daisy_approximate (-J_above, J_sum); } // We set a fixed concentration below lower boundary, if specified. std::map<size_t, double> C_border; const double C_below = chemical.C_below (); if (C_below >= 0.0) { const std::vector<size_t>& edge_below = geometry ().cell_edges (Geometry::cell_below); const size_t edge_below_size = edge_below.size (); for (size_t i = 0; i < edge_below_size; i++) { const size_t edge = edge_below[i]; C_border[edge] = C_below; } } // Tertiary transport. tertiary->solute (geometry (), soil_water, J_tertiary, dt, chemical, msg); // Fully adsorbed. if (chemical.adsorption ().full ()) { static const symbol solid_name ("immobile transport"); Treelog::Open nest (msg, solid_name); if (!iszero (J_above)) { std::ostringstream tmp; tmp << "J_above = " << J_above << ", expected 0 for full sorbtion"; msg.error (tmp.str ()); } // Secondary "transport". std::vector<double> J2 (edge_size, 0.0); // Flux delivered by flow. std::vector<double> Mn (cell_size); // New content. for (size_t c = 0; c < cell_size; c++) { Mn[c] = chemical.M_secondary (c) + chemical.S_secondary (c) * dt; if (Mn[c] < 0.0) { S_extra[c] = Mn[c] / dt; Mn[c] = 0.0; } else S_extra[c] = 0.0; } chemical.set_secondary (soil, soil_water, Mn, J2); // Primary "transport". primary_transport (geometry (), soil, soil_water, *matrix_solid, sink_sorbed, 0, J_primary, C_border, chemical, S_extra, dt, scope, msg); return; } // Secondary transport activated. secondary_transport (geometry (), soil, soil_water, J_secondary, C_border, chemical, S_extra, dt, scope, msg); // Solute primary transport. for (size_t transport_iteration = 0; transport_iteration < 2; transport_iteration++) for (size_t i = 0; i < matrix_solute.size (); i++) { solute_attempt (i); static const symbol solute_name ("solute"); Treelog::Open nest (msg, solute_name, i, matrix_solute[i]->objid); try { primary_transport (geometry (), soil, soil_water, *matrix_solute[i], sink_sorbed, transport_iteration, J_primary, C_border, chemical, S_extra, dt, scope, msg); if (i > 0) msg.debug ("Succeeded"); return; } catch (const char* error) { msg.debug (std::string ("Solute problem: ") + error); } catch (const std::string& error) { msg.debug(std::string ("Solute trouble: ") + error); } solute_failure (i); } throw "Matrix solute transport failed"; }
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); }