HeatFluidCoupledSpecies.h
Go to the documentation of this file.
1 // This file is part of the MercuryDPM project (https://www.mercurydpm.org).
2 // Copyright (c), The MercuryDPM Developers Team. All rights reserved.
3 // License: BSD 3-Clause License; see the LICENSE file in the root directory.
4 
5 #ifndef HEATFLUIDCOUPLEDSPECIES_H
6 #define HEATFLUIDCOUPLEDSPECIES_H
7 #include "ThermalSpecies.h"
9 class BaseInteraction;
10 
12 template<class NormalForceSpecies>
13 class HeatFluidCoupledSpecies : public ThermalSpecies<NormalForceSpecies>
14 {
15 public:
16 
18 
21 
24 
26  virtual ~HeatFluidCoupledSpecies();
27 
29  void write(std::ostream& os) const;
30 
32  void read(std::istream& is);
33 
35  std::string getBaseName() const;
36 
39 
41  void setMassTransferCoefficient(Mdouble massTransferCoefficient);
42 
45 
47  void setLatentHeatVaporization(Mdouble latentHeatVaporization);
48 
50  Mdouble getLiquidDensity() const;
51 
53  void setLiquidDensity(Mdouble liquidDensity);
54 
57 
59  void setEvaporationCoefficientA(Mdouble evaporationCoefficientA);
60 
63 
65  void setEvaporationCoefficientB(Mdouble evaporationCoefficientB);
66 
69 
71  void setAmbientHumidity(Mdouble ambientHumidity);
72 
75 
77  void setAmbientEquilibriumMoistureContent(Mdouble ambientEquilibriumMoistureContent);
78 
81 
83  void setAmbientVapourConcentration(Mdouble ambientVapourConcentration);
84 
85  void actionsAfterTimeStep(BaseParticle* particle) const override;
86 
88  std::array<double,2> f(double liquidVolume,double temperature, double mass, double surfaceArea) const;
89 
90 private:
91 
96 
101 
106 
111 
116 
121 
126 
131 
132 };
133 
134 template<class NormalForceSpecies>
137 {
140  liquidDensity_=1.0;
143  // note, this default value is unrealistically high; 0.3 is realistic.
144  ambientHumidity_=1.0;
147 }
148 
149 template<class NormalForceSpecies>
152 {
153  massTransferCoefficient_= s.massTransferCoefficient_;
154  latentHeatVaporization_= s.latentHeatVaporization_;
155  liquidDensity_=s.liquidDensity_;
156  evaporationCoefficientA_=s.evaporationCoefficientA_;
157  evaporationCoefficientB_=s.evaporationCoefficientB_;
158  ambientHumidity_=s.ambientHumidity_;
159  ambientEquilibriumMoistureContent_=s.ambientEquilibriumMoistureContent_;
160  ambientVapourConcentration_=s.ambientVapourConcentration_;
161 }
162 
163 template<class NormalForceSpecies>
165 {}
166 
167 template<class NormalForceSpecies>
169 {
171  os << " massTransferCoefficient " << massTransferCoefficient_;
172  os << " latentHeatVaporization " << latentHeatVaporization_;
173  os << " liquidDensity " << liquidDensity_;
174  os << " evaporationCoefficientA " << evaporationCoefficientA_;
175  os << " evaporationCoefficientA " << evaporationCoefficientB_;
176  os << " ambientHumidity " << ambientHumidity_;
177  os << " ambientEquilibriumMoistureContent " << ambientEquilibriumMoistureContent_;
178  os << " ambientVapourConcentration " << ambientVapourConcentration_;
179 }
180 
181 template<class NormalForceSpecies>
183 {
184  std::string dummy;
186  is >> dummy >> massTransferCoefficient_;
187  is >> dummy >> latentHeatVaporization_;
188  is >> dummy >> liquidDensity_;
189  is >> dummy >> evaporationCoefficientA_;
190  is >> dummy >> evaporationCoefficientB_;
191  is >> dummy >> ambientHumidity_;
192  is >> dummy >> ambientEquilibriumMoistureContent_;
193  is >> dummy >> ambientVapourConcentration_;
194  double ambientTemperature;
195  if (helpers::readOptionalVariable<Mdouble>(is, "ambientTemperature", ambientTemperature)) {
197  }
198 }
199 
200 template<class NormalForceSpecies>
202 {
203  return "HeatFluidCoupled" + NormalForceSpecies::getBaseName();
204 }
205 
206 template<class NormalForceSpecies>
208 {
209  return massTransferCoefficient_;
210 }
211 
212 template<class NormalForceSpecies>
214 {
215  logger.assert_always(massTransferCoefficient > 0,
216  "[HeatFluidCoupledSpecies<>::setMassTransferCoefficient(%)] value has to be positive",
217  massTransferCoefficient);
218  massTransferCoefficient_ = massTransferCoefficient;
219 }
220 
221 template<class NormalForceSpecies>
223 {
224  return latentHeatVaporization_;
225 }
226 
227 template<class NormalForceSpecies>
229 {
230  logger.assert_always(latentHeatVaporization > 0,
231  "[HeatFluidCoupledSpecies<>::setLatentHeatVaporization(%)] value has to be positive",
232  latentHeatVaporization);
233  latentHeatVaporization_ = latentHeatVaporization;
234 }
235 
236 template<class NormalForceSpecies>
238 {
239  return liquidDensity_;
240 }
241 
242 template<class NormalForceSpecies>
244 {
245  logger.assert_always(liquidDensity > 0,
246  "[HeatFluidCoupledSpecies<>::setLiquidDensity(%)] value has to be positive",
247  liquidDensity);
248  liquidDensity_ = liquidDensity;
249 }
250 
251 template<class NormalForceSpecies>
253 {
254  return evaporationCoefficientA_;
255 }
256 
257 template<class NormalForceSpecies>
259 {
260  logger.assert_always(evaporationCoefficientA >= 0,
261  "[HeatFluidCoupledSpecies<>::setEvaporationCoefficientA(%)] value has to be positive",
262  evaporationCoefficientA);
263  evaporationCoefficientA_ = evaporationCoefficientA;
264 }
265 
266 template<class NormalForceSpecies>
268 {
269  return evaporationCoefficientB_;
270 }
271 
272 template<class NormalForceSpecies>
274 {
275  logger.assert_always(evaporationCoefficientB <= 0,
276  "[HeatFluidCoupledSpecies<>::setEvaporationCoefficientB(%)] value has to be negative",
277  evaporationCoefficientB);
278  evaporationCoefficientB_ = evaporationCoefficientB;
279 }
280 
281 template<class NormalForceSpecies>
283 {
284  return ambientHumidity_;
285 }
286 
287 template<class NormalForceSpecies>
289 {
290  //note, this is not allowed to be zero!
291  logger.assert_always(ambientHumidity > 0,
292  "[HeatFluidCoupledSpecies<>::setAmbientHumidity(%)] value has to be positive",
293  ambientHumidity);
294  ambientHumidity_ = ambientHumidity;
295 }
296 
297 template<class NormalForceSpecies>
299 {
300  return ambientEquilibriumMoistureContent_;
301 }
302 
303 template<class NormalForceSpecies>
305 {
306  logger.assert_always(ambientEquilibriumMoistureContent >= 0,
307  "[HeatFluidCoupledSpecies<>::setAmbientEquilibriumMoistureContent(%)] value has to be positive",
308  ambientEquilibriumMoistureContent);
309  ambientEquilibriumMoistureContent_ = ambientEquilibriumMoistureContent;
310 }
311 
312 template<class NormalForceSpecies>
314 {
315  return ambientVapourConcentration_;
316 }
317 
318 template<class NormalForceSpecies>
320 {
321  logger.assert_always(ambientVapourConcentration >= 0,
322  "[HeatFluidCoupledSpecies<>::setAmbientVapourConcentration(%)] value has to be positive",
323  ambientVapourConcentration);
324  ambientVapourConcentration_ = ambientVapourConcentration;
325 }
326 
327 template<class NormalForceSpecies>
329 {
330  double dt = baseParticle->getHandler()->getDPMBase()->getTimeStep();
331  auto p = dynamic_cast<HeatFluidCoupledParticle*>(baseParticle);
332  double mass = p->getMass();
333  double surfaceArea = p->getSurfaceArea();
334 
335  // Runge–Kutta method.
336  std::array<double,2> k1 = f(p->getLiquidVolume() , p->getTemperature() , mass, surfaceArea);
337  std::array<double,2> k2 = f(p->getLiquidVolume() + 0.5*dt*k1[0], p->getTemperature() + 0.5*dt*k1[1], mass, surfaceArea);
338  std::array<double,2> k3 = f(p->getLiquidVolume() + 0.5*dt*k2[0], p->getTemperature() + 0.5*dt*k2[1], mass, surfaceArea);
339  std::array<double,2> k4 = f(p->getLiquidVolume() + dt*k3[0], p->getTemperature() + dt*k3[1], mass, surfaceArea);
340  double dLiquidVolume = dt * (k1[0] + 2*k2[0] + 2*k3[0] + k4[0]) / 6.0;
341  double dTemperature = dt * (k1[1] + 2*k2[1] + 2*k3[1] + k4[1]) / 6.0;
342  // Change sign, so we can think in terms of subtracting a positive number, instead of adding a negative number.
343  // Keep in mind, it is still possible that we are adding liquid/temperature (so now subtracting a negative number),
344  // however, since there is only a lower limit of 0 but no upper limit, this is easier to think about.
345  dLiquidVolume = -dLiquidVolume;
346  dTemperature = -dTemperature;
347 
348  // Subtract as much as possible from the liquid film. Any remainder is subtracted from the liquid bridges.
349  double dLiquidFilm = std::min(dLiquidVolume, p->getLiquidVolume());
350  double remainder = dLiquidVolume - dLiquidFilm;
351 
352  if (remainder > 0.0)
353  {
354  // Get the total liquid bridge volume. Note, don't use p->getLiquidBridgeVolume() as it halves the bridges with
355  // other particles. The order of handling the particles matters for how much liquid bridge is still available
356  // to them. It might seem more correct to use half the bridge instead of the full bridge, however that would
357  // only add an error, because the second particle halving the bridge would include the evaporated volume of the
358  // first particle. So instead of using L/2 it would use (L-evap)/2, which completely undoes the "correction" of
359  // halving the bridges in the first place.
360  double liquidBridgeVolume = 0.0;
361  for (auto i : p->getInteractions())
362  {
363  auto j = dynamic_cast<LiquidMigrationWilletInteraction*>(i);
364  liquidBridgeVolume += j->getLiquidBridgeVolume();
365  }
366  double dLiquidBridge = std::min(remainder, liquidBridgeVolume);
367  remainder -= dLiquidBridge;
368 
369  double factor = liquidBridgeVolume == 0.0 ? 0.0 : dLiquidBridge / liquidBridgeVolume;
370  for (auto i : p->getInteractions())
371  {
372  auto j = dynamic_cast<LiquidMigrationWilletInteraction*>(i);
373  j->addLiquidBridgeVolumeByEvaporation(-factor * j->getLiquidBridgeVolume());
374  }
375  }
376 
377  p->addLiquidVolume(-dLiquidFilm);
378  p->addTotalEvaporatedLiquidVolume(dLiquidVolume - remainder);
379  // If not all liquid could be removed, correct the temperature to be removed.
380  double dLiquidVolumeFactor = dLiquidVolume == 0.0 ? 0.0 : (dLiquidVolume - remainder) / dLiquidVolume;
381  p->setTemperature(std::max(0.0, p->getTemperature() - dTemperature * dLiquidVolumeFactor));
382 }
383 
392 template<class NormalForceSpecies>
393 std::array<double, 2> HeatFluidCoupledSpecies<NormalForceSpecies>::f(double liquidVolume, double temperature, double mass, double surfaceArea) const
394 {
395  // Saturated vapour concentration (kg/m^3), eq(7)
396  // Dependency on temperature is valid between 1 and 200 degree Celsius
397  // (it is unphysically decreasing between 0 and 1 degree),
398  // extrapolated as linear functions
399  double dT = temperature - 273;
400  double saturatedVapourConcentration = dT < 1 ? 8.319815774e-3 * temperature / 274 :
401  (((4.844e-9*dT - 1.4807e-7)*dT + 2.6572e-5)*dT - 4.8613e-5)*dT + 8.342e-3;
402 
403  // Relative activation energy of evaporation, eq(6)
404  double equilibriumActivationEnergy = -constants::R * this->getAmbientTemperature() * log(getAmbientHumidity());
405  // \todo what is the difference between the variable X and Y in Azmir?
406  double moistureContent = liquidVolume * getLiquidDensity() / mass;
407  double activationEnergy = equilibriumActivationEnergy * (moistureContent - getAmbientEquilibriumMoistureContent());
408 
409  // Vapour concentrations at the particle-medium interface (kg/m^3), eq(5)
410  // Implemented such that the code does not necessarily fail if temperature is 0
411  double interfaceVapourConcentration = temperature == 0 ? 0.0 :
412  exp(-activationEnergy / (constants::R * temperature)) * saturatedVapourConcentration;
413 
414  // Drying rate of liquid film mass (kg/s), eq (4)
415  double dLiquidMass = -getMassTransferCoefficient() * surfaceArea * (interfaceVapourConcentration - getAmbientVapourConcentration());
416 
417  // Drying rate of liquid film volume (kg/s), eq (3)
418  double dLiquidVolume = dLiquidMass / getLiquidDensity();
419 
420  // Heat of evaporation (J/s), eq (2)
421  double heatOfEvaporation = getLatentHeatVaporization() * (1.0 + getEvaporationCoefficientA() *
422  exp((getEvaporationCoefficientB() * getLiquidDensity() / mass) * liquidVolume)) * dLiquidMass;
423 
424  // Cooling rate of particle (K/s), eq (1)
425  double dTemperature = heatOfEvaporation / (mass * this->getHeatCapacity());
426 
427  return { dLiquidVolume, dTemperature };
428 }
429 #endif
int i
Definition: BiCGSTAB_step_by_step.cpp:9
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
float * p
Definition: Tutorial_Map_using.cpp:9
DPMBase * getDPMBase()
Gets the problem that is solved using this handler.
Definition: BaseHandler.h:733
Stores information about interactions between two interactable objects; often particles but could be ...
Definition: BaseInteraction.h:39
Definition: BaseParticle.h:33
ParticleHandler * getHandler() const
Returns pointer to the particle's ParticleHandler.
Definition: BaseParticle.cc:650
Mdouble getTimeStep() const
Returns the simulation time step.
Definition: DPMBase.cc:1241
Definition: HeatFluidCoupledInteraction.h:17
Species for the HeatFluidCoupledParticle.
Definition: HeatFluidCoupledSpecies.h:14
Mdouble getAmbientVapourConcentration() const
Allows ambientVapourConcentration_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:313
void setEvaporationCoefficientB(Mdouble evaporationCoefficientB)
Allows evaporationCoefficientB_ to be changed.
Definition: HeatFluidCoupledSpecies.h:273
Mdouble getEvaporationCoefficientA() const
Allows evaporationCoefficientA_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:252
Mdouble ambientVapourConcentration_
The ambient vapour concentration (kg/m^3).
Definition: HeatFluidCoupledSpecies.h:130
Mdouble getLiquidDensity() const
Allows liquidDensity_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:237
void setEvaporationCoefficientA(Mdouble evaporationCoefficientA)
Allows evaporationCoefficientA_ to be changed.
Definition: HeatFluidCoupledSpecies.h:258
Mdouble evaporationCoefficientB_
The evaporation coefficient b (dimensionless)
Definition: HeatFluidCoupledSpecies.h:115
HeatFluidCoupledSpecies()
The default constructor.
Definition: HeatFluidCoupledSpecies.h:135
void read(std::istream &is)
Reads the species properties from an input stream.
Definition: HeatFluidCoupledSpecies.h:182
void setAmbientVapourConcentration(Mdouble ambientVapourConcentration)
Allows ambientVapourConcentration_ to be changed.
Definition: HeatFluidCoupledSpecies.h:319
void setMassTransferCoefficient(Mdouble massTransferCoefficient)
Allows massTransferCoefficient_ to be changed.
Definition: HeatFluidCoupledSpecies.h:213
void setLiquidDensity(Mdouble liquidDensity)
Allows liquidDensity_ to be changed.
Definition: HeatFluidCoupledSpecies.h:243
void actionsAfterTimeStep(BaseParticle *particle) const override
Definition: HeatFluidCoupledSpecies.h:328
Mdouble massTransferCoefficient_
The mass transfer rate (m/s)
Definition: HeatFluidCoupledSpecies.h:95
Mdouble ambientHumidity_
The ambient humidity (dimensionless, between 0 and 1, but cannot be 0)
Definition: HeatFluidCoupledSpecies.h:120
void setLatentHeatVaporization(Mdouble latentHeatVaporization)
Allows latentHeatVaporization_ to be changed.
Definition: HeatFluidCoupledSpecies.h:228
Mdouble ambientEquilibriumMoistureContent_
The ambient equilibrium moisture content (dimensionless, between 0 and 1).
Definition: HeatFluidCoupledSpecies.h:125
HeatFluidCoupledInteraction< typename NormalForceSpecies::InteractionType > InteractionType
Definition: HeatFluidCoupledSpecies.h:17
virtual ~HeatFluidCoupledSpecies()
The default destructor.
Definition: HeatFluidCoupledSpecies.h:164
Mdouble evaporationCoefficientA_
The evaporation coefficient a (dimensionless)
Definition: HeatFluidCoupledSpecies.h:110
void write(std::ostream &os) const
Writes the species properties to an output stream.
Definition: HeatFluidCoupledSpecies.h:168
void setAmbientEquilibriumMoistureContent(Mdouble ambientEquilibriumMoistureContent)
Allows ambientEquilibriumMoistureContent_ to be changed.
Definition: HeatFluidCoupledSpecies.h:304
std::array< double, 2 > f(double liquidVolume, double temperature, double mass, double surfaceArea) const
f1 is used in Runge–Kutta method.
Definition: HeatFluidCoupledSpecies.h:393
void setAmbientHumidity(Mdouble ambientHumidity)
Allows ambientHumidity_ to be changed.
Definition: HeatFluidCoupledSpecies.h:288
Mdouble getAmbientHumidity() const
Allows ambientHumidity_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:282
Mdouble getAmbientEquilibriumMoistureContent() const
Allows ambientEquilibriumMoistureContent_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:298
Mdouble latentHeatVaporization_
The latent heat of vaporization (J/kg)
Definition: HeatFluidCoupledSpecies.h:100
Mdouble getEvaporationCoefficientB() const
Allows evaporationCoefficientB_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:267
std::string getBaseName() const
Used in Species::getName to obtain a unique name for each Species.
Definition: HeatFluidCoupledSpecies.h:201
Mdouble liquidDensity_
The liquid density (kg/m^3)
Definition: HeatFluidCoupledSpecies.h:105
Mdouble getLatentHeatVaporization() const
Allows latentHeatVaporization_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:222
Mdouble getMassTransferCoefficient() const
Allows massTransferCoefficient_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:207
Class of particles that store both temperature and liquid volume, which is adapted for the CFD-DEM st...
Definition: HeatFluidCoupledParticle.h:25
Defines the liquid bridge willet interaction between two particles or walls.
Definition: LiquidMigrationWilletInteraction.h:30
Defines a contact force parallel to the contact normal.
Definition: ThermalSpecies.h:14
void read(std::istream &is)
Reads the species properties from an input stream.
Definition: ThermalSpecies.h:210
void write(std::ostream &os) const
Writes the species properties to an output stream.
Definition: ThermalSpecies.h:196
void setAmbientTemperature(Mdouble ambientTemperature)
Definition: ThermalSpecies.h:58
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
#define min(a, b)
Definition: datatypes.h:22
#define max(a, b)
Definition: datatypes.h:23
RealScalar s
Definition: level1_cplx_impl.h:130
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 exp(const bfloat16 &a)
Definition: BFloat16.h:615
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 log(const bfloat16 &a)
Definition: BFloat16.h:618
const Mdouble R
Definition: ExtendedMath.h:29
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2