1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
|
/**
* Create thermal profile, characteristics of the profile can be adapted.
* Writes <tt>thermalprofile.h</tt> and prints values to stdout, you can view
* them using gnuplot or something else.
*
*
* Jens Wilhelm Wulf
*/
/**
* Was habe ich mir dabei gedacht?
* Fr den inneren Teil wollte ich eine Funktion dritter Ordnung haben, damit
* die folgenden Forderungen erfllbar sind:
* 1. Steigung=0 bei x=0
* 2. Nullstelle bei x=r
* 3. Einstellbare Steigung bei x=r, damit es einen stetigen bergang zur
* ueren Funktion gibt.
*
* Daher schreibe ich mal
* f_i(x) = (x-r)(x-p)(x+A)
* Nun soll aber auch gelten: f_i(x=0) = 0. Daher braucht man einen Nenner und
* erhlt
* f_i(x) = (x-r)(x-p)(x+A) / (r*p*A)
* Der Parameter r ist nicht frei, den er gibt das Ende des inneren Teils an.
* Dann hat man noch zwei freie Parameter (p, A). Die erste Ableitung von
* f_i(x) ist
* f_i'(x) = [3x^2 + 2x(A-p-r) -pA -Ar +pr] / (pAr)
* Sie soll bei x=0 null sein. Daraus ergibt sich
* 0 = -pA -Ar +pr
* A = pr/(p+r)
* Die erste Ableitung bei x=r ergibt sich damit zu
* f_i'(x=r) = [r^2 + Ar - pr - pA] / (pAr)
* f_i'(x=r) = [r^2 + pr - 2p^2] / (p^2 r)
* Zunchst wird p mit p>r vorgegeben. Damit wird die Ableitung am Rand berechnet und das Volumen des
* inneren Teils.
*
* Der uere Teil muss folgende Bedingung erfllen:
* 1. Funktionswert=0 bei x_e=1-r
* 2. Steigung=0 bei x_e
* 3. Funktionswert=0 bei x=0
* 4. Eine bestimmte Steigung bei x=0. Die Steigung wird durch die innere Funktion vorgegeben.
* 5. Sie muss in Y-Richtung skalierbar sein.
* Damit kommt man schnell zu der Grundfunktion
* f_a(x) = m x (x-x_e)^2 (x+c)
* Wobei man c noch so bestimmen muss, dass die Steigung bei x=0 den Wert s hat. Die Ableitung ist
* f_a'(x) = m * [4x^3 + 3x^2(c-2x_e) +2x(x^2+2 x_e c) + (x_e)^2 c]
* Somit muss gelten
* c = s / [m (x_e)^2]
*
*
* Nun wrde ich gerne auch ein Profil machen, was dem der alten Simulation etwas nher kommt.
* Wenn das mit einfachen Formeln zu beschreiben sein soll, muss ich mir den stetigen
* Steigungsverlauf an der Trennstelle abschminken.
* In der Mitte benutze ich einfach x^10. Es gelten die Bedingungen:
* 1. Steigung=0 bei x=0
* 2. Nullstelle bei x=r
* Daraus ergibt sich
* f_i(x) = 1 - (x^10 / r^10)
* f_i'(x) = -10/r^10 x^9
* f_i'(x=r) = -10/r
*/
#include <iostream>
#include <fstream>
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
// Define PROFTYPE to 0 for the original new style thermal.
// Define PROFTYPE to 1 for something which is similar to an old style thermal.
#define PROFTYPE 0
/**
* compute formula for inner part of thermal
*/
double getVelocityCenter(double dDist,
double dRadiusCenter,
double dPar)
{
#if (PROFTYPE == 0)
double A;
A = dRadiusCenter * dPar / (dRadiusCenter + dPar);
return(
(dDist-dRadiusCenter) * (dDist-dPar) * (dDist + A)
/
(dRadiusCenter*dPar*A)
);
#endif
#if (PROFTYPE == 1)
return(1 - (pow(dDist, 10)/pow(dRadiusCenter, 10)) );
#endif
}
/**
* compute first derivation of inner part at its end
* (dDist = dRadiusCenter)
*/
double getCenterDer(double dRadiusCenter,
double dPar)
{
#if (PROFTYPE == 0)
return(
(dRadiusCenter*dRadiusCenter + dPar*dRadiusCenter - 2*dPar*dPar)
/
(dPar*dPar*dRadiusCenter)
);
#endif
#if (PROFTYPE == 1)
return(-10/dRadiusCenter);
#endif
}
/**
* compute formula for outer part of thermal
*/
double getVelocityOuter(double dDist,
double dRadiusCenter,
double dMul,
double dDer)
{
double dXe = 1 - dRadiusCenter;
double dX = dDist - dRadiusCenter;
return(
dMul * dX * (dX - dXe) * (dX - dXe) * (dX +
( dDer / (dMul*dXe*dXe) )
)
);
}
int main()
{
/** Adjust to your needs: */
// size of center:
double dRadiusCenter = 0.35;
// affects transition (algorithm may need to adjust this value)
double dPar = dRadiusCenter * 10; // multiplier has to be >= 1
// size of table
int nBits = 6;
/** There is nothing to edit below ! */
double dStep = 1.0/(1<<nBits);
double dDer;
double dMul;
dDer = getCenterDer(dRadiusCenter, dPar);
// Calculate volume of inner part
double dVI = 0;
for (double x=0; x<dRadiusCenter; x+= dStep)
{
double dY = getVelocityCenter(x, dRadiusCenter, dPar);
dVI += M_PI * dY * (2*x*dStep + dStep*dStep);
}
// Adjust dMul to get inner volume = outer volume
dMul = -1;
double dVO;
do
{
std::cerr << "Steigung = " << dDer << "\n";
// Calculate volume of outer part
dVO = 0;
for (double x=dRadiusCenter; x<1; x+= dStep)
{
double dY = getVelocityOuter(x, dRadiusCenter, dMul, dDer);
dVO -= M_PI * dY * (2*x*dStep + dStep*dStep);
}
dMul = dMul * dVI/dVO;
/*
std::cerr << "inner volume: " << dVI << " "
<< "dMul = " << dMul << " outer volume = " << dVO << "\n";
*/
if (fabs(dMul) < 1.0E-20)
{
std::cerr << "...had to adjust...\n";
#if (PROFTYPE == 0)
dPar *= 0.8;
if (dPar < dRadiusCenter)
dPar = dRadiusCenter;
dDer = getCenterDer(dRadiusCenter, dPar);
#endif
#if (PROFTYPE == 1)
dDer = dDer / 2;
#endif
dMul = -1;
}
}
while (fabs((dVI - dVO)/dVI) > 0.01);
std::ofstream outfile;
outfile.open("thermalprofile.h");
outfile << "#ifndef THERMALPROFILE_H\n";
outfile << "#define THERMALPROFILE_H\n";
outfile << "// PROFTYPE = " << (int)(PROFTYPE) << "\n";
std::cout << "# PROFTYPE = " << (int)(PROFTYPE) << "\n";
outfile << "const double ThermalRadius = " << dRadiusCenter << ";\n";
std::cout << "# const double ThermalRadius = " << dRadiusCenter << ";\n";
outfile << "const int ThermalProfile_bits = " << nBits << ";\n";
outfile << "const double ThermalProfile[] = {\n";
double mx = 1;
double my = 1;
// double mx = 2.3;
// double my = 1.5;
// double mx = 1.5;
// double my = 2.5;
for (double x=0; x<dRadiusCenter; x+= dStep)
{
double dTmp = getVelocityCenter(x, dRadiusCenter, dPar);
std::cout << (mx*x/dRadiusCenter) << " " << (my*dTmp) << "\n";
outfile << " " << dTmp << ",\n";
}
for (double x=dRadiusCenter; x<1; x+= dStep)
{
double dTmp = getVelocityOuter(x, dRadiusCenter, dMul, dDer);
std::cout << (mx*x/dRadiusCenter) << " " << (my*dTmp) << "\n";
outfile << " " << dTmp << ",\n";
}
// one more value to get a faster interpolation code
outfile << " 0};\n";
outfile << "#endif\n";
}
|