Intrepid2
Intrepid2_CellToolsDefPhysToRef.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Intrepid2 Package
4//
5// Copyright 2007 NTESS and the Intrepid2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10
16#ifndef __INTREPID2_CELLTOOLS_DEF_PHYS_TO_REF_HPP__
17#define __INTREPID2_CELLTOOLS_DEF_PHYS_TO_REF_HPP__
18
19// disable clang warnings
20#if defined (__clang__) && !defined (__INTEL_COMPILER)
21#pragma clang system_header
22#endif
23
24namespace Intrepid2 {
25
26
27 //============================================================================================//
28 // //
29 // Reference-to-physical frame mapping and its inverse //
30 // //
31 //============================================================================================//
32
33 namespace FunctorCellTools {
34
40 template<typename OutViewType, typename TanViewType, typename InViewType>
42 OutViewType result_;
43 TanViewType workview_;
44 const TanViewType tangents_;
45 const InViewType residual_;
46 const typename OutViewType::value_type scaling_;
47
48 KOKKOS_INLINE_FUNCTION
49 F_scaledResidualNormalComponent3d( OutViewType result,
50 TanViewType workview,
51 const TanViewType tangents,
52 const InViewType residual,
53 const typename OutViewType::value_type scaling)
54 : result_(result), workview_(workview), tangents_(tangents), residual_(residual), scaling_(scaling) {}
55
56 KOKKOS_INLINE_FUNCTION
57 void operator()(const ordinal_type cell,
58 const ordinal_type point) const {
59
60 auto t1 = Kokkos::subview( tangents_, cell, point, Kokkos::ALL(), 0);
61 auto t2 = Kokkos::subview( tangents_, cell, point, Kokkos::ALL(), 1);
62 auto n = Kokkos::subview( workview_, cell, point, Kokkos::ALL());
63 Kernels::Serial::vector_product_d3(n, t1, t2);
64 result_(cell,point) = (n(0)*residual_(cell,point,0) + n(1)*residual_(cell,point,1) + n(2)*residual_(cell,point,2))*scaling_/Kernels::Serial::norm(n, NORM_TWO);
65 }
66 };
67
71 template<typename OutViewType, typename TanViewType, typename InViewType>
73 OutViewType result_;
74 const TanViewType tangents_;
75 const InViewType residual_;
76 const typename InViewType::value_type scaling_;
77
78 KOKKOS_INLINE_FUNCTION
79 F_scaledResidualNormalComponent2d( OutViewType result,
80 const TanViewType tangents,
81 const InViewType residual,
82 const typename InViewType::value_type scaling)
83 : result_(result), tangents_(tangents), residual_(residual), scaling_(scaling) {}
84
85 KOKKOS_INLINE_FUNCTION
86 void operator()(const ordinal_type cell,
87 const ordinal_type point) const {
88 auto t = Kokkos::subview( tangents_, cell, point, Kokkos::ALL(), 0); // n = [-t_1, t_0]
89 result_(cell,point) = (-t(1)*residual_(cell,point,0) + t(0)*residual_(cell,point,1))*scaling_/Kernels::Serial::norm(t, NORM_TWO);
90 }
91 };
92
96 template<typename ViewType>
97 struct F_maxNorm {
98 const ViewType view_;
99 KOKKOS_INLINE_FUNCTION
100 F_maxNorm( const ViewType view)
101 : view_(view) {}
102
103 KOKKOS_INLINE_FUNCTION
104 void operator()(const ordinal_type cl,
105 const ordinal_type pt,
106 typename ViewType::value_type& lmax) const {
107 if (view_(cl,pt) > lmax) lmax = view_(cl,pt);
108 }
109 };
110
111 }
112
113 template<typename DeviceType>
114 template<typename OutViewType, typename TanViewType, typename InViewType>
115 void
118 OutViewType result,
119 const TanViewType tangents,
120 const InViewType residual,
121 const typename InViewType::value_type scaling)
122 {
123 constexpr bool is_accessible =
124 Kokkos::SpaceAccessibility<MemSpaceType,
125 typename decltype(tangents)::memory_space>::accessible;
126 static_assert(is_accessible, "CellTools<DeviceType>::setJacobian(..): output view's memory space is not compatible with DeviceType");
127
128 using range_policy_type = Kokkos::MDRangePolicy
129 < ExecSpaceType, Kokkos::Rank<2>, Kokkos::IndexType<ordinal_type> >;
130 range_policy_type policy( { 0, 0 },
131 { tangents.extent(0), tangents.extent(1) } );
132 if (tangents.extent_int(2) == 2) {
134 Kokkos::parallel_for( policy, FunctorType(result, tangents, residual, scaling) );
135 } else {
137 TanViewType work = Impl::createMatchingDynRankView(tangents, "work_view", tangents.extent_int(0), tangents.extent_int(1), tangents.extent_int(2));
138 Kokkos::parallel_for( policy, FunctorType(result, work, tangents, residual, scaling) );
139 }
140 }
141
142
143
144 template<typename DeviceType>
145 template<typename refPointValueType, class ...refPointProperties,
146 typename physPointValueType, class ...physPointProperties,
147 typename worksetCellValueType, class ...worksetCellProperties>
148 bool
150 mapToReferenceFrame( Kokkos::DynRankView<refPointValueType,refPointProperties...> refPoints,
151 const Kokkos::DynRankView<physPointValueType,physPointProperties...> physPoints,
152 const Kokkos::DynRankView<worksetCellValueType,worksetCellProperties...> worksetCell,
153 const shards::CellTopology cellTopo,
154 const physPointValueType shellThickness ) {
155 constexpr bool are_accessible =
156 Kokkos::SpaceAccessibility<MemSpaceType,
157 typename decltype(refPoints)::memory_space>::accessible &&
158 Kokkos::SpaceAccessibility<MemSpaceType,
159 typename decltype(physPoints)::memory_space>::accessible &&
160 Kokkos::SpaceAccessibility<MemSpaceType,
161 typename decltype(worksetCell)::memory_space>::accessible;
162
163 static_assert(are_accessible, "CellTools<DeviceType>::mapToReferenceFrame(..): input/output views' memory spaces are not compatible with DeviceType");
164
165#ifdef HAVE_INTREPID2_DEBUG
166 CellTools_mapToReferenceFrameArgs(refPoints, physPoints, worksetCell, cellTopo);
167#endif
168 using deviceType = typename decltype(refPoints)::device_type;
169
170 typedef RealSpaceTools<deviceType> rst;
171 typedef Kokkos::DynRankView<typename ScalarTraits<refPointValueType>::scalar_type,deviceType> refPointViewSpType;
172
173 const auto spaceDim = cellTopo.getDimension();
174 refPointViewSpType
175 cellCenter("CellTools::mapToReferenceFrame::cellCenter", spaceDim);
176 getReferenceCellCenter(cellCenter, cellTopo);
177
178 // initialize refPoints with the cell center
179 rst::clone(refPoints, cellCenter);
180
181 auto basis = createHGradBasis<refPointValueType,refPointValueType>(cellTopo);
182 return mapToReferenceFrame(refPoints, physPoints, worksetCell, basis, shellThickness);
183 }
184
185
186 template<typename DeviceType>
187 template<typename refPointValueType, class ...refPointProperties,
188 typename physPointValueType, class ...physPointProperties,
189 typename worksetCellValueType, class ...worksetCellProperties>
190 bool
192 mapToReferenceFrame( Kokkos::DynRankView<refPointValueType,refPointProperties...> refPoints,
193 const Kokkos::DynRankView<physPointValueType,physPointProperties...> physPoints,
194 const Kokkos::DynRankView<worksetCellValueType,worksetCellProperties...> worksetCell,
196 const physPointValueType shellThickness) {
197 constexpr bool are_accessible =
198 Kokkos::SpaceAccessibility<MemSpaceType,
199 typename decltype(refPoints)::memory_space>::accessible &&
200 Kokkos::SpaceAccessibility<MemSpaceType,
201 typename decltype(physPoints)::memory_space>::accessible &&
202 Kokkos::SpaceAccessibility<MemSpaceType,
203 typename decltype(worksetCell)::memory_space>::accessible;
204
205 static_assert(are_accessible, "CellTools<DeviceType>::mapToReferenceFrameInitGuess(..): input/output views' memory spaces are not compatible with DeviceType");
206
207 const bool isShell = (shellThickness>0);
208
209 //note, for Beam and Shell elements, refPoints have refDim+1 dimension
210 const ordinal_type refDim = basis->getDomainDimension();
211 const ordinal_type physDim = physPoints.extent_int(2);
212
213 // Default: map (C,P,D) array of physical pt. sets to (C,P,D) array.
214 // Requires (C,P,D) temp arrays and (C,P,D,D) Jacobians.
215 const auto numCells = worksetCell.extent(0);
216 const auto numPoints = physPoints.extent(1);
217
218 using rst = RealSpaceTools<DeviceType>;
219 auto refDimRange = Kokkos::pair<ordinal_type,ordinal_type>(0,refDim);
220
221 using result_layout = typename DeduceLayout< decltype(refPoints) >::result_layout;
222 // Temp arrays for Newton iterates and Jacobians. Resize according to rank of ref. point array
223 auto xOld = Impl::createMatchingDynRankView(refPoints, "CellTools::mapToReferenceFrameInitGuess::xOld", numCells, numPoints, refDim);
224 auto xTmp = Impl::createMatchingDynRankView(refPoints, "CellTools::mapToReferenceFrameInitGuess::xTmp", numCells, numPoints, refDim);
225 auto physTmp = Impl::createMatchingDynRankView(refPoints, "CellTools::mapToReferenceFrameInitGuess::physTmp", numCells, numPoints, physDim);
226
227 // deep copy may not work with FAD but this is right thing to do as it can move data between devices
228 Kokkos::deep_copy(xOld, Kokkos::subview(refPoints, Kokkos::ALL(), Kokkos::ALL(), refDimRange));
229
230 // jacobian should select fad dimension between xOld and worksetCell as they are input; no front interface yet
231 using valueTypeJ = std::common_type_t<typename decltype(refPoints)::value_type, typename decltype(worksetCell)::value_type>;
232 using viewTypeJ = Kokkos::DynRankView<valueTypeJ, result_layout, DeviceType >;
233 using view_factory = Impl::CreateViewFactory<decltype(refPoints), decltype(worksetCell)>;
234
235 viewTypeJ metric;
236 if(refDim < physDim)
237 metric = view_factory::template create_view<viewTypeJ>(refPoints, worksetCell, "CellTools::mapToReferenceFrameInitGuess::metric", numCells, numPoints, refDim, refDim);
238 viewTypeJ jacobian = view_factory::template create_view<viewTypeJ>(refPoints, worksetCell, "CellTools::mapToReferenceFrameInitGuess::jacobian", numCells, numPoints, physDim, refDim);
239
240 // when refDim < physDim, this will contain the inverse of the metric
241 viewTypeJ jacobianInv = view_factory::template create_view<viewTypeJ>(refPoints, worksetCell, "CellTools::mapToReferenceFrameInitGuess::jacobianInv", numCells, numPoints, refDim, refDim);
242
243
244 using errorViewType = Kokkos::DynRankView<typename ScalarTraits<refPointValueType>::scalar_type, DeviceType>;
245 using errorType = typename errorViewType::value_type;
246 errorViewType
247 xScalarTmp ("CellTools::mapToReferenceFrameInitGuess::xScalarTmp", numCells, numPoints, physDim),
248 errorPointwise("CellTools::mapToReferenceFrameInitGuess::errorPointwise", numCells, numPoints);
249
250
251 const auto tol = tolerance<errorType>();
252
253 errorType error(0), physInfNorm(0);
254
255 rst::extractScalarValues(xScalarTmp, physPoints);
256 rst::vectorNorm(errorPointwise, xScalarTmp, NORM_TWO);
257 using range_policy_type = Kokkos::MDRangePolicy<typename DeviceType::execution_space, Kokkos::Rank<2>, Kokkos::IndexType<ordinal_type> >;
258 range_policy_type policy( { 0, 0 }, { numCells, numPoints } );
260 Kokkos::parallel_reduce("MaxReduction", policy, FunctorType(errorPointwise), Kokkos::Max<errorType>(physInfNorm));
261
262 auto refPts = Kokkos::subview(refPoints,Kokkos::ALL(), Kokkos::ALL(), refDimRange);
263
264
265 // Newton method to solve the equation F(refPoints) - physPoints = 0:
266 // refPoints = xOld - DF^{-1}(xOld)*(F(xOld) - physPoints) = xOld + DF^{-1}(xOld)*(physPoints - F(xOld))
267 bool converged(false);
268 for (ordinal_type iter=0;iter<Parameters::MaxNewton;++iter) {
269
270 // Jacobians at the old iterates and their inverses.
271 setJacobian(jacobian, xOld, worksetCell, basis);
272
273 // The Newton step.
274 mapToPhysicalFrame(physTmp, xOld, worksetCell, basis); // physTmp <- F(xOld)
275 rst::subtract(physTmp, physPoints, physTmp); // physTmp <- physPoints - F(xOld)
276
277 // l2 error (Euclidean distance) of the residual |physPoints - F(xOld)|
278 rst::extractScalarValues(xScalarTmp, physTmp);
279 rst::vectorNorm(errorPointwise, xScalarTmp, NORM_TWO);
280
281 error = 0;
282 Kokkos::parallel_reduce("MaxReduction", policy, FunctorType(errorPointwise), Kokkos::Max<errorType>(error));
283
284 if (error < tol*physInfNorm) {
285 converged = true;
286 break;
287 }
288
289
290 if(refDim < physDim) {
291 rst::matvec(xTmp, jacobian, physTmp, true); // xTmp <- DF^{T}( physPoints - F(xOld) ))
292 rst::AtA(metric,jacobian);
293 setJacobianInv(jacobianInv, metric);
294 rst::matvec(refPts, jacobianInv, xTmp); // refPoints <- (DF^{T} DF)^{-1} DF^{T}( physPoints - F(xOld) )
295 }
296 else {
297 setJacobianInv(jacobianInv, jacobian);
298 rst::matvec(refPts, jacobianInv, physTmp); // refPoints <- DF^{-1}( physPoints - F(xOld) )
299 }
300
301 // extract values
302 rst::extractScalarValues(Kokkos::subview(xScalarTmp, Kokkos::ALL(), Kokkos::ALL(), refDimRange), refPts);
303
304 rst::add(refPts, xOld); // refPoints <- refPoints + xOld
305
306
307 error = 0;
308 // l2 error (Euclidean distance) between old and new iterates: |xOld - xNew|
309 rst::vectorNorm(errorPointwise, Kokkos::subview(xScalarTmp, Kokkos::ALL(), Kokkos::ALL(), refDimRange), NORM_TWO);
310 Kokkos::parallel_reduce("MaxReduction", policy, FunctorType(errorPointwise), Kokkos::Max<errorType>(error));
311
312 // Stopping criterion:
313 if (error < tol) {
314 converged = true;
315 if(isShell) { //update Jacobian and residual so that they are consistent with refPts
316 setJacobian(jacobian, refPts, worksetCell, basis);
317 mapToPhysicalFrame(physTmp, refPts, worksetCell, basis); // physTmp <- F(refPts)
318 rst::subtract(physTmp, physPoints, physTmp); // physTmp <- physPoints - F(refPts)
319 }
320 break;
321 }
322
323 // initialize next Newton step ( this is not device friendly )
324 Kokkos::deep_copy(xOld, refPts);
325 }
326
327 if(isShell) {
328 //for shell elements, we can reconstruct the orthogonal reference component by approximating the
329 //signed distance between the physical point and the map to physical space of the reference line (in 2d) or triangle,quad (in 3d),
330 //and dividing it by the shell half thickness. We do so by solving
331 //(physPoints - F(xOld)) * n /|n|^2 / (H/2)
332 //where H is the shell thickness and n is the normal to the manifold defined by the map to physical frame (n is orthogonal to the tangents defined by the Jacobian)
333 scaledResidualNormalComponent(
334 Kokkos::subview(refPoints,Kokkos::ALL(), Kokkos::ALL(), refDim),
335 jacobian,
336 physTmp,
337 2.0/shellThickness);
338 }
339
340 return converged;
341 }
342
343
344 template<typename DeviceType>
345 template<typename refPointValueType, class ...refPointProperties,
346 typename initGuessValueType, class ...initGuessProperties,
347 typename physPointValueType, class ...physPointProperties,
348 typename worksetCellValueType, class ...worksetCellProperties>
349 bool
351 mapToReferenceFrameInitGuess( Kokkos::DynRankView<refPointValueType,refPointProperties...> refPoints,
352 const Kokkos::DynRankView<initGuessValueType,initGuessProperties...> initGuess,
353 const Kokkos::DynRankView<physPointValueType,physPointProperties...> physPoints,
354 const Kokkos::DynRankView<worksetCellValueType,worksetCellProperties...> worksetCell,
355 const shards::CellTopology cellTopo,
356 const physPointValueType shellThickness) {
357
358 #ifdef HAVE_INTREPID2_DEBUG
359 CellTools_mapToReferenceFrameInitGuessArgs(refPoints, initGuess, physPoints, worksetCell, cellTopo);
360 #endif
361
362 Kokkos::deep_copy(refPoints,initGuess);
363 auto basis = createHGradBasis<refPointValueType,refPointValueType>(cellTopo);
364 return mapToReferenceFrame(refPoints,
365 physPoints,
366 worksetCell,
367 basis,
368 shellThickness);
369 }
370
371}
372
373#endif
Teuchos::RCP< Basis< DeviceType, OutputType, PointType > > BasisPtr
Basis Pointer.
void CellTools_mapToReferenceFrameArgs(const refPointViewType refPoints, const physPointViewType physPoints, const worksetCellViewType worksetCell, const shards::CellTopology cellTopo)
Validates arguments to Intrepid2::CellTools::mapToReferenceFrame with default initial guess.
static bool mapToReferenceFrame(Kokkos::DynRankView< refPointValueType, refPointProperties... > refPoints, const Kokkos::DynRankView< physPointValueType, physPointProperties... > physPoints, const Kokkos::DynRankView< worksetCellValueType, worksetCellProperties... > worksetCell, const shards::CellTopology cellTopo, const physPointValueType shellThickness=-1.0)
Computes , the inverse of the reference-to-physical frame map using a default initial guess.
static void scaledResidualNormalComponent(OutViewType result, const TanViewType tangents, const InViewType residual, const typename InViewType::value_type scaling)
Computes the scaled normal component of a d-dimensional resudial vecor with respect to a (d-1) dimens...
static bool mapToReferenceFrameInitGuess(Kokkos::DynRankView< refPointValueType, refPointProperties... > refPoints, const Kokkos::DynRankView< initGuessValueType, initGuessProperties... > initGuess, const Kokkos::DynRankView< physPointValueType, physPointProperties... > physPoints, const Kokkos::DynRankView< worksetCellValueType, worksetCellProperties... > worksetCell, const HGradBasisPtrType basis, const physPointValueType shellThickness=-1.0)
[Deprecated] Computation of , the inverse of the reference-to-physical frame map using user-supplied ...
static constexpr ordinal_type MaxNewton
Maximum number of Newton iterations used internally in methods such as computing the action of the in...
Implementation of basic linear algebra functionality in Euclidean space.
layout deduction (temporary meta-function)
Functor for computing the max norm of a view.
Functor for computing the scaled normal component of the residual, 2d version.
Functor for computing the scaled normal component of the residual, 3d version.
Factory to create a view based on the properties of input views The class is useful when the view can...