diff --git a/Team25/shape.geo b/Team25/shape.geo new file mode 100644 index 0000000000000000000000000000000000000000..71d2bab2f61c3410987a2266fe0885da52c9d7df --- /dev/null +++ b/Team25/shape.geo @@ -0,0 +1,152 @@ +DefineConstant[ + mm = 1e-3 + deg = Pi/180 + R1 = 6*mm + L2 = 18*mm + L3 = 15*mm + L4 = L2/L3*Sqrt[L3^2-(12.5*mm)^2] + angleMeasure = 50*deg + lc = 12*mm + lcd = lc/15 + + // mesh perturb + PerturbMesh = 0 + VelocityTag = -1 + Perturbation = 1e-6 + modelpath = CurrentDir +]; + +Point(1) = {0, 0, 0, lcd}; + +For k In {0:10} + theta = k * 90/10 * deg; + DefineConstant[Rs~{k} = {R1, Name Sprintf["Constructive parameters/spline radius %g",k+1]}]; + Point(2020+k) = {Rs~{k}*Cos[theta], Rs~{k}*Sin[theta], 0, lcd}; +EndFor + +BSpline(4020) = {2020,2021, 2022, 2023}; +BSpline(4021) = {2023, 2024, 2025, 2026}; +BSpline(4022) = {2026, 2027, 2028, 2029, 2030}; + +Point(26) = {L2/L3*Sqrt[L3^2-((12.5-2)*mm)^2], (12.5-2)*mm, 0, lcd}; + +For k In {0:10} + theta = k * 35/10 * deg; + DefineConstant[Rso~{k} = {L2*L3/Sqrt[(L3*Cos[theta])^2+(L2*Sin[theta])^2], + Name Sprintf["Constructive parameters/outer spline radius %g",k+1]}]; + Point(6020+k) = {Rso~{k}*Cos[theta], Rso~{k}*Sin[theta], 0, lcd}; +EndFor + +BSpline(4023) = {6020, 6021, 6022, 6023}; +BSpline(4024) = {6023, 6024, 6025, 6026}; +BSpline(4025) = {6026, 6027, 6028}; +BSpline(4026) = {6028, 6029, 6030, 26}; + +Point(6) = {20*mm, 0, 0, lcd}; +Point(8) = {0, L3, 0, lc}; +Point(9) = {25*mm, 0, 0, lc}; +Point(10) = {163*mm, 0, 0, lc}; +Point(11) = {25*mm, 50*mm, 0, lc}; +Point(12) = {113*mm, 50*mm, 0, lc}; +Point(13) = {113*mm, (50+80)*mm, 0, lc}; +Point(14) = {0, (50+80)*mm, 0, lc}; +Point(15) = {0, 180*mm, 0, lc}; +Point(16) = {163*mm, 180*mm, 0, lc}; +Point(17) = {25*mm, (50+7.5)*mm, 0, lc}; +Point(18) = {113*mm, (50+7.5)*mm, 0, lc}; +Point(19) = {25*mm, (50+7.5+39)*mm, 0, lc}; +Point(20) = {113*mm, (50+7.5+39)*mm, 0, lc}; + +Point(1021) = {(9.5+2.25)*Cos[angleMeasure]*mm, (9.5+2.25)*Sin[angleMeasure]*mm, 0, lcd}; +Point(1022) = {(9.5+2.25)*mm, 0, 0, lcd}; + +Point(23) = {20*mm, 12.5*mm, 0, lcd}; +Point(24) = {20*mm-L4, 12.5*mm, 0, lcd}; +Point(25) = {20*mm-L4, (12.5-2)*mm, 0, lcd}; + +Circle(1016) = {1022, 1, 1021}; +Line(2) = {9, 10}; +Line(3) = {10, 16}; +Line(4) = {16, 15}; +Line(5) = {15, 14}; +Line(6) = {14, 13}; +Line(8) = {12, 11}; +Line(9) = {11, 9}; +Line(10) = {17, 18}; +Line(11) = {12, 18}; +Line(12) = {18, 20}; +Line(13) = {20, 19}; +Line(14) = {19, 17}; +Line(15) = {20, 13}; +Line(18) = {1, 2020}; +Line(24) = {2020, 6020}; +Line(22) = {1, 2030}; +Line(26) = {6, 23}; +Line(27) = {24, 23}; +Line(28) = {24, 25}; +Line(29) = {25, 26}; +Line(30) = {6020, 6}; +Line(31) = {6, 9}; +Line(32) = {2030, 14}; + +Curve Loop(1) = {-22, 18, 4020, 4021, 4022}; +Plane Surface(1) = {1}; +Curve Loop(2) = {4023,4024,4025,4026, -29, -28, 27, -26, -30}; +Plane Surface(2) = {2}; +Curve Loop(3) = {9, 2, 3, 4, 5, 6, -15, -12, -11, 8}; +Plane Surface(3) = {3}; +Curve Loop(4) = {13, 14, 10, 12}; +Plane Surface(4) = {4}; +Curve Loop(6) = {24, 4023,4024,4025,4026, -29, -28, 27, -26, 31, -9, -8, 11, -10, -14, -13, 15, -6, -32, -4020, -4021, -4022}; +Plane Surface(6) = {6}; + +Physical Surface("pole", 1) = {3}; +Physical Surface("inductor", 2) = {4}; +Physical Surface("die molds", 3) = {1,2}; +Physical Surface("air", 5) = {6}; +Physical Line("dirichlet", 6) = {3,4,18,20,24,30,31,2}; +Physical Line("neuman", 7) = {22,32}; + +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; + + // 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; + + // 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"; + Delete View[1]; + SendToServer View[0] Sprintf("Optimization/Results/velocity_%g",VelocityTag); // Hidden +EndIf diff --git a/Team25/shape.pro b/Team25/shape.pro new file mode 100644 index 0000000000000000000000000000000000000000..6cdaf8f3f1a13fcfb29669cf248001e7e3902b75 --- /dev/null +++ b/Team25/shape.pro @@ -0,0 +1,421 @@ +/* ------------------------------------------------------------------- + Tutorial: Optimization of Die Press Model (TEAM25) + + Features: + - Nonlinear magnetostatic model of the die press + - CAD parameters as ONELAB parameters + - Direct approach of the shape sensitivity analysis + based on the Lie derivative + + To compute the solution in a terminal: + getdp shape.pro -solve GetPerformancesAndGradients + + To compute the solution interactively from the Gmsh GUI: + File > Open > shape.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +/* This model computes the static magnetic field produced by a DC current. This + corresponds to a "magnetostatic" physical model, obtained by combining the + time-invariant Maxwell-Ampere equation (curl h = js, with h the magnetic + field and js the source current density) with Gauss' law (Div b = 0, with b + the magnetic flux density) and the magnetic constitutive law (b = mu h, with + mu the magnetic permeability). + + Since Div b = 0, b can be derived from a vector magnetic potential a, such + that b = curl a. Plugging this potential in Maxwell-Ampere's law and using + the constitutive law leads to a vector Poisson equation in terms of the + magnetic vector potential: curl(nu curl a) = js, where nu = 1/mu is + the reluctivity. + + It is useful to share parameters with the user of the model, + i.e., to make them editable in the GUI before running the model. + Such variables are called ONELAB variables (because the sharing + mechanism between the model and the GUI uses the ONELAB interface). + ONELAB parameters are defined with a "DefineConstant" statement, + which can be invoked in the .geo and .pro files. + + The optimization part is organized as follows: + + (1) We replaced both curves g-h and i-j by nurbs which have a certain + of control points. We set the shape design variables as the distance + of these control points from the origin point. Their actual value is + provided by shape.py. + + (2) We make use of the solution of the nonlinear magnetostatic problem, + for a given CAD configuration, to compute the objective function, + w = Sum_{i=1}^{10} ((bpx_i-box_o)^2 + (bpy_i-boy_o)^2), + as defined in TEAM25. + + (3) We compute the derivative of the flux density along the velocity + field generated by the perturbation of each design variable, by means + of the Lie derivative. The derivative of he objective, w, is therefore + obtained by applying the chain rule. This is known as the direct approach + of the sensitivity analysis, see [1]. + + The value of the objective function as well as is derivative with respect + to each design variable are provided to the ONELAB database. They can be + accessed by shape.py. + + [1]:Erin Kuci, François Henrotte, Pierre Duysinx, and Christophe Geuzaine. + ``Design sensitivity analysis for shape optimization based on the Lie derivative'', + Computer Methods in Applied Mechanics and Engineering 317 (2017), pp. 702 –722. + issn: 0045-7825. +*/ + +DefineConstant [ + Opt_ResDir = "res_opt/" + Opt_ResDir_Onelab = "Optimization/Results/" + Model_smallAT = {1, Name "Model/Small Ampere-Turn", Choices{0,1}} + Flag_PrintLevel = 1 + VelocityTag = -1 + // Nonlinear iterations + Nb_max_iter = 30 + relaxation_factor = 1 + stop_criterion = 1e-5 +]; + +Group { + // One starts by giving explicit meaningful names to the Physical regions + // defined in the "shape.geo" mesh file. + Coil = Region[2]; + Core = Region[{1,3}]; + + // Then one difines abstract regions so as to allow a generic definition of the + // FunctionSpace, Formulation and PostProcessing fields with no reference to + // model-specific Physical regions. + Domain = Region[{Core,Coil,5}]; + NoFlux = Region[6]; +} + +Function{ + // Material law (here the magnetic reluctivity) is defined as piecewise + // function (note the square brackets), in terms of the above defined + // physical regions. + + mu0 = 4 * Pi * 1e-7; + Mat1_b = {0.0,0.11,0.18,0.28,0.35,0.74,0.82,0.91,0.98,1.02,1.08,1.15, + 1.27,1.32,1.36,1.39,1.42,1.47,1.51,1.54,1.56,1.60,1.64,1.72}; + Mat1_h = {0.0,140.0,178.0,215.0,253.0,391.0,452.0,529.0,596.0,677.0,774.0,902.0, + 1164.0,1299.0,1462.0,1640.0,1851.0,2262.0,2685.0,3038.0,3395.0,4094.0,4756.0,7079.0}; + Mat1_b2 = List[Mat1_b]^2; + Mat1_nu = List[Mat1_h]/List[Mat1_b]; + Mat1_nu(0) = Mat1_nu(1); + Mat1_nu_b2 = ListAlt[Mat1_b2, Mat1_nu]; + nu[Core] = InterpolationLinear[ SquNorm[$1] ]{List[Mat1_nu_b2]} ; + nu[Region[{Domain,-Core}]] = 1/mu0; // linear + + dnudb2[] = dInterpolationLinear[SquNorm[$1]]{List[Mat1_nu_b2]} ; + dnudb_1[] = 2.0*dInterpolationLinear[SquNorm[$1]]{List[Mat1_nu_b2]}*SquDyadicProduct[$1]; + dhdb_NL[Core] = 2*dnudb2[$1#1] * SquDyadicProduct[#1]; + + // This is the current density which feeds the inductor. + js[Coil] = Vector[0, 0, (Model_smallAT==1?4253:17500)/SurfaceArea[]{2}]; + + // This is the desired x and y components of the induction field + // in the cavity as defined in TEAM25. + bx[] = (Model_smallAT==1?0.35:1.5) * X[]/Sqrt[X[]^2+Y[]^2]; + by[] = (Model_smallAT==1?0.35:1.5) * Y[]/Sqrt[X[]^2+Y[]^2]; +} + +Jacobian { + { Name Vol; Case { { Region All ; Jacobian Vol; } } } + { Name Sur; Case { { Region All ; Jacobian Sur; } } } +} + +Integration{ + { Name Int2; + Case{ + { Type Gauss; + Case{ + { GeoElement Line; NumberOfPoints 3; } + { GeoElement Triangle; NumberOfPoints 4; } + { GeoElement Quadrangle; NumberOfPoints 4; } + } + } + } + } +} + +// ------------------------------------------------------------------------- +// The weak formulation for this problem is derived. The fields are +// vector-valued, and we have one linear (source) term in addition +// to the bilinear term. + +Constraint{ + { Name Dirichlet; + Case{ + { Region NoFlux; Type Assign; Value 0; } + } + } +} + +FunctionSpace { + { Name HCurl2D; Type Form1P; + BasisFunction{ + { Name se1; NameOfCoef ae1; Function BF_PerpendicularEdge; + Support Region[Domain]; Entity NodesOf[All]; } + } + Constraint{ + { NameOfCoef ae1; EntityType NodesOf; NameOfConstraint Dirichlet; } + } + } +} + +Formulation{ + { Name MVP2D; Type FemEquation; + Quantity{ + { Name a; Type Local; NameOfSpace HCurl2D; } + } + Equation{ + Galerkin{ [nu[{d a}] * Dof{d a}, {d a}]; + In Domain; Jacobian Vol; Integration Int2; } + Galerkin { JacNL [ dhdb_NL[{d a}] * Dof{d a} , {d a} ]; + In Core; Jacobian Vol ; Integration Int2 ; } + Galerkin { [-js[], {a}]; + In Coil; Jacobian Vol; Integration Int2; } + } + } +} + +// ------------------------------------------------------------------------- +// Handling of the velocity field (through a fully-fixed function space +// defined on Domain). + +Function{ + 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 { + For i In {1:3} + { Name velocity~{i} ; + Case { + { Region Domain ; Value velocity~{i}[]; } + } + } + EndFor +} + +FunctionSpace { + For i In {1:3} + { Name H_v~{i} ; Type Form0; + BasisFunction { + { Name sn ; NameOfCoef un ; Function BF_Node ; + Support Domain; Entity NodesOf[ All ] ; } + } + Constraint { + { NameOfCoef un ; EntityType NodesOf ; NameOfConstraint velocity~{i}; } + } + } + EndFor +} + +// ------------------------------------------------------------------------- +// Magnetic vector potential handling (through a fully-fixed function space +// defined on Domain). + +Function{ + l_a = ListFromServer[StrCat[Opt_ResDir_Onelab,"a"]]; + aFromServer[] = ValueFromIndex[]{l_a()}; +} + +Constraint { + { Name aFromServer; + Case { + { Region Domain ; Value aFromServer[]; } + { Region NoFlux; Type Assign; Value 0; } + } + } +} + +FunctionSpace{ + { Name HCurl2D_a_fullyfixed; Type Form1P; + BasisFunction{ + { Name se1; NameOfCoef ae1; Function BF_PerpendicularEdge; + Support Region[Domain]; Entity NodesOf[All]; } + } + Constraint{ + { NameOfCoef ae1; EntityType NodesOf; NameOfConstraint aFromServer; } + } + } +} + +// ------------------------------------------------------------------------- +// Handling of the direct sensitivity problem (depending on a given +// design variable represeted by the velocity field). + +Function{ + dV[] = Transpose[Tensor[CompX[$1],CompX[$2],0, + CompY[$1],CompY[$2],0, + CompZ[$1],CompZ[$2],0]]; + + // 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; + + // Lie derivative of the 2-form Js ($1:Js[], $2:dV) + LieOf_Js[] = TTrace[$2]*js[] - Transpose[$2]*js[]; +} + +FunctionSpace{ + { Name HCurl2D_Lva; Type Form1P ; + BasisFunction { + { Name se1 ; NameOfCoef ae1 ; Function BF_PerpendicularEdge ; + Support Region[{ Domain}] ; Entity NodesOf [ All ] ; } + } + Constraint { + { NameOfCoef ae1 ; EntityType NodesOf ; NameOfConstraint Dirichlet; } + } + } +} + +Formulation { + { Name DirectFormulationOf_MagSta_a_2D; Type FemEquation ; + Quantity { + { Name a; Type Local; NameOfSpace HCurl2D_a_fullyfixed; } + { Name Lva; Type Local; NameOfSpace HCurl2D_Lva; } + 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 Domain; Jacobian Vol; Integration Int2; } + Galerkin { [LieOf_HB[{d a},dV[{d v_1},{d v_2},{d v_3}]],{d Lva}]; + In Domain; Jacobian Vol; Integration Int2; } + Galerkin { [LieOf_HB_NL[{d a},dV[{d v_1},{d v_2},{d v_3}]],{d Lva}]; + In Core; Jacobian Vol; Integration Int2; } + Galerkin { [ LieOf_Js[js[], dV[{d v_1},{d v_2},{d v_3}]], {Lva} ] ; + In Coil ; Jacobian Vol; Integration Int2; } + + Galerkin { [ 0*Dof{a}, {a} ] ; + In Domain; Jacobian Vol ; Integration Int2 ; } + + For i In {1:3} + Galerkin { [ 0*Dof{v~{i}}, {v~{i}} ] ; + In Domain; Jacobian Vol ; Integration Int2 ; } + EndFor + } + } +} + +// ------------------------------------------------------------------------- +// In the following, we create the post-operations necessary +// for the computation of objective and constraints, +// as well as their sensitivities. + +PostProcessing { + { Name ObjectiveConstraints; NameOfFormulation MVP2D; + Quantity { + { Name w; Value{ Term{[(CompX[{d a}]-bx[])^2+(CompY[{d a}]-by[])^2 ]; In Domain; Jacobian Vol; } } } + { Name az; Value{ Term{ [CompZ[{a}]]; In Domain; Jacobian Vol; } } } + { Name b; Value{ Term{ [{d a}]; In Domain; Jacobian Vol; } } } + { Name bMag; Value{ Term{ [Norm[{d a}]]; In Domain; Jacobian Vol; } } } + { Name js; Value{ Term{ [js[]]; In Coil; Jacobian Vol; } } } + { Name mur; Value{ Term{ [1/(nu[{d a}]*mu0)]; In Domain; Jacobian Vol; } } } + } + } +} + +PostOperation Get_ObjectiveConstraints UsingPost ObjectiveConstraints { + CreateDir[Opt_ResDir]; + Print[w, + OnGrid {(9.5e-3+2.25e-3)*Cos[$A],(9.5e-3+2.25e-3)*Sin[$A],0}{0:50*Pi/180:5*Pi/180,0,0}, + Format SimpleTable, File StrCat[Opt_ResDir,"w.txt"]]; + Print[bMag, + OnGrid {(9.5e-3+2.25e-3)*Cos[$A],(9.5e-3+2.25e-3)*Sin[$A],0}{0:50*Pi/180:5*Pi/180,0,0}, + Format SimpleTable, File StrCat[Opt_ResDir,"bMag.txt"]]; + Print[az, OnElementsOf Domain, Format NodeTable, File "", + SendToServer StrCat[Opt_ResDir_Onelab,"a"], Hidden 1]; + Print[bMag, OnElementsOf Domain, File StrCat[Opt_ResDir,"az.pos"]]; + //Print[az, OnElementsOf Domain, File StrCat[Opt_ResDir,"az.pos"]]; + If(Flag_PrintLevel>5) + Print[mur, OnElementsOf Domain, File StrCat[Opt_ResDir,"mur.pos"]]; + Print[az, OnElementsOf Domain, File StrCat[Opt_ResDir,"az.pos"]]; + Print[a, OnElementsOf Domain, File StrCat[Opt_ResDir,"a.pos"]]; + Print[b, OnElementsOf Domain, File StrCat[Opt_ResDir,"b.pos"]]; + Print[bMag, OnElementsOf Domain, File StrCat[Opt_ResDir,"bMag.pos"]]; + Print[js, OnElementsOf Coil, File StrCat[Opt_ResDir,"js.pos"]]; + EndIf +} + +// ------------------------------------------------------------------------- +// Sensitivity of w based on a direct method + +PostProcessing{ + { Name Direct_MagSta; NameOfFormulation DirectFormulationOf_MagSta_a_2D; + PostQuantity { + { Name Lie_w; Value { Term { [ 2*(CompX[{d a}]-bx[])*CompX[{d Lva}] + +2*(CompY[{d a}]-by[])*CompY[{d Lva}] ] ; In Domain; Jacobian Vol; }}} + } + } +} + +PostOperation Get_GradOf_w UsingPost Direct_MagSta { + Print[Lie_w, OnGrid {(9.5e-3+2.25e-3)*Cos[$A],(9.5e-3+2.25e-3)*Sin[$A], 0} { 0:50*Pi/180:5*Pi/180, 0, 0 }, + Format SimpleTable, File StrCat[Opt_ResDir,Sprintf["Grad_w_wrt_dv_%g.txt",VelocityTag]]]; +} + +// Show useful data +PostProcessing { + { Name Show_shape; NameOfFormulation DirectFormulationOf_MagSta_a_2D; + PostQuantity { + { Name VV; Value{Term{[ Vector[{v_1},{v_2},{v_3}] ];In Domain ; Jacobian Vol;}}} + { Name Lie_az; Value { Term { [ CompZ[{Lva}] ] ; In Domain ; Jacobian Vol; }}} + } + } +} + +PostOperation Show_shape UsingPost Show_shape{ + CreateDir[Opt_ResDir]; + Print[ VV, OnElementsOf Domain,File StrCat[Opt_ResDir, "velocity.pos"] ]; + Print[ Lie_az, OnElementsOf Domain,File StrCat[Opt_ResDir, "Lie_az.pos"] ]; +} + +// ------------------------------------------------------------------------- +// The following resolution solves the physical problem +// to obtain the objective and the constraints. + +Resolution { + { Name GetPerformances; + System { + { Name SYS; NameOfFormulation MVP2D;} + } + Operation { + // Initialization of the systems + InitSolution[SYS]; + + // Solve the nonlinear magnetostatic problem + IterativeLoop[Nb_max_iter, stop_criterion, relaxation_factor]{ + GenerateJac[SYS]; + SolveJac[SYS]; + Evaluate[ SetNumberRunTime[$Iteration]{"iterNL"} ]; + Evaluate[ SetNumberRunTime[$Residual]{"residualNL"} ]; + } + + // Compute the objective function and the constraints + PostOperation[Get_ObjectiveConstraints]; + } + } +} + +// ------------------------------------------------------------------------- +// This resolution solves the direct problem to compute the sensitivity +// of the induction flux with respect to a given design variable. + +Resolution { + { Name GetGradient_wrt_dv; + System { + { Name DIR; NameOfFormulation DirectFormulationOf_MagSta_a_2D; } + } + Operation { + InitSolution[DIR]; + Generate[DIR]; + Solve[DIR]; + PostOperation[Get_GradOf_w]; + } + } +} diff --git a/Team25/shape.py b/Team25/shape.py new file mode 100644 index 0000000000000000000000000000000000000000..6a01cc95144b2efda7e138ef8e9d9a37aabaddfe --- /dev/null +++ b/Team25/shape.py @@ -0,0 +1,181 @@ +# Open this file with Gmsh (interactively with File->Open->penning.py, or on the +# command line with 'gmsh penning.py') +# +from shutil import copyfile +import numpy as np +import optlab +import onelab + +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)) + +# append correct path to model file names +file_geo = c.getPath('shape.geo') +file_msh = c.getPath('shape.msh') +file_pro = c.getPath('shape.pro') + +# build command strings with appropriate parameters and options +mygetdp += ' -p 0 ' + file_pro + ' -msh ' + file_msh + ' ' +mygmsh += ' -p 0 -v 2 -parametric ' + file_geo + ' ' + +# load geometry in GUI to have something to look at +c.openProject(file_geo) + +# dry getdp run (without -solve or -pos option) to get model parameters in the GUI +c.runSubClient('myGetDP', mygetdp) + +# define now optimization parameters +# some of them as Onelab parameter, to be editable in the GUI +maxIter = c.defineNumber('Optimization/00Max iterations', value=100) +maxChange = c.defineNumber('Optimization/01Max change', value=1e-5) + +# end of check phase. We're done if we do not start the optimization +if c.action == 'check' : + exit(0) + +x = {} +for k in xrange(11): + xe = 6.0e-3 + x[k] = ['Constructive parameters/spline radius '+str(k+1),xe, xe-4.0e-3, xe+4.0e-3, 'Rs_'+str(k)] +sizeX = len(x.keys()) + +L2 = 18.0e-3;L3 = 15.0e-3 +for k in xrange(11): + theta = float(k) * 35.0/10.0 * np.pi/180.0 + xe = L2*L3/((L3*np.cos(theta))**2.0+(L2*np.sin(theta))**2.0)**0.5 + x[sizeX+k] = ['Constructive parameters/outer spline radius '+str(k+1), xe, xe-4.0e-3, xe+1.5e-3, 'Rso_'+str(k)] + +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-6): + for id, var in xvar.iteritems(): + c.runNonBlockingSubClient('myGmsh', mygmsh \ + + ' -setnumber PerturbMesh 1'\ + + ' -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]) + +# 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 +optlab.mma.initialize(initialPoint, lowerBound, upperBound) + +# Set some options for MMA +optlab.mma.option.setNumber('General.Verbosity', 4) +optlab.mma.option.setNumber('General.SaveHistory', 0) +optlab.mma.option.setNumber('SubProblem.isRobustMoveLimit', 1) +optlab.mma.option.setNumber('SubProblem.isRobustAsymptotes', 1) +optlab.mma.option.setNumber('SubProblem.type', 0) +optlab.mma.option.setNumber('SubProblem.addConvexity', 0) +optlab.mma.option.setNumber('SubProblem.asymptotesRmax', 100.0) +optlab.mma.option.setNumber('SubProblem.asymptotesRmin', 0.001) + +# Get iteration count (here it will be 1 - could be different in case of restart) +it = optlab.mma.getOuterIteration() +change = 1.0 + +while it <= maxIter and c.getString('shape/Action') != 'stop': + + c.setNumber('Optimization/01Current iteration', value=it, readOnly=1, + attributes={'Highlight':'LightYellow'}) + + # get (copy of) current point + xFromMMA = np.array(optlab.mma.getCurrentPoint()) + + # send the current point to GetDP model + for label, var in x.iteritems(): + x[label][1] = xFromMMA[label] + c.setNumber(var[0],value=x[label][1]) + + # reload the geometry in GUI to see the geometrical changes + c.openProject(file_geo) + + # mesh the geometry + c.runSubClient('myGmsh', mygmsh + ' -2') + + # generate the velocity field of each design variable + getVelocityField(x) + + # compute objective function and constraints + c.runSubClient('myGetDP', mygetdp + '-solve GetPerformances') + + # 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() + + # get the value of the objective function and of the constraints + # as well as their sensitivity with respect to design variables at `x' + objective = np.sum(readSimpleTable('res_opt/w.txt')) + constraints = np.array([np.sum(xFromMMA)/100.0-1.0]) + grad_objective = np.asarray([np.sum(readSimpleTable('res_opt/Grad_w_wrt_dv_'+str(dv)+'.txt'))\ + for dv in xrange(numVariables)]) + grad_constraints = np.ones(numVariables)/100.0 + + if it == 1: fscale = 1.0 / objective + objective *= fscale + grad_objective *= fscale + + print '*'*50 + print 'iteration: ', it + print 'change: ', change + print 'current point:', xFromMMA + print 'objective:', objective + print 'constraints:', constraints + c.sendInfo('Optimization: it. {}, obj. {}, constr. {}'.format(it,objective,constraints[0])) + #print 'gradient of objective:', grad_objective + #print 'gradient of constraints:', grad_constraints + + # call MMA and update the current point + optlab.mma.setMoveLimits(lowerBound, upperBound, 1.0e-4) + optlab.mma.updateCurrentPoint(constraints,grad_objective,grad_constraints) + change = optlab.mma.getDesignChange() + it = optlab.mma.getOuterIteration() + +# This should be called at the end +optlab.mma.finalize()