Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_ScatterDirichletResidual_Tpetra_impl.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Panzer: A partial differential equation assembly
4// engine for strongly coupled complex multiphysics systems
5//
6// Copyright 2011 NTESS and the Panzer contributors.
7// SPDX-License-Identifier: BSD-3-Clause
8// *****************************************************************************
9// @HEADER
10
11#ifndef PANZER_SCATTER_DIRICHLET_RESIDUAL_TPETRA_IMPL_HPP
12#define PANZER_SCATTER_DIRICHLET_RESIDUAL_TPETRA_IMPL_HPP
13
14#include "Teuchos_RCP.hpp"
15#include "Teuchos_Assert.hpp"
16
17#include "Phalanx_DataLayout.hpp"
18
20#include "Panzer_PureBasis.hpp"
25
26#include "Phalanx_DataLayout_MDALayout.hpp"
27
28#include "Teuchos_FancyOStream.hpp"
29
30// **********************************************************************
31// Specialization: Residual
32// **********************************************************************
33
34
35template<typename TRAITS,typename LO,typename GO,typename NodeT>
37ScatterDirichletResidual_Tpetra(const Teuchos::RCP<const GlobalIndexer> & indexer,
38 const Teuchos::ParameterList& p)
39 : globalIndexer_(indexer)
40 , globalDataKey_("Residual Scatter Container")
41{
42 std::string scatterName = p.get<std::string>("Scatter Name");
43 scatterHolder_ =
44 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
45
46 // get names to be evaluated
47 const std::vector<std::string>& names =
48 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
49
50 // grab map from evaluated names to field names
51 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
52
53 // determine if we are scattering an initial condition
54 scatterIC_ = p.isParameter("Scatter Initial Condition") ? p.get<bool>("Scatter Initial Condition") : false;
55
56 Teuchos::RCP<PHX::DataLayout> dl = (!scatterIC_) ?
57 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional :
58 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional ;
59 if (!scatterIC_) {
60 side_subcell_dim_ = p.get<int>("Side Subcell Dimension");
61 local_side_id_ = p.get<int>("Local Side ID");
62 scratch_basisIds_.resize(names.size());
63 }
64
65 // build the vector of fields that this is dependent on
66 scatterFields_.resize(names.size());
67 scratch_offsets_.resize(names.size());
68 for (std::size_t eq = 0; eq < names.size(); ++eq) {
69 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
70
71 // tell the field manager that we depend on this field
72 this->addDependentField(scatterFields_[eq]);
73 }
74
75 checkApplyBC_ = p.isParameter("Check Apply BC") ? p.get<bool>("Check Apply BC") : false;
76 if (checkApplyBC_) {
77 applyBC_.resize(names.size());
78 for (std::size_t eq = 0; eq < names.size(); ++eq) {
79 applyBC_[eq] = PHX::MDField<const bool,Cell,NODE>(std::string("APPLY_BC_")+fieldMap_->find(names[eq])->second,dl);
80 this->addDependentField(applyBC_[eq]);
81 }
82 }
83
84 // this is what this evaluator provides
85 this->addEvaluatedField(*scatterHolder_);
86
87 if (p.isType<std::string>("Global Data Key"))
88 globalDataKey_ = p.get<std::string>("Global Data Key");
89
90 this->setName(scatterName+" Scatter Residual");
91}
92
93// **********************************************************************
94template<typename TRAITS,typename LO,typename GO,typename NodeT>
96postRegistrationSetup(typename TRAITS::SetupData d,
98{
99 fieldIds_.resize(scatterFields_.size());
100 const Workset & workset_0 = (*d.worksets_)[0];
101 std::string blockId = this->wda(workset_0).block_id;
102
103 // load required field numbers for fast use
104 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
105 // get field ID from DOF manager
106 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
107 fieldIds_[fd] = globalIndexer_->getFieldNum(fieldName);
108
109 if (!scatterIC_) {
110 const std::pair<std::vector<int>,std::vector<int> > & indicePair
111 = globalIndexer_->getGIDFieldOffsets_closure(blockId,fieldIds_[fd], side_subcell_dim_, local_side_id_);
112 const std::vector<int> & offsets = indicePair.first;
113 const std::vector<int> & basisIdMap = indicePair.second;
114
115 scratch_offsets_[fd] = PHX::View<int*>("offsets",offsets.size());
116 Kokkos::deep_copy(scratch_offsets_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(offsets.data(), offsets.size()));
117
118 scratch_basisIds_[fd] = PHX::View<int*>("basisIds",basisIdMap.size());
119 Kokkos::deep_copy(scratch_basisIds_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(basisIdMap.data(), basisIdMap.size()));
120
121 } else {
122 const std::vector<int> & offsets = globalIndexer_->getGIDFieldOffsets(blockId,fieldIds_[fd]);
123 scratch_offsets_[fd] = PHX::View<int*>("offsets",offsets.size());
124 Kokkos::deep_copy(scratch_offsets_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(offsets.data(), offsets.size()));
125 }
126 }
127
128 scratch_lids_ = PHX::View<LO**>("lids",scatterFields_[0].extent(0),
129 globalIndexer_->getElementBlockGIDCount(blockId));
130}
131
132// **********************************************************************
133template<typename TRAITS,typename LO,typename GO,typename NodeT>
135preEvaluate(typename TRAITS::PreEvalData d)
136{
137 // extract linear object container
138 tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject(globalDataKey_));
139
140 if(tpetraContainer_==Teuchos::null) {
141 // extract linear object container
142 Teuchos::RCP<LinearObjContainer> loc = Teuchos::rcp_dynamic_cast<LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true)->getGhostedLOC();
143 tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(loc);
144
145 dirichletCounter_ = Teuchos::null;
146 }
147 else {
148 // extract dirichlet counter from container
149 Teuchos::RCP<LOC> tpetraContainer
150 = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject("Dirichlet Counter"),true);
151
152 dirichletCounter_ = tpetraContainer->get_f_mv();
153 TEUCHOS_ASSERT(!Teuchos::is_null(dirichletCounter_));
154 }
155}
156
157// **********************************************************************
158namespace panzer {
159namespace {
160
161template <typename ScalarT,typename LO,typename GO,typename NodeT>
162class ScatterDirichletResidual_Residual_Functor {
163public:
164 typedef typename PHX::Device execution_space;
165 typedef PHX::MDField<const ScalarT,Cell,NODE> ScalarFieldType;
166 typedef PHX::MDField<const bool,Cell,NODE> BoolFieldType;
167
168 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> r_data;
169 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> dirichlet_counter;
170
171 PHX::View<const LO**> lids; // local indices for unknowns
172 PHX::View<const int*> offsets; // how to get a particular field
173 PHX::View<const int*> basisIds;
174 ScalarFieldType field;
175 BoolFieldType applyBC;
176
178
179 KOKKOS_INLINE_FUNCTION
180 void operator()(const unsigned int cell) const
181 {
182
183 // loop over the basis functions (currently they are nodes)
184 for(std::size_t basis=0; basis < offsets.extent(0); basis++) {
185 int offset = offsets(basis);
186 LO lid = lids(cell,offset);
187 if (lid<0) continue; // not on this processor
188
189 int basisId = basisIds(basis);
190 if (checkApplyBC)
191 if(!applyBC(cell,basisId)) continue;
192
193 r_data(lid,0) = field(cell,basisId);
194
195 // record that you set a dirichlet condition
196 if (dirichlet_counter.extent(0) > 0)
197 dirichlet_counter(lid,0) = 1.0;
198
199 } // end basis
200 }
201};
202
203template <typename ScalarT,typename LO,typename GO,typename NodeT>
204class ScatterDirichletResidualIC_Residual_Functor {
205public:
206 typedef typename PHX::Device execution_space;
207 typedef PHX::MDField<const ScalarT,Cell,NODE> FieldType;
208
209 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> r_data;
210 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> dirichlet_counter;
211
212 PHX::View<const LO**> lids; // local indices for unknowns
213 PHX::View<const int*> offsets; // how to get a particular field
215
216 KOKKOS_INLINE_FUNCTION
217 void operator()(const unsigned int cell) const
218 {
219
220 // loop over the basis functions (currently they are nodes)
221 for(std::size_t basis=0; basis < offsets.extent(0); basis++) {
222 int offset = offsets(basis);
223 LO lid = lids(cell,offset);
224 if (lid<0) continue; // not on this processor
225
226 r_data(lid,0) = field(cell,basis);
227
228 // record that you set a dirichlet condition
229 if (dirichlet_counter.extent(0) > 0)
230 dirichlet_counter(lid,0) = 1.0;
231
232 } // end basis
233 }
234};
235}
236}
237
238// **********************************************************************
239template<typename TRAITS,typename LO,typename GO,typename NodeT>
241evaluateFields(typename TRAITS::EvalData workset)
242{
243 std::vector<GO> GIDs;
244 std::vector<LO> LIDs;
245
246 // for convenience pull out some objects from workset
247 std::string blockId = this->wda(workset).block_id;
248
249 globalIndexer_->getElementLIDs(this->wda(workset).cell_local_ids_k,scratch_lids_);
250
251 Teuchos::RCP<typename LOC::MultiVectorType> r = (!scatterIC_) ?
252 tpetraContainer_->get_f_mv() :
253 tpetraContainer_->get_x_mv();
254
255 if (scatterIC_) {
256 ScatterDirichletResidualIC_Residual_Functor<ScalarT,LO,GO,NodeT> functor;
257 functor.r_data = r->getLocalViewDevice(Tpetra::Access::ReadWrite);
258 functor.lids = scratch_lids_;
259 if (dirichletCounter_ != Teuchos::null)
260 functor.dirichlet_counter = dirichletCounter_->getLocalViewDevice(Tpetra::Access::ReadWrite);
261
262 // for each field, do a parallel for loop
263 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
264 functor.offsets = scratch_offsets_[fieldIndex];
265 functor.field = scatterFields_[fieldIndex];
266
267 Kokkos::parallel_for(workset.num_cells,functor);
268 }
269 } else {
270 ScatterDirichletResidual_Residual_Functor<ScalarT,LO,GO,NodeT> functor;
271 functor.r_data = r->getLocalViewDevice(Tpetra::Access::ReadWrite);
272 functor.lids = scratch_lids_;
273 if (dirichletCounter_ != Teuchos::null)
274 functor.dirichlet_counter = dirichletCounter_->getLocalViewDevice(Tpetra::Access::ReadWrite);
275
276 // for each field, do a parallel for loop
277 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
278 functor.offsets = scratch_offsets_[fieldIndex];
279 functor.field = scatterFields_[fieldIndex];
280 if (checkApplyBC_) functor.applyBC = applyBC_[fieldIndex];
281 functor.checkApplyBC = checkApplyBC_;
282 functor.basisIds = scratch_basisIds_[fieldIndex];
283
284 Kokkos::parallel_for(workset.num_cells,functor);
285 }
286 }
287
288}
289
290// **********************************************************************
291// Specialization: Tangent
292// **********************************************************************
293
294
295template<typename TRAITS,typename LO,typename GO,typename NodeT>
297ScatterDirichletResidual_Tpetra(const Teuchos::RCP<const GlobalIndexer> & indexer,
298 const Teuchos::ParameterList& p)
299 : globalIndexer_(indexer)
300 , globalDataKey_("Residual Scatter Container")
301{
302 std::string scatterName = p.get<std::string>("Scatter Name");
303 scatterHolder_ =
304 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
305
306 // get names to be evaluated
307 const std::vector<std::string>& names =
308 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
309
310 // grab map from evaluated names to field names
311 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
312
313 // determine if we are scattering an initial condition
314 scatterIC_ = p.isParameter("Scatter Initial Condition") ? p.get<bool>("Scatter Initial Condition") : false;
315
316 Teuchos::RCP<PHX::DataLayout> dl = (!scatterIC_) ?
317 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional :
318 p.get< Teuchos::RCP<const panzer::PureBasis> >("Basis")->functional ;
319 if (!scatterIC_) {
320 side_subcell_dim_ = p.get<int>("Side Subcell Dimension");
321 local_side_id_ = p.get<int>("Local Side ID");
322 scratch_basisIds_.resize(names.size());
323 }
324
325 // build the vector of fields that this is dependent on
326 scatterFields_.resize(names.size());
327 scratch_offsets_.resize(names.size());
328 for (std::size_t eq = 0; eq < names.size(); ++eq) {
329 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
330
331 // tell the field manager that we depend on this field
332 this->addDependentField(scatterFields_[eq]);
333 }
334
335 checkApplyBC_ = p.isParameter("Check Apply BC") ? p.get<bool>("Check Apply BC") : false;
336 if (checkApplyBC_) {
337 applyBC_.resize(names.size());
338 for (std::size_t eq = 0; eq < names.size(); ++eq) {
339 applyBC_[eq] = PHX::MDField<const bool,Cell,NODE>(std::string("APPLY_BC_")+fieldMap_->find(names[eq])->second,dl);
340 this->addDependentField(applyBC_[eq]);
341 }
342 }
343
344 // this is what this evaluator provides
345 this->addEvaluatedField(*scatterHolder_);
346
347 if (p.isType<std::string>("Global Data Key"))
348 globalDataKey_ = p.get<std::string>("Global Data Key");
349
350 this->setName(scatterName+" Scatter Tangent");
351}
352
353// **********************************************************************
354template<typename TRAITS,typename LO,typename GO,typename NodeT>
356postRegistrationSetup(typename TRAITS::SetupData d,
358{
359 fieldIds_.resize(scatterFields_.size());
360 const Workset & workset_0 = (*d.worksets_)[0];
361 std::string blockId = this->wda(workset_0).block_id;
362
363 // load required field numbers for fast use
364 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
365 // get field ID from DOF manager
366 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
367 fieldIds_[fd] = globalIndexer_->getFieldNum(fieldName);
368
369 if (!scatterIC_) {
370 const std::pair<std::vector<int>,std::vector<int> > & indicePair
371 = globalIndexer_->getGIDFieldOffsets_closure(blockId,fieldIds_[fd], side_subcell_dim_, local_side_id_);
372 const std::vector<int> & offsets = indicePair.first;
373 const std::vector<int> & basisIdMap = indicePair.second;
374
375 scratch_offsets_[fd] = PHX::View<int*>("offsets",offsets.size());
376 Kokkos::deep_copy(scratch_offsets_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(offsets.data(), offsets.size()));
377
378 scratch_basisIds_[fd] = PHX::View<int*>("basisIds",basisIdMap.size());
379 Kokkos::deep_copy(scratch_basisIds_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(basisIdMap.data(), basisIdMap.size()));
380
381 } else {
382 const std::vector<int> & offsets = globalIndexer_->getGIDFieldOffsets(blockId,fieldIds_[fd]);
383 scratch_offsets_[fd] = PHX::View<int*>("offsets",offsets.size());
384 Kokkos::deep_copy(scratch_offsets_[fd], Kokkos::View<const int*, Kokkos::HostSpace, Kokkos::MemoryUnmanaged>(offsets.data(), offsets.size()));
385 }
386 }
387
388 scratch_lids_ = PHX::View<LO**>("lids",scatterFields_[0].extent(0),
389 globalIndexer_->getElementBlockGIDCount(blockId));
390
391}
392
393// **********************************************************************
394template<typename TRAITS,typename LO,typename GO,typename NodeT>
396preEvaluate(typename TRAITS::PreEvalData d)
397{
398 // extract linear object container
399 tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject(globalDataKey_));
400
401 if(tpetraContainer_==Teuchos::null) {
402 // extract linear object container
403 Teuchos::RCP<LinearObjContainer> loc = Teuchos::rcp_dynamic_cast<LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true)->getGhostedLOC();
404 tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(loc);
405
406 dirichletCounter_ = Teuchos::null;
407 }
408 else {
409 // extract dirichlet counter from container
410 Teuchos::RCP<LOC> tpetraContainer
411 = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject("Dirichlet Counter"),true);
412
413 dirichletCounter_ = tpetraContainer->get_f_mv();
414 TEUCHOS_ASSERT(!Teuchos::is_null(dirichletCounter_));
415 }
416
417 using Teuchos::RCP;
418 using Teuchos::rcp_dynamic_cast;
419
420 // this is the list of parameters and their names that this scatter has to account for
421 std::vector<std::string> activeParameters =
422 rcp_dynamic_cast<ParameterList_GlobalEvaluationData>(d.gedc->getDataObject("PARAMETER_NAMES"))->getActiveParameters();
423
424 // Only the outer view is allocated here. The device views of the df/dp
425 // vectors are acquired and released in evaluateFields().
426 dfdpFieldsVoV_.initialize("ScatterResidual_Tpetra<Tangent>::dfdpFieldsVoV_",activeParameters.size());
427
428 dfdpVectors_.resize(activeParameters.size());
429 for(std::size_t i=0;i<activeParameters.size();i++)
430 dfdpVectors_[i] = rcp_dynamic_cast<LOC>(d.gedc->getDataObject(activeParameters[i]),true)->get_f_mv();
431
432}
433
434// **********************************************************************
435namespace panzer {
436namespace {
437
438template <typename ScalarT,typename LO,typename GO,typename NodeT>
439class ScatterDirichletResidual_Tangent_Functor {
440public:
441 typedef typename PHX::Device execution_space;
442 typedef PHX::MDField<const ScalarT,Cell,NODE> ScalarFieldType;
443 typedef PHX::MDField<const bool,Cell,NODE> BoolFieldType;
444
445 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> r_data;
446 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> dirichlet_counter;
447
448 Kokkos::View<Kokkos::View<double**,Kokkos::LayoutLeft,PHX::Device>*> dfdp_fields; // tangent fields
449 std::size_t num_params;
450
451 PHX::View<const LO**> lids; // local indices for unknowns
452 PHX::View<const int*> offsets; // how to get a particular field
453 PHX::View<const int*> basisIds;
454 ScalarFieldType field;
455 BoolFieldType applyBC;
456
457 bool checkApplyBC;
458
459 KOKKOS_INLINE_FUNCTION
460 void operator()(const unsigned int cell) const
461 {
462
463 // loop over the basis functions (currently they are nodes)
464 for(std::size_t basis=0; basis < offsets.extent(0); basis++) {
465 int offset = offsets(basis);
466 LO lid = lids(cell,offset);
467 if (lid<0) continue; // not on this processor
468
469 int basisId = basisIds(basis);
470 if (checkApplyBC)
471 if(!applyBC(cell,basisId)) continue;
472
473 r_data(lid,0) = field(cell,basisId).val();
474
475 // loop over the tangents
476 for(std::size_t i_param=0; i_param<num_params; i_param++)
477 dfdp_fields(i_param)(lid,0) = field(cell,basisId).fastAccessDx(i_param);
478
479 // record that you set a dirichlet condition
480 if (dirichlet_counter.extent(0) > 0)
481 dirichlet_counter(lid,0) = 1.0;
482
483 } // end basis
484 }
485};
486
487template <typename ScalarT,typename LO,typename GO,typename NodeT>
488class ScatterDirichletResidualIC_Tangent_Functor {
489public:
490 typedef typename PHX::Device execution_space;
491 typedef PHX::MDField<const ScalarT,Cell,NODE> FieldType;
492
493 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> r_data;
494 Kokkos::View<double**, Kokkos::LayoutLeft,PHX::Device> dirichlet_counter;
495
496 Kokkos::View<Kokkos::View<double**,Kokkos::LayoutLeft,PHX::Device>*> dfdp_fields; // tangent fields
497 std::size_t num_params;
498
499 PHX::View<const LO**> lids; // local indices for unknowns
500 PHX::View<const int*> offsets; // how to get a particular field
502
503 KOKKOS_INLINE_FUNCTION
504 void operator()(const unsigned int cell) const
505 {
506
507 // loop over the basis functions (currently they are nodes)
508 for(std::size_t basis=0; basis < offsets.extent(0); basis++) {
509 int offset = offsets(basis);
510 LO lid = lids(cell,offset);
511 if (lid<0) continue; // not on this processor
512
513 r_data(lid,0) = field(cell,basis).val();
514
515 // loop over the tangents
516 for(std::size_t i_param=0; i_param<num_params; i_param++)
517 dfdp_fields(i_param)(lid,0) = field(cell,basis).fastAccessDx(i_param);
518
519 // record that you set a dirichlet condition
520 if (dirichlet_counter.extent(0) > 0)
521 dirichlet_counter(lid,0) = 1.0;
522
523 } // end basis
524 }
525};
526}
527}
528
529// **********************************************************************
530template<typename TRAITS,typename LO,typename GO,typename NodeT>
532evaluateFields(typename TRAITS::EvalData workset)
533{
534 std::vector<GO> GIDs;
535 std::vector<LO> LIDs;
536
537 // for convenience pull out some objects from workset
538 std::string blockId = this->wda(workset).block_id;
539
540 globalIndexer_->getElementLIDs(this->wda(workset).cell_local_ids_k,scratch_lids_);
541
542 Teuchos::RCP<typename LOC::MultiVectorType> r = (!scatterIC_) ?
543 tpetraContainer_->get_f_mv() :
544 tpetraContainer_->get_x_mv();
545
546 // Acquire the df/dp device views for the duration of this method only. See
547 // the release loop at the end of this method.
548 for(std::size_t i=0;i<dfdpVectors_.size();i++)
549 dfdpFieldsVoV_.addView(dfdpVectors_[i]->getLocalViewDevice(Tpetra::Access::ReadWrite),i);
550 dfdpFieldsVoV_.syncHostToDevice();
551
552 if (scatterIC_) {
553 ScatterDirichletResidualIC_Tangent_Functor<ScalarT,LO,GO,NodeT> functor;
554 functor.r_data = r->getLocalViewDevice(Tpetra::Access::ReadWrite);
555 functor.lids = scratch_lids_;
556 if (dirichletCounter_ != Teuchos::null)
557 functor.dirichlet_counter = dirichletCounter_->getLocalViewDevice(Tpetra::Access::ReadWrite);
558 functor.dfdp_fields = dfdpFieldsVoV_.getViewDevice();
559
560 // for each field, do a parallel for loop
561 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
562 functor.offsets = scratch_offsets_[fieldIndex];
563 functor.field = scatterFields_[fieldIndex];
564 functor.num_params = Sacado::dimension_scalar(scatterFields_[fieldIndex].get_view())-1;
565
566 Kokkos::parallel_for(workset.num_cells,functor);
567 }
568 } else {
569 ScatterDirichletResidual_Tangent_Functor<ScalarT,LO,GO,NodeT> functor;
570 functor.r_data = r->getLocalViewDevice(Tpetra::Access::ReadWrite);
571 functor.lids = scratch_lids_;
572 if (dirichletCounter_ != Teuchos::null)
573 functor.dirichlet_counter = dirichletCounter_->getLocalViewDevice(Tpetra::Access::ReadWrite);
574 functor.dfdp_fields = dfdpFieldsVoV_.getViewDevice();
575
576 // for each field, do a parallel for loop
577 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
578 functor.offsets = scratch_offsets_[fieldIndex];
579 functor.field = scatterFields_[fieldIndex];
580 if (checkApplyBC_) functor.applyBC = applyBC_[fieldIndex];
581 functor.checkApplyBC = checkApplyBC_;
582 functor.basisIds = scratch_basisIds_[fieldIndex];
583 functor.num_params = Sacado::dimension_scalar(scatterFields_[fieldIndex].get_view())-1;
584
585 Kokkos::parallel_for(workset.num_cells,functor);
586 }
587 }
588
589 // Release the df/dp device views. Holding a device view past the return of
590 // this method makes any subsequent host access to the same vector throw, e.g.
591 // AssemblyEngine::evaluateDirichletBCs() -> adjustForDirichletConditions().
592 for(std::size_t i=0;i<dfdpVectors_.size();i++)
593 dfdpFieldsVoV_.addView(Kokkos::View<RealT**,Kokkos::LayoutLeft,PHX::Device>(),i);
594}
595
596// **********************************************************************
597// Specialization: Jacobian
598// **********************************************************************
599
600template<typename TRAITS,typename LO,typename GO,typename NodeT>
602ScatterDirichletResidual_Tpetra(const Teuchos::RCP<const GlobalIndexer> & indexer,
603 const Teuchos::ParameterList& p)
604 : globalIndexer_(indexer)
605 , globalDataKey_("Residual Scatter Container")
606{
607 std::string scatterName = p.get<std::string>("Scatter Name");
608 scatterHolder_ =
609 Teuchos::rcp(new PHX::Tag<ScalarT>(scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0))));
610
611 // get names to be evaluated
612 const std::vector<std::string>& names =
613 *(p.get< Teuchos::RCP< std::vector<std::string> > >("Dependent Names"));
614
615 // grab map from evaluated names to field names
616 fieldMap_ = p.get< Teuchos::RCP< std::map<std::string,std::string> > >("Dependent Map");
617
618 Teuchos::RCP<PHX::DataLayout> dl =
619 p.get< Teuchos::RCP<panzer::PureBasis> >("Basis")->functional;
620
621 side_subcell_dim_ = p.get<int>("Side Subcell Dimension");
622 local_side_id_ = p.get<int>("Local Side ID");
623
624 // build the vector of fields that this is dependent on
625 scatterFields_.resize(names.size());
626 for (std::size_t eq = 0; eq < names.size(); ++eq) {
627 scatterFields_[eq] = PHX::MDField<const ScalarT,Cell,NODE>(names[eq],dl);
628
629 // tell the field manager that we depend on this field
630 this->addDependentField(scatterFields_[eq]);
631 }
632
633 checkApplyBC_ = p.get<bool>("Check Apply BC");
634 if (checkApplyBC_) {
635 applyBC_.resize(names.size());
636 for (std::size_t eq = 0; eq < names.size(); ++eq) {
637 applyBC_[eq] = PHX::MDField<const bool,Cell,NODE>(std::string("APPLY_BC_")+fieldMap_->find(names[eq])->second,dl);
638 this->addDependentField(applyBC_[eq]);
639 }
640 }
641
642 // this is what this evaluator provides
643 this->addEvaluatedField(*scatterHolder_);
644
645 if (p.isType<std::string>("Global Data Key"))
646 globalDataKey_ = p.get<std::string>("Global Data Key");
647
648 this->setName(scatterName+" Scatter Residual (Jacobian)");
649}
650
651// **********************************************************************
652template<typename TRAITS,typename LO,typename GO,typename NodeT>
654postRegistrationSetup(typename TRAITS::SetupData /* d */,
656{
657 fieldIds_.resize(scatterFields_.size());
658 // load required field numbers for fast use
659 for(std::size_t fd=0;fd<scatterFields_.size();++fd) {
660 // get field ID from DOF manager
661 std::string fieldName = fieldMap_->find(scatterFields_[fd].fieldTag().name())->second;
662 fieldIds_[fd] = globalIndexer_->getFieldNum(fieldName);
663 }
664
665 // get the number of nodes (Should be renamed basis)
666 num_nodes = scatterFields_[0].extent(1);
667 num_eq = scatterFields_.size();
668}
669
670// **********************************************************************
671template<typename TRAITS,typename LO,typename GO,typename NodeT>
673preEvaluate(typename TRAITS::PreEvalData d)
674{
675 // extract linear object container
676 tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject(globalDataKey_));
677
678 if(tpetraContainer_==Teuchos::null) {
679 // extract linear object container
680 Teuchos::RCP<LinearObjContainer> loc = Teuchos::rcp_dynamic_cast<LOCPair_GlobalEvaluationData>(d.gedc->getDataObject(globalDataKey_),true)->getGhostedLOC();
681 tpetraContainer_ = Teuchos::rcp_dynamic_cast<LOC>(loc);
682
683 dirichletCounter_ = Teuchos::null;
684 }
685 else {
686 // extract dirichlet counter from container
687 Teuchos::RCP<LOC> tpetraContainer
688 = Teuchos::rcp_dynamic_cast<LOC>(d.gedc->getDataObject("Dirichlet Counter"),true);
689
690 dirichletCounter_ = tpetraContainer->get_f_mv();
691 TEUCHOS_ASSERT(!Teuchos::is_null(dirichletCounter_));
692 }
693}
694
695// **********************************************************************
696template<typename TRAITS,typename LO,typename GO,typename NodeT>
698evaluateFields(typename TRAITS::EvalData workset)
699{
700 std::vector<GO> GIDs;
701
702 // for convenience pull out some objects from workset
703 std::string blockId = this->wda(workset).block_id;
704 const std::vector<std::size_t> & localCellIds = this->wda(workset).cell_local_ids;
705
706 Teuchos::RCP<typename LOC::MultiVectorType> r = tpetraContainer_->get_f_mv();
707 Teuchos::RCP<typename LOC::CrsMatrixType> Jac = tpetraContainer_->get_A();
708
709 using HostView = typename LOC::MultiVectorType::host_view_type;
710 const bool haveResidual = Teuchos::nonnull(r);
711 const bool haveDirichletCounter = Teuchos::nonnull(dirichletCounter_);
712
713 HostView r_view;
714 if (haveResidual)
715 r_view = r->getLocalViewHost(Tpetra::Access::ReadWrite);
716 HostView dc_view;
717 if (haveDirichletCounter)
718 dc_view = dirichletCounter_->getLocalViewHost(Tpetra::Access::ReadWrite);
719
720 // Size the row scratch to the widest row in this matrix, once, so the
721 // scatter loop below allocates nothing. getLocalRowCopy() explicitly allows
722 // a buffer larger than the row it is asked for.
723 if (Jac != Teuchos::null) {
724 const std::size_t maxRowEntries = Jac->getLocalMaxNumRowEntries();
725 if (rowIndices_.extent(0) < maxRowEntries) {
726 rowIndices_ = typename LOC::CrsMatrixType::nonconst_local_inds_host_view_type("indices", maxRowEntries);
727 rowValues_ = typename LOC::CrsMatrixType::nonconst_values_host_view_type("values", maxRowEntries);
728 }
729 }
730
731 // NOTE: A reordering of these loops will likely improve performance
732 // The "getGIDFieldOffsets may be expensive. However the
733 // "getElementGIDs" can be cheaper. However the lookup for LIDs
734 // may be more expensive!
735
736 // scatter operation for each cell in workset
737 auto LIDs = globalIndexer_->getLIDs();
738 // Reuse the host copies below rather than allocating a mirror per call. The
739 // contents still have to be refreshed, but the buffers are only grown.
740 if constexpr (lidsAreHostResident_) {
741 // The mirror is the source view; aliasing it costs nothing and cannot go stale.
742 lids_h_ = Kokkos::create_mirror_view(Kokkos::HostSpace(),LIDs);
743 }
744 else {
745 if (lids_h_.extent(0) != LIDs.extent(0) || lids_h_.extent(1) != LIDs.extent(1))
746 lids_h_ = Kokkos::create_mirror_view(Kokkos::HostSpace(),LIDs);
747 Kokkos::deep_copy(lids_h_, LIDs);
748 }
749 auto& LIDs_h = lids_h_;
750
751 if (scatterFields_h_.size() != scatterFields_.size())
752 scatterFields_h_.resize(scatterFields_.size());
753 // loop over each field to be scattered
754 for(std::size_t fieldIndex = 0; fieldIndex < scatterFields_.size(); fieldIndex++) {
755 int fieldNum = fieldIds_[fieldIndex];
756 const auto scatterFieldsDevice = scatterFields_[fieldIndex].get_static_view();
757 if (scatterFields_h_[fieldIndex].extent(0) != scatterFieldsDevice.extent(0) ||
758 scatterFields_h_[fieldIndex].extent(1) != scatterFieldsDevice.extent(1))
759 scatterFields_h_[fieldIndex] = Kokkos::create_mirror_view(scatterFieldsDevice);
760 auto& scatterFields_h = scatterFields_h_[fieldIndex];
761 Kokkos::deep_copy(scatterFields_h, scatterFieldsDevice);
762 for(std::size_t worksetCellIndex=0;worksetCellIndex<localCellIds.size();++worksetCellIndex) {
763 std::size_t cellLocalId = localCellIds[worksetCellIndex];
764
765 globalIndexer_->getElementGIDs(cellLocalId,GIDs);
766
767 // this call "should" get the right ordering according to the Intrepid2 basis
768 const std::pair<std::vector<int>,std::vector<int> > & indicePair
769 = globalIndexer_->getGIDFieldOffsets_closure(blockId,fieldNum, side_subcell_dim_, local_side_id_);
770 const std::vector<int> & elmtOffset = indicePair.first;
771 const std::vector<int> & basisIdMap = indicePair.second;
772
773 // loop over basis functions
774 for(std::size_t basis=0;basis<elmtOffset.size();basis++) {
775 int offset = elmtOffset[basis];
776 int lid = LIDs_h(cellLocalId, offset);
777 if(lid<0) // not on this processor
778 continue;
779
780 int basisId = basisIdMap[basis];
781
782 if (checkApplyBC_)
783 if (!applyBC_[fieldIndex](worksetCellIndex,basisId))
784 continue;
785
786 // zero out matrix row
787 {
788 std::size_t numEntries = 0;
789
790 Jac->getLocalRowCopy(lid,rowIndices_,rowValues_,numEntries);
791
792 for(std::size_t i=0;i<numEntries;i++)
793 rowValues_(i) = 0.0;
794
795 // Only the first numEntries of the scratch belong to this row.
796 const auto rowRange = std::make_pair(std::size_t(0),numEntries);
797 Jac->replaceLocalValues(lid,
798 Kokkos::subview(rowIndices_,rowRange),
799 Kokkos::subview(rowValues_,rowRange));
800 }
801
802 GO gid = GIDs[offset];
803 const ScalarT scatterField = scatterFields_h(worksetCellIndex,basisId);
804
805 if (haveResidual)
806 r_view(lid,0) = scatterField.val();
807 if (haveDirichletCounter)
808 dc_view(lid,0) = 1.0; // mark row as dirichlet
809
810 // loop over the sensitivity indices: all DOFs on a cell
811 jacRow_.resize(scatterField.size());
812
813 for(int sensIndex=0;sensIndex<scatterField.size();++sensIndex)
814 jacRow_[sensIndex] = scatterField.fastAccessDx(sensIndex);
815 TEUCHOS_ASSERT(jacRow_.size()==GIDs.size());
816
817 Jac->replaceGlobalValues(gid, GIDs, jacRow_);
818 }
819 }
820 }
821}
822
823// **********************************************************************
824
825#endif
PHX::View< const int * > offsets
PHX::MDField< ScalarT, panzer::Cell, panzer::BASIS > field
A field to which we'll contribute, or in which we'll store, the result of computing this integral.
Kokkos::View< Kokkos::View< double **, Kokkos::LayoutLeft, PHX::Device > * > dfdp_fields
Kokkos::View< double **, Kokkos::LayoutLeft, PHX::Device > dirichlet_counter
PHX::View< const LO ** > lids
PHX::View< const int * > basisIds
Kokkos::View< double **, Kokkos::LayoutLeft, PHX::Device > r_data
Pushes residual values into the residual vector for a Newton-based solve.
std::string block_id
DEPRECATED - use: getElementBlock()
FieldType
The type of discretization to use for a field pattern.