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::subdynrankview(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::subdynrankview(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 // The Newton residual at the old iterate.
271 mapToPhysicalFrame(physTmp, xOld, worksetCell, basis); // physTmp <- F(xOld)
272 rst::subtract(physTmp, physPoints, physTmp); // physTmp <- physPoints - F(xOld)
273
274 // l2 error (Euclidean distance) of the residual |physPoints - F(xOld)|
275 rst::extractScalarValues(xScalarTmp, physTmp);
276 rst::vectorNorm(errorPointwise, xScalarTmp, NORM_TWO);
277
278 error = 0;
279 Kokkos::parallel_reduce("MaxReduction", policy, FunctorType(errorPointwise), Kokkos::Max<errorType>(error));
280
281 if (error < tol*physInfNorm) {
282 converged = true;
283 if(isShell) { // update Jacobian so that it is consistent with xOld/refPoints
284 setJacobian(jacobian, xOld, worksetCell, basis);
285 }
286 break;
287 }
288
289 // Jacobians at the old iterates and their inverses.
290 setJacobian(jacobian, xOld, worksetCell, basis);
291
292 if(refDim < physDim) {
293 rst::matvec(xTmp, jacobian, physTmp, true); // xTmp <- DF^{T}( physPoints - F(xOld) ))
294 rst::AtA(metric,jacobian);
295 setJacobianInv(jacobianInv, metric);
296 rst::matvec(refPts, jacobianInv, xTmp); // refPoints <- (DF^{T} DF)^{-1} DF^{T}( physPoints - F(xOld) )
297 }
298 else {
299 setJacobianInv(jacobianInv, jacobian);
300 rst::matvec(refPts, jacobianInv, physTmp); // refPoints <- DF^{-1}( physPoints - F(xOld) )
301 }
302
303 // extract values
304 rst::extractScalarValues(Kokkos::subdynrankview(xScalarTmp, Kokkos::ALL(), Kokkos::ALL(), refDimRange), refPts);
305
306 rst::add(refPts, xOld); // refPoints <- refPoints + xOld
307
308
309 error = 0;
310 // l2 error (Euclidean distance) between old and new iterates: |xOld - xNew|
311 rst::vectorNorm(errorPointwise, Kokkos::subdynrankview(xScalarTmp, Kokkos::ALL(), Kokkos::ALL(), refDimRange), NORM_TWO);
312 Kokkos::parallel_reduce("MaxReduction", policy, FunctorType(errorPointwise), Kokkos::Max<errorType>(error));
313
314 // Stopping criterion:
315 if (error < tol) {
316 converged = true;
317 if(isShell) { //update Jacobian and residual so that they are consistent with refPts
318 setJacobian(jacobian, refPts, worksetCell, basis);
319 mapToPhysicalFrame(physTmp, refPts, worksetCell, basis); // physTmp <- F(refPts)
320 rst::subtract(physTmp, physPoints, physTmp); // physTmp <- physPoints - F(refPts)
321 }
322 break;
323 }
324
325 // initialize next Newton step ( this is not device friendly )
326 Kokkos::deep_copy(xOld, refPts);
327 }
328
329 if(isShell) {
330 //for shell elements, we can reconstruct the orthogonal reference component by approximating the
331 //signed distance between the physical point and the map to physical space of the reference line (in 2d) or triangle,quad (in 3d),
332 //and dividing it by the shell half thickness. We do so by solving
333 //(physPoints - F(xOld)) * n /|n|^2 / (H/2)
334 //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)
335 scaledResidualNormalComponent(
336 Kokkos::subdynrankview(refPoints,Kokkos::ALL(), Kokkos::ALL(), refDim),
337 jacobian,
338 physTmp,
339 2.0/shellThickness);
340 }
341
342 return converged;
343 }
344
345
346 template<typename DeviceType>
347 template<typename refPointValueType, class ...refPointProperties,
348 typename initGuessValueType, class ...initGuessProperties,
349 typename physPointValueType, class ...physPointProperties,
350 typename worksetCellValueType, class ...worksetCellProperties>
351 bool
353 mapToReferenceFrameInitGuess( Kokkos::DynRankView<refPointValueType,refPointProperties...> refPoints,
354 const Kokkos::DynRankView<initGuessValueType,initGuessProperties...> initGuess,
355 const Kokkos::DynRankView<physPointValueType,physPointProperties...> physPoints,
356 const Kokkos::DynRankView<worksetCellValueType,worksetCellProperties...> worksetCell,
357 const shards::CellTopology cellTopo,
358 const physPointValueType shellThickness) {
359
360 #ifdef HAVE_INTREPID2_DEBUG
361 CellTools_mapToReferenceFrameInitGuessArgs(refPoints, initGuess, physPoints, worksetCell, cellTopo);
362 #endif
363
364 Kokkos::deep_copy(refPoints,initGuess);
365 auto basis = createHGradBasis<refPointValueType,refPointValueType>(cellTopo);
366 return mapToReferenceFrame(refPoints,
367 physPoints,
368 worksetCell,
369 basis,
370 shellThickness);
371 }
372
373}
374
375#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...