main.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // This code simulates the heating that arises when DC current flows through a tungsten conductor
  2. // with a thin central part. The DC current flow is calculated with an electrokinetic formulation
  3. // based on applied electric potentials at both ends and the temperature field is calculated
  4. // using the heat equation formulation, including the Joule heating due to the current flow.
  5. // The dependency of the tungsten resistivity and its thermal conductivity on the temperature is taken into
  6. // account. Because of this the problem is nonlinear and requires an iterative resolution to converge.
  7. #include "sparselizardbase.h"
  8. using namespace mathop;
  9. mesh createmesh(void);
  10. void sparselizard(void)
  11. {
  12. // Region number
  13. // - 1 corresponds to the whole volume
  14. // - 2 to the left face (input, electrically actuated)
  15. // - 3 to the right face (output, grounded)
  16. //
  17. int volume = 1, input = 2, output = 3;
  18. // Create the geometry and the mesh:
  19. mesh mymesh = createmesh();
  20. // Write to file for visualization:
  21. mymesh.write("meshed.msh");
  22. // Voltage [V] applied between the input and output faces:
  23. double appliedvoltage = 0.2;
  24. // Create the electric potential field v and temperature field T (both with nodal shape functions h1):
  25. field v("h1"), T("h1");
  26. // Use an order 2 interpolation for both fields:
  27. v.setorder(volume,2);
  28. T.setorder(volume,2);
  29. // Apply the requested voltage to the input and ground the output:
  30. v.setconstraint(input, appliedvoltage);
  31. v.setconstraint(output);
  32. // Assume the temperature is fixed to 293 K on the input and output faces:
  33. T.setconstraint(input, 293);
  34. T.setconstraint(output, 293);
  35. // The tungsten resistivity 'rho' [Ohm*m] is a function of the temperature (5.60e-8 at 293 K with a 0.0045 [K^-1] temperature coefficient):
  36. parameter rho, k;
  37. rho|volume = 5.6e-8*(1+0.0045*(T-293));
  38. // Its thermal conductivity varies from 173 to 118 [W/(m*K)] between 293 and 1000 K:
  39. k|volume = 173-(173-118)*(T-293)/(1000-293);
  40. // Expression for the electric field E [V/m] and current density j [A/m^2]:
  41. expression E = -grad(v);
  42. expression j = 1/rho * E;
  43. // Define the weak formulation for the static current flow.
  44. //
  45. // The strong form is:
  46. //
  47. // div(1/rho * grad(v)) = 0
  48. //
  49. // with E = -grad(v)
  50. //
  51. formulation electrokinetics;
  52. electrokinetics += integral(volume, grad(tf(v))*1/rho*grad(dof(v)));
  53. // Define the weak formulation for the heat equation.
  54. //
  55. // Can be found at https://en.wikiversity.org/wiki/Nonlinear_finite_elements/Weak_form_of_heat_equation
  56. //
  57. // Strong form is r*cp*dT/dt - div(k*grad(T)) = volumic heat sources [W/m^3]
  58. //
  59. // where r [kg/m^3] is the density and cp [J/(kg*K)] is the specific heat capacity.
  60. //
  61. formulation heatequation;
  62. // Here the time derivative is zero (static simulation):
  63. // heatequation += integral(volume, r*cp*dt(dof(T))*tf(T));
  64. heatequation += integral(volume, grad(tf(T))*k*grad(dof(T)));
  65. // Add the current heating source:
  66. heatequation += integral(volume, -j*E*tf(T));
  67. // Start with a uniform 293 K temperature everywhere:
  68. T.setvalue(volume, 293);
  69. // Initial all-zero solution vector for the heat equation:
  70. vec solheat(heatequation);
  71. double relres = 1;
  72. while (relres > 1e-7)
  73. {
  74. // Compute the static current everywhere:
  75. electrokinetics.generate();
  76. // Get A and b to solve Ax = b:
  77. vec solv = solve(electrokinetics.A(), electrokinetics.b());
  78. // Transfer the data from the solution vector to the v field to be used for the heat equation below:
  79. v.setdata(volume, solv);
  80. // Deduce the temperature field everywhere:
  81. heatequation.generate();
  82. // Get A and b to solve Ax = b:
  83. mat Aheat = heatequation.A();
  84. vec bheat = heatequation.b();
  85. // Compute a relative residual:
  86. relres = (bheat - Aheat*solheat).norm() / bheat.norm();
  87. // Solve Ax = b:
  88. solheat = solve(Aheat, bheat);
  89. // Transfer the data from the solution vector to the T field to be used for the electrokinetics above:
  90. T.setdata(volume, solheat);
  91. std::cout << "Current iteration has relative residual: " << relres << std::endl;
  92. }
  93. // Compute the total current flowing trough the input face.
  94. // Since the computation involves a gradient that has to be
  95. // calculated in the volume (and not on the input face)
  96. // one can not simply call (normal(input)*j).integrate(input,4)
  97. // since with this a surface gradient will be calculated.
  98. // 'on()' is called to force the evaluation in the volume.
  99. double I = (-normal(input)*on(volume, j)).integrate(input, 4);
  100. // Compute the electric resistance R between input and output:
  101. double R = appliedvoltage/I;
  102. std::cout << std::endl << "Resistance is " << R << " Ohm. Current is " << I << " A" << std::endl;
  103. // Compute the peak temperature on the whole volume:
  104. double peaktemperature = T.max(volume,2)[0];
  105. std::cout << "Peak temperature is " << peaktemperature << " K" << std::endl << std::endl;
  106. // Write v, j and T:
  107. v.write(volume, "v.pos");
  108. j.write(volume, "j.pos");
  109. T.write(volume, "T.pos");
  110. // Code validation line. Can be removed.
  111. std::cout << (peaktemperature < 618.446 && peaktemperature > 618.444 && I < 1851.30 && I > 1851.28);
  112. }
  113. mesh createmesh(void)
  114. {
  115. // Give names to the physical region numbers:
  116. int volume = 1, input = 2, output = 3;
  117. // Define the x, y and z coordinate fields:
  118. field x("x"), y("y"), z("z");
  119. double length = 0.2, thickness = 0.01, width = 0.05;
  120. // Define the 2D base to be extruded:
  121. shape leftquad("quadrangle", -1, {-length/2,-width/2,-thickness/2, -0.5*length/2,-width/2,-thickness/2, -0.5*length/2,width/2,-thickness/2, -length/2,width/2,-thickness/2}, {8,8,8,8});
  122. shape rightquad("quadrangle", -1, {0.5*length/2,-width/2,-thickness/2, length/2,-width/2,-thickness/2, length/2,width/2,-thickness/2, 0.5*length/2,width/2,-thickness/2}, {8,8,8,8});
  123. shape centralquad("quadrangle", -1, {-0.5*length/2,-width/2,-thickness/2, 0.5*length/2,-width/2,-thickness/2, 0.5*length/2,width/2,-thickness/2, -0.5*length/2,width/2,-thickness/2}, {16,8,16,8});
  124. // Extrude the 2D base:
  125. shape leftblock = leftquad.extrude(volume, thickness, 3);
  126. shape rightblock = rightquad.extrude(volume, thickness, 3);
  127. shape centralblock = centralquad.extrude(volume, thickness, 3);
  128. // Make the central block less large in the middle:
  129. centralblock.deform(0, 15*(abs(x)-0.5*length/2)*y, 0);
  130. // Make it also a little thinner (in the z direction) in the middle:
  131. centralblock.deform(0, 0, 15*(abs(x)-0.5*length/2)*z);
  132. // Get the input and output faces:
  133. shape inputface = leftblock.getsons()[4];
  134. shape outputface = rightblock.getsons()[2];
  135. // Assign the physical region numbers as detailed above:
  136. inputface.setphysicalregion(input);
  137. outputface.setphysicalregion(output);
  138. // Load to the mesh all shapes important for the finite element simulation:
  139. mesh mymesh({leftblock,rightblock,centralblock,inputface,outputface});
  140. // The mesh can be written at any time to have a feedback while creating the geometry!
  141. // mymesh.write("meshed.msh");
  142. return mymesh;
  143. }
  144. int main(void)
  145. {
  146. SlepcInitialize(0,{},0,0);
  147. sparselizard();
  148. SlepcFinalize();
  149. return 0;
  150. }