HeatFluidCoupledSpecies.h
Go to the documentation of this file.
1 //Copyright (c) 2013-2023, The MercuryDPM Developers Team. All rights reserved.
2 //For the list of developers, see <http://www.MercuryDPM.org/Team>.
3 //
4 //Redistribution and use in source and binary forms, with or without
5 //modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name MercuryDPM nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 //DISCLAIMED. IN NO EVENT SHALL THE MERCURYDPM DEVELOPERS TEAM BE LIABLE FOR ANY
19 //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #ifndef HEATFLUIDCOUPLEDSPECIES_H
27 #define HEATFLUIDCOUPLEDSPECIES_H
28 #include "ThermalSpecies.h"
30 class BaseInteraction;
31 
33 template<class NormalForceSpecies>
34 class HeatFluidCoupledSpecies : public ThermalSpecies<NormalForceSpecies>
35 {
36 public:
37 
39 
42 
45 
47  virtual ~HeatFluidCoupledSpecies();
48 
50  void write(std::ostream& os) const;
51 
53  void read(std::istream& is);
54 
56  std::string getBaseName() const;
57 
60 
62  void setMassTransferCoefficient(Mdouble massTransferCoefficient);
63 
66 
68  void setLatentHeatVaporization(Mdouble latentHeatVaporization);
69 
71  Mdouble getLiquidDensity() const;
72 
74  void setLiquidDensity(Mdouble liquidDensity);
75 
78 
80  void setEvaporationCoefficientA(Mdouble evaporationCoefficientA);
81 
84 
86  void setEvaporationCoefficientB(Mdouble evaporationCoefficientB);
87 
90 
92  void setAmbientHumidity(Mdouble ambientHumidity);
93 
96 
98  void setAmbientEquilibriumMoistureContent(Mdouble ambientEquilibriumMoistureContent);
99 
102 
104  void setAmbientVapourConcentration(Mdouble ambientVapourConcentration);
105 
108 
110  void setAmbientTemperature(Mdouble ambientTemperature);
111 
112  void actionsAfterTimeStep(BaseParticle* particle) const override;
113 
115  std::array<double,2> f(double liquidVolume,double temperature, double mass, double surfaceArea) const;
116 
117 private:
118 
123 
128 
133 
138 
143 
148 
153 
158 
163 
164 };
165 
166 template<class NormalForceSpecies>
169 {
172  liquidDensity_=1.0;
175  // note, this default value is unrealistically high; 0.3 is realistic.
176  ambientHumidity_=1.0;
180 }
181 
182 template<class NormalForceSpecies>
185 {
195 }
196 
197 template<class NormalForceSpecies>
199 {}
200 
201 template<class NormalForceSpecies>
203 {
205  os << " massTransferCoefficient " << massTransferCoefficient_;
206  os << " latentHeatVaporization " << latentHeatVaporization_;
207  os << " liquidDensity " << liquidDensity_;
208  os << " evaporationCoefficientA " << evaporationCoefficientA_;
209  os << " evaporationCoefficientA " << evaporationCoefficientB_;
210  os << " ambientHumidity " << ambientHumidity_;
211  os << " ambientEquilibriumMoistureContent " << ambientEquilibriumMoistureContent_;
212  os << " ambientVapourConcentration " << ambientVapourConcentration_;
213  os << " ambientTemperature " << ambientTemperature_;
214 }
215 
216 template<class NormalForceSpecies>
218 {
219  std::string dummy;
221  is >> dummy >> massTransferCoefficient_;
222  is >> dummy >> latentHeatVaporization_;
223  is >> dummy >> liquidDensity_;
224  is >> dummy >> evaporationCoefficientA_;
225  is >> dummy >> evaporationCoefficientB_;
226  is >> dummy >> ambientHumidity_;
227  is >> dummy >> ambientEquilibriumMoistureContent_;
228  is >> dummy >> ambientVapourConcentration_;
229  is >> dummy >> ambientTemperature_;
230 }
231 
232 template<class NormalForceSpecies>
234 {
235  return "HeatFluidCoupled" + NormalForceSpecies::getBaseName();
236 }
237 
238 template<class NormalForceSpecies>
240 {
241  return massTransferCoefficient_;
242 }
243 
244 template<class NormalForceSpecies>
246 {
247  logger.assert_always(massTransferCoefficient > 0,
248  "[HeatFluidCoupledSpecies<>::setMassTransferCoefficient(%)] value has to be positive",
249  massTransferCoefficient);
250  massTransferCoefficient_ = massTransferCoefficient;
251 }
252 
253 template<class NormalForceSpecies>
255 {
256  return latentHeatVaporization_;
257 }
258 
259 template<class NormalForceSpecies>
261 {
262  logger.assert_always(latentHeatVaporization > 0,
263  "[HeatFluidCoupledSpecies<>::setLatentHeatVaporization(%)] value has to be positive",
264  latentHeatVaporization);
265  latentHeatVaporization_ = latentHeatVaporization;
266 }
267 
268 template<class NormalForceSpecies>
270 {
271  return liquidDensity_;
272 }
273 
274 template<class NormalForceSpecies>
276 {
277  logger.assert_always(liquidDensity > 0,
278  "[HeatFluidCoupledSpecies<>::setLiquidDensity(%)] value has to be positive",
279  liquidDensity);
280  liquidDensity_ = liquidDensity;
281 }
282 
283 template<class NormalForceSpecies>
285 {
286  return evaporationCoefficientA_;
287 }
288 
289 template<class NormalForceSpecies>
291 {
292  logger.assert_always(evaporationCoefficientA >= 0,
293  "[HeatFluidCoupledSpecies<>::setEvaporationCoefficientA(%)] value has to be positive",
294  evaporationCoefficientA);
295  evaporationCoefficientA_ = evaporationCoefficientA;
296 }
297 
298 template<class NormalForceSpecies>
300 {
301  return evaporationCoefficientB_;
302 }
303 
304 template<class NormalForceSpecies>
306 {
307  logger.assert_always(evaporationCoefficientB <= 0,
308  "[HeatFluidCoupledSpecies<>::setEvaporationCoefficientB(%)] value has to be negative",
309  evaporationCoefficientB);
310  evaporationCoefficientB_ = evaporationCoefficientB;
311 }
312 
313 template<class NormalForceSpecies>
315 {
316  return ambientHumidity_;
317 }
318 
319 template<class NormalForceSpecies>
321 {
322  //note, this is not allowed to be zero!
323  logger.assert_always(ambientHumidity > 0,
324  "[HeatFluidCoupledSpecies<>::setAmbientHumidity(%)] value has to be positive",
325  ambientHumidity);
326  ambientHumidity_ = ambientHumidity;
327 }
328 
329 template<class NormalForceSpecies>
331 {
332  return ambientEquilibriumMoistureContent_;
333 }
334 
335 template<class NormalForceSpecies>
337 {
338  logger.assert_always(ambientEquilibriumMoistureContent >= 0,
339  "[HeatFluidCoupledSpecies<>::setAmbientEquilibriumMoistureContent(%)] value has to be positive",
340  ambientEquilibriumMoistureContent);
341  ambientEquilibriumMoistureContent_ = ambientEquilibriumMoistureContent;
342 }
343 
344 template<class NormalForceSpecies>
346 {
347  return ambientVapourConcentration_;
348 }
349 
350 template<class NormalForceSpecies>
352 {
353  logger.assert_always(ambientVapourConcentration >= 0,
354  "[HeatFluidCoupledSpecies<>::setAmbientVapourConcentration(%)] value has to be positive",
355  ambientVapourConcentration);
356  ambientVapourConcentration_ = ambientVapourConcentration;
357 }
358 
359 template<class NormalForceSpecies>
361 {
362  return ambientTemperature_;
363 }
364 
365 template<class NormalForceSpecies>
367 {
368  logger.assert_always(ambientTemperature > 0,
369  "[HeatFluidCoupledSpecies<>::setAmbientTemperature(%)] value has to be positive",
370  ambientTemperature);
371  ambientTemperature_ = ambientTemperature;
372 }
373 
374 template<class NormalForceSpecies>
376 {
377  double dt = baseParticle->getHandler()->getDPMBase()->getTimeStep();
378  auto p = dynamic_cast<HeatFluidCoupledParticle*>(baseParticle);
379  double mass = p->getMass();
380  double surfaceArea = p->getSurfaceArea();
381  //Runge–Kutta method
382  std::array<double,2> k1 = f(p->getLiquidVolume(),p->getTemperature(), mass, surfaceArea);
383  //logger(INFO, "dL % dT %", k1[0], k1[1]);
384  std::array<double,2> k2 = f(p->getLiquidVolume()+dt*0.5*k1[0],p->getTemperature()+dt*0.5*k1[1], mass, surfaceArea);
385  std::array<double,2> k3 = f(p->getLiquidVolume()+dt*0.5*k2[0],p->getTemperature()+dt*0.5*k2[1], mass, surfaceArea);
386  std::array<double,2> k4 = f(p->getLiquidVolume()+dt*k3[0],p->getTemperature()+dt*k3[1], mass, surfaceArea);
387  double dliquidVolume = dt*(k1[0]+2*k2[0]+2*k3[0]+k4[0])/6.0;
388  double dTemperature = dt*(k1[1]+2*k2[1]+2*k3[1]+k4[1])/6.0;
389  // if liquid film volume is larger than the volume that needs to be subtracted
390  if (p->getLiquidVolume()+dliquidVolume>=0.0) {
391  p->setLiquidVolume(p->getLiquidVolume()+dliquidVolume);
392  p->setTemperature(std::max(0.0,p->getTemperature()+dTemperature));
393  //logger(INFO,"% LF % T %", p->getIndex(), p->getLiquidVolume(), p->getTemperature());
394  } else {
395  // how much to remove from liquid bridges
396  double liquidVolumeToDistribute = - (p->getLiquidVolume()+dliquidVolume);
397  p->setLiquidVolume(0.0);
398  // get liquid bridge volume
399  double liquidBridgeVolume = 0.0;
400  for (BaseInteraction* i : p-> getInteractions()) {
401  auto j = dynamic_cast<LiquidMigrationWilletInteraction*>(i);
402  liquidBridgeVolume += j->getLiquidBridgeVolume();
403  }
404  // if liquid bridge volume is larger than the volume that needs to be subtracted
405  if (liquidVolumeToDistribute<=liquidBridgeVolume) {
406  double factor = 1.0-liquidVolumeToDistribute/liquidBridgeVolume;
407  for (BaseInteraction* i : p-> getInteractions()) {
408  auto j = dynamic_cast<LiquidMigrationWilletInteraction*>(i);
409  j->setLiquidBridgeVolume(factor*j->getLiquidBridgeVolume());
410  }
411  p->setTemperature(std::max(0.0,p->getTemperature()+dTemperature));
412  } else {
413  // if both liquid bridges and liquid films are empty after the subtraction
414  if (liquidBridgeVolume!=0.0) {
415  liquidVolumeToDistribute -= liquidBridgeVolume;
416  for (BaseInteraction *i: p->getInteractions()) {
417  auto j = dynamic_cast<LiquidMigrationWilletInteraction *>(i);
418  j->setLiquidBridgeVolume(0.0);
419  }
420  }
421  double factor = 1.0+liquidVolumeToDistribute/dliquidVolume;
422  p->setTemperature(std::max(0.0,p->getTemperature()+factor*dTemperature));
423  }
424  }
425 }
426 
435 template<class NormalForceSpecies>
436 std::array<double,2> HeatFluidCoupledSpecies<NormalForceSpecies>::f(double liquidVolume_,double temperature_, double mass, double surfaceArea) const {
437  // Saturated vapour concentration (kg/m^3), eq(7)
438  // Dependency on temperature is valid between 1 and 200 degree Celsius
439  // (it is unphysically decreasing between 0 and 1 degree),
440  // extrapolated as linear functions
441  double dT = temperature_-273;
442  double saturatedVapourConcentration = dT < 1 ? 8.319815774e-3*temperature_/274 :
443  (((4.844e-9*dT-1.4807e-7)*dT+2.6572e-5)*dT-4.8613e-5)*dT+8.342e-3;
444 
445  // Relative activation energy of evaporation, eq(6)
446  double equilibriumActivationEnergy=-constants::R*getAmbientTemperature()*log(getAmbientHumidity());
447  // \todo what is the difference between the variable X and Y in Azmir?
448  double moistureContent = liquidVolume_*getLiquidDensity()/mass;
449  double activationEnergy=equilibriumActivationEnergy*(moistureContent-getAmbientEquilibriumMoistureContent());
450 
451  // Vapour concentrations at the particle-medium interface (kg/m^3), eq(5)
452  // Implemented such that the code does not necessarily fail if temperature is 0
453  double interfaceVapourConcentration = temperature_==0?0.0:
454  exp(-activationEnergy/(constants::R*temperature_))*saturatedVapourConcentration;
455 
456  // Drying rate of liquid film mass (kg/s), eq (4)
457  double dLiquidMass=-getMassTransferCoefficient()*surfaceArea
458  *(interfaceVapourConcentration-getAmbientVapourConcentration());
459 
460  // Drying rate of liquid film volume (kg/s), eq (3)
461  double dLiquidVolume = dLiquidMass/getLiquidDensity();
462 
463  // Heat of evaporation (J/s), eq (2)
464  double heatOfEvaporation = getLatentHeatVaporization()*(1.0+getEvaporationCoefficientA()*exp((getEvaporationCoefficientB()*getLiquidDensity()/mass)*liquidVolume_))*dLiquidMass;
465 
466  // Cooling rate of particle (K/s), eq (1)
467  double dTemperature = heatOfEvaporation / (mass * this->getHeatCapacity());
468 
469  return {dLiquidVolume, dTemperature};
470 }
471 #endif
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
DPMBase * getDPMBase()
Gets the problem that is solved using this handler.
Definition: BaseHandler.h:725
Stores information about interactions between two interactable objects; often particles but could be ...
Definition: BaseInteraction.h:60
Definition: BaseParticle.h:54
ParticleHandler * getHandler() const
Returns pointer to the particle's ParticleHandler.
Definition: BaseParticle.cc:673
Mdouble getTimeStep() const
Returns the simulation time step.
Definition: DPMBase.cc:1250
Definition: HeatFluidCoupledInteraction.h:38
Species for the HeatFluidCoupledParticle.
Definition: HeatFluidCoupledSpecies.h:35
Mdouble getAmbientVapourConcentration() const
Allows ambientVapourConcentration_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:345
void setEvaporationCoefficientB(Mdouble evaporationCoefficientB)
Allows evaporationCoefficientB_ to be changed.
Definition: HeatFluidCoupledSpecies.h:305
Mdouble getEvaporationCoefficientA() const
Allows evaporationCoefficientA_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:284
Mdouble ambientVapourConcentration_
The ambient vapour concentration (kg/m^3).
Definition: HeatFluidCoupledSpecies.h:157
Mdouble getLiquidDensity() const
Allows liquidDensity_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:269
void setEvaporationCoefficientA(Mdouble evaporationCoefficientA)
Allows evaporationCoefficientA_ to be changed.
Definition: HeatFluidCoupledSpecies.h:290
Mdouble evaporationCoefficientB_
The evaporation coefficient b (dimensionless)
Definition: HeatFluidCoupledSpecies.h:142
HeatFluidCoupledSpecies()
The default constructor.
Definition: HeatFluidCoupledSpecies.h:167
void read(std::istream &is)
Reads the species properties from an input stream.
Definition: HeatFluidCoupledSpecies.h:217
void setAmbientVapourConcentration(Mdouble ambientVapourConcentration)
Allows ambientVapourConcentration_ to be changed.
Definition: HeatFluidCoupledSpecies.h:351
void setMassTransferCoefficient(Mdouble massTransferCoefficient)
Allows massTransferCoefficient_ to be changed.
Definition: HeatFluidCoupledSpecies.h:245
void setLiquidDensity(Mdouble liquidDensity)
Allows liquidDensity_ to be changed.
Definition: HeatFluidCoupledSpecies.h:275
void actionsAfterTimeStep(BaseParticle *particle) const override
Definition: HeatFluidCoupledSpecies.h:375
Mdouble massTransferCoefficient_
The mass transfer rate (m/s)
Definition: HeatFluidCoupledSpecies.h:122
Mdouble ambientHumidity_
The ambient humidity (dimensionless, between 0 and 1, but cannot be 0)
Definition: HeatFluidCoupledSpecies.h:147
void setLatentHeatVaporization(Mdouble latentHeatVaporization)
Allows latentHeatVaporization_ to be changed.
Definition: HeatFluidCoupledSpecies.h:260
Mdouble ambientEquilibriumMoistureContent_
The ambient equilibrium moisture content (dimensionless, between 0 and 1).
Definition: HeatFluidCoupledSpecies.h:152
HeatFluidCoupledInteraction< typename NormalForceSpecies::InteractionType > InteractionType
Definition: HeatFluidCoupledSpecies.h:38
virtual ~HeatFluidCoupledSpecies()
The default destructor.
Definition: HeatFluidCoupledSpecies.h:198
Mdouble evaporationCoefficientA_
The evaporation coefficient a (dimensionless)
Definition: HeatFluidCoupledSpecies.h:137
void write(std::ostream &os) const
Writes the species properties to an output stream.
Definition: HeatFluidCoupledSpecies.h:202
void setAmbientEquilibriumMoistureContent(Mdouble ambientEquilibriumMoistureContent)
Allows ambientEquilibriumMoistureContent_ to be changed.
Definition: HeatFluidCoupledSpecies.h:336
std::array< double, 2 > f(double liquidVolume, double temperature, double mass, double surfaceArea) const
f1 is used in Runge–Kutta method.
Definition: HeatFluidCoupledSpecies.h:436
void setAmbientHumidity(Mdouble ambientHumidity)
Allows ambientHumidity_ to be changed.
Definition: HeatFluidCoupledSpecies.h:320
Mdouble getAmbientHumidity() const
Allows ambientHumidity_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:314
Mdouble getAmbientEquilibriumMoistureContent() const
Allows ambientEquilibriumMoistureContent_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:330
Mdouble latentHeatVaporization_
The latent heat of vaporization (J/kg)
Definition: HeatFluidCoupledSpecies.h:127
Mdouble getEvaporationCoefficientB() const
Allows evaporationCoefficientB_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:299
Mdouble getAmbientTemperature() const
Allows ambientTemperature_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:360
std::string getBaseName() const
Used in Species::getName to obtain a unique name for each Species.
Definition: HeatFluidCoupledSpecies.h:233
Mdouble liquidDensity_
The liquid density (kg/m^3)
Definition: HeatFluidCoupledSpecies.h:132
Mdouble getLatentHeatVaporization() const
Allows latentHeatVaporization_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:254
Mdouble ambientTemperature_
The ambient temperature (K).
Definition: HeatFluidCoupledSpecies.h:162
Mdouble getMassTransferCoefficient() const
Allows massTransferCoefficient_ to be accessed.
Definition: HeatFluidCoupledSpecies.h:239
void setAmbientTemperature(Mdouble ambientTemperature)
Allows ambientTemperature_ to be changed.
Definition: HeatFluidCoupledSpecies.h:366
Class of particles that store both temperature and liquid volume, which is adapted for the CFD-DEM st...
Definition: HeatFluidCoupledParticle.h:46
Defines the liquid bridge willet interaction between two particles or walls.
Definition: LiquidMigrationWilletInteraction.h:45
void setLiquidBridgeVolume(Mdouble liquidBridgeVolume)
Definition: LiquidMigrationWilletInteraction.cc:467
Defines a contact force parallel to the contact normal.
Definition: ThermalSpecies.h:35
void read(std::istream &is)
Reads the species properties from an input stream.
Definition: ThermalSpecies.h:112
void write(std::ostream &os) const
Writes the species properties to an output stream.
Definition: ThermalSpecies.h:104
const Mdouble R
Definition: ExtendedMath.h:50
const std::complex< Mdouble > i
Definition: ExtendedMath.h:51
Mdouble log(Mdouble Power)
Definition: ExtendedMath.cc:104
Mdouble exp(Mdouble Exponent)
Definition: ExtendedMath.cc:84