SPH
HeatDiffusion.cpp
Go to the documentation of this file.
1 #include "Sph.h"
2 #include <iostream>
3 
4 using namespace Sph;
5 
6 // In this example, we need to set up some material parameters that are not present in BodySettingsId enum,
7 // so they cannot be stored directly in BodySettings object. To do this, we can:
8 // 1) Simply assign unique indices to your parameters and cast them to BodySettingsId.
9 // 2) Create a custom material by deriving from IMaterial and store the parameters manually.
10 // Here we show how to implement the second solution.
11 
12 struct CustomMaterial : public NullMaterial {
13 
14  // Initial temperature of the material
16 
17  // Thermal conductivity
19 
20  // Density (yes, there is BodySettingsId::DENSITY, but we duplicate it to have all parameters
21  // at one place).
23 
24  // Specific heat capacity
26 
27  // Albedo of the surface
29 
31  : NullMaterial(BodySettings::getDefaults()) {}
32 };
33 
34 // Our custom solver, computing temperature derivatives using 1D finite differences.
35 class HdeSolver : public ISolver {
36 private:
37  // Parameters related to the boundary conditions
38 
39  // Solar constant
40  Float Phi = 1360._f;
41 
42  // Rotational frequency of the asteroid
43  Float omega = 2._f * PI / (60._f * 60._f * 2._f);
44 
45 
46  // Numerical parameters of the solver
47 
48  // Number of discretization elements in space
49  Size n = 1000;
50 
51  // Step in position
52  Float dz = 0.001_f;
53 
54 public:
55  // Function create should initialize all quantities in the provided storage, using the given material
56  // parameters. It is called for every created body (only once in this example).
57  virtual void create(Storage& storage, IMaterial& material) const override {
58  // Cast to access our material parameters
59  CustomMaterial& customMaterial = static_cast<CustomMaterial&>(material);
60 
61  // Initialize the temperature in the storage
62  Array<Float> T(n);
63  T.fill(customMaterial.temperature);
64  storage.insert<Float>(QuantityId::TEMPERATURE, OrderEnum::FIRST, std::move(T));
65  }
66 
67  // Main entry point of the solver. The function should compute the temporal derivatives of all time
68  // dependent quantities. In our case, we have just one quantity - temperature. We compute the derivative
69  // using the heat diffusion equation and save them to corresponding array in the storage.
70  virtual void integrate(Storage& storage, Statistics& stats) override {
71  // Get the quantities from the storage
74 
75  // Storage can contain multiple materials. While this example only uses one material, here we show a
76  // more general approach: we obtain material parameters from the material of each particle.
77  for (Size matId = 0; matId < storage.getMaterialCnt(); ++matId) {
78 
79  // This object holds a reference to the material and a list of particles with that material.
80  MaterialView materialView = storage.getMaterial(matId);
81 
82  // Cast to access our custom parameters
83  CustomMaterial& material = static_cast<CustomMaterial&>(materialView.material());
84 
85  // Iterate over all the particles with this material
86  for (Size i : materialView.sequence()) {
87 
88  if (i == 0) {
89  // First element: we need to apply the boundary condition on the surface.
90  // Set the temperature gradient based on the illumination and the surface temperature.
91  const Float A = material.albedo;
92  const Float K = material.conductivity;
93  const Float t = stats.get<Float>(StatisticsId::RUN_TIME);
94  const Float incidentFlux = (1._f - A) * Phi * max(cos(omega * t), 0._f);
95  const Float emissionFlux = Constants::stefanBoltzmann * pow<4>(T[0]);
96  T[0] = T[1] + dz * (incidentFlux - emissionFlux) / K;
97  } else if (i == n - 1) {
98  // Last element: we need to apply the boundary condition at "infinity".
99  // Set the temperature gradient to zero
100  T[n - 1] = T[n - 2];
101  } else {
102  // Compute the temporal derivative using the laplacian
103  const Float K = material.conductivity;
104  const Float rho = material.density;
105  const Float C = material.heatCapacity;
106  dT[i] = K / (rho * C) * (T[i + 1] + T[i - 1] - 2._f * T[i]) / sqr(dz);
107 
108  // Note that it is enough to set the temporal derivative. We do not have to integrate the
109  // quantity manually, the code does this automatically.
110  }
111  }
112  }
113  }
114 };
115 
116 // Custom logger, writing the current progress to standard output every 2 minutes.
117 // It also writes the surface temperature to file 'temperature.txt'.
119 private:
120  StdOutLogger stdout;
121  FileLogger file;
122 
123 public:
125  : PeriodicTrigger(120._f, 0._f)
126  , file(Path("temperature.txt")) {}
127 
128  virtual AutoPtr<ITrigger> action(Storage& storage, Statistics& stats) override {
129  const Float progress = stats.get<Float>(StatisticsId::RELATIVE_PROGRESS);
130  stdout.write("Progress: ", int(progress * 100._f), "%");
131 
132  const Float time = stats.get<Float>(StatisticsId::RUN_TIME);
134  file.write(time, " ", T[0]);
135  return nullptr;
136  }
137 };
138 
139 class Hde : public IRun {
140 public:
141  virtual void setUp(SharedPtr<Storage> storage) override {
142  settings.set(RunSettingsId::RUN_NAME, std::string("Heat diffusion"));
143 
144  // No need for output, we do that ourselvers here
146 
147  // Create the material and set up the parameters
148  AutoPtr<CustomMaterial> material = makeAuto<CustomMaterial>();
149  material->temperature = 250._f;
150  material->conductivity = 1._f;
151  material->density = 2500._f;
152  material->heatCapacity = 680._f;
153  material->albedo = 0.1_f;
154 
155  // Create the storage, passing our custom material
156  *storage = Storage(std::move(material));
157 
158  // Set the solver and create the quantities
159  solver = makeAuto<HdeSolver>();
160  solver->create(*storage, storage->getMaterial(0));
161 
162  // Set up the integrator with contant time step, for simplicity
166  .set(RunSettingsId::RUN_END_TIME, 60._f * 60._f * 12._f);
167 
168  // Create our custom progress logger
169  triggers.pushBack(makeAuto<ProgressLogger>());
170 
171  // Since we use custom trigger for logging, disable the default log writer
172  logWriter = makeAuto<NullLogWriter>();
173  }
174 
175  virtual void tearDown(const Storage& UNUSED(storage), const Statistics& UNUSED(stats)) override {}
176 };
177 
178 int main() {
179  try {
180  Hde simulation;
181  Storage storage;
182  simulation.run(storage);
183  } catch (const Exception& e) {
184  std::cout << "Error during simulation: " << e.what() << std::endl;
185  return -1;
186  }
187  return 0;
188 }
const EmptyFlags EMPTY_FLAGS
Definition: Flags.h:16
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
int main()
constexpr INLINE T max(const T &f1, const T &f2)
Definition: MathBasic.h:20
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
INLINE T cos(const T f)
Definition: MathUtils.h:291
constexpr INLINE Float pow< 4 >(const Float v)
Definition: MathUtils.h:136
constexpr Float PI
Mathematical constants.
Definition: MathUtils.h:361
#define UNUSED(x)
Definition: Object.h:37
@ TEMPERATURE
Temperature, always a scalar quantity.
@ FIRST
Quantity with 1st derivative.
Includes common headers.
@ RUN_TIME
Current time of the simulation in code units. Does not necessarily have to be 0 when run starts.
void fill(const T &t)
Sets all elements of the array to given value.
Definition: Array.h:187
Wrapper of pointer that deletes the resource from destructor.
Definition: AutoPtr.h:15
Generic exception.
Definition: Exceptions.h:10
virtual const char * what() const noexcept
Definition: Exceptions.h:18
File output logger.
Definition: Logger.h:160
virtual void create(Storage &storage, IMaterial &material) const override
Initializes all quantities needed by the solver in the storage.
virtual void integrate(Storage &storage, Statistics &stats) override
Computes derivatives of all time-dependent quantities.
virtual void setUp(SharedPtr< Storage > storage) override
Prepares the run, creates logger, output, ...
virtual void tearDown(const Storage &UNUSED(storage), const Statistics &UNUSED(stats)) override
void write(TArgs &&... args)
Creates and logs a message by concatenating arguments.
Definition: Logger.h:37
Material settings and functions specific for one material.
Definition: IMaterial.h:110
Defines the interface for a run.
Definition: IRun.h:61
Statistics run(Storage &storage)
Runs the simulation.
Definition: IRun.cpp:187
Base class for all solvers.
Definition: ISolver.h:20
Non-owning wrapper of a material and particles with this material.
Definition: IMaterial.h:30
INLINE IMaterial & material()
Returns the reference to the material of the particles.
Definition: IMaterial.h:43
INLINE IndexSequence sequence()
Returns iterable index sequence.
Definition: IMaterial.h:75
Material that does not require any initialization or finalization.
Definition: IMaterial.h:200
Object representing a path on a filesystem.
Definition: Path.h:17
Trigger executing given action every period.
Definition: Trigger.h:37
virtual AutoPtr< ITrigger > action(Storage &storage, Statistics &stats) override
Action executed when the condition is fulfilled.
Object holding various statistics about current run.
Definition: Statistics.h:22
TValue get(const StatisticsId idx) const
Returns value of a statistic.
Definition: Statistics.h:88
Standard output logger.
Definition: Logger.h:138
Container storing all quantities used within the simulations.
Definition: Storage.h:230
Size getMaterialCnt() const
Return the number of materials in the storage.
Definition: Storage.cpp:437
Quantity & insert(const QuantityId key, const OrderEnum order, const TValue &defaultValue)
Creates a quantity in the storage, given its key, value type and order.
Definition: Storage.cpp:270
Array< TValue > & getDt(const QuantityId key)
Retrieves a quantity derivative from the storage, given its key and value type.
Definition: Storage.cpp:217
MaterialView getMaterial(const Size matIdx) const
Returns an object containing a reference to given material.
Definition: Storage.cpp:366
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
Definition: Storage.cpp:191
@ NONE
No input/output.
@ EULER_EXPLICIT
Explicit (forward) 1st-order integration.
@ TIMESTEPPING_INITIAL_TIMESTEP
@ RUN_OUTPUT_TYPE
Selected format of the output file, see IoEnum.
@ TIMESTEPPING_INTEGRATOR
Selected timestepping integrator.
@ RUN_NAME
User-specified name of the run, used in some output files.
constexpr Float stefanBoltzmann
Stefan-Boltzmann constant.
Definition: Constants.h:23
Definition: MemoryPool.h:5