Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #include "SamplerBase.h" 11 : 12 : // MOOSE includes 13 : #include "IndirectSort.h" 14 : #include "InputParameters.h" 15 : #include "MooseEnum.h" 16 : #include "MooseError.h" 17 : #include "VectorPostprocessor.h" 18 : #include "MooseVariableFieldBase.h" 19 : #include "MooseBaseParameterInterface.h" 20 : 21 : #include "libmesh/point.h" 22 : 23 : InputParameters 24 131636 : SamplerBase::validParams() 25 : { 26 131636 : InputParameters params = emptyInputParameters(); 27 : 28 131636 : MooseEnum sort_options("x y z id"); 29 131636 : params.addRequiredParam<MooseEnum>("sort_by", sort_options, "What to sort the samples by"); 30 : 31 : // The value from this VPP is naturally already on every processor 32 : // TODO: Make this not the case! See #11415 33 131636 : params.set<bool>("_auto_broadcast") = false; 34 : 35 263272 : return params; 36 131636 : } 37 : 38 1650 : SamplerBase::SamplerBase(const InputParameters & parameters, 39 : VectorPostprocessor * vpp, 40 1650 : const libMesh::Parallel::Communicator & comm) 41 1650 : : _sampler_params(parameters), 42 1650 : _vpp(vpp), 43 1650 : _comm(comm), 44 1650 : _sort_by(parameters.get<MooseEnum>("sort_by")), 45 1650 : _x(vpp->declareVector("x")), 46 1650 : _y(vpp->declareVector("y")), 47 1650 : _z(vpp->declareVector("z")), 48 3300 : _id(vpp->declareVector("id")) 49 : { 50 1650 : } 51 : 52 : void 53 1626 : SamplerBase::setupVariables(const std::vector<std::string> & variable_names) 54 : { 55 1626 : _variable_names = variable_names; 56 1626 : _values.reserve(variable_names.size()); 57 : 58 3835 : for (const auto & variable_name : variable_names) 59 2209 : _values.push_back(&_vpp->declareVector(variable_name)); 60 1626 : } 61 : 62 : void 63 209508 : SamplerBase::addSample(const Point & p, const Real & id, const std::vector<Real> & values) 64 : { 65 209508 : _x.push_back(p(0)); 66 209508 : _y.push_back(p(1)); 67 209508 : _z.push_back(p(2)); 68 : 69 209508 : _id.push_back(id); 70 : 71 : mooseAssert(values.size() == _variable_names.size(), "Mismatch of variable names to vector size"); 72 424501 : for (MooseIndex(values) i = 0; i < values.size(); ++i) 73 214993 : _values[i]->emplace_back(values[i]); 74 209508 : } 75 : 76 : void 77 13009 : SamplerBase::initialize() 78 : { 79 : // Don't reset the vectors if we want to retain history 80 13009 : if (_vpp->containsCompleteHistory() && _comm.rank() == 0) 81 400 : return; 82 : 83 12609 : _x.clear(); 84 12609 : _y.clear(); 85 12609 : _z.clear(); 86 12609 : _id.clear(); 87 : 88 12609 : std::for_each( 89 13934 : _values.begin(), _values.end(), [](VectorPostprocessorValue * vec) { vec->clear(); }); 90 : } 91 : 92 : void 93 1819 : SamplerBase::checkForStandardFieldVariableType(const MooseVariableFieldBase * const var_ptr, 94 : const std::string & var_param_name) const 95 : { 96 : // A pointer to a MooseVariableFieldBase should never be SCALAR 97 : mooseAssert(var_ptr->feType().family != SCALAR, 98 : "Scalar variable '" + var_ptr->name() + "' cannot be sampled."); 99 : mooseAssert(dynamic_cast<const MooseObject *>(_vpp), "Should have succeeded"); 100 1819 : if (var_ptr->isVector()) 101 16 : dynamic_cast<const MooseObject *>(_vpp)->paramError( 102 : var_param_name, 103 : "The variable '", 104 8 : var_ptr->name(), 105 : "' is a vector variable. Sampling those is not currently supported in the " 106 : "framework. It may be supported using a dedicated object in your application. Use " 107 : "'VectorVariableComponentAux' auxkernel to copy those values into a regular field " 108 : "variable"); 109 1811 : if (var_ptr->isArray()) 110 16 : dynamic_cast<const MooseObject *>(_vpp)->paramError( 111 : var_param_name, 112 : "The variable '", 113 8 : var_ptr->name(), 114 : "' is an array variable. Sampling those is not currently supported in the " 115 : "framework. It may be supported using a dedicated object in your application. Use " 116 : "'ArrayVariableComponent' auxkernel to copy those values into a regular field variable"); 117 1803 : } 118 : 119 : void 120 8733 : SamplerBase::finalize() 121 : { 122 : /** 123 : * We have several vectors that all need to be processed in the same way. 124 : * Rather than enumerate them all, let's just create a vector of pointers 125 : * and work on them that way. 126 : */ 127 8733 : constexpr auto NUM_ID_VECTORS = 4; 128 : 129 8733 : std::vector<VectorPostprocessorValue *> vec_ptrs; 130 8733 : vec_ptrs.reserve(_values.size() + NUM_ID_VECTORS); 131 : // Initialize the pointer vector with the position and ID vectors 132 8733 : vec_ptrs = {{&_x, &_y, &_z, &_id}}; 133 : // Now extend the vector by all the remaining values vector before processing 134 8733 : vec_ptrs.insert(vec_ptrs.end(), _values.begin(), _values.end()); 135 : 136 : // Gather up each of the partial vectors 137 53165 : for (auto vec_ptr : vec_ptrs) 138 44432 : _comm.allgather(*vec_ptr, /* identical buffer lengths = */ false); 139 : 140 : // Now create an index vector by using an indirect sort 141 8733 : std::vector<std::size_t> sorted_indices; 142 8733 : Moose::indirectSort(vec_ptrs[_sort_by]->begin(), vec_ptrs[_sort_by]->end(), sorted_indices); 143 : 144 : /** 145 : * We now have one sorted vector. The remaining vectors need to be sorted according to that 146 : * vector. 147 : * We'll need a temporary vector to hold values as we map them according to the sorted indices. 148 : * After that, we'll swap the vector contents with the sorted vector to get the values 149 : * back into the original vector. 150 : */ 151 : // This vector is used as temp storage to sort each of the remaining vectors according to the 152 : // first 153 8733 : auto vector_length = sorted_indices.size(); 154 8733 : VectorPostprocessorValue tmp_vector(vector_length); 155 : 156 : #ifndef NDEBUG 157 : for (const auto vec_ptr : vec_ptrs) 158 : if (vec_ptr->size() != vector_length) 159 : mooseError("Vector length mismatch"); 160 : #endif 161 : 162 : // Sort each of the vectors using the same sorted indices 163 53165 : for (auto & vec_ptr : vec_ptrs) 164 : { 165 1517888 : for (MooseIndex(sorted_indices) j = 0; j < sorted_indices.size(); ++j) 166 1473456 : tmp_vector[j] = (*vec_ptr)[sorted_indices[j]]; 167 : 168 : // Swap vector storage with sorted vector 169 44432 : vec_ptr->swap(tmp_vector); 170 : } 171 8733 : } 172 : 173 : void 174 417 : SamplerBase::threadJoin(const SamplerBase & y) 175 : { 176 417 : _x.insert(_x.end(), y._x.begin(), y._x.end()); 177 417 : _y.insert(_y.end(), y._y.begin(), y._y.end()); 178 417 : _z.insert(_z.end(), y._z.begin(), y._z.end()); 179 : 180 417 : _id.insert(_id.end(), y._id.begin(), y._id.end()); 181 : 182 840 : for (MooseIndex(_variable_names) i = 0; i < _variable_names.size(); i++) 183 423 : _values[i]->insert(_values[i]->end(), y._values[i]->begin(), y._values[i]->end()); 184 417 : }