diff --git a/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticles.cpp b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticles.cpp new file mode 100644 index 000000000..e93f899e8 --- /dev/null +++ b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticles.cpp @@ -0,0 +1,464 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#include "thermalSphereParticles.hpp" +#include "thermalSphereParticlesKernels.hpp" +#include + +namespace pFlow +{ + +//----------------------------- protected methods ----------------------------- + +// ========================================================================= // +// Section 1: Memory Management +// ========================================================================= // + +void thermalSphereParticles::checkHostMemory() +{ + sphereFluidParticles::checkHostMemory(); + + if (temperature_.size() != temperatureHost_.size()) + { + size_t oldSize = temperatureHost_.size(); + size_t newSize = temperature_.size(); + + resizeNoInit(temperatureHost_, newSize); + resizeNoInit(heatSourceConvHost_, newSize); + resizeNoInit(heatSourceRadHost_, newSize); + resizeNoInit(heatSourceCondPPHost_, newSize); + resizeNoInit(emissivityHost_, newSize); + resizeNoInit(radSumTempHost_, newSize); + resizeNoInit(radNumPrtHost_, newSize); + resizeNoInit(fluidKappaHost_, newSize); + resizeNoInit(fluidAlphaHost_, newSize); + + for (size_t i = oldSize; i < newSize; ++i) + { + temperatureHost_[i] = temperature_.field()[i]; + heatSourceConvHost_[i] = heatSourceConv_.field()[i]; + heatSourceRadHost_[i] = heatSourceRad_.field()[i]; + heatSourceCondPPHost_[i] = heatSourceCondPP_.field()[i]; + emissivityHost_[i] = emissivity_.field()[i]; + radSumTempHost_[i] = radSumTemp_.field()[i]; + radNumPrtHost_[i] = radNumPrt_.field()[i]; + fluidKappaHost_[i] = fluidKappa_.field()[i]; + fluidAlphaHost_[i] = fluidAlpha_.field()[i]; + } + } +} + +//----------------------------- constructors ---------------------------------- + +// ========================================================================= // +// Section 2: Constructor & Initialization +// ========================================================================= // + +thermalSphereParticles::thermalSphereParticles( + systemControl& control, + const sphereShape& shpShape, + const thermalSphereShape& thShpShape) +: + sphereFluidParticles(control, shpShape), + thSpheres_(thShpShape), + temperature_( + objectFile( + "temperature", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + Cp_( + objectFile( + "Cp", + "", + objectFile::READ_NEVER, + objectFile::WRITE_NEVER), + dynPointStruct(), + 1.0), + conductivity_( + objectFile( + "conductivity", + "", + objectFile::READ_NEVER, + objectFile::WRITE_NEVER), + dynPointStruct(), + 1.0), + heatSourceConv_( + objectFile( + "heatSourceConv", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + heatSourceRad_( + objectFile( + "heatSourceRad", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + heatSourceCondPP_( + objectFile( + "heatSourceCondPP", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + heatSourcePFP_( + objectFile( + "heatSourcePFP", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + emissivity_( + objectFile( + "emissivity", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + radSumTemp_( + objectFile( + "radSumTemp", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + radNumPrt_( + objectFile( + "radNumPrt", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0u), + E0_( + objectFile( + "E0", + "", + objectFile::READ_NEVER, + objectFile::WRITE_NEVER), + dynPointStruct(), + 1e9), + nu_( + objectFile( + "nu", + "", + objectFile::READ_NEVER, + objectFile::WRITE_NEVER), + dynPointStruct(), + 0.3), + temperatureRate_( + objectFile( + "temperatureRate", + "", + objectFile::READ_NEVER, + objectFile::WRITE_NEVER), + dynPointStruct(), + 0.0), + fluidKappa_( + objectFile( + "fluidKappa", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + fluidAlpha_( + objectFile( + "fluidAlpha", + "", + objectFile::READ_ALWAYS, + objectFile::WRITE_ALWAYS), + dynPointStruct(), + 0.0), + heatTransferTimer_("heatTransfer", &this->timers()), + temperatureIntegrationTimer_("tempInt", &this->timers()) +{ + initializeThermalParticles(); + checkHostMemory(); + + temperatureHostUpdatedSync(); + radiationDataHostUpdatedSync(); +} + +//---------------------------- public methods --------------------------------- + +bool thermalSphereParticles::initializeThermalParticles() +{ + auto activeMask = this->dynPointStruct().activePointsMaskDevice(); + + realVector h_Cp = thSpheres_.heatCapacities(); + realVector h_K = thSpheres_.heatConductivities(); + realVector h_Eps = thSpheres_.emissivities(); + realVector h_E0 = thSpheres_.realYoungsModuli(); + realVector h_Nu = thSpheres_.poissonRatios(); + + deviceViewType1D d_Cp ("dCp", h_Cp.size()); + deviceViewType1D d_K ("dK", h_K.size()); + deviceViewType1D d_Eps("dEps", h_Eps.size()); + deviceViewType1D d_E0 ("dE0", h_E0.size()); + deviceViewType1D d_Nu ("dNu", h_Nu.size()); + + auto m_Cp = Kokkos::create_mirror_view(d_Cp); + auto m_K = Kokkos::create_mirror_view(d_K); + auto m_Eps = Kokkos::create_mirror_view(d_Eps); + auto m_E0 = Kokkos::create_mirror_view(d_E0); + auto m_Nu = Kokkos::create_mirror_view(d_Nu); + + for (size_t i = 0; i < h_Cp.size(); ++i) + { + m_Cp (i) = h_Cp [i]; + m_K (i) = h_K [i]; + m_Eps(i) = h_Eps[i]; + m_E0 (i) = h_E0 [i]; + m_Nu (i) = h_Nu [i]; + } + + Kokkos::deep_copy(d_Cp, m_Cp); + Kokkos::deep_copy(d_K, m_K); + Kokkos::deep_copy(d_Eps, m_Eps); + Kokkos::deep_copy(d_E0, m_E0); + Kokkos::deep_copy(d_Nu, m_Nu); + + thermalSphereParticlesKernels::initThermalProperties( + activeMask, + shapeIndex().deviceViewAll(), + Cp_.deviceViewAll(), + conductivity_.deviceViewAll(), + emissivity_.deviceViewAll(), + E0_.deviceViewAll(), + nu_.deviceViewAll(), + d_Cp, + d_K, + d_Eps, + d_E0, + d_Nu); + + return true; +} + +// ========================================================================= // +// Section 3: Core Iteration Logic +// ========================================================================= // + +bool thermalSphereParticles::beforeIteration() +{ + sphereFluidParticles::beforeIteration(); + checkHostMemory(); + + if (heatSourceConvHost_.size() == heatSourceConv_.deviceView().size()) + { + Kokkos::deep_copy(heatSourceConv_.deviceView(), heatSourceConvHost_); + } + + if (heatSourceRadHost_.size() == heatSourceRad_.deviceView().size()) + { + Kokkos::deep_copy(heatSourceRad_.deviceView(), heatSourceRadHost_); + } + + temperatureRate_.field().fill(0.0); + + temperatureHostUpdatedSync(); + radiationDataHostUpdatedSync(); + + return true; +} + +bool thermalSphereParticles::iterate() +{ + if (!sphereFluidParticles::iterate()) + { + return false; + } + + auto mask = dynPointStruct().activePointsMaskDevice(); + + heatTransferTimer_.start(); + + thermalSphereParticlesKernels::calcFluidParticleHeatTransfer( + mask, + diameter().deviceViewAll(), + mass().deviceViewAll(), + Cp().deviceViewAll(), + temperature().deviceViewAll(), + heatSourceConv_.deviceViewAll(), + heatSourceRad_.deviceViewAll(), + heatSourceCondPP_.deviceViewAll(), + heatSourcePFP_.deviceViewAll(), + temperatureRate_.deviceViewAll()); + + heatTransferTimer_.end(); + + temperatureIntegrationTimer_.start(); + + thermalSphereParticlesKernels::integrateTemperature( + mask, + control().time().dt(), + temperature().deviceViewAll(), + temperatureRate_.deviceViewAll()); + + temperatureIntegrationTimer_.end(); + + return true; +} + +// ========================================================================= // +// Section 4: Particle Insertion +// ========================================================================= // + +bool thermalSphereParticles::insertParticles( + const realx3Vector& pos, + const wordVector& names, + const anyList& vars) +{ + anyList nv(vars); + + realVector cpV ("Cp"); + realVector kV ("k"); + realVector epsV ("emissivity"); + realVector e0V ("E0"); + realVector nuV ("nu"); + realVector tV ("T"); + realVector kappaV ("fluidKappa"); + realVector alphaV ("fluidAlpha"); + realVector pfpV ("heatSourcePFP"); + + for (const auto& name : names) + { + uint32 i; + if (thSpheres_.shapeNameToIndex(name, i)) + { + cpV .push_back(thSpheres_.heatCapacity(i)); + kV .push_back(thSpheres_.heatConductivity(i)); + epsV.push_back(thSpheres_.emissivity(i)); + e0V .push_back(thSpheres_.realYoungsModulus(i)); + nuV .push_back(thSpheres_.poissonRatio(i)); + + kappaV.push_back(0.0); + alphaV.push_back(0.0); + pfpV .push_back(0.0); + + // Fetch insertion temperature directly from properties + tV.push_back(thSpheres_.insertionTemperature()); + } + } + + nv.emplaceBack(Cp_.name() + "Vector", std::move(cpV)); + nv.emplaceBack(conductivity_.name() + "Vector", std::move(kV)); + nv.emplaceBack(emissivity_.name() + "Vector", std::move(epsV)); + nv.emplaceBack(E0_.name() + "Vector", std::move(e0V)); + nv.emplaceBack(nu_.name() + "Vector", std::move(nuV)); + nv.emplaceBack(temperature_.name() + "Vector", std::move(tV)); + nv.emplaceBack(fluidKappa_.name() + "Vector", std::move(kappaV)); + nv.emplaceBack(fluidAlpha_.name() + "Vector", std::move(alphaV)); + nv.emplaceBack(heatSourcePFP_.name() + "Vector", std::move(pfpV)); + + return sphereFluidParticles::insertParticles(pos, names, nv); +} + +// ========================================================================= // +// Section 5: MPI Synchronisation Routines (Host <-> Device) +// ========================================================================= // + +void thermalSphereParticles::heatSourcesHostUpdatedSync() +{ + checkHostMemory(); + + bool sizeConv = + (heatSourceConvHost_.size() == heatSourceConv_.deviceView().size()); + bool sizeRad = + (heatSourceRadHost_.size() == heatSourceRad_.deviceView().size()); + bool sizeCond = + (heatSourceCondPPHost_.size() == heatSourceCondPP_.deviceView().size()); + + if (sizeConv && sizeRad && sizeCond) + { + Kokkos::deep_copy( + heatSourceConv_.deviceView(), + heatSourceConvHost_); + + Kokkos::deep_copy( + heatSourceRad_.deviceView(), + heatSourceRadHost_); + + Kokkos::deep_copy( + heatSourceCondPP_.deviceView(), + heatSourceCondPPHost_); + } +} + +void thermalSphereParticles::fluidPropertiesHostUpdatedSync() +{ + checkHostMemory(); + + bool sizeKappa = + (fluidKappaHost_.size() == fluidKappa_.deviceView().size()); + bool sizeAlpha = + (fluidAlphaHost_.size() == fluidAlpha_.deviceView().size()); + + if (sizeKappa && sizeAlpha) + { + Kokkos::deep_copy(fluidKappa_.deviceView(), fluidKappaHost_); + Kokkos::deep_copy(fluidAlpha_.deviceView(), fluidAlphaHost_); + } +} + +void thermalSphereParticles::temperatureHostUpdatedSync() +{ + checkHostMemory(); + + if (temperatureHost_.size() == temperature_.deviceView().size()) + { + Kokkos::deep_copy(temperatureHost_, temperature_.deviceView()); + } +} + +void thermalSphereParticles::radiationDataHostUpdatedSync() +{ + checkHostMemory(); + + bool sizeEps = + (emissivityHost_.size() == emissivity_.deviceView().size()); + bool sizeSum = + (radSumTempHost_.size() == radSumTemp_.deviceView().size()); + bool sizeNum = + (radNumPrtHost_.size() == radNumPrt_.deviceView().size()); + + if (sizeEps && sizeSum && sizeNum) + { + Kokkos::deep_copy(emissivityHost_, emissivity_.deviceView()); + Kokkos::deep_copy(radSumTempHost_, radSumTemp_.deviceView()); + Kokkos::deep_copy(radNumPrtHost_, radNumPrt_.deviceView()); + } +} + +//+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} // pFlow diff --git a/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticles.hpp b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticles.hpp new file mode 100644 index 000000000..24a01a87f --- /dev/null +++ b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticles.hpp @@ -0,0 +1,367 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#ifndef pFlow_thermalSphereParticles_hpp +#define pFlow_thermalSphereParticles_hpp + +#include "sphereFluidParticles.hpp" +#include "thermalSphereShape.hpp" + +namespace pFlow +{ + +/** + * @brief Manages the thermal state and thermodynamic properties of + * spherical particles on the GPU. + * + * @details + * Extends sphereFluidParticles by introducing device (Kokkos) memory for: + * - Temperatures and integration rates (Explicit Euler). + * - Thermodynamic properties (heat capacities, conductivities, emissivities). + * - Multi-mode heat sources (Convection, Radiation, Conduction, PFP). + * - Host (CPU) mirror arrays used for MPI and OpenFOAM coupling synchronization. + */ +class thermalSphereParticles +: + public sphereFluidParticles +{ +public: + + //- Type info + + TypeInfo("thermalSphereParticles"); + +private: + + //- private members + + // --- Section 1: Shape Reference --- + + const thermalSphereShape& thSpheres_; + + // --- Section 2: Device Fields (GPU/Kokkos) --- + + realPointField_D temperature_; + realPointField_D Cp_; + realPointField_D conductivity_; + realPointField_D temperatureRate_; + + realPointField_D heatSourceConv_; + realPointField_D heatSourceRad_; + realPointField_D heatSourceCondPP_; + realPointField_D heatSourcePFP_; + + realPointField_D emissivity_; + realPointField_D radSumTemp_; + uint32PointField_D radNumPrt_; + + realPointField_D E0_; + realPointField_D nu_; + + realPointField_D fluidKappa_; + realPointField_D fluidAlpha_; + + // --- Section 3: Performance Timers --- + + Timer heatTransferTimer_; + Timer temperatureIntegrationTimer_; + + // --- Section 4: Host Mirror Fields (CPU RAM) --- + + hostViewType1D temperatureHost_; + hostViewType1D heatSourceConvHost_; + hostViewType1D heatSourceRadHost_; + hostViewType1D heatSourceCondPPHost_; + hostViewType1D emissivityHost_; + hostViewType1D radSumTempHost_; + hostViewType1D radNumPrtHost_; + hostViewType1D fluidKappaHost_; + hostViewType1D fluidAlphaHost_; + +protected: + + //- protected methods + + // --- Section 5: Memory Management --- + + /** + * @brief Ensures host arrays are sized to match their corresponding + * device arrays and initializes newly allocated memory slots. + */ + void checkHostMemory(); + +public: + + //- constructors + + // --- Section 6: Constructor and Initialization --- + + thermalSphereParticles( + systemControl& control, + const sphereShape& shpShape, + const thermalSphereShape& thShpShape); + + ~thermalSphereParticles() override = default; + + //- public methods + + /** + * @brief Scatters per-material thermal properties to individual + * particle slots on the GPU. + * @return True upon successful mapping. + */ + bool initializeThermalParticles(); + + // --- Section 7: Core Iteration Hooks --- + + bool beforeIteration() override; + + bool iterate() override; + + bool insertParticles( + const realx3Vector& pos, + const wordVector& names, + const anyList& vars) override; + + // --- Section 8: Device Accessors --- + + inline + const realPointField_D& temperature() const + { + return temperature_; + } + + inline + realPointField_D& temperature() + { + return temperature_; + } + + inline + const realPointField_D& Cp() const + { + return Cp_; + } + + inline + const realPointField_D& conductivity() const + { + return conductivity_; + } + + inline + realPointField_D& conductivity() + { + return conductivity_; + } + + inline + const realPointField_D& heatSourceConv() const + { + return heatSourceConv_; + } + + inline + realPointField_D& heatSourceConv() + { + return heatSourceConv_; + } + + inline + const realPointField_D& heatSourceRad() const + { + return heatSourceRad_; + } + + inline + realPointField_D& heatSourceRad() + { + return heatSourceRad_; + } + + inline + const realPointField_D& heatSourceCondPP() const + { + return heatSourceCondPP_; + } + + inline + realPointField_D& heatSourceCondPP() + { + return heatSourceCondPP_; + } + + inline + const realPointField_D& heatSourcePFP() const + { + return heatSourcePFP_; + } + + inline + realPointField_D& heatSourcePFP() + { + return heatSourcePFP_; + } + + inline + const realPointField_D& emissivity() const + { + return emissivity_; + } + + inline + realPointField_D& emissivity() + { + return emissivity_; + } + + inline + const realPointField_D& radSumTemp() const + { + return radSumTemp_; + } + + inline + realPointField_D& radSumTemp() + { + return radSumTemp_; + } + + inline + const uint32PointField_D& radNumPrt() const + { + return radNumPrt_; + } + + inline + uint32PointField_D& radNumPrt() + { + return radNumPrt_; + } + + inline + const realPointField_D& E0() const + { + return E0_; + } + + inline + const realPointField_D& nu() const + { + return nu_; + } + + inline + const realPointField_D& fluidKappa() const + { + return fluidKappa_; + } + + inline + realPointField_D& fluidKappa() + { + return fluidKappa_; + } + + inline + const realPointField_D& fluidAlpha() const + { + return fluidAlpha_; + } + + inline + realPointField_D& fluidAlpha() + { + return fluidAlpha_; + } + + // --- Section 9: Host Accessors --- + + inline + auto& temperatureHost() + { + return temperatureHost_; + } + + inline + auto& heatSourceConvHost() + { + return heatSourceConvHost_; + } + + inline + auto& heatSourceRadHost() + { + return heatSourceRadHost_; + } + + inline + auto& heatSourceCondPPHost() + { + return heatSourceCondPPHost_; + } + + inline + auto& emissivityHost() + { + return emissivityHost_; + } + + inline + auto& radSumTempHost() + { + return radSumTempHost_; + } + + inline + auto& radNumPrtHost() + { + return radNumPrtHost_; + } + + inline + auto& fluidKappaHost() + { + return fluidKappaHost_; + } + + inline + auto& fluidAlphaHost() + { + return fluidAlphaHost_; + } + + // --- Section 10: Synchronisation Routines (Host <-> Device) --- + + void heatSourcesHostUpdatedSync(); + + void fluidPropertiesHostUpdatedSync(); + + void temperatureHostUpdatedSync(); + + void radiationDataHostUpdatedSync(); + +}; // thermalSphereParticles + +} // pFlow + +#endif // pFlow_thermalSphereParticles_hpp + + diff --git a/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticlesKernels.cpp b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticlesKernels.cpp new file mode 100644 index 000000000..dc3b20bdd --- /dev/null +++ b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticlesKernels.cpp @@ -0,0 +1,170 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#include "thermalSphereParticlesKernels.hpp" + +namespace pFlow +{ +namespace thermalSphereParticlesKernels +{ + +// ========================================================================= // +// Section 1: Execution Policy Definition +// Schedule is used for optimal load balancing on uniform particle +// arrays +// ========================================================================= // + +using policy = Kokkos::RangePolicy< + pFlow::DefaultExecutionSpace, + Kokkos::Schedule, + Kokkos::IndexType>; + +// ========================================================================= // +// Section 2: Property Initialization Kernel +// ========================================================================= // + +void initThermalProperties( + const pFlagTypeDevice& m, + const deviceViewType1D& idx, + deviceViewType1D Cp, + deviceViewType1D K, + deviceViewType1D emissivity, + deviceViewType1D E0, + deviceViewType1D nu, + const deviceViewType1D& sCp, + const deviceViewType1D& sK, + const deviceViewType1D& sEps, + const deviceViewType1D& sE0, + const deviceViewType1D& sNu) +{ + auto r = m.activeRange(); + + Kokkos::parallel_for( + "initThermalProps", + policy(r.start(), r.end()), + KOKKOS_LAMBDA(uint32 i) + { + if (m(i)) + { + // Map the particle to its material type + uint32 j = idx[i]; + + // Scatter properties to the main particle arrays + Cp[i] = sCp[j]; + K[i] = sK[j]; + emissivity[i] = sEps[j]; + E0[i] = sE0[j]; + nu[i] = sNu[j]; + } + }); + + Kokkos::fence(); +} + +// ========================================================================= // +// Section 3: Energy Equation Kernel +// ========================================================================= // + +void calcFluidParticleHeatTransfer( + const pFlagTypeDevice& m, + const deviceViewType1D& d, + const deviceViewType1D& ms, + const deviceViewType1D& Cp, + const deviceViewType1D& T, + const deviceViewType1D& Q_conv, + const deviceViewType1D& Q_rad, + const deviceViewType1D& Q_pp, + const deviceViewType1D& Q_pfp, + deviceViewType1D TR) +{ + auto r = m.activeRange(); + + Kokkos::parallel_for( + "calcHeatTransferRate", + policy(r.start(), r.end()), + KOKKOS_LAMBDA(uint32 i) + { + if (m(i)) + { + // --------------------------------------------------------- // + // Particle Energy Equation (Lumped Capacitance Model) + // m * Cp * dT/dt = Q_conv + Q_rad + Q_pp + Q_pfp + // --------------------------------------------------------- // + + // Thermal Inertia = Mass [kg] * Specific Heat Capacity + // [J/(kg.K)] = [J/K] + real thermalInertia = ms[i] * Cp[i]; + + // Protection against division by zero (Thermal Inertia Guard) + if (thermalInertia > 1e-12) + { + TR[i] = (Q_conv[i] + Q_rad[i] + Q_pp[i] + Q_pfp[i]) / + thermalInertia; + } + else + { + TR[i] = 0.0; + } + } + }); + + Kokkos::fence(); +} + +// ========================================================================= // +// Section 4: Time Integration Kernel +// ========================================================================= // + +void integrateTemperature( + const pFlagTypeDevice& m, + const real dt, + deviceViewType1D T, + const deviceViewType1D& TR) +{ + auto r = m.activeRange(); + + Kokkos::parallel_for( + "integrateTemp", + policy(r.start(), r.end()), + KOKKOS_LAMBDA(uint32 i) + { + if (m(i)) + { + // --------------------------------------------------------- // + // Explicit Euler Integration for particle temperature. + // Stability is naturally enhanced because Q_rad is + // analytically linearized in the CFD solver, preventing + // the stiff T^4 equation from causing numerical explosions. + // --------------------------------------------------------- // + + T[i] += TR[i] * dt; + } + }); + + Kokkos::fence(); +} + +//+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} // thermalSphereParticlesKernels +} // pFlow + + + diff --git a/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticlesKernels.hpp b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticlesKernels.hpp new file mode 100644 index 000000000..7ace1ca8b --- /dev/null +++ b/src/Particles/SphereParticles/thermalSphereParticles/thermalSphereParticlesKernels.hpp @@ -0,0 +1,130 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#ifndef pFlow_thermalSphereParticlesKernels_hpp +#define pFlow_thermalSphereParticlesKernels_hpp + +#include "types.hpp" +#include "pointFlag.hpp" + +namespace pFlow +{ + +/** + * @namespace pFlow::thermalSphereParticlesKernels + * @brief High-performance GPU/CPU kernels for Lagrangian particle + * thermodynamics. + * + * @details + * This namespace isolates the raw numerical integration and physical + * calculations for particle heat transfer from the memory management classes. + * By using Kokkos `deviceViewType1D`, these functions map directly to + * massively parallel execution spaces (like NVIDIA CUDA or AMD HIP), ensuring + * that thermodynamic updates for millions of particles occur efficiently. + */ +namespace thermalSphereParticlesKernels +{ + + /** + * @brief Maps macroscopic shape properties to individual particle arrays. + * + * @param mask Active particle flag. + * @param shapeIndex The index linking a particle to its material type. + * @param Cp [OUT] Specific heat capacity array of particles. + * @param K [OUT] Thermal conductivity array of particles. + * @param emissivity [OUT] Surface emissivity array of particles. + * @param E0 [OUT] Real Young's Modulus array of particles. + * @param nu [OUT] Poisson's Ratio array of particles. + * @param shapeCp Dictionary-loaded heat capacities per material type. + * @param shapeK Dictionary-loaded conductivities per material type. + * @param shapeEps Dictionary-loaded emissivities per material type. + * @param shapeE0 Dictionary-loaded Real Young's Moduli per material. + * @param shapeNu Dictionary-loaded Poisson's Ratios per material type. + */ + void initThermalProperties( + const pFlagTypeDevice& mask, + const deviceViewType1D& shapeIndex, + deviceViewType1D Cp, + deviceViewType1D K, + deviceViewType1D emissivity, + deviceViewType1D E0, + deviceViewType1D nu, + const deviceViewType1D& shapeCp, + const deviceViewType1D& shapeK, + const deviceViewType1D& shapeEps, + const deviceViewType1D& shapeE0, + const deviceViewType1D& shapeNu); + + /** + * @brief Evaluates the First Law of Thermodynamics for each particle. + * + * @details + * Uses the Lumped Capacitance Model to calculate the temporal + * temperature derivative: + * dT/dt = (Q_conv + Q_rad + Q_pp + Q_pfp) / (m * Cp) + * + * @param mask Active particle flag. + * @param diameter Particle diameter array. + * @param mass Particle mass array. + * @param Cp Particle specific heat capacity array. + * @param temperature Current particle temperature array. + * @param Q_conv Convective heat source array [W]. + * @param Q_rad Radiative heat source array [W]. + * @param Q_pp Collisional heat transfer array [W]. + * @param Q_pfp Particle-Fluid-Particle sub-grid heat [W]. + * @param temperatureRate [OUT] The resulting rate of temperature change. + */ + void calcFluidParticleHeatTransfer( + const pFlagTypeDevice& mask, + const deviceViewType1D& diameter, + const deviceViewType1D& mass, + const deviceViewType1D& Cp, + const deviceViewType1D& temperature, + const deviceViewType1D& Q_conv, + const deviceViewType1D& Q_rad, + const deviceViewType1D& Q_pp, + const deviceViewType1D& Q_pfp, + deviceViewType1D temperatureRate); + + /** + * @brief Marches the particle temperatures forward in time. + * + * @details + * Applies Explicit Euler integration: + * T(t+dt) = T(t) + (dT/dt) * dt + * + * @param mask Active particle flag. + * @param dt The physical time step size [s]. + * @param temperature [IN/OUT] Particle temperature array to be updated. + * @param temperatureRate Computed rate of temperature change (dT/dt). + */ + void integrateTemperature( + const pFlagTypeDevice& mask, + const real dt, + deviceViewType1D temperature, + const deviceViewType1D& temperatureRate); + +} // thermalSphereParticlesKernels +} // pFlow + +#endif // pFlow_thermalSphereParticlesKernels_hpp + + + diff --git a/src/Particles/SphereParticles/thermalSphereShape/thermalSphereShape.cpp b/src/Particles/SphereParticles/thermalSphereShape/thermalSphereShape.cpp new file mode 100644 index 000000000..55b5ccd6e --- /dev/null +++ b/src/Particles/SphereParticles/thermalSphereShape/thermalSphereShape.cpp @@ -0,0 +1,141 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#include "thermalSphereShape.hpp" +#include "thermalProperty.hpp" + +namespace pFlow +{ + +//----------------------------- private methods ------------------------------- + +bool thermalSphereShape::readThermalProperties() +{ + // Retrieve the array that links each shape index to a specific material ID + auto pids = shapePropertyIds(); + + // Allocate memory for shape-specific thermal property vectors + cp_ = realVector("Cp", numShapes()); + k_ = realVector("k", numShapes()); + emissivity_ = realVector("emissivity", numShapes()); + E0_ = realVector("realYoungsModuli", numShapes()); + nu_ = realVector("poissonRatios", numShapes()); + + // ---------------------------------------------------------------------- // + // Direct access to the already-constructed base property object, which + // holds all dictionary values parsed from the case file. No separate + // fileDictionary instantiation or hardcoded path is needed here. + // ---------------------------------------------------------------------- // + const thermalProperty* tProps = + dynamic_cast(&properties()); + + if (!tProps) + { + fatalErrorInFunction + << "Provided property object is not a thermalProperty!" + << endl; + fatalExit; + } + + const realVector& allCp = tProps->heatCapacities(); + const realVector& allK = tProps->heatConductivities(); + const realVector& allEps = tProps->emissivities(); + const realVector& allE0 = tProps->realYoungsModuli(); + const realVector& allNu = tProps->poissonRatios(); + + // Map the global material properties to the specific local shapes + for (uint32 i = 0; i < numShapes(); ++i) + { + cp_[i] = allCp [pids[i]]; + k_[i] = allK [pids[i]]; + emissivity_[i] = allEps[pids[i]]; + E0_[i] = allE0 [pids[i]]; + nu_[i] = allNu [pids[i]]; + } + + // ---------------------------------------------------------------------- // + // Initial temperature assigned to newly inserted particles. + // + // A silently-defaulted value here (e.g. a stale 300 K) would mean any + // particle inserted through dynamic insertion (rather than read from + // an initial positions file) enters the domain at an unintended + // temperature with no warning at all, so this must be supplied + // explicitly rather than falling back to a built-in default. + // ---------------------------------------------------------------------- // + if (!properties().containsDataEntry("insertionTemperature")) + { + fatalErrorInFunction + << "Missing MANDATORY entry 'insertionTemperature' in the " + << "interaction dictionary." << endl; + fatalExit; + } + + insertionTemperature_ = properties().getVal("insertionTemperature"); + + return true; +} + +//---------------------------- protected methods ------------------------------ + +bool thermalSphereShape::writeToDict(dictionary& dict) const +{ + bool isWritten = sphereShape::writeToDict(dict) + && dict.add("heatCapacities", cp_) + && dict.add("heatConductivities", k_) + && dict.add("emissivities", emissivity_) + && dict.add("realYoungsModuli", E0_) + && dict.add("poissonRatios", nu_); + + return isWritten; +} + +//----------------------------- constructors ---------------------------------- + +// ========================================================================= // +// Constructors +// ========================================================================= // + +thermalSphereShape::thermalSphereShape( + const word& fileName, + repository* owner, + const property& prop) +: + sphereShape(fileName, owner, prop) +{ + readThermalProperties(); +} + +thermalSphereShape::thermalSphereShape( + const word& shapeType, + const word& fileName, + repository* owner, + const property& prop) +: + thermalSphereShape(fileName, owner, prop) +{ + // Body intentionally empty — delegates to primary constructor +} + +//+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} // pFlow + + + diff --git a/src/Particles/SphereParticles/thermalSphereShape/thermalSphereShape.hpp b/src/Particles/SphereParticles/thermalSphereShape/thermalSphereShape.hpp new file mode 100644 index 000000000..749bd8ba7 --- /dev/null +++ b/src/Particles/SphereParticles/thermalSphereShape/thermalSphereShape.hpp @@ -0,0 +1,222 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#ifndef pFlow_thermalSphereShape_hpp +#define pFlow_thermalSphereShape_hpp + +#include "sphereShape.hpp" + +namespace pFlow +{ + +/** + * @class thermalSphereShape + * @brief Maps global material thermal properties to specific discrete + * particle shapes. + * + * @details + * While `thermalProperty` acts as a global database of material properties + * (e.g., "Steel", "Glass"), this class assigns those macroscopic properties + * to specific geometric entities (e.g., "Small_Steel", "Large_Glass"). + * It inherits from the mechanical `sphereShape` and adds thermodynamic data + * arrays (Cp, k, emissivity, E0, nu) tailored to the number of defined shapes + * in the simulation. + */ +class thermalSphereShape +: + public sphereShape +{ +public: + + //- Type info + + TypeInfo("shape"); + +private: + + //- private members + + /// @brief Heat capacity mapped to each specific particle shape + /// [J/(kg.K)]. + realVector cp_; + + /// @brief Thermal conductivity mapped to each specific particle shape + /// [W/(m.K)]. + realVector k_; + + /// @brief Surface emissivity mapped to each specific particle shape + /// (dimensionless). + realVector emissivity_; + + /// @brief Real Young's Modulus mapped to each specific particle shape + /// [Pa]. + realVector E0_; + + /// @brief Poisson's ratio mapped to each specific particle shape + /// (dimensionless). + realVector nu_; + + /** + * @brief Initial temperature [K] assigned to newly inserted particles. + * + * When a batch of particles is inserted and no existing particles are + * present to sample from, this value is used as the initial + * temperature. + * + * Read from the property dictionary key 'insertionTemperature', which + * is mandatory: the case file must state this value explicitly rather + * than relying on a built-in default. + */ + real insertionTemperature_ = real(300); + + //- private methods + + /** + * @brief Populates the shape-specific thermal arrays. + * @details Reads the master material properties from the simulation + * dictionary and maps them to the local shape arrays using the + * shape-to-material ID index. + * @return True if mapping is successful. + */ + bool readThermalProperties(); + +protected: + + //- protected methods + + /** + * @brief Serializes both mechanical and thermal shape data to a + * dictionary. + * @param dict The target phasicFlow dictionary object. + * @return True if all data is successfully written. + */ + bool writeToDict(dictionary& dict) const override; + +public: + + //- constructors + + thermalSphereShape( + const word& fileName, + repository* owner, + const property& prop); + + thermalSphereShape( + const word& shapeType, + const word& fileName, + repository* owner, + const property& prop); + + ~thermalSphereShape() override = default; + + //- public methods + + // ================================================================= // + // Accessor Methods (Vector Level) + // ================================================================= // + + inline + realVector heatCapacities() const + { + return cp_; + } + + inline + realVector heatConductivities() const + { + return k_; + } + + inline + realVector emissivities() const + { + return emissivity_; + } + + inline + realVector realYoungsModuli() const + { + return E0_; + } + + inline + realVector poissonRatios() const + { + return nu_; + } + + // ================================================================= // + // Accessor Methods (Scalar Level for specific shape indices) + // ================================================================= // + + inline + real heatCapacity(uint32 i) const + { + return cp_[i]; + } + + inline + real heatConductivity(uint32 i) const + { + return k_[i]; + } + + inline + real emissivity(uint32 i) const + { + return emissivity_[i]; + } + + inline + real realYoungsModulus(uint32 i) const + { + return E0_[i]; + } + + inline + real poissonRatio(uint32 i) const + { + return nu_[i]; + } + + /** + * @brief Initial temperature for newly inserted particles [K]. + * + * Used by thermalSphereParticles::insertParticles() when the + * temperature field is empty (first insertion event) and no existing + * particle can be sampled from. Configured via the mandatory + * 'insertionTemperature' key in the property dictionary. + */ + inline + real insertionTemperature() const + { + return insertionTemperature_; + } + + add_vCtor(shape, thermalSphereShape, word); + +}; // thermalSphereShape + +} // pFlow + +#endif // pFlow_thermalSphereShape_hpp + + + diff --git a/src/Property/thermalProperty/thermalProperty.cpp b/src/Property/thermalProperty/thermalProperty.cpp new file mode 100644 index 000000000..e7db25b82 --- /dev/null +++ b/src/Property/thermalProperty/thermalProperty.cpp @@ -0,0 +1,171 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#include "thermalProperty.hpp" +#include "fileDictionary.hpp" + +namespace pFlow +{ + +//----------------------------- private methods ------------------------------- + +// ========================================================================= // +// Section 1: Dictionary I/O +// ========================================================================= // + +bool thermalProperty::readDictionary() +{ + uniquePtr thermoDictPtr = nullptr; + + // Dynamic path resolution + if (p_dir_ != nullptr) + { + thermoDictPtr = makeUnique( + "thermoPhysicalInteraction", + *p_dir_); + } + else + { + // Safe fallback for legacy code calling the default constructor + thermoDictPtr = makeUnique( + "thermoPhysicalInteraction", + fileSystem("caseSetup")); + } + + auto& thermoDict = thermoDictPtr(); + + // Read thermal properties + heatCapacities_ = + thermoDict.getVal("heatCapacities"); + + heatConductivities_ = + thermoDict.getVal("heatConductivities"); + + emissivities_ = + thermoDict.getVal("emissivities"); + + // Read mechanical properties from the base interaction dictionary + realYoungsModuli_ = + this->getVal("realYoungsModuli"); + + poissonRatios_ = + this->getVal("poissonRatios"); + + // Validate sizes against the materials list + bool isValid = + (materials().size() == heatCapacities_.size()) && + (materials().size() == heatConductivities_.size()) && + (materials().size() == emissivities_.size()) && + (materials().size() == realYoungsModuli_.size()) && + (materials().size() == poissonRatios_.size()); + + if (!isValid) + { + fatalErrorInFunction + << " Mismatch in the number of material properties between " + << "'interaction' and 'thermoPhysicalInteraction' dictionaries." + << endl; + fatalExit; + } + + return isValid; +} + +bool thermalProperty::writeDictionary() +{ + bool isWritten = + add("heatCapacities", heatCapacities_) && + add("heatConductivities", heatConductivities_) && + add("emissivities", emissivities_) && + add("realYoungsModuli", realYoungsModuli_) && + add("poissonRatios", poissonRatios_); + + if (!isWritten) + { + fatalErrorInFunction + << " Error in writing thermal properties to dictionary " + << globalName() << endl; + } + + return isWritten; +} + +//----------------------------- constructors ---------------------------------- + +// ========================================================================= // +// Section 2: Constructors +// ========================================================================= // + +thermalProperty::thermalProperty( + const word& fileName, + repository* owner) +: + property(fileName, owner) +{ + if (!readDictionary()) + { + fatalExit; + } +} + +thermalProperty::thermalProperty( + const word& fileName, + const fileSystem& dir) +: + property(fileName, dir), + p_dir_(&dir) +{ + if (!readDictionary()) + { + fatalExit; + } +} + +thermalProperty::thermalProperty( + const word& fileName, + const wordVector& materials, + const realVector& densities, + const realVector& heatCapacities, + const realVector& heatConductivities, + const realVector& emissivities, + const realVector& realYoungsModuli, + const realVector& poissonRatios, + repository* owner) +: + property(fileName, materials, densities, owner), + heatCapacities_(heatCapacities), + heatConductivities_(heatConductivities), + emissivities_(emissivities), + realYoungsModuli_(realYoungsModuli), + poissonRatios_(poissonRatios) +{ + if (!writeDictionary()) + { + fatalExit; + } +} + +//+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} // pFlow + + + + diff --git a/src/Property/thermalProperty/thermalProperty.hpp b/src/Property/thermalProperty/thermalProperty.hpp new file mode 100644 index 000000000..6e150c64b --- /dev/null +++ b/src/Property/thermalProperty/thermalProperty.hpp @@ -0,0 +1,183 @@ +/*------------------------------- phasicFlow --------------------------------- + O C enter of + O O E ngineering and + O O M ultiscale modeling of + OOOOOOO F luid flow +------------------------------------------------------------------------------ + Copyright (C): www.cemf.ir + email: hamid.r.norouzi AT gmail.com +------------------------------------------------------------------------------ +Licence: + This file is part of phasicFlow code. It is a free software for simulating + granular and multiphase flows. You can redistribute it and/or modify it under + the terms of GNU General Public License v3 or any other later versions. + + phasicFlow is distributed to help others in their research in the field of + granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +-----------------------------------------------------------------------------*/ + +#ifndef pFlow_thermalProperty_hpp +#define pFlow_thermalProperty_hpp + +#include "property.hpp" + +namespace pFlow +{ + +/** + * @class thermalProperty + * @brief Manages macroscopic thermal properties of materials in the simulation. + * + * @details + * Acts as the centralized database for thermodynamic material properties + * (e.g., heat capacity, conductivity, emissivity) loaded from the + * case dictionaries. It ensures that the mechanical and thermal + * definitions of materials remain strictly synchronized. + */ +class thermalProperty +: + public property +{ +public: + + //- Type info + + TypeInfo("thermalProperty"); + +private: + + //- private members + + // --- Section 2: Material Property Arrays --- + + realVector heatCapacities_; + + realVector heatConductivities_; + + realVector emissivities_; + + realVector realYoungsModuli_; + + realVector poissonRatios_; + + //- private methods + + // --- Section 3: File I/O --- + + bool readDictionary(); + + bool writeDictionary(); + +protected: + + //- protected members + + // --- Section 1: Internal Path Resolution --- + + /// @brief Safely caches the dictionary directory path. + const fileSystem* p_dir_ = nullptr; + +public: + + //- constructors + + // --- Section 4: Constructors --- + + explicit thermalProperty( + const word& fileName, + repository* owner = nullptr); + + thermalProperty( + const word& fileName, + const fileSystem& dir); + + thermalProperty( + const word& fileName, + const wordVector& materials, + const realVector& densities, + const realVector& heatCapacities, + const realVector& heatConductivities, + const realVector& emissivities, + const realVector& realYoungsModuli, + const realVector& poissonRatios, + repository* owner = nullptr); + + ~thermalProperty() override = default; + + //- public methods + + // --- Section 5: Vector Accessor Methods --- + + inline + const auto& heatCapacities() const + { + return heatCapacities_; + } + + inline + const auto& heatConductivities() const + { + return heatConductivities_; + } + + inline + const auto& emissivities() const + { + return emissivities_; + } + + inline + const auto& realYoungsModuli() const + { + return realYoungsModuli_; + } + + inline + const auto& poissonRatios() const + { + return poissonRatios_; + } + + // --- Section 6: Scalar Accessor Methods --- + + inline + real heatCapacity(uint32 i) const + { + return heatCapacities_[i]; + } + + inline + real heatConductivity(uint32 i) const + { + return heatConductivities_[i]; + } + + inline + real emissivity(uint32 i) const + { + return emissivities_[i]; + } + + inline + real realYoungsModulus(uint32 i) const + { + return realYoungsModuli_[i]; + } + + inline + real poissonRatio(uint32 i) const + { + return poissonRatios_[i]; + } + +}; // thermalProperty + +} // pFlow + +#endif // pFlow_thermalProperty_hpp + + + +