main.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // This example shows the time-simulation of a 2D axisymmetric high-temperature superconductor (HTS):
  2. // a superconducting tube is used to shield its inside from an externally applied magnetic field
  3. // that increases linearly over time. For the simulation the so called a-v magnetodynamic formulation
  4. // is used. The v part can be disregarded in the configuration of this example.
  5. //
  6. // The tube height is 210 mm, its thickness is 1 mm and its inner radius is 10 mm.
  7. //
  8. // This example is based on and validated with the experimental and simulation work done by K. Hogan in his thesis
  9. // "Passive magnetic shielding with bulk high temperature superconductors under a non-uniform magnetic field".
  10. //
  11. // Details on the equations for HTS can also be found in "Numerical simulation of the magnetization of
  12. // high-temperature superconductors: a 3D finite element method using a single time-step iteration" (G. Lousberg)
  13. #include "sparselizardbase.h"
  14. using namespace mathop;
  15. void sparselizard(void)
  16. {
  17. // The physical region numbers as defined in the mesh file:
  18. int tube = 1, air = 2, domainskin = 3;
  19. setaxisymmetry();
  20. mesh mymesh("tubeinair.msh");
  21. // Define the whole domain for convenience:
  22. int wholedomain = regionunion({tube, air});
  23. // Magnetic permeability of the air:
  24. double mu = 4.0*getpi()*1e-7;
  25. // In this axisymmetric problem the magnetic vector potential can
  26. // be expressed as a vector with only a non-zero z component:
  27. field az("h1"), x("x");
  28. // Use interpolation order 1:
  29. az.setorder(wholedomain, 1);
  30. expression a = array3x1(0,0,az);
  31. // Put a magnetic wall (i.e. set field a to 0) all
  32. // around the domain (no magnetic flux can cross it):
  33. az.setconstraint(domainskin);
  34. // The magnetic vector potential a is rewritten as the sum of a known
  35. // source term and an unknown part to be determined: atotal = a + asource.
  36. // We want to apply an external induction field b of 1 mT in
  37. // the y direction that linearly increases over time:
  38. expression bsource = array3x1(0,1e-3*t(),0);
  39. // Since b = curl(a) (in cylindrical coordinates) a valid choice for a is:
  40. expression asource = array3x1(0,0,-1e-3*0.5*t()*x);
  41. // And dt(a)/dt is:
  42. expression dtasource = array3x1(0,0,-1e-3*0.5*x);
  43. // The strong form of the magnetodynamic a-v formulation is
  44. //
  45. // curl( 1/mu * curl(a) ) + sigma * (dt(a) + grad(v)) = js, with b = curl(a) and e = -dt(a) - grad(v)
  46. //
  47. // Here grad(v) is zero because of axisymmetry and y direction bsource and the electric field becomes:
  48. //
  49. expression e = -dt(a)-dtasource;
  50. // The conductivity of the high temperature superconductor is modeled using
  51. // a power law relation between the electric field and the current density:
  52. //
  53. // J = Jc/Ec^(1/n) * norm(E)^((1-n)/n) * E
  54. // |_______________________________|
  55. // sigma(E)
  56. //
  57. // where the critical current density Jc [A/m^2] and critical electric field Ec [V/m] are supposed
  58. // constant here and the J(E) relation is isotropic. An extra 1e-11 is added to never divide by 0.
  59. //
  60. double n = 30.0, Ec = 1e-4, Jc = 1e8;
  61. expression sigma = Jc/( pow(Ec,1.0/n) ) * pow( norm(e) + 1e-11, (1.0-n)/n );
  62. // Define the weak magnetodynamic formulation:
  63. formulation magdyn;
  64. magdyn += integral(wholedomain, 1/mu*( curl(dof(a)) + bsource ) * curl(tf(a)) );
  65. // Add an extra odd integration degree for convergence:
  66. magdyn += integral(tube, sigma*( dt(dof(a)) + dtasource )*tf(a), +1 );
  67. // Start the implicit Euler time resolution with an all zero solution and time derivative:
  68. vec initsol(magdyn), initdtsol(magdyn);
  69. impliciteuler eul(magdyn, initsol, initdtsol);
  70. // Tolerance on the nonlinear iteration:
  71. eul.settolerance(1e-4);
  72. // Use a 1 second timestep:
  73. double timestep = 1.0;
  74. // Run from 0 to 150 sec with a fixed-point nonlinear iteration at every timestep:
  75. std::vector<std::vector<vec>> sols = eul.runnonlinear(0.0, timestep, 150.0);
  76. // Field a is available at every timestep in sols[0] and its time derivative in sols[1]:
  77. std::vector<vec> asol = sols[0];
  78. std::vector<vec> dtasol = sols[1];
  79. // Loop over all time solutions:
  80. std::vector<double> bcenter(asol.size());
  81. for (int i = 0; i < asol.size(); i++)
  82. {
  83. // Set variable t() to the time of the current timestep:
  84. settime(timestep*i);
  85. // Make the data of vector asol[i] available in field az:
  86. az.setdata(wholedomain, asol[i]);
  87. // Write a and b = curl(a) to disk:
  88. norm(a).write(wholedomain, "norma" + std::to_string(i+1000) + ".vtu");
  89. norm(curl(a) + bsource).write(wholedomain, "normbtotal" + std::to_string(i+1000) + ".vtu");
  90. // Output the b induction field [T] at the tube center to assess the shielding effectiveness.
  91. // Interpolate at a x coordinate slightly away from 0 to avoid NaN issues:
  92. bcenter[i] = norm(curl(a) + bsource).interpolate(wholedomain, {1e-10,0,0})[0];
  93. std::cout << "b source " << timestep*i << " mT --> b tube center " << bcenter[i]*1e3 << " mT" << std::endl;
  94. }
  95. // Combine all timesteps in a ParaView .pvd file for convenience:
  96. std::vector<double> timestepvalues(151);
  97. for (int i = 0; i < 151; i++)
  98. timestepvalues[i] = timestep*i;
  99. grouptimesteps("normbtotal.pvd", "normbtotal", 1000, timestepvalues);
  100. // Write to file the field at the tube center for all timesteps:
  101. writevector("bcenter.csv", bcenter);
  102. // Code validation line. Can be removed:
  103. std::cout << (bcenter[asol.size()-1] < 0.03746 && bcenter[asol.size()-1] > 0.03744);
  104. }
  105. int main(void)
  106. {
  107. SlepcInitialize(0,{},0,0);
  108. sparselizard();
  109. SlepcFinalize();
  110. return 0;
  111. }