void Engine2D::CreateMesh(Mesh2D& mesh) { // Fill side1 length BC -> Left side // Fill side2 length BC -> Right side // Fill width1 BC ->Top // Fill width2 BC ->bottom mesh.number_of_nodes = (mesh.spacial_length / mesh.spacial_step_size); mesh.all_node_locations.push_back(0); for (int i = 0; i < mesh.number_of_nodes; i++) { mesh.all_node_locations.push_back(mesh.all_node_locations.back() + mesh.spacial_step_size); } // !Create a boundary condition for each state for (int state = 0; state <= number_of_states; state++) { mesh.left_side_boundary_conditions.push_back(mesh.SideBoundary()); mesh.right_side_boundary_conditions.push_back(mesh.SideBoundary()); // !First and last states if (state== 0 || state==number_of_states) { mesh.top_width_boundary_conditions.push_back(mesh.WidthBoundary()); mesh.bottom_width_boundary_conditions.push_back(mesh.WidthBoundary()); } } }
// ============================================================================= bool Mesh2DUtils::identify_patch_upper_right(const Mesh2D&m, double u, double v, int& x_ix, int& y_ix) // ============================================================================= { double tol = 1.0e-9; x_ix = first_larger_knotvalue_ix(m, XFIXED, u); y_ix = first_larger_knotvalue_ix(m, YFIXED, v); // adjustment of index if positioned _exactly_ at upper bound of grid if ((x_ix == m.numDistinctKnots(XFIXED) - 1) && (fabs(u-m.maxParam(XFIXED) < tol))) --x_ix; if ((y_ix == m.numDistinctKnots(YFIXED) - 1) && (fabs(v-m.maxParam(YFIXED) < tol))) --y_ix; // checking if a valid corner was found if (x_ix == 0 || x_ix >= m.numDistinctKnots(XFIXED)) return false; // u outside domain if (y_ix == 0 || y_ix >= m.numDistinctKnots(YFIXED)) return false; // v outside domain // We have now found the largest smaller knot in the u and v direction. From here we // can search downwards to the lower-left corner of the containing mesh element, which // defines the sought-for "patch" of the surface. x_ix = search_upwards_for_nonzero_multiplicity(m, XFIXED, x_ix, y_ix); y_ix = search_upwards_for_nonzero_multiplicity(m, YFIXED, y_ix, x_ix); return true; }
// ============================================================================= int Mesh2DUtils::last_nonlarger_knotvalue_ix(const Mesh2D&m, Direction2D d, double par) // ============================================================================= { const double* a = m.knotsBegin(d); const double* b = m.knotsEnd(d); double tol = 1.0e-8; // if (par < a[0] && par >= a[0]-tol) // par = a[0]; // if (par > b[-1] && par <= b[-1]+tol) // par = b[-1]; // searching for last nonlarger knotvalue using bisection for (int diff = (b-a)/2; diff != 0; diff = (b-a)/2) { if (par < a[0]+tol && par >= a[0]-tol) par = a[0]; if (par > b[-1]-tol && par <= b[-1]+tol) par = b[-1]; const double* mid = a + diff; ( (*mid > par) ? b : a) = mid; } if (b == m.knotsEnd(d)) --b; if (fabs(par-b[0]) < tol && fabs(par-a[0]) > tol) return (b - m.knotsBegin(d)); else return (a - m.knotsBegin(d)); // if index becomes negative, it signalizes that 'par' // is smaller than even the first knot value }
//============================================================================== int Mesh2DUtils::search_upwards_for_nonzero_multiplicity(const Mesh2D& m, Direction2D d, int start_ix, int other_ix) //============================================================================== { // provided that the mesh is a valid LR mesh, a valid index should always be found. int ix; for (ix = start_ix; ix != m.numDistinctKnots(d) && m.nu(d, ix, other_ix - 1, other_ix) == 0; ++ix); return ix; // @@ not yet tested! }
// ============================================================================= int Mesh2DUtils::first_larger_knotvalue_ix(const Mesh2D& m, Direction2D d, double par) // ============================================================================= { int ix = last_nonlarger_knotvalue_ix(m, d, par); if (ix < m.numDistinctKnots(d)-1) ix++; return ix; }
// ============================================================================= int Mesh2DUtils::search_downwards_for_nonzero_multiplicity(const Mesh2D& m, Direction2D d, int start_ix, int other_ix) // ============================================================================= { // provided that the mesh is a valid LR mesh, a valid index should always be found. int ix; for (ix = start_ix; ix != 0 && m.nu(d, ix, other_ix, other_ix + 1) == 0; --ix); return ix; }
// Derive the knotvector resulting from moving along the u-direction (if d == XFIXED) or // v-direction (if d == YFIXED) from 'beg' to 'end', and with multiplicities equal to // the 'nu' value of the segment in the ortogonal direction, starting at 'orto_min' and // extending to 'orto_max'. //------------------------------------------------------------------------------ vector<int> LRBSpline2DUtils::derive_knots(const Mesh2D& m, Direction2D d, int beg, int end, int orto_min, int orto_max) //------------------------------------------------------------------------------ { vector<int> result; for (int pos = beg; pos <= end; ++pos) result.insert(result.end(), m.nu(d, pos, orto_min, orto_max), pos); // 0 multiplicities will not be inserted return result; }
//============================================================================== // if 'b' can be split at least once in the mesh 'm', split it once, and return the // result through 'b1' and 'b2'. The function never carries out more than one split, // even when several splits are possible. bool LRBSpline2DUtils::try_split_once(const LRBSpline2D& b, const Mesh2D& mesh, LRBSpline2D*& b1, LRBSpline2D*& b2) //============================================================================== { const int umin = b.suppMin(XFIXED); const int vmin = b.suppMin(YFIXED); const int umax = b.suppMax(XFIXED); const int vmax = b.suppMax(YFIXED); const vector<int> m_kvec_u = derive_knots(mesh, XFIXED, umin, umax, vmin, vmax); const vector<int> m_kvec_v = derive_knots(mesh, YFIXED, vmin, vmax, umin, umax); // @@ The assertions below should always hold if function is called with correct // argument. When code is properly debugged and tested, they can be taken away for // efficiency (asserts should go away anyway when compiling in optimized mode). // Alternatively, if it is a concern that users might call this function with wrong // argument, the assertions could be replaced by exception-throwing 'if'-statements. assert(std::includes(m_kvec_u.begin(), m_kvec_u.end(), b.kvec(XFIXED).begin(), b.kvec(XFIXED).end())); assert(std::includes(m_kvec_v.begin(), m_kvec_v.end(), b.kvec(YFIXED).begin(), b.kvec(YFIXED).end())); if (num_inner_knots(m_kvec_u) > num_inner_knots(b.kvec(XFIXED))) { // Since we know that m_kvec_u contains more elements than b.kvec(XFIXED) and since // we know that the latter is included in the former, we know that there must be at least // one knot in 'm_kvec_u' that is not found in b.kvec(XFIXED). We can therefore call // the following function without risking an exception to be thrown. const int new_ix = find_uncovered_inner_knot(m_kvec_u, b.kvec(XFIXED)); // @@@ VSK. Cannot set pointers to the new bsplines before it is placed in the // global array. Will the position of the element change when a bspline is removed? split_function(b, mesh, XFIXED, mesh.knotsBegin(XFIXED), new_ix, b1, b2); return true; } else if (num_inner_knots(m_kvec_v) > num_inner_knots(b.kvec(YFIXED))) { // same comment as above const int new_ix = find_uncovered_inner_knot(m_kvec_v, b.kvec(YFIXED)); split_function(b, mesh, YFIXED, mesh.knotsBegin(YFIXED), new_ix, b1, b2); return true; } // No splits possible return false; }
void Engine2D::CreateInitialState(Mesh2D &mesh) { vector<vector<tuple<double, double>>> instance_container; for (int i = 0; i < (mesh.spacial_length / mesh.spacial_step_size); i++) { this->current_configuration.push_back(std::make_tuple(mesh.all_node_locations.front(), mesh.left_side_boundary_conditions.at(0))); //Put the first I.C in. for (float j = 1; j <= mesh.number_of_nodes - 1; ++j) // Iterate over the nodes which are not boundary conditions. (starts at node 1 and stops at # of nodes-1 { this->current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(j), mesh.InitialDistribution(0))); } this->current_configuration.push_back(std::make_tuple(mesh.all_node_locations.back(), mesh.right_side_boundary_conditions.at(0))); // Once filled, set the last B.C. Instance.push_back(current_configuration); this->current_configuration.clear(); // Clear the current state } this->Results.push_back(Instance); // Add to the vector of states Instance.clear(); }