From f0cb67780234e637edf735f6597627290831cb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Henrotte?= <francois.henrotte@uclouvain.be> Date: Fri, 12 Oct 2018 17:07:39 +0200 Subject: [PATCH] tuto shape optimization in Magnetostatics --- Ccore/ccore.geo | 167 +++++++++++++++ Ccore/ccore.pro | 457 +++++++++++++++++++++++++++++++++++++++++ Ccore/ccore_common.pro | 62 ++++++ Ccore/shp.plt | 53 +++++ Ccore/shp.py | 245 ++++++++++++++++++++++ 5 files changed, 984 insertions(+) create mode 100644 Ccore/ccore.geo create mode 100644 Ccore/ccore.pro create mode 100644 Ccore/ccore_common.pro create mode 100644 Ccore/shp.plt create mode 100644 Ccore/shp.py diff --git a/Ccore/ccore.geo b/Ccore/ccore.geo new file mode 100644 index 0000000..348dff3 --- /dev/null +++ b/Ccore/ccore.geo @@ -0,0 +1,167 @@ + +/* + All geometrical parameters of the model are used in both + Gmsh (CAO) and GetDP (shape optimisation). + They are therefore defined in the file "ccore_common.pro". +*/ + +Include "ccore_common.pro"; + +// The mesh refinement factor is rather a global user parameter, +// therefore defined as a Onelab variable. +R = DefineNumber[1, Name "Model/Parameters/Mesh refinement factor", + Help "R=5 far raw mesh, R=1 normal mesh"]; + +// Center C-core in air box +CoreX=(L-A)/2; // X-position of C-core's bottom left corner +CoreY=(L-B)/2; // Y-position of C-core's bottom left corner + +// external boundary +lc1=L/10.*R; + +Point(1) = {0,0,0,lc1}; +Point(2) = {L,0,0,lc1}; +Point(3) = {L,L,0,lc1}; +Point(4) = {0,L,0,lc1}; +Line(1) = {1,2}; +Line(2) = {2,3}; +Line(3) = {3,4}; +Line(4) = {4,1}; +Curve Loop(1) = {1 ... 4}; + +// magnetic C-core + +lc2=A/10.*R; +lc3=D/2.*R; + +Point(5) = {CoreX,CoreY,0,lc2}; +Point(6) = {CoreX+A,CoreY,0,lc2}; +Point(7) = {CoreX+A,CoreY+(B-D)/2.,0,lc3}; +Point(8) = {CoreX+A-E,CoreY+(B-D)/2.,0,lc3}; +Point(9) = {CoreX+A-E,CoreY+E,0,lc2}; +Point(10) = {CoreX+E,CoreY+E,0,lc2}; +Point(11) = {CoreX+E,CoreY+B-E,0,lc2}; +Point(12) = {CoreX+A-E,CoreY+B-E,0,lc2}; +Point(13) = {CoreX+A-E,CoreY+(B+D)/2.,0,lc3}; +Point(14) = {CoreX+A,CoreY+(B+D)/2.,0,lc3}; +Point(15) = {CoreX+A,CoreY+B,0,lc2}; +Point(16) = {CoreX,CoreY+B,0,lc2}; + +Line(5) = {5,6}; +Line(6) = {6,7}; +Line(7) = {7,8}; +Line(8) = {8,9}; +Line(9) = {9,10}; +Line(10) = {10,11}; +Line(11) = {11,12}; +Line(12) = {12,13}; +Line(13) = {13,14}; +Line(14) = {14,15}; +Line(15) = {15,16}; +Line(16) = {16,5}; + +Curve Loop(2) = {5 ... 16}; + +// inductors + +lc4=lc2; //F/2.*R; + +Point(17) = {CoreX+E+F,CoreY+E+F,0,lc4}; +Point(18) = {CoreX+E+F+G,CoreY+E+F,0,lc4}; +Point(19) = {CoreX+E+F+G,CoreY+B-E-F,0,lc4}; +Point(20) = {CoreX+E+F,CoreY+B-E-F,0,lc4}; +Line(17) = {17,18}; +Line(18) = {18,19}; +Line(19) = {19,20}; +Line(20) = {20,17}; + +Curve Loop(3) = {17 ... 20}; + +Point(21) = {CoreX-F-G,CoreY+E+F,0,lc4}; +Point(22) = {CoreX-F,CoreY+E+F,0,lc4}; +Point(23) = {CoreX-F,CoreY+B-E-F,0,lc4}; +Point(24) = {CoreX-F-G,CoreY+B-E-F,0,lc4}; +Line(21) = {21,22}; +Line(22) = {22,23}; +Line(23) = {23,24}; +Line(24) = {24,21}; + +Curve Loop(4) = {21 ... 24}; + + +Plane Surface(1) = {1,2,3,4}; +Plane Surface(2) = {2}; +Plane Surface(3) = {3}; +Plane Surface(4) = {4}; + + +Physical Surface("AIR", 1) = 1; +Physical Surface("CORE", 2) = 2; +Physical Surface("COILP", 3) = 3; +Physical Surface("COILN", 4) = 4; + +Physical Line("DIR", 11) = {1 ... 4}; + + +/* + The remainder of the file is a generic block of commands + for the automatic computation of velocity fields. + It should be copied unmodified at the bottom + of all shape optimisation .geo files. + */ + +DefineConstant[ + PerturbMesh = 0 + VelocityTag = -1 + Perturbation = 1e-10 + modelpath = CurrentDir +]; + +If(PerturbMesh == 1) + Printf("Computing velocity field ..."); + modelName = StrPrefix(StrRelative(General.FileName)); + + SyncModel; + + // Merge the original mesh + Merge StrCat(modelpath, modelName, ".msh"); + + // create a view with the original node coordinates as a vector dataset + Plugin(NewView).NumComp = 3; + Plugin(NewView).Run; + Plugin(ModifyComponents).View = 0; + Plugin(ModifyComponents).Expression0 = "x"; + Plugin(ModifyComponents).Expression1 = "y"; + Plugin(ModifyComponents).Expression2 = "z"; + Plugin(ModifyComponents).Run; + Save View[0] StrCat(modelpath, Sprintf("view_%g.msh",0)); + + // relocate the vertices of the original mesh on the perturbed geometry + + RelocateMesh Point "*"; + RelocateMesh Line "*"; + RelocateMesh Surface "*"; + + // Create a view with the perturbed node coordinates as vector dataset + Plugin(NewView).NumComp = 3; + Plugin(NewView).Run; + Plugin(ModifyComponents).View = 1; + Plugin(ModifyComponents).Expression0 = "x"; + Plugin(ModifyComponents).Expression1 = "y"; + Plugin(ModifyComponents).Expression2 = "z"; + Plugin(ModifyComponents).Run; + Save View[1] StrCat(modelpath, Sprintf("view_%g.msh",1)); + + // compute the velocity field by subtracting the two vector datasets + Plugin(ModifyComponents).View = 0; + Plugin(ModifyComponents).OtherView = 1; + Plugin(ModifyComponents).Expression0 = Sprintf("(w0 - v0)/(%g)", Perturbation); + Plugin(ModifyComponents).Expression1 = Sprintf("(w1 - v1)/(%g)", Perturbation); + Plugin(ModifyComponents).Expression2 = Sprintf("(w2 - v2)/(%g)", Perturbation); + Plugin(ModifyComponents).Run; + View.Name = "velocity"; + Save View[0] StrCat(modelpath, Sprintf("view_%g.msh",2)); + Delete View[1]; + Save View[0] StrCat(modelpath, Sprintf("velocity_%g.msh",VelocityTag)); + SendToServer View[0] Sprintf("Optimization/Results/velocity_%g",VelocityTag); +EndIf diff --git a/Ccore/ccore.pro b/Ccore/ccore.pro new file mode 100644 index 0000000..e32cb7f --- /dev/null +++ b/Ccore/ccore.pro @@ -0,0 +1,457 @@ +Include "ccore_common.pro"; + +DefineConstant[ + R_ = {"GetPerformances", Name "GetDP/1ResolutionChoices", Visible 0} + C_ = {"-solve -v 5 -v2", Name "GetDP/9ComputeCommand", Visible 0} + P_ = {"", Name "GetDP/2PostOperationChoices", Visible 0} + VelocityTag = -1 + OptiIterNumber = 0 +]; + + +NL_tol_abs = 1e-8; // absolute tolerance on residual for noninear iterations +NL_tol_relax = 1.0; // relaxation on residual for noninear iterations +NL_iter_max = 50; // maximum number of noninear iterations +Flag_NL = + DefineNumber[ 1, Name "Model/Parameters/Non linear core material", Choices {0,1}]; +murCore = + DefineNumber[300, Name "Model/Parameters/Mur core", Visible 1,//!Flag_NL, + Help "Magnetic relative permeability of Core"]; +Flag_Jfixed = + DefineNumber[ 1, Name "Model/Parameters/Fixed current density", Choices {0,1}]; +CurrentDensity = 1e6 * + DefineNumber[1, Name "Model/Parameters/Current Density", Visible Flag_Jfixed, + Help "Current density in coil [A/mm2]"]; +NbTurns = 300; +Current = + DefineNumber[CurrentDensity*CoilSection_ref/NbTurns, + Name "Model/Parameters/Current [A]", Visible !Flag_Jfixed, + Help "Current in coil [A]"]; + +CoilSection = G*(B-2*E-2*F); +If(Flag_Jfixed) + Mmf = CurrentDensity * CoilSection; + Current = Mmf / NbTurns; +Else + Mmf = NbTurns * Current; + CurrentDensity = Mmf / CoilSection; +EndIf + +By_target = 1.; +Px_target = CoreX + A - E/2 ; +Py_target = CoreY + B/2 ; + +Group { + // Physical regions (in capital letters): + AIR = Region[ 1 ]; + CORE = Region[ 2 ]; + COILP = Region[ 3 ]; + COILN = Region[ 4 ]; + NOFLUX = Region[ 11 ]; + + // Abstract regions + Vol_Mag = Region[ {AIR, CORE, COILP, COILN} ]; + Vol_S_Mag = Region[ {COILP, COILN} ]; + Sur_Dir_Mag = Region[ {NOFLUX} ]; + Sur_Neu_Mag = Region[ {} ]; + + Vol_NL_Mag = Region[ {} ]; + If(Flag_NL) + Vol_NL_Mag = Region[ {CORE} ]; + EndIf + Vol_L_Mag = Region[ {Vol_Mag,-Vol_NL_Mag} ]; +} + +Function { + mu0 = 4.e-7 * Pi ; + nu0 = 1. / mu0 ; + + nu [ Region[{AIR, COILP, COILN}] ] = nu0; + + Mat_h_r = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 250, + 300, 400, 500, 600, 700, 800, 900, 1000, 1250, 1500, 2000, 2500, 5000, + 7500, 10000, 15000, 20000, 59000, 174000, 514000, 1520000, 4470000, + 13200000, 38900000, 115000000, 339000000, 1000000000 } ; + Mat_b_r = { 0.0, 0.194880829963, 0.377143018857, 0.537767739762, 0.672888260835, + 0.783043000477, 0.871342430831,0.941778611986, 0.998183303557, 1.04378111223, + 1.08110469369, 1.14963767549, 1.19607212343, 1.22964695907, 1.25515221835, + 1.29162498935, 1.31678879432, 1.35015120537, 1.37220092877, 1.38859114656, + 1.4017440574, 1.41287024565, 1.42264180514, 1.43146158921, 1.45082466146, + 1.46784549989, 1.49819370601, 1.52578650709, 1.64314027719, 1.73458485332, + 1.8039068939,1.89568786291, 1.95213815187, 2.1390774927, 2.45827909293, + 3.32303272825, 5.85485500678, 13.2701832298, 35.2114648741, 99.8027446541, + 291.062951228, 854.036370229, 2515.3105707 } ; + + Mat_b2_r = Mat_b_r()^2; + Mat_nu_r = Mat_h_r()/Mat_b_r(); + Mat_nu_r(0) = Mat_nu_r(1); + Mat_nu_b2_r = ListAlt[Mat_b2_r(), Mat_nu_r()]; + nu_interp_r[] = InterpolationLinear[ SquNorm[$1] ]{Mat_nu_b2_r()}; + dnudb2_interp_r[] = dInterpolationLinear[SquNorm[$1]]{Mat_nu_b2_r()}; + h_interp_r[] = nu_interp_r[$1] * $1 ; + + If(!Flag_NL) + nu [ CORE ] = nu0/murCore; + dhdb_NL[ CORE ] = 0; + mu_analytic = mu0*murCore; + Else + nu [ Vol_NL_Mag ] = nu_interp_r[$1] ; + dhdb_NL[ Vol_NL_Mag ] = 2*dnudb2_interp_r[$1#2]*SquDyadicProduct[#2]; + mu_analytic = 1/Mat_nu_r(0); + EndIf + + // shape function of J : js[] = nI * Jshape[] + Jshape[ COILP ] = Vector[0,0,+1]/CoilSection; + Jshape[ COILN ] = Vector[0,0,-1]/CoilSection; + js[] = Mmf * Jshape[]; + + // Analytical solution + RelGap = D/(mu0*E); + RelCore = (2*(A+B-2*E)-D)/(mu_analytic*E); + Flux = NbTurns*Mmf/(RelGap+RelCore); // analytic approximation + SetNumber("Model/Results/Flux analytic", Flux); + //Flux = 0; + If( ParamIndex == 0 ) // D + dFluxdTau = Flux/E*Flux/(NbTurns*Mmf)*(1/mu_analytic-1/mu0); + ElseIf( ParamIndex == 1 ) // E + dFluxdTau = Flux/E*(1.+4*Flux/(NbTurns*Mmf*mu_analytic)); + If( Flag_Jfixed ) + dFluxdTau -= 2*Flux*G/CoilSection; + EndIf + ElseIf( ParamIndex == 2 ) // F + dFluxdTau = 0; + EndIf + + + VV[] = Vector[$1,$2,0*$3] ; + dV[] = TensorV[$1,$2,0*$3] ; + Lie2form[] = TTrace[$2]*$1 - Transpose[$2]*$1; // $1=2-form (vector field), $2=dV (tensor) + + If(Flag_Jfixed) + LieOf_js[] = Lie2form[js[], $1]; // $1=dV + Else + LieOf_js[] = 0; + EndIf + + // Lie derivative of H(B) where B is a 2-form and H a 1-form ($1:{d a}, $2:dV) + LieOf_HB[] = nu[$1] * (Transpose[$2] * $1 - TTrace[$2] * $1 + $2 * $1) ; + LieOf_HB_NL[] = dhdb_NL[$1] * (Transpose[$2] - TTrace[$2] * TensorDiag[1,1,1]) * $1; +} + + + +Group { + Dom_Hcurl_a_Mag_2D = Region[ {Vol_Mag, Sur_Neu_Mag} ]; +} + +Function{ + l_a = ListFromServer["Optimization/Results/a"]; + aFromServer[] = ValueFromIndex[]{l_a()}; + For i In {1:3} + l_v~{i} = ListFromServer[Sprintf["Optimization/Results/velocity_%g_%g",VelocityTag,i]]; + velocity~{i}[] = ValueFromIndex[]{l_v~{i}()}; + EndFor +} + +Constraint { + { Name Dirichlet_a_Mag; + Case { + { Region NOFLUX; Type Assign; Value 0; } + } + } + { Name aFromServer; + Case { + { Region Vol_Mag; Type Assign; Value aFromServer[]; } + { Region NOFLUX; Type Assign; Value 0; } + } + } + For i In {1:3} + { Name velocity~{i} ; + Case { + { Region Vol_Mag ; Value velocity~{i}[]; } + } + } + EndFor +} + + + +FunctionSpace { + { Name Hcurl_a_2D; Type Form1P; + BasisFunction { + { Name se; NameOfCoef ae; Function BF_PerpendicularEdge; + Support Dom_Hcurl_a_Mag_2D ; Entity NodesOf[ All ]; } + } + Constraint { + { NameOfCoef ae; EntityType NodesOf; + NameOfConstraint Dirichlet_a_Mag; } + } + } + + { Name Hcurl_a_2D_fullyfixed; Type Form1P; + BasisFunction{ + { Name se1; NameOfCoef ae1; Function BF_PerpendicularEdge; + Support Vol_Mag; Entity NodesOf[All]; } + } + Constraint{ + { NameOfCoef ae1; EntityType NodesOf; NameOfConstraint aFromServer; } + } + } + For i In {1:3} + { Name H_v~{i} ; Type Form0; + BasisFunction { + { Name sn ; NameOfCoef un ; Function BF_Node ; + Support Vol_Mag; Entity NodesOf[ All ] ; } + } + Constraint { + { NameOfCoef un ; EntityType NodesOf ; NameOfConstraint velocity~{i}; } + } + } + EndFor +} + +Jacobian { + { Name Vol ; + Case { + { Region All ; Jacobian Vol ; } + } + } + { Name Sur; + Case { + { Region All; Jacobian Sur; } + } + } +} + +Integration { + { Name Int ; + Case { { Type Gauss ; + Case { + { GeoElement Point; NumberOfPoints 1; } + { GeoElement Line; NumberOfPoints 5; } + { GeoElement Triangle; NumberOfPoints 4; } + { GeoElement Quadrangle; NumberOfPoints 4; } + } + } + } + } +} + + +// ------------------------------------------------------------------------- +// This resolution solves the direct problem to compute the sensitivity +// of the induction flux with respect to a given design variable. + + +Formulation { + { Name MagSta_a; Type FemEquation; + Quantity { + { Name a; Type Local; NameOfSpace Hcurl_a_2D; } + } + Equation { + Integral { [ nu[{d a}] * Dof{d a} , {d a} ]; + In Vol_Mag ; Jacobian Vol; Integration Int; } + Integral { JacNL [ dhdb_NL[{d a}] * Dof{d a} , {d a} ]; + In Vol_NL_Mag; Jacobian Vol; Integration Int; } + Integral { [ -js[] , {a} ]; + In Vol_S_Mag; Jacobian Vol; Integration Int; } + } + } +} + +Resolution { + { Name GetPerformances; + System { + { Name SYS; NameOfFormulation MagSta_a;} + } + Operation { + If( OptiIterNumber == 1 ) + CreateDir[ResDir]; + DeleteFile[StrCat[ResDir,"w.txt"]]; + DeleteFile[StrCat[ResDir,"Lie_w.txt"]]; + EndIf + InitSolution[SYS]; + IterativeLoop[NL_iter_max, NL_tol_abs, NL_tol_relax]{ + GenerateJac[SYS]; + SolveJac[SYS]; + } + PostOperation[Get_ObjectiveConstraints]; + } + } +} + +PostProcessing { + { Name MagSta_a_2D; NameOfFormulation MagSta_a; + Quantity { + { Name az; + Value { + Term { [ CompZ[{a}] ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + { Name b; + Value { + Term { [ {d a} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + { Name by; + Value { + Term { [ CompY[{d a}] ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + { Name js; + Value { + Term { [ js[] ]; In Vol_S_Mag; Jacobian Vol; } + } + } + { Name Flux ; Value { Integral { + [ {a} * NbTurns * Jshape[] ] ; + In Vol_S_Mag ; Jacobian Vol ; Integration Int ; } } + } + { Name fobj_b_at_point; + Value { + Term { [ SquNorm[ CompY[{d a}] - By_target ] ]; + In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + } + } +} + +PostOperation { + { Name Get_ObjectiveConstraints; NameOfPostProcessing MagSta_a_2D; + Operation{ + + CreateDir["res"]; + //Print[js, OnElementsOf Vol_S_Mag, File "res/js.pos"]; + Print[b, OnElementsOf Vol_Mag, File "res/b.pos"]; + + Print[az, OnElementsOf Vol_Mag, File "res/az.pos"]; + Echo[ Str["k= PostProcessing.NbViews-1;", + "View[k].IntervalsType = 3;", + "View[0].NbIso = 30;"], + File "tmp.geo", LastTimeStepOnly] ; + + // In memory transfer of the a field for assembling sensitivity equations + Print[az, OnElementsOf Vol_Mag, Format NodeTable, File "", + SendToServer "Optimization/Results/a", Hidden 1]; + + Print[ Flux[ Vol_S_Mag ], OnGlobal, + Format Table, File > "", + SendToServer "Model/Results/Flux computed"]; + + Print[ by, OnPoint { Px_target, Py_target, 0}, + Format Table, File "", + SendToServer "Model/Results/b probe"]; + + Print[ fobj_b_at_point, OnPoint { Px_target, Py_target, 0}, + Format Table, File > "res/w.txt", + SendToServer "Optimization/Results/w"]; + } + } +} + +// ------------------------------------------------------------------------- +// This resolution solves the direct problem to compute the sensitivity +// of the induction flux with respect to a given design variable. + +Formulation { + { Name DirectFormulationOf_MagSta_a_2D; Type FemEquation ; + Quantity { + { Name Lva; Type Local; NameOfSpace Hcurl_a_2D; } + { Name a; Type Local; NameOfSpace Hcurl_a_2D_fullyfixed; } + For i In {1:3} + { Name v~{i} ; Type Local ; NameOfSpace H_v~{i}; } + EndFor + } + Equation { + Galerkin { [ nu[{d a}] * Dof{d Lva}, {d Lva} ]; + In Vol_Mag; Jacobian Vol; Integration Int; } + Galerkin { [ dhdb_NL[{d a}] * Dof{d Lva}, {d Lva} ]; + In Vol_NL_Mag; Jacobian Vol; Integration Int; } + Galerkin { [LieOf_HB[{d a},dV[{d v_1},{d v_2},{d v_3}]], {d Lva}]; + In Vol_Mag; Jacobian Vol; Integration Int; } + Galerkin { [LieOf_HB_NL[{d a},dV[{d v_1},{d v_2},{d v_3}]], {d Lva}]; + In Vol_NL_Mag; Jacobian Vol; Integration Int; } + + Integral { [ -LieOf_js[dV[{d v_1},{d v_2},{d v_3}]], {Lva} ] ; + In Vol_S_Mag ; Jacobian Vol; Integration Int; } + + Integral { [ 0*Dof{a}, {a} ] ; + In Vol_Mag; Jacobian Vol ; Integration Int ; } + For i In {1:3} + Integral { [ 0*Dof{v~{i}}, {v~{i}} ] ; + In Vol_Mag; Jacobian Vol ; Integration Int ; } + EndFor + } + } +} + +Resolution { + { Name GetGradient_wrt_dv; + System { + { Name DIR; NameOfFormulation DirectFormulationOf_MagSta_a_2D; } + } + Operation { + InitSolution[DIR]; + Generate[DIR]; + Solve[DIR]; + PostOperation[Get_GradOf_w]; + } + } +} + +PostProcessing{ + { Name Direct_MagSta; NameOfFormulation DirectFormulationOf_MagSta_a_2D; + PostQuantity { + { Name az; + Value{ + Term{ [ CompZ[{a}] ]; In Vol_Mag; Jacobian Vol; } + } + } + { Name VV; + Value{ + Term{ [ Vector[{v_1},{v_2},{v_3}] ]; In Vol_Mag ; Jacobian Vol;} + } + } + { Name Lie_az; + Value { + Term { [ CompZ[ {Lva}] ] ; In Vol_Mag ; Jacobian Vol; } + } + } + { Name Lie_b_at_point ; Value { + Term { [ 2 * (CompY[{d a}] - By_target) * CompY[{d Lva}] ] ; + In Vol_Mag; Jacobian Vol; } + } + } + } + } +} + +PostOperation{ + { Name Get_GradOf_w; NameOfPostProcessing Direct_MagSta; + Operation { + CreateDir["res"]; + + Print[ VV, OnElementsOf Vol_Mag,File "res/velocity.pos" ]; + Echo[ Str["View[PostProcessing.NbViews-1].GlyphLocation = 2;"], + File "tmp.geo", LastTimeStepOnly] ; + + //Print[az, OnElementsOf Vol_Mag, File "res/azstar.pos"]; + Echo[ Str["k= PostProcessing.NbViews-1;", + "View[k].IntervalsType = 3;", + "View[0].NbIso = 30;"], + File "tmp.geo", LastTimeStepOnly] ; + + Print[ Lie_az, OnElementsOf Vol_Mag, File "res/Lie_az.pos" ]; + Echo[ Str["k= PostProcessing.NbViews-1;", + "View[k].IntervalsType = 3;", + "View[0].NbIso = 30;"], + File "tmp.geo", LastTimeStepOnly] ; + + Print[ Lie_b_at_point, OnPoint{ Px_target, Py_target, 0}, + Format Table, File > "res/Lie_w.txt", + SendToServer Sprintf["Optimization/Results/dwdtau_%g",VelocityTag]]; + + } + } +} diff --git a/Ccore/ccore_common.pro b/Ccore/ccore_common.pro new file mode 100644 index 0000000..3898872 --- /dev/null +++ b/Ccore/ccore_common.pro @@ -0,0 +1,62 @@ + +/* + This tutorial deals with shape sensitivity analysis in Magnetostatics. + The model consists of a ferromagnetic C-core powered + by a coil with 'NbTurns' windings suplied with a DC current. + The ferromagnetic behavior of the C-core material can be + represented by either a linear of a nonlinear saturable law. + The power supply is set to maintain either a constant total current + or a constant current density as the design parameters vary. + + Three geometrical parametrs are + + */ + + +ParamIndex = + DefineNumber[0, Name "Optimization/Sweep on parameter", + Choices {0="None", + 1="D: air gap length", + 2="E: C-core thickness", + 3="F: Core-coil gap"} ]; +StepsInRange = + DefineNumber[20, Name "Optimization/Steps in range", Visible ParamIndex]; + + +w = + DefineNumber[0, Name "Optimization/Results/w", + Graph "030000000000000000000000000000000000"]; +dwdt = + DefineNumber[0, Name Sprintf["Optimization/Results/dwdtau_%g",0], + Graph "000300000000000000000000000000000000"]; + + + +DefineConstant[ + D = DefineNumber[0.01, Name "Optimization/Parameters/D", + Min 0.001, Max 0.050] + E = DefineNumber[0.1 , Name "Optimization/Parameters/E", + Min 0.01 , Max 0.15] + F = DefineNumber[0.01, Name "Optimization/Parameters/F", + Min 0.001, Max 0.090] +]; + + +DefineConstant[ + // all dimensions in meter + L=1 // sidelength of the air box square + + CoreX=0.3 // X-position of C-core's bottom left corner + CoreY=0.3 // Y-position of C-core's bottom left corner + A=0.4 // C-core length along X-axis + B=0.4 // C-core length along Y-axis + D=0.01 // air gap length + E=0.1 // C-core thickness + F=0.01 // gap between C-core and coil + G=0.05 // coil width along X-axis + + CoilSection_ref = G*(B-2*E-2*F) + + R=1 // refinement factor: R=5 far raw mesh, R=1 normal mesh +]; + diff --git a/Ccore/shp.plt b/Ccore/shp.plt new file mode 100644 index 0000000..7fee2e8 --- /dev/null +++ b/Ccore/shp.plt @@ -0,0 +1,53 @@ +#set terminal pdf + +set grid +set ytics nomirror +set y2tics +set style data lines + +set xlabel "tau" +set y2label "w" +set ylabel "dw/dtau" + +set output "aaa.pdf" +plot "aaa" u 2:3 axis x1y2 t"w",\ + "aaa" u 2:4 t"dwdt",\ + "aaa" u 2:5 w linesp t"dwdt FD" + +pause -1 + +set output "optishape1.pdf" +plot "Torque_linTH.txt" u 2:3 axis x1y2 t"w",\ + "Torque_linTH.txt" u 2:4 t"dwdt",\ + "Torque_linTH.txt" u 2:5 w linesp t"dwdt FD" + +pause -1 + +set output "optishape2.pdf" +plot "LieDevSmoother.txt" u 2:3 axis x1y2 t"w",\ + "LieDevSmoother.txt" u 2:4 t"dwdt",\ + "LieDevSmoother.txt" u 2:5 w linesp t"dwdt FD" + +pause -1 + +set output "optishape3.pdf" +plot "Torque_linTH2.txt" u 2:3 axis x1y2 t"w",\ + "Torque_linTH2.txt" u 2:4 t"dwdt",\ + "Torque_linTH2.txt" u 2:5 w linesp t"dwdt FD" + +pause -1 + +set output "optishape4.pdf" +plot "LieDevSmoother2.txt" u 2:3 axis x1y2 t"w",\ + "LieDevSmoother2.txt" u 2:4 t"dwdt",\ + "LieDevSmoother2.txt" u 2:5 w linesp t"dwdt FD" + +pause -1 + +set output "optishape5.pdf" +plot "Torque_TH.txt" u 2:3 axis x1y2 t"w",\ + "Torque_TH.txt" u 2:4 t"dwdt",\ + "Torque_TH.txt" u 2:5 w linesp t"dwdt FD" + +pause -1 + diff --git a/Ccore/shp.py b/Ccore/shp.py new file mode 100644 index 0000000..32aa8d2 --- /dev/null +++ b/Ccore/shp.py @@ -0,0 +1,245 @@ +# Open this file with Gmsh (interactively with File->Open->shape.py, or on the +# command line with 'gmsh shape.py') +# + +import numpy as np +import conveks +import onelab +from scipy.optimize import minimize + + +c = onelab.client(__file__) + +# get gmsh and getdp locations from Gmsh options +mygmsh = c.getString('General.ExecutableFileName') +mygetdp = '' +for s in range(9): + n = c.getString('Solver.Name' + str(s)) + if(n == 'GetDP'): + mygetdp = c.getString('Solver.Executable' + str(s)) + break +if(not len(mygetdp)): + c.sendError('This appears to be the first time you are trying to run GetDP') + c.sendError('Please run a GetDP model interactively once with Gmsh to ' + + 'initialize the solver location') + exit(0) + +c.sendInfo('Will use gmsh={0} and getdp={1}'.format(mygmsh, mygetdp)) + +modelName = 'ccore' + +# append correct path to model file names +file_geo = c.getPath(modelName+'.geo') +file_msh = c.getPath(modelName+'.msh') +file_pro = c.getPath(modelName+'.pro') + +# build command strings with appropriate parameters and options +mygmsh += ' -p 0 -v 2 -parametric ' + file_geo + ' ' +mygetdp += ' -p 0 ' + file_pro + ' -msh ' + file_msh + ' ' + +# load geometry in GUI to have something to look at +c.openProject(file_geo) + +c.sendCommand('Solver.AutoMesh = -1;') + +# dry getdp run (without -solve or -pos option) to get model parameters in the GUI +c.runSubClient('myGetDP', mygetdp) + +# define optimization parameters as Onelab parameter (editable in the GUI) +maxIter = c.defineNumber('Optimization/00Max iterations', value=100) +maxChange = c.defineNumber('Optimization/01Max change', value=1e-0) + +# end of check phase. We're done if we do not start the optimization +if c.action == 'check' : + exit(0) + +## def readSimpleTable(path): +## with open(path) as FileObj: +## return np.array([float(lines.split()[-1]) for lines in FileObj]) + +def setNodeTable(var, nodes, val): + data = np.ravel(np.column_stack((nodes, val))) + data = np.insert(data, 0, float(len(nodes))) + c.setNumber(var, values=data, visible=0) + +def getVelocityField(xvar, perturb=1e-7): + for id, var in xvar.iteritems(): + c.runNonBlockingSubClient('myGmsh', mygmsh \ + + ' -setnumber PerturbMesh 1'\ + + ' -setnumber Perturbation '+str(perturb)\ + + ' -setnumber VelocityTag '+str(id)\ + + ' -setnumber '+var[-1]+' '+str(var[1]+perturb)\ + + ' -run') + c.waitOnSubClients() + # send the x,y,z components of each velocity field + for label, var in x.iteritems(): + d = c.getNumbers('Optimization/Results/velocity_'+str(label)) + if label==0: + nodes = np.array(d[1::4]) + setNodeTable('Optimization/Results/velocity_'+str(label)+'_1',nodes,np.array(d[2::4])) + setNodeTable('Optimization/Results/velocity_'+str(label)+'_2',nodes,np.array(d[3::4])) + setNodeTable('Optimization/Results/velocity_'+str(label)+'_3',nodes,np.array(d[4::4])) + c.setNumber(var[0],value=x[label][1]) + +def fobj(xFromOpti): + # send the current point to GetDP model + for label, var in x.iteritems(): + x[label][1] = xFromOpti[label] + c.setNumber(var[0],value=x[label][1]) + + # reload the geometry in GUI to see the geometrical changes + c.openProject(file_geo) + + c.runSubClient('myGmsh', mygmsh + ' -2') + getVelocityField(x) + c.runSubClient('myGetDP', mygetdp + '-solve GetPerformances' \ + + ' - setnumber OuterIteration ' + str(0)) # it !! + return c.getNumber('Optimization/Results/w') + + +def grad(xFromOpti): + # send the current point to GetDP model + for label, var in x.iteritems(): + x[label][1] = xFromOpti[label] + c.setNumber(var[0],value=x[label][1]) + + # as well as their sensitivity with respect to design variables at `x' + for dv, var in x.iteritems(): + c.runNonBlockingSubClient('myGetDP', mygetdp \ + + ' -setnumber VelocityTag '+str(dv)\ + + ' -solve GetGradient_wrt_dv') + c.waitOnSubClients() + grads = [c.getNumber('Optimization/Results/dwdtau_0'), c.getNumber('Optimization/Results/dwdtau_1')] + return np.asarray(grads) + +Nfeval = 1 +def callbackF(Xi): + global Nfeval + print '{0:4d} {1: 3.6f} {2: 3.6f} {3: 3.6f}'.format(Nfeval, Xi[0], fobj(Xi), grad(Xi)[0]) + Nfeval += 1 + +def test(n): + tab = np.zeros((n+1,4)) + for step in range(n+1): + xstep = x[0][2] + (x[0][3]-x[0][2])/float(n)*step + f,g,d = fobj([xstep]), grad([xstep]), 0 + tab[step] = [xstep, f, g, d] + if step >= 2 : + tab[step-1][3] = (tab[step][1]-tab[step-2][1])/(tab[step][0]-tab[step-2][0]) + if c.getString(c.name+'/Action') == 'stop': + exit(1) + print + for step in range(n+1): + ind1, ind2 = max(step-1,0), min(step+1,n) + tab[step][3] = (tab[ind2][1]-tab[ind1][1])/(tab[ind2][0]-tab[ind1][0]) + print "%4d" % step, + for item in tab[step] : print "%3.6f" % item, + print + + return tab + + +# x is the list of design parameters with format +# [ "Onelab name", value, Min, Max, "variable name" ] +designParameters={ + 0 : ['Optimization/Parameters/D', 0.01, 0.001, 0.050, 'D'], + 1 : ['Optimization/Parameters/E', 0.01 , 0.01, 0.15 , 'E'] +# 2 : ['Optimization/Parameters/F', 0.01, 0.001, 0.090, 'F'] +} + + +x = {} +index = int(c.getNumber('Optimization/Sweep on parameter'))-1 + +if index >= 0: + x[0] = designParameters[index]; + test(int(c.getNumber('Optimization/Steps in range'))) + #callback=callbackF, + res = minimize(fobj, [x[0][1]], jac=grad, bounds=[(x[0][2],x[0][3])],\ + callback=callbackF, method = 'L-BFGS-B', tol=None,\ + options={'ftol': 1e-5, 'gtol': 1e-3, 'disp':True} ) + print res + +else: + for label, var in designParameters.iteritems(): + x[label] = var + values = [designParameters[i][1] for i in range(len(designParameters))] + bounds = [(designParameters[i][2], designParameters[i][3]) for i in range(len(designParameters))] + ## print x + ## print values, bounds + ## print fobj(values) + ## print grad(values) + ## exit(1) + + res = minimize(fobj, values, jac=grad, bounds=bounds, callback=callbackF,\ + method = 'L-BFGS-B', tol=None, options={'ftol': 1e-5, 'gtol': 1e-3, 'disp':True} ) + print res + + + +exit(1) + +# number of design variables and number of constraints +numVariables = len(x.keys()) + +# initial value of the variables in the design space, +# the lower bound for design variables, +# as well as the upper bound for design variables. +initialPoint = np.zeros(numVariables) +lowerBound = np.zeros(numVariables) +upperBound = np.zeros(numVariables) +for label, var in x.iteritems(): + initialPoint[label] = var[1] + lowerBound[label] = var[2] + upperBound[label] = var[3] + + + +# Initialize the MMA optimizer +conveks.mma.initialize(initialPoint, lowerBound, upperBound) + +# Set some options for MMA +conveks.mma.option.setNumber('General.Verbosity', 0) # def 4 +conveks.mma.option.setNumber('General.SaveHistory', 0) +conveks.mma.option.setNumber('SubProblem.isRobustMoveLimit', 1) # def 1 +conveks.mma.option.setNumber('SubProblem.isRobustAsymptotes', 1) # def 1 +conveks.mma.option.setNumber('SubProblem.type', 0) +conveks.mma.option.setNumber('SubProblem.addConvexity', 0) +conveks.mma.option.setNumber('SubProblem.asymptotesRmax', 100.0) +conveks.mma.option.setNumber('SubProblem.asymptotesRmin', 0.001) # def 0.001 + +# Get iteration count (here it will be 1 - could be different in case of restart) +it = conveks.mma.getOuterIteration() +change = 1.0 + +while it <= maxIter and c.getString(c.name+'/Action') != 'stop': #and change > 1e-6 : + c.setNumber('Optimization/01Current iteration', value=it, readOnly=1, + attributes={'Highlight':'LightYellow'}) + + # get (copy of) current point + xFromMMA = np.array(conveks.mma.getCurrentPoint()) + print 'xFromMMA = ', xFromMMA + + # get the value of the objective function and of the constraints + # as well as their sensitivity with respect to design variables at `x' + objective = fobj(xFromMMA) + grad_objective = grad(xFromMMA) + constraints = np.array([np.sum(xFromMMA)/100.0-1.0]) + grad_constraints = np.ones(numVariables)/100.0 + + if it == 1: fscale = 1.0 / np.abs(objective) + objective *= fscale + grad_objective *= fscale + + print it, xFromMMA, objective, grad_objective + c.sendInfo('Optimization: it. {}, obj. {}, constr. {}'.format(it,objective,constraints[0])) + + # call MMA and update the current point + conveks.mma.setMoveLimits(lowerBound, upperBound, 1e-0) # parametre interessant + conveks.mma.updateCurrentPoint(constraints,grad_objective,grad_constraints) + change = conveks.mma.getDesignChange() + it = conveks.mma.getOuterIteration() + +# This should be called at the end +conveks.mma.finalize() + -- GitLab