123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- // This code simulates the static magnetic field created by 5 permanent magnets (1cm x 1cm) placed side by side.
- // A steel region above the magnets is perturbing the magnetic field lines.
- //
- // The magnetic scalar potential is used to solve this problem. This is valid since there are no current sources.
- // The permanent magnets are treated as pre-magnetized pieces of non-magnetic material (since all magnetic domains are already fully oriented).
- #include "sparselizardbase.h"
- using namespace mathop;
- void sparselizard(void)
- {
- // The domain regions as defined in 'halbacharray.geo':
- int magnet1 = 1, magnet2 = 2, magnet3 = 3, magnet4 = 4, magnet5 = 5, steel = 6, air = 7, zeropotential = 8;
- // The mesh can be curved!
- mesh mymesh("halbacharray.msh");
- // Define new physical regions for convenience:
- int magnets = regionunion({magnet1, magnet2, magnet3, magnet4, magnet5});
- int wholedomain = regionunion({magnets, steel, air});
- // Nodal shape functions 'h1' for the magnetic scalar potential 'phi'.
- field phi("h1");
- // Use interpolation order 2 on the whole domain:
- phi.setorder(wholedomain, 2);
- // The magnetic scalar potential (just like the electric potential)
- // needs to be fixed at least at one node to have a well-posed problem.
- // Here it is forced to 0 at a permanent magnet corner point.
- phi.setconstraint(zeropotential);
- // Vacuum magnetic permeability [H/m]:
- double mu0 = 4*getpi()*1e-7;
- // Define the permeability in all regions:
- parameter mu;
- mu|air = mu0;
- mu|steel = 1000*mu0;
- mu|magnets = mu0;
- formulation magnetostatic;
- // In the absence of current sources the static Maxwell equations give:
- //
- // curl h = 0
- //
- // One can thus define a magnetic scalar potential 'phi' such that h = -grad(phi).
- //
- // Considering also that div(b) = 0 we get
- //
- // div(mu*(-grad(phi))) = 0
- //
- // with b = mu * h.
- //
- // In the permanent magnet region b = mu0 * (h + m),
- // i.e. the material is non-magnetic but it is pre-magnetized by the magnetization vector m [A/m].
- // We thus get:
- // div(mu0*(-grad(phi)) + mu0*m) = 0
- //
- // A permanent magnet with a [0, 800e3] A/m magnetization is considered.
- // The weak form corresponding to the above equations:
- magnetostatic += integral(wholedomain, -grad(dof(phi)) * mu * grad(tf(phi)) );
- // This is when all magnets are oriented in the y direction:
- magnetostatic += integral(magnets, array2x1(0, 800e3) * mu * grad(tf(phi)) );
- // This is in Halbach configuration (to maximise the magnetic field above the array):
- //magnetostatic += integral(magnet1, array2x1(-800e3, 0) * mu * grad(tf(phi)) );
- //magnetostatic += integral(magnet2, array2x1(0, -800e3) * mu * grad(tf(phi)) );
- //magnetostatic += integral(magnet3, array2x1(800e3, 0) * mu * grad(tf(phi)) );
- //magnetostatic += integral(magnet4, array2x1(0, 800e3) * mu * grad(tf(phi)) );
- //magnetostatic += integral(magnet5, array2x1(-800e3, 0) * mu * grad(tf(phi)) );
- magnetostatic.generate();
- // Solve the algebraic system Ax = b:
- vec sol = solve(magnetostatic.A(), magnetostatic.b());
- // Transfer the data from the solution vector to the phi field:
- phi.setdata(wholedomain, sol);
- // Write the magnetic scalar potential and the magnetic field with an order 2 interpolation.
- phi.write(wholedomain, "phi.pos", 2);
- norm(-grad(phi)).write(wholedomain, "hnorm.pos", 2);
- (-grad(phi)).write(wholedomain, "h.pos");
-
- // Evaluate the magnetic field 1.5cm above the center of the magnet array:
- std::vector<double> magfieldnorm = norm(-grad(phi)).interpolate(wholedomain, {0,0.02,0});
- std::cout << "Magnetic field 1.5cm above the array center: " << magfieldnorm[0] << " A/m" << std::endl;
- // Write 20 magnetic field lines starting on the top side of the magnet array:
- shape ln("line", -1, {-0.025,0.01,0, 0.025,0.01,0}, 20);
- (-grad(phi)).streamline(regionexclusion(wholedomain, magnets), "magneticfieldline.pos", ln.getcoords(), 0.01/5);
- // The MAGNETOSTATIC FORCE acting on the steel disk is computed below.
-
- // This field will hold the x and y component of the magnetic forces:
- field magforce("h1xy");
- // The magnetic force is projected on field 'magforce' on the steel region.
- // This is done with a formulation of the type dof*tf - force calculation = 0.
- formulation forceprojection;
- forceprojection += integral(steel, dof(magforce)*tf(magforce));
- // The force term integral must be performed on all elements in the steel region AND in the ELEMENT LAYER AROUND.
- // This is obtained by considering the elements on the whole domain 'wholedomain'. Since the force must only be
- // calculated on the steel disk, the test functions are only selected on the steel (this is done with tf(..., steel)).
- forceprojection += integral(wholedomain, - predefinedmagnetostaticforce(tf(magforce, steel), -grad(phi), mu));
- forceprojection.generate();
- vec solf = solve(forceprojection.A(), forceprojection.b());
- magforce.setdata(wholedomain, solf);
- std::cout << "Force acting on the steel disk (fx, fy) = (" << compx(magforce).integrate(steel, 5) << ", " << compy(magforce).integrate(steel, 5) << ") N per unit depth" << std::endl;
- // Code validation line. Can be removed.
- std::cout << (magfieldnorm[0] < 64963.8 && magfieldnorm[0] > 64963.6);
- }
- int main(void)
- {
- SlepcInitialize(0,{},0,0);
- sparselizard();
- SlepcFinalize();
- return 0;
- }
|