int STable3D::Push4 (int r, int c, int f, int t) { MFEM_ASSERT(r != c && r != f && r != t && c != f && c != t && f != t, " r = " << r << ", c = " << c << ", f = " << f << ", t = " << t); int i = 0; int max = r; if (max < c) { max = c, i = 1; } if (max < f) { max = f, i = 2; } if (max < t) { max = t, i = 3; } switch (i) { case 0: return Push (c,f,t); case 1: return Push (r,f,t); case 2: return Push (r,c,t); case 3: return Push (r,c,f); } return -1; }
double ElementTransformation::EvalWeight() { MFEM_ASSERT((EvalState & WEIGHT_MASK) == 0, ""); Jacobian(); EvalState |= WEIGHT_MASK; return (Wght = (dFdx.Width() == 0) ? 1.0 : dFdx.Weight()); }
void ParGridFunction::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset) { face_nbr_data.Destroy(); GridFunction::MakeRef(f, v, v_offset); pfes = dynamic_cast<ParFiniteElementSpace*>(f); MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace"); }
void ParGridFunction::SetSpace(FiniteElementSpace *f) { face_nbr_data.Destroy(); GridFunction::SetSpace(f); pfes = dynamic_cast<ParFiniteElementSpace*>(f); MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace"); }
void ParGridFunction::MakeRef(FiniteElementSpace *f, double *v) { face_nbr_data.Destroy(); GridFunction::MakeRef(f, v); pfes = dynamic_cast<ParFiniteElementSpace*>(f); MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace"); }
void BlockVector::Update(const Array<int> &bOffsets) { blockOffsets = bOffsets.GetData(); if (OwnsData()) { // check if 'bOffsets' agree with the 'blocks' if (bOffsets.Size() == numBlocks+1) { if (numBlocks == 0) { return; } if (Size() == bOffsets.Last()) { for (int i = numBlocks - 1; true; i--) { if (i < 0) { return; } if (blocks[i].Size() != bOffsets[i+1] - bOffsets[i]) { break; } MFEM_ASSERT(blocks[i].GetData() == data + bOffsets[i], "invalid blocks[" << i << ']'); } } } } else { Destroy(); } SetSize(bOffsets.Last()); if (numBlocks != bOffsets.Size()-1) { delete [] blocks; numBlocks = bOffsets.Size()-1; blocks = new Vector[numBlocks]; } SetBlocks(); }
// Convert a HYPRE_Int to int inline int to_int(HYPRE_Int i) { #ifdef HYPRE_BIGINT MFEM_ASSERT(HYPRE_Int(int(i)) == i, "overflow converting HYPRE_Int to int"); #endif return int(i); }
int STable3D::Push (int r, int c, int f) { STable3DNode *node; MFEM_ASSERT(r != c && c != f && f != r, "STable3D::Push : r = " << r << ", c = " << c << ", f = " << f); Sort3 (r, c, f); for (node = Rows[r]; node != NULL; node = node->Prev) { if (node->Column == c) if (node->Floor == f) { return node->Number; } } #ifdef MFEM_USE_MEMALLOC node = NodesMem.Alloc (); #else node = new STable3DNode; #endif node->Column = c; node->Floor = f; node->Number = NElem; node->Prev = Rows[r]; Rows[r] = node; NElem++; return (NElem-1); }
Vector &Vector::operator=(const double *v) { if (data != v) { MFEM_ASSERT(data + size <= v || v + size <= data, "Vectors overlap!"); mfem::Memcpy(data, v, sizeof(double)*size); } return *this; }
const DenseMatrix &ElementTransformation::EvalAdjugateJ() { MFEM_ASSERT((EvalState & ADJUGATE_MASK) == 0, ""); Jacobian(); adjJ.SetSize(dFdx.Width(), dFdx.Height()); if (dFdx.Width() > 0) { CalcAdjugate(dFdx, adjJ); } EvalState |= ADJUGATE_MASK; return adjJ; }
const DenseMatrix &IsoparametricTransformation::EvalJacobian() { MFEM_ASSERT(space_dim == PointMat.Height(), "the IsoparametricTransformation has not been finalized;" " call FinilizeTransformation() after setup"); MFEM_ASSERT((EvalState & JACOBIAN_MASK) == 0, ""); dshape.SetSize(FElem->GetDof(), FElem->GetDim()); dFdx.SetSize(PointMat.Height(), dshape.Width()); if (dshape.Width() > 0) { FElem->CalcDShape(*IntPoint, dshape); Mult(PointMat, dshape, dFdx); } EvalState |= JACOBIAN_MASK; return dFdx; }
Point(const Point& p0, const Point& p1, const Point& p2, const Point& p3) { dim = p0.dim; MFEM_ASSERT(p1.dim == dim && p2.dim == dim && p3.dim == dim, ""); for (int i = 0; i < dim; i++) { coord[i] = (p0.coord[i] + p1.coord[i] + p2.coord[i] + p3.coord[i]) * 0.25; } }
T Array<T>::Min() const { MFEM_ASSERT(size > 0, "Array is empty with size " << size); T min = operator[](0); for (int i = 1; i < size; i++) if (operator[](i) < min) min = operator[](i); return min; }
T Array<T>::Max() const { MFEM_ASSERT(size > 0, "Array is empty with size " << size); T max = operator[](0); for (int i = 1; i < size; i++) if (max < operator[](i)) max = operator[](i); return max; }
const DenseMatrix &ElementTransformation::EvalInverseJ() { // TODO: compute as invJ = / adjJ/Weight, if J is square, // \ adjJ/Weight^2, otherwise. MFEM_ASSERT((EvalState & INVERSE_MASK) == 0, ""); Jacobian(); invJ.SetSize(dFdx.Width(), dFdx.Height()); if (dFdx.Width() > 0) { CalcInverse(dFdx, invJ); } EvalState |= INVERSE_MASK; return invJ; }
void IsoparametricTransformation::Transform (const DenseMatrix &matrix, DenseMatrix &result) { MFEM_ASSERT(matrix.Height() == GetDimension(), "invalid input"); result.SetSize(PointMat.Height(), matrix.Width()); IntegrationPoint ip; Vector col; for (int j = 0; j < matrix.Width(); j++) { ip.Set(matrix.GetColumn(j), matrix.Height()); result.GetColumnReference(j, col); Transform(ip, col); } }
Vector::Vector(const Vector &v) { int s = v.Size(); if (s > 0) { MFEM_ASSERT(v.data, "invalid source vector"); allocsize = size = s; data = mfem::New<double>(s); mfem::Memcpy(data, v.data, sizeof(double)*s); } else { allocsize = size = 0; data = NULL; } }
void ParGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, Array<int> &bdr_attr) { Array<int> values_counter; AccumulateAndCountBdrTangentValues(vcoeff, bdr_attr, values_counter); if (pfes->Conforming()) { Vector values(Size()); for (int i = 0; i < values.Size(); i++) { values(i) = values_counter[i] ? (*this)(i) : 0.0; } // Count the values globally. GroupCommunicator &gcomm = pfes->GroupComm(); gcomm.Reduce<int>(values_counter, GroupCommunicator::Sum); // Accumulate the values globally. gcomm.Reduce<double>(values, GroupCommunicator::Sum); // Only the values in the master are guaranteed to be correct! for (int i = 0; i < values.Size(); i++) { if (values_counter[i]) { (*this)(i) = values(i)/values_counter[i]; } } } else { // FIXME: same as the conforming case after 'cut-mesh-groups-dev-*' is // merged? ComputeMeans(ARITHMETIC, values_counter); } #ifdef MFEM_DEBUG Array<int> ess_vdofs_marker; pfes->GetEssentialVDofs(bdr_attr, ess_vdofs_marker); for (int i = 0; i < values_counter.Size(); i++) { MFEM_ASSERT(pfes->GetLocalTDofNumber(i) == -1 || bool(values_counter[i]) == bool(ess_vdofs_marker[i]), "internal error"); } #endif }
double ParGridFunction::GetValue(int i, const IntegrationPoint &ip, int vdim) const { Array<int> dofs; Vector DofVal, LocVec; int nbr_el_no = i - pfes->GetParMesh()->GetNE(); if (nbr_el_no >= 0) { int fes_vdim = pfes->GetVDim(); pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs); if (fes_vdim > 1) { int s = dofs.Size()/fes_vdim; Array<int> _dofs(&dofs[(vdim-1)*s], s); face_nbr_data.GetSubVector(_dofs, LocVec); DofVal.SetSize(s); } else { face_nbr_data.GetSubVector(dofs, LocVec); DofVal.SetSize(dofs.Size()); } pfes->GetFaceNbrFE(nbr_el_no)->CalcShape(ip, DofVal); } else { fes->GetElementDofs(i, dofs); fes->DofsToVDofs(vdim-1, dofs); DofVal.SetSize(dofs.Size()); const FiniteElement *fe = fes->GetFE(i); MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type"); fe->CalcShape(ip, DofVal); GetSubVector(dofs, LocVec); } return (DofVal * LocVec); }
int InverseElementTransformation::NewtonSolve(const Vector &pt, IntegrationPoint &ip) { MFEM_ASSERT(pt.Size() == T->GetSpaceDim(), "invalid point"); const double phys_tol = phys_rtol*pt.Normlinf(); const int geom = T->GetGeometryType(); const int dim = T->GetDimension(); const int sdim = T->GetSpaceDim(); IntegrationPoint xip, prev_xip; double xd[3], yd[3], dxd[3], dx_norm = -1.0, err_phys, real_dx_norm = -1.0; Vector x(xd, dim), y(yd, sdim), dx(dxd, dim); bool hit_bdr = false, prev_hit_bdr = false; // Use ip0 as initial guess: xip = *ip0; xip.Get(xd, dim); // xip -> x if (print_level >= 3) { NewtonPrint(1, 0.); // iter 0 NewtonPrintPoint(", ref_pt", x, "\n"); } for (int it = 0; true; ) { // Remarks: // If f(x) := 1/2 |pt-F(x)|^2, then grad(f)(x) = -J^t(x) [pt-F(x)]. // Linearize F(y) at y=x: F(y) ~ L[x](y) := F(x) + J(x) [y-x]. // Newton iteration for F(y)=b is given by L[x_old](x_new) = b, i.e. // F(x_old) + J(x_old) [x_new-x_old] = b. // // To minimize: 1/2 |F(y)-b|^2, subject to: l(y) >= 0, we may consider the // iteration: minimize: |L[x_old](x_new)-b|^2, subject to l(x_new) >= 0, // i.e. minimize: |F(x_old) + J(x_old) [x_new-x_old] - b|^2. // This method uses: // Newton iteration: x := x + J(x)^{-1} [pt-F(x)] // or when dim != sdim: x := x + [J^t.J]^{-1}.J^t [pt-F(x)] // Compute the physical coordinates of the current point: T->Transform(xip, y); if (print_level >= 3) { NewtonPrint(11, 0.); // continuation line NewtonPrintPoint("approx_pt", y, ", "); NewtonPrintPoint("exact_pt", pt, "\n"); } subtract(pt, y, y); // y = pt-y // Check for convergence in physical coordinates: err_phys = y.Normlinf(); if (err_phys < phys_tol) { if (print_level >= 1) { NewtonPrint(1, (double)it); NewtonPrint(3, dx_norm); NewtonPrint(30, err_phys); } ip = xip; if (solver_type != Newton) { return Inside; } return Geometry::CheckPoint(geom, ip, ip_tol) ? Inside : Outside; } if (print_level >= 1) { if (it == 0 || print_level >= 2) { NewtonPrint(1, (double)it); NewtonPrint(3, dx_norm); NewtonPrint(18, err_phys); } } if (hit_bdr) { xip.Get(xd, dim); // xip -> x if (prev_hit_bdr || it == max_iter || print_level >= 2) { prev_xip.Get(dxd, dim); // prev_xip -> dx subtract(x, dx, dx); // dx = xip - prev_xip real_dx_norm = dx.Normlinf(); if (print_level >= 2) { NewtonPrint(41, real_dx_norm); } if (prev_hit_bdr && real_dx_norm < ref_tol) { if (print_level >= 0) { if (print_level <= 1) { NewtonPrint(1, (double)it); NewtonPrint(3, dx_norm); NewtonPrint(18, err_phys); NewtonPrint(41, real_dx_norm); } mfem::out << "Newton: *** stuck on boundary!\n"; } return Outside; } } } if (it == max_iter) { break; } // Perform a Newton step: T->SetIntPoint(&xip); T->InverseJacobian().Mult(y, dx); x += dx; it++; if (solver_type != Newton) { prev_xip = xip; prev_hit_bdr = hit_bdr; } xip.Set(xd, dim); // x -> xip // Perform projection based on solver_type: switch (solver_type) { case Newton: break; case NewtonSegmentProject: hit_bdr = !Geometry::ProjectPoint(geom, prev_xip, xip); break; case NewtonElementProject: hit_bdr = !Geometry::ProjectPoint(geom, xip); break; default: MFEM_ABORT("invalid solver type"); } if (print_level >= 3) { NewtonPrint(1, double(it)); xip.Get(xd, dim); // xip -> x NewtonPrintPoint(", ref_pt", x, "\n"); } // Check for convergence in reference coordinates: dx_norm = dx.Normlinf(); if (dx_norm < ref_tol) { if (print_level >= 1) { NewtonPrint(1, (double)it); NewtonPrint(27, dx_norm); } ip = xip; if (solver_type != Newton) { return Inside; } return Geometry::CheckPoint(geom, ip, ip_tol) ? Inside : Outside; } } if (print_level >= 0) { if (print_level <= 1) { NewtonPrint(1, (double)max_iter); NewtonPrint(3, dx_norm); NewtonPrint(18, err_phys); if (hit_bdr) { NewtonPrint(41, real_dx_norm); } } mfem::out << "Newton: *** iteration did not converge!\n"; } ip = xip; return Unknown; }
/// Check if the mesh of the solution was modified. bool MeshIsModified() { long mesh_sequence = solution->FESpace()->GetMesh()->GetSequence(); MFEM_ASSERT(mesh_sequence >= current_sequence, ""); return (mesh_sequence > current_sequence); }