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 : #pragma once 11 : 12 : // MOOSE includes 13 : #include "DistributionInterface.h" 14 : #include "FunctionInterface.h" 15 : #include "UserObjectInterface.h" 16 : #include "PostprocessorInterface.h" 17 : #include "VectorPostprocessorInterface.h" 18 : #include "ReporterInterface.h" 19 : #include "MeshChangedInterface.h" 20 : #include "MeshDisplacedInterface.h" 21 : #include "MooseObject.h" 22 : #include "MooseTypes.h" 23 : #include "Restartable.h" 24 : #include "MeshMetaDataInterface.h" 25 : #include "ScalarCoupleable.h" 26 : #include "SetupInterface.h" 27 : #include "PerfGraphInterface.h" 28 : #include "SamplerInterface.h" 29 : 30 : #include "libmesh/parallel.h" 31 : 32 : class FEProblemBase; 33 : class SubProblem; 34 : class Assembly; 35 : class SystemBase; 36 : 37 : /** 38 : * Base class for user-specific data 39 : */ 40 : class UserObject : public MooseObject, 41 : public SetupInterface, 42 : protected FunctionInterface, 43 : public UserObjectInterface, 44 : protected PostprocessorInterface, 45 : protected VectorPostprocessorInterface, 46 : protected ReporterInterface, 47 : protected DistributionInterface, 48 : protected SamplerInterface, 49 : protected Restartable, 50 : protected MeshMetaDataInterface, 51 : protected MeshChangedInterface, 52 : protected MeshDisplacedInterface, 53 : protected PerfGraphInterface, 54 : public DependencyResolverInterface 55 : { 56 : public: 57 : static InputParameters validParams(); 58 : 59 : UserObject(const InputParameters & params); 60 70266 : virtual ~UserObject() = default; 61 : 62 : /** 63 : * Execute method. 64 : */ 65 : virtual void execute() = 0; 66 : 67 : /** 68 : * Called before execute() is ever called so that data can be cleared. 69 : */ 70 : virtual void initialize() = 0; 71 : 72 : /** 73 : * Finalize. This is called _after_ execute() and _after_ threadJoin()! This is probably where 74 : * you want to do MPI communication! 75 : */ 76 : virtual void finalize() = 0; 77 : 78 : /** 79 : * Returns a reference to the subproblem that 80 : * this postprocessor is tied to 81 : */ 82 22 : SubProblem & getSubProblem() const { return _subproblem; } 83 : 84 : /** 85 : * Returns whether or not this user object should be executed twice during the initial condition 86 : * when depended upon by an IC. 87 : */ 88 : bool shouldDuplicateInitialExecution() const { return _duplicate_initial_execution; } 89 : 90 : /** 91 : * Optional interface function for "evaluating" a UserObject at a spatial position. 92 : * If a UserObject overrides this function that UserObject can then be used in a 93 : * Transfer to transfer information from one domain to another. 94 : */ 95 4 : virtual Real spatialValue(const Point & /*p*/) const 96 : { 97 4 : mooseError(name(), " does not satisfy the Spatial UserObject interface!"); 98 : } 99 : 100 : /** 101 : * Optional interface function for providing the points at which a UserObject attains 102 : * spatial values. If a UserObject overrides this function, then other objects that 103 : * take both the UserObject and points can instead directly use the points specified 104 : * on the UserObject. 105 : */ 106 0 : virtual const std::vector<Point> spatialPoints() const 107 : { 108 0 : mooseError("Spatial UserObject interface is not satisfied; spatialPoints() must be overridden"); 109 : } 110 : 111 : /** 112 : * Must override. 113 : * 114 : * @param uo The UserObject to be joined into _this_ object. Take the data from the uo object and 115 : * "add" it into the data for this object. 116 : */ 117 : virtual void threadJoin(const UserObject & uo) = 0; 118 : 119 : /** 120 : * Gather the parallel sum of the variable passed in. It takes care of values across all threads 121 : * and CPUs (we DO hybrid parallelism!) 122 : * 123 : * After calling this, the variable that was passed in will hold the gathered value. 124 : */ 125 : template <typename T> 126 424775 : void gatherSum(T & value) 127 : { 128 424775 : _communicator.sum(value); 129 424775 : } 130 : 131 : /** 132 : * Gather the parallel max of the variable passed in. It takes care of values across all threads 133 : * and CPUs (we DO hybrid parallelism!) 134 : * 135 : * After calling this, the variable that was passed in will hold the gathered value. 136 : */ 137 : template <typename T> 138 563 : void gatherMax(T & value) 139 : { 140 563 : _communicator.max(value); 141 563 : } 142 : 143 : /** 144 : * Gather the parallel min of the variable passed in. It takes care of values across all threads 145 : * and CPUs (we DO hybrid parallelism!) 146 : * 147 : * After calling this, the variable that was passed in will hold the gathered value. 148 : */ 149 : template <typename T> 150 1674 : void gatherMin(T & value) 151 : { 152 1674 : _communicator.min(value); 153 1674 : } 154 : 155 : /** 156 : * Deteremine the value of a variable according to the parallel 157 : * maximum of the provided proxy. 158 : * @param[in] proxy maximum proxy will be selected 159 : * @param[in] value value to be obtained corresponding to the location of maximum proxy 160 : */ 161 : template <typename T1, typename T2> 162 : void gatherProxyValueMax(T1 & proxy, T2 & value); 163 : 164 : /** 165 : * Determine the value of a variable according to which process has the parallel 166 : * minimum of the provided proxy. 167 : * @param[in] proxy minimum proxy will be selected 168 : * @param[in] value value to be obtained corresponding to the location of minimum proxy 169 : */ 170 : template <typename T1, typename T2> 171 : void gatherProxyValueMin(T1 & proxy, T2 & value); 172 : 173 : void setPrimaryThreadCopy(UserObject * primary); 174 : 175 363043 : UserObject * primaryThreadCopy() { return _primary_thread_copy; } 176 : 177 : /** 178 : * Recursively return a set of user objects this user object depends on 179 : * Note: this can be called only after all user objects are constructed. 180 : */ 181 : std::set<UserObjectName> getDependObjects() const; 182 : 183 : /** 184 : * Whether or not a threaded copy of this object is needed when obtaining it in 185 : * another object, like via the UserObjectInterface. 186 : * 187 : * Derived classes should override this as needed. 188 : */ 189 82799 : virtual bool needThreadedCopy() const { return false; } 190 : 191 334373 : const std::set<std::string> & getRequestedItems() override { return _depend_uo; } 192 : 193 334373 : const std::set<std::string> & getSuppliedItems() override { return _supplied_uo; } 194 : 195 : /** 196 : * @returns the number of the system associated with this object 197 : */ 198 : unsigned int systemNumber() const; 199 : 200 : protected: 201 : virtual void addPostprocessorDependencyHelper(const PostprocessorName & name) const override; 202 : virtual void 203 : addVectorPostprocessorDependencyHelper(const VectorPostprocessorName & name) const override; 204 : virtual void addUserObjectDependencyHelper(const UserObject & uo) const override; 205 : void addReporterDependencyHelper(const ReporterName & reporter_name) override; 206 : 207 : /// Reference to the Subproblem for this user object 208 : SubProblem & _subproblem; 209 : 210 : /// Reference to the FEProblemBase for this user object 211 : FEProblemBase & _fe_problem; 212 : 213 : /// Reference to the system object for this user object. This should correspond to a nonlinear 214 : /// system (either through the FEProblemBase or the DisplacedProblem) 215 : SystemBase & _sys; 216 : 217 : /// Thread ID of this postprocessor 218 : const THREAD_ID _tid; 219 : Assembly & _assembly; 220 : 221 : /// Coordinate system 222 : const Moose::CoordinateSystemType & _coord_sys; 223 : 224 : const bool _duplicate_initial_execution; 225 : 226 : /// Depend UserObjects that to be used both for determining user object sorting and by AuxKernel 227 : /// for finding the full UO dependency 228 : mutable std::set<std::string> _depend_uo; 229 : 230 : private: 231 : UserObject * _primary_thread_copy = nullptr; 232 : 233 : /// A name of the "supplied" user objects, which is just this object 234 : std::set<std::string> _supplied_uo; 235 : }; 236 : 237 : template <typename T1, typename T2> 238 : void 239 1752 : UserObject::gatherProxyValueMax(T1 & proxy, T2 & value) 240 : { 241 : // Get all proxy, value pairs. _communicator.maxloc would be faster but leads to 242 : // partitioning dependent results if the maximum proxy is not unique. 243 1752 : std::vector<std::pair<T1, T2>> all(n_processors()); 244 1752 : const auto pair = std::make_pair(proxy, value); 245 1752 : _communicator.allgather(pair, all); 246 : 247 : // find maximum, disambiguated by the value 248 1752 : const auto it = std::max_element(all.begin(), all.end()); 249 1752 : proxy = it->first; 250 1752 : value = it->second; 251 1752 : } 252 : 253 : template <typename T1, typename T2> 254 : void 255 764 : UserObject::gatherProxyValueMin(T1 & proxy, T2 & value) 256 : { 257 : // get all proxy, value pairs 258 764 : std::vector<std::pair<T1, T2>> all(n_processors()); 259 764 : const auto pair = std::make_pair(proxy, value); 260 764 : _communicator.allgather(pair, all); 261 : 262 : // find minimum, disambiguated by the value 263 764 : const auto it = std::min_element(all.begin(), all.end()); 264 764 : proxy = it->first; 265 764 : value = it->second; 266 764 : }