MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
oneDFlame.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "oneDFlame.h"
8#include "MEMORY/alloc.h"
9
10#if defined(WITH_CANTERA)
11using PtrCanteraSolution = typename std::shared_ptr<Cantera::Solution>;
12using PtrCanteraThermo = typename std::shared_ptr<Cantera::ThermoPhase>;
13using PtrCanteraKinetics = typename std::shared_ptr<Cantera::Kinetics>;
14using PtrCanteraTransport = typename std::shared_ptr<Cantera::Transport>;
15#endif
16
17OneDFlame::OneDFlame(MFloat T, MFloat p, MFloat* Y, MInt domainId, MInt solverId, std::vector<MString> speciesName)
18 : m_TInlet(T),
19 m_pInlet(p),
20 m_YInlet(Y),
21 m_domainId(domainId),
22 m_solverId(solverId),
23 m_speciesName(std::move(speciesName)) {
24// These lines allow Intel compilation when Cantera is not defined
25#if not defined(WITH_CANTERA)
26 (void)m_TInlet;
27 (void)m_pInlet;
28 (void)m_YInlet;
29 (void)m_rhoInlet;
30#endif
31
33}
34
35OneDFlame::~OneDFlame() = default;
36
38#if defined(WITH_CANTERA)
39
40 const MUint noSpecies = m_canteraThermo->nSpecies();
41
42 const MFloat UInlet = 0.1;
43
44 // MFloat phi = m_equivalenceRatio;
45 std::vector<MFloat> X(noSpecies, 0.0);
46
47 // given as molar fraction
48 // gas->setEquivalenceRatio(phi, "H2", "O2:0.21,N2:0.79");
49
50 std::vector<MFloat> YInlet(noSpecies, F0);
51 for(MUint s = 0; s < noSpecies; ++s) {
52 YInlet[s] = m_YInlet[s];
53 }
54
55 // set gas to correct thermodynamic state
56 m_canteraThermo->setState_TPY(m_TInlet, m_pInlet, &YInlet[0]);
57 m_canteraThermo->getMoleFractions(X.data());
58
59 m_rhoInlet = m_canteraThermo->density();
60
61 m_canteraThermo->equilibrate("HP");
62 std::vector<MFloat> YOutlet(noSpecies);
63 m_canteraThermo->getMassFractions(&YOutlet[0]);
64
65 MFloat rhoOutlet = m_canteraThermo->density();
66 MFloat adiabaticT = m_canteraThermo->temperature();
67
68 //-------- step 1: create the flow -------------
69 Cantera::StFlow flow(m_canteraThermo);
70 flow.setFreeFlow();
71
72 // create an initial grid
75 std::vector<MFloat> z(nz);
76 MFloat dz = lz / ((MFloat)(nz - 1));
77 for(int iz = 0; iz < nz; iz++) {
78 z[iz] = ((MFloat)iz) * dz;
79 }
80
81 flow.setupGrid(nz, &z[0]);
82
83 std::unique_ptr<Cantera::Transport> trmix(
84 Cantera::newTransportMgr(m_transportModel, m_canteraSolution->thermo().get()));
85
86 flow.setTransport(*trmix);
87 flow.setKinetics(*m_canteraSolution->kinetics());
88 flow.setPressure(m_pInlet);
89
90 //------- step 2: create the inlet -----------------------
91 Cantera::Inlet1D inlet;
92
93 inlet.setMoleFractions(X.data());
94 double massFlow = UInlet * m_rhoInlet;
95 inlet.setMdot(massFlow);
96 inlet.setTemperature(m_TInlet);
97
98 //------- step 3: create the outlet ---------------------
99 Cantera::Outlet1D outlet;
100
101 //=================== create the container and insert the domains =====
102 std::vector<Cantera::Domain1D*> domains{&inlet, &flow, &outlet};
103 Cantera::Sim1D flame(domains);
104
105 //----------- Supply initial guess----------------------
106 std::vector<MFloat> locs{0.0, 0.3, 0.7, 1.0};
107 std::vector<MFloat> value;
108
109 const double UOutlet = inlet.mdot() / rhoOutlet;
110 value = {UInlet, UInlet, UOutlet, UOutlet};
111 flame.setInitialGuess("velocity", locs, value);
112 value = {m_TInlet, m_TInlet, adiabaticT, adiabaticT};
113 flame.setInitialGuess("T", locs, value);
114
115 for(size_t i = 0; i < noSpecies; i++) {
116 value = {m_YInlet[i], m_YInlet[i], YOutlet[i], YOutlet[i]};
117 flame.setInitialGuess(m_canteraThermo->speciesName(i), locs, value);
118 }
119
120 inlet.setMoleFractions(X.data());
121 inlet.setMdot(massFlow);
122 inlet.setTemperature(m_TInlet);
123
124 MInt flowdomain = 1;
125 MFloat gridRatio = m_gridRatio; // 10
126 MFloat gridSlope = m_gridSlope; // 0.1
127 MFloat gridCurve = m_gridCurve; // 0.01
128 MFloat gridPrune = m_gridPrune;
129 MInt loglevel = (m_domainId == 0) ? 1 : 0;
130
131 flame.setRefineCriteria(flowdomain, gridRatio, gridSlope, gridCurve, gridPrune);
132
133 flame.setMaxTimeStepCount(10000);
134 flame.setMaxGridPoints(flowdomain, 10000);
135
136 flame.setFixedTemperature(0.5 * (m_TInlet + adiabaticT));
137
138 flame.solve(loglevel, false);
139 flow.solveEnergyEqn();
140 flame.solve(loglevel, true);
141
142 MFloat flameSpeedNew = flame.value(flowdomain, flow.componentIndex("velocity"), 0);
143 MFloat flameSpeedOld = 0.0;
144
145 gridRatio = 10.0;
146 MInt noIterations = 10;
147
148 // iterative 1D grid convergence
149 for(MInt iteration = 0; iteration < noIterations; ++iteration) {
150 gridSlope *= 0.5;
151 gridCurve *= 0.35;
152
153 flame.setRefineCriteria(flowdomain, gridRatio, gridSlope, gridCurve, gridPrune);
154
155 flame.solve(loglevel, true);
156
157 flameSpeedOld = flameSpeedNew;
158
159 flameSpeedNew = flame.value(flowdomain, flow.componentIndex("velocity"), 0);
160
161 MFloat relError = fabs(flameSpeedNew - flameSpeedOld) / fabs(flameSpeedNew);
162
163 if(relError < m_allowedRelError) break;
164 }
165
166 MInt noGridPoints = flow.nPoints();
167
168 // probably a better way
169 mAlloc(m_profile.velocity, noGridPoints, "velocity", -9999.9, AT_);
170 mAlloc(m_profile.temperature, noGridPoints, "temperature", -9999.9, AT_);
171 mAlloc(m_profile.massFractions, noSpecies * noGridPoints, "massFractions", -9999.9, AT_);
172
173 for(MInt n = 0; n < noGridPoints; ++n) {
174 m_profile.velocity[n] = flame.value(flowdomain, flow.componentIndex("velocity"), n);
175 m_profile.temperature[n] = flame.value(flowdomain, flow.componentIndex("T"), n);
176 m_grid.push_back(flow.grid(n));
177
178 for(MUint s = 0; s < noSpecies; ++s) {
179 m_profile.massFractions[noSpecies * n + s] = flame.value(flowdomain, flow.componentIndex(m_speciesName[s]), n);
180 }
181 }
182
183 ASSERT((MInt)m_grid.size() == noGridPoints,
184 "Vector m_oneGridSize has incorrect number of values, terminating now...");
185
186 std::vector<MFloat> dTdx(noGridPoints, 0.0);
187 MFloat maximumSlope = 0.0;
188 for(MInt n = 1; n < (noGridPoints - 1); ++n) {
189 MFloat deltaX = m_grid[n + 1] - m_grid[n - 1];
190 MFloat deltaT = m_profile.temperature[n + 1] - m_profile.temperature[n - 1];
191 dTdx[n] = deltaT / deltaX;
192 if(dTdx[n] > maximumSlope) maximumSlope = dTdx[n];
193 }
194
195 m_laminarFlameThickness = (m_profile.temperature[noGridPoints - 1] - m_profile.temperature[0]) / maximumSlope;
196
197 m_fixedTemperatureLocation = flame.fixedTemperatureLocation();
198#endif
199}
200
201void OneDFlame::log(MFloat cellLengthAtMaxRfnLevel) {
202 const MFloat requiredFlameResolution = 10.0;
203 if(m_domainId == 0) {
204 std::cerr << "Computed flame thickness: " << m_laminarFlameThickness << std::endl;
205 std::cerr << "Resolution at maximum refinement level: " << cellLengthAtMaxRfnLevel << std::endl;
206 std::cerr << "Flame front resolved by a total of " << m_laminarFlameThickness / cellLengthAtMaxRfnLevel << " cells"
207 << std::endl;
208 if(m_laminarFlameThickness / cellLengthAtMaxRfnLevel < requiredFlameResolution) {
209 std::cerr
210 << "Flame front is underresolved! Increase the refinement level to get an accurate solution! A resolution "
211 "of at least "
212 << requiredFlameResolution << "cells inside the flame front is required." << std::endl;
213 }
214 }
215}
216
217#if defined(WITH_CANTERA)
219 PtrCanteraThermo canteraThermo,
220 PtrCanteraKinetics canteraKinetics,
221 PtrCanteraTransport canteraTransport) {
222 m_canteraSolution = canteraSolution;
223 m_canteraThermo = canteraThermo;
224 m_canteraKinetics = canteraKinetics;
225 m_canteraTransport = canteraTransport;
226}
227#endif
228
230 // Default grid values through trial and error of succesfully converged one dimensional simulations
231 m_gridRatio = 5.0;
232 m_gridRatio = Context::getSolverProperty<MFloat>("gridRatio", m_solverId, AT_, &m_gridRatio);
233
234 m_gridSlope = 0.5;
235 m_gridSlope = Context::getSolverProperty<MFloat>("gridSlope", m_solverId, AT_, &m_gridSlope);
236
237 m_gridCurve = 0.3;
238 m_gridCurve = Context::getSolverProperty<MFloat>("gridCurve", m_solverId, AT_, &m_gridCurve);
239
240 m_gridPrune = -0.00005;
241 m_gridPrune = Context::getSolverProperty<MFloat>("gridPrune", m_solverId, AT_, &m_gridPrune);
242
243 m_noGridPoints = 10;
244 m_noGridPoints = Context::getSolverProperty<MInt>("noGridPoints", m_solverId, AT_, &m_noGridPoints);
245
246 m_domainLength = 0.03;
247 m_domainLength = Context::getSolverProperty<MFloat>("domainLength", m_solverId, AT_, &m_domainLength);
248
249 // Controls the number of iterations of the one dimensional simulation for a "converged" result (based on laminar
250 // burning speed)
251 m_allowedRelError = 0.001;
252 m_allowedRelError = Context::getSolverProperty<MFloat>("allowedRelError", m_solverId, AT_, &m_allowedRelError);
253
254 m_transportModel = Context::getSolverProperty<MString>("transportModel", m_solverId, AT_);
255}
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
Definition: alloc.h:173
MInt m_noGridPoints
Definition: oneDFlame.h:84
MFloat m_gridPrune
Definition: oneDFlame.h:83
const std::vector< MString > m_speciesName
Definition: oneDFlame.h:89
struct OneDFlame::@22 m_profile
const MInt m_solverId
Definition: oneDFlame.h:78
MString m_transportModel
Definition: oneDFlame.h:91
const MFloat m_TInlet
Definition: oneDFlame.h:74
const MFloat * m_YInlet
Definition: oneDFlame.h:76
void readProperties()
Definition: oneDFlame.cpp:229
std::vector< MFloat > m_grid
Definition: oneDFlame.h:54
MFloat m_rhoInlet
Definition: oneDFlame.h:73
MFloat m_domainLength
Definition: oneDFlame.h:85
const MInt m_domainId
Definition: oneDFlame.h:77
PtrCanteraThermo m_canteraThermo
Definition: oneDFlame.h:68
PtrCanteraSolution m_canteraSolution
Definition: oneDFlame.h:67
void log(MFloat)
Definition: oneDFlame.cpp:201
const MFloat m_pInlet
Definition: oneDFlame.h:75
MFloat m_gridSlope
Definition: oneDFlame.h:81
MFloat m_gridRatio
Definition: oneDFlame.h:80
MFloat m_fixedTemperatureLocation
Definition: oneDFlame.h:56
MFloat m_laminarFlameThickness
Definition: oneDFlame.h:57
void setCanteraObjects(PtrCanteraSolution, PtrCanteraThermo, PtrCanteraKinetics, PtrCanteraTransport)
Definition: oneDFlame.cpp:218
PtrCanteraTransport m_canteraTransport
Definition: oneDFlame.h:70
MFloat m_gridCurve
Definition: oneDFlame.h:82
MFloat m_allowedRelError
Definition: oneDFlame.h:87
PtrCanteraKinetics m_canteraKinetics
Definition: oneDFlame.h:69
void run()
Definition: oneDFlame.cpp:37
OneDFlame(MFloat, MFloat, MFloat *, MInt, MInt, std::vector< MString >)
Definition: oneDFlame.cpp:17
int32_t MInt
Definition: maiatypes.h:62
uint32_t MUint
Definition: maiatypes.h:63
double MFloat
Definition: maiatypes.h:52
typename std::shared_ptr< Cantera::Transport > PtrCanteraTransport
Definition: oneDFlame.cpp:14
typename std::shared_ptr< Cantera::ThermoPhase > PtrCanteraThermo
Definition: oneDFlame.cpp:12
typename std::shared_ptr< Cantera::Kinetics > PtrCanteraKinetics
Definition: oneDFlame.cpp:13
typename std::shared_ptr< Cantera::Solution > PtrCanteraSolution
Definition: oneDFlame.cpp:11
typename std::shared_ptr< Cantera::Transport > PtrCanteraTransport
Definition: oneDFlame.h:37
typename std::shared_ptr< Cantera::ThermoPhase > PtrCanteraThermo
Definition: oneDFlame.h:35
typename std::shared_ptr< Cantera::Kinetics > PtrCanteraKinetics
Definition: oneDFlame.h:36
typename std::shared_ptr< Cantera::Solution > PtrCanteraSolution
Definition: oneDFlame.h:34