diff --git a/README.md b/README.md index b2530e512740968d92d0fafadf377df718ec1ebc..ae94909629b33953ad17c02389d8c63533c68bf6 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,69 @@ To build the independent FEM solver: - similar procedure but to be done in the srcs/FEM folder To build the independent BEM solver: -- similar procedure but to be done in the srcs/BEM folder \ No newline at end of file +- similar procedure but to be done in the srcs/BEM folder + +## Creation of a .geo file + +To create a .geo file compatible with the program, some rules must be respected: +- For the elastic FEM part: + 1. The FEM domain should be defined as a `Physical Surface` with the precise name `FEM_domain`. + First, a `Curve Loop` gathering the lines representing the boundary of the FEM domain must be created. + Then, a `Plane Surface` containing the corresponding curve loop must be created. + Finally, if the plane surface is the first of the .geo file, the physical surface must be created as: + `Physical Surface("FEM_domain", x) = {1};`, + where x is the tag of the physical surface. + Multiple sub domains can be included in the FEM domain. For example, if plane surfaces have been created for + five sub domains, the physical surface must be created as: + <pre><code>Physical Surface("FEM_domain", x) = {1, 2, 3, 4, 5};.<code><pre> + + 2. The mechanical boundary conditions, material properties and volumic forces must be specified for the FEM domain: + - **BOUNDARY CONDITIONS**: + 1. The edges on which the user wants to impose a boundary condition must be defined as `Physical Curve`. + As an example, if the user want to impose a condition on the bottom edge related to the `Line(1)`: + <pre><code>`Physical Curve("bottom_edge", x) = {1};`<code><pre> + 2. All boundary conditions must be written as `SetNumber("Boundary Conditions/name_of_the_physical_curve/...")` + with `name_of_the_physical_curve` the physical curve on which the condition is imposed. + 3. The Dirichlet boundary conditions, i.e the imposed horizontal and vertical displacement `u_x` and `u_y` of an edge, + expressed in [m], must be written as `Setnumber("Boundary Conditions/name_of_the_physical_curve/ux", desired_value);`, same applies for `u_y`. Note that the horizontal displacement can be imposed on a physical curve without imposing the vertical displacement, and vice-versa. + As an example, if the user wants the left edge to be clamped: + <pre><code>SetNumber("Boundary Conditions/left_edge/ux", 0.); + SetNumber("Boundary Conditions/left_edge/uy", 0.);<code><pre> + 4. The Neumann boundary conditions, i.e surface traction in the horizontal (`t_x`) or vertical (`t_y`) direction imposed on + an edge, expressed in [Pa], must be written as `SetNumber("Boundary Conditions/name_of_the_physical_curve/tx", desired_value)`, + same applies for `t_y`. Note that on a specific edge, both horizontal and vertical surface tractions must be + prescribed. If the user only wants to prescribe `t_x`, `t_y` must also be set to zero. + 5. Dirichlet boundary conditions can also be imposed on a specific point of the domain. In this case, a `Physical Point` + must be created. + - **MATERIAL PROPERTIES**: + All the material properties must be written as `SetNumber("Materials/FEM_domain/name_of_property", value_of_property);`. + The different properties that must be specified are: + - Young's modulus, expressed in [Pa], named `Young`. + - Poisson's ratio, without physical units, named `Poisson`. + - Mass density, expressed in [kg/m3], named `rho`. + - **VOLUMIC FORCES**: + Volumic forces in the horizontal (`b_x`) or vertical (`b_y`) direction, expressed in [m/s2], must be written as `SetNumber("Volumic Forces/FEM_domain/b_x",0);`, same applies for `b_y`. +- For the electrostatic BEM part: + 1. The lines corresponding to the boundary of the BEM surfaces must be created in such a way that the area of the BEM surface is located on the left of the Curve Loop. + 2. Multiple BEM domains can be defined. One BEM domain should be defined as a `Physical Surface` with the precise name `BEM_domain_X`, with `X` the identifier of the BEM domain (`X=1` if it is the first domain, `X=2` if it is the second one, ...). + 3. Boundary conditions and material properties must then be specified for the BEM domain: + - **BOUNDARY CONDITIONS**: + 1. Dirichlet boundary conditions, corresponding to imposing an electric potential expressed in [V], can be imposed on a physical curve as: + `SetNumber("Boundary Conditions/name_of_the_physical_curve/BEM_domain_X/dirichlet", value_of_potential);`. + 2. Neumann boundary conditions, corresponding to imposing the normal component of the electric field expressed in [V/m], can be imposed on a physical curve as: `SetNumber("Boundary Conditions/name_of_the_physical_curve/BEM_domain_X/neumann", value_of_field);`. + - **MATERIAL PROPERTIES**: The dielectric permittivity of the material inside the BEM domain must be specified. It is done writing `SetNumber("Materials/BEM_domain_X/Epsilon", value_of_Epsilon);`. + + **Note**: These operations must be done for each BEM domain the user wants to create, replacing `X` by the given identifier of the BEM domain. +- For the coupling between the FEM and BEM domains: + 1. All the lines belonging to the interface between the FEM domain and the different BEM domains must be specified as a single `Physical Curve("BEM_FEM_boundary, x)={List_of_the_interface_lines}`. As an example, if `Line(1)`, `Line(4)` and `Line(5)` belong to the intersection of the BEM domains and the FEM domain: + <pre><code> Physical Curve("BEM_FEM_boundary", x) = {1, 4, 5};<code><pre> +- For the mechanical or the coupled solver, the user can choose between the linear or non-linear iterative solver, by setting + `SetNumber("Non_linear_solver",0);` for the linear solver, or `SetNumber("Non_linear_solver",1);` for the non-linear solver. + + + + + + + + diff --git a/bem.nb b/bem.nb new file mode 100644 index 0000000000000000000000000000000000000000..1ba81baaaf6a0e0c29c1d9f3b54138982f4a2f07 --- /dev/null +++ b/bem.nb @@ -0,0 +1,4647 @@ +(* Content-type: application/vnd.wolfram.mathematica *) + +(*** Wolfram Notebook File ***) +(* http://www.wolfram.com/nb *) + +(* CreatedBy='Mathematica 12.1' *) + +(*CacheID: 234*) +(* Internal cache information: +NotebookFileLineBreakTest +NotebookFileLineBreakTest +NotebookDataPosition[ 158, 7] +NotebookDataLength[ 195984, 4639] +NotebookOptionsPosition[ 190249, 4554] +NotebookOutlinePosition[ 190641, 4570] +CellTagsIndexPosition[ 190598, 4567] +WindowFrame->Normal*) + +(* Beginning of Notebook Content *) +Notebook[{ +Cell[TextData[StyleBox["temps et complexit\[EAcute] des diff\[EAcute]rents \ +algorithmes de la bem", "Title"]], "Text", + CellChangeTimes->{ + 3.8612586147638197`*^9},ExpressionUUID->"2a4634af-38af-46df-ba82-\ +22e16ff7cedb"], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{"\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"tottime", "=", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "9"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "26"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "66"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "115"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "194"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "286"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "394"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "506"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "702"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "847"}], "}"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "7"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "21"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "50"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "88"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "141"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "200"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "283"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "345"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "452"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "535"}], "}"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "42"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "251"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "599"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "1157"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "2389"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "3561"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "5576"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "7523"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "11067"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "13760"}], "}"}]}], "}"}], ",", + "\[IndentingNewLine]", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "54"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "494"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "1285"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "2973"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "6234"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "10100"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "16246"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "25339"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "42998"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "51864"}], "}"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "65"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "250"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "456"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "800"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "1241"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "1830"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "2547"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "3241"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "4391"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "5325"}], "}"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "188"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "1665"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "4583"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "11210"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "24026"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "40420"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "62792"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "95113"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "142988"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "180652"}], "}"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "547"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "2942"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "7483"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "17045"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "35325"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "57890"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "90039"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "134877"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "206100"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "257071"}], "}"}]}], "}"}]}], "}"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{"tottime", "=", + RowBox[{"tottime", "[", + RowBox[{"[", "7", "]"}], "]"}]}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g1", "=", + RowBox[{"ListPlot", "[", "tottime", "]"}]}], ";"}], + "\[IndentingNewLine]", "interpolation", "\[IndentingNewLine]", + RowBox[{ + RowBox[{"f", "=", + RowBox[{"Interpolation", "[", + RowBox[{"tottime", ",", + RowBox[{"InterpolationOrder", "\[Rule]", "1"}]}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g2", "=", + RowBox[{"Plot", "[", + RowBox[{ + RowBox[{"f", "[", "x", "]"}], ",", + RowBox[{"{", + RowBox[{"x", ",", "0", ",", "500"}], "}"}]}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{"g1", ",", "g2"}], "]"}], "\[IndentingNewLine]", "fit", + "\[IndentingNewLine]", + RowBox[{"(*", + RowBox[{"line", "=", + RowBox[{"Fit", "[", + RowBox[{"tottime", ",", + RowBox[{"{", + RowBox[{"1", ",", "x"}], "}"}], ",", "x"}], "]"}]}], "*)"}], + "\[IndentingNewLine]", + RowBox[{"parabola", "=", + RowBox[{"Fit", "[", + RowBox[{"tottime", ",", + RowBox[{"{", + RowBox[{"x", "^", "3"}], "}"}], ",", "x"}], "]"}]}], + "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{ + RowBox[{"ListPlot", "[", + RowBox[{"tottime", ",", + RowBox[{"PlotStyle", "\[Rule]", "Red"}]}], "]"}], ",", + RowBox[{"Plot", "[", + RowBox[{ + RowBox[{"{", "parabola", "}"}], ",", + RowBox[{"{", + RowBox[{"x", ",", "0", ",", "500"}], "}"}], ",", + RowBox[{"PlotRange", "\[Rule]", + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "500"}], "}"}], ",", + RowBox[{"{", + RowBox[{"0", ",", "260000"}], "}"}]}], "}"}]}]}], "]"}], ",", + RowBox[{"Frame", "->", "True"}]}], "]"}], "\[IndentingNewLine]", + "formula", "\[IndentingNewLine]", + RowBox[{"fit", "=", + RowBox[{"FindFormula", "[", + RowBox[{"tottime", ",", "x"}], "]"}]}], "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{"g1", ",", + RowBox[{"Plot", "[", + RowBox[{"fit", ",", + RowBox[{"{", + RowBox[{"x", ",", "0", ",", "500"}], "}"}]}], "]"}]}], "]"}], + "\[IndentingNewLine]", + RowBox[{"(*", + RowBox[{"juste", " ", "quelques", " ", "petits", " ", "tests"}], "*)"}], + "\[IndentingNewLine]", "nonlinearmodelfit", "\[IndentingNewLine]", + RowBox[{"nlm", "=", + RowBox[{"NonlinearModelFit", "[", + RowBox[{"tottime", ",", + RowBox[{"a", "*", + RowBox[{"x", "^", "3"}]}], ",", + RowBox[{"{", "a", "}"}], ",", "x"}], "]"}]}], "\[IndentingNewLine]", + RowBox[{"Normal", "[", "nlm", "]"}], "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{ + RowBox[{"ListPlot", "[", "tottime", "]"}], ",", + RowBox[{"Plot", "[", + RowBox[{ + RowBox[{"nlm", "[", "x", "]"}], ",", + RowBox[{"{", + RowBox[{"x", ",", "0", ",", "500"}], "}"}]}], "]"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}], "\[IndentingNewLine]", + RowBox[{"nlm", "[", "\"\<FitResiduals\>\"", "]"}], "\[IndentingNewLine]", + RowBox[{"ListPlot", "[", + RowBox[{"%", ",", + RowBox[{"Filling", "\[Rule]", "Axis"}]}], "]"}], + "\[IndentingNewLine]"}]}]], "Input", + CellChangeTimes->{ + 3.860953426578657*^9, {3.860953463836258*^9, 3.860953584913463*^9}, { + 3.8609536201467247`*^9, 3.860953707544536*^9}, {3.860953745800506*^9, + 3.860953819621065*^9}, {3.8609538556351748`*^9, 3.8609539466166277`*^9}, { + 3.860954009342905*^9, 3.8609541499745893`*^9}, {3.86095418287741*^9, + 3.860954253405746*^9}, {3.8609542847431583`*^9, 3.860954306660102*^9}, + 3.8609543371796837`*^9, {3.860954377783967*^9, 3.8609544724716043`*^9}, { + 3.860954537244658*^9, 3.860954579100382*^9}, {3.8609546179977207`*^9, + 3.860954722852202*^9}, {3.860954871127983*^9, 3.860954949325055*^9}, { + 3.860954981711828*^9, 3.8609550095180683`*^9}, {3.860955064155086*^9, + 3.86095510202353*^9}, {3.860955210151617*^9, 3.86095527115606*^9}, { + 3.8609553014468193`*^9, 3.8609553018922*^9}, {3.860955344616881*^9, + 3.860955369640203*^9}, {3.860955401632543*^9, 3.860955422826654*^9}, { + 3.8611196515343533`*^9, 3.861119686934135*^9}, {3.861123389830142*^9, + 3.861123393073531*^9}, {3.861123423637659*^9, 3.8611234462467403`*^9}, { + 3.8611269092812862`*^9, 3.861127052199102*^9}, {3.861127251583521*^9, + 3.861127310227153*^9}, {3.8612586019290237`*^9, 3.8612586182822723`*^9}, + 3.8612588223947983`*^9, {3.861258880213319*^9, 3.86125892206304*^9}, { + 3.861260785357984*^9, 3.861260794129675*^9}}, + CellLabel->"In[59]:=",ExpressionUUID->"4ed55133-bec1-4475-ad1f-833b36b2d4c6"], + +Cell[BoxData[ + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"0", ",", "0"}], "}"}], ",", + RowBox[{"{", + RowBox[{"50", ",", "547"}], "}"}], ",", + RowBox[{"{", + RowBox[{"100", ",", "2942"}], "}"}], ",", + RowBox[{"{", + RowBox[{"150", ",", "7483"}], "}"}], ",", + RowBox[{"{", + RowBox[{"200", ",", "17045"}], "}"}], ",", + RowBox[{"{", + RowBox[{"250", ",", "35325"}], "}"}], ",", + RowBox[{"{", + RowBox[{"300", ",", "57890"}], "}"}], ",", + RowBox[{"{", + RowBox[{"350", ",", "90039"}], "}"}], ",", + RowBox[{"{", + RowBox[{"400", ",", "134877"}], "}"}], ",", + RowBox[{"{", + RowBox[{"450", ",", "206100"}], "}"}], ",", + RowBox[{"{", + RowBox[{"500", ",", "257071"}], "}"}]}], "}"}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260794774898*^9}, + CellLabel->"Out[60]=",ExpressionUUID->"65fdfe1a-aa66-4933-962e-56e19b792ce1"], + +Cell[BoxData["interpolation"], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260794857626*^9}, + CellLabel->"Out[62]=",ExpressionUUID->"89f7ea64-7da5-4498-b160-d9b88f8879d8"], + +Cell[BoxData[ + GraphicsBox[{{{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.012833333333333334`], + AbsoluteThickness[1.6], + PointBox[{{0., 0.}, {50., 547.}, {100., 2942.}, {150., 7483.}, {200., + 17045.}, {250., 35325.}, {300., 57890.}, {350., 90039.}, {400., + 134877.}, {450., 206100.}, {500., 257071.}}]}, {{}, {}}}, {{{}, {}, + TagBox[ + {RGBColor[0.368417, 0.506779, 0.709798], AbsoluteThickness[1.6], + Opacity[1.], LineBox[CompressedData[" +1:eJwVV3k01I/bHUuYyNJqT2lB2WkT7ieyFCoqa2RsQxLDaDTDiCKVpaJflooI +bepbQrJlyVKW7EJZSkJ2Wmyv96/nPOfec5977jnPOc+ziXLO3IWTRCL5cZBI +/1+HJ+dNDFy/65BIwaev6knp0h4GqOunlOmSVrforWr/p8vg/+UqltKkSzIv +KWhsWwlmUTqJO6VfN3hCM+B1mzgW/hdq+jd5ShfvvNvS2xRQxD05NZXMBRn5 +qLD7bfsgrSVvOJG8Bnzdkl8S2w7BrLV8fCxZFqTd38gJbTbAjVD+g34aUIm/ +ZhL/5wxEpk6+uOGkA+1VJ94bVvpB+tSm4+FXdbA6SAfDvX7YWTn8m/WfDgZH +t+dHzfvBKDFYl7qkg1sN/561qNIRpPe4TidRF4O3kuOckuiYrQ6apbsDceIj +zmwffziJN66VTSEwsj2UK1eCAY8juQN3swmU3vEMtNnFgPelpDzRKgK3ySd/ +LxxlIGjU1U5wjMCBYblh/TAGEkrnUv/uP4D4rLrGxnEGGjy2qje0H4C+pviD +0YoA6LxlHAsU1sfdA/9hmzcTMo0/6+5t1ceXfdP5/JFMcPy0MSnZpw8p9d2a +E4+YKF+vbcjlssyXLZQv6GfiEI1DO+KNPpK4q1ebW7JwUv6qXBzlIJLe93wL +1AnEHsw9zDl/EF1Fsg5OtoEQs/SUbb9+EBK5rh1GjEB0XTKTlsg9iMSMkdo1 +LwNB6Vm9NoXfAAlX/uQ82hqEc/9LXHqabYDEQ8IRLQJsHM0SCKyrNsDnAxZc +b+XZUKsI/Df2xQASWrcDkw3YmJ10mFEjGyJphyTtTDAbLLMtw3mnlnsBOVuO +aTbsXeKon2mG8Ap57eHLFwxdFs/AXLghohZbtw+sDwbn48EenZeGqJsVe/BB +PRhXVjxrLecxgumP+7dvnw2Gh6T08QEJI3g5vbMgs4JxWD36E6+qESK/9gmz +rgZD0NHn4yFbI9S2bb3mmBGM8fN9xp7eRvhlYWjU/DoYn6IsKiMvG2FVA3WF +YXkwYgs0SxueL+tXPWHv7A2Gf1O67mS5Ec7q1+6/PxYMy6ENhWs+L+uXjP4V +WQzGHo6IfZpjRni6Xzj3ksBFiIv+yz3JbQy74cpdC1suYl7pjCZDzBiZa0e+ +6jpfRPfBrpfxSsaY1haOCEm9iGTfomddVsaIibHq5N0cgr+j5gpxnsZo7r1Y +JnIqBOYeP9JNg40hqv7kicSdEHA7CicXZRgjrWWBqSwYCqoZ5WbyrDEKxFMl +Lf+FQkWe57xz7CEMpv06ld54GcVfTDFSfxh4E9KjHxqBL8bdjXMGZvjr3ToJ +WgxcDl/4Rak/Bqm84rJHPndA5P/mrvc6Dlfu1t7urcngz+slSfSexKGn0o02 +9akYP/q/sNzhk9huel5K+2sqmn+aCByfPQmu0XrqxrFU3JXI2xDJb4kC5YtL +/YJpUGZHKS1pWkLpVf/Os2ZpsDDQsuu/agmR/Mxwdm0a9nwd72XHWWLUhqPJ +sTsNkox0N8lkS9TMWUvr/0rD90civideWyJUm/8136qHOL9qMKLyqyVmSs72 +3TB5iMTm2NwnGlZor1TTTvvwEMFnD2kb6VrhNfXalbDOh3DmIZV9M7bCDfK3 +JurwQyjuOVMn5WCFQ4fjPBT501GcSHyPjrBCQd3v/+UcSkeaxm+PnbFWiD93 +tP+OTTqu1D4dr7pnBT/hR0pMj3QcW9owz5FtBUVzmwrdq+nop4yu9vtihfst +BZNV1emomku9I/zTCiz/dTpPOtLxNNZa+tmUFaw2eEVE/kxHjKJQmvGiFTTy +3jef+5sO+vty+QE+ayB0bw6xLgM2Dheeh6yxxvzWJ1cd1DOg80dZc6O0NbKr +JB0Cj2WAVyERVurWUBAk8b2JzMBI6dH309rWGHjh09X6JAMNtjwmN4yscc+i +/8V0dQbiI30sa05ZY238e2sVnkzsmDD02n9lWV828klGUCZM9kf7brlpjSva +/+2qSMiEZ3grQyDJGqstW9715WTiqZRLaNdza2y+KtUuNZaJnYdC7rDarGEw +/ow71uERlFILSgu22eBmQd2pYDyG2gnVDdoVNpA7ISxszfkU+96Il2hz2sEy +7JbfyrDneG7ssPX9OXu0s20ecWm+QuFK4UWRiNMw3OF/bW4iBzSXsID5yNOw +bbE0GFvKgVzJ/PTAzdOgsfdy9K/KxU36z+G3SaeR0DTvXyOfC2pPaYfLi9MY +Y4ZS4h1zsTaH/vpN2zL+MWbv7k+58HTs9HTc5ojxs09+0F7kYXPBscHDOxzB +Ixr5wLUoD23rq5x2qThCvNTrlM3HPBz4mG3Dv88RB9erNRGDeRDdHWX02tQR +CUV5RcIyb1AmQGwh0x1xQOh9XFb0G4jnpXe+KHNE3IsevSGvfBjwkzhXVDvC +JSzqGzkoHzR7aznrOkdo2u2/LB+ZjxpuATpHhyNaeO+8pz7JB/OYj6D5qCNE +HY4Y//iRj64hLWJKlIKEVUVm306/BZ9OnJuhNAUe/WfGuLzfQuPGaGSiLGU5 +V7EYWfZbXN+d8llPiYIOZ/onyt230L7E4xerR4Fkwc7jvR1vcU/qU7qmFwX3 +PBKtv5gXoMZboTbClwIvGP9bcCzAbFnoVDeDAp31vxOkfApg5rELYaEUfHln +3mUXXYClnMSO1jsUyIitdOj8UICdK2eWFO5RMDWau/TvcwGsTpltY6dSUFbu +kiw+VIAXXBy+27MocPJ+12vNV4iukzbxzFcUqBucCwnYUAi+x6+K6/Mo4JKU +ko3fVgiNBYEB2SIKGidqyvI0C3H6qKsAo4yCfxBWf3ukENdTi9U+VlFgYy7z +6ta5QuTNilrL1FFQ4KSi7hldCOG7Hx5WtVPACjuqLlVfiHc/VXTFRing/Bij +zjYrwubQOZ98USestBTR0DMtxtc3zPQZKSekv8xODvMsRtL43GcVWSccELRa +VXOtGOvt5/UyFJ1woeLewNGaYqzcu7Au9oATZsRumzyXLcHE6OKbs55OcLoi +u1SQXIISG07OTSVOgIuOc3vCO9irkW+GuzljXtpPSSi6DCLypmnl913wICZH +RUSjEue0j5zznHTFt84wQS65D/girV9n99sV5IDX2yt2fYAZaa+i6bwrVNd/ +Q/jBD9hZtnlYkccNF44SvvxOHzBkNOs6JuaGtRVzbWvufYDz8bv2NMINyPJO +2bL2I2zODJsyYtxwP9hGw4BUi2qTnqfUODeUS0WY8gnVYo9SC791ghsG83Nd +a6RqsWGiqHpvmhs0Z9bGm2nVotn/5sG5XDd8cK9fOOlfiyMhe7WDvrrhn7l+ +pdtILfTjw3deUqLi5FYlm4j2Oij4Ouz6ok5F398atfDBOgib7saevVScq3Pj +v/ynDl2kHxYjelSEn08pCBathx/VgHncmoq86rUbGVb1SNu9ombLJSrEveb6 +XdvrcVWkuykogor0A3cKnAfr4T2c3d0eRYXaBs04yp967L/vPHE9noqtp3fL +Kgs0oJmnXHQmiwodsk+zws4GcLeGuFV0LM+3/bZrs2cDhp7b+Gz8SsXrCjXZ +TX4NaIhQYwZ8o2JO+aKQDKsBOU4rLzf9pIJIqJ+TvtSAJO2+KMWxZb/c0oNS +1xsQsiH/Tvg0FbVens2SsQ2gTtx40PuXijUd+SUSSQ0w++D+VGuJChs98jPx +tAZoPCRy4rjd0cXe4WH1sgHibLGSMbI7+JqMbqe8awDJeqLaWMgdGttcS4ca +GvBRIKV7QcwdkR+TxQPHGuDsR1rhquwObbH1H1J2fsIhs3bBEg13uHuq/x7S ++gQVuRei4vvccbv4qKzG4U+Y73TYWafvjlGXa8z37p8Qq1dsscvGHfdeknYO +p39C+eqgBzyX3UEyGb6usakRWg2sfMOr7ohm+wXsUmnEy0hm45Vod0i/WnDZ +o9uI+3wBnPwJ7tgrLqy7/1QjLiz6UoSeu4M2qDGhF98I1SH3zaId7hi8FHTC +QqQJ996deCCv6IHGQhFpGkczznsrPjBp8UCy8p7nz3tbkLJuTSynkCeUJMdn +8xw7cL49R0fW6SyykK+/S7Eb5X0xna+SvbAq93enjF0P9D/JcvK1nwNXUUVu +6uE+5Hnle/fHeqNCWtBM4P43RIgGdVxQ80G2spZlVs0AVD4l3zPs9kGJxouj +fVt+orO2ymrgqw8Savi2b1T6ibCa8dWX+3zgd9pxwXb3T3SVIbz0hw/krq9+ +3GL8E1dyes5pT/rgRr8fV7XXT/QkyhDqvDRQbu7NeZ73EzGuyf3SqjRwjZdK +BJoMQcup6m6hOg3dlyUm35wYwoDDuKXdLhryJPyqZu2HsN8aH+O1aPA03Er3 +9hnC4OGe7LUGNDTfC69zuj0EqMqErbSl4aGpycVDPUMYn7svN3uJBsMnLQMb +/Iah4PK01C2chr6mvw9es4bhXJdn1xFBQ+C8lIPF5WG0J3+KKYii4ZWpa1vU +7WGUHOT6G3KHBpnx2coVb4bxL0vo1nQCDW9FJS6lvhuGhqikoutdGk4SuiBq +hpE5pOFo/ICG6zfD81idw4iOdq0WekrDjIboo6mFYVT9oTldzFrGT+13ucEz +Ak4Ke2HyBQ3bw05vUhYagb/GHdXW1zTYt2XGe8iM4MXdtA+GeTT8Xfp4gk9+ +BEM8/7m8yachVm5CJF11BFu8C5cUCmlQPrauTm/fCOw7quOTimmoCdh7tffA +CO4caFUXLKXBiNNG75bZCBqf9NWyy5fzU1Vq7bAZgUHQHIdTNQ2vo1vnXH1H +oCSr6CHftJyXyXbDi2kjoF7fy53YssxnznVUvhjBg5mD9wTaaYh5XO8pWDiC +9VX2jWNdNHTwMW4mtoxg0TNmX84ADWcqqrpf8/xCbc7USr1/NFzV8fAbov6C +56H8J3abfFGr8izFQnEUhRnq1/7U+GL4WdFoZsk4auSqnEzc/dCRLHrK3GwS +ExJ7OUK46cjb/XVkW/MU/tjKPJPlpaPl847J0s9TICXxWleQ6ZgJZPy2752C +sGTrCz4hOjTKRTj/NzoFFUnf09FidLw8qr+BlzwNb8lnxUlKdDx3f0T80J7G +mOSmoFwrOjISfW9nZExj1o5PwdqWjnKdkkS9rGksJo21/DtFR3+vQMrX7GkI +ShUp6jjRISuX/mRD6TSUpGy7y8/SkZLdXhLeNQ0vqbj9jSF03KvVHnYTmcEv +KfLcyFM64pZ4IcecwaWa5jDH53Ts8Lg9an5xBuLnk1e3/kdHUfOWu4HhMzBq +2K1QnEPH4CPiX+OtGaSFuFrfKKFD5zgzO/DpDLSU1b6vKKOjqYjslPlyBo2d +C94XKuhwl78j0pQ3A5Jm3BWnGjpiF7O95CpmYPujLFezmY4fmaNyTd0zmLwV +rfe4lQ7WmsC2hf4ZXIFtvXQHHUJB/GFyQzPY+Gub7a1OOh4OxmtYjM8gJ35y +gPcLHfss5PoDZ2dgalBEY/XQsSVRaVx2YQbfJiMWx/voGHaSzy1cMYvVJpvW +f/5BR8CM9MGJ9bN49GckxWyIDhSJCVzbOAs8zFMsG6GDJ3xt0xa5WXgtHjn4 +dGLZr+hKR6u9s6h+EeQXNEfHU60ZVrHtLE6fOkSaWqDDl3tcz9p5FrPk9dfd +SP7YVTu0cspzFlucnqUeXeGPcvueO9uCZhG8rqtxs5A/ei5+yI5MnsXuC3tV +Kzf7Y01Vyojt91k81Jv+JXTIHxeOm9n98foNNYaONnXaHyPVmwezyv6C2ZB6 +mXHrPPxzx6p6xufQnfD9pocyAyRHUda2NYs4IH1dRUiNgZzrYulUyUWkp6jV +vdJgwD1PvOHx1kV4Z7LJC3sZaBGS2qK8ZxHcOWLB0foMPCva9HH3qUXs+GR6 +NtuaAWvJHZLGGYsI4M0xXAxl4GWbdsEZrSV8uWr3/UEYA1Qu3YFn+kvLdxNX +qGEEAxLKEB43XYLAuqNFMVEMhIcdcPY7vYTkzUMasvEMOGgaCgReXkKltvRm +oywG+G8dtYuqX8I6v7D5G+0MqGWoBrWrkgg+Z5EL5E4G5hW7IhR2kYh5i6Tf +wd0MVGaHxbH2kYhv6i8nz/UxYF/a+VRGj0RkT3UPmo4wcK37cif1OInI7Ke6 +VowycNJZ5Ue+FYlIaprq3z/BwKbhz5MCp0hE6Cvy1x2zy/n8UV75nwuJ8E+N +tUv9w0Aw+/M6Lg8S4XFr42fxOQYO81zedMKLRNiHPra8ucDA+khlxQwaiTD3 +1WwhkwKwcFfXlus8iTBwKjG/yBmARZVMoieQROyzONzwhzsApHJhucJLJGKT +uuOHH+Tlfqh32v8miRifvP6uYk0AOHddihp6RiKiad+eXdwegJV1Ve8+fSMR +IZRzO/7KB4DPUTUza3jZn/m/TO+dy/h0fNS1yWU/asJpDqoBEBA/Y3uQxEEo +TWolaGsFYLXrqpk8CQ7io8+tsL9mAdiweEwu2ZyDIPsccPDxD8AWpc4orxIO +opF1Sjps0wWItd5LdEviIl7/O/6AVX0B3WVHul6dW0FYJLlt3OHKBG1bnOpd +WV5irVNtViOViYTc7OYlBV6iVV5d58IZJsqNms9T1HgJm9xFu2pvJjacWVO0 +neAlKI1xCW5MJoqf3zj00p6X8OYrX5cWwwR5b5RTZTwvEeknIyD1lon7h8Pj +JoT4CDOtsMTyQibed6XvOb6BjxDmHFHwLGEu/2vvO3Ok+YjY6FzjtxVM6Mes +2MxS5COSHpuFWzcwMdIcmsVzmI943MPivP2dCU374EqJMD7CM6PvhvYgEw5j +9z2CIvkIJS+jTd+HmIgILl7VG8tH/De3BhrjTHx+sGiRnspH5K1/Etj4jwn2 +D1aPyjs+otKk44+gMAsfvQP+HpznI0SDZakRq1mothgW3sFFJqivzrZxrWOh +fNcpOeGVZGKlOGfOHzEWiudh+XkDmbAxNdnqK8nCm68vvYqlycST4Nuxv6RZ +yC3dEpa2lUzMv+rhom5iwUjGvN5zB5kw+aHg2yfLAiWUn8NOhUzcFaf32W1j +IXigXO2wJpkYNS0+1ibHwl3jIOd9+8hEdLaFykdF1vL+TlSK6pOJxousX693 +L+sltUa1WJKJLzkb++wcWFhd5/m4Kp1MzMq4fnicxUK6anxvlv5KQtetniJ3 +KBCv6u8uHLzAT9gX/O9k52QgVtwSuiVfI0Ds0WTqGcQEYVWYyfhtLkGilXlA +YcWtIHRL7vITJAsS9FKySHlcEJ6/2vjnsqAg8fLInS9EYhCO9U4u+YkJEjs9 +Xgdopwfh9v54IQtlQULm/thzjYIgSE99VxKyFSTIZGdJ2cEgqJ5mnw1/KUhk +HtnB1TcUBK7f1InFXEHC4Pbkz+RfQWiKNKf7FwoSl2Qv5kpPBeH8262BLlWC +xKL2PXPxxSC8Xf/xut4XQWKS1n5FZC0berWiT5fIQkTMm/vnGtazscaZU+W8 +kBChTHI7GS3Gxvd/w69G1woRnpEzsqs2shEuV/y2e6MQMZCxuphPgY2PoS4f +3moKEZdGOx5W7mQjSfzIEXUtIUJWM+V6mDIbXv/taXoMIeJ0qbINtyYbwl/5 +O+MPCxGLfL9RtpuNHvqMvcgxIeLukaLtIfvYeCnwte/KSSFi/+3LgoQ2G5dS +q1xJdkLE5y6TmSVdNo7vezl03lGI+D+rp8is + "]]}, + Annotation[#, "Charting`Private`Tag$53917#1"]& ]}, {}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{0, 0}, + DisplayFunction->Identity, + Frame->{{False, False}, {False, False}}, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + ImageMargins->0., + ImageSize->Automatic, + ImageSizeRaw->Automatic, + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& )}}, + PlotRange->{{0, 500.}, {0, 257071.}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, Automatic}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260794910377*^9}, + CellLabel->"Out[65]=",ExpressionUUID->"7a89971a-d470-4aba-b097-89238335c823"], + +Cell[BoxData[ + RowBox[{"914.5652349321464`", "\[VeryThinSpace]", "+", + RowBox[{"0.0021137341020296026`", " ", + SuperscriptBox["x", "3"]}]}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260794917577*^9}, + CellLabel->"Out[66]=",ExpressionUUID->"c024bf23-b077-4190-b9e3-f1d5fb19ed2f"], + +Cell[BoxData[ + RowBox[{"0.002124924552859501`", " ", + SuperscriptBox["x", "3"]}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260794921052*^9}, + CellLabel->"Out[67]=",ExpressionUUID->"c87b3cd2-72e1-4211-9c33-d98771a9e76c"], + +Cell[BoxData[ + GraphicsBox[{{{}, + {RGBColor[1, 0, 0], PointSize[0.012833333333333334`], AbsoluteThickness[ + 1.6], PointBox[{{0., 0.}, {50., 547.}, {100., 2942.}, {150., 7483.}, { + 200., 17045.}, {250., 35325.}, {300., 57890.}, {350., 90039.}, {400., + 134877.}, {450., 206100.}, {500., 257071.}}]}, {{}, {}}}, {{{}, {}, + TagBox[ + {RGBColor[0.368417, 0.506779, 0.709798], AbsoluteThickness[1.6], + Opacity[1.], LineBox[CompressedData[" +1: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 + + "]]}, + Annotation[#, "Charting`Private`Tag$53999#1"]& ]}, {}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{0, 0}, + DisplayFunction->Identity, + Frame->True, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + ImageMargins->0., + ImageSize->Automatic, + ImageSizeRaw->Automatic, + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& )}}, + PlotRange->{{0, 500.}, {0, 257071.}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, Automatic}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.8612607949648123`*^9}, + CellLabel->"Out[68]=",ExpressionUUID->"9b57112f-d238-4317-89cb-371ba4a2c235"], + +Cell[BoxData["formula"], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260794976637*^9}, + CellLabel->"Out[69]=",ExpressionUUID->"8a451dcb-573e-4f9f-97e1-ed70aded0195"], + +Cell[BoxData[ + RowBox[{"914.9059240288545`", "\[VeryThinSpace]", "+", + RowBox[{"0.0021137341020296026`", " ", + SuperscriptBox["x", "3"]}]}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.8612607963488626`*^9}, + CellLabel->"Out[70]=",ExpressionUUID->"71c50b88-43c3-43d1-9b99-9504c5bd5f96"], + +Cell[BoxData[ + GraphicsBox[{{{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.012833333333333334`], + AbsoluteThickness[1.6], + PointBox[{{0., 0.}, {50., 547.}, {100., 2942.}, {150., 7483.}, {200., + 17045.}, {250., 35325.}, {300., 57890.}, {350., 90039.}, {400., + 134877.}, {450., 206100.}, {500., 257071.}}]}, {{}, {}}}, {{{}, {}, + TagBox[ + {RGBColor[0.368417, 0.506779, 0.709798], AbsoluteThickness[1.6], + Opacity[1.], LineBox[CompressedData[" +1:eJwV02k41VsbBvAIEW1TJGWODPsgYwr7/ktkyBxRVCpDKZTioK0kxbtt2xQZ +t4whSeakgaKckjpEpaQ0mWeSvP/zYV3r+n1a9/U865bz9Hc4yrlixYoF8vx3 +D03+tjbzGjRu+CKxh5bKwKmCv7VNc5tp9soSrv85hH/Ea33ua5qlpsiZ/6xv +KlXFCuyjBe/lePifw5oKV3Dlfqbd+P3RCaTfvjUuosV8p90JKd5FkN421707 +LHCEdlR5T5UJ6ecx+qHvqBO0BO/+W6akl1Iv7l5gT9FWJ5o6mpOmFnbIrhOb +pbFXhtdYkt5ftWFaJ2aepihxYcKGNOORd6vD0i/acTWbjU6kG1/eSQ8IXKKZ +XuuzcSM9/GH5BHNwmXb+nkruIdLM2QLZbioHpqaoasdIFy5ZrR704oRf2ieu +INJNXJNTU+yVuM9jYhZBups/rY/zHRca03etYpAeFTFuFRbjgW7F2IF00jyS +XypkbVfh9/UtPiWkpeVi0zVieDHwgndrI2k9Zc0o42Y+NMT7f+sgbaPRfWL3 +0mo4EQeZg6S99MJd9usLIJLWZbpE+pyRPHE8cA3WfW2TX5fGQLJpm2poKQWf +WbrQJl1mdXJtzKAg6jLEqu1Je6qsXm6PF4K35+Frp0iPUvtOv6YKoxnrua+S +DtWs+P72qTCyErcINZLm0bnoPuAlgtY7ha++kJbermI+wRaF3WtWn/E1BkqM +f9+dN1oLh5hfewJI65l0aK54txZD50oG80nbWJyRFBQTx6bEJyXr0sn9Wu+K +F68Uh6/vZiFn0l52G7ikbdchdrR2OJU03eXhCDVGAsWB9seVMhhYvS/ZU0dp +PSw22xqdJn3Vw/vN9ub1WPPr6Ndm0uVH1zy0XJKEqVebVGAm+V98+3Ud0jfA +rZb3/XPST/zulLjqb8S7ZKtO9SwG+k67JvsESsHjyKMHS6R9gql8ARRpcFOG +fh7PZmA6dPlccKk09t1ZLv1AWiCywDt6UAYHDnY7vMph4B8Tw1EzQhYVMnE+ +jmwGElsKip/Fy2LOYv2ZXtLSbSFSr6hyuGWT8Wo6l4EvFgNv9oTJobn/kmPs +dXJe7VaJvU/lILZbQ00xj5xXh/SqT17yqFYoNj6eT86ru2V8jK2A3tdJKduL +GIj46O5KmVWAlpmguGAxAxXfZx9SrTbhW1HVgx+khReVk3xnNmHl3kpKdQkD +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 +vN6pklmuLkT8H5cWJlE= + "]]}, + Annotation[#, "Charting`Private`Tag$81847#1"]& ]}, {}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{0, 0}, + DisplayFunction->Identity, + Frame->{{False, False}, {False, False}}, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + ImageMargins->0., + ImageSize->Automatic, + ImageSizeRaw->Automatic, + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& )}}, + PlotRange->{{0, 500.}, {0, 257071.}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, Automatic}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.8612607963738747`*^9}, + CellLabel->"Out[71]=",ExpressionUUID->"db2bab01-4618-4db7-8683-117d6150b911"], + +Cell[BoxData["nonlinearmodelfit"], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260796380981*^9}, + CellLabel->"Out[72]=",ExpressionUUID->"ba354193-5beb-4a8c-962b-96de2fd88bc5"], + +Cell[BoxData[ + TagBox[ + RowBox[{"FittedModel", "[", + TagBox[ + PanelBox[ + TagBox[ + RowBox[{"0.002124924552859501`", " ", + SuperscriptBox["x", "3"]}], + Short[#, 2]& ], + FrameMargins->5], + Editable -> False], "]"}], + InterpretTemplate[ + FittedModel[{ + "Nonlinear", {$CellContext`a -> + 0.002124924552859501}, {{$CellContext`x}, $CellContext`a \ +$CellContext`x^3}}, {1}, {{0, 0}, {50, 547}, {100, 2942}, {150, 7483}, {200, + 17045}, {250, 35325}, {300, 57890}, {350, 90039}, {400, 134877}, {450, + 206100}, {500, 257071}}, + Function[Null, + Internal`LocalizedBlock[{$CellContext`a, $CellContext`x}, #], { + HoldAll}]]& ], + Editable->False, + SelectWithContents->True, + Selectable->True]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260796505725*^9}, + CellLabel->"Out[73]=",ExpressionUUID->"b590e101-f372-4eaa-b07a-74c6853e96a8"], + +Cell[BoxData[ + RowBox[{"0.002124924552859501`", " ", + SuperscriptBox["x", "3"]}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260796514821*^9}, + CellLabel->"Out[74]=",ExpressionUUID->"6b5e6dbe-960f-4c2f-b7df-540c1741735c"], + +Cell[BoxData[ + GraphicsBox[{{{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.012833333333333334`], + AbsoluteThickness[1.6], + PointBox[{{0., 0.}, {50., 547.}, {100., 2942.}, {150., 7483.}, {200., + 17045.}, {250., 35325.}, {300., 57890.}, {350., 90039.}, {400., + 134877.}, {450., 206100.}, {500., 257071.}}]}, {{}, {}}}, {{{}, {}, + TagBox[ + {RGBColor[0.368417, 0.506779, 0.709798], AbsoluteThickness[1.6], + Opacity[1.], LineBox[CompressedData[" +1:eJwVlPc/lY3jh9GhjBwiTsmxInRCMiLH/b4lsjcRCllJVvaqyErISGmgRFMe +KjMKFRpSVkQipcfILnnk+/n+cL2u1/UPXBKufpbubCwsLEv/4/89PvufsZ7H +qLbvtd7pzve6WoE3w3fpFjYRMvtyyqs3DGmHcU96bCr8QMgxz58338BHqOuK +PswIGCAqa+s/3KNvJyLri1kohSOEkGQt65YNIPr6tEuI5DFCt8p4u6GbGaH5 +q9skMmCSsLBWKA+gHyTeJKtH9DNmiNy2MTvpJHdiJTfOZKlgjsjkXa5m3eBP +MIrbxYU3LhKvcheN87+EEI4PReZVkn8TQ2u1RSTcYonURs+Xlit/iD7lbF/n +kXii7l1Fnn/ACiHkmCBhTT9LTAyu+qaNrhJnT5nr6DHPE2mLN8W7Gawo7lqr +wZ+UQxSvGHGNerBBeCLG9WJkHlFPmZ2bK1gDoybpC/P8BUQ398UBtn4KfCtY +Tyfp3SCmNmi/5N/IAYtt1+6mfSkmODZ/LRM3W4t3q89b1/+4Q9AlUvIUk9eh +TVQ3i8ftAaEmqxSv3cQJnn8CPrfIlxOmit2+JitceGtbyWo58pDwUIuyc1Tn +Qa5/L7f0YCURzZQkfQLW4/1xTft99FoiW7dFPuIuL2af6ex7XFxP3DM6Lpg8 +SsUu37s5TOYzwlWOa/VVOh9MBY9XGJk2EVOMgaAPDH6c4r0itzbpORGhVDbW +18oPNsGxmzPjLwkOlTinYY8N4BqgdKdGthH0PXL6MwUC2PuGSZnif0fc0f6v +9jdTEI9iRSta8zsINZ12JZZ+QRygGAmf0vtAmBoEb6ZuFELh/LxDwpduos94 +f7pQuRBiaVvHbHp6CQ9zEQrdTBhLMRwJlB99RIzds0lGMg3a8YZmbG6fCa6D +2a4qMptQ4KuY7f1tiLjg7Nmzp2kTSmafqzXJDxOl7uufGa5sxqlnba+MRr4S +mt5DqpZ5IvDz3JCz58A34sWxijv26lsgKrZJhz74nRgIss/2ChDFaKTQApM+ +TniFMjj9eenYEv2tY8/HCWI+YjU69C4dRvtlUVo8RfCcvumZMCqGQ3/sCQ3m +DPFaR2tKjxQH36XxzEbMEpnNN2+1pYujJ4zKoW86R9BbwkTfMyTQZPddgi1p +gfhqMNxjEymBRco6tUsPF4k7r4wyP7ZK4KBZNibGfxFq7fS1Xzwk0SncSk2M +/EOYdjdP/yyQwrYYw9p/+VkQ+9nJnndRCr7C6weSv7GgbGzxGcNoKwiNS4OO +jazgX5bN8l7YipL8Nwc3ZayBDqVxOdFQGm9udeniNAWB6w8eKc6XxuUmj7GN +UezoFDunOmIgA6fKEY39iWvBLidzjTVfBv3WijbDF9dBTbmBQ3xeBpLnmtiL +yzmRqzvT43htGyTtzrBKr3LDwdsmontWFp5JNg9KY/lwNnBqeF5fDkqSddR3 +8vyoi0w0Ergqh4jMhI2n+vghmla9xVxfHuK1xTHt+gIYKhdtaL28HUWp5c2v +DgqBv+7xtrHp7XDV7Dah7RCGznOzDA49Bhr0Re381tBQ1HPKZe80A6P7gu0i +GjbB87/RNU90FdCmOM5THiKKi+yxx/ovKeCoZks2SyAdLby0rqUpBTTvSArt +DBSDvIRhsdolRRQaJA0UNYrjl6Td1t4QJeR/mhZJ/SWJjJIbBzwLldCjotkm +lioFWcZ06uIrJSw9t86qkNqKA6rJC4ISO2ESfJ/x56A0avRrX1i82okdu+si ++ma2wfL12uWhhZ1oSHT+uy9fFuPm1or+4sp437mT66eZHLY4TOamBSuj1EAk +gFYrj+hjYt6vxHZh39uWiPzqHcD5OO59J1Rg/GWNpoiiMl4OCmmzXVHB0jqN +mdFLyjBl3PFvaFKBw7aEy2Ycu+D08l2XhoAqvnp2GvB83YWIFdEChXJV9HWp +ZpyuUMVD7yoV2rQaKq0q+uk3NbCn0sizS1gdQlcFOsy2a6KR8vlSJqGO0YNa +tRYVmujIZ1/lSVdHnL3VVGfLHkx1WbayKuxGvHKqpRKXNmR1Jp3GfTSwuNUr +J/IEiQfpJzNuZWnA890/Wj0vSKgNCDS512pgekH9kMpmHewL05Qd4tKEaIOi +7VKTDlxLE2c7b2uipUr/zUcpXVzZLJlY/30PUp9OjFsK6UPK61F1JFULt8es +3pwK18edR/sndqtrYU9bu/yrAX1Um/tZVCRoIa91T17F7f3oTqgTuSXNhIDs +IZ61Zobgn7MtO++mDdX+YgOhDhPQnSSsE1O0cZKFU9hO1xSMl+O/ov7RxrT4 +gGdDlSn2Xz5JeK1qI+BDbSjPTTPE7L3zVvsyAR3UPh96bo7F1pjFYG9gOO7v +ff9WS6z8dWuZjgJY5jxSbvJYgaJikOeTAWw9bDAdbm4F/msC2i6VQNaJY4aU +PiswAm+dMWYnMa/3pKti3hpum98LShWS+JsrrCplYIejZpXfrj4k0XFUf83t +C3bwj79SRWshQdcql+z7aoeYKQ9H3p8kdDbL6ZNxB5DXuHxjSUsHEWd2NKu3 +2OPdUeld73p1MCoqFnk0yBHatWEW0Xy6eN2cIr5W3gXi73+8vSati6q+Ikrk +YRew/nAwfqqpizM/ZPJccl3QLMTUX+Oui67F9JokDlcYBrIyk6t1oTqntGT0 +ryts5VJkc1z3gfNs4gNqyxH45V5evfdQDyG/zKjdn71gXsoT/bZVD9IX1JWT +pb2h/Dz6z89BPTyx+Umt9/HG4uyhBWVOfdzS+u9T6ZI3oky3jlc56cPk9YvR +ahEfJLHf727m2I/13L/nBsN8URBUf//TAQN4jbQm2ZkEYGnKUj7nmAEq2Itd +PgYHwPLo92KTkwa4AV+dvGsBoLjwFdSXGOCsrcnnj9MB8DJ1zSxYNMAhJ73P +NhcDoSTHEXok2xBCpaUNPnNBaBg0wUS7EbIFfmq794eA5jBcVzRihBpWWrsM +Tyj8u0I0nH4ZIba6NG4HMxSSr/OV39KNQfv0SJS7IBQJ1TNby3yNsW+/6HEe +7zCYZudwnuA2QVrWiL7luggMGgy8X9YzRfn9ryJkdDQ2lKz8cXA0ReQTo/jP +tdHQo9ClagJMYTK436r7TzTu1zsHhV0xRfj+KdG34TGI2jUksDBjinXBuiqT +kbHYJDpiPXXFDDd+ck6kt5yEfNgJH/9wc7gyFw3OsMShuTh+VSzeHE16i4q5 +0nFw7srOak8zh7vCKOOjYRwylR/VKhSZQ1qAMjaZE4eliQXuybfmyDwX3Oak +EI8Wl9B73lstYEO/Hh7odQbuRhGTru0WqPH/bWzAlgRxsvfq0EcL1J90Lm5n +JOGTmpqp81cLGIQM0pLskmApOVtqv2SBDpaZ+vT7ScCSt7+5lCUUtzTprxxM +xpYS+zlmqCVsHyhSfRpT8IFNY4kmZoUsl9fnDj0+h7TfF25fkLPCw/73G12/ +n4Ph1Ly9oMr/unyzex4tDU8/ltVQDaywyWNX+73INJSWyUZxBFlB0mec01E3 +HSnOtNW5F1a4Tds39dcvA2TNL0r7cWvsPpKZmCaeid2u31UuhllDwPzcqWLN +TChx9RxxOW2N26qr4T3WmaA7PG6ey7EGo2zDhfjkTPxZOhFPe2INtvK4Vp75 +TDzUmF3jym0D9iNj5z+/yYJM9QTbQokNbthnGA1n54C76guLyBdbhJouhS0F +XsK0eW5C5bgtLDkyOgMvXELnD2Me60VbrPm+Kry+5hKuilQJn+O2Q9xLh6wi +1jwoxqYprKraISU+hcMlMw9WenscR1LsIDjB3CVacxmXO7Mr76ocQPpBa4P1 +UtewfUb/uFaSPdSS8p/xPSiEsVZ60NZMe8gMndxe2lSIY4ndYTxX7FGokJt9 +sLcQ90Td4z49sEdfDSP6G+t1MAxPX4zqsUfel1M2T2yuQ+FGXWOdjANcZznS +T7DcgLLNTmHmcweYB/AlqrgWQbN681MmmyOOejbl2hwowQODQ9Iv/JzRuyso +j3/hPp5w8f3lTz4Me3NuvXa1CmyuKu4va3IBR/ChfpEPlZCMWw6oobmhTMko +oeriEzgrc2Ymeh6B1OXD31XXN4JfzqSoOd8d+R3hAv5Rz+HHNPM7NusB39oT +/j/vtUL3UiIjXsELWTC2EuJ5i+YNMdc5zniDtv8cl8etDoT677hu3HUUGck/ +vP4kdKJwo0A2G/UYWi4vvrAI60Fo72NtKTdfXAiJDh9e7EPzcEZ/RcFxVFzU +fxSUMAjdDim2db1+aNZNO+my7Quqjtf4j2T7Q4RdyUfs8AiSaTEfI5QD8Hjc +u8Li6iiUOgqu6Q8EIM91crlIcwzTy/myi/GBUDwy76P1918cM6y56ygRhMBu +itTPp5N4UrLr7O+2IKy8GEllj5hGm2yLm7H3Cfwu8BYf45/FjIgG62lKMJ6N +iVCja+YwKcq5PHEvGM3fBiKf3ljAzb3zk1TDEPDIlfV1Jf6Ccpg202s+BL9X +qjMvViwh8t2NM2FZofBZHLWM7F3GQN5o5lHFMPg5XTcNoP7FxhMJ/53vDYMH +Iz21xYiF5AzQORQQEo5S5dt9O1NYyfdRTvQEiQjI0oSTNy2wkY/+WF+Pao3A +Y15D0399KKTVFU+x7R6R8Lr5z7+n+9jJl8Yff/PyRWFgN81lLmItuSju8epO +aRTKSt2uTPFzkoRnu6usYTT6t/gv2Zdzkc51ubb9s9FYNpep2ZTCQ+5Wjdyr +lxGDu14VMX42vGR3pI48e1YMGINJAledeMngRk7+5pwY9D5NEH/tzkuWm10c +JC/HQHDy9A2FEF6ScfRROLM4Bgt1ChbsubykeP7PByp1MRiijXgt9fKSnJxH +tkiN/e+jj1RDVpyo5C2z7WuG/42BDEeqhYMHldS7MPujYDIGSg17b1cdp5Lx +Uqcq6XMx6Ep2fhseSyX/Mq9Zbv4bgy1Oc7PrC6nkbGBvEr9gLHb3yTZFf6WS +GdX5fu+EYsFzyOfE7ASVVGTxtE3fFIvh1u1FXgtU8ti5Ban1YrEIrupuYKzh +I7+VbGhYJx8L6WnlHBlBPjJ+6uPNl4xY+FYV/fCg8ZFSqoWpCYqxEM36tFKy +hY883KjoQFGNhQt12J0hzUf+XfcLTeqxeBvWUe0nx0deNavfdlozFrbxbW8q +dvCRWhfO8JLMWHzdOFj4eycf2ffJeGGViIUbv6iathof+X+cc/aI + "]]}, + Annotation[#, "Charting`Private`Tag$81961#1"]& ]}, {}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{0, 0}, + DisplayFunction->Identity, + Frame->True, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + ImageMargins->0., + ImageSize->Automatic, + ImageSizeRaw->Automatic, + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& )}}, + PlotRange->{{0, 500.}, {0, 257071.}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, Automatic}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.86126079657021*^9}, + CellLabel->"Out[75]=",ExpressionUUID->"f64ed0f3-5f81-46ef-b0d2-0deaec21c948"], + +Cell[BoxData[ + RowBox[{"{", + RowBox[{ + "0.`", ",", "281.38443089256236`", ",", "817.0754471404989`", ",", + "311.37963409918393`", ",", "45.60357712399127`", ",", + "2123.053861570297`", ",", "517.0370727934715`", ",", + RowBox[{"-", "1067.140203851115`"}], ",", + RowBox[{"-", "1118.1713830080698`"}], ",", "12466.250120677956`", ",", + RowBox[{"-", "8544.569107437623`"}]}], "}"}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260796584264*^9}, + CellLabel->"Out[76]=",ExpressionUUID->"1ad22f7c-dddb-4448-9317-229eaab684eb"], + +Cell[BoxData[ + GraphicsBox[{{}, GraphicsComplexBox[CompressedData[" +1:eJxTTMoPSmViYGBQAGIQDQEf7BlQgQPXJ8aFatMKHSBcDgeNE+wtszo6oXwB +B4F2k99CZcVQvogDg8gTZqezblC+hMOD1H2TpactgPJlHBxkLr3x1miA8hUc +HHRnTuxfM+EAhK/kwPCbrX59xcQDMPtRnaPm4GDSfMNjw4ED909asmYYKjtU +zA3weOKx20Fmd1HmpFYVOB/mXlT9Amh8ETS+BBpfBo2vgMZXwnAfKn+whaeK +w4fAL8wKkSccYO6FhScAM8lexg== + "], {{{}, {}, {}, + {RGBColor[0.368417, 0.506779, 0.709798], Opacity[0.3], LineBox[{19, 8}], + LineBox[{20, 9}], LineBox[{21, 11}]}, + {RGBColor[0.368417, 0.506779, 0.709798], Opacity[0.3], LineBox[{10, 2}], + LineBox[{14, 3}], LineBox[{15, 4}], LineBox[{16, 5}], + LineBox[{17, 6}], LineBox[{18, 7}]}}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[ + 0.012833333333333334`], AbsoluteThickness[1.6], + PointBox[{22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}]}}], {{}, {}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{0., 0}, + DisplayFunction->Identity, + Frame->{{False, False}, {False, False}}, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + ImageMargins->0., + ImageSize->Automatic, + ImageSizeRaw->Automatic, + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& )}}, + PlotRange->{{0., 11.}, {-8544.569107437623, 6984.891728437848}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.05], + Scaled[0.05]}}, + Ticks->{Automatic, Automatic}]], "Output", + CellChangeTimes->{ + 3.860953469098629*^9, 3.860953709361183*^9, 3.860953820838641*^9, + 3.860953948078908*^9, 3.860954013883754*^9, 3.860954046377944*^9, + 3.860954151038829*^9, 3.860954255700719*^9, 3.860954350633729*^9, { + 3.860954414483062*^9, 3.860954437320591*^9}, 3.860954583772027*^9, + 3.8609546361711683`*^9, {3.860954685049466*^9, 3.860954723270211*^9}, { + 3.860954914169093*^9, 3.860954938685191*^9}, {3.860954982682733*^9, + 3.860955010729517*^9}, {3.860955047851603*^9, 3.86095510246842*^9}, { + 3.86095527369858*^9, 3.860955302695095*^9}, {3.860955345454904*^9, + 3.860955369948269*^9}, {3.860955402566491*^9, 3.860955428206354*^9}, { + 3.861123438131472*^9, 3.861123456327256*^9}, 3.861127055114929*^9, { + 3.861127264611608*^9, 3.861127274891913*^9}, 3.861127311959764*^9, + 3.861181688408037*^9, 3.861259438722706*^9, 3.861260796613441*^9}, + CellLabel->"Out[77]=",ExpressionUUID->"f67cbd93-c669-4bc7-87c6-cf7ae689c11a"] +}, Open ]], + +Cell[TextData[StyleBox["\[EAcute]tude de la convergence de la solution num\ +\[EAcute]rique vers la solution analytique du champ \[EAcute]lectrique de la \ +BEM en fonction du nombre de points de gauss utilis\[EAcute] pour l\ +\[CloseCurlyQuote]int\[EAcute]gration", "Title"]], "Text", + CellChangeTimes->{{3.861258741265164*^9, + 3.86125880430346*^9}},ExpressionUUID->"a9e8cb00-e27d-4ce1-93f1-\ +c63f24dce0c4"], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{ + RowBox[{"(*", + RowBox[{ + "convergence", " ", "de", " ", "la", " ", "solution", " ", + "num\[EAcute]rique", " ", "g\[EAcute]n\[EAcute]ralisation"}], "*)"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"dataelectricfieldgauss", "=", + RowBox[{ + "Import", "[", "\"\</Users/Kevin/BEM/build/Debug/gauss_square.csv\>\"", + "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"dataelectricfieldanaly", "=", + RowBox[{ + "Import", "[", "\"\</Users/Kevin/BEM/build/Debug/analytique.csv\>\"", + "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{"(*", + RowBox[{ + RowBox[{"dataelectricfieldgauss", "=", + RowBox[{ + "Import", "[", "\"\</Users/Kevin/BEM/build/Debug/gauss_hole_48.csv\>\"", + "]"}]}], ";", "\[IndentingNewLine]", + RowBox[{"dataelectricfieldanaly", "=", + RowBox[{ + "Import", "[", + "\"\</Users/Kevin/BEM/build/Debug/gauss_hole_analytique.csv\>\"", + "]"}]}], ";"}], "*)"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"dataelectricfieldanaly", "=", + RowBox[{"dataelectricfieldanaly", "[", + RowBox[{"[", "1", "]"}], "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"abserror", "=", + RowBox[{"{", "}"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"relativeerror", "=", + RowBox[{"{", "}"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{"For", "[", + RowBox[{ + RowBox[{"i", "=", "1"}], ",", + RowBox[{"i", "\[LessEqual]", + RowBox[{"Length", "[", "dataelectricfieldgauss", "]"}]}], ",", + RowBox[{"i", "++"}], ",", "\[IndentingNewLine]", + RowBox[{ + RowBox[{"AppendTo", "[", + RowBox[{"abserror", ",", + RowBox[{"{", + RowBox[{ + RowBox[{"2", "*", "i"}], ",", + RowBox[{"Sqrt", "[", + RowBox[{"Sum", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"dataelectricfieldgauss", "[", + RowBox[{"[", + RowBox[{"i", ",", "j"}], "]"}], "]"}], "-", + RowBox[{"dataelectricfieldanaly", "[", + RowBox[{"[", "j", "]"}], "]"}]}], ")"}], "^", "2"}], ",", + RowBox[{"{", + RowBox[{"j", ",", "1", ",", + RowBox[{"Length", "[", "dataelectricfieldanaly", "]"}]}], + "}"}]}], "]"}], "]"}]}], "}"}]}], "]"}], ";", + "\[IndentingNewLine]", + RowBox[{"AppendTo", "[", + RowBox[{"relativeerror", ",", + RowBox[{"{", + RowBox[{ + RowBox[{"i", "*", "2"}], ",", + RowBox[{"Sqrt", "[", + RowBox[{ + RowBox[{"(", + RowBox[{"Sum", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"dataelectricfieldgauss", "[", + RowBox[{"[", + RowBox[{"i", ",", "j"}], "]"}], "]"}], "-", + RowBox[{"dataelectricfieldanaly", "[", + RowBox[{"[", "j", "]"}], "]"}]}], ")"}], "^", "2"}], ",", + RowBox[{"{", + RowBox[{"j", ",", "1", ",", + RowBox[{"Length", "[", "dataelectricfieldanaly", "]"}]}], + "}"}]}], "]"}], ")"}], "/", + RowBox[{"(", + RowBox[{"Sum", "[", + RowBox[{ + RowBox[{ + RowBox[{"dataelectricfieldanaly", "[", + RowBox[{"[", "j", "]"}], "]"}], "^", "2"}], ",", + RowBox[{"{", + RowBox[{"j", ",", "1", ",", + RowBox[{"Length", "[", "dataelectricfieldanaly", "]"}]}], + "}"}]}], "]"}], ")"}]}], "]"}]}], "}"}]}], "]"}], ";"}]}], + "]"}], "\[IndentingNewLine]", "abserror", "\[IndentingNewLine]", + "relativeerror", "\[IndentingNewLine]", "\[IndentingNewLine]"}]}]], "Input", + CellChangeTimes->{{3.861120198227779*^9, 3.8611202086509027`*^9}, { + 3.861120476136898*^9, 3.861120519489415*^9}, {3.861121142471794*^9, + 3.861121397677162*^9}, {3.8611214473307447`*^9, 3.8611217038415203`*^9}, { + 3.861121977612794*^9, 3.861122033978256*^9}, {3.861122363404669*^9, + 3.8611223692759743`*^9}, {3.861122481670773*^9, 3.861122549413241*^9}, { + 3.861122748564005*^9, 3.861122817288172*^9}, {3.861122981637671*^9, + 3.8611229828416443`*^9}, {3.861123153290061*^9, 3.861123155911878*^9}, { + 3.8611289012277*^9, 3.8611289088187933`*^9}, {3.861129299526593*^9, + 3.8611293058475227`*^9}, {3.861173521581609*^9, 3.861173527697165*^9}}, + CellLabel-> + "In[259]:=",ExpressionUUID->"3022f7f2-8c9c-43ae-9732-d602151de8a8"], + +Cell[BoxData[ + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"2", ",", "95004.77856950945`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"4", ",", "36205.63944299908`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"6", ",", "12316.897572120495`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"8", ",", "2753.571943809188`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"10", ",", "1108.913267961656`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"12", ",", "326.093452993495`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"14", ",", "99.14905399558761`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"16", ",", "30.407862601472058`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"18", ",", "9.580813127287266`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"20", ",", "3.011998313412531`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"22", ",", "0.8988662191894848`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"24", ",", "0.2548494065129372`"}], "}"}]}], "}"}]], "Output", + CellChangeTimes->{3.861122551406989*^9, 3.861123161460887*^9, + 3.8611289120849953`*^9, 3.861129326381927*^9, 3.861173532512989*^9}, + CellLabel-> + "Out[265]=",ExpressionUUID->"953df72a-406a-4325-a6b7-b588ecdbd337"], + +Cell[BoxData[ + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"2", ",", "6.722461226945124`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"4", ",", "2.561881739182639`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"6", ",", "0.8715337018995811`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"8", ",", "0.19484052177773273`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"10", ",", "0.07846580519592629`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"12", ",", "0.02307410876712432`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"14", ",", "0.007015706801379136`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"16", ",", "0.0021516357430706665`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"18", ",", "0.0006779305813935762`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"20", ",", "0.00021312656249943826`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"22", ",", "0.00006360304605405775`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"24", ",", "0.000018032937708914684`"}], "}"}]}], "}"}]], "Output",\ + + CellChangeTimes->{3.861122551406989*^9, 3.861123161460887*^9, + 3.8611289120849953`*^9, 3.861129326381927*^9, 3.861173532566594*^9}, + CellLabel-> + "Out[266]=",ExpressionUUID->"505cf359-5431-4db8-b379-4278c65326ec"] +}, Open ]], + +Cell[BoxData[ + RowBox[{"\[IndentingNewLine]", + RowBox[{"(*", + RowBox[{"plot", " ", "part"}], "*)"}]}]], "Input", + CellChangeTimes->{{3.861122068014279*^9, + 3.8611220747751293`*^9}},ExpressionUUID->"5184b6ce-6f3e-4ace-8f94-\ +4112569cfa78"], + +Cell[BoxData[{ + RowBox[{ + RowBox[{"g1", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"abserror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"PlotStyle", "\[Rule]", "Red"}], ",", + RowBox[{"Joined", "\[Rule]", "True"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g2", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"abserror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{"g1", ",", "g2"}], "]"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g3", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"relativeerror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"PlotStyle", "\[Rule]", "Red"}], ",", + RowBox[{"Joined", "\[Rule]", "True"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g4", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"relativeerror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{"g3", ",", "g4"}], "]"}]}], "Input", + CellChangeTimes->{{3.8611220359218893`*^9, 3.861122092969523*^9}}, + CellLabel-> + "In[267]:=",ExpressionUUID->"131c83d3-03c9-4c25-8f61-e5f9f199818d"], + +Cell[BoxData[ + GraphicsBox[{{{}, {{}, {}, + {RGBColor[1, 0, 0], PointSize[0.012833333333333334`], AbsoluteThickness[ + 1.6], LineBox[{{2., 11.461682470049317`}, {4., 10.496970171398734`}, { + 6., 9.418727384930653}, {8., 7.920654236492377}, {10., + 7.011135776863383}, {12., 5.787184005910186}, {14., + 4.5966243137764415`}, {16., 3.414701213177399}, {18., + 2.259762465968268}, {20., 1.1026037499814914`}, { + 22., -0.10662106627415432`}, { + 24., -1.367082470968909}}]}}, {{}, {}}}, {{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.012833333333333334`], + AbsoluteThickness[1.6], + PointBox[{{2., 11.461682470049317`}, {4., 10.496970171398734`}, {6., + 9.418727384930653}, {8., 7.920654236492377}, {10., 7.011135776863383}, { + 12., 5.787184005910186}, {14., 4.5966243137764415`}, {16., + 3.414701213177399}, {18., 2.259762465968268}, {20., + 1.1026037499814914`}, {22., -0.10662106627415432`}, { + 24., -1.367082470968909}}]}, {{}, {}}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{1.5416666666666667`, -2.3710061312278032`}, + DisplayFunction->Identity, + Frame->{{True, True}, {True, True}}, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->FrontEndValueCache[{{ + Charting`ScaledTicks[{Log, Exp}], + Charting`ScaledFrameTicks[{Identity, Identity}]}, { + Automatic, Automatic}}, {{{{-2.3025850929940455`, + FormBox[ + TagBox[ + InterpretationBox[ + StyleBox["\"0.1\"", ShowStringCharacters -> False], 0.1, + AutoDelete -> True], NumberForm[#, { + DirectedInfinity[1], 1}]& ], TraditionalForm], {0.01, 0.}}, {0., + FormBox["1", TraditionalForm], {0.01, 0.}}, {2.302585092994046, + FormBox["10", TraditionalForm], {0.01, 0.}}, {4.605170185988092, + FormBox["100", TraditionalForm], {0.01, 0.}}, {6.907755278982137, + FormBox["1000", TraditionalForm], {0.01, 0.}}, {9.210340371976184, + FormBox[ + TemplateBox[{"10", "4"}, "Superscript", SyntaxForm -> + SuperscriptBox], TraditionalForm], {0.01, 0.}}, { + 11.512925464970229`, + FormBox[ + TemplateBox[{"10", "5"}, "Superscript", SyntaxForm -> + SuperscriptBox], TraditionalForm], {0.01, 0.}}, {-4.605170185988091, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.912023005428146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.506557897319982, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.2188758248682006`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.995732273553991, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.8134107167600364`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.659260036932778, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.5257286443082556`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.4079456086518722`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.6094379124341003`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.2039728043259361`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.916290731874155, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.6931471805599453, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.5108256237659907, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.35667494393873245`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.2231435513142097, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.10536051565782628`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 0.6931471805599453, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.0986122886681098`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.3862943611198906`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.6094379124341003`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.791759469228055, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.9459101490553132`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.0794415416798357`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.1972245773362196`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.995732273553991, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.4011973816621555`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.6888794541139363`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.912023005428146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.0943445622221, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.248495242049359, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.382026634673881, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.499809670330265, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.298317366548036, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.703782474656201, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.991464547107982, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.214608098422191, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.396929655216146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.551080335043404, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.684611727667927, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.802394763324311, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 7.600902459542082, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.006367567650246, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.294049640102028, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.517193191416238, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.699514748210191, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.85366542803745, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.987196820661973, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9.104979856318357, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9.903487552536127, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.308952660644293`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.596634733096073`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.819778284410283`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.002099841204238`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.156250521031495`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.289781913656018`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.407564949312402`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12.206072645530174`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12.611537753638338`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12.89921982609012, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.122363377404328`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.304684934198283`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.458835614025542`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.592367006650065`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.710150042306449`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.815510557964274`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.9108207377686, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.997832114758229`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 14.077874822431765`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 14.151982794585487`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}}, {{-2.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {0., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, { + 2.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {5., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, { + 7.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, { + 10., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, + 0.}}, {-5., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 0.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 7., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}}}, { + Automatic, Automatic}}], + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& )}}, + PlotRange->{{1.5416666666666667`, 24.}, {-2.3710061312278032`, + 11.461682470049317`}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, + Charting`ScaledTicks[{Log, Exp}]}]], "Output", + CellChangeTimes->{{3.861121495823804*^9, 3.861121503028514*^9}, { + 3.861121598448876*^9, 3.861121612760919*^9}, {3.861121651882359*^9, + 3.861121708912607*^9}, {3.861122010692439*^9, 3.8611220241323547`*^9}, + 3.861122096424819*^9, 3.861122537165831*^9, 3.861123164008923*^9, + 3.861128916416933*^9, 3.861129335734619*^9, 3.861173536753436*^9}, + CellLabel-> + "Out[269]=",ExpressionUUID->"d727041d-b24d-4120-99a1-a4716f0510ef"], + +Cell[BoxData[ + GraphicsBox[{{{}, {{}, {}, + {RGBColor[1, 0, 0], PointSize[0.012833333333333334`], AbsoluteThickness[ + 1.6], LineBox[{{2., 1.9054543414901217`}, {4., 0.940742042839539}, { + 6., -0.1375007436285417}, {8., -1.6355738920668188`}, { + 10., -2.545092351695813}, {12., -3.7690441226490092`}, { + 14., -4.959603814782754}, {16., -6.141526915381797}, { + 18., -7.296465662590927}, {20., -8.453624378577704}, { + 22., -9.662849194833349}, { + 24., -10.923310599528104`}}]}}, {{}, {}}}, {{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.012833333333333334`], + AbsoluteThickness[1.6], + PointBox[{{2., 1.9054543414901217`}, {4., 0.940742042839539}, { + 6., -0.1375007436285417}, {8., -1.6355738920668188`}, { + 10., -2.545092351695813}, {12., -3.7690441226490092`}, { + 14., -4.959603814782754}, {16., -6.141526915381797}, { + 18., -7.296465662590927}, {20., -8.453624378577704}, { + 22., -9.662849194833349}, {24., -10.923310599528104`}}]}, {{}, {}}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{1.5416666666666667`, -11.927234259787001`}, + DisplayFunction->Identity, + Frame->{{True, True}, {True, True}}, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->FrontEndValueCache[{{ + Charting`ScaledTicks[{Log, Exp}], + Charting`ScaledFrameTicks[{Identity, Identity}]}, { + Automatic, Automatic}}, {{{{-11.512925464970229`, + FormBox[ + TemplateBox[{"10", + RowBox[{"-", "5"}]}, "Superscript", SyntaxForm -> SuperscriptBox], + TraditionalForm], {0.01, 0.}}, {-9.210340371976182, + FormBox[ + TemplateBox[{"10", + RowBox[{"-", "4"}]}, "Superscript", SyntaxForm -> SuperscriptBox], + TraditionalForm], {0.01, 0.}}, {-6.907755278982137, + FormBox["0.001`", TraditionalForm], {0.01, 0.}}, {-4.605170185988091, + + FormBox[ + TagBox[ + InterpretationBox[ + StyleBox["\"0.010\"", ShowStringCharacters -> False], 0.01, + AutoDelete -> True], NumberForm[#, { + DirectedInfinity[1], 3}]& ], TraditionalForm], {0.01, + 0.}}, {-2.3025850929940455`, + FormBox[ + TagBox[ + InterpretationBox[ + StyleBox["\"0.100\"", ShowStringCharacters -> False], 0.1, + AutoDelete -> True], NumberForm[#, { + DirectedInfinity[1], 3}]& ], TraditionalForm], {0.01, 0.}}, {0., + FormBox["1", TraditionalForm], {0.01, 0.}}, {2.302585092994046, + FormBox["10", TraditionalForm], {0.01, 0.}}, {-13.815510557964274`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-13.122363377404328`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-12.716898269296165`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-12.429216196844383`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-12.206072645530174`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-12.02375108873622, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-11.86960040890896, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-11.736069016284437`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-11.618285980628055`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-10.819778284410283`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-10.41431317630212, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-10.126631103850338`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-9.903487552536127, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-9.721165995742174, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-9.567015315914915, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-9.433483923290392, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-9.315700887634009, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-8.517193191416238, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-8.111728083308073, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-7.824046010856292, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-7.600902459542082, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-7.418580902748128, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-7.264430222920869, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-7.1308988302963465`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-7.013115794639964, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-6.214608098422191, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.809142990314028, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.521460917862246, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.298317366548036, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.115995809754082, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.961845129926823, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.8283137373023015`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.710530701645918, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.912023005428146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.506557897319982, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.2188758248682006`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.995732273553991, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.8134107167600364`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.659260036932778, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.5257286443082556`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.4079456086518722`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.6094379124341003`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.2039728043259361`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.916290731874155, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.6931471805599453, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.5108256237659907, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.35667494393873245`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.2231435513142097, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.10536051565782628`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 0.6931471805599453, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.0986122886681098`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.3862943611198906`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.6094379124341003`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.791759469228055, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.9459101490553132`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.0794415416798357`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.1972245773362196`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.995732273553991, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.4011973816621555`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.6888794541139363`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.912023005428146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.0943445622221, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.248495242049359, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.382026634673881, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.499809670330265, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.605170185988092, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}}, {{-10., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, + 0.}}, {-7.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, + 0.}}, {-5., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, + 0.}}, {-2.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {0., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, { + 2.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, + 0.}}, {-12.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-12., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-11.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-11., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-10.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-9.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-9., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-8.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-8., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-7., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-6.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-6., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 0.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}}}, { + Automatic, Automatic}}], + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& )}}, + PlotRange->{{1.5416666666666667`, 24.}, {-11.927234259787001`, + 1.9054543414901217`}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, + Charting`ScaledTicks[{Log, Exp}]}]], "Output", + CellChangeTimes->{{3.861121495823804*^9, 3.861121503028514*^9}, { + 3.861121598448876*^9, 3.861121612760919*^9}, {3.861121651882359*^9, + 3.861121708912607*^9}, {3.861122010692439*^9, 3.8611220241323547`*^9}, + 3.861122096424819*^9, 3.861122537165831*^9, 3.861123164008923*^9, + 3.861128916416933*^9, 3.861129335734619*^9, 3.8611735369093018`*^9}, + CellLabel-> + "Out[272]=",ExpressionUUID->"bbcb174f-e6ea-4287-b0fd-9ee0a29f0795"], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{ + RowBox[{"(*", + RowBox[{ + "pour", " ", "le", " ", "carr\[EAcute]", " ", "uniquement", " ", + "comparaison", " ", "par", " ", "rapport", " ", "\[AGrave]", " ", "la", + " ", "vraie", " ", "valeur", " ", "analytique"}], "*)"}], + "\[IndentingNewLine]", + RowBox[{"(*", + RowBox[{ + RowBox[{ + RowBox[{ + "erreur", " ", "entre", " ", "la", " ", "solution", " ", + "num\[EAcute]rique", " ", "de", " ", "gauss", " ", "et", " ", "la", " ", + "vrai", " ", "solution", " ", "analytique", " ", "du", " ", + "carr\[EAcute]"}], " ", "-", " ", + RowBox[{"exemple", " ", "100", "*", "100"}]}], ",", " ", + RowBox[{"20000", " ", "\[EAcute]l\[EAcute]ments"}], ",", " ", "triangle", + ",", " ", + RowBox[{"200", "V", " ", + RowBox[{"d", "'"}], "un", " ", "c\[OHat]t\[EAcute]", " ", "et", " ", + "100", "V", " ", "de", " ", + RowBox[{"l", "'"}], "autre"}], ",", " ", + RowBox[{ + "probl\[EGrave]mes", " ", "sur", " ", "les", " ", "bords", " ", "du", " ", + "aux", " ", "\[EAcute]l\[EAcute]ments", " ", "constants", " ", "de", + " ", "la", " ", "BEM"}]}], "*)"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"datasquareanalytique", " ", "=", " ", + RowBox[{"Table", "[", + RowBox[{"100", ",", + RowBox[{"{", + RowBox[{"i", ",", "1", ",", + RowBox[{"Length", "[", "dataelectricfieldanaly", "]"}]}], "}"}]}], + "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"abserror", "=", + RowBox[{"{", "}"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"relativeerror", "=", + RowBox[{"{", "}"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{"For", "[", + RowBox[{ + RowBox[{"i", "=", "1"}], ",", + RowBox[{"i", "\[LessEqual]", + RowBox[{"Length", "[", "dataelectricfieldgauss", "]"}]}], ",", + RowBox[{"i", "++"}], ",", "\[IndentingNewLine]", + RowBox[{ + RowBox[{"AppendTo", "[", + RowBox[{"abserror", ",", + RowBox[{"{", + RowBox[{ + RowBox[{"2", "*", "i"}], ",", + RowBox[{"Sqrt", "[", + RowBox[{"Sum", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"dataelectricfieldgauss", "[", + RowBox[{"[", + RowBox[{"i", ",", "j"}], "]"}], "]"}], "-", + RowBox[{"datasquareanalytique", "[", + RowBox[{"[", "j", "]"}], "]"}]}], ")"}], "^", "2"}], ",", + RowBox[{"{", + RowBox[{"j", ",", "1", ",", + RowBox[{"Length", "[", "datasquareanalytique", "]"}]}], + "}"}]}], "]"}], "]"}]}], "}"}]}], "]"}], ";", + "\[IndentingNewLine]", + RowBox[{"AppendTo", "[", + RowBox[{"relativeerror", ",", + RowBox[{"{", + RowBox[{ + RowBox[{"i", "*", "2"}], ",", + RowBox[{"Sqrt", "[", + RowBox[{ + RowBox[{"(", + RowBox[{"Sum", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"dataelectricfieldgauss", "[", + RowBox[{"[", + RowBox[{"i", ",", "j"}], "]"}], "]"}], "-", + RowBox[{"datasquareanalytique", "[", + RowBox[{"[", "j", "]"}], "]"}]}], ")"}], "^", "2"}], ",", + RowBox[{"{", + RowBox[{"j", ",", "1", ",", + RowBox[{"Length", "[", "dataelectricfieldanaly", "]"}]}], + "}"}]}], "]"}], ")"}], "/", + RowBox[{"(", + RowBox[{"Sum", "[", + RowBox[{ + RowBox[{ + RowBox[{"datasquareanalytique", "[", + RowBox[{"[", "j", "]"}], "]"}], "^", "2"}], ",", + RowBox[{"{", + RowBox[{"j", ",", "1", ",", + RowBox[{"Length", "[", "datasquareanalytique", "]"}]}], + "}"}]}], "]"}], ")"}]}], "]"}]}], "}"}]}], "]"}], ";"}]}], + "]"}], "\[IndentingNewLine]", "abserror", "\[IndentingNewLine]", + "relativeerror"}]}]], "Input", + CellChangeTimes->{{3.8611230061599903`*^9, 3.861123006703861*^9}, { + 3.8611230866723146`*^9, 3.861123125388547*^9}, {3.861123206040749*^9, + 3.861123206521308*^9}, {3.861260836376354*^9, + 3.861260877461598*^9}},ExpressionUUID->"d24f20d6-729f-4ebb-9bdc-\ +788273f1e3f9"], + +Cell[BoxData[ + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"2", ",", "94942.80299918952`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"4", ",", "36143.53185124503`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"6", ",", "12257.188553966953`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"8", ",", "2686.854589001577`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"10", ",", "1092.1147355483317`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"12", ",", "337.37939925116`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"14", ",", "133.75233133719817`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"16", ",", "94.47331513035483`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"18", ",", "90.44860982366231`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"20", ",", "89.91014036466134`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"22", ",", "89.89450332422635`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"24", ",", "89.8862246056054`"}], "}"}]}], "}"}]], "Output", + CellChangeTimes->{3.8611231276753063`*^9, 3.86112316929661*^9, + 3.86117354759518*^9}, + CellLabel-> + "Out[277]=",ExpressionUUID->"87820575-f7aa-4bd3-8d26-eb8329c9e90d"], + +Cell[BoxData[ + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{"2", ",", "6.713469982558538`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"4", ",", "2.5557336468047334`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"6", ",", "0.8667141144792165`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"8", ",", "0.18998930999452093`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"10", ",", "0.07722417353399785`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"12", ",", "0.023856326104313885`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"14", ",", "0.00945771804880428`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"16", ",", "0.006680272176984757`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"18", ",", "0.00639568253552078`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"20", ",", "0.006357606994928636`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"22", ",", "0.006356501289195709`"}], "}"}], ",", + RowBox[{"{", + RowBox[{"24", ",", "0.006355915895388069`"}], "}"}]}], "}"}]], "Output", + CellChangeTimes->{3.8611231276753063`*^9, 3.86112316929661*^9, + 3.861173547600374*^9}, + CellLabel-> + "Out[278]=",ExpressionUUID->"c9d67024-7484-400e-99a3-606c54038a95"] +}, Open ]], + +Cell[CellGroupData[{ + +Cell[BoxData[{ + RowBox[{ + RowBox[{"g1", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"abserror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"PlotStyle", "\[Rule]", "Red"}], ",", + RowBox[{"Joined", "\[Rule]", "True"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g2", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"abserror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{"g1", ",", "g2"}], "]"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g3", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"relativeerror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"PlotStyle", "\[Rule]", "Red"}], ",", + RowBox[{"Joined", "\[Rule]", "True"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g4", "=", + RowBox[{"ListLogPlot", "[", + RowBox[{"relativeerror", ",", + RowBox[{"PlotRange", "\[Rule]", "All"}], ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{"g3", ",", "g4"}], "]"}]}], "Input", + CellLabel-> + "In[279]:=",ExpressionUUID->"c0d3d828-445a-4391-980f-255c7b107643"], + +Cell[BoxData[ + GraphicsBox[{{{}, {{}, {}, + {RGBColor[1, 0, 0], PointSize[0.012833333333333334`], AbsoluteThickness[ + 1.6], LineBox[{{2., 11.461029915570789`}, {4., 10.49525328630111}, {6., + 9.413867864592913}, {8., 7.89612649066494}, {10., 6.995871219968924}, { + 12., 5.821208110900904}, {14., 4.895989816182697}, {16., + 4.548317415050113}, {18., 4.504781842167219}, {20., + 4.49881073116398}, {22., 4.498636797497378}, {24., + 4.498544699543141}}]}}, {{}, {}}}, {{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.012833333333333334`], + AbsoluteThickness[1.6], + PointBox[{{2., 11.461029915570789`}, {4., 10.49525328630111}, {6., + 9.413867864592913}, {8., 7.89612649066494}, {10., 6.995871219968924}, { + 12., 5.821208110900904}, {14., 4.895989816182697}, {16., + 4.548317415050113}, {18., 4.504781842167219}, {20., 4.49881073116398}, { + 22., 4.498636797497378}, {24., 4.498544699543141}}]}, {{}, {}}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{1.5416666666666667`, 3.9536907190774175`}, + DisplayFunction->Identity, + Frame->{{True, True}, {True, True}}, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->FrontEndValueCache[{{ + Charting`ScaledTicks[{Log, Exp}], + Charting`ScaledFrameTicks[{Identity, Identity}]}, { + Automatic, Automatic}}, {{{{4.605170185988092, + FormBox["100", TraditionalForm], {0.01, 0.}}, {6.907755278982137, + FormBox["1000", TraditionalForm], {0.01, 0.}}, {9.210340371976184, + FormBox[ + TemplateBox[{"10", "4"}, "Superscript", SyntaxForm -> + SuperscriptBox], TraditionalForm], {0.01, 0.}}, { + 11.512925464970229`, + FormBox[ + TemplateBox[{"10", "5"}, "Superscript", SyntaxForm -> + SuperscriptBox], TraditionalForm], {0.01, 0.}}, { + 2.302585092994046, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.995732273553991, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.4011973816621555`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.6888794541139363`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.912023005428146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.0943445622221, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.248495242049359, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.382026634673881, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.499809670330265, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.298317366548036, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.703782474656201, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.991464547107982, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.214608098422191, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.396929655216146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.551080335043404, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.684611727667927, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.802394763324311, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 7.600902459542082, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.006367567650246, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.294049640102028, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.517193191416238, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.699514748210191, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.85366542803745, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.987196820661973, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9.104979856318357, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9.903487552536127, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.308952660644293`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.596634733096073`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.819778284410283`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.002099841204238`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.156250521031495`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.289781913656018`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.407564949312402`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12.206072645530174`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12.611537753638338`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12.89921982609012, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.122363377404328`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.304684934198283`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.458835614025542`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.592367006650065`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.710150042306449`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 13.815510557964274`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}}, {{ + 4., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {6., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {8., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, { + 10., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {2., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 5.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 6.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 7., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 7.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 8.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 9.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 10.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 11.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 12., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}}}, { + Automatic, Automatic}}], + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& )}}, + PlotRange->{{1.5416666666666667`, 24.}, {3.9536907190774175`, + 11.461029915570789`}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, + Charting`ScaledTicks[{Log, Exp}]}]], "Output", + CellChangeTimes->{3.861123181547842*^9, 3.861173551563908*^9}, + CellLabel->"Out[281]=",ImageCache->GraphicsData["CompressedBitmap", "\<\ +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 +pd578w==\ +\>", "ImageResolution" -> \ +144.],ExpressionUUID->"97b112e4-ab45-4d66-a9b3-928d93705112"], + +Cell[BoxData[ + GraphicsBox[{{{}, {{}, {}, + {RGBColor[1, 0, 0], PointSize[0.012833333333333334`], AbsoluteThickness[ + 1.6], LineBox[{{2., 1.9041159533146328`}, {4., 0.9383393240449559}, { + 6., -0.1430460976632426}, {8., -1.6607874715912152`}, { + 10., -2.561042742287231}, {12., -3.735705851355251}, { + 14., -4.660924146073459}, {16., -5.008596547206042}, { + 18., -5.052132120088936}, {20., -5.058103231092176}, { + 22., -5.058277164758778}, { + 24., -5.058369262713015}}]}}, {{}, {}}}, {{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.012833333333333334`], + AbsoluteThickness[1.6], + PointBox[{{2., 1.9041159533146328`}, {4., 0.9383393240449559}, { + 6., -0.1430460976632426}, {8., -1.6607874715912152`}, { + 10., -2.561042742287231}, {12., -3.735705851355251}, { + 14., -4.660924146073459}, {16., -5.008596547206042}, { + 18., -5.052132120088936}, {20., -5.058103231092176}, { + 22., -5.058277164758778}, {24., -5.058369262713015}}]}, {{}, {}}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{1.5416666666666667`, -5.603223243178739}, + DisplayFunction->Identity, + Frame->{{True, True}, {True, True}}, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->FrontEndValueCache[{{ + Charting`ScaledTicks[{Log, Exp}], + Charting`ScaledFrameTicks[{Identity, Identity}]}, { + Automatic, Automatic}}, {{{{-4.605170185988091, + FormBox[ + TagBox[ + InterpretationBox[ + StyleBox["\"0.01\"", ShowStringCharacters -> False], 0.01, + AutoDelete -> True], NumberForm[#, { + DirectedInfinity[1], 2}]& ], TraditionalForm], {0.01, + 0.}}, {-2.3025850929940455`, + FormBox[ + TagBox[ + InterpretationBox[ + StyleBox["\"0.10\"", ShowStringCharacters -> False], 0.1, + AutoDelete -> True], NumberForm[#, { + DirectedInfinity[1], 2}]& ], TraditionalForm], {0.01, 0.}}, {0., + FormBox["1", TraditionalForm], {0.01, 0.}}, {2.302585092994046, + FormBox["10", TraditionalForm], {0.01, 0.}}, {-6.907755278982137, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-6.214608098422191, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.809142990314028, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.521460917862246, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.298317366548036, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.115995809754082, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.961845129926823, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.8283137373023015`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.710530701645918, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.912023005428146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.506557897319982, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.2188758248682006`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.995732273553991, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.8134107167600364`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.659260036932778, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.5257286443082556`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.4079456086518722`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.6094379124341003`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.2039728043259361`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.916290731874155, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.6931471805599453, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.5108256237659907, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.35667494393873245`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.2231435513142097, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.10536051565782628`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 0.6931471805599453, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.0986122886681098`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.3862943611198906`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.6094379124341003`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.791759469228055, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.9459101490553132`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.0794415416798357`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.1972245773362196`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.995732273553991, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.4011973816621555`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.6888794541139363`, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.912023005428146, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.0943445622221, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.248495242049359, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.382026634673881, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4.499809670330265, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}}, {{-4., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, + 0.}}, {-2., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {0., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, 0.}}, {2., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.01, + 0.}}, {-6., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-5., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-4.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-3., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-2.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-1., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, + 0.}}, {-0.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 0.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 1.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 2.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 3.5, + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}, { + 4., + FormBox[ + TemplateBox[{0., 0.}, "Spacer2"], TraditionalForm], {0.005, 0.}}}}, { + Automatic, Automatic}}], + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Exp[ + Part[#, 2]]}& )}}, + PlotRange->{{1.5416666666666667`, 24.}, {-5.603223243178739, + 1.9041159533146328`}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, + Charting`ScaledTicks[{Log, Exp}]}]], "Output", + CellChangeTimes->{3.861123181547842*^9, 3.861173551653295*^9}, + CellLabel-> + "Out[284]=",ExpressionUUID->"d62a01ba-286a-47ed-b239-185edba12dd4"] +}, Open ]], + +Cell[BoxData[" "], "Input", + CellChangeTimes->{ + 3.861173940573041*^9},ExpressionUUID->"69447a35-9817-4522-9f86-\ +97bb0194d98b"], + +Cell[TextData[StyleBox["Plot d\[CloseCurlyQuote]une coupe de potentiel du \ +domaine BEM", "Title"]], "Text", + CellChangeTimes->{{3.861258541228631*^9, 3.86125858675126*^9}, { + 3.8612589640592527`*^9, + 3.861258967152192*^9}},ExpressionUUID->"d4c6205f-288d-4ba9-9e4e-\ +bc0171921df9"], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{ + RowBox[{"(*", + RowBox[{ + RowBox[{"data", "=", + RowBox[{"Import", "[", + RowBox[{ + "\"\</Users/Kevin/Downloads/phi.msh_Levelset.txt\>\"", ",", + "\"\<Table\>\""}], "]"}]}], ";"}], "*)"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"data", "=", + RowBox[{"Import", "[", + RowBox[{ + "\"\</Users/Kevin/Downloads/double_hole.txt\>\"", ",", + "\"\<Table\>\""}], "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{"(*", + RowBox[{ + RowBox[{"data", "=", + RowBox[{"Import", "[", + RowBox[{ + "\"\</Users/Kevin/Desktop/phi.msh_Levelset.txt\>\"", ",", + "\"\<Table\>\""}], "]"}]}], ";"}], "*)"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data1", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "1"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data2", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "2"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data3", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "3"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data4", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "4"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data5", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "5"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data6", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "6"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data7", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "7"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data8", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "8"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data9", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "9"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data9", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "9"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data10", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "10"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data11", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "11"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data12", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "12"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data13", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "13"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data14", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "14"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data15", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "15"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"data16", "=", + RowBox[{"data", "[", + RowBox[{"[", + RowBox[{"All", ",", "16"}], "]"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"length", "=", + RowBox[{"Length", "[", "data16", "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"potential1", "=", + RowBox[{"Table", "[", + RowBox[{ + RowBox[{"{", + RowBox[{ + RowBox[{"data6", "[", + RowBox[{"[", "i", "]"}], "]"}], ",", + RowBox[{"data8", "[", + RowBox[{"[", "i", "]"}], "]"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{"i", ",", "1", ",", "length"}], "}"}]}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"potential2", "=", + RowBox[{"Table", "[", + RowBox[{ + RowBox[{"{", + RowBox[{ + RowBox[{"data14", "[", + RowBox[{"[", "i", "]"}], "]"}], ",", + RowBox[{"data16", "[", + RowBox[{"[", "i", "]"}], "]"}]}], "}"}], ",", + RowBox[{"{", + RowBox[{"i", ",", "1", ",", "length"}], "}"}]}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"potential", "=", + RowBox[{"Join", "[", + RowBox[{"potential1", ",", "potential2"}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"g1", "=", + RowBox[{"ListPlot", "[", + RowBox[{"potential", ",", + RowBox[{"Frame", "\[Rule]", "True"}]}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{ + RowBox[{"rescale", "=", + RowBox[{ + RowBox[{"RescalingTransform", "[", + RowBox[{"CoordinateBounds", "[", "potential", "]"}], "]"}], "@", + "potential"}]}], ";"}], "\n", + RowBox[{"new", "=", + RowBox[{"FindCurvePath", "@", "rescale"}]}], "\n", + RowBox[{ + RowBox[{"g2", "=", + RowBox[{"ListLinePlot", "[", + RowBox[{ + RowBox[{ + RowBox[{ + RowBox[{"potential", "[", + RowBox[{"[", "#", "]"}], "]"}], "&"}], "/@", "new"}], ",", + RowBox[{"PlotStyle", "\[Rule]", "Red"}]}], "]"}]}], ";"}], + "\[IndentingNewLine]", + RowBox[{"Show", "[", + RowBox[{"g2", ",", "g1", ",", + RowBox[{"Frame", "->", "True"}]}], "]"}], + "\[IndentingNewLine]"}]}]], "Input", + CellChangeTimes->{{3.8611851956862497`*^9, 3.861185302243578*^9}, { + 3.861185349637801*^9, 3.861185369291651*^9}, {3.861185419887733*^9, + 3.86118546737477*^9}, 3.861187912937941*^9, {3.861187984360655*^9, + 3.8611879922982883`*^9}, {3.8611880322634363`*^9, 3.861188048614867*^9}, { + 3.861188096279683*^9, 3.861188138790277*^9}, {3.8611881750587587`*^9, + 3.86118834581749*^9}, {3.861188399757311*^9, 3.861188473593074*^9}, { + 3.861188511707906*^9, 3.861188550238516*^9}, {3.861188647426079*^9, + 3.861188954510017*^9}, {3.861189078808382*^9, 3.86118911851886*^9}, { + 3.861189410491591*^9, 3.861189413179975*^9}, {3.861189633611978*^9, + 3.861189660756143*^9}, {3.861189697543219*^9, 3.8611896984885674`*^9}, { + 3.8611897900042667`*^9, 3.861189803558625*^9}, {3.861189840651662*^9, + 3.861189867869316*^9}, {3.861190246562645*^9, 3.861190301065031*^9}, + 3.861190342461088*^9, {3.861190428180133*^9, 3.861190553086246*^9}, { + 3.861190900168805*^9, 3.861190941666606*^9}, {3.8611954752493477`*^9, + 3.8611954755274143`*^9}, {3.861195713486902*^9, 3.861195716839321*^9}, { + 3.861195857565535*^9, 3.861195861741111*^9}}, + CellLabel-> + "In[1326]:=",ExpressionUUID->"b039c25c-3c81-424e-b355-8af2a1fea5a1"], + +Cell[BoxData[ + RowBox[{"{", + RowBox[{ + RowBox[{"{", + RowBox[{ + "2", ",", "1", ",", "52", ",", "49", ",", "7", ",", "3", ",", "30", ",", + "35", ",", "103", ",", "43", ",", "41", ",", "38", ",", "20", ",", "32", + ",", "22", ",", "26", ",", "24", ",", "28", ",", "46", ",", "54", ",", + "114", ",", "59", ",", "57", ",", "11"}], "}"}], ",", + RowBox[{"{", + RowBox[{ + "8", ",", "4", ",", "31", ",", "34", ",", "102", ",", "42", ",", "40", + ",", "39", ",", "21", ",", "33", ",", "23", ",", "27", ",", "25", ",", + "29", ",", "47", ",", "55", ",", "115", ",", "60", ",", "58", ",", + "12"}], "}"}], ",", + RowBox[{"{", + RowBox[{ + "10", ",", "9", ",", "19", ",", "51", ",", "66", ",", "5", ",", "65", ",", + "13", ",", "53", ",", "48", ",", "8"}], "}"}], ",", + RowBox[{"{", + RowBox[{"18", ",", "17", ",", "62", ",", "2"}], "}"}], ",", + RowBox[{"{", + RowBox[{"18", ",", "10"}], "}"}]}], "}"}]], "Output", + CellChangeTimes->{{3.861185259766171*^9, 3.861185302922409*^9}, + 3.861185352523041*^9, {3.861185428923902*^9, 3.8611854677912807`*^9}, + 3.861188049002152*^9, {3.861188118104989*^9, 3.861188139327779*^9}, { + 3.861188180943853*^9, 3.86118834213377*^9}, {3.861188425687414*^9, + 3.861188436288494*^9}, {3.861188503504902*^9, 3.861188512232707*^9}, + 3.861188550741851*^9, 3.8611887322200603`*^9, {3.86118878471275*^9, + 3.861188861712639*^9}, {3.86118891927712*^9, 3.8611889553269978`*^9}, { + 3.861189097359291*^9, 3.861189119265131*^9}, 3.861189221033667*^9, + 3.8611894137688503`*^9, 3.8611896614846*^9, 3.861189805499155*^9, + 3.8611898706038837`*^9, 3.8611902659300528`*^9, {3.861190343287168*^9, + 3.8611903641335173`*^9}, {3.861190431354424*^9, 3.86119055360843*^9}, + 3.8611909427969017`*^9, 3.861195486997033*^9, 3.861195717614942*^9, + 3.8611958634851627`*^9}, + CellLabel-> + "Out[1350]=",ExpressionUUID->"75c96493-d7f7-4956-b2cf-f98cdd66fda1"], + +Cell[BoxData[ + GraphicsBox[{{{}, {{}, {}, + {RGBColor[1, 0, 0], PointSize[ + NCache[ + Rational[1, 60], 0.016666666666666666`]], AbsoluteThickness[1.6], + LineBox[CompressedData[" +1:eJxTTMoPSmViYGCQAGIQHbRwAq9KyM79FR8t/l8TzXa4eMPQ2Nj48H5HHaCk +Q5YDAxhc2A+mgPy7XC4rdZou7S/vyUm/ppjpwHFD7snR3Zf3Zzw8PitkWobD +O5leTs7VV/crf9C+1Lkr3SG1Ss3w7qNr+2++X3Kx1CDdQftxTco19pv7NZyX +xC2xS3NIOhEgFPb+5v7fLlGtr2+kOjw7Km5ekXFn/7q2vDsbjqQ4KOb4Vmd8 +uLM/pvSV3ITOFAfxyt2WEw/f3z/z8zbZ4sBkh/+f7LZwf7m/X6i64OFMm2SH +xMQUPuYrD/bveL4xrbEpyWHRcuGtLLUP9/9WPXGQ/1OiQ19ek/Ll/of777Hw +L5V5lOjwcNdTO1bGx/vnv7CfeWdlgsNp9o7cu9aP9xvc5rTJqUhwuCh4eiVz +8ZP90TH3Hpo8j3PwuK5Xzr36yf4G5/0WGzrjHAxfayheWf10/zHVazlr7sY4 +NFu8WG349On+k4GSDCl1MQ4TetOP8u1+tv9HrQf7daloaHi+gIQnQ6QDANwo +uO8= + "]]}, + {RGBColor[1, 0, 0], PointSize[ + NCache[ + Rational[1, 60], 0.016666666666666666`]], AbsoluteThickness[1.6], + LineBox[CompressedData[" +1:eJwBUQGu/iFib1JlAgAAABQAAAACAAAACNge5MW70z8sn/DnPPpsQOocjQkJ +q9U/24+hfurNa0BjeiYx3eLWP+W6MitGEWtAJ+N8ZNYH2T/2VyIxA8dpQF/I +UBJW79k/dnIDqxs8aUDkxRc3eGjcP7E+IToUw2dAHWxNe2jw3D8CRyHpY3Jn +QBd5uzmRw98/sxj4bqzIZUD/8j60C/TfP3aekTU+rGVAX2FkDgPU4D8h6unT +lq5kQKCnE7UEfeE/mClhl7HpY0CMboIj04/hP6U174H202NA4brlPgUB4z8q +dudKmypiQMsHiG3dO+M/M5xqoknnYUDSEcupA3PkP2I0jsUwhGBASdcudwur +5D85Ti8cjERgQDHrKCHUq+U/Z/pCzpNCXkCDOOirMeXlP93X7KLtwF1AkI1n +xQ675j/YyLCDHN1bQAAAAAAAAOg/AAAAAAAAWUCndJX9 + "]]}, + {RGBColor[1, 0, 0], PointSize[ + NCache[ + Rational[1, 60], 0.016666666666666666`]], AbsoluteThickness[1.6], + LineBox[{{-0.005541704640846631, 229.0153249535908}, { + 0.02881512838732802, 233.6160342365152}, {0.03597247053500965, + 234.5721069260967}, {0.04189221989451287, 235.3707250988907}, { + 0.07256871407405026, 239.4982910187085}, {0.09613814558468319, + 242.6884857924242}, {0.1149695112192741, 245.2413719521836}, {0.15, + 250.}, {0.25, 250.}, {0.2891952183710324, 237.7777554985219}, { + 0.3083357551325894, 231.8199348163265}}]}, + {RGBColor[1, 0, 0], PointSize[ + NCache[ + Rational[1, 60], 0.016666666666666666`]], AbsoluteThickness[1.6], + LineBox[{{-0.0465353753516164, + 223.5857702997704}, {-0.04885286659846285, + 223.2779014698886}, {-0.05092566205446281, + 223.0053827702079}, {-0.09894013720680064, 216.6824947464154}}]}, + {RGBColor[1, 0, 0], PointSize[ + NCache[ + Rational[1, 60], 0.016666666666666666`]], AbsoluteThickness[1.6], + LineBox[{{-0.0465353753516164, + 223.5857702997704}, {-0.005541704640846631, + 229.0153249535908}}]}}, {{}, {}}}, {{}, + {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.009166666666666668], + AbsoluteThickness[1.6], PointBox[CompressedData[" +1:eJyllGtMk1cYxwtlQSSTiHdEl07xRiN09YLa9DxT4mWJRpiXuCLQGwV6wWBE +nOAEd5EFFDQ6URxCSkgtIaCz4RI9GmRiiE6oKxBapNLSAnNgZ4yBLKxyePnw +9sP5sJO8OfnlPTk5z5P/7+HJMuKV/hwOJ9v7fdw7ugVCobAFf8n3AqRDfEXx +pysPNOLstzGTlgVq+Du8KCjI+CdeMRbZWdCkgmHCqPdixZnhZ2qQrI/KyC9r +QJ/tksybdUjnw7O6lztam8041f7k+oGrqQwjfvmYSzSugb7BTedNeTfRJamu +yCTUgmh8JXfwThb+6Y9HP+fe0gBnarkx2Y8wjBgWTq0WwpDBMDnvrUd1cNK7 +XNgd5jd1fprR0FnC21JM0WKuAXdeKS9xuNXQGJyzMMdcjTUhkooHHjUII/w7 +JtIr0Qt+1N198VqY9Ih/C373CoeePmYvFckZRlm/lmwU1yihsnrevYBcO56I +aHsU4pHCLcLo2lrpL/VDcrA3OcWf+A3gcjcqtRqSGUbrslxf3Vgngwu6/BXm +i3bcFxBSFf5aCoWEUdXG0bz3Zjm0B57X2rYN4OjeIJEmO5lhJCxLr9zjkoLy +21UC22sL7hnVd5yIVoGcMHI2fRG5c64apFLFHO7Lftzgqk/Jy5dBEmHEGx4y +X61VwOqBHIUlsAe9P/y5gPskDSIJ4zU79Il6cQq1vkWnmreUtLzCpf+Ylh2P +m2F0d/EHXU2bEpZp9p5OHbMi/128IXmmCniEccKJ4eXFBQpwtC7anJ1qRfVi +3tb5LSoYJIxrf9RZ6x7T39cxt93APe7AkoQ++wZXInQSRrINF1qjv0+G3tmx +Bn5+J/I8+y5poEELNsL4ZKFGZeGlwfz+KR9QgNkbE5QB0ubnemdmFTr81j5u +VWun8/diJl/TPJO/3V3rTwYbHfjsDhxTV5AIewijLfuiwgtjk33yVFykap3T +PIg/5O4O7AqTMIy62+rOhdskcC7GbRQ4nfhp3BKO4kwCw8jW9Vflm4dHfXyN +iwi7/Sb0Nl79MGcxv19N9a92f2O8XncflS2piWus1kFRpOFf6+U7qL3aj+MZ +9e0Pu39sX9n+0Pxj95s9j2j9YdfL9pk9X2j5/L/+0fym5ZM2b2nzh+07ex7Q +/Gf7yPaV5mdS2/7QQ6M9KCuTa1wqSgMZYTwR+80PI91K6n+aP1+fIr4tNJG8 +TDMeefqR06l5Zp9n3ycYWcN7aXTi3yMsmhpbAsNINb79+eXtiT7zgOYn7b7/ +AMLFk6k= + "]]}, {{}, {}}}}, + AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], + Axes->{True, True}, + AxesLabel->{None, None}, + AxesOrigin->{0, 0}, + DisplayFunction->Identity, + Frame->True, + FrameLabel->{{None, None}, {None, None}}, + FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, + GridLines->{None, None}, + GridLinesStyle->Directive[ + GrayLevel[0.5, 0.4]], + Method->{ + "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, + "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& ), "CopiedValueFunction" -> ({ + Identity[ + Part[#, 1]], + Identity[ + Part[#, 2]]}& )}}, + PlotRange->{{-0.75, 0.75}, {0, 250.}}, + PlotRangeClipping->True, + PlotRangePadding->{{ + Scaled[0.02], + Scaled[0.02]}, { + Scaled[0.02], + Scaled[0.05]}}, + Ticks->{Automatic, Automatic}]], "Output", + CellChangeTimes->{{3.861185259766171*^9, 3.861185302922409*^9}, + 3.861185352523041*^9, {3.861185428923902*^9, 3.8611854677912807`*^9}, + 3.861188049002152*^9, {3.861188118104989*^9, 3.861188139327779*^9}, { + 3.861188180943853*^9, 3.86118834213377*^9}, {3.861188425687414*^9, + 3.861188436288494*^9}, {3.861188503504902*^9, 3.861188512232707*^9}, + 3.861188550741851*^9, 3.8611887322200603`*^9, {3.86118878471275*^9, + 3.861188861712639*^9}, {3.86118891927712*^9, 3.8611889553269978`*^9}, { + 3.861189097359291*^9, 3.861189119265131*^9}, 3.861189221033667*^9, + 3.8611894137688503`*^9, 3.8611896614846*^9, 3.861189805499155*^9, + 3.8611898706038837`*^9, 3.8611902659300528`*^9, {3.861190343287168*^9, + 3.8611903641335173`*^9}, {3.861190431354424*^9, 3.86119055360843*^9}, + 3.8611909427969017`*^9, 3.861195486997033*^9, 3.861195717614942*^9, + 3.8611958635176287`*^9}, + CellLabel-> + "Out[1352]=",ExpressionUUID->"1674e868-ef4e-477c-b5e8-342b479f4694"] +}, Open ]], + +Cell[TextData[StyleBox["Calcul des matrices G, gradG, gradH de \ +mani\[EGrave]re analytique", "Title"]], "Text", + CellChangeTimes->{{3.861258663748384*^9, + 3.8612586958361387`*^9}},ExpressionUUID->"c6929cf8-3e79-4e5a-a751-\ +f0adefbedc6a"], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{ + RowBox[{"(*", + RowBox[{ + "calcul", " ", "de", " ", "G", " ", "par", " ", "changement", " ", "de", + " ", "coordonn\[EAcute]es", " ", "\[Xi]"}], "*)"}], "\[IndentingNewLine]", + RowBox[{"(*", + RowBox[{ + RowBox[{ + RowBox[{"j", "'"}], "ai", " ", "du", " ", "proc\[EAcute]der", " ", "par", + " ", "\[EAcute]tapes", " ", "car", " ", "m\[EHat]me", " ", "en", " ", + "mettant", " ", "des", " ", "assumptions"}], ",", " ", + RowBox[{ + "mathematica", " ", "refuse", " ", "de", " ", "me", " ", "calculer", " ", + + RowBox[{"l", "'"}], "int\[EAcute]grale", " ", "entre", " ", "2", " ", + RowBox[{"bornes", ".", " ", "Je"}], " ", "passe", " ", "donc", " ", + "par", " ", "le", " ", "calcul", " ", "de", " ", "la", " ", "primitive", + " ", "que", " ", + RowBox[{"j", "'"}], "\[EAcute]value", " ", "ensuite", " ", "aux", " ", + "bornes", " ", + RowBox[{"d", "'"}], "int\[EAcute]grations"}]}], "*)"}], "\n", + RowBox[{ + RowBox[{ + RowBox[{ + RowBox[{"x", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "+", "xj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "-", "xj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"y", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "+", "yj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "-", "yj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"r", "[", "\[Xi]_", "]"}], ":=", + RowBox[{"Sqrt", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"matG", "=", + RowBox[{"Integrate", "[", + RowBox[{ + RowBox[{ + RowBox[{"lj", "/", + RowBox[{"(", + RowBox[{"4", "*", "Pi"}], ")"}]}], "*", + RowBox[{"Log", "[", + RowBox[{"r", "[", "\[Xi]", "]"}], "]"}]}], ",", "\[Xi]"}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"bornesup", "=", + RowBox[{"matG", "/.", + RowBox[{"\[Xi]", "\[Rule]", "1"}]}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"borneinf", "=", + RowBox[{"matG", "/.", + RowBox[{"\[Xi]", "\[Rule]", + RowBox[{"-", "1"}]}]}]}], ";"}], "\[IndentingNewLine]", + RowBox[{"matG", "=", + RowBox[{"FullSimplify", "[", + RowBox[{"bornesup", "-", "borneinf"}], "]"}]}], "\[IndentingNewLine]", + RowBox[{"formec", "=", + RowBox[{"CForm", "[", "%", "]"}]}]}]}]], "Input", + CellChangeTimes->{{3.861257483289976*^9, 3.861257488134403*^9}, { + 3.861257895179406*^9, 3.861257996199999*^9}, {3.8612580708324127`*^9, + 3.861258085264085*^9}}, + CellLabel->"In[1]:=",ExpressionUUID->"aba879f4-4fa1-4a20-84ae-7797ad362ead"], + +Cell[BoxData[ + RowBox[{ + FractionBox["1", + RowBox[{"4", " ", "\[Pi]", " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}], "2"]}], ")"}]}]], + RowBox[{"lj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"-", "2"}], " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}], "2"]}], ")"}]}], "+", + RowBox[{"2", " ", + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"-", "xj"}], " ", "yi"}], "+", + RowBox[{"xjp1", " ", "yi"}], "+", + RowBox[{"xi", " ", "yj"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xi", " ", "yjp1"}], "+", + RowBox[{"xj", " ", "yjp1"}]}], ")"}], " ", + RowBox[{"ArcTan", "[", + FractionBox[ + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}]}]}], + RowBox[{ + RowBox[{ + RowBox[{"-", "xj"}], " ", "yi"}], "+", + RowBox[{"xjp1", " ", "yi"}], "+", + RowBox[{"xi", " ", "yj"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xi", " ", "yjp1"}], "+", + RowBox[{"xj", " ", "yjp1"}]}]], "]"}]}], "+", + RowBox[{"2", " ", + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"-", "xjp1"}], " ", "yi"}], "-", + RowBox[{"xi", " ", "yj"}], "+", + RowBox[{"xjp1", " ", "yj"}], "+", + RowBox[{"xj", " ", + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}]}], "+", + RowBox[{"xi", " ", "yjp1"}]}], ")"}], " ", + RowBox[{"ArcTan", "[", + FractionBox[ + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}]}]}], + RowBox[{ + RowBox[{"xjp1", " ", "yi"}], "+", + RowBox[{"xi", " ", "yj"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xi", " ", "yjp1"}], "+", + RowBox[{"xj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "yi"}], "+", "yjp1"}], ")"}]}]}]], "]"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"-", + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}]}], " ", + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}]}], "-", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}]}]}], ")"}], " ", + RowBox[{"Log", "[", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], "2"]}], "]"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}]}]}], ")"}], " ", + RowBox[{"Log", "[", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], "2"]}], "]"}]}]}], + ")"}]}]}]], "Output", + CellChangeTimes->{ + 3.8612578087441063`*^9, {3.861258073184415*^9, 3.86125808640173*^9}, + 3.8612581448196383`*^9}, + CellLabel->"Out[7]=",ExpressionUUID->"1a498cc3-ec98-4fb7-9364-dcc415205357"], + +Cell["\<\ +(lj*(-2*(Power(xj - xjp1,2) + Power(yj - yjp1,2)) + 2*(-(xj*yi) + xjp1*yi + \ +xi*yj - xjp1*yj - xi*yjp1 + xj*yjp1)* + ArcTan(((xi - xjp1)*(xj - xjp1) + (yi - yjp1)*(yj - yjp1))/(-(xj*yi) \ ++ xjp1*yi + xi*yj - xjp1*yj - xi*yjp1 + xj*yjp1)) + + 2*(-(xjp1*yi) - xi*yj + xjp1*yj + xj*(yi - yjp1) + \ +xi*yjp1)*ArcTan(((xi - xj)*(xj - xjp1) + (yi - yj)*(yj - yjp1))/ + (xjp1*yi + xi*yj - xjp1*yj - xi*yjp1 + xj*(-yi + yjp1))) + (-((xi - \ +xj)*(xj - xjp1)) - (yi - yj)*(yj - yjp1))*Log(Power(xi - xj,2) + Power(yi - \ +yj,2)) + + ((xi - xjp1)*(xj - xjp1) + (yi - yjp1)*(yj - yjp1))*Log(Power(xi - \ +xjp1,2) + Power(yi - yjp1,2))))/(4.*Pi*(Power(xj - xjp1,2) + Power(yj - \ +yjp1,2)))\ +\>", "Output", + CellChangeTimes->{ + 3.8612578087441063`*^9, {3.861258073184415*^9, 3.86125808640173*^9}, + 3.861258144830161*^9}, + CellLabel-> + "Out[8]//CForm=",ExpressionUUID->"b3ea9741-9cac-4165-ac03-4789f7b7458a"] +}, Open ]], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{ + RowBox[{"(*", + RowBox[{"calcul", " ", "de", " ", "gradGx", " ", "par", " ", "\[Xi]"}], + "*)"}], "\n", + RowBox[{ + RowBox[{ + RowBox[{ + RowBox[{"x", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "+", "xj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "-", "xj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\n", + RowBox[{ + RowBox[{ + RowBox[{"y", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "+", "yj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "-", "yj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\n", + RowBox[{ + RowBox[{"r", "[", "\[Xi]_", "]"}], ":=", + RowBox[{"Sqrt", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"x", "[", "\[Xi]", "]"}], "-", "xi"}], ")"}], "^", "2"}], + "+", + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"y", "[", "\[Xi]", "]"}], "-", "yi"}], ")"}], "^", "2"}]}], + "]"}]}], "\n", + RowBox[{ + RowBox[{"g1", "=", + RowBox[{"Integrate", "[", + RowBox[{ + RowBox[{ + RowBox[{"lj", "/", "2"}], "*", + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "/", + RowBox[{"(", + RowBox[{"2", "*", "Pi", "*", + RowBox[{"(", + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "2"}], ")"}]}], ")"}]}]}], + ",", "\[Xi]"}], "]"}]}], ";"}], "\n", + RowBox[{ + RowBox[{"g2", "=", + RowBox[{"g1", "/.", + RowBox[{"{", + RowBox[{"\[Xi]", "\[Rule]", "1"}], "}"}]}]}], ";"}], "\n", + RowBox[{ + RowBox[{"g3", "=", + RowBox[{"Integrate", "[", + RowBox[{ + RowBox[{ + RowBox[{"lj", "/", "2"}], "*", + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "/", + RowBox[{"(", + RowBox[{"2", "*", "Pi", "*", + RowBox[{"(", + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "2"}], ")"}]}], ")"}]}]}], + ",", "\[Xi]"}], "]"}]}], ";"}], "\n", + RowBox[{ + RowBox[{"g4", "=", + RowBox[{"g3", "/.", + RowBox[{"{", + RowBox[{"\[Xi]", "\[Rule]", + RowBox[{"-", "1"}]}], "}"}]}]}], ";"}], "\n", + RowBox[{"FullSimplify", "[", + RowBox[{"g2", "-", "g4"}], "]"}], "\n", + RowBox[{"CForm", "[", "%", "]"}]}]}]], "Input", + CellLabel-> + "In[1359]:=",ExpressionUUID->"70e041ab-7a76-4842-a412-090b3714cc63"], + +Cell[BoxData[ + FractionBox[ + RowBox[{"lj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"-", "2"}], " ", + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"ArcTan", "[", + FractionBox[ + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}]}]}], + RowBox[{ + RowBox[{"xjp1", " ", "yi"}], "+", + RowBox[{"xi", " ", "yj"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xi", " ", "yjp1"}], "+", + RowBox[{"xj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "yi"}], "+", "yjp1"}], ")"}]}]}]], "]"}], "+", + RowBox[{"ArcTan", "[", + FractionBox[ + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "xj"}], "+", "xjp1"}], ")"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "yj"}], "+", "yjp1"}], ")"}]}]}], + RowBox[{ + RowBox[{"xjp1", " ", "yi"}], "+", + RowBox[{"xi", " ", "yj"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xi", " ", "yjp1"}], "+", + RowBox[{"xj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "yi"}], "+", "yjp1"}], ")"}]}]}]], "]"}]}], + ")"}]}], "-", + RowBox[{ + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"Log", "[", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], "2"]}], "]"}], "-", + RowBox[{"Log", "[", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], "2"]}], "]"}]}], ")"}]}]}], + ")"}]}], + RowBox[{"4", " ", "\[Pi]", " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}], "2"]}], ")"}]}]]], "Output", + CellChangeTimes->{3.861257820955475*^9}, + CellLabel-> + "Out[1366]=",ExpressionUUID->"fb22a801-d9c9-4302-a409-04f757cc31d5"], + +Cell["\<\ +(lj*(-2*(yj - yjp1)*(ArcTan(((xi - xj)*(xj - xjp1) + (yi - yj)*(yj - \ +yjp1))/(xjp1*yi + xi*yj - xjp1*yj - xi*yjp1 + xj*(-yi + yjp1))) + + ArcTan(((xi - xjp1)*(-xj + xjp1) + (yi - yjp1)*(-yj + \ +yjp1))/(xjp1*yi + xi*yj - xjp1*yj - xi*yjp1 + xj*(-yi + yjp1)))) - + (xj - xjp1)*(Log(Power(xi - xj,2) + Power(yi - yj,2)) - Log(Power(xi - \ +xjp1,2) + Power(yi - yjp1,2)))))/(4.*Pi*(Power(xj - xjp1,2) + Power(yj - \ +yjp1,2)))\ +\>", "Output", + CellChangeTimes->{3.861257820963357*^9}, + CellLabel-> + "Out[1367]//CForm=",ExpressionUUID->"0edfe664-e358-4b8b-8c1e-f77d428b251b"] +}, Open ]], + +Cell[CellGroupData[{ + +Cell[BoxData[ + RowBox[{ + RowBox[{"(*", + RowBox[{"calcul", " ", "de", " ", "gradGy", " ", "par", " ", "\[Xi]"}], + "*)"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{ + RowBox[{"x", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "+", "xj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "-", "xj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\n", + RowBox[{ + RowBox[{ + RowBox[{"y", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "+", "yj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "-", "yj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\n", + RowBox[{ + RowBox[{"r", "[", "\[Xi]_", "]"}], ":=", + RowBox[{"Sqrt", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"x", "[", "\[Xi]", "]"}], "-", "xi"}], ")"}], "^", "2"}], + "+", + RowBox[{ + RowBox[{"(", + RowBox[{ + RowBox[{"y", "[", "\[Xi]", "]"}], "-", "yi"}], ")"}], "^", "2"}]}], + "]"}]}], "\n", + RowBox[{ + RowBox[{"g1", "=", + RowBox[{"Integrate", "[", + RowBox[{ + RowBox[{ + RowBox[{"lj", "/", "2"}], "*", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}], "/", + RowBox[{"(", + RowBox[{"2", "*", "Pi", "*", + RowBox[{"(", + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "2"}], ")"}]}], ")"}]}]}], + ",", "\[Xi]"}], "]"}]}], ";"}], "\n", + RowBox[{ + RowBox[{"g2", "=", + RowBox[{"g1", "/.", + RowBox[{"{", + RowBox[{"\[Xi]", "\[Rule]", "1"}], "}"}]}]}], ";"}], "\n", + RowBox[{ + RowBox[{"g3", "=", + RowBox[{"Integrate", "[", + RowBox[{ + RowBox[{ + RowBox[{"lj", "/", "2"}], "*", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}], "/", + RowBox[{"(", + RowBox[{"2", "*", "Pi", "*", + RowBox[{"(", + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "2"}], ")"}]}], ")"}]}]}], + ",", "\[Xi]"}], "]"}]}], ";"}], "\n", + RowBox[{ + RowBox[{"g4", "=", + RowBox[{"g3", "/.", + RowBox[{"{", + RowBox[{"\[Xi]", "\[Rule]", + RowBox[{"-", "1"}]}], "}"}]}]}], ";"}], "\n", + RowBox[{"FullSimplify", "[", + RowBox[{"g2", "-", "g4"}], "]"}], "\n", + RowBox[{"CForm", "[", "%", "]"}]}]}]], "Input", + CellChangeTimes->{{3.861258155747745*^9, 3.861258156239802*^9}}, + CellLabel->"In[9]:=",ExpressionUUID->"4421bad8-e670-4d02-a48b-904eeb29edfb"], + +Cell[BoxData[ + FractionBox[ + RowBox[{"lj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"2", " ", + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"ArcTan", "[", + FractionBox[ + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}]}]}], + RowBox[{ + RowBox[{"xjp1", " ", "yi"}], "+", + RowBox[{"xi", " ", "yj"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xi", " ", "yjp1"}], "+", + RowBox[{"xj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "yi"}], "+", "yjp1"}], ")"}]}]}]], "]"}], "+", + RowBox[{"ArcTan", "[", + FractionBox[ + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "xj"}], "+", "xjp1"}], ")"}]}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "yj"}], "+", "yjp1"}], ")"}]}]}], + RowBox[{ + RowBox[{"xjp1", " ", "yi"}], "+", + RowBox[{"xi", " ", "yj"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xi", " ", "yjp1"}], "+", + RowBox[{"xj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"-", "yi"}], "+", "yjp1"}], ")"}]}]}]], "]"}]}], + ")"}]}], "-", + RowBox[{ + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}], " ", + RowBox[{"(", + RowBox[{ + RowBox[{"Log", "[", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], "2"]}], "]"}], "-", + RowBox[{"Log", "[", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], "2"]}], "]"}]}], ")"}]}]}], + ")"}]}], + RowBox[{"4", " ", "\[Pi]", " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xj", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yj", "-", "yjp1"}], ")"}], "2"]}], ")"}]}]]], "Output", + CellChangeTimes->{3.861257873532209*^9, 3.861258173520028*^9}, + CellLabel->"Out[16]=",ExpressionUUID->"c8795095-361d-4b25-bcd0-742fae5fbfde"], + +Cell["\<\ +(lj*(2*(xj - xjp1)*(ArcTan(((xi - xj)*(xj - xjp1) + (yi - yj)*(yj - \ +yjp1))/(xjp1*yi + xi*yj - xjp1*yj - xi*yjp1 + xj*(-yi + yjp1))) + + ArcTan(((xi - xjp1)*(-xj + xjp1) + (yi - yjp1)*(-yj + \ +yjp1))/(xjp1*yi + xi*yj - xjp1*yj - xi*yjp1 + xj*(-yi + yjp1)))) - + (yj - yjp1)*(Log(Power(xi - xj,2) + Power(yi - yj,2)) - Log(Power(xi - \ +xjp1,2) + Power(yi - yjp1,2)))))/(4.*Pi*(Power(xj - xjp1,2) + Power(yj - \ +yjp1,2)))\ +\>", "Output", + CellChangeTimes->{3.861257873532209*^9, 3.861258173530663*^9}, + CellLabel-> + "Out[17]//CForm=",ExpressionUUID->"a7803c49-73b0-4652-a89a-bc89a1cb4cec"] +}, Open ]], + +Cell[CellGroupData[{ + +Cell[BoxData[{ + RowBox[{ + RowBox[{ + RowBox[{"x", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "+", "xj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "-", "xj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"y", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "+", "yj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "-", "yj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"r", "[", "\[Xi]_", "]"}], ":=", + RowBox[{"Sqrt", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"gradHx", "=", + RowBox[{"Integrate", "[", + RowBox[{ + RowBox[{ + FractionBox["lj", + RowBox[{"2", "*", "Pi"}]], "*", + RowBox[{"(", + RowBox[{ + RowBox[{ + FractionBox[ + RowBox[{"-", + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"1", "/", "2"}], "*", + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "2"}]}], "-", + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}]}], + ")"}]}], + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "4"}]], "*", "nx"}], "+", + RowBox[{ + FractionBox[ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "*", + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}]}], + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "4"}]], "*", "ny"}]}], + ")"}]}], ",", "\[Xi]"}], "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"bornesup", "=", + RowBox[{"gradHx", "/.", + RowBox[{"\[Xi]", "\[Rule]", "1"}]}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"borneinf", "=", + RowBox[{"gradHx", "/.", + RowBox[{"\[Xi]", "\[Rule]", + RowBox[{"-", "1"}]}]}]}], ";"}], "\[IndentingNewLine]", + RowBox[{"gradHx", "=", + RowBox[{"FullSimplify", "[", + RowBox[{"bornesup", "-", "borneinf"}], "]"}]}], "\[IndentingNewLine]", + RowBox[{"formec", "=", + RowBox[{"CForm", "[", "%", "]"}]}]}], "Input", + CellLabel->"In[30]:=",ExpressionUUID->"c1f1582f-6978-4e3e-9743-4da5fa3fe712"], + +Cell[BoxData[ + FractionBox[ + RowBox[{"lj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"nx", " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox["xi", "2"], "+", + RowBox[{"xj", " ", "xjp1"}], "-", + RowBox[{"xi", " ", + RowBox[{"(", + RowBox[{"xj", "+", "xjp1"}], ")"}]}], "-", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}]}]}], ")"}]}], "-", + RowBox[{"ny", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"xj", " ", "yi"}], "+", + RowBox[{"xjp1", " ", "yi"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xj", " ", "yjp1"}], "+", + RowBox[{"xi", " ", + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"-", "2"}], " ", "yi"}], "+", "yj", "+", "yjp1"}], + ")"}]}]}], ")"}]}]}], ")"}]}], + RowBox[{"2", " ", "\[Pi]", " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], "2"]}], ")"}], " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], "2"]}], ")"}]}]]], "Output", + CellChangeTimes->{3.861258377252224*^9}, + CellLabel->"Out[36]=",ExpressionUUID->"8918a234-b86f-421c-aab8-2633de35a885"], + +Cell["\<\ +(lj*(nx*(Power(xi,2) + xj*xjp1 - xi*(xj + xjp1) - (yi - yj)*(yi - yjp1)) - \ +ny*(xj*yi + xjp1*yi - xjp1*yj - xj*yjp1 + xi*(-2*yi + yj + yjp1))))/ + (2.*Pi*(Power(xi - xj,2) + Power(yi - yj,2))*(Power(xi - xjp1,2) + \ +Power(yi - yjp1,2)))\ +\>", "Output", + CellChangeTimes->{3.8612583772630167`*^9}, + CellLabel-> + "Out[37]//CForm=",ExpressionUUID->"7827bc67-ba5a-419b-a3b4-d82b0dca4cef"] +}, Open ]], + +Cell[CellGroupData[{ + +Cell[BoxData[{ + RowBox[{ + RowBox[{ + RowBox[{"x", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "+", "xj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xjp1", "-", "xj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"y", "[", "\[Xi]_", "]"}], ":=", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "+", "yj"}], ")"}], "/", "2"}], "+", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"yjp1", "-", "yj"}], ")"}], "/", "2"}], "*", "\[Xi]"}]}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{ + RowBox[{"r", "[", "\[Xi]_", "]"}], ":=", + RowBox[{"Sqrt", "[", + RowBox[{ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}], "+", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}]}], "]"}]}], + ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"gradHy", "=", + RowBox[{"Integrate", "[", + RowBox[{ + RowBox[{ + FractionBox["lj", + RowBox[{"2", "*", "Pi"}]], "*", + RowBox[{"(", + RowBox[{ + RowBox[{ + FractionBox[ + RowBox[{ + RowBox[{"(", + RowBox[{"xi", "-", + RowBox[{"x", "[", "\[Xi]", "]"}]}], ")"}], "*", + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}]}], + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "4"}]], "*", "nx"}], "-", + RowBox[{ + FractionBox[ + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"1", "/", "2"}], "*", + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "2"}]}], "-", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", + RowBox[{"y", "[", "\[Xi]", "]"}]}], ")"}], "^", "2"}]}], ")"}], + RowBox[{ + RowBox[{"r", "[", "\[Xi]", "]"}], "^", "4"}]], "*", "ny"}]}], + ")"}]}], ",", "\[Xi]"}], "]"}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"bornesup", "=", + RowBox[{"gradHy", "/.", + RowBox[{"\[Xi]", "\[Rule]", "1"}]}]}], ";"}], "\[IndentingNewLine]", + RowBox[{ + RowBox[{"borneinf", "=", + RowBox[{"gradHy", "/.", + RowBox[{"\[Xi]", "\[Rule]", + RowBox[{"-", "1"}]}]}]}], ";"}], "\[IndentingNewLine]", + RowBox[{"gradHy", "=", + RowBox[{"FullSimplify", "[", + RowBox[{"bornesup", "-", "borneinf"}], "]"}]}], "\[IndentingNewLine]", + RowBox[{"formec", "=", + RowBox[{"CForm", "[", "%", "]"}]}]}], "Input", + CellLabel->"In[38]:=",ExpressionUUID->"03f15880-2958-4e18-9bb8-16c122fc0a39"], + +Cell[BoxData[ + RowBox[{"-", + FractionBox[ + RowBox[{"lj", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"ny", " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox["xi", "2"], "+", + RowBox[{"xj", " ", "xjp1"}], "-", + RowBox[{"xi", " ", + RowBox[{"(", + RowBox[{"xj", "+", "xjp1"}], ")"}]}], "-", + RowBox[{ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], " ", + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}]}]}], ")"}]}], "+", + RowBox[{"nx", " ", + RowBox[{"(", + RowBox[{ + RowBox[{"xj", " ", "yi"}], "+", + RowBox[{"xjp1", " ", "yi"}], "-", + RowBox[{"xjp1", " ", "yj"}], "-", + RowBox[{"xj", " ", "yjp1"}], "+", + RowBox[{"xi", " ", + RowBox[{"(", + RowBox[{ + RowBox[{ + RowBox[{"-", "2"}], " ", "yi"}], "+", "yj", "+", "yjp1"}], + ")"}]}]}], ")"}]}]}], ")"}]}], + RowBox[{"2", " ", "\[Pi]", " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xj"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yj"}], ")"}], "2"]}], ")"}], " ", + RowBox[{"(", + RowBox[{ + SuperscriptBox[ + RowBox[{"(", + RowBox[{"xi", "-", "xjp1"}], ")"}], "2"], "+", + SuperscriptBox[ + RowBox[{"(", + RowBox[{"yi", "-", "yjp1"}], ")"}], "2"]}], ")"}]}]]}]], "Output", + CellChangeTimes->{3.861258380590827*^9}, + CellLabel->"Out[44]=",ExpressionUUID->"a3781fd5-d327-4440-918d-e56f72684d55"], + +Cell["\<\ +-(lj*(ny*(Power(xi,2) + xj*xjp1 - xi*(xj + xjp1) - (yi - yj)*(yi - yjp1)) + \ +nx*(xj*yi + xjp1*yi - xjp1*yj - xj*yjp1 + xi*(-2*yi + yj + yjp1))))/ + (2.*Pi*(Power(xi - xj,2) + Power(yi - yj,2))*(Power(xi - xjp1,2) + \ +Power(yi - yjp1,2)))\ +\>", "Output", + CellChangeTimes->{3.8612583806008244`*^9}, + CellLabel-> + "Out[45]//CForm=",ExpressionUUID->"f99fcb66-bf4a-41a0-b4d3-08c71e8326bd"] +}, Open ]] +}, +WindowSize->{1440, 768}, +WindowMargins->{{0, Automatic}, {Automatic, 0}}, +FrontEndVersion->"12.1 for Mac OS X x86 (64-bit) (June 19, 2020)", +StyleDefinitions->"Default.nb", +ExpressionUUID->"62450a5e-61bb-4842-a3e4-6a2b62f893d3" +] +(* End of Notebook Content *) + +(* Internal cache information *) +(*CellTagsOutline +CellTagsIndex->{} +*) +(*CellTagsIndex +CellTagsIndex->{} +*) +(*NotebookFileOutline +Notebook[{ +Cell[558, 20, 223, 4, 73, "Text",ExpressionUUID->"2a4634af-38af-46df-ba82-22e16ff7cedb"], +Cell[CellGroupData[{ +Cell[806, 28, 11065, 286, 799, "Input",ExpressionUUID->"4ed55133-bec1-4475-ad1f-833b36b2d4c6"], +Cell[11874, 316, 1718, 38, 34, "Output",ExpressionUUID->"65fdfe1a-aa66-4933-962e-56e19b792ce1"], +Cell[13595, 356, 998, 14, 34, "Output",ExpressionUUID->"89f7ea64-7da5-4498-b160-d9b88f8879d8"], +Cell[14596, 372, 10273, 185, 232, "Output",ExpressionUUID->"7a89971a-d470-4aba-b097-89238335c823"], +Cell[24872, 559, 1114, 17, 34, "Output",ExpressionUUID->"c024bf23-b077-4190-b9e3-f1d5fb19ed2f"], +Cell[25989, 578, 1052, 16, 34, "Output",ExpressionUUID->"c87b3cd2-72e1-4211-9c33-d98771a9e76c"], +Cell[27044, 596, 7500, 140, 232, "Output",ExpressionUUID->"9b57112f-d238-4317-89cb-371ba4a2c235"], +Cell[34547, 738, 992, 14, 34, "Output",ExpressionUUID->"8a451dcb-573e-4f9f-97e1-ed70aded0195"], +Cell[35542, 754, 1116, 17, 34, "Output",ExpressionUUID->"71c50b88-43c3-43d1-9b99-9504c5bd5f96"], +Cell[36661, 773, 7697, 143, 232, "Output",ExpressionUUID->"db2bab01-4618-4db7-8683-117d6150b911"], +Cell[44361, 918, 1002, 14, 34, "Output",ExpressionUUID->"ba354193-5beb-4a8c-962b-96de2fd88bc5"], +Cell[45366, 934, 1716, 37, 46, "Output",ExpressionUUID->"b590e101-f372-4eaa-b07a-74c6853e96a8"], +Cell[47085, 973, 1052, 16, 34, "Output",ExpressionUUID->"6b5e6dbe-960f-4c2f-b7df-540c1741735c"], +Cell[48140, 991, 7759, 144, 232, "Output",ExpressionUUID->"f64ed0f3-5f81-46ef-b0d2-0deaec21c948"], +Cell[55902, 1137, 1365, 22, 34, "Output",ExpressionUUID->"1ad22f7c-dddb-4448-9317-229eaab684eb"], +Cell[57270, 1161, 2871, 62, 249, "Output",ExpressionUUID->"f67cbd93-c669-4bc7-87c6-cf7ae689c11a"] +}, Open ]], +Cell[60156, 1226, 407, 6, 197, "Text",ExpressionUUID->"a9e8cb00-e27d-4ce1-93f1-c63f24dce0c4"], +Cell[CellGroupData[{ +Cell[60588, 1236, 4682, 111, 472, "Input",ExpressionUUID->"3022f7f2-8c9c-43ae-9732-d602151de8a8"], +Cell[65273, 1349, 1194, 30, 56, "Output",ExpressionUUID->"953df72a-406a-4325-a6b7-b588ecdbd337"], +Cell[66470, 1381, 1227, 31, 56, "Output",ExpressionUUID->"505cf359-5431-4db8-b379-4278c65326ec"] +}, Open ]], +Cell[67712, 1415, 245, 6, 52, "Input",ExpressionUUID->"5184b6ce-6f3e-4ace-8f94-4112569cfa78"], +Cell[67960, 1423, 1468, 39, 224, InheritFromParent,ExpressionUUID->"131c83d3-03c9-4c25-8f61-e5f9f199818d"], +Cell[69431, 1464, 15945, 392, 238, "Output",ExpressionUUID->"d727041d-b24d-4120-99a1-a4716f0510ef"], +Cell[85379, 1858, 15836, 389, 238, "Output",ExpressionUUID->"bbcb174f-e6ea-4287-b0fd-9ee0a29f0795"], +Cell[CellGroupData[{ +Cell[101240, 2251, 4431, 108, 373, "Input",ExpressionUUID->"d24f20d6-729f-4ebb-9bdc-788273f1e3f9"], +Cell[105674, 2361, 1145, 30, 56, "Output",ExpressionUUID->"87820575-f7aa-4bd3-8d26-eb8329c9e90d"], +Cell[106822, 2393, 1171, 30, 56, "Output",ExpressionUUID->"c9d67024-7484-400e-99a3-606c54038a95"] +}, Open ]], +Cell[CellGroupData[{ +Cell[108030, 2428, 1400, 38, 224, "Input",ExpressionUUID->"c0d3d828-445a-4391-980f-255c7b107643"], +Cell[109433, 2468, 23699, 472, 238, 9980, 246, "CachedBoxData", "BoxData", "Output",ExpressionUUID->"97b112e4-ab45-4d66-a9b3-928d93705112"], +Cell[133135, 2942, 10339, 254, 246, "Output",ExpressionUUID->"d62a01ba-286a-47ed-b239-185edba12dd4"] +}, Open ]], +Cell[143489, 3199, 129, 3, 30, "Input",ExpressionUUID->"69447a35-9817-4522-9f86-97bb0194d98b"], +Cell[143621, 3204, 284, 5, 73, "Text",ExpressionUUID->"d4c6205f-288d-4ba9-9e4e-bc0171921df9"], +Cell[CellGroupData[{ +Cell[143930, 3213, 6943, 204, 1045, "Input",ExpressionUUID->"b039c25c-3c81-424e-b355-8af2a1fea5a1"], +Cell[150876, 3419, 1948, 37, 56, "Output",ExpressionUUID->"75c96493-d7f7-4956-b2cf-f98cdd66fda1"], +Cell[152827, 3458, 5964, 122, 244, "Output",ExpressionUUID->"1674e868-ef4e-477c-b5e8-342b479f4694"] +}, Open ]], +Cell[158806, 3583, 240, 4, 73, "Text",ExpressionUUID->"c6929cf8-3e79-4e5a-a751-f0adefbedc6a"], +Cell[CellGroupData[{ +Cell[159071, 3591, 3247, 89, 299, "Input",ExpressionUUID->"aba879f4-4fa1-4a20-84ae-7797ad362ead"], +Cell[162321, 3682, 4424, 136, 138, "Output",ExpressionUUID->"1a498cc3-ec98-4fb7-9364-dcc415205357"], +Cell[166748, 3820, 932, 18, 106, "Output",ExpressionUUID->"b3ea9741-9cac-4165-ac03-4789f7b7458a"] +}, Open ]], +Cell[CellGroupData[{ +Cell[167717, 3843, 2745, 91, 293, "Input",ExpressionUUID->"70e041ab-7a76-4842-a412-090b3714cc63"], +Cell[170465, 3936, 2984, 91, 68, "Output",ExpressionUUID->"fb22a801-d9c9-4302-a409-04f757cc31d5"], +Cell[173452, 4029, 595, 11, 70, "Output",ExpressionUUID->"0edfe664-e358-4b8b-8c1e-f77d428b251b"] +}, Open ]], +Cell[CellGroupData[{ +Cell[174084, 4045, 2822, 91, 293, "Input",ExpressionUUID->"4421bad8-e670-4d02-a48b-904eeb29edfb"], +Cell[176909, 4138, 2979, 89, 68, "Output",ExpressionUUID->"c8795095-361d-4b25-bcd0-742fae5fbfde"], +Cell[179891, 4229, 614, 11, 81, "Output",ExpressionUUID->"a7803c49-73b0-4652-a89a-bc89a1cb4cec"] +}, Open ]], +Cell[CellGroupData[{ +Cell[180542, 4245, 2852, 90, 258, "Input",ExpressionUUID->"c1f1582f-6978-4e3e-9743-4da5fa3fe712"], +Cell[183397, 4337, 1564, 49, 62, "Output",ExpressionUUID->"8918a234-b86f-421c-aab8-2633de35a885"], +Cell[184964, 4388, 397, 8, 63, "Output",ExpressionUUID->"7827bc67-ba5a-419b-a3b4-d82b0dca4cef"] +}, Open ]], +Cell[CellGroupData[{ +Cell[185398, 4401, 2803, 88, 258, "Input",ExpressionUUID->"03f15880-2958-4e18-9bb8-16c122fc0a39"], +Cell[188204, 4491, 1628, 50, 62, "Output",ExpressionUUID->"a3781fd5-d327-4440-918d-e56f72684d55"], +Cell[189835, 4543, 398, 8, 63, "Output",ExpressionUUID->"f99fcb66-bf4a-41a0-b4d3-08c71e8326bd"] +}, Open ]] +} +] +*) + diff --git a/srcs/BEM/functionsBEM.hpp b/srcs/BEM/functionsBEM.hpp index e705a73356775bcb6d84184ecb05b2d99d7b7f7a..c2cce535a33e45229b983a63ae0000941a7ff197 100644 --- a/srcs/BEM/functionsBEM.hpp +++ b/srcs/BEM/functionsBEM.hpp @@ -206,4 +206,4 @@ double computeAnalyticalGradHx(const double x, const double y, const elementStru double computeAnalyticalGradHy(const double x, const double y, const elementStruct &element); double computeAnalyticalGradGx(const double x, const double y, const elementStruct &element); double computeAnalyticalGradGy(const double x, const double y, const elementStruct &element); -double computeAnalyticalG(const double x, const double y, const elementStruct &element); \ No newline at end of file +double computeAnalyticalG(const double x, const double y, const elementStruct &element); diff --git a/srcs/BEM/mainBEM.cpp b/srcs/BEM/mainBEM.cpp index 35655adb9b513d22220df01b905da9a8178b7b90..02035781a5f8ac07e30bc7e0ac8848a8994c4116 100644 --- a/srcs/BEM/mainBEM.cpp +++ b/srcs/BEM/mainBEM.cpp @@ -22,7 +22,7 @@ int main(int argc, char **argv) std::map<int,std::pair<double,double>> nodalDisplacements; const bool postProcessing = true; const bool meshUntangler = false; - + solverBEM(electrostaticPressure, nbViews, nodalDisplacements, postProcessing, 1, meshUntangler); // iteration number randomly set to 1 if(postProcessing) diff --git a/srcs/FEM/complex_validation.geo b/srcs/FEM/complex_validation.geo index 47e62fe7faf89f96039b9b0497e4db00896d6c36..c6497d704d992ca7c8e18d45c13bd1a1477d9b89 100644 --- a/srcs/FEM/complex_validation.geo +++ b/srcs/FEM/complex_validation.geo @@ -2,15 +2,15 @@ Lx = 5; Ly = 2; -nx = 50; -ny = 20; - -Point(1) = {0, 0, 0, 0.1}; -Point(2) = {Lx, 0, 0, 0.2}; -Point(3) = {Lx, Ly, 0, 0.2}; -Point(4) = {0, Ly, 0, 0.1}; -Point(5) = {Lx/2, 0, 0, 0.15}; -Point(6) = {Lx/2, Ly, 0, 0.15}; +nx = 250; +ny = 100; + +Point(1) = {0, 0, 0, 0.05}; //4th number is mesh density +Point(2) = {Lx, 0, 0, 0.1}; +Point(3) = {Lx, Ly, 0, 0.1}; +Point(4) = {0, Ly, 0, 0.05}; +Point(5) = {Lx/2, 0, 0, 0.075}; +Point(6) = {Lx/2, Ly, 0, 0.075}; Line(1) = {1, 5}; Line(2) = {2, 5}; Line(3) = {3, 2}; @@ -52,6 +52,8 @@ SetNumber("Boundary Conditions/right_edge/tx", 21e3); //for simple tension condi SetNumber("Boundary Conditions/right_edge/ty", 0.); SetNumber("Volumic Forces/FEM_domain/bx",0.); SetNumber("Volumic Forces/FEM_domain/by",0.); //set to -9.81 for gravity -SetNumber("Boundary Conditions/fixed_node/uy",0.); +SetNumber("Boundary Conditions/fixed_node/uy",2); Physical Curve("BEM_FEM_boundary", 10) = {1,2,3,4,5,6}; + +SetNumber("Non_linear_solver", 0); \ No newline at end of file diff --git a/srcs/FEM/functionsFEM.cpp b/srcs/FEM/functionsFEM.cpp index 5e9c0f8d378069bb173514d0d35f8ca361783761..4e39d98fc945929feef1a900577489a4f010f6de 100644 --- a/srcs/FEM/functionsFEM.cpp +++ b/srcs/FEM/functionsFEM.cpp @@ -1,82 +1,236 @@ #ifdef _MSC_VER -#include <gmsh.h_cwrap> // gmsh main header +#include <gmsh.h_cwrap> #else -#include <gmsh.h> // gmsh main header +#include <gmsh.h> #endif #include "functionsFEM.hpp" -#include <iostream> // for std::cout +#include <iostream> #include <map> -#include <sstream> // for std::stringstream -#include <Eigen/Dense> // Eigen library -#include <Eigen/Sparse> // Eigen library for sparse matrices +#include <sstream> +#include <Eigen/Dense> +#include <Eigen/Sparse> #include <Eigen/SparseCholesky> // solving sparse linear systems #include <Eigen/Core> #include <cmath> -#include <algorithm> // to sort and merge the FEM node vectors +#include <algorithm> #ifdef _OPENMP #include <omp.h> #endif #define PI M_PI -//Compute the matrix H -Eigen::Matrix<double, 3, 3> computeHmatrix(const double E, const double nu) +// returns the boolean non_linear_solver parameter based on what is set in the .geo file, +// add SetNumber("Non_linear_solver", 0); in .geo file to use linear solver. +bool getNonLinearParameter() { - Eigen::Matrix<double, 3, 3> H_matrix; - H_matrix(0,0) = 1.; - H_matrix(1,0) = nu; - H_matrix(2,0) = 0.; - H_matrix(0,1) = nu; - H_matrix(1,1) = 1.; - H_matrix(2,1) = 0.; - H_matrix(0,2) = 0.; - H_matrix(1,2) = 0.; - H_matrix(2,2) = (1-nu)/2; - H_matrix = E/(1-nu*nu)*H_matrix; - return H_matrix; + std::vector<std::string> keys; + gmsh::onelab::getNames(keys, "Non_linear_solver"); + if(keys.size()) + { + std::vector<double> value; + gmsh::onelab::getNumber(keys[0], value); + if(value[0]) + { + return true; + } + else + { + return false; + } + } + else + { + std::cout << "you did not choose the type of solver (linear or not) in the .geo file, 'SetNumber('Non_linear_solver',x);'. Automatically set to non linear type \n"; + return true; + } } -//Compute the full matrix "f" of one given thread -void assembleFthread(const int i, const int el, - const std::vector<std::vector<std::size_t>> & nodeTags, - const int numNodes, std::map<int, int> & nodeIndexMap, - std::list<std::pair<int,double>> & thread_f_vector, - std::vector<double> & f_vector) +// fills the "FEM_nodeTags" vector with the nodes in the FEM domain, fills the "FEM_nodeCoordsMap" with the coordinates (x,y) +// corresponding to each nodeTag, looking at entity tags "tags" of dimension "dim" corresponding to the FEM domain. +void RetrieveFEMNodeTagsAndCoords(std::vector<std::size_t> & FEM_nodeTags, + std::map<int,std::pair<double,double>> & FEM_nodeCoordsMap, + const int & dim, const std::vector<int> & tags) { - int first_node_index; - int first_node; - int my_row; - for (int j = 0; j < 2*numNodes; ++j) + //loop over the entities of the FEM domain to retrieve all nodeTags by taking care not to take some nodes twice + //using sort and set_union methods + retrieving the node coordinates and storing them in a map + std::vector<double> FEM_nodecoord; + std::vector<double> FEM_nodeparametricCoord; + std::vector<std::vector<std::size_t>> tmp_nodeTags(tags.size()); // will store the nodeTags associated to one given entity of the domain + gmsh::model::mesh::getNodes(tmp_nodeTags[0], FEM_nodecoord, FEM_nodeparametricCoord, dim, tags[0], true); + for(std::size_t j = 0; j < tmp_nodeTags[0].size(); j++) { - first_node_index = (int) j/2; - first_node = nodeTags[i][numNodes*el+first_node_index]; - my_row = nodeIndexMap[first_node] + j % 2; - thread_f_vector.push_back(std::pair<int, double>(my_row, f_vector[j])); + FEM_nodeCoordsMap[tmp_nodeTags[0][j]] = std::pair<double, double>(FEM_nodecoord[3*j], FEM_nodecoord[3*j+1]); + } + std::sort(tmp_nodeTags[0].begin(), tmp_nodeTags[0].end()); // need to sort the vectors in order to merge them afterwards + for (std::size_t i = 1; i < tags.size(); i++) + { // in the case the domain contains multiple entities + gmsh::model::mesh::getNodes(tmp_nodeTags[i], FEM_nodecoord, FEM_nodeparametricCoord, dim, tags[i], true); + for(std::size_t j = 0; j < tmp_nodeTags[i].size(); j++) + { + FEM_nodeCoordsMap[tmp_nodeTags[i][j]] = std::pair<double, double>(FEM_nodecoord[3*j], FEM_nodecoord[3*j+1]); + } + std::sort(tmp_nodeTags[i].begin(), tmp_nodeTags[i].end()); + std::set_union(tmp_nodeTags[i-1].begin(), tmp_nodeTags[i-1].end(), + tmp_nodeTags[i].begin(), tmp_nodeTags[i].end(), std::back_inserter(FEM_nodeTags)); // works only for 2 domains -> see little trick just below + + } + if(tags.size() == 1){ // if the domain contains one single entity + FEM_nodeTags = tmp_nodeTags[0]; + } + else{ // little trick for more than 2 domains + std::sort(FEM_nodeTags.begin(), FEM_nodeTags.end()); + auto last = std::unique(FEM_nodeTags.begin(), FEM_nodeTags.end()); + FEM_nodeTags.erase(last, FEM_nodeTags.end()); } } +// fills the "FEM_elementTags" vector with all element tags of the elements of dimension "dim" (in practice: 2) +// in the entities associated to the entity tags "tags" (corresponding to the FEM domain). +// associates an initialized elementData structure to each element tag through the "FEM_kinematicsMap" map, +// using the "FEM_nodeCoordsMap" map gathering the coordinates of each node in the FEM domain. +int initKinematics(std::vector<std::size_t> & FEM_elementTags, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int,std::pair<double,double>> & FEM_nodeCoordsMap, + const int & dim, const std::vector<int> & tags) +{ + std::vector<int> elementTypes; + std::vector<std::vector<std::size_t>> elementTags; + std::vector<std::vector<std::size_t>> elnodeTags; -void computeBmatrix(const int j, const int numNodes, const std::vector<double> & basisFunctionsGradient, - const std::vector<double> & determinants, - const Eigen::Matrix<double, 2, 2> & jacobinvtrans, - const Eigen::Matrix<double, 3, 3> & H_matrix, - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & B_matrix) + std::string elementName; + int elDim, order, numNodes, numPrimaryNodes; + std::vector<double> localNodeCoord; + + int nbelems=0; // will store total number of elements in FEM domain + for(std::size_t i=0; i< tags.size(); ++i) + { + gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[i]); + for(std::size_t j=0; j< elementTags.size(); ++j) + { + nbelems+=elementTags[j].size(); + // filling the FEM_elementTags vector + FEM_elementTags.insert(FEM_elementTags.end(), elementTags[j].begin(), elementTags[j].end()); + + // getting element properties, in particular: number of nodes + gmsh::model::mesh::getElementProperties(elementTypes[j], + elementName, elDim, order, + numNodes, localNodeCoord, + numPrimaryNodes); + for(std::size_t k = 0; k < elementTags[j].size(); k++) + { + elementData element; + std::vector<size_t> tmp_nodes(numNodes); + std::vector<double> tmp_x(numNodes); + std::vector<double> tmp_y(numNodes); + std::vector<double> tmp_u(numNodes); + std::vector<double> tmp_v(numNodes); + std::vector<double> tmp_ui(numNodes); + std::vector<double> tmp_vi(numNodes); + double tmp_xc = 0; + double tmp_yc = 0; + for(int l = 0; l < numNodes; l++) + { + tmp_nodes[l] = elnodeTags[j][numNodes*k + l]; + tmp_x[l] = FEM_nodeCoordsMap[tmp_nodes[l]].first; + tmp_y[l] = FEM_nodeCoordsMap[tmp_nodes[l]].second; + tmp_u[l] = 0; // initializing the displacement at zero + tmp_v[l] = 0; + tmp_ui[l] = 0; + tmp_vi[l] = 0; + tmp_xc += tmp_x[l]; + tmp_yc += tmp_y[l]; + } + tmp_xc = tmp_xc / numNodes; + tmp_yc = tmp_yc / numNodes; + + std::vector<double> tmp_xi(numNodes); + std::vector<double> tmp_yi(numNodes); + for(int l = 0; l < numNodes; l++) + { + tmp_xi[l] = tmp_x[l] - tmp_xc; + tmp_yi[l] = tmp_y[l] - tmp_yc; + } + element.nodes = tmp_nodes; + element.x = tmp_x; + element.y = tmp_y; + element.xc = tmp_xc; + element.yc = tmp_yc; + element.xi = tmp_xi; + element.yi = tmp_yi; + element.u = tmp_u; + element.v = tmp_v; + element.uc = 0; + element.vc = 0; + element.theta = 0; + element.ui = tmp_ui; + element.vi = tmp_vi; + element.pl = Eigen::Matrix<double, Eigen::Dynamic, 1>::Zero(2*numNodes,1); + element.A = Eigen::Matrix<double, Eigen::Dynamic, 1>(2*numNodes,1); + element.G = Eigen::Matrix<double, 1, Eigen::Dynamic>(1,2*numNodes); + element.E = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>::Zero(2*numNodes, 2*numNodes); + + FEM_kinematicsMap[elementTags[j][k]] = element; + updateKinMatrices(& FEM_kinematicsMap[elementTags[j][k]], false); + } + } + } + return nbelems; +} + +// updates the kinematics matrices of one element "element" based on its updated nodal positions and rotation angle. +// if "computeFl" is set as true, also computes the local nodal forces vector "fl = Kl*pl", only OK if +// the local stiffness matrix Kl has already been initialized, using "fillElementalKandF". +void updateKinMatrices(elementData* element, const bool computeFl) { - for (int l = 0; l < numNodes; ++l){ // looping over the number of shape functions - B_matrix(0,2*l) = jacobinvtrans(0,0)*basisFunctionsGradient[3*l+numNodes*3*j]+jacobinvtrans(0,1)*basisFunctionsGradient[3*l+numNodes*3*j+1]; - B_matrix(1,2*l) = 0.; - B_matrix(2,2*l) = jacobinvtrans(1,0)*basisFunctionsGradient[3*l+numNodes*3*j]+jacobinvtrans(1,1)*basisFunctionsGradient[3*l+numNodes*3*j+1]; - B_matrix(0,2*l+1) = 0.; - B_matrix(1,2*l+1) = B_matrix(2,2*l); - B_matrix(2,2*l+1) = B_matrix(0,2*l); + // for the different formulas, please refer to the report + size_t numNodes = element->nodes.size(); + // update A matrix + for(size_t i = 0; i < numNodes; i++) + { + element->A(2*i, 0) = -(element->vi[i]+element->yi[i]); + element->A(2*i + 1, 0) = element->ui[i]+element->xi[i]; + } + + // update G matrix + double denominator = 0; + for(size_t i = 0; i < numNodes; i++) + { + element->G(0, 2*i) = -element->yi[i]; + element->G(0, 2*i + 1) = element->xi[i]; + denominator += element->xi[i]*(element->ui[i]+element->xi[i]) + element->yi[i]*(element->vi[i]+element->yi[i]); + } + element->G *= 1 / denominator; + + // update P matrix + element->P = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>::Identity(2*numNodes,2*numNodes) - element->A*element->G; + + // update E matrix + double tmp_cos = cos(element->theta); + double tmp_sin = sin(element->theta); + for(size_t i = 0; i < numNodes; i++) + { + element->E(2*i, 2*i) = tmp_cos; + element->E(2*i, 2*i + 1) = -tmp_sin; + element->E(2*i + 1, 2*i) = tmp_sin; + element->E(2*i + 1, 2*i + 1) = tmp_cos; + } + + //update C matrix + element->C = element->P*element->E.transpose(); + + //update fl vector, only if Kl has been initialized + if(computeFl) + { + element->fl = element->Kl*element->pl; } } -//Get physical properties of domain -void getPhysicalProperties(const std::vector<std::string> & keys, double & E, double & nu, double & rho, - double & bx, double & by) +// gets physical properties of FEM_domain: Young's modulus "E", Poisson's ratio "nu", +// density "rho", volumic force along x "bx", volumic force along y "by". +void getPhysicalProperties(double & E, double & nu, double & rho, double & bx, double & by) { + std::vector<std::string> keys; + gmsh::onelab::getNames(keys, "(Volumic Forces|Materials).+"); for (auto &key : keys) { // get corresponding value @@ -110,12 +264,30 @@ void getPhysicalProperties(const std::vector<std::string> & keys, double & E, do } } -void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double rho, const double bx, const double by, - const std::string & integration_rule, - int & dim, std::vector<int> & tags, std::map<int, int> & nodeIndexMap, - std::vector<std::list<Eigen::Triplet <double>>> & my_k_list, - std::vector<std::list<std::pair<int,double>>> & thread_f_vector, - std::map<int, elementData> & FEM_kinematicsMap) +// computes the Hooke's matrix in plane stress "H_matrix" based on the Young's modulus "E" and Poisson's ratio "nu". +Eigen::Matrix<double, 3, 3> computeHmatrix(const double E, const double nu) +{ + Eigen::Matrix<double, 3, 3> H_matrix; + H_matrix(0,0) = 1.; + H_matrix(1,0) = nu; + H_matrix(2,0) = 0.; + H_matrix(0,1) = nu; + H_matrix(1,1) = 1.; + H_matrix(2,1) = 0.; + H_matrix(0,2) = 0.; + H_matrix(1,2) = 0.; + H_matrix(2,2) = (1-nu)/2; + H_matrix = E/(1-nu*nu)*H_matrix; + return H_matrix; +} + +// looping over every element in the FEM_domain (dimension "dim" and entity tags "tags"), filling "full_f_vector", +// with the local volumic forces computed based on the volumic force ("bx","by") and density "rho" with the help of +// "nodeIndexMap" mapping each nodeTag to its global index. +// filling the local stiffness matrices stored in the elementData structure contained in "FEM_kinematicsMap". +void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double & rho, const double & bx, + const double & by, const int & dim, const std::vector<int> & tags, std::map<int, int> & nodeIndexMap, + std::vector<double> & full_f_vector, std::map<int, elementData> & FEM_kinematicsMap) { std::vector<int> elementTypes; std::vector<std::vector<std::size_t>> elementTags; @@ -133,7 +305,7 @@ void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double gmsh::model::mesh::getElements(elementTypes, elementTags, nodeTags, dim, tags[k]); - // looping over element types, enlever les déclarations des boucles pr aller plus vite (cfr Boman) + // looping over element types for (std::size_t i = 0; i < elementTypes.size(); ++i) { // getting element properties @@ -141,17 +313,24 @@ void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double elementName, elDim, order, numNodes, localNodeCoord, numPrimaryNodes); + + // adapting the composite integration rule as a function of the order of the elements + std::string adapting_integration_rule = "CompositeGauss14"; + if(order < 8) + { + adapting_integration_rule = "CompositeGauss" + std::to_string(2*order); + } // get Gauss points coordinates and weights gmsh::model::mesh::getIntegrationPoints(elementTypes[i], - integration_rule, // "Gauss2" + adapting_integration_rule, localCoords, weights); // get determinants and Jacobians std::vector<double> jacobians, determinants, coords; gmsh::model::mesh::getJacobians(elementTypes[i], localCoords, jacobians, - determinants, coords); + determinants, coords, tags[k]); // values and derivatives of the shape functions at the Gauss points of the reference element // we are here working with derivatives in the reference space, same for all elements @@ -167,15 +346,16 @@ void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double /*---------computing the K matrix (and f vector, only volumic part for now)------*/ // looping over the elements (computing elemental K matrices) - //double test1 = omp_get_wtime(); - //Eigen::setNbThreads(1); - #pragma omp parallel for #ifdef _MSC_VER // https://github.com/tesseract-ocr/tesseract/issues/3285 // OpenMP 2.0 standard is enforced - we may use /openmp:llvm and keep size_t - for (int el = 0; el < elementTags[i].size(); el++){ + #pragma omp parallel for + for (size_t el = 0; el < elementTags[i].size(); el++) + { #else - for (std::size_t el = 0; el < elementTags[i].size(); el++){ + #pragma omp parallel for + for (std::size_t el = 0; el < elementTags[i].size(); el++) + { #endif // elemental K matrix and f vector initialization Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> K_matrix(2*numNodes,2*numNodes); @@ -183,12 +363,13 @@ void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double K_matrix.setZero(); for (int j = 0; j < 2*numNodes; ++j)f_vector[j] = 0.; - // looping over the Gauss points (formula of slide 17) - for (std::size_t j = 0; j < weights.size(); ++j){ + // looping over the Gauss points + for (std::size_t gaussIndex = 0; gaussIndex < weights.size(); ++gaussIndex) + { // converting jacobian to Eigen format Eigen::Matrix<double, 2, 2> jacob2D; Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > - jacob(&jacobians[9*j+9*weights.size()*el], 3, 3); + jacob(&jacobians[9*gaussIndex+9*weights.size()*el], 3, 3); // 3D to 2D (plane stress case) jacob2D(0,0) = jacob(0,0); jacob2D(1,0) = jacob(1,0); @@ -204,67 +385,68 @@ void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double // computing the B matrix (formula slide 19) and the f vector (also using gauss integration) Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); - - computeBmatrix(j, numNodes, basisFunctionsGradient, determinants, - jacobinvtrans, H_matrix, B_matrix); + computeBmatrix(gaussIndex, numNodes, basisFunctionsGradient, determinants, jacobinvtrans, B_matrix); - for (int l = 0; l < numNodes; ++l){ // looping over the number of shape functions - f_vector[2*l] = f_vector[2*l] + rho*basisFunctions[l+numNodes*j]*bx*determinants[j+weights.size()*el]*weights[j]; //pas oublier le dét ! - f_vector[2*l+1] = f_vector[2*l+1] + rho*basisFunctions[l+numNodes*j]*by*determinants[j+weights.size()*el]*weights[j]; // pas oublier le weights[j] non plus ! + for (int l = 0; l < numNodes; ++l) + { // looping over the number of shape functions + f_vector[2*l] = f_vector[2*l] + rho*basisFunctions[l+numNodes*gaussIndex]*bx*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; + f_vector[2*l+1] = f_vector[2*l+1] + rho*basisFunctions[l+numNodes*gaussIndex]*by*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; } - K_matrix = K_matrix + B_matrix.transpose()*H_matrix*B_matrix*determinants[j+weights.size()*el]*weights[j]; + K_matrix = K_matrix + B_matrix.transpose()*H_matrix*B_matrix*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; } /*------------- ASSEMBLY PROCESS ------------*/ - // USE LIST OF TRIPLETS TO PUSH ONLY ONCE -> more rapid and easier to parallelize FEM_kinematicsMap[elementTags[i][el]].Kl = K_matrix; - assembleFthread(i, el, nodeTags, numNodes, nodeIndexMap, thread_f_vector[omp_get_thread_num()], f_vector); - //std::cout << omp_get_thread_num() << "\n"; + assembleFlocal(el, nodeTags[i], numNodes, nodeIndexMap, full_f_vector, f_vector); } - //double test2 = omp_get_wtime() - test1; - //std::cout << "loop time: " << test2 << "\n"; } } } -/*-----------computing the f vector components related to this Neumann BC---------*/ -void computeNeumannBC(const int numNodes, const int i, const std::vector<std::vector<std::size_t>> & elementTags, - const double tx, const double ty, std::map<int, int> & nodeIndexMap, - std::vector<double> & f_vector, - const std::vector<double> & weights, const std::vector<double> & basisFunctions, - const std::vector<double> & determinants, const std::vector<std::vector<std::size_t>> & nodeTags, - std::vector<double> & full_f_vector) +// computing the strain displacement "B_matrix" at the "gaussIndex"-th gaussian point of the element +// consisting of "numNodes" nodes, based on the "basisFunctionsGradient", "determinants" and the inverse of the jacobian +// matrix "jacobinvtrans". +void computeBmatrix(const int &gaussIndex, const int &numNodes, const std::vector<double> & basisFunctionsGradient, + const std::vector<double> & determinants, + const Eigen::Matrix<double, 2, 2> & jacobinvtrans, + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & B_matrix) +{ + for (int l = 0; l < numNodes; ++l){ // looping over the number of shape functions + B_matrix(0,2*l) = jacobinvtrans(0,0)*basisFunctionsGradient[3*l+numNodes*3*gaussIndex]+jacobinvtrans(0,1)*basisFunctionsGradient[3*l+numNodes*3*gaussIndex+1]; + B_matrix(1,2*l) = 0.; + B_matrix(2,2*l) = jacobinvtrans(1,0)*basisFunctionsGradient[3*l+numNodes*3*gaussIndex]+jacobinvtrans(1,1)*basisFunctionsGradient[3*l+numNodes*3*gaussIndex+1]; + B_matrix(0,2*l+1) = 0.; + B_matrix(1,2*l+1) = B_matrix(2,2*l); + B_matrix(2,2*l+1) = B_matrix(0,2*l); + } +} + +// assembles the local "f_vector" into the full f vector, "elIndex" is the element index with respect to "nodeTags" +// having "numNodes" nodes, "nodeTags" gathering all the nodeTags of the current element type in the current entity. +// "nodeIndexMap" associates a global index to each nodetag. +void assembleFlocal(const int &elIndex, const std::vector<std::size_t> & nodeTags, const int &numNodes, + std::map<int, int> & nodeIndexMap, std::vector<double> & full_f_vector, const std::vector<double> & f_vector) { int first_node_index; int first_node; int my_row; - - for (std::size_t el = 0; el < elementTags[i].size(); el++){ - for (int j = 0; j < 2*numNodes; ++j){ - f_vector[j] = 0.; - } - // looping over the Gauss points (formula of slide 17) - for (std::size_t j = 0; j < weights.size(); ++j){ - // looping over the number of shape functions - for (int l = 0; l < numNodes; ++l){ - f_vector[2*l] = f_vector[2*l] + basisFunctions[l+numNodes*j]*tx*determinants[j+weights.size()*el]*weights[j]; //pas oublier le dét ! - f_vector[2*l+1] = f_vector[2*l+1] + basisFunctions[l+numNodes*j]*ty*determinants[j+weights.size()*el]*weights[j]; // le weight non plus ! - } - } - /*------------- ASSEMBLY PROCESS ------------*/ - for (int j = 0; j < 2*numNodes; ++j){ - first_node_index = (int) j/2; - first_node = nodeTags[i][numNodes*el+first_node_index]; - my_row = nodeIndexMap[first_node] + j % 2; - full_f_vector[my_row] += f_vector[j]; - } - } + for (int j = 0; j < 2*numNodes; ++j) + { + first_node_index = (int) j/2; + first_node = nodeTags[numNodes*elIndex+first_node_index]; + my_row = nodeIndexMap[first_node] + j % 2; + #pragma omp atomic update + full_f_vector[my_row] += f_vector[j]; + } } -/*-----------focus on neumann BC's (surface traction) into full_f_vector------------*/ -void includeNeumannBC(const std::vector<std::string> & keys, const std::string & integration_rule, - std::map<int, int> & nodeIndexMap, - std::map<std::string, std::pair<int, int>> & groups, +// fills the "full_f_vector" with the surfacic contribution of the neumann boundary conditions based on the +// "nodeIndexMap" associating a global index to each node tag, the local integration of the surfacic forces is +// performed using Gauss integration based on "integration rule". +// "BCkeys" gathers the keys associated to boundary conditions in the .geo file (using SetNumber(...)). +// "groups" associates a dimension and a tag to each physical group. +void includeNeumannBC(const std::vector<std::string> & BCkeys, const std::string & integration_rule, + std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, std::vector<double> & full_f_vector) { double tx = 0; // surface traction along x axis @@ -283,7 +465,7 @@ void includeNeumannBC(const std::vector<std::string> & keys, const std::string & int numComponents, numOrientations; std::vector<double> basisFunctions; - for (auto &key : keys) + for (auto &key : BCkeys) { // get corresponding value std::vector<double> value; @@ -306,9 +488,8 @@ void includeNeumannBC(const std::vector<std::string> & keys, const std::string & if(tx || ty) // there is no need the consider Neumann BC if it is homogeneous groupname = words[1]; } - //here, if we are dealing with neumann BC's, we should have retrieved a non-empty group_name + //here, if we are dealing with neumann BC's, we should have retrieved a non-empty groupname if(groupname.compare("") != 0){ - //loop over elements of group_name dim = groups[groupname].first; tag = groups[groupname].second; if (tag == 0) @@ -316,7 +497,7 @@ void includeNeumannBC(const std::vector<std::string> & keys, const std::string & std::cerr << "Group '" << groupname << "' does not exist!\n"; return; } - gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); + gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); // entities of particular groupname // loop over entities for (std::size_t k = 0; k < tags.size(); ++k) @@ -334,26 +515,44 @@ void includeNeumannBC(const std::vector<std::string> & keys, const std::string & // get Gauss points coordinates and weights gmsh::model::mesh::getIntegrationPoints(elementTypes[i], - integration_rule, //maybe use different integration method on boundary than in domain + integration_rule, localCoords, weights); // get determinants and Jacobians (only determinants will be useful) std::vector<double> jacobians, determinants, coords; gmsh::model::mesh::getJacobians(elementTypes[i], localCoords, jacobians, - determinants, coords,tags[k]); // ai dû rajouter mon tags[k] pr focus on this particular entity + determinants, coords, tags[k]); gmsh::model::mesh::getBasisFunctions(elementTypes[i], localCoords, "Lagrange", numComponents, basisFunctions, numOrientations); - /*-----------computing the f vector components related to this Neumann BC---------*/ - //looping over the elements - std::vector<double> f_vector(2*numNodes); - computeNeumannBC(numNodes, i, elementTags, tx, ty, nodeIndexMap, - f_vector, weights, basisFunctions, - determinants, nodeTags, full_f_vector); + //looping over the element types + #pragma omp parallel for + for (std::size_t el = 0; el < elementTags[i].size(); el++){ + std::vector<double> f_vector(2*numNodes); + for (int j = 0; j < 2*numNodes; ++j){ + f_vector[j] = 0.; + } + // looping over the Gauss points + for (std::size_t j = 0; j < weights.size(); ++j){ + // looping over the number of shape functions + for (int l = 0; l < numNodes; ++l){ + f_vector[2*l] = f_vector[2*l] + basisFunctions[l+numNodes*j]*tx*determinants[j+weights.size()*el]*weights[j]; //pas oublier le dét ! + f_vector[2*l+1] = f_vector[2*l+1] + basisFunctions[l+numNodes*j]*ty*determinants[j+weights.size()*el]*weights[j]; // le weight non plus ! + } + } + /*------------- ASSEMBLY PROCESS ------------*/ + for (int j = 0; j < 2*numNodes; ++j){ + int first_node_index = (int) j/2; + int first_node = nodeTags[i][numNodes*el+first_node_index]; + int my_row = nodeIndexMap[first_node] + j % 2; + #pragma omp atomic update + full_f_vector[my_row] += f_vector[j]; + } + } } } } @@ -361,367 +560,20 @@ void includeNeumannBC(const std::vector<std::string> & keys, const std::string & } } -// looping over the boundary conditions imposed in the .geo file, the purpose of the whole loop is -// to fill the two vectors defined just above -void fillDOFindicesDirBC(const std::vector<std::string> & keys, - std::map<int, int> & nodeIndexMap, - std::map<std::string, std::pair<int, int>> & groups, - std::vector<int> & new_DOFindices, - std::vector<double> & dir_BC) +// for the coupled solver, fills the "full_f_vector" with the electrostatic pressure contained in the +// "electrostaticPressure" map for different element tags, using Gauss integration "integration_rule", the "nodeIndexMap" +// associating a global nodal index to each nodeTag, "nodeCoordsMap" gathering the coordinates of each node and "groups" +// containing the different physical groups of the domain. +void applyElecPressure(const std::string & integration_rule, std::map<int,std::pair<double,double>> & nodeCoordsMap, + std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, + std::map<int, double> &electrostaticPressure, std::vector<double> & full_f_vector) { - - for (std::size_t j = 0; j < new_DOFindices.size(); ++j){ - new_DOFindices[j] = (int) j; - } - for (std::size_t j = 0; j < dir_BC.size(); ++j){ - dir_BC[j] = 0; - } - - double ux; // imposed displacement along x axis - double uy; // imposed displacement along y axis - - int dim; - int tag; + // electrostatic pressure must only be applied on the BEM_FEM_boundary + std::string groupname = "BEM_FEM_boundary"; + int dim = groups[groupname].first; + int tag = groups[groupname].second; std::vector<int> tags; - std::vector<int> elementTypes; - std::vector<std::vector<std::size_t>> elementTags; - std::vector<std::vector<std::size_t>> nodeTags; - std::string elementName; - int elDim, order, numNodes, numPrimaryNodes; - std::vector<double> localNodeCoord; - - int first_node_index; - int first_node; - int my_row; - - for (auto &key : keys) - { - // get corresponding value - std::vector<double> value; - gmsh::onelab::getNumber(key, value); - // expected key structure is "type/group_name/field" - // => split the key string into components - std::stringstream ss(key); - std::vector<std::string> words; - std::string word; - while(std::getline(ss, word, '/')) // read string until '/' - words.push_back(word); - if(words.size()==3) - { - if(words[2].compare("ux") == 0 || words[2].compare("uy") == 0){ - ux = 0; - uy = 0; - if(words[2].compare("ux") == 0) - ux = value[0]; - if(words[2].compare("uy") == 0) - uy = value[0]; - std::string groupname = words[1]; - - //loop over elements of group_name - dim = groups[groupname].first; - tag = groups[groupname].second; - if (tag == 0) - { - std::cerr << "Group '" << groupname << "' does not exist!\n"; - return; - } - gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - - for (std::size_t k = 0; k < tags.size(); ++k) - { - gmsh::model::mesh::getElements(elementTypes, elementTags, - nodeTags, dim, tags[k]); - - for (std::size_t i = 0; i < elementTypes.size(); ++i) - { - gmsh::model::mesh::getElementProperties(elementTypes[i], - elementName, elDim, order, - numNodes, localNodeCoord, - numPrimaryNodes); - //looping over the elements - for (std::size_t el = 0; el < elementTags[i].size(); el++){ - for (int j = 0; j < 2*numNodes; ++j){ - first_node_index = (int) j/2; - first_node = nodeTags[i][numNodes*el+first_node_index]; - my_row = nodeIndexMap[first_node] + j % 2; // j % 2 == 1 corresponds to y nodal displacement - if(words[2].compare("uy") == 0 && j % 2){ // we are dealing with a uy type of node - dir_BC[my_row] = uy; - new_DOFindices[my_row] = -1; - } - if(words[2].compare("ux") == 0 && j % 2 == 0){ // ux type of node - dir_BC[my_row] = ux; - new_DOFindices[my_row] = -1; - } - } - } - } - } - } - } - } -} - -void computeReactionForces(std::map<std::string, std::pair<int, int>> & groups, - std::map<int, int> & nodeIndexMap, std::vector<double> & final_nodal_forces, - const std::vector<std::string> & keys) -{ - double Rx; - double Ry; - - int dim; - int tag; - std::vector<int> tags; - - std::vector<std::size_t> nodeTags; - std::vector<double> coord; //useless but mandatory - std::vector<double> parametricCoord; //useless but mandatory - - for (auto &key : keys) - { - // get corresponding value - std::vector<double> value; - gmsh::onelab::getNumber(key, value); - // expected key structure is "type/group_name/field" - // => split the key string into components - std::stringstream ss(key); - std::vector<std::string> words; - std::string word; - while(std::getline(ss, word, '/')) // read string until '/' - words.push_back(word); - if(words.size()==3) - { - if(words[2].compare("ux") == 0 || words[2].compare("uy") == 0){ - Rx = 0; - Ry = 0; - std::string groupname = words[1]; - std::cout << "-------------------- " << groupname << " ------------------- \n"; - - //loop over elements of group_name - dim = groups[groupname].first; - tag = groups[groupname].second; - if (tag == 0) - { - std::cerr << "Group '" << groupname << "' does not exist!\n"; - return; - } - gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - - // loop over entities - for (std::size_t k = 0; k < tags.size(); ++k) - { - // retrieving all the nodes in this particular entity - gmsh::model::mesh::getNodes(nodeTags, coord, parametricCoord, dim, tags[k], true); - - - for (std::size_t j = 0; j < nodeTags.size(); ++j){ - if(words[2].compare("ux") == 0){ // computing Rx - int my_new_col = nodeIndexMap[nodeTags[j]]; // le noeud numéro nodeIndexMap[nodeTags[j]] correspond à la ligne/colonne dans K, f - Rx += final_nodal_forces[my_new_col]; - } - if(words[2].compare("uy") == 0){ // computing Ry - int my_new_col = nodeIndexMap[nodeTags[j]] + 1; - Ry += final_nodal_forces[my_new_col]; - } - } - } - std::cout << "Rx: " << Rx << " [N/m], Ry: " << Ry << " [N/m] \n"; - } - } - } -} - -void plotUxUy(const std::vector<std::size_t> & FEM_nodeTags, const std::vector<double> & full_d_vector, const int nbViews, std::vector<std::string> & names) -{ - int viewtag1 = gmsh::view::add("ux"); - int viewtag2 = gmsh::view::add("uy"); - std::vector<std::vector<double>> data1(FEM_nodeTags.size()); - std::vector<std::vector<double>> data2(FEM_nodeTags.size()); - for (std::size_t i = 0; i < FEM_nodeTags.size(); ++i) - { - data1[i].resize(1); - data1[i][0] = full_d_vector[2*i]; //ux // à modifier ici - data2[i].resize(1); - data2[i][0] = full_d_vector[2*i+1]; //uy - } - - gmsh::view::addModelData(viewtag1, 0, names[0], "NodeData", - FEM_nodeTags, data1); //independent of time here - gmsh::view::addModelData(viewtag2, 0, names[0], "NodeData", - FEM_nodeTags, data2); //independent of time here - - // save the results to disk - //gmsh::view::write(viewtag1, "ux.msh"); - //gmsh::view::write(viewtag2, "uy.msh"); - - // set display options & view results - /*gmsh::option::setNumber("View[" + std::to_string(nbViews +2) + "].IntervalsType", 3); - gmsh::option::setNumber("View[" + std::to_string(nbViews + 2) + "].AdaptVisualizationGrid", 1); - gmsh::option::setNumber("View[" + std::to_string(nbViews + 2) + "].MaxRecursionLevel", 3); - gmsh::option::setNumber("View[" + std::to_string(nbViews + 2) + "].TargetError", -0.0001); - gmsh::option::setNumber("View[" + std::to_string(nbViews +3) + "].IntervalsType", 3); - gmsh::option::setNumber("View[" + std::to_string(nbViews +3) + "].AdaptVisualizationGrid", 1); - gmsh::option::setNumber("View[" + std::to_string(nbViews +3) + "].MaxRecursionLevel", 3); - gmsh::option::setNumber("View[" + std::to_string(nbViews +3) + "].TargetError", -0.0001);*/ -} - -void computeStressStrainElNodal(const std::vector<int> & elementTypes, const std::vector<std::vector<std::size_t>> &elementTags, - const std::vector<std::vector<std::size_t>> &elnodeTags, - std::vector<std::size_t> & elems2D, const Eigen::Matrix<double, 3, 3> &H_matrix, - const double nu, const double E, std::map<int, elementData> & FEM_kinematicsMap, - std::vector<std::vector<double>> & data3, std::vector<std::vector<double>> & data4, - std::vector<std::vector<double>> & data5, std::vector<std::vector<double>> & data6, - std::vector<std::vector<double>> & data7, std::vector<std::vector<double>> & data8, - std::vector<std::vector<double>> & data9, std::vector<std::vector<double>> & data10, - int & k) -{ - // The strains and stresses are computed in local axes - // They are then converted back into global axes, using a simple rotation matrix - - std::string name; - int dim, order, numNodes, numPrimaryNodes; - std::vector<double> paramCoord2D; - int numComponents, numOrientations; - std::vector<double> basisFunctionsGradient; - - Eigen::Vector3d epsilon; // will contain local values of the strains (Voigt notation) - Eigen::Vector3d sigma; // will contain local values of the stresses (Voigt notation) - - Eigen::Matrix<double, 2, 2> jacob2D; - Eigen::Matrix<double, 2, 2> jacobinv; - Eigen::Matrix<double, 2, 2> jacobinvtrans; - - elementData* element; - double theta; - double dN_dx_local; - double dN_dy_local; - - Eigen::Matrix<double, 2, 2> strain_tensor; - Eigen::Matrix<double, 2, 2> stress_tensor; - Eigen::Matrix<double, 2, 2> rotation_tensor; - - for (std::size_t ityp = 0; ityp < elementTypes.size(); ++ityp) - { - // get info about this type of element - gmsh::model::mesh::getElementProperties(elementTypes[ityp], name, dim, order, - numNodes, paramCoord2D, numPrimaryNodes); - //paramCoord contains the coordinates of the nodes in 2D - // passage en 3D pour utiliser getJacobians - std::vector<double> paramCoord(3*paramCoord2D.size()/2); - for(std::size_t j = 0; j < paramCoord2D.size()/2; ++j){ - paramCoord[3*j] = paramCoord2D[2*j]; - paramCoord[3*j+1] = paramCoord2D[2*j+1]; - paramCoord[3*j+2] = 0.; - } - - // select element/node tags for this type of element - auto &etags = elementTags[ityp]; - - // get determinants and Jacobians (only jacob useful here) AT NODES AND NOT AT GAUSS POINTS - std::vector<double> jacobians, determinants, coords; - gmsh::model::mesh::getJacobians(elementTypes[ityp], - paramCoord, jacobians, - determinants, coords); - - // derivatives of the shape functions at the nodes of the reference element - // we are here working with derivatives in the reference space, same for all elements - gmsh::model::mesh::getBasisFunctions(elementTypes[ityp], paramCoord, - "GradLagrange", numComponents, - basisFunctionsGradient, - numOrientations); - - // loop over elements of type "ityp" - for (std::size_t i = 0; i < etags.size(); ++i) - { - element = & FEM_kinematicsMap[etags[i]]; - elems2D[k] = etags[i]; - - theta = element->theta; - rotation_tensor(0,0) = cos(theta); - rotation_tensor(0,1) = sin(theta); - rotation_tensor(1,0) = -sin(theta); - rotation_tensor(1,1) = cos(theta); - - data3[k].resize(numNodes); - data4[k].resize(numNodes); - data5[k].resize(numNodes); - data6[k].resize(numNodes); - data7[k].resize(numNodes); - data8[k].resize(numNodes); - data9[k].resize(numNodes); - data10[k].resize(numNodes); - - for (int j = 0; j < numNodes; ++j){ - // converting jacobian to Eigen format - Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > - jacob(&jacobians[9*j+9*numNodes*i], 3, 3); - // 3D to 2D (plane stress case) - jacob2D(0,0) = jacob(0,0); - jacob2D(1,0) = jacob(1,0); - jacob2D(0,1) = jacob(0,1); - jacob2D(1,1) = jacob(1,1); - - // computing the inverse - jacobinv = jacob2D.inverse(); - - // computing the transpose of the inverse - jacobinvtrans = jacobinv.transpose(); - - // computing the B matrix (formula slide 19) - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); - - computeBmatrix(j, numNodes, basisFunctionsGradient, determinants, - jacobinvtrans, H_matrix, B_matrix); - - // WARNING, the B_matrix is expressed in terms of global axes -> convert back to local axes - for(int l = 0; l < numNodes; l++) - { - dN_dx_local = cos(theta)*B_matrix(0,2*l) + sin(theta)*B_matrix(2,2*l); - dN_dy_local = -sin(theta)*B_matrix(0,2*l) + cos(theta)*B_matrix(2,2*l); - B_matrix(0,2*l) = dN_dx_local; - B_matrix(2,2*l) = dN_dy_local; - B_matrix(1,2*l+1) = dN_dy_local; - B_matrix(2,2*l+1) = dN_dx_local; - } - // expressed in local axes (and in Voigt notation) - epsilon = B_matrix*element->pl; - sigma = H_matrix*epsilon; - - // converting to tensor notation (still in local axes) - strain_tensor(0,0) = epsilon(0); - strain_tensor(1,0) = epsilon(2)/2; // divide by 2 because engineering shear strain -> pure shear strain - strain_tensor(0,1) = epsilon(2)/2; - strain_tensor(1,1) = epsilon(1); - - stress_tensor(0,0) = sigma(0); - stress_tensor(1,0) = sigma(2); - stress_tensor(0,1) = sigma(2); - stress_tensor(1,1) = sigma(1); - - //converting back to global axes - strain_tensor = rotation_tensor.transpose()*strain_tensor*rotation_tensor; - stress_tensor = rotation_tensor.transpose()*stress_tensor*rotation_tensor; - - data3[k][j] = strain_tensor(0,0); - data4[k][j] = strain_tensor(1,1); - data5[k][j] = strain_tensor(1,0); - data6[k][j] = -nu/E*(stress_tensor(0,0)+stress_tensor(1,1));// formula slide 11/20 elasticity - data7[k][j] = stress_tensor(0,0); - data8[k][j] = stress_tensor(1,1); - data9[k][j] = stress_tensor(1,0); - data10[k][j] = sqrt(stress_tensor(0,0)*stress_tensor(0,0) + stress_tensor(1,1)*stress_tensor(1,1) - stress_tensor(0,0)*stress_tensor(1,1) + 3*stress_tensor(1,0)*stress_tensor(1,0)); - } - k++; - } - } -} - -void applyElecPressure(const std::string & integration_rule, std::map<int,std::pair<double,double>> & nodeCoordsMap, std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, std::map<int, double> &electrostaticPressure, std::vector<double> & full_f_vector) -{ - std::string groupname = "BEM_FEM_boundary"; - int dim = groups[groupname].first; - int tag = groups[groupname].second; - std::vector<int> tags; - gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); + gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); int first_nodeTag; int second_nodeTag; @@ -756,14 +608,14 @@ void applyElecPressure(const std::string & integration_rule, std::map<int,std::p // get Gauss points coordinates and weights std::vector<double> localCoords, weights; gmsh::model::mesh::getIntegrationPoints(elementTypes[j], - integration_rule, //maybe use different integration method on boundary than in domain + integration_rule, localCoords, weights); // get determinants and Jacobians (only determinants will be useful) std::vector<double> jacobians, determinants, coords; gmsh::model::mesh::getJacobians(elementTypes[j], localCoords, jacobians, - determinants, coords,tags[i]); // ai dû rajouter mon tags[k] pr focus on this particular entity + determinants, coords,tags[i]); int numComponents, numOrientations; std::vector<double> basisFunctions; @@ -772,11 +624,12 @@ void applyElecPressure(const std::string & integration_rule, std::map<int,std::p basisFunctions, numOrientations); - /*-----------computing the f vector components related to this Neumann BC---------*/ - std::vector<double> f_vector(2*numNodes); - + #pragma omp parallel for private(first_nodeTag, second_nodeTag, nx, ny, norm, p, tx, ty, first_node_index, first_node) for(std::size_t k=0; k < elementTags[j].size(); ++k) { + std::vector<double> f_vector(2*numNodes); + // computing the outward normal to the element, assuming the BEM domain is traveled "aire à gauche", hence + // the FEM domain "aire à droite" first_nodeTag = elnodeTags[j][numNodes*k]; second_nodeTag = elnodeTags[j][numNodes*k+1]; nx = -(nodeCoordsMap[second_nodeTag].second - nodeCoordsMap[first_nodeTag].second); @@ -785,18 +638,18 @@ void applyElecPressure(const std::string & integration_rule, std::map<int,std::p nx = nx / norm; //normalisation ny = ny / norm; p = electrostaticPressure[elementTags[j][k]]; - tx = p*nx; + tx = p*nx; // projecting the pressure onto the outward normal ty = p*ny; for (int n = 0; n < 2*numNodes; ++n){ f_vector[n] = 0.; } - // looping over the Gauss points (formula of slide 17) + // looping over the Gauss points for (std::size_t n = 0; n < weights.size(); ++n){ // looping over the number of shape functions for (int l = 0; l < numNodes; ++l){ - f_vector[2*l] = f_vector[2*l] + basisFunctions[l+numNodes*n]*tx*determinants[n+weights.size()*k]*weights[n]; //pas oublier le dét ! - f_vector[2*l+1] = f_vector[2*l+1] + basisFunctions[l+numNodes*n]*ty*determinants[n+weights.size()*k]*weights[n]; // le weight non plus ! + f_vector[2*l] = f_vector[2*l] + basisFunctions[l+numNodes*n]*tx*determinants[n+weights.size()*k]*weights[n]; + f_vector[2*l+1] = f_vector[2*l+1] + basisFunctions[l+numNodes*n]*ty*determinants[n+weights.size()*k]*weights[n]; } } /*------------- ASSEMBLY PROCESS ------------*/ @@ -804,6 +657,7 @@ void applyElecPressure(const std::string & integration_rule, std::map<int,std::p first_node_index = (int) n/2; first_node = elnodeTags[j][numNodes*k+first_node_index]; my_row = nodeIndexMap[first_node] + n % 2; + #pragma omp atomic update full_f_vector[my_row] += f_vector[n]; } } @@ -811,95 +665,122 @@ void applyElecPressure(const std::string & integration_rule, std::map<int,std::p } } -int initKinematics(std::vector<std::size_t> & FEM_elementTags, std::map<int, elementData> & FEM_kinematicsMap, std::map<int,std::pair<double,double>> & FEM_nodeCoordsMap, int & dim, std::vector<int> & tags) +// looping over the boundary conditions imposed in the .geo file and gathered in "BCkeys" related to the +// physical groups "groups", the goal is to fill the two vectors "new_DOFindices" and "dir_BC": +// "new_DOFindices" vector will contain the new indices of the K matrix after the "number_removed_lines" rows/columns +// corresponding to dirichlet boundary conditions have been removed. A removed index will correspond to "new_DOFindices"= -1. +// dir_BC[index] will contain the dirichlet boundary condition prescribed to the node whose global index is retrieved using +// "nodeIndexMap". +void fillDOFindicesDirBC(const std::vector<std::string> & BCkeys, std::map<int, int> & nodeIndexMap, + std::map<std::string, std::pair<int, int>> & groups, + std::vector<int> & new_DOFindices, std::vector<double> & dir_BC, int & number_removed_lines) { + + for (std::size_t j = 0; j < new_DOFindices.size(); ++j){ + new_DOFindices[j] = (int) j; + } + for (std::size_t j = 0; j < dir_BC.size(); ++j){ + dir_BC[j] = 0; + } + + double ux; // imposed displacement along x axis + double uy; // imposed displacement along y axis + + int dim; + int tag; + std::vector<int> tags; std::vector<int> elementTypes; std::vector<std::vector<std::size_t>> elementTags; - std::vector<std::vector<std::size_t>> elnodeTags; - + std::vector<std::vector<std::size_t>> nodeTags; std::string elementName; int elDim, order, numNodes, numPrimaryNodes; std::vector<double> localNodeCoord; - - int nbelems=0; // will store total number of elements in FEM domain - for(std::size_t i=0; i< tags.size(); ++i) + + int first_node_index; + int first_node; + int my_row; + + for (auto &key : BCkeys) { - gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[i]); - for(std::size_t j=0; j< elementTags.size(); ++j) + // get corresponding value + std::vector<double> value; + gmsh::onelab::getNumber(key, value); + // expected key structure is "type/group_name/field" + // => split the key string into components + std::stringstream ss(key); + std::vector<std::string> words; + std::string word; + while(std::getline(ss, word, '/')) // read string until '/' + words.push_back(word); + if(words.size()==3) { - nbelems+=elementTags[j].size(); - // filling the FEM_elementTags vector - FEM_elementTags.insert(FEM_elementTags.end(), elementTags[j].begin(), elementTags[j].end()); + if(words[2].compare("ux") == 0 || words[2].compare("uy") == 0){ + ux = 0; + uy = 0; + if(words[2].compare("ux") == 0) + ux = value[0]; + if(words[2].compare("uy") == 0) + uy = value[0]; + std::string groupname = words[1]; + + //loop over elements of group_name + dim = groups[groupname].first; + tag = groups[groupname].second; + if (tag == 0) + { + std::cerr << "Group '" << groupname << "' does not exist!\n"; + return; + } + gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - // getting element properties, in particular: number of nodes - gmsh::model::mesh::getElementProperties(elementTypes[j], + for (std::size_t k = 0; k < tags.size(); ++k) + { + gmsh::model::mesh::getElements(elementTypes, elementTags, + nodeTags, dim, tags[k]); + + for (std::size_t i = 0; i < elementTypes.size(); ++i) + { + gmsh::model::mesh::getElementProperties(elementTypes[i], elementName, elDim, order, numNodes, localNodeCoord, numPrimaryNodes); - for(std::size_t k = 0; k < elementTags[j].size(); k++) - { - elementData element; - std::vector<size_t> tmp_nodes(numNodes); - std::vector<double> tmp_x(numNodes); - std::vector<double> tmp_y(numNodes); - std::vector<double> tmp_u(numNodes); - std::vector<double> tmp_v(numNodes); - std::vector<double> tmp_ui(numNodes); - std::vector<double> tmp_vi(numNodes); - double tmp_xc = 0; - double tmp_yc = 0; - for(int l = 0; l < numNodes; l++) - { - tmp_nodes[l] = elnodeTags[j][numNodes*k + l]; - tmp_x[l] = FEM_nodeCoordsMap[tmp_nodes[l]].first; - tmp_y[l] = FEM_nodeCoordsMap[tmp_nodes[l]].second; - tmp_u[l] = 0; // initializing the displacement at zero - tmp_v[l] = 0; - tmp_ui[l] = 0; - tmp_vi[l] = 0; - tmp_xc += tmp_x[l]; - tmp_yc += tmp_y[l]; - } - tmp_xc = tmp_xc / numNodes; - tmp_yc = tmp_yc / numNodes; - - std::vector<double> tmp_xi(numNodes); - std::vector<double> tmp_yi(numNodes); - for(int l = 0; l < numNodes; l++) - { - tmp_xi[l] = tmp_x[l] - tmp_xc; - tmp_yi[l] = tmp_y[l] - tmp_yc; + //looping over the elements + for (std::size_t el = 0; el < elementTags[i].size(); el++){ + for (int j = 0; j < 2*numNodes; ++j){ + first_node_index = (int) j/2; + first_node = nodeTags[i][numNodes*el+first_node_index]; + my_row = nodeIndexMap[first_node] + j % 2; // j % 2 == 1 corresponds to y nodal displacement + if(words[2].compare("uy") == 0 && j % 2){ // we are dealing with a uy type of node + dir_BC[my_row] = uy; + new_DOFindices[my_row] = -1; + } + if(words[2].compare("ux") == 0 && j % 2 == 0){ // ux type of node + dir_BC[my_row] = ux; + new_DOFindices[my_row] = -1; + } + } + } + } } - element.nodes = tmp_nodes; - element.x = tmp_x; - element.y = tmp_y; - element.xc = tmp_xc; - element.yc = tmp_yc; - element.xi = tmp_xi; - element.yi = tmp_yi; - element.u = tmp_u; - element.v = tmp_v; - element.uc = 0; - element.vc = 0; - element.theta = 0; - element.ui = tmp_ui; - element.vi = tmp_vi; - element.pl = Eigen::Matrix<double, Eigen::Dynamic, 1>::Zero(2*numNodes,1); - element.A = Eigen::Matrix<double, Eigen::Dynamic, 1>(2*numNodes,1); - element.G = Eigen::Matrix<double, 1, Eigen::Dynamic>(1,2*numNodes); - element.E = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>::Zero(2*numNodes, 2*numNodes); - - FEM_kinematicsMap[elementTags[j][k]] = element; - updateKinMatrices(& FEM_kinematicsMap[elementTags[j][k]], false); } } } - return nbelems; + for (std::size_t j = 0; j < new_DOFindices.size(); ++j){ + if(new_DOFindices[j] < 0){ // line has to be removed + number_removed_lines++; + } + else{ + new_DOFindices[j] -= number_removed_lines; + } + } } -void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, std::vector<double> & full_d_vector, std::map<int, int> & nodeIndexMap, std::vector<std::size_t> & FEM_elementTags) +// updating the kinematics of the "FEM_elementTags" contained in the "FEM_kinematicsMap", +// based on the "full_d_vector" gathering the nodal displacements associated to the global +// node indices contained in "nodeIndexMap". +void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, const std::vector<double> & full_d_vector, + std::map<int, int> & nodeIndexMap, const std::vector<std::size_t> & FEM_elementTags) { - elementData* element; size_t numNodes; size_t tmp_nodeTag; int node_index; @@ -909,9 +790,10 @@ void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, std::vecto double angle2; double norm1; double norm2; + #pragma omp parallel for private(numNodes, tmp_nodeTag, node_index, numerator, denominator, angle1, angle2, norm1, norm2) for(std::size_t i=0; i< FEM_elementTags.size(); ++i) { - element = & FEM_kinematicsMap[FEM_elementTags[i]]; + elementData* element = & FEM_kinematicsMap[FEM_elementTags[i]]; numNodes = element->nodes.size(); element->uc = 0; element->vc = 0; @@ -929,7 +811,7 @@ void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, std::vecto element->vc = element->vc / numNodes; numerator = 0; - denominator =0; + denominator = 0; for(size_t l = 0; l < numNodes; l++) { numerator += element->xi[l]*(element->yi[l]+element->v[l]-element->vc); @@ -947,7 +829,7 @@ void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, std::vecto { angle2 = angle1 - PI; } - // filling ui and vi while finding the angle minimizing equation (4) in the paper (what i call the norm) + // filling ui and vi while finding the angle minimizing equation (70) in the report (VERIFIER EQUATION) std::vector<double> tmp_ui1(numNodes); std::vector<double> tmp_ui2(numNodes); std::vector<double> tmp_vi1(numNodes); @@ -984,264 +866,670 @@ void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, std::vecto } } -void updateKinMatrices(elementData* element, bool computeFl) +// retrieving the global nodal forces based on local nodal forces of the +// "FEM_elementTags" contained in the "FEM_kinematicsMap", +// each node Tag corresponds to a global index given by "nodeIndexMap". +void retrieveTotalNodalForces(std::vector<double> & final_nodal_forces, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int, int> & nodeIndexMap, const std::vector<std::size_t> & FEM_elementTags) { - size_t numNodes = element->nodes.size(); - // update A matrix - for(size_t i = 0; i < numNodes; i++) + for(size_t i = 0; i < final_nodal_forces.size(); i++) { - element->A(2*i, 0) = -(element->vi[i]+element->yi[i]); - element->A(2*i + 1, 0) = element->ui[i]+element->xi[i]; + final_nodal_forces[i] = 0; } - // update G matrix - double denominator = 0; - for(size_t i = 0; i < numNodes; i++) + #pragma omp parallel for + for(size_t i = 0; i < FEM_elementTags.size(); i++) { - element->G(0, 2*i) = -element->yi[i]; - element->G(0, 2*i + 1) = element->xi[i]; - denominator += element->xi[i]*(element->ui[i]+element->xi[i]) + element->yi[i]*(element->vi[i]+element->yi[i]); + elementData* element = & FEM_kinematicsMap[FEM_elementTags[i]]; + int numNodes = (int) element->nodes.size(); + Eigen::Matrix<double, Eigen::Dynamic, 1> fg = element->C.transpose()*element->fl; + for(int j = 0; j < numNodes; j++) + { + int nodeTag = element->nodes[j]; + #pragma omp atomic update + final_nodal_forces[nodeIndexMap[nodeTag]] += fg(2*j); + #pragma omp atomic update + final_nodal_forces[nodeIndexMap[nodeTag] + 1] += fg(2*j + 1); + } } - element->G *= 1 / denominator; +} - // update P matrix - element->P = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>::Identity(2*numNodes,2*numNodes) - element->A*element->G; +// assembles the "global_f_vector" based on the local nodal forces vector of the +// "FEM_elementTags" contained in the "FEM_kinematicsMap", +// without taking into account the DOFs fixed by a dirichlet boundary condition, +// the nodes are renumbered using "new_DOFindices". +// each node Tag corresponds to a global index given by "nodeIndexMap". +void assembleGlobalF(std::vector<double> & global_f_vector, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int, int> & nodeIndexMap, const std::vector<int> & new_DOFindices, + const std::vector<std::size_t> & FEM_elementTags) +{ + #pragma omp parallel for + for(size_t i = 0; i < FEM_elementTags.size(); i++) + { + elementData* element = & FEM_kinematicsMap[FEM_elementTags[i]]; + int numNodes = (int) element->nodes.size(); + Eigen::Matrix<double, Eigen::Dynamic, 1> fg = element->C.transpose()*element->fl; + for(int j = 0; j < numNodes; j++) + { + int nodeTag = element->nodes[j]; + int index1 = new_DOFindices[nodeIndexMap[nodeTag]]; // current index related to x DOF of the node (= -1 if dirichlet BC) + int index2 = new_DOFindices[nodeIndexMap[nodeTag] + 1]; // current index related to y DOF of the node (= -1 if dirichlet BC) + if(index1 >= 0) // need to assemble in global f vector + { + #pragma omp atomic update + global_f_vector[index1] += fg(2*j); + } + if(index2 >= 0) + { + #pragma omp atomic update + global_f_vector[index2] += fg(2*j + 1); + } + } + } +} - // update E matrix - double tmp_cos = cos(element->theta); - double tmp_sin = sin(element->theta); - for(size_t i = 0; i < numNodes; i++) +// assembling the global tangent stiffness matrix based on the local elemental stiffness matrices contained +// in the "FEM_kinematicsMap" associated to each "FEM_elementTags". +// "new_DOFindices" maps the global initial node index (from "nodeIndexMap") to the index +// obtained without considering the fixed DOFs. +void assembleGlobalKg(Eigen::SparseMatrix<double> & global_tangent_matrix, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int, int> & nodeIndexMap, const std::vector<int> & new_DOFindices, + const std::vector<std::size_t> & FEM_elementTags) +{ + // to allow efficient parallelization, one triplet list is created for every thread, then the different lists are assembled + // to further increase efficiency, space is reserved for each list + int estimated_number_of_entries = (int) new_DOFindices.size()/2 *8*8; // accurate in the case of Q4 elements, otherwise it provides a good estimation + std::vector<Eigen::Triplet <double>> Kg_tripletList; + Kg_tripletList.reserve(estimated_number_of_entries); + + int max_threads = omp_get_max_threads(); + int estimated_number_of_entries_per_thread = (int) estimated_number_of_entries / max_threads; + std::vector<std::vector<Eigen::Triplet <double>>> thread_Kg_list(max_threads); + for(int i = 0; i < max_threads; i++) { - element->E(2*i, 2*i) = tmp_cos; - element->E(2*i, 2*i + 1) = -tmp_sin; - element->E(2*i + 1, 2*i) = tmp_sin; - element->E(2*i + 1, 2*i + 1) = tmp_cos; + thread_Kg_list[i].reserve(estimated_number_of_entries_per_thread); } - //update B matrix - element->B = element->P*element->E.transpose(); + std::vector<Eigen::Triplet <double>>* my_Kg_list; - //update fl vector, only if Kl has been initialized - if(computeFl) + #pragma omp parallel for private(my_Kg_list) + for(size_t i = 0; i < FEM_elementTags.size(); i++) { - element->fl = element->Kl*element->pl; + elementData* element = & FEM_kinematicsMap[FEM_elementTags[i]]; + int numNodes = (int) element->nodes.size(); + Eigen::Matrix<double, Eigen::Dynamic, 1> tmp_F = element->P.transpose()*element->fl; + + Eigen::Matrix<double, 1, Eigen::Dynamic> F(1,2*numNodes); + for(int j = 0; j < numNodes; j++) + { + F(0,2*j) = tmp_F(2*j+1, 0); + F(0,2*j+1) = -tmp_F(2*j, 0); + } + + // see report for the formula + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Kh = element->E*(-F.transpose()*element->G - element->G.transpose()*F*element->P)*element->E.transpose(); + + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Kg = element->C.transpose()*element->Kl*element->C + Kh; + + int threadNum = omp_get_thread_num(); + my_Kg_list = & thread_Kg_list[threadNum]; + + // assemble Kg into tripletlist + for (int j = 0; j < 2*numNodes; ++j) + { + int first_node_index = (int) j/2; + int first_node = element->nodes[first_node_index]; + int my_row = new_DOFindices[nodeIndexMap[first_node] + j % 2]; + if(my_row >= 0) // else, the DOF corresponds to a Dirichlet BC + { + for(int l = 0; l <= j; ++l) + { // to exploit symmetry + int second_node_index = (int) l/2; + int second_node = element->nodes[second_node_index]; + int my_col = new_DOFindices[nodeIndexMap[second_node] + l % 2]; + + if(my_col >= 0) // else, the DOF corresponds to a Dirichlet BC + { + (*my_Kg_list).push_back(Eigen::Triplet<double>(my_row,my_col,Kg(j,l))); + if(j != l) + { + (*my_Kg_list).push_back(Eigen::Triplet<double>(my_col,my_row,Kg(j,l))); + } + } + } + } + } } + // gathering the different lists in one single list + Kg_tripletList = thread_Kg_list[0]; + if(max_threads > 1) + { + for (int i = 1; i < max_threads; i++) + { + Kg_tripletList.insert(Kg_tripletList.end(), thread_Kg_list[i].begin(), thread_Kg_list[i].end()); + } + } + global_tangent_matrix.setFromTriplets(Kg_tripletList.begin(), Kg_tripletList.end()); } -void assembleGlobalF(std::vector<double> & global_f_vector, std::map<int, elementData> & FEM_kinematicsMap, std::map<int, int> & nodeIndexMap, std::vector<int> & new_DOFindices, std::vector<std::size_t> & FEM_elementTags) +// updating the "full_d_vector" based on the "global_p_vector", using the global and reduced index mapping: +// "new_DOFindices". +void updateNodalDispVector(std::vector<double> & full_d_vector, const std::vector<double> & global_p_vector, + const std::vector<int> & new_DOFindices) { - elementData* element; - Eigen::Matrix<double, Eigen::Dynamic, 1> fg; - int numNodes; - int index1; - int index2; + for(size_t i = 0; i < full_d_vector.size(); i++) + { + if(new_DOFindices[i] >= 0) + { + full_d_vector[i] = global_p_vector[new_DOFindices[i]]; + } + } +} + +// retrieving the nodal displacements on the BEM_FEM_boundary in order to communicate them to the +// BEM solver in the two-way coupled solver. Using the "groups" to find the physical group associated +// to the boundary, all nodes of the boundary are associated through the "boundaryDisplacementMap" their +// nodal displacement (u,v) retrieved from "full_d_vector" using the indexation of "nodeIndexMap". +void retrieveBoundaryDisplacements(std::map<int,std::pair<double,double>> & boundaryDisplacementMap, + const std::vector<double> & full_d_vector, std::map<int, int> & nodeIndexMap, + std::map<std::string, std::pair<int, int>> & groups) +{ + std::string groupname = "BEM_FEM_boundary"; + int dim = groups[groupname].first; + int tag = groups[groupname].second; + std::vector<int> tags; + gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); + std::vector<int> elementTypes; + std::vector<std::vector<std::size_t>> elementTags; + std::vector<std::vector<std::size_t>> elnodeTags; + int nodeTag; - for(size_t i = 0; i < FEM_elementTags.size(); i++) + double u; + double v; + + std::string elementName; + int elDim, order, numNodes, numPrimaryNodes; + std::vector<double> localNodeCoord; + + for(std::size_t i=0; i< tags.size(); ++i) { - element = & FEM_kinematicsMap[FEM_elementTags[i]]; - numNodes = (int) element->nodes.size(); - fg = element->B.transpose()*element->fl; - for(int j = 0; j < numNodes; j++) + gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[i]); + for(std::size_t j=0; j< elementTypes.size(); ++j) { - nodeTag = element->nodes[j]; - index1 = new_DOFindices[nodeIndexMap[nodeTag]]; // current index related to x DOF of the node (= -1 if dirichlet BC) - index2 = new_DOFindices[nodeIndexMap[nodeTag] + 1]; // current index related to y DOF of the node (= -1 if dirichlet BC) - if(index1 >= 0) // need to assemble in global f vector + + // getting element properties + gmsh::model::mesh::getElementProperties(elementTypes[j], + elementName, elDim, order, + numNodes, localNodeCoord, + numPrimaryNodes); + + for(std::size_t k=0; k < elementTags[j].size(); ++k) { - global_f_vector[index1] += fg(2*j); + for(int l = 0; l < numNodes; l++) + { + nodeTag = elnodeTags[j][numNodes*k + l]; + u = full_d_vector[nodeIndexMap[nodeTag]]; + v = full_d_vector[nodeIndexMap[nodeTag] + 1]; + boundaryDisplacementMap[nodeTag] = std::pair<double, double>(u, v); + } } - if(index2 >= 0) + } + } +} + +// computing the reaction forces on all the physical groups "groups" for which a dirichlet boundary +// condition has been prescribed (using the "BCkeys" to retrieve the groups from the .geo file), +// based on the "final_nodal_forces" and the "nodeIndexMap" to retrieve the global index associated +// to one given node tag. +void computeReactionForces(std::map<std::string, std::pair<int, int>> & groups, + std::map<int, int> & nodeIndexMap, const std::vector<double> & final_nodal_forces, + const std::vector<std::string> & BCkeys) +{ + double Rx; + double Ry; + + int dim; + int tag; + std::vector<int> tags; + + std::vector<std::size_t> nodeTags; + std::vector<double> coord; //useless but mandatory + std::vector<double> parametricCoord; //useless but mandatory + + for (auto &key : BCkeys) + { + // get corresponding value + std::vector<double> value; + gmsh::onelab::getNumber(key, value); + // expected key structure is "type/group_name/field" + // => split the key string into components + std::stringstream ss(key); + std::vector<std::string> words; + std::string word; + while(std::getline(ss, word, '/')) // read string until '/' + words.push_back(word); + if(words.size()==3) + { + if(words[2].compare("ux") == 0 || words[2].compare("uy") == 0){ + Rx = 0; + Ry = 0; + std::string groupname = words[1]; + std::cout << "-------------------- " << groupname << " ------------------- \n"; + + //loop over elements of group_name + dim = groups[groupname].first; + tag = groups[groupname].second; + if (tag == 0) + { + std::cerr << "Group '" << groupname << "' does not exist!\n"; + return; + } + gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); + + // loop over entities + for (std::size_t k = 0; k < tags.size(); ++k) + { + // retrieving all the nodes in this particular entity + gmsh::model::mesh::getNodes(nodeTags, coord, parametricCoord, dim, tags[k], true); + + + for (std::size_t j = 0; j < nodeTags.size(); ++j){ + if(words[2].compare("ux") == 0){ // computing Rx + int my_new_col = nodeIndexMap[nodeTags[j]]; //nodeIndexMap[nodeTags[j]] corresponds to line/column index in K, f + Rx += final_nodal_forces[my_new_col]; + } + if(words[2].compare("uy") == 0){ // computing Ry + int my_new_col = nodeIndexMap[nodeTags[j]] + 1; + Ry += final_nodal_forces[my_new_col]; + } + } + } + std::cout << "Rx: " << Rx << " [N/m], Ry: " << Ry << " [N/m] \n"; + } + } + } +} + +// plotting the nodal displacement values associated to "FEM_nodeTags" in the "names[0]" model, +// based on the "full_d_vector". +void plotUxUy(const std::vector<std::size_t> & FEM_nodeTags, const std::vector<double> & full_d_vector, + const std::vector<std::string> & names) +{ + int viewtagUx = gmsh::view::add("ux"); + int viewtagUy = gmsh::view::add("uy"); + std::vector<std::vector<double>> dataUx(FEM_nodeTags.size()); + std::vector<std::vector<double>> dataUy(FEM_nodeTags.size()); + for (std::size_t i = 0; i < FEM_nodeTags.size(); ++i) + { + dataUx[i].resize(1); + dataUx[i][0] = full_d_vector[2*i]; //ux // à modifier ici + dataUy[i].resize(1); + dataUy[i][0] = full_d_vector[2*i+1]; //uy + } + + gmsh::view::addModelData(viewtagUx, 0, names[0], "NodeData", + FEM_nodeTags, dataUx); //independent of time here + gmsh::view::addModelData(viewtagUy, 0, names[0], "NodeData", + FEM_nodeTags, dataUy); //independent of time here +} + +// computing the elemental-nodal strains and stresses in the FEM domain (dimension "dim" and entity tags "tags"), +// based on Hooke's matrix in plane stress "H_matrix", Young's modulus "E", Poisson's ratio "nu", looping over the +// "nbelems" elements contained in "FEM_kinematicsMap". +// returning the "max_VM_stress" and the corresponding nodetag "max_VM_nodeTag". +void computeStressStrainElNodal(const int & dim, const std::vector<int> & tags, const Eigen::Matrix<double, 3, 3> &H_matrix, + const double nu, const double E, std::map<int, elementData> & FEM_kinematicsMap, + const int & nbelems, double & max_VM_stress, int & max_VM_nodeTag) +{ + std::vector<std::string> names; + gmsh::model::list(names); + + int viewTagEpsX = gmsh::view::add("nodal_eps_x"); + int viewTagEpsY = gmsh::view::add("nodal_eps_y"); + int viewTagEpsXY = gmsh::view::add("nodal_2eps_xy"); + int viewTagEpsZ = gmsh::view::add("nodal_eps_z"); + int viewTagSigX = gmsh::view::add("nodal_sig_x"); + int viewTagSigY = gmsh::view::add("nodal_sig_y"); + int viewTagSigXY = gmsh::view::add("nodal_sig_xy"); + int viewTagSigVM = gmsh::view::add("nodal_sig_VM"); + + std::vector<std::vector<std::vector<double>>> dataEps(4); + dataEps[0].resize(nbelems); // eps X + dataEps[1].resize(nbelems); // eps Y + dataEps[2].resize(nbelems); // eps XY + dataEps[3].resize(nbelems); // eps Z + + std::vector<std::vector<std::vector<double>>> dataSig(4); + dataSig[0].resize(nbelems); // Sig X + dataSig[1].resize(nbelems); // Sig Y + dataSig[2].resize(nbelems); // Sig XY + dataSig[3].resize(nbelems); // Sig VM + std::vector<std::size_t> elems2D(nbelems); + + int data_index = 0; + + std::vector<int> elementTypes; + std::vector<std::vector<std::size_t>> elementTags; + std::vector<std::vector<std::size_t>> elnodeTags; + for(std::size_t entityTag = 0; entityTag < tags.size(); ++entityTag) + { + gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[entityTag]); + + std::string name; + int dim, order, numNodes, numPrimaryNodes; + std::vector<double> paramCoord2D; + int numComponents, numOrientations; + std::vector<double> basisFunctionsGradient; + + Eigen::Vector3d epsilon; // will contain local values of the strains (Voigt notation) + Eigen::Vector3d sigma; // will contain local values of the stresses (Voigt notation) + + Eigen::Matrix<double, 2, 2> jacob2D; + Eigen::Matrix<double, 2, 2> jacobinv; + Eigen::Matrix<double, 2, 2> jacobinvtrans; + + elementData* element; + double theta; + + Eigen::Matrix<double, 2, 2> strain_tensor; + Eigen::Matrix<double, 2, 2> stress_tensor; + Eigen::Matrix<double, 2, 2> rotation_tensor; + + for (std::size_t ityp = 0; ityp < elementTypes.size(); ++ityp) + { + // get info about this type of element + gmsh::model::mesh::getElementProperties(elementTypes[ityp], name, dim, order, + numNodes, paramCoord2D, numPrimaryNodes); + //paramCoord contains the coordinates of the nodes in 2D + // passage en 3D pour utiliser getJacobians + std::vector<double> paramCoord(3*paramCoord2D.size()/2); + for(std::size_t j = 0; j < paramCoord2D.size()/2; ++j){ + paramCoord[3*j] = paramCoord2D[2*j]; + paramCoord[3*j+1] = paramCoord2D[2*j+1]; + paramCoord[3*j+2] = 0.; + } + + // select element/node tags for this type of element + auto &etags = elementTags[ityp]; + + // get determinants and Jacobians (only jacob useful here) AT NODES AND NOT AT GAUSS POINTS + std::vector<double> jacobians, determinants, coords; + gmsh::model::mesh::getJacobians(elementTypes[ityp], + paramCoord, jacobians, + determinants, coords, tags[entityTag]); + + // derivatives of the shape functions at the nodes of the reference element + // we are here working with derivatives in the reference space, same for all elements + gmsh::model::mesh::getBasisFunctions(elementTypes[ityp], paramCoord, + "GradLagrange", numComponents, + basisFunctionsGradient, + numOrientations); + + // loop over elements of type "ityp" + for (std::size_t i = 0; i < etags.size(); ++i) { - global_f_vector[index2] += fg(2*j + 1); + element = & FEM_kinematicsMap[etags[i]]; + elems2D[data_index] = etags[i]; + + theta = element->theta; + rotation_tensor(0,0) = cos(theta); + rotation_tensor(0,1) = sin(theta); + rotation_tensor(1,0) = -sin(theta); + rotation_tensor(1,1) = cos(theta); + + dataEps[0][data_index].resize(numNodes); + dataEps[1][data_index].resize(numNodes); + dataEps[2][data_index].resize(numNodes); + dataEps[3][data_index].resize(numNodes); + dataSig[0][data_index].resize(numNodes); + dataSig[1][data_index].resize(numNodes); + dataSig[2][data_index].resize(numNodes); + dataSig[3][data_index].resize(numNodes); + + for (int j = 0; j < numNodes; ++j){ + // converting jacobian to Eigen format + Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > + jacob(&jacobians[9*j+9*numNodes*i], 3, 3); + // 3D to 2D (plane stress case) + jacob2D(0,0) = jacob(0,0); + jacob2D(1,0) = jacob(1,0); + jacob2D(0,1) = jacob(0,1); + jacob2D(1,1) = jacob(1,1); + + // computing the inverse + jacobinv = jacob2D.inverse(); + + // computing the transpose of the inverse + jacobinvtrans = jacobinv.transpose(); + + // computing the B matrix (formula slide 19) + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); + + computeBmatrix(j, numNodes, basisFunctionsGradient, determinants, jacobinvtrans, B_matrix); + + // expressed in local axes (and in Voigt notation) + epsilon = B_matrix*element->pl; + sigma = H_matrix*epsilon; + + // converting to tensor notation (still in local axes) + strain_tensor(0,0) = epsilon(0); + strain_tensor(1,0) = epsilon(2)/2; // divide by 2 because engineering shear strain -> pure shear strain + strain_tensor(0,1) = epsilon(2)/2; + strain_tensor(1,1) = epsilon(1); + + stress_tensor(0,0) = sigma(0); + stress_tensor(1,0) = sigma(2); + stress_tensor(0,1) = sigma(2); + stress_tensor(1,1) = sigma(1); + + strain_tensor = rotation_tensor.transpose()*strain_tensor*rotation_tensor; + stress_tensor = rotation_tensor.transpose()*stress_tensor*rotation_tensor; + + dataEps[0][data_index][j] = strain_tensor(0,0); + dataEps[1][data_index][j] = strain_tensor(1,1); + dataEps[2][data_index][j] = strain_tensor(1,0); + dataEps[3][data_index][j] = -nu/E*(stress_tensor(0,0)+stress_tensor(1,1));// from plane stress hypothesis + dataSig[0][data_index][j] = stress_tensor(0,0); + dataSig[1][data_index][j] = stress_tensor(1,1); + dataSig[2][data_index][j] = stress_tensor(1,0); + // VM stress in plane stress + dataSig[3][data_index][j] = sqrt(stress_tensor(0,0)*stress_tensor(0,0) + stress_tensor(1,1)*stress_tensor(1,1) - stress_tensor(0,0)*stress_tensor(1,1) + 3*stress_tensor(1,0)*stress_tensor(1,0)); + + //retrieving maximal nodal von mises stress + if(dataSig[3][data_index][j] > max_VM_stress) + { + max_VM_stress = dataSig[3][data_index][j]; + max_VM_nodeTag = (int) elnodeTags[ityp][numNodes*i+j]; + } + } + data_index++; } } } + + gmsh::view::addModelData(viewTagEpsX, 0, names[0], "ElementNodeData", + elems2D, dataEps[0], 1); + gmsh::view::addModelData(viewTagEpsY, 0, names[0], "ElementNodeData", + elems2D, dataEps[1], 1); + gmsh::view::addModelData(viewTagEpsXY, 0, names[0], "ElementNodeData", + elems2D, dataEps[2], 1); + gmsh::view::addModelData(viewTagEpsZ, 0, names[0], "ElementNodeData", + elems2D, dataEps[3], 1); + gmsh::view::addModelData(viewTagSigX, 0, names[0], "ElementNodeData", + elems2D, dataSig[0], 1); + gmsh::view::addModelData(viewTagSigY, 0, names[0], "ElementNodeData", + elems2D, dataSig[1], 1); + gmsh::view::addModelData(viewTagSigXY, 0, names[0], "ElementNodeData", + elems2D, dataSig[2], 1); + gmsh::view::addModelData(viewTagSigVM, 0, names[0], "ElementNodeData", + elems2D, dataSig[3], 1); } -double computeResidualNorm(std::vector<double> & global_f_vector, std::vector<double> & f_app_vector, Eigen::Matrix<double, Eigen::Dynamic, 1> & residual) +// computing the work done by external forces, as the nodal forces are energy consistent, it +// is sufficient to compute the "externalWork" as the dot product of the nodal displacements +// "full_d_vector" and the nodal forces "final_nodal_forces". +void computeWorkDoneByExternalForces(double &externalWork, const std::vector<double> & full_d_vector, + const std::vector<double> & final_nodal_forces) { - // norm computed as a geometrical norm (one could also use an other norm) - double res = 0; - for(size_t i = 0; i < global_f_vector.size(); i++) + for(size_t i = 0; i < full_d_vector.size(); i++) { - residual(i,0) = global_f_vector[i] - f_app_vector[i]; - res += residual(i,0)*residual(i,0); + externalWork += full_d_vector[i]*final_nodal_forces[i]; } - res = res / f_app_vector.size(); - res = sqrt(res); - return res; } -void assembleGlobalKg(Eigen::SparseMatrix<double> & global_tangent_matrix, std::map<int, elementData> & FEM_kinematicsMap, std::map<int, int> & nodeIndexMap, std::vector<int> & new_DOFindices, std::vector<std::size_t> & FEM_elementTags) +// computing the total (internal) strain energy "strain_energy" in the whole FEM domain (dimension "dim" and +// entity tags "tags"), using the elementData stored in "FEM_kinematicsMap" gathering the informations for all +// FEM elements. The Hooke's matrix in plane stress "H_matrix" is used to compute the stresses from the strains. +// Computed as a sum of integrals over the finite elements, using Gauss integration "integration_rule". +void computeStrainEnergy(double & strainEnergy, const int & dim, const std::vector<int> & tags, + std::map<int, elementData> & FEM_kinematicsMap, const Eigen::Matrix<double, 3, 3> &H_matrix, + const std::string & integration_rule) { - std::list<Eigen::Triplet <double>> Kg_tripletList; + std::vector<int> elementTypes; + std::vector<std::vector<std::size_t>> elementTags; + std::vector<std::vector<std::size_t>> nodeTags; + std::string elementName; + int elDim, order, numNodes, numPrimaryNodes; + std::vector<double> localNodeCoord; + std::vector<double> localCoords, weights; + int numComponents, numOrientations; + std::vector<double> basisFunctions; + std::vector<double> basisFunctionsGradient; + + for (std::size_t k = 0; k < tags.size(); ++k) + { + gmsh::model::mesh::getElements(elementTypes, elementTags, + nodeTags, dim, tags[k]); + + // looping over element types + for (std::size_t i = 0; i < elementTypes.size(); ++i) + { + // getting element properties + gmsh::model::mesh::getElementProperties(elementTypes[i], + elementName, elDim, order, + numNodes, localNodeCoord, + numPrimaryNodes); + + // get Gauss points coordinates and weights + gmsh::model::mesh::getIntegrationPoints(elementTypes[i], + integration_rule, + localCoords, weights); + + // get determinants and Jacobians + std::vector<double> jacobians, determinants, coords; + gmsh::model::mesh::getJacobians(elementTypes[i], + localCoords, jacobians, + determinants, coords, tags[k]); - elementData* element; - Eigen::Matrix<double, Eigen::Dynamic, 1> fg; - int numNodes; - Eigen::Matrix<double, Eigen::Dynamic, 1> tmp_F; - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Kh; - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Kg; + // values and derivatives of the shape functions at the Gauss points of the reference element + // we are here working with derivatives in the reference space, same for all elements + gmsh::model::mesh::getBasisFunctions(elementTypes[i], localCoords, + "Lagrange", numComponents, + basisFunctions, + numOrientations); + + gmsh::model::mesh::getBasisFunctions(elementTypes[i], localCoords, + "GradLagrange", numComponents, + basisFunctionsGradient, + numOrientations); + + #pragma omp parallel for + for (std::size_t el = 0; el < elementTags[i].size(); el++){ + + Eigen::Matrix<double, Eigen::Dynamic, 1> local_nodal_displacement = FEM_kinematicsMap[elementTags[i][el]].pl; + + double elementalStrainEnergy = 0; + + // looping over the Gauss points: Gauss integration + for (std::size_t gaussIndex = 0; gaussIndex < weights.size(); ++gaussIndex){ + // converting jacobian to Eigen format + Eigen::Matrix<double, 2, 2> jacob2D; + Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > + jacob(&jacobians[9*gaussIndex+9*weights.size()*el], 3, 3); + // 3D to 2D (plane stress case) + jacob2D(0,0) = jacob(0,0); + jacob2D(1,0) = jacob(1,0); + jacob2D(0,1) = jacob(0,1); + jacob2D(1,1) = jacob(1,1); + + // computing the inverse + Eigen::Matrix<double, 2, 2> jacobinv = jacob2D.inverse(); - int first_node_index; - int first_node; - int my_row; - int second_node_index; - int second_node; - int my_col; - for(size_t i = 0; i < FEM_elementTags.size(); i++) - { - element = & FEM_kinematicsMap[FEM_elementTags[i]]; - numNodes = (int) element->nodes.size(); - tmp_F = element->P.transpose()*element->fl; + // computing the transpose of the inverse + Eigen::Matrix<double, 2, 2> jacobinvtrans = jacobinv.transpose(); - Eigen::Matrix<double, 1, Eigen::Dynamic> F(1,2*numNodes); - for(int j = 0; j < numNodes; j++) - { - F(0,2*j) = tmp_F(2*j+1, 0); - F(0,2*j+1) = -tmp_F(2*j, 0); - } - - Kh = element->E*(-F.transpose()*element->G - element->G.transpose()*F*element->P)*element->E.transpose(); + // computing the B matrix + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); - Kg = element->B.transpose()*element->Kl*element->B + Kh; + computeBmatrix(gaussIndex, numNodes, basisFunctionsGradient, determinants, jacobinvtrans, B_matrix); - // assemble Kg into tripletlist - for (int j = 0; j < 2*numNodes; ++j) - { - first_node_index = (int) j/2; - first_node = element->nodes[first_node_index]; - my_row = new_DOFindices[nodeIndexMap[first_node] + j % 2]; - if(my_row >= 0) // else, the DOF corresponds to a Dirichlet BC - { - for(int l = 0; l <= j; ++l) - { // to exploit symmetry - second_node_index = (int) l/2; - second_node = element->nodes[second_node_index]; - my_col = new_DOFindices[nodeIndexMap[second_node] + l % 2]; + Eigen::Vector3d epsilon = B_matrix*local_nodal_displacement; + Eigen::Vector3d sigma = H_matrix*epsilon; - if(my_col >= 0) // else, the DOF corresponds to a Dirichlet BC + double dot_product = 0; + for(int z = 0; z < 3; z++) { - Kg_tripletList.push_back(Eigen::Triplet<double>(my_row,my_col,Kg(j,l))); - if(j != l) - { - Kg_tripletList.push_back(Eigen::Triplet<double>(my_col,my_row,Kg(j,l))); - } + dot_product += epsilon(z)*sigma(z); } + + elementalStrainEnergy += 0.5*dot_product*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; } + /*------------- ASSEMBLY PROCESS ------------*/ + #pragma omp atomic update + strainEnergy += elementalStrainEnergy; } } } - global_tangent_matrix.setFromTriplets(Kg_tripletList.begin(), Kg_tripletList.end()); -} -void updateNodalDispVector(std::vector<double> & full_d_vector, std::vector<double> & global_p_vector, std::vector<int> & new_DOFindices) -{ - for(size_t i = 0; i < full_d_vector.size(); i++) - { - if(new_DOFindices[i] >= 0) - { - full_d_vector[i] = global_p_vector[new_DOFindices[i]]; - } - } } -void retrieveFinalNodalForces(std::vector<double> & final_nodal_forces, std::map<int, elementData> & FEM_kinematicsMap, std::map<int, int> & nodeIndexMap, std::vector<std::size_t> & FEM_elementTags) +//displays the time of the desired code section "function_name", if "display_time" is set as true. +void displayTime(const double &start, const double &end, const std::string &function_name, const bool &display_time) { - elementData* element; - Eigen::Matrix<double, Eigen::Dynamic, 1> fg; - int numNodes; - int nodeTag; - for(size_t i = 0; i < FEM_elementTags.size(); i++) + if(display_time) { - element = & FEM_kinematicsMap[FEM_elementTags[i]]; - numNodes = (int) element->nodes.size(); - fg = element->B.transpose()*element->fl; - for(int j = 0; j < numNodes; j++) - { - nodeTag = element->nodes[j]; - final_nodal_forces[nodeIndexMap[nodeTag]] += fg(2*j); - final_nodal_forces[nodeIndexMap[nodeTag] + 1] += fg(2*j + 1); - } - } -} - -void retrieveBoundaryDisplacements(std::map<int,std::pair<double,double>> & boundaryDisplacementMap, const std::vector<double> & full_d_vector, std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups) -{ - std::string groupname = "BEM_FEM_boundary"; - int dim = groups[groupname].first; - int tag = groups[groupname].second; - std::vector<int> tags; - gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - std::vector<int> elementTypes; - std::vector<std::vector<std::size_t>> elementTags; - std::vector<std::vector<std::size_t>> elnodeTags; - - int nodeTag; - double u; - double v; - - std::string elementName; - int elDim, order, numNodes, numPrimaryNodes; - std::vector<double> localNodeCoord; + std::cout << std::endl; + std::cout << function_name << std::endl; + std::cout << "Elapsed time in nanoseconds: " + << end - start << " ns" << std::endl; - for(std::size_t i=0; i< tags.size(); ++i) - { - gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[i]); - for(std::size_t j=0; j< elementTypes.size(); ++j) - { + std::cout << "Elapsed time in microseconds: " + << end - start << " µs" << std::endl; - // getting element properties - gmsh::model::mesh::getElementProperties(elementTypes[j], - elementName, elDim, order, - numNodes, localNodeCoord, - numPrimaryNodes); + std::cout << "Elapsed time in milliseconds: " + << end - start << " ms" << std::endl; - for(std::size_t k=0; k < elementTags[j].size(); ++k) - { - for(int l = 0; l < numNodes; l++) - { - nodeTag = elnodeTags[j][numNodes*k + l]; - u = full_d_vector[nodeIndexMap[nodeTag]]; - v = full_d_vector[nodeIndexMap[nodeTag] + 1]; - boundaryDisplacementMap[nodeTag] = std::pair<double, double>(u, v); - } - } - } + std::cout << "Elapsed time in seconds: " + << end - start << " sec"; + std::cout << std::endl; + std::cout << std::endl; } } /*-------------- FUNCTIONS SPECIFIC TO LINEAR FEM ------------------*/ -void assembleKtriplet(const int i, const int el, - const std::vector<std::vector<std::size_t>> & nodeTags, - const int numNodes, std::map<int, int> & nodeIndexMap, - std::list<Eigen::Triplet <double>> & k_tripletList, - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & K_matrix, - std::vector<double> & f_vector) +// assembling the full stiffness matrix "full_K_matrix" using first a triplet vector, assembling the volumic part +// of the nodal forces "full_f_vector", in the FEM_domain (dimension "dim" and entity tag "tags") using the global +// node indexation defined by "nodeIndexMap". "H_matrix" is the plane stress Hooke's matrix, "rho" the density of the +// material, "bx" the volumic force along x, "by" the volumic force along y. +void assembleKVolumicF(const Eigen::Matrix<double, 3, 3> & H_matrix, const double & rho, const double & bx, const double & by, + const int & dim, const std::vector<int> & tags, std::map<int, int> & nodeIndexMap, + Eigen::SparseMatrix<double> & full_K_matrix, std::vector<double> & full_f_vector) { - for (int j = 0; j < 2*numNodes; ++j){ - int first_node_index = (int) j/2; - int first_node = nodeTags[i][numNodes*el+first_node_index]; - int my_row = nodeIndexMap[first_node] + j % 2; // node list begins at 1, '-1' correction to begin at 0 - for(int l = 0; l <= j; ++l){ // to exploit symmetry - int second_node_index = (int) l/2; - int second_node = nodeTags[i][numNodes*el+second_node_index]; - int my_col = nodeIndexMap[second_node] + l % 2; - - k_tripletList.push_back(Eigen::Triplet<double>(my_row,my_col,K_matrix(j,l))); - if(j != l){ - k_tripletList.push_back(Eigen::Triplet<double>(my_col,my_row,K_matrix(j,l))); - } - } + // to allow efficient parallelization, one triplet list (as a vector) is created for every thread, then the different lists are assembled + // to further increase efficiency, space is reserved for each list + int estimated_number_of_entries = (int) full_f_vector.size()/2 *8*8; // accurate in the case of Q4 elements, otherwise it provides a good estimation + std::vector<Eigen::Triplet <double>> K_tripletList; + K_tripletList.reserve(estimated_number_of_entries); + + int max_threads = omp_get_max_threads(); + int estimated_number_of_entries_per_thread = (int) estimated_number_of_entries / max_threads; + std::vector<std::vector<Eigen::Triplet <double>>> thread_K_list(max_threads); + for(int i = 0; i < max_threads; i++) + { + thread_K_list[i].reserve(estimated_number_of_entries_per_thread); } -} -void assembleKlistVolumicF(const Eigen::Matrix<double, 3, 3> H_matrix, const double rho, const double bx, const double by, - const std::string & integration_rule, - int & dim, std::vector<int> & tags, std::map<int, int> & nodeIndexMap, - std::vector<std::list<Eigen::Triplet <double>>> & my_k_list, - std::vector<std::list<std::pair<int,double>>> & thread_f_vector) -{ + std::vector<Eigen::Triplet <double>>* my_K_list; std::vector<int> elementTypes; std::vector<std::vector<std::size_t>> elementTags; @@ -1259,7 +1547,7 @@ void assembleKlistVolumicF(const Eigen::Matrix<double, 3, 3> H_matrix, const dou gmsh::model::mesh::getElements(elementTypes, elementTags, nodeTags, dim, tags[k]); - // looping over element types, enlever les déclarations des boucles pr aller plus vite (cfr Boman) + // looping over element types for (std::size_t i = 0; i < elementTypes.size(); ++i) { // getting element properties @@ -1267,17 +1555,24 @@ void assembleKlistVolumicF(const Eigen::Matrix<double, 3, 3> H_matrix, const dou elementName, elDim, order, numNodes, localNodeCoord, numPrimaryNodes); + + // adapting the composite integration rule as a function of the order of the elements + std::string adapting_integration_rule = "CompositeGauss14"; + if(order < 8) + { + adapting_integration_rule = "CompositeGauss" + std::to_string(2*order); + } // get Gauss points coordinates and weights gmsh::model::mesh::getIntegrationPoints(elementTypes[i], - integration_rule, // "Gauss2" + adapting_integration_rule, localCoords, weights); // get determinants and Jacobians std::vector<double> jacobians, determinants, coords; gmsh::model::mesh::getJacobians(elementTypes[i], localCoords, jacobians, - determinants, coords); + determinants, coords, tags[k]); // values and derivatives of the shape functions at the Gauss points of the reference element // we are here working with derivatives in the reference space, same for all elements @@ -1293,15 +1588,15 @@ void assembleKlistVolumicF(const Eigen::Matrix<double, 3, 3> H_matrix, const dou /*---------computing the K matrix (and f vector, only volumic part for now)------*/ // looping over the elements (computing elemental K matrices) - //double test1 = omp_get_wtime(); - //Eigen::setNbThreads(1); - #pragma omp parallel for #ifdef _MSC_VER // https://github.com/tesseract-ocr/tesseract/issues/3285 // OpenMP 2.0 standard is enforced - we may use /openmp:llvm and keep size_t + #pragma omp parallel for for (int el = 0; el < elementTags[i].size(); el++){ #else - for (std::size_t el = 0; el < elementTags[i].size(); el++){ + #pragma omp parallel for private (my_K_list) + for (std::size_t el = 0; el < elementTags[i].size(); el++) + { #endif // elemental K matrix and f vector initialization Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> K_matrix(2*numNodes,2*numNodes); @@ -1309,12 +1604,15 @@ void assembleKlistVolumicF(const Eigen::Matrix<double, 3, 3> H_matrix, const dou K_matrix.setZero(); for (int j = 0; j < 2*numNodes; ++j)f_vector[j] = 0.; - // looping over the Gauss points (formula of slide 17) - for (std::size_t j = 0; j < weights.size(); ++j){ + int threadNum = omp_get_thread_num(); + my_K_list = & thread_K_list[threadNum]; + + // looping over the Gauss points + for (std::size_t gaussIndex = 0; gaussIndex < weights.size(); ++gaussIndex){ // converting jacobian to Eigen format Eigen::Matrix<double, 2, 2> jacob2D; Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > - jacob(&jacobians[9*j+9*weights.size()*el], 3, 3); + jacob(&jacobians[9*gaussIndex+9*weights.size()*el], 3, 3); // 3D to 2D (plane stress case) jacob2D(0,0) = jacob(0,0); jacob2D(1,0) = jacob(1,0); @@ -1327,37 +1625,74 @@ void assembleKlistVolumicF(const Eigen::Matrix<double, 3, 3> H_matrix, const dou // computing the transpose of the inverse Eigen::Matrix<double, 2, 2> jacobinvtrans = jacobinv.transpose(); - // computing the B matrix (formula slide 19) and the f vector (also using gauss integration) + // computing the B matrix and the f vector (also using gauss integration) Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); - - computeBmatrix(j, numNodes, basisFunctionsGradient, determinants, - jacobinvtrans, H_matrix, B_matrix); + computeBmatrix(gaussIndex, numNodes, basisFunctionsGradient, determinants, jacobinvtrans, B_matrix); for (int l = 0; l < numNodes; ++l){ // looping over the number of shape functions - f_vector[2*l] = f_vector[2*l] + rho*basisFunctions[l+numNodes*j]*bx*determinants[j+weights.size()*el]*weights[j]; //pas oublier le dét ! - f_vector[2*l+1] = f_vector[2*l+1] + rho*basisFunctions[l+numNodes*j]*by*determinants[j+weights.size()*el]*weights[j]; // pas oublier le weights[j] non plus ! + f_vector[2*l] = f_vector[2*l] + rho*basisFunctions[l+numNodes*gaussIndex]*bx*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; + f_vector[2*l+1] = f_vector[2*l+1] + rho*basisFunctions[l+numNodes*gaussIndex]*by*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; } - K_matrix = K_matrix + B_matrix.transpose()*H_matrix*B_matrix*determinants[j+weights.size()*el]*weights[j]; + K_matrix = K_matrix + B_matrix.transpose()*H_matrix*B_matrix*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; } /*------------- ASSEMBLY PROCESS ------------*/ // USE LIST OF TRIPLETS TO PUSH ONLY ONCE -> more rapid and easier to parallelize - assembleKtriplet(i, el, nodeTags, numNodes, nodeIndexMap, my_k_list[omp_get_thread_num()], K_matrix, f_vector); - assembleFthread(i, el, nodeTags, numNodes, nodeIndexMap, thread_f_vector[omp_get_thread_num()], f_vector); + assembleKtriplet(el, nodeTags[i], numNodes, nodeIndexMap, *my_K_list, K_matrix); + assembleFlocal(el, nodeTags[i], numNodes, nodeIndexMap, full_f_vector, f_vector); + } + } + } + // gathering all triplet vectors in one single vector + K_tripletList = thread_K_list[0]; + if(max_threads > 1) + { + for (int i = 1; i < max_threads; i++) + { + K_tripletList.insert(K_tripletList.end(), thread_K_list[i].begin(), thread_K_list[i].end()); + } + } + // assembling the full sparse K matrix + full_K_matrix.setFromTriplets(K_tripletList.begin(), K_tripletList.end()); +} + +// assembles the elemental "K_matrix" into a vector of triplets "k_tripletList" using +// the node tags provided by "nodeTags" vector (index of the element is "elIndex"). +// The element has "numNodes" nodes. "nodeIndexMap" provides the global nodal index corresponding to a given node tag. +void assembleKtriplet(const int &elIndex, const std::vector<std::size_t> & nodeTags, const int numNodes, + std::map<int, int> & nodeIndexMap, std::vector<Eigen::Triplet <double>> & k_tripletList, + const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & K_matrix) +{ + //we go through the lower half of the elemental K_matrix before assembling in the triplet vector + for (int j = 0; j < 2*numNodes; ++j){ + int first_node_index = (int) j/2; + int first_node = nodeTags[numNodes*elIndex+first_node_index]; + int my_row = nodeIndexMap[first_node] + j % 2; + for(int l = 0; l <= j; ++l){ // to exploit symmetry + int second_node_index = (int) l/2; + int second_node = nodeTags[numNodes*elIndex+second_node_index]; + int my_col = nodeIndexMap[second_node] + l % 2; + + k_tripletList.push_back(Eigen::Triplet<double>(my_row,my_col,K_matrix(j,l))); + if(j != l){ + k_tripletList.push_back(Eigen::Triplet<double>(my_col,my_row,K_matrix(j,l))); } - //double test2 = omp_get_wtime() - test1; - //std::cout << "loop time: " << test2 << "\n"; } } } +// the "full_f_vector" and "full_K_matrix" are reduced in "reduced_f_vector" and "reduced_K_matrix" respectively, +// taking into account the dirichlet boundary conditions contained in "dir_BC". +// "new_DOFindices" gathers the new indices of the DOFs when taking the boundary conditions into account. void fillReducedKf(const std::vector<double> & full_f_vector, const Eigen::SparseMatrix<double> & full_K_matrix, - const std::vector<int> & new_DOFindices, const std::vector<double> & dir_BC, - Eigen::SparseMatrix<double> & reduced_K_matrix, - std::vector<double> & reduced_f_vector, - std::list<Eigen::Triplet <double>> & reduced_k_tripletList) + const std::vector<int> & new_DOFindices, const std::vector<double> & dir_BC, + Eigen::SparseMatrix<double> & reduced_K_matrix, std::vector<double> & reduced_f_vector) { + //the correction term on the f vector comes from the "Finite Element Method" theoretical course (JP Ponthot, ULiege), Chap2 Slide 38/50 + std::list<Eigen::Triplet <double>> reduced_k_tripletList; + + // initializing the reduced f vector for (std::size_t j = 0; j < reduced_f_vector.size(); ++j){ reduced_f_vector[j] = 0.; } @@ -1367,7 +1702,7 @@ void fillReducedKf(const std::vector<double> & full_f_vector, const Eigen::Spars int new_row; int new_col; double k_value; - for (int col=0; col<full_K_matrix.outerSize(); ++col){ + for (int col=0; col < full_K_matrix.outerSize(); ++col){ new_col = new_DOFindices[col]; for (Eigen::SparseMatrix<double>::InnerIterator it(full_K_matrix,col); it; ++it){ k_value = it.value(); @@ -1393,121 +1728,293 @@ void fillReducedKf(const std::vector<double> & full_f_vector, const Eigen::Spars reduced_K_matrix.setFromTriplets(reduced_k_tripletList.begin(), reduced_k_tripletList.end()); } -void computeStressStrainLinearWay(const std::vector<int> & elementTypes, const std::vector<std::vector<std::size_t>> &elementTags, - const std::vector<std::vector<std::size_t>> &elnodeTags, - const std::vector<double> &full_d_vector, std::vector<std::size_t> & elems2D, - const Eigen::Matrix<double, 3, 3> &H_matrix, const double nu, const double E, - std::map<int, int> & nodeIndexMap, - std::vector<std::vector<double>> & data3, std::vector<std::vector<double>> & data4, - std::vector<std::vector<double>> & data5, std::vector<std::vector<double>> & data6, - std::vector<std::vector<double>> & data7, std::vector<std::vector<double>> & data8, - std::vector<std::vector<double>> & data9, std::vector<std::vector<double>> & data10, - int & k) + +// computing the elemental-nodal strains and stresses in the FEM domain (dimension "dim" and entity tags "tags"), +// based on Hooke's matrix in plane stress "H_matrix", Young's modulus "E", Poisson's ratio "nu", and the full nodal +// displacement vector "full_d_vector" and the global nodal index map "nodeIndexMap". +// "nbelems" is the number of 2D elements contained in the FEM domain. +// returning the "max_VM_stress" and the corresponding nodetag "max_VM_nodeTag". +void computeStressStrainLinearWay(const int & dim, const std::vector<int> & tags, const std::vector<double> &full_d_vector, + const Eigen::Matrix<double, 3, 3> &H_matrix, const double &nu, const double &E, + std::map<int, int> & nodeIndexMap, const int &nbelems, double &max_VM_stress, int &max_VM_nodeTag) +{ + std::vector<std::string> names; + gmsh::model::list(names); + + int viewTagEpsX = gmsh::view::add("nodal_eps_x"); + int viewTagEpsY = gmsh::view::add("nodal_eps_y"); + int viewTagEpsXY = gmsh::view::add("nodal_2eps_xy"); + int viewTagEpsZ = gmsh::view::add("nodal_eps_z"); + int viewTagSigX = gmsh::view::add("nodal_sig_x"); + int viewTagSigY = gmsh::view::add("nodal_sig_y"); + int viewTagSigXY = gmsh::view::add("nodal_sig_xy"); + int viewTagSigVM = gmsh::view::add("nodal_sig_VM"); + + std::vector<std::vector<std::vector<double>>> dataEps(4); + dataEps[0].resize(nbelems); // eps X + dataEps[1].resize(nbelems); // eps Y + dataEps[2].resize(nbelems); // eps XY + dataEps[3].resize(nbelems); // eps Z + + std::vector<std::vector<std::vector<double>>> dataSig(4); + dataSig[0].resize(nbelems); // Sig X + dataSig[1].resize(nbelems); // Sig Y + dataSig[2].resize(nbelems); // Sig XY + dataSig[3].resize(nbelems); // Sig VM + std::vector<std::size_t> elems2D(nbelems); + + + int data_index = 0; + std::vector<int> elementTypes; + std::vector<std::vector<std::size_t>> elementTags; + std::vector<std::vector<std::size_t>> elnodeTags; + + for(std::size_t entityTag = 0; entityTag< tags.size(); ++entityTag) + { + gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[entityTag]); + + std::string name; + int dim, order, numNodes, numPrimaryNodes; + std::vector<double> paramCoord2D; + int numComponents, numOrientations; + std::vector<double> basisFunctionsGradient; + Eigen::Vector3d epsilon; // will contain local values of the strains + Eigen::Vector3d sigma; // will contain local values of the stresses + int nodeTag; + Eigen::Matrix<double, 2, 2> jacob2D; + Eigen::Matrix<double, 2, 2> jacobinv; + Eigen::Matrix<double, 2, 2> jacobinvtrans; + + for (std::size_t ityp = 0; ityp < elementTypes.size(); ++ityp) + { + // get info about this type of element + gmsh::model::mesh::getElementProperties(elementTypes[ityp], name, dim, order, + numNodes, paramCoord2D, numPrimaryNodes); + //paramCoord contains the coordinates of the nodes in 2D + // passage en 3D pour utiliser getJacobians + std::vector<double> paramCoord(3*paramCoord2D.size()/2); + for(std::size_t j = 0; j < paramCoord2D.size()/2; ++j){ + paramCoord[3*j] = paramCoord2D[2*j]; + paramCoord[3*j+1] = paramCoord2D[2*j+1]; + paramCoord[3*j+2] = 0.; + } + + + // select element/node tags for this type of element + auto &etags = elementTags[ityp]; + auto &enods = elnodeTags[ityp]; + + // will contain the d vector inside each element + Eigen::VectorXd nodal_displacement(2*numNodes); //use eigen vector to use Eigen matric product later + + // get determinants and Jacobians (only jacob useful here) AT NODES AND NOT AT GAUSS POINTS + std::vector<double> jacobians, determinants, coords; + gmsh::model::mesh::getJacobians(elementTypes[ityp], + paramCoord, jacobians, + determinants, coords, tags[entityTag]); + + // derivatives of the shape functions at the nodes of the reference element + // we are here working with derivatives in the reference space, same for all elements + gmsh::model::mesh::getBasisFunctions(elementTypes[ityp], paramCoord, + "GradLagrange", numComponents, + basisFunctionsGradient, + numOrientations); + + // loop over elements of type "ityp" + for (std::size_t i = 0; i < etags.size(); ++i) + { + elems2D[data_index] = etags[i]; + + dataEps[0][data_index].resize(numNodes); + dataEps[1][data_index].resize(numNodes); + dataEps[2][data_index].resize(numNodes); + dataEps[3][data_index].resize(numNodes); + dataSig[0][data_index].resize(numNodes); + dataSig[1][data_index].resize(numNodes); + dataSig[2][data_index].resize(numNodes); + dataSig[3][data_index].resize(numNodes); + + // loop over nodes of the element, filling the local nodal displacement vector "d" + for (int j = 0; j < numNodes; ++j) + { + nodeTag = enods[numNodes * i + j]; + nodal_displacement(2*j) = full_d_vector[nodeIndexMap[nodeTag]]; + nodal_displacement(2*j+1) = full_d_vector[nodeIndexMap[nodeTag]+1]; + } + // looping over the nodes + for (int j = 0; j < numNodes; ++j){ + // converting jacobian to Eigen format + Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > + jacob(&jacobians[9*j+9*numNodes*i], 3, 3); + // 3D to 2D (plane stress case) + jacob2D(0,0) = jacob(0,0); + jacob2D(1,0) = jacob(1,0); + jacob2D(0,1) = jacob(0,1); + jacob2D(1,1) = jacob(1,1); + + // computing the inverse + jacobinv = jacob2D.inverse(); + + // computing the transpose of the inverse + jacobinvtrans = jacobinv.transpose(); + + // computing the B matrix + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); + + computeBmatrix(j, numNodes, basisFunctionsGradient, determinants, jacobinvtrans, B_matrix); + + epsilon = B_matrix*nodal_displacement; + sigma = H_matrix*epsilon; + + dataEps[0][data_index][j] = epsilon(0); + dataEps[1][data_index][j] = epsilon(1); + dataEps[2][data_index][j] = epsilon(2); + dataEps[3][data_index][j] = -nu/E*(sigma(0)+sigma(1)); + dataSig[0][data_index][j] = sigma(0); + dataSig[1][data_index][j] = sigma(1); + dataSig[2][data_index][j] = sigma(2); + dataSig[3][data_index][j] = sqrt(sigma(0)*sigma(0) + sigma(1)*sigma(1) - sigma(0)*sigma(1) + 3*sigma(2)*sigma(2)); + + //retrieving maximal nodal von mises stress + if(dataSig[3][data_index][j] > max_VM_stress) + { + max_VM_stress = dataSig[3][data_index][j]; + max_VM_nodeTag = (int) elnodeTags[ityp][numNodes*i+j]; + } + } + data_index++; + } + } + } + + gmsh::view::addModelData(viewTagEpsX, 0, names[0], "ElementNodeData", + elems2D, dataEps[0], 1); + gmsh::view::addModelData(viewTagEpsY, 0, names[0], "ElementNodeData", + elems2D, dataEps[1], 1); + gmsh::view::addModelData(viewTagEpsXY, 0, names[0], "ElementNodeData", + elems2D, dataEps[2], 1); + gmsh::view::addModelData(viewTagEpsZ, 0, names[0], "ElementNodeData", + elems2D, dataEps[3], 1); + gmsh::view::addModelData(viewTagSigX, 0, names[0], "ElementNodeData", + elems2D, dataSig[0], 1); + gmsh::view::addModelData(viewTagSigY, 0, names[0], "ElementNodeData", + elems2D, dataSig[1], 1); + gmsh::view::addModelData(viewTagSigXY, 0, names[0], "ElementNodeData", + elems2D, dataSig[2], 1); + gmsh::view::addModelData(viewTagSigVM, 0, names[0], "ElementNodeData", + elems2D, dataSig[3], 1); +} + +// computing the total (internal) strain energy "strain_energy" in the whole FEM domain (dimension "dim" and +// entity tags "tags"), using the nodal displacements in "full_d_vector". The nodes are indexed using the "nodeIndexMap". +// The Hooke's matrix in plane stress "H_matrix" is used to compute the stresses from the strains. +// Computed as a sum of integrals over the finite elements, using Gauss integration "integration_rule". +void computeStrainEnergyLinearWay(double & strainEnergy, const int & dim, const std::vector<int> & tags, + const std::vector<double> &full_d_vector, const Eigen::Matrix<double, 3, 3> &H_matrix, + std::map<int, int> & nodeIndexMap, const std::string & integration_rule) { - std::string name; - int dim, order, numNodes, numPrimaryNodes; - std::vector<double> paramCoord2D; + std::vector<int> elementTypes; + std::vector<std::vector<std::size_t>> elementTags; + std::vector<std::vector<std::size_t>> nodeTags; + std::string elementName; + int elDim, order, numNodes, numPrimaryNodes; + std::vector<double> localNodeCoord; + std::vector<double> localCoords, weights; int numComponents, numOrientations; + std::vector<double> basisFunctions; std::vector<double> basisFunctionsGradient; + int nodeTag; + Eigen::Vector3d epsilon; // will contain local values of the strains Eigen::Vector3d sigma; // will contain local values of the stresses - int nodeTag; - Eigen::Matrix<double, 2, 2> jacob2D; - Eigen::Matrix<double, 2, 2> jacobinv; - Eigen::Matrix<double, 2, 2> jacobinvtrans; - for (std::size_t ityp = 0; ityp < elementTypes.size(); ++ityp) + for (std::size_t k = 0; k < tags.size(); ++k) { - // get info about this type of element - gmsh::model::mesh::getElementProperties(elementTypes[ityp], name, dim, order, - numNodes, paramCoord2D, numPrimaryNodes); - //paramCoord contains the coordinates of the nodes in 2D - // passage en 3D pour utiliser getJacobians - std::vector<double> paramCoord(3*paramCoord2D.size()/2); - for(std::size_t j = 0; j < paramCoord2D.size()/2; ++j){ - paramCoord[3*j] = paramCoord2D[2*j]; - paramCoord[3*j+1] = paramCoord2D[2*j+1]; - paramCoord[3*j+2] = 0.; - } + gmsh::model::mesh::getElements(elementTypes, elementTags, + nodeTags, dim, tags[k]); + // looping over element types + for (std::size_t i = 0; i < elementTypes.size(); ++i) + { + // getting element properties + gmsh::model::mesh::getElementProperties(elementTypes[i], + elementName, elDim, order, + numNodes, localNodeCoord, + numPrimaryNodes); + + // get Gauss points coordinates and weights + gmsh::model::mesh::getIntegrationPoints(elementTypes[i], + integration_rule, + localCoords, weights); - // select element/node tags for this type of element - auto &etags = elementTags[ityp]; - auto &enods = elnodeTags[ityp]; + // get determinants and Jacobians + std::vector<double> jacobians, determinants, coords; + gmsh::model::mesh::getJacobians(elementTypes[i], + localCoords, jacobians, + determinants, coords, tags[k]); - // will contain the d vector inside each element - Eigen::VectorXd nodal_displacement(2*numNodes); //use eigen vector to use Eigen matric product later + // values and derivatives of the shape functions at the Gauss points of the reference element + // we are here working with derivatives in the reference space, same for all elements + gmsh::model::mesh::getBasisFunctions(elementTypes[i], localCoords, + "Lagrange", numComponents, + basisFunctions, + numOrientations); - // get determinants and Jacobians (only jacob useful here) AT NODES AND NOT AT GAUSS POINTS - std::vector<double> jacobians, determinants, coords; - gmsh::model::mesh::getJacobians(elementTypes[ityp], - paramCoord, jacobians, - determinants, coords); + gmsh::model::mesh::getBasisFunctions(elementTypes[i], localCoords, + "GradLagrange", numComponents, + basisFunctionsGradient, + numOrientations); + + Eigen::VectorXd nodal_displacement(2*numNodes); //use eigen vector to use Eigen matric product later - // derivatives of the shape functions at the nodes of the reference element - // we are here working with derivatives in the reference space, same for all elements - gmsh::model::mesh::getBasisFunctions(elementTypes[ityp], paramCoord, - "GradLagrange", numComponents, - basisFunctionsGradient, - numOrientations); + for (std::size_t el = 0; el < elementTags[i].size(); el++){ - // loop over elements of type "ityp" - for (std::size_t i = 0; i < etags.size(); ++i) - { - elems2D[k] = etags[i]; - - data3[k].resize(numNodes); - data4[k].resize(numNodes); - data5[k].resize(numNodes); - data6[k].resize(numNodes); - data7[k].resize(numNodes); - data8[k].resize(numNodes); - data9[k].resize(numNodes); - data10[k].resize(numNodes); - - // loop over nodes of the element, filling the local nodal displacement vector "d" - for (int j = 0; j < numNodes; ++j) - { - nodeTag = enods[numNodes * i + j]; - nodal_displacement(2*j) = full_d_vector[nodeIndexMap[nodeTag]]; - nodal_displacement(2*j+1) = full_d_vector[nodeIndexMap[nodeTag]+1]; - } - // looping over the nodes - for (int j = 0; j < numNodes; ++j){ - // converting jacobian to Eigen format - Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > - jacob(&jacobians[9*j+9*numNodes*i], 3, 3); - // 3D to 2D (plane stress case) - jacob2D(0,0) = jacob(0,0); - jacob2D(1,0) = jacob(1,0); - jacob2D(0,1) = jacob(0,1); - jacob2D(1,1) = jacob(1,1); - - // computing the inverse - jacobinv = jacob2D.inverse(); - - // computing the transpose of the inverse - jacobinvtrans = jacobinv.transpose(); - - // computing the B matrix (formula slide 19) - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); - - computeBmatrix(j, numNodes, basisFunctionsGradient, determinants, - jacobinvtrans, H_matrix, B_matrix); - - epsilon = B_matrix*nodal_displacement; - sigma = H_matrix*epsilon; - - data3[k][j] = epsilon(0); - data4[k][j] = epsilon(1); - data5[k][j] = epsilon(2); - data6[k][j] = -nu/E*(sigma(0)+sigma(1));// formula slide 11/20 elasticity - data7[k][j] = sigma(0); - data8[k][j] = sigma(1); - data9[k][j] = sigma(2); - data10[k][j] = sqrt(sigma(0)*sigma(0) + sigma(1)*sigma(1) - sigma(0)*sigma(1) + 3*sigma(2)*sigma(2)); + for (int j = 0; j < numNodes; ++j) + { + nodeTag = nodeTags[i][numNodes * el + j]; + nodal_displacement(2*j) = full_d_vector[nodeIndexMap[nodeTag]]; + nodal_displacement(2*j+1) = full_d_vector[nodeIndexMap[nodeTag]+1]; + } + + double elementalStrainEnergy = 0; + + // looping over the Gauss points + for (std::size_t gaussIndex = 0; gaussIndex < weights.size(); ++gaussIndex){ + // converting jacobian to Eigen format + Eigen::Matrix<double, 2, 2> jacob2D; + Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > + jacob(&jacobians[9*gaussIndex+9*weights.size()*el], 3, 3); + // 3D to 2D (plane stress case) + jacob2D(0,0) = jacob(0,0); + jacob2D(1,0) = jacob(1,0); + jacob2D(0,1) = jacob(0,1); + jacob2D(1,1) = jacob(1,1); + + // computing the inverse + Eigen::Matrix<double, 2, 2> jacobinv = jacob2D.inverse(); + + // computing the transpose of the inverse + Eigen::Matrix<double, 2, 2> jacobinvtrans = jacobinv.transpose(); + + // computing the B matrix + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B_matrix(3,2*numNodes); + + computeBmatrix(gaussIndex, numNodes, basisFunctionsGradient, determinants, jacobinvtrans, B_matrix); + + epsilon = B_matrix*nodal_displacement; + sigma = H_matrix*epsilon; + + double dot_product = 0; + for(int z = 0; z < 3; z++) + { + dot_product += epsilon(z)*sigma(z); + } + + elementalStrainEnergy += 0.5*dot_product*determinants[gaussIndex+weights.size()*el]*weights[gaussIndex]; + } + /*------------- ASSEMBLY PROCESS ------------*/ + strainEnergy += elementalStrainEnergy; } - k++; } } } \ No newline at end of file diff --git a/srcs/FEM/functionsFEM.hpp b/srcs/FEM/functionsFEM.hpp index 5cd5c13da97758ba0262a73ac278af33c075836a..cadea106899f5c85d6499d90de0a282f1cffb5ec 100644 --- a/srcs/FEM/functionsFEM.hpp +++ b/srcs/FEM/functionsFEM.hpp @@ -1,10 +1,11 @@ #include <iostream> -#include <vector> // Why should I include this ? +#include <vector> #include <map> #include <Eigen/Dense> #include <list> -#include <Eigen/Sparse> // Eigen library for sparse matrices +#include <Eigen/Sparse> +// data structure used for the non-linear solver "solverFEMnonLinear" struct elementData{ // will store all the kinematics data std::vector<size_t> nodes; // will contain the tags of the nodes @@ -34,41 +35,232 @@ struct elementData{ Eigen::Matrix<double, Eigen::Dynamic, 1> fl; //local current (iterative) forces under vector form - Eigen::Matrix<double, Eigen::Dynamic, 1> A; - Eigen::Matrix<double, 1, Eigen::Dynamic> G; - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> P; - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> E; - Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> B; + Eigen::Matrix<double, Eigen::Dynamic, 1> A; // see report for exact definition + Eigen::Matrix<double, 1, Eigen::Dynamic> G; // see report for exact definition + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> P; // see report for exact definition + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> E; // see report for exact definition + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> C; // see report for exact definition }; +/*------------ "SOLVER" functions -----------------*/ + +// solves the non-linear (large displacements, no large deformations) elastic problem. +// if coupled to the BEM solver, "electrostaticPressure" is the pressure computed from the electric field +// on the BEM_FEM boundary (mapping element tag -> pressure). "boundaryDisplacementMap" is filled for all +// nodes on the BEM_FEM_boundary as (node tag -> (u,v) displacement) +// "nbViews" is the current number of views already allocated in the gmsh window. +// "postProcessing" boolean activates the post processing operations (must only be computed once at the end of the +// coupled solver). "iteration" denotes the current iteration of the two-way coupled solver (starting at 1). +// "viewTagU" and "viewTagF" correspond to the view tags of the nodal displacements and the nodal forces in the gmsh window. +// when "untangleMesh" is activated, the nodal coordinates of the nodes in the FEM_domain are updated according to +// their final nodal displacements. +void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, + std::map<int,std::pair<double,double>> & boundaryDisplacementMap, int &nbViews, bool postProcessing, + const int iteration, const int viewTagU, const int viewTagF, bool untangleMesh); + +// solves the linear elastic problem in the FEM domain. +// "electrostaticPressure" contains the pressure resulting from the electric field computation on the +// BEM_FEM_boundary. "nbViews" is the current number of views already allocated in the gmsh window. +void solverFEM(std::map<int, double> &electrostaticPressure, int &nbViews); + +/*------------ More specific functions called inside the "SOLVER" functions -----------------*/ + +// returns the boolean non_linear_solver parameter based on what is set in the .geo file, +// add SetNumber("Non_linear_solver", 0); in .geo file to use linear solver. +bool getNonLinearParameter(); + +// fills the "FEM_nodeTags" vector with the nodes in the FEM domain, fills the "FEM_nodeCoordsMap" with the coordinates (x,y) +// corresponding to each nodeTag, looking at entity tags "tags" of dimension "dim" corresponding to the FEM domain. +void RetrieveFEMNodeTagsAndCoords(std::vector<std::size_t> & FEM_nodeTags, + std::map<int,std::pair<double,double>> & FEM_nodeCoordsMap, + const int & dim, const std::vector<int> & tags); + +// fills the "FEM_elementTags" vector with all element tags of the elements of dimension "dim" (in practice: 2) +// in the entities associated to the entity tags "tags" (corresponding to the FEM domain). +// associates an initialized elementData structure to each element tag through the "FEM_kinematicsMap" map, +// using the "FEM_nodeCoordsMap" map gathering the coordinates of each node in the FEM domain. +int initKinematics(std::vector<std::size_t> & FEM_elementTags, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int,std::pair<double,double>> & FEM_nodeCoordsMap, + const int & dim, const std::vector<int> & tags); + +// updates the kinematics matrices of one element "element" based on its updated nodal positions and rotation angle. +// if "computeFl" is set as true, also computes the local nodal forces vector "fl = Kl*pl", only OK if +// the local stiffness matrix Kl has already been initialized, using "fillElementalKandF". +void updateKinMatrices(elementData* element, const bool computeFl); + +// gets physical properties of FEM_domain: Young's modulus "E", Poisson's ratio "nu", +// density "rho", volumic force along x "bx", volumic force along y "by". +void getPhysicalProperties(double & E, double & nu, double & rho, double & bx, double & by); + +// computes the Hooke's matrix in plane stress "H_matrix" based on the Young's modulus "E" and Poisson's ratio "nu". Eigen::Matrix<double, 3, 3> computeHmatrix(const double E, const double nu); -void assembleFthread(const int i, const int el, const std::vector<std::vector<std::size_t>> & nodeTags, const int numNodes, std::map<int, int> & nodeIndexMap, std::list<std::pair<int,double>> & thread_f_vector, std::vector<double> & f_vector); -void computeBmatrix(const int j, const int numNodes, const std::vector<double> & basisFunctionsGradient, const std::vector<double> & determinants, const Eigen::Matrix<double, 2, 2> & jacobinvtrans, const Eigen::Matrix<double, 3, 3> & H_matrix, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & B_matrix); -void getPhysicalProperties(const std::vector<std::string> & keys, double & E, double & nu, double & rho, double & bx, double & by); -void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double rho, const double bx, const double by, const std::string & integration_rule, int & dim, std::vector<int> & tags, std::map<int, int> & nodeIndexMap, std::vector<std::list<Eigen::Triplet <double>>> & my_k_list, std::vector<std::list<std::pair<int,double>>> & thread_f_vector, std::map<int, elementData> & FEM_kinematicsMap); -void computeNeumannBC(const int numNodes, const int i, const std::vector<std::vector<std::size_t>> & elementTags, const double tx, const double ty, std::map<int, int> & nodeIndexMap, std::vector<double> & f_vector, const std::vector<double> & weights, const std::vector<double> & basisFunctions, const std::vector<double> & determinants, const std::vector<std::vector<std::size_t>> & nodeTags, std::vector<double> & full_f_vector); -void includeNeumannBC(const std::vector<std::string> & keys, const std::string & integration_rule, std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, std::vector<double> & full_f_vector); -void fillDOFindicesDirBC(const std::vector<std::string> & keys, std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, std::vector<int> & new_DOFindices, std::vector<double> & dir_BC); -void computeReactionForces(std::map<std::string, std::pair<int, int>> & groups, std::map<int, int> & nodeIndexMap, std::vector<double> & nodal_forces, const std::vector<std::string> & keys); -void plotUxUy(const std::vector<std::size_t> & FEM_nodeTags, const std::vector<double> & full_d_vector, const int nbViews, std::vector<std::string> & names); -void computeStressStrainElNodal(const std::vector<int> & elementTypes, const std::vector<std::vector<std::size_t>> &elementTags, const std::vector<std::vector<std::size_t>> &elnodeTags, std::vector<std::size_t> & elems2D, const Eigen::Matrix<double, 3, 3> &H_matrix, const double nu, const double E, std::map<int, elementData> & FEM_kinematicsMap, std::vector<std::vector<double>> & data3, std::vector<std::vector<double>> & data4, std::vector<std::vector<double>> & data5, std::vector<std::vector<double>> & data6, std::vector<std::vector<double>> & data7, std::vector<std::vector<double>> & data8, std::vector<std::vector<double>> & data9, std::vector<std::vector<double>> & data10, int & k); -void applyElecPressure(const std::string & integration_rule, std::map<int,std::pair<double,double>> & nodeCoordsMap, std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, std::map<int, double> &electrostaticPressure, std::vector<double> & full_f_vector); -int initKinematics(std::vector<std::size_t> & FEM_elementTags, std::map<int, elementData> & FEM_kinematicsMap, std::map<int,std::pair<double,double>> & FEM_nodeCoordsMap, int & dim, std::vector<int> & tags); -void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, std::vector<double> & full_d_vector, std::map<int, int> & nodeIndexMap, std::vector<std::size_t> & FEM_elementTags); -void updateKinMatrices(elementData* element, bool computeFl); -void assembleGlobalF(std::vector<double> & global_f_vector, std::map<int, elementData> & FEM_kinematicsMap, std::map<int, int> & nodeIndexMap, std::vector<int> & new_DOFindices, std::vector<std::size_t> & FEM_elementTags); -double computeResidualNorm(std::vector<double> & global_f_vector, std::vector<double> & f_app_vector, Eigen::Matrix<double, Eigen::Dynamic, 1> & residual); -void assembleGlobalKg(Eigen::SparseMatrix<double> & global_tangent_matrix, std::map<int, elementData> & FEM_kinematicsMap, std::map<int, int> & nodeIndexMap, std::vector<int> & new_DOFindices, std::vector<std::size_t> & FEM_elementTags); -void updateNodalDispVector(std::vector<double> & full_d_vector, std::vector<double> & global_p_vector, std::vector<int> & new_DOFindices); -void retrieveFinalNodalForces(std::vector<double> & final_nodal_forces, std::map<int, elementData> & FEM_kinematicsMap, std::map<int, int> & nodeIndexMap, std::vector<std::size_t> & FEM_elementTags); -void retrieveBoundaryDisplacements(std::map<int,std::pair<double,double>> & boundaryDisplacementMap, const std::vector<double> & full_d_vector, std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups); - -void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<int,std::pair<double,double>> & boundaryDisplacementMap, const int nbViews, bool postProcessing, const int iteration, const int viewTagU, const int viewTagF); + +// looping over every element in the FEM_domain (dimension "dim" and entity tags "tags"), filling "full_f_vector", +// with the local volumic forces computed based on the volumic force ("bx","by") and density "rho" with the help of +// "nodeIndexMap" mapping each nodeTag to its global index. +// filling the local stiffness matrices stored in the elementData structure contained in "FEM_kinematicsMap". +void fillElementalKandF(const Eigen::Matrix<double, 3, 3> H_matrix, const double & rho, const double & bx, + const double & by, const int & dim, const std::vector<int> & tags, std::map<int, int> & nodeIndexMap, + std::vector<double> & full_f_vector, std::map<int, elementData> & FEM_kinematicsMap); + +// computing the strain displacement "B_matrix" at the "gaussIndex"-th gaussian point of the element +// consisting of "numNodes" nodes, based on the "basisFunctionsGradient", "determinants" and the inverse of the jacobian +// matrix "jacobinvtrans". +void computeBmatrix(const int &gaussIndex, const int &numNodes, const std::vector<double> & basisFunctionsGradient, + const std::vector<double> & determinants, + const Eigen::Matrix<double, 2, 2> & jacobinvtrans, + Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & B_matrix); + +// assembles the local "f_vector" into the full f vector, "elIndex" is the element index with respect to "nodeTags" +// having "numNodes" nodes, "nodeTags" gathering all the nodeTags of the current element type in the current entity. +// "nodeIndexMap" associates a global index to each nodetag. +void assembleFlocal(const int &elIndex, const std::vector<std::size_t> & nodeTags, const int &numNodes, + std::map<int, int> & nodeIndexMap, std::vector<double> & full_f_vector, const std::vector<double> & f_vector); + +// fills the "full_f_vector" with the surfacic contribution of the neumann boundary conditions based on the +// "nodeIndexMap" associating a global index to each node tag, the local integration of the surfacic forces is +// performed using Gauss integration based on "integration rule". +// "BCkeys" gathers the keys associated to boundary conditions in the .geo file (using SetNumber(...)). +// "groups" associates a dimension and a tag to each physical group. +void includeNeumannBC(const std::vector<std::string> & BCkeys, const std::string & integration_rule, + std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, + std::vector<double> & full_f_vector); + +// for the coupled solver, fills the "full_f_vector" with the electrostatic pressure contained in the +// "electrostaticPressure" map for different element tags, using Gauss integration "integration_rule", the "nodeIndexMap" +// associating a global nodal index to each nodeTag, "nodeCoordsMap" gathering the coordinates of each node and "groups" +// containing the different physical groups of the domain. +void applyElecPressure(const std::string & integration_rule, std::map<int,std::pair<double,double>> & nodeCoordsMap, + std::map<int, int> & nodeIndexMap, std::map<std::string, std::pair<int, int>> & groups, + std::map<int, double> &electrostaticPressure, std::vector<double> & full_f_vector); + +// looping over the boundary conditions imposed in the .geo file and gathered in "BCkeys" related to the +// physical groups "groups", the goal is to fill the two vectors "new_DOFindices" and "dir_BC": +// "new_DOFindices" vector will contain the new indices of the K matrix after the "number_removed_lines" rows/columns +// corresponding to dirichlet boundary conditions have been removed. A removed index will correspond to "new_DOFindices"= -1. +// dir_BC[index] will contain the dirichlet boundary condition prescribed to the node whose global index is retrieved using +// "nodeIndexMap". +void fillDOFindicesDirBC(const std::vector<std::string> & BCkeys, std::map<int, int> & nodeIndexMap, + std::map<std::string, std::pair<int, int>> & groups, + std::vector<int> & new_DOFindices, std::vector<double> & dir_BC, int & number_removed_lines); + +// updating the kinematics of the "FEM_elementTags" contained in the "FEM_kinematicsMap", +// based on the "full_d_vector" gathering the nodal displacements associated to the global +// node indices contained in "nodeIndexMap". +void updateKinematics(std::map<int, elementData> & FEM_kinematicsMap, const std::vector<double> & full_d_vector, + std::map<int, int> & nodeIndexMap, const std::vector<std::size_t> & FEM_elementTags); + +// retrieving the global nodal forces based on local nodal forces of the +// "FEM_elementTags" contained in the "FEM_kinematicsMap", +// each node Tag corresponds to a global index given by "nodeIndexMap". +void retrieveTotalNodalForces(std::vector<double> & final_nodal_forces, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int, int> & nodeIndexMap, const std::vector<std::size_t> & FEM_elementTags); + +// assembles the "global_f_vector" based on the local nodal forces vector of the +// "FEM_elementTags" contained in the "FEM_kinematicsMap", +// without taking into account the DOFs fixed by a dirichlet boundary condition, +// the nodes are renumbered using "new_DOFindices". +// each node Tag corresponds to a global index given by "nodeIndexMap". +void assembleGlobalF(std::vector<double> & global_f_vector, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int, int> & nodeIndexMap, const std::vector<int> & new_DOFindices, + const std::vector<std::size_t> & FEM_elementTags); + +// assembling the global tangent stiffness matrix based on the local elemental stiffness matrices contained +// in the "FEM_kinematicsMap" associated to each "FEM_elementTags". +// "new_DOFindices" maps the global initial node index (from "nodeIndexMap") to the index +// obtained without considering the fixed DOFs. +void assembleGlobalKg(Eigen::SparseMatrix<double> & global_tangent_matrix, std::map<int, elementData> & FEM_kinematicsMap, + std::map<int, int> & nodeIndexMap, const std::vector<int> & new_DOFindices, + const std::vector<std::size_t> & FEM_elementTags); + +// updating the "full_d_vector" based on the "global_p_vector", using the global and reduced index mapping: +// "new_DOFindices". +void updateNodalDispVector(std::vector<double> & full_d_vector, const std::vector<double> & global_p_vector, + const std::vector<int> & new_DOFindices); + +// retrieving the nodal displacements on the BEM_FEM_boundary in order to communicate them to the +// BEM solver in the two-way coupled solver. Using the "groups" to find the physical group associated +// to the boundary, all nodes of the boundary are associated through the "boundaryDisplacementMap" their +// nodal displacement (u,v) retrieved from "full_d_vector" using the indexation of "nodeIndexMap". +void retrieveBoundaryDisplacements(std::map<int,std::pair<double,double>> & boundaryDisplacementMap, + const std::vector<double> & full_d_vector, std::map<int, int> & nodeIndexMap, + std::map<std::string, std::pair<int, int>> & groups); + +// computing the reaction forces on all the physical groups "groups" for which a dirichlet boundary +// condition has been prescribed (using the "BCkeys" to retrieve the groups from the .geo file), +// based on the "final_nodal_forces" and the "nodeIndexMap" to retrieve the global index associated +// to one given node tag. +void computeReactionForces(std::map<std::string, std::pair<int, int>> & groups, + std::map<int, int> & nodeIndexMap, const std::vector<double> & final_nodal_forces, + const std::vector<std::string> & BCkeys); + +// plotting the nodal displacement values associated to "FEM_nodeTags" in the "names[0]" model, +// based on the "full_d_vector". +void plotUxUy(const std::vector<std::size_t> & FEM_nodeTags, const std::vector<double> & full_d_vector, + const std::vector<std::string> & names); + +// computing the elemental-nodal strains and stresses in the FEM domain (dimension "dim" and entity tags "tags"), +// based on Hooke's matrix in plane stress "H_matrix", Young's modulus "E", Poisson's ratio "nu", looping over the +// "nbelems" elements contained in "FEM_kinematicsMap". +// returning the "max_VM_stress" and the corresponding nodetag "max_VM_nodeTag". +void computeStressStrainElNodal(const int & dim, const std::vector<int> & tags, const Eigen::Matrix<double, 3, 3> &H_matrix, + const double nu, const double E, std::map<int, elementData> & FEM_kinematicsMap, + const int & nbelems, double & max_VM_stress, int & max_VM_nodeTag); + +// computing the work done by external forces, as the nodal forces are energy consistent, it +// is sufficient to compute the "externalWork" as the dot product of the nodal displacements +// "full_d_vector" and the nodal forces "final_nodal_forces". +void computeWorkDoneByExternalForces(double &externalWork, const std::vector<double> & full_d_vector, + const std::vector<double> & final_nodal_forces); + +// computing the total (internal) strain energy "strain_energy" in the whole FEM domain (dimension "dim" and +// entity tags "tags"), using the elementData stored in "FEM_kinematicsMap" gathering the informations for all +// FEM elements. The Hooke's matrix in plane stress "H_matrix" is used to compute the stresses from the strains. +// Computed as a sum of integrals over the finite elements, using Gauss integration "integration_rule". +void computeStrainEnergy(double & strainEnergy, const int & dim, const std::vector<int> & tags, + std::map<int, elementData> & FEM_kinematicsMap, const Eigen::Matrix<double, 3, 3> &H_matrix, + const std::string & integration_rule); + +//displays the time of the desired code section "function_name", if "display_time" is set as true. +void displayTime(const double &start, const double &end, const std::string &function_name, const bool &display_time); /*-------------- FUNCTIONS SPECIFIC TO LINEAR FEM ------------------*/ -void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews); -void assembleKtriplet(const int i, const int el, const std::vector<std::vector<std::size_t>> & nodeTags, const int numNodes, std::map<int, int> & nodeIndexMap, std::list<Eigen::Triplet <double>> & k_tripletList, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & K_matrix, std::vector<double> & f_vector); -void assembleKlistVolumicF(const Eigen::Matrix<double, 3, 3> H_matrix, const double rho, const double bx, const double by, const std::string & integration_rule, int & dim, std::vector<int> & tags, std::map<int, int> & nodeIndexMap, std::vector<std::list<Eigen::Triplet <double>>> & my_k_list, std::vector<std::list<std::pair<int,double>>> & thread_f_vector); -void fillReducedKf(const std::vector<double> & full_f_vector, const Eigen::SparseMatrix<double> & full_K_matrix, const std::vector<int> & new_DOFindices, const std::vector<double> & dir_BC, Eigen::SparseMatrix<double> & reduced_K_matrix, std::vector<double> & reduced_f_vector, std::list<Eigen::Triplet <double>> & reduced_k_tripletList); -void computeStressStrainLinearWay(const std::vector<int> & elementTypes, const std::vector<std::vector<std::size_t>> &elementTags, const std::vector<std::vector<std::size_t>> &elnodeTags, const std::vector<double> &full_d_vector, std::vector<std::size_t> & elems2D, const Eigen::Matrix<double, 3, 3> &H_matrix, const double nu, const double E, std::map<int, int> & nodeIndexMap, std::vector<std::vector<double>> & data3, std::vector<std::vector<double>> & data4, std::vector<std::vector<double>> & data5, std::vector<std::vector<double>> & data6, std::vector<std::vector<double>> & data7, std::vector<std::vector<double>> & data8, std::vector<std::vector<double>> & data9, std::vector<std::vector<double>> & data10, int & k); \ No newline at end of file +// assembling the full stiffness matrix "full_K_matrix" using first a triplet vector, assembling the volumic part +// of the nodal forces "full_f_vector", in the FEM_domain (dimension "dim" and entity tag "tags") using the global +// node indexation defined by "nodeIndexMap". "H_matrix" is the plane stress Hooke's matrix, "rho" the density of the +// material, "bx" the volumic force along x, "by" the volumic force along y. +void assembleKVolumicF(const Eigen::Matrix<double, 3, 3> & H_matrix, const double & rho, const double & bx, const double & by, + const int & dim, const std::vector<int> & tags, std::map<int, int> & nodeIndexMap, + Eigen::SparseMatrix<double> & full_K_matrix, std::vector<double> & full_f_vector); + +// assembles the elemental "K_matrix" into a vector of triplets "k_tripletList" using +// the node tags provided by "nodeTags" vector (index of the element is "elIndex"). +// The element has "numNodes" nodes. "nodeIndexMap" provides the global nodal index corresponding to a given node tag. +void assembleKtriplet(const int &elIndex, const std::vector<std::size_t> & nodeTags, const int numNodes, + std::map<int, int> & nodeIndexMap, std::vector<Eigen::Triplet <double>> & k_tripletList, + const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> & K_matrix); + +// the "full_f_vector" and "full_K_matrix" are reduced in "reduced_f_vector" and "reduced_K_matrix" respectively, +// taking into account the dirichlet boundary conditions contained in "dir_BC". +// "new_DOFindices" gathers the new indices of the DOFs when taking the boundary conditions into account. +void fillReducedKf(const std::vector<double> & full_f_vector, const Eigen::SparseMatrix<double> & full_K_matrix, + const std::vector<int> & new_DOFindices, const std::vector<double> & dir_BC, + Eigen::SparseMatrix<double> & reduced_K_matrix, std::vector<double> & reduced_f_vector); + +// computing the elemental-nodal strains and stresses in the FEM domain (dimension "dim" and entity tags "tags"), +// based on Hooke's matrix in plane stress "H_matrix", Young's modulus "E", Poisson's ratio "nu", and the full nodal +// displacement vector "full_d_vector" and the global nodal index map "nodeIndexMap". +// "nbelems" is the number of 2D elements contained in the FEM domain. +// returning the "max_VM_stress" and the corresponding nodetag "max_VM_nodeTag". +void computeStressStrainLinearWay(const int & dim, const std::vector<int> & tags, const std::vector<double> &full_d_vector, + const Eigen::Matrix<double, 3, 3> &H_matrix, const double &nu, const double &E, + std::map<int, int> & nodeIndexMap, const int &nbelems, double &max_VM_stress, int &max_VM_nodeTag); + +// computing the total (internal) strain energy "strain_energy" in the whole FEM domain (dimension "dim" and +// entity tags "tags"), using the nodal displacements in "full_d_vector". The nodes are indexed using the "nodeIndexMap". +// The Hooke's matrix in plane stress "H_matrix" is used to compute the stresses from the strains. +// Computed as a sum of integrals over the finite elements, using Gauss integration "integration_rule". +void computeStrainEnergyLinearWay(double & strainEnergy, const int & dim, const std::vector<int> & tags, + const std::vector<double> &full_d_vector, const Eigen::Matrix<double, 3, 3> &H_matrix, + std::map<int, int> & nodeIndexMap, const std::string & integration_rule); \ No newline at end of file diff --git a/srcs/FEM/large_rotation_validation.geo b/srcs/FEM/large_rotation_validation.geo new file mode 100644 index 0000000000000000000000000000000000000000..113db4e8a52d2345b5b8075dc49a0b23ff2dab77 --- /dev/null +++ b/srcs/FEM/large_rotation_validation.geo @@ -0,0 +1,88 @@ + +h = 1; +H = 10; + +n = 16; + +Point(1) = {0, 0, 0, 0.5}; +Point(2) = {0.9*H, 0, 0, 0.5}; +Point(3) = {0.9*H, h, 0, 0.5}; +Point(4) = {0, h, 0, 0.5}; + +Point(5) = {0.95*H, 0, 0, 0.5}; +Point(6) = {0.95*H, h, 0, 0.5}; + +Point(7) = {0.95*H, H, 0, 0.5}; +Point(8) = {0.9*H, H, 0, 0.5}; + +Point(9) = {H, 0, 0, 0.5}; +Point(10) = {H, h, 0, 0.5}; +Point(11) = {H, H, 0, 0.5}; + +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; +Curve Loop(1) = {1, 2, 3, 4}; +Plane Surface(1) = {1}; + +Line(5) = {2, 5}; +Line(6) = {5, 6}; +Line(7) = {6, 3}; +Curve Loop(2) = {5, 6, 7, -2}; +Plane Surface(2) = {2}; + +Line(8) = {6, 7}; +Line(9) = {7, 8}; +Line(10) = {8, 3}; +Curve Loop(3) = {-7, 8, 9, 10}; +Plane Surface(3) = {3}; + +Line(11) = {5, 9}; +Line(12) = {9, 10}; +Line(13) = {10, 6}; +Curve Loop(4) = {11, 12, 13, -6}; +Plane Surface(4) = {4}; + +Line(14) = {10, 11}; +Line(15) = {11, 7}; +Curve Loop(5) = {14, 15, -8, -13}; +Plane Surface(5) = {5}; + +Transfinite Curve {1, 3, 8, 10, 14} = 18*n+1 Using Progression 1; +Transfinite Curve {2, 4, 6, 12} = 2*n+1 Using Progression 1; +Transfinite Curve {5, 7, 9, 11, 13, 15} = n+1 Using Progression 1; +Transfinite Surface {1}; +Transfinite Surface {2}; +Transfinite Surface {3}; +Transfinite Surface {4}; +Transfinite Surface {5}; + +Recombine Surface {1}; +Recombine Surface {2}; +Recombine Surface {3}; +Recombine Surface {4}; +Recombine Surface {5}; + +Physical Curve("left_edge", 1) = {4}; +Physical Surface("FEM_domain", 2) = {1, 2, 3, 4, 5}; // the trick is to include both plane surfaces in one single domain +Physical Curve("top_edge", 3) = {9, 15}; + +Physical Point("point_A", 5) = {7}; + +F = 40000; + +// additional parameters given to the solver +SetNumber("Boundary Conditions/left_edge/ux", 0.); // ALWAYS NEED TO IMPOSE BOTH ux AND uy ON A GIVEN EDGE !! (pas très réaliste, faut y réfléchir) +SetNumber("Boundary Conditions/left_edge/uy", 0.); +SetNumber("Materials/FEM_domain/Young", 3e7); +SetNumber("Materials/FEM_domain/Poisson", 0.3); +SetNumber("Materials/FEM_domain/rho",7800); //volumic mass of acier +SetNumber("Boundary Conditions/top_edge/tx", F); // ALWAYS NEED TO IMPOSE BOTH tx AND ty ON A GIVEN EDGE (realiste, OK) ! +SetNumber("Boundary Conditions/top_edge/ty", 0); //set to some other value for vertical deflection +SetNumber("Volumic Forces/FEM_domain/bx",0.); +SetNumber("Volumic Forces/FEM_domain/by",0.); //set to -9.81 for gravity + +SetNumber("Non_linear_solver",1); // activate non linear solver + +Physical Curve("BEM_FEM_boundary", 4) = {4}; \ No newline at end of file diff --git a/srcs/FEM/large_rotation_validation_single_surface.geo b/srcs/FEM/large_rotation_validation_single_surface.geo new file mode 100644 index 0000000000000000000000000000000000000000..d15291b19f3553b05de6fcccd5bd78e967e6b1a7 --- /dev/null +++ b/srcs/FEM/large_rotation_validation_single_surface.geo @@ -0,0 +1,56 @@ + +h = 1; +H = 2; + +n = 10; + +Point(1) = {0, 0, 0, 0.5}; +Point(2) = {(H-h), 0, 0, 0.5}; +Point(3) = {H-h, h, 0, 0.5}; +Point(4) = {0, h, 0, 0.5}; + +Point(5) = {H, 0, 0, 0.5}; +Point(6) = {H, h, 0, 0.5}; + +Point(7) = {H, H, 0, 0.5}; +Point(8) = {H-h, H, 0, 0.5}; + +Line(1) = {1, 2}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; + +Line(5) = {2, 5}; +Line(6) = {5, 6}; + +Line(8) = {6, 7}; +Line(9) = {7, 8}; +Line(10) = {8, 3}; + +Curve Loop(1) = {1, 5, 6, 8, 9, 10, 3, 4}; +Plane Surface(1) = {1}; + +Transfinite Curve {1, 3, 8, 10} = (H-h)*n+1 Using Progression 1; +Transfinite Curve {4, 5, 6, 9} = n+1 Using Progression 1; + +Recombine Surface {1}; + +Physical Curve("left_edge", 1) = {4}; +Physical Surface("FEM_domain", 2) = {1}; // the trick is to include both plane surfaces in one single domain +Physical Curve("top_edge", 3) = {9}; + +F = 40000; + +// additional parameters given to the solver +SetNumber("Boundary Conditions/left_edge/ux", 0.); // ALWAYS NEED TO IMPOSE BOTH ux AND uy ON A GIVEN EDGE !! (pas très réaliste, faut y réfléchir) +SetNumber("Boundary Conditions/left_edge/uy", 0.); +SetNumber("Materials/FEM_domain/Young", 3e7); +SetNumber("Materials/FEM_domain/Poisson", 0.3); +SetNumber("Materials/FEM_domain/rho",7800); //volumic mass of acier +SetNumber("Boundary Conditions/top_edge/tx", F); // ALWAYS NEED TO IMPOSE BOTH tx AND ty ON A GIVEN EDGE (realiste, OK) ! +SetNumber("Boundary Conditions/top_edge/ty", 0); //set to some other value for vertical deflection +SetNumber("Volumic Forces/FEM_domain/bx",0.); +SetNumber("Volumic Forces/FEM_domain/by",0.); //set to -9.81 for gravity + +Physical Curve("BEM_FEM_boundary", 4) = {4};//+ + +Mesh.Algorithm = 8; diff --git a/srcs/FEM/mainFEM.cpp b/srcs/FEM/mainFEM.cpp index afa5756ec2b98155936a32737447af80df724c0b..3883e6b5f063b324b5d6f5f445e0dd7ee0f257ad 100644 --- a/srcs/FEM/mainFEM.cpp +++ b/srcs/FEM/mainFEM.cpp @@ -4,17 +4,18 @@ #include <iostream> #include <omp.h> +// this program implements a FEM solver, either linear or non-linear (by taking large displacements into account) +// to choose the linear solver, please add: SetNumber("Non_linear_solver",0); in the .geo file. int main(int argc, char **argv) { - - bool nonLinearSolver = true; // use non-linear solver or not - if (argc < 2) { std::cout << "Usage: " << argv[0] << " <geo_file>\n"; return 0; } + double start = omp_get_wtime(); + // If compiled with OpenMP support, gmsh::initialize // also sets the number of threads to "General.NumThreads". int nthreads = omp_get_max_threads(); @@ -26,22 +27,32 @@ int main(int argc, char **argv) Eigen::initParallel(); + // determine if non linear solver must be set + bool nonLinearSolver = getNonLinearParameter(); + + // maps the elementTags to a corresponding electrostaticPressure (only useful for coupled solver) std::map<int, double> electrostaticPressure; + int nbViews = 0; // number of views passed to the BEM solver (only useful for coupled solver) + if(nonLinearSolver) { - std::map<int,std::pair<double,double>> boundaryDisplacementMap; + std::map<int,std::pair<double,double>> boundaryDisplacementMap; //(only useful for coupled solver) - int viewTagU = gmsh::view::add("u"); // à modifier plus tard - int viewTagF = gmsh::view::add("f"); + int viewTagU = gmsh::view::add("u"); //viewtag of the displacement view + int viewTagF = gmsh::view::add("f"); //viewtag of the nodal forces view - solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, 0, true, 1, viewTagU, viewTagF); //iteration randomly set to 1 + solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, nbViews, true, 1, viewTagU, viewTagF, false); } else { - solverFEM(electrostaticPressure, 0); + solverFEM(electrostaticPressure, nbViews); } + double total_time = omp_get_wtime() - start; + std::cout << "-----------------------------------------\n"; + std::cout << "total execution time: " << total_time << " [s]. \n"; + gmsh::fltk::run(); gmsh::finalize(); diff --git a/srcs/FEM/my_geo.geo b/srcs/FEM/my_geo.geo index e35f149294f371474652ecb2ff64bd827a7d2ae2..fde90809eae403a3dd4574e691689a4ee1ed5da6 100644 --- a/srcs/FEM/my_geo.geo +++ b/srcs/FEM/my_geo.geo @@ -1,7 +1,7 @@ -Lx = 5; -Ly = 2; -nx = 5; // prend beaucoup de temps à pd de 200x40 -ny = 2; +Lx = 2; +Ly = 1; +nx = 16; // prend beaucoup de temps à pd de 200x40 +ny = 8; Point(1) = {0, 0, 0, 0.1}; Point(2) = {Lx, 0, 0, 0.1}; @@ -21,7 +21,7 @@ Recombine Surface {1}; // quads instead of triangles Mesh.ElementOrder = 1; -Physical Curve("left_edge", 5) = {4,5}; +Physical Curve("left_edge", 5) = {4}; Physical Surface("FEM_domain", 6) = {1}; Physical Curve("top_edge", 7) = {3}; Physical Curve("right_edge", 8) = {2}; @@ -29,17 +29,17 @@ Physical Point("fixed_node", 9) = {1}; // additional parameters given to the solver SetNumber("Boundary Conditions/left_edge/ux", 0.); // HERE YOU DO NOT HAVE TO IMPOSE BOTH ux and uy simultaneously ! (permet aussi de simuler appuis à roulettes) -//SetNumber("Boundary Conditions/left_edge/uy", 2.); +//SetNumber("Boundary Conditions/left_edge/uy", 0.); SetNumber("Materials/FEM_domain/Young", 210e3); SetNumber("Materials/FEM_domain/Poisson", 0.3); SetNumber("Materials/FEM_domain/rho",7800); //volumic mass of acier SetNumber("Boundary Conditions/top_edge/tx", 0.); // ALWAYS NEED TO IMPOSE BOTH tx AND ty ON A GIVEN EDGE (realiste, OK) ! SetNumber("Boundary Conditions/top_edge/ty", 0.); //set to some non-zero value to induce vertical deflection SetNumber("Boundary Conditions/right_edge/tx", 21e3); // for simple tension conditions -SetNumber("Boundary Conditions/right_edge/ty", 0.); -SetNumber("Volumic Forces/FEM_domain/bx",0.); +SetNumber("Boundary Conditions/right_edge/ty", 0); +SetNumber("Volumic Forces/FEM_domain/bx",0); SetNumber("Volumic Forces/FEM_domain/by",0.); //set to -9.81 for gravity -SetNumber("Boundary Conditions/fixed_node/uy",0.02); -//SetNumber("Boundary Conditions/fixed_node/uy",0.); +//SetNumber("Boundary Conditions/fixed_node/ux",0.); +SetNumber("Boundary Conditions/fixed_node/uy",2.); Physical Curve("BEM_FEM_boundary", 10) = {1,2,3}; \ No newline at end of file diff --git a/srcs/FEM/self_weight.geo b/srcs/FEM/self_weight.geo index d50925376b3a42a31e2508c7fa480d9ccdfba644..c04a6a8a44f4dd0dc62137b00f36ea44a94cd666 100644 --- a/srcs/FEM/self_weight.geo +++ b/srcs/FEM/self_weight.geo @@ -37,4 +37,6 @@ SetNumber("Boundary Conditions/right_edge/ty", 0.); SetNumber("Volumic Forces/FEM_domain/bx",0.); SetNumber("Volumic Forces/FEM_domain/by",-9.81); //set to -9.81 for gravity -Physical Curve("BEM_FEM_boundary", 9) = {1,2,3}; // useless but necessary to make it work \ No newline at end of file +Physical Curve("BEM_FEM_boundary", 9) = {1,2,3}; // useless but necessary to make it work + +SetNumber("Non_linear_solver", 1); \ No newline at end of file diff --git a/srcs/FEM/simple_tension.geo b/srcs/FEM/simple_tension.geo index 18783ae0b69b461a559836c84cbd892676cec6a4..f1452e518608936d6c4b17101e93a32c0f296abd 100644 --- a/srcs/FEM/simple_tension.geo +++ b/srcs/FEM/simple_tension.geo @@ -1,7 +1,7 @@ Lx = 5; Ly = 2; -nx = 5; -ny = 2; +nx = 50; +ny = 20; Point(1) = {0, 0, 0, 1.0}; Point(2) = {Lx, 0, 0, 1.0}; @@ -39,6 +39,8 @@ SetNumber("Boundary Conditions/right_edge/tx", 21e3); // for simple tension cond SetNumber("Boundary Conditions/right_edge/ty", 0.); SetNumber("Volumic Forces/FEM_domain/bx",0.); SetNumber("Volumic Forces/FEM_domain/by",0.); //set to -9.81 for gravity -SetNumber("Boundary Conditions/fixed_node/uy",0.); +SetNumber("Boundary Conditions/fixed_node/uy",2.); Physical Curve("BEM_FEM_boundary", 10) = {1,2,3}; // useless in this case but necessary to make it work + +SetNumber("Non_linear_solver",1); \ No newline at end of file diff --git a/srcs/FEM/solverFEM.cpp b/srcs/FEM/solverFEM.cpp index 7df3c0d51742e28e2a33cfd2ce20f54effba1cbb..97bcda367a82fab7ef26824712b9e056fac5069f 100644 --- a/srcs/FEM/solverFEM.cpp +++ b/srcs/FEM/solverFEM.cpp @@ -1,23 +1,35 @@ #include "functionsFEM.hpp" #ifdef _MSC_VER -#include <gmsh.h_cwrap> // gmsh main header +#include <gmsh.h_cwrap> #else -#include <gmsh.h> // gmsh main header +#include <gmsh.h> #endif -#include <iostream> // for std::cout +#include <iostream> #include <map> -#include <sstream> // for std::stringstream -#include <Eigen/Dense> // Eigen library -#include <Eigen/Sparse> // Eigen library for sparse matrices -#include <Eigen/SparseCholesky> // solving sparse linear systems +#include <sstream> +#include <Eigen/Dense> +#include <Eigen/Sparse> +#include <Eigen/SparseCholesky> #include <Eigen/Core> #include <cmath> -#include <algorithm> // to sort and merge the FEM node vectors +#include <algorithm> #include <omp.h> -void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<int,std::pair<double,double>> & boundaryDisplacementMap, const int nbViews, bool postProcessing, const int iteration, const int viewTagU, const int viewTagF) +// solves the non-linear (large displacements, no large deformations) elastic problem. +// if coupled to the BEM solver, "electrostaticPressure" is the pressure computed from the electric field +// on the BEM_FEM boundary (mapping element tag -> pressure). "boundaryDisplacementMap" is filled for all +// nodes on the BEM_FEM_boundary as (node tag -> (u,v) displacement) +// "nbViews" is the current number of views already allocated in the gmsh window. +// "postProcessing" boolean activates the post processing operations (must only be computed once at the end of the +// coupled solver). "iteration" denotes the current iteration of the two-way coupled solver (starting at 1). +// "viewTagU" and "viewTagF" correspond to the view tags of the nodal displacements and the nodal forces in the gmsh window. +// when "untangleMesh" is activated, the nodal coordinates of the nodes in the FEM_domain are updated according to +// their final nodal displacements. +void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, + std::map<int,std::pair<double,double>> & boundaryDisplacementMap, int &nbViews, bool postProcessing, + const int iteration, const int viewTagU, const int viewTagF, bool untangleMesh) { /*--------------INITIALIZATION OF ITERATIVE ALGORITHM----------------*/ /* FIRST STEP: @@ -26,17 +38,15 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i - initialize the full d vector with Dirichlet boundary conditions and set pg = 0 - important remark: in pg we focus only on the free DOFs (we do not focus on the DOFs fixed by dirichlet BCs)*/ - bool openGUI = false; // Graphical interface of GMSH. + bool display_time = false; //displays time of every different step of the algorithm + bool validation = false; //retrieves displacement of point A for large_rotation_validation.geo - //double start = omp_get_wtime(); - int max_threads = omp_get_max_threads(); + double start = omp_get_wtime(); + /*--------Integration rule used in the code for surface integration (neumann BC)----------*/ + std::string integration_rule = "CompositeGauss4"; - /*--------Integration rule used in the code----------*/ - // could be useful to pass it as an argument in the .geo file - std::string integration_rule = "CompositeGauss4"; // tested with other methods, OK too. - - /*--------get physical groups--------------*/ + /*--------get all physical groups--------------*/ std::map<std::string, std::pair<int, int>> groups; gmsh::vectorpair dimTags; gmsh::model::getPhysicalGroups(dimTags); @@ -50,41 +60,16 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i } /*--------get nodes related to FEM-----------------*/ - std::string groupname = "FEM_domain"; // we consider the domain as containing the FEM 2d model + std::string groupname = "FEM_domain"; // we consider the FEM_domain as containing the FEM 2d model int dim = groups[groupname].first; int tag = groups[groupname].second; + // Getting entities of the domain to fill FEM_nodeTags + std::vector<int> tags; + gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - //loop over the entities of the domain to retrieve all nodeTags by taking care not to take some nodes twice - //using sort and set_union methods + retrieving the node coordinates and storing them in a map std::vector<std::size_t> FEM_nodeTags; - std::vector<double> FEM_nodecoord; - std::vector<double> FEM_nodeparametricCoord; std::map<int,std::pair<double,double>> FEM_nodeCoordsMap; // nodeTag -> (x,y) - // Getting entities of the domain to fill FEM_nodeTags, en faire une fonction ? - std::vector<int> tags; - gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - std::vector<std::vector<std::size_t>> tmp_nodeTags(tags.size()); // will store the nodeTags associated to one given entity of the domain - gmsh::model::mesh::getNodes(tmp_nodeTags[0], FEM_nodecoord, FEM_nodeparametricCoord, dim, tags[0], true); - for(std::size_t j = 0; j < tmp_nodeTags[0].size(); j++) - { - FEM_nodeCoordsMap[tmp_nodeTags[0][j]] = std::pair<double, double>(FEM_nodecoord[3*j], FEM_nodecoord[3*j+1]); - } - std::sort(tmp_nodeTags[0].begin(), tmp_nodeTags[0].end()); // need to sort the vectors in order to merge them afterwards - for (std::size_t i = 1; i < tags.size(); i++) - { // in the case the domain contains multiple entities - gmsh::model::mesh::getNodes(tmp_nodeTags[i], FEM_nodecoord, FEM_nodeparametricCoord, dim, tags[i], true); - for(std::size_t j = 0; j < tmp_nodeTags[i].size(); j++) - { - FEM_nodeCoordsMap[tmp_nodeTags[i][j]] = std::pair<double, double>(FEM_nodecoord[3*j], FEM_nodecoord[3*j+1]); - } - std::sort(tmp_nodeTags[i].begin(), tmp_nodeTags[i].end()); - std::set_union(tmp_nodeTags[i-1].begin(), tmp_nodeTags[i-1].end(), - tmp_nodeTags[i].begin(), tmp_nodeTags[i].end(), std::back_inserter(FEM_nodeTags)); - - } - if(tags.size() == 1){ // if the domain contains one single entity - FEM_nodeTags = tmp_nodeTags[0]; - } + RetrieveFEMNodeTagsAndCoords(FEM_nodeTags, FEM_nodeCoordsMap, dim, tags); /*-----get elements related to FEM--------------*/ std::vector<std::size_t> FEM_elementTags; @@ -92,6 +77,11 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i // map is initialized, see functionsFEM.hpp for structure of elementData type int nbelems = initKinematics(FEM_elementTags, FEM_kinematicsMap, FEM_nodeCoordsMap, dim, tags); + if(iteration == 1) + { + std::cout << "The FEM domain contains " << nbelems << " element(s) and " << FEM_nodeTags.size() << " nodes\n"; + } + /*-------map between nodeTag and index of first nodal displacement associated to the node (second one is the same +1)------*/ std::map<int, int> nodeIndexMap; for (std::size_t i = 0; i < FEM_nodeTags.size(); ++i) @@ -102,20 +92,18 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i } /*-----------get physical properties of domain----------------------*/ - std::vector<std::string> keys; - gmsh::onelab::getNames(keys, "(Volumic Forces|Materials).+"); double E = 0; // Young modulus double nu = 0; // Poisson ratio double rho = 0; // volumic mass double bx = 0; // volumic force along x axis double by = 0; // volumic force along y axis - - getPhysicalProperties(keys, E, nu, rho, bx, by); + getPhysicalProperties(E, nu, rho, bx, by); /*-----------------H matrix involved in stress computation------------------*/ Eigen::Matrix<double, 3, 3> H_matrix = computeHmatrix(E, nu); - //double startbis = omp_get_wtime(); - //std::cout << "preliminary: " << startbis-start << "\n"; + double start2 = omp_get_wtime(); + std::string step_name = "initialization of global variables"; + displayTime(start, start2, step_name, display_time); /*------------computing full f vector------------------------*/ // we first consider volumic part of the f vector, computed simultaneously with local K matrices @@ -125,62 +113,44 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i full_f_vector[i] = 0; } - std::vector<std::list<Eigen::Triplet <double>>> my_k_list(max_threads); - std::vector<std::list<std::pair<int,double>>> thread_f_vector(max_threads); + // Looping over entities of FEM_dimain and computing local K matrices and volumic f vector + fillElementalKandF(H_matrix, rho, bx, by, dim, tags, nodeIndexMap, full_f_vector, FEM_kinematicsMap); - // Looping over entities and compute local K matrices and volumic f vector - fillElementalKandF(H_matrix, rho, bx, by, integration_rule, dim, tags, nodeIndexMap, my_k_list, thread_f_vector, FEM_kinematicsMap); - - for(int i = 0; i < max_threads; i++){ - std::list<std::pair<int,double>> &tmp_vector = thread_f_vector[i]; - for(auto &p : tmp_vector) { - full_f_vector[p.first] += p.second; - } - } - - //double start2 = omp_get_wtime(); - //std::cout << "time for K assembly: " << start2-startbis << "\n"; + double start3 = omp_get_wtime(); + step_name = "volumic f and elemental Kl"; + displayTime(start2, start3, step_name, display_time); /*-----------------BOUNDARY CONDITIONS------------*/ /*-----------get group_names related to BC's----------------------*/ - gmsh::onelab::getNames(keys, "(Boundary Conditions).+"); + std::vector<std::string> BCkeys; + gmsh::onelab::getNames(BCkeys, "(Boundary Conditions).+"); /*-----------first focus on neumann BC's (surface traction) into full_f_vector------------*/ - includeNeumannBC(keys, integration_rule, nodeIndexMap, groups, full_f_vector); - - //double start3 = omp_get_wtime(); - //std::cout << "time for neumann: " << start3 - start2 << "\n"; + includeNeumannBC(BCkeys, integration_rule, nodeIndexMap, groups, full_f_vector); - /* taking ELECTROSTATIC PRESSURE */ - if(electrostaticPressure.size() != 0) + /* taking ELECTROSTATIC PRESSURE into account */ + if(electrostaticPressure.size() != 0) // size == 0 if FEM solver used alone applyElecPressure(integration_rule, FEM_nodeCoordsMap, nodeIndexMap, groups, electrostaticPressure, full_f_vector); - //double start4 = omp_get_wtime(); - //std::cout << "time for elec pressure: " << start4 - start3 << "\n"; + double start4 = omp_get_wtime(); + step_name = "Neumann BC and elec pressure"; + displayTime(start3, start4, step_name, display_time); /*------------FOCUS ON DIRICHLET BC'S---------------*/ // new_DOFindices vector will contain the new indices of the K matrix after the rows/columns corresponding // to dirichlet boundary conditions have been removed // IN THIS IMPLEMENTATION WE DECIDE TO REMOVE EVERY ROW/COL ASSOCIATED TO DIR. BC's - // non-homo. dir BC will induce a correction in the RHS term f of the other rows, while homogeneous not + // non-homo. dir BC will induce a correction in the RHS term f of the other rows, while homogeneous not, // if the given index has been removed, it will be set to -1 in new_DOFindices std::vector<int> new_DOFindices(2*FEM_nodeTags.size()); // dir_BC[index] will contain the dirichlet boundary condition prescribed to this node std::vector<double> dir_BC(2*FEM_nodeTags.size()); - // Fill the two vectors defined just above - fillDOFindicesDirBC(keys, nodeIndexMap, groups, new_DOFindices, dir_BC); - + // Fills the two vectors defined just above int number_removed_lines = 0; - for (std::size_t j = 0; j < new_DOFindices.size(); ++j){ - if(new_DOFindices[j] < 0){ // line has to be removed - number_removed_lines++; - } - else{ - new_DOFindices[j] -= number_removed_lines; - } - } + fillDOFindicesDirBC(BCkeys, nodeIndexMap, groups, new_DOFindices, dir_BC, number_removed_lines); + // initializing the full_d_vector with the dirichlet boundary conditions std::vector<double> full_d_vector(2*FEM_nodeTags.size()); for (std::size_t j = 0; j < full_d_vector.size(); ++j){ if(new_DOFindices[j] < 0){ // line was previously removed due to dirichlet boundary conditions @@ -190,7 +160,7 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i full_d_vector[j] = 0; } } - // initializing the applied forces vector (will remain constant) and the global p (p_g) vector + // initializing the applied forces vector (will remain constant) and the global p vector (p_g) std::vector<double> f_app_vector(2*FEM_nodeTags.size() - number_removed_lines); std::vector<double> global_p_vector(2*FEM_nodeTags.size() - number_removed_lines); int nb_free_DOFs = 0; @@ -204,34 +174,36 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i } } - // computing the norm of the applied forces vector - double f_app_norm = 0; - for(size_t i = 0; i < f_app_vector.size(); i++) - { - f_app_norm += f_app_vector[i]*f_app_vector[i]; - } - f_app_norm = sqrt(f_app_norm); - std::cout << "f app norm: " << f_app_norm << "\n"; - - std::vector<double> global_f_vector(nb_free_DOFs); - + // useful during the iterative process + std::vector<double> global_f_vector(nb_free_DOFs); // f_g Eigen::Matrix<double, Eigen::Dynamic, 1> residual(nb_free_DOFs, 1); - double residualNorm = 100000000; // hardcoded and arbitrary - double residualTolerance = 2e-12; // empirical - - /*double max_applied_force = 0; - for(int i = 0; i < nb_free_DOFs; i++) + // useful for the stopping criterion + std::vector<double> previousTotalNodalForces(2*FEM_nodeTags.size()); + std::vector<double> currentTotalNodalForces(2*FEM_nodeTags.size()); + std::vector<double> relativeDifference(2*FEM_nodeTags.size()); + double relativeForces = 1e17; + double previousRelativeForces = 1e17; + double currentMaxNodalForce; + for(size_t i = 0; i < 2*FEM_nodeTags.size(); i++) { - if(abs(f_app_vector[i]) > max_applied_force) - max_applied_force = abs(f_app_vector[i]); + previousTotalNodalForces[i] = 0; + currentTotalNodalForces[i] = 0; } - std::cout << "max applied force: " << max_applied_force << "\n";*/ + double residualTolerance = 1e-12; // empirical + + double start5 = omp_get_wtime(); + step_name = "further initialization of global variables for the iterative algorithm"; + displayTime(start4, start5, step_name, display_time); /*---------ITERATIVE PART---------------*/ - int max_number_of_steps = 10; // purely arbitrary - for(int step = 0; step < max_number_of_steps; step++) + int max_number_of_steps = 200; // can be tuned + int step = 0; + + double num_diverged_steps = 0; // stores the number of times the residual has increased between two steps, after 5 times, + // we take the assumption it has converged towards an other value + for(step = 0; step < max_number_of_steps; step++) { /*------------STEP 2 of the algorithm----------------*/ /* @@ -240,7 +212,56 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i - compute the residual = norm(f_g - f_app)*/ /*--------- UPDATING KINEMATICS---------------*/ + double start_update = omp_get_wtime(); updateKinematics(FEM_kinematicsMap, full_d_vector, nodeIndexMap, FEM_elementTags); + double end_update = omp_get_wtime(); + step_name = "update kinematics"; + displayTime(start_update, end_update, step_name, display_time); + + + // stopping criterion: focussing on the iterative difference of the full nodal forces vector + for(size_t i = 0; i < 2*FEM_nodeTags.size(); i++) + { + previousTotalNodalForces[i] = currentTotalNodalForces[i]; + } + retrieveTotalNodalForces(currentTotalNodalForces, FEM_kinematicsMap, nodeIndexMap, FEM_elementTags); + double end_retrieveTotalForces = omp_get_wtime(); + step_name = "retrieve total nodal forces"; + displayTime(end_update, end_retrieveTotalForces, step_name, display_time); + + if(step > 1) + { + previousRelativeForces = relativeForces; + relativeForces = 0; + currentMaxNodalForce = 0; + for(size_t i = 0; i < 2*FEM_nodeTags.size(); i++) + { + if(previousTotalNodalForces[i] != 0.0) + relativeDifference[i] = abs( (currentTotalNodalForces[i] - previousTotalNodalForces[i])); + else + relativeDifference[i] = 0; + + if(abs(currentTotalNodalForces[i]) > currentMaxNodalForce) + currentMaxNodalForce = abs(currentTotalNodalForces[i]); + + relativeForces += relativeDifference[i]*relativeDifference[i]; + } + if(currentMaxNodalForce > 0) + relativeForces = sqrt(relativeForces/(2*FEM_nodeTags.size())/currentMaxNodalForce); // norm made relative + else //to avoid division by zero + relativeForces = 1e17; + std::cout << "step: " << step << ", relativeForces: " << relativeForces << "\n"; + + if(previousRelativeForces < relativeForces) //the current step induces an increase of nodal difference + { + num_diverged_steps++; + if(num_diverged_steps == 5) + { + std::cout << "-----------------------------------------\n"; + std::cout << "Pay attention, the differential residual has not reached the tolerance of " << residualTolerance << ", it has converged towards: " << relativeForces << ", after " << step <<" steps\n"; + } + } + } /*--------COMPUTING AND ASSEMBLING THE GLOBAL F VECTOR BASED ON PREVIOUS ITERATION-----------*/ for(int i = 0; i < nb_free_DOFs; i++) @@ -249,173 +270,217 @@ void solverFEMnonLinear(std::map<int, double> &electrostaticPressure, std::map<i } assembleGlobalF(global_f_vector, FEM_kinematicsMap, nodeIndexMap, new_DOFindices, FEM_elementTags); - residualNorm = computeResidualNorm(global_f_vector, f_app_vector, residual); + // computing the residual + for(size_t i = 0; i < global_f_vector.size(); i++) + { + residual(i,0) = global_f_vector[i] - f_app_vector[i]; + } - std::cout << "residual value: " << residualNorm/f_app_norm << "\n"; + double end_assembleglobalf = omp_get_wtime(); + step_name = "assemble global f and residual norm"; + displayTime(end_retrieveTotalForces, end_assembleglobalf, step_name, display_time); /*------------STEP 3: EVALUATING THE RESIDUAL, have we converged ??----------*/ - if (residualNorm/f_app_norm < residualTolerance) - break; + if ((relativeForces < residualTolerance && step > 0) || num_diverged_steps == 5) + break; /*------------STEP 4: ASSEMBLING THE GLOBAL TANGENT STIFFNESS MATRIX----------*/ // it is assembled as a sparse matrix Eigen::SparseMatrix<double> global_tangent_matrix(nb_free_DOFs, nb_free_DOFs); assembleGlobalKg(global_tangent_matrix, FEM_kinematicsMap, nodeIndexMap, new_DOFindices, FEM_elementTags); + double end_assembleglobalKg = omp_get_wtime(); + step_name = "assemble global stiffness matrix"; + displayTime(end_assembleglobalf, end_assembleglobalKg, step_name, display_time); + //std::cout << "global tangent matrix: " << global_tangent_matrix << "\n"; /*-----------STEP 5: SOLVING THE SYSTEM----------*/ Eigen::Matrix<double, Eigen::Dynamic, 1> global_delta_p(nb_free_DOFs, 1); - // solve Kg*Deltapg=-res + // solve Kg*Deltapg=-res, using a direct sparse Cholesky factorization, + // efficient for sparse positive semi-definite matrix Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver; solver.compute(global_tangent_matrix); global_delta_p = solver.solve(-residual); + double end_solve = omp_get_wtime(); + step_name = "solving the system"; + displayTime(end_assembleglobalKg, end_solve, step_name, display_time); + /*----------STEP 6: updating the global p vector and the full d vector of nodal values-----------*/ for(size_t i = 0; i < global_p_vector.size(); i++) { global_p_vector[i] += global_delta_p(i,0); } updateNodalDispVector(full_d_vector, global_p_vector, new_DOFindices); + + double end_updateNodalDisp = omp_get_wtime(); + step_name = "updating the nodal disp vector"; + displayTime(end_solve, end_updateNodalDisp, step_name, display_time); } + + if(step == max_number_of_steps) + { + std::cout << "-----------------------------------------\n"; + std::cout << "Pay attention, the differential residual has not reached the tolerance of " << residualTolerance << ", final value: " << relativeForces << "\n"; + } + + double start_postPro = omp_get_wtime(); //updating the kinematics according to the results of last iteration updateKinematics(FEM_kinematicsMap, full_d_vector, nodeIndexMap, FEM_elementTags); /*--------------COMPUTING NODAL FORCES-------------*/ std::vector<double> final_nodal_forces(2*FEM_nodeTags.size()); - retrieveFinalNodalForces(final_nodal_forces, FEM_kinematicsMap, nodeIndexMap, FEM_elementTags); - - /*--------------RETRIEVING NODAL DISPLACEMENTS ON BEM-FEM BOUNDARY------------*/ - //those displacements will be sent to the BEM code in the non-linear iterative solver - //std::map<int,std::pair<double,double>> boundaryDisplacementMap; - // mapping nodeTag (of node on the boundary) into (u,v) displacements of the node - retrieveBoundaryDisplacements(boundaryDisplacementMap, full_d_vector, nodeIndexMap, groups); + retrieveTotalNodalForces(final_nodal_forces, FEM_kinematicsMap, nodeIndexMap, FEM_elementTags); std::vector<std::string> names; gmsh::model::list(names); + /*-------------POST PROCESSING---------------------*/ if(postProcessing) { - /*--------------REACTION FORCES COMPUTATION------------------*/ - computeReactionForces(groups, nodeIndexMap, final_nodal_forces, keys); + // retrieving and displaying maximal nodal displacement + double max_disp = 0; + double max_u = 0; + double max_v = 0; + int max_disp_nodeTag = 0; - //double start5 = omp_get_wtime(); - //std::cout << "time for rest: " << start5 - start4 << "\n"; + for(size_t i = 0; i < FEM_nodeTags.size(); i++) + { + double tmp_index = nodeIndexMap[FEM_nodeTags[i]]; + double tmp_disp = full_d_vector[tmp_index]*full_d_vector[tmp_index] + full_d_vector[tmp_index + 1]*full_d_vector[tmp_index + 1]; + if (tmp_disp > max_disp) + { + max_disp = tmp_disp; + max_disp_nodeTag = FEM_nodeTags[i]; + max_u = full_d_vector[tmp_index]; + max_v = full_d_vector[tmp_index + 1]; + } + } + std::cout << "-----------------------------------------\n"; + std::cout << "maximal nodal displacement (u,v) = (" << max_u << "," << max_v << ") [m], at node " << max_disp_nodeTag << "\n"; + + /*--------------REACTION FORCES COMPUTATION------------------*/ + computeReactionForces(groups, nodeIndexMap, final_nodal_forces, BCkeys); /*--------------PLOTTING NODAL VALUES------------------*/ - plotUxUy(FEM_nodeTags, full_d_vector, nbViews, names); + plotUxUy(FEM_nodeTags, full_d_vector, names); /*-------------POST PROCESSING---------------*/ - /*-------------Computing and saving strains/stresses-----------------*/ - - - /*-------------------ELEMENTAL-NODAL VALUES-----------------------*/ - // éventuellement faire un tableau ici qui regroupe tout le bazar pour ne pas avoir la même ligne 7 fois ... - int viewtag3 = gmsh::view::add("nodal_eps_x"); - int viewtag4 = gmsh::view::add("nodal_eps_y"); - int viewtag5 = gmsh::view::add("nodal_eps_xy"); - int viewtag6 = gmsh::view::add("nodal_eps_z"); - int viewtag7 = gmsh::view::add("nodal_sig_x"); - int viewtag8 = gmsh::view::add("nodal_sig_y"); - int viewtag9 = gmsh::view::add("nodal_sig_xy"); - int viewtag10 = gmsh::view::add("nodal_sig_VM"); - std::vector<std::vector<double>> data3(nbelems); - std::vector<std::vector<double>> data4(nbelems); - std::vector<std::vector<double>> data5(nbelems); - std::vector<std::vector<double>> data6(nbelems); - std::vector<std::vector<double>> data7(nbelems); - std::vector<std::vector<double>> data8(nbelems); - std::vector<std::vector<double>> data9(nbelems); - std::vector<std::vector<double>> data10(nbelems); - std::vector<std::size_t> elems2D(nbelems); - - std::vector<int> elementTypes; - std::vector<std::vector<std::size_t>> elementTags; - std::vector<std::vector<std::size_t>> elnodeTags; - - // computing the elemental nodal data for each physical group of the domain - int k = 0; // current index of data vectors, k is incremented in computeStressStrainElNodal at each element - for(std::size_t i=0; i< tags.size(); ++i) - { - gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[i]); - computeStressStrainElNodal(elementTypes, elementTags, elnodeTags, elems2D, H_matrix, - nu, E, FEM_kinematicsMap, data3, data4, data5, data6, data7, data8, data9, data10, k); - } - - gmsh::view::addModelData(viewtag3, 0, names[0], "ElementNodeData", - elems2D, data3, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag4, 0, names[0], "ElementNodeData", - elems2D, data4, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag5, 0, names[0], "ElementNodeData", - elems2D, data5, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag6, 0, names[0], "ElementNodeData", - elems2D, data6, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag7, 0, names[0], "ElementNodeData", - elems2D, data7, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag8, 0, names[0], "ElementNodeData", - elems2D, data8, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag9, 0, names[0], "ElementNodeData", - elems2D, data9, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag10, 0, names[0], "ElementNodeData", - elems2D, data10, 1); // the last ,1 is important! - } - // representing vector displacement field and nodal forces - //int viewTagU = gmsh::view::add("u"); - //int viewTagF = gmsh::view::add("f"); - std::vector<std::vector<double>> data11(FEM_nodeTags.size()); - std::vector<std::vector<double>> data12(FEM_nodeTags.size()); + /*-------------Computing and saving elemental-nodal strains/stresses-----------------*/ + double max_VM_stress = 0; + int max_VM_nodeTag; + computeStressStrainElNodal(dim, tags, H_matrix, nu, E, FEM_kinematicsMap, nbelems, max_VM_stress, max_VM_nodeTag); + std::cout << "-----------------------------------------\n"; + std::cout << "maximal nodal von Mises stress: " << max_VM_stress << " [Pa], at node " << max_VM_nodeTag << "\n"; + + // retrieving work done by external forces + double externalWork = 0; + computeWorkDoneByExternalForces(externalWork, full_d_vector, final_nodal_forces); + std::cout << "-----------------------------------------\n"; + std::cout << "work done by external forces: " << externalWork << " [J/m].\n"; + + // strain energy + double strainEnergy = 0; + computeStrainEnergy(strainEnergy, dim, tags, FEM_kinematicsMap, H_matrix, integration_rule); + // peut etre pas OK en non-linear -> repartir des local displacements pour calculer tout ça + + std::cout << "-----------------------------------------\n"; + std::cout << "strain energy: " << strainEnergy << " [J/m].\n"; + + std::cout << "-----------------------------------------\n"; + std::cout << "Total potential energy: " << strainEnergy - externalWork << " [J/m].\n"; + } + // representing vector displacement field and nodal forces as vectorial quantities + std::vector<std::vector<double>> dataU(FEM_nodeTags.size()); + std::vector<std::vector<double>> dataF(FEM_nodeTags.size()); for (std::size_t i = 0; i < FEM_nodeTags.size(); ++i) { - data11[i].resize(3); - data12[i].resize(3); - data11[i][0] = full_d_vector[2*i]; //ux, here use NodeIndexMap - data11[i][1] = full_d_vector[2*i+1]; //uy - data11[i][2] = 0.; //uz - data12[i][0] = final_nodal_forces[2*i]; //fx - data12[i][1] = final_nodal_forces[2*i+1]; //fy - data12[i][2] = 0.; //fz + dataU[i].resize(3); + dataF[i].resize(3); + dataU[i][0] = full_d_vector[2*i]; //ux, here use NodeIndexMap + dataU[i][1] = full_d_vector[2*i+1]; //uy + dataU[i][2] = 0.; //uz + dataF[i][0] = final_nodal_forces[2*i]; //fx + dataF[i][1] = final_nodal_forces[2*i+1]; //fy + dataF[i][2] = 0.; //fz } gmsh::view::addModelData(viewTagU, iteration, names[0], "NodeData", - FEM_nodeTags, data11, iteration); //independent of time here + FEM_nodeTags, dataU, iteration); gmsh::view::addModelData(viewTagF, iteration, names[0], "NodeData", - FEM_nodeTags, data12, iteration); //independent of time here + FEM_nodeTags, dataF, iteration); if(postProcessing) { - // empeche que tout se plot l'un sur l'autre - int nb_views = 12 + nbViews; //hardcoded - for( int i = 0; i < nb_views; ++i){ + nbViews = 12 + nbViews; // FEM code adds 12 views + // avoiding that all the views are superposed + for( int i = 0; i < nbViews; ++i){ std::string my_string = "View[" + std::to_string(i) + "].Visible"; gmsh::option::setNumber(my_string, 0); } - gmsh::option::setNumber("View[0].VectorType", 5); // plot automatiquement sous forme de déplacement - gmsh::option::setNumber("View[0].RangeType", 3); // abscisses par step + gmsh::option::setNumber("View[0].VectorType", 5); // plot the displacement in deformed configuration + gmsh::option::setNumber("View[0].RangeType", 3); } + double end_postPro = omp_get_wtime(); + step_name = "post processing"; + displayTime(start_postPro, end_postPro, step_name, display_time); - if(openGUI && postProcessing) - gmsh::fltk::run(); // opens the gmsh window -} - + /*--------------RETRIEVING NODAL DISPLACEMENTS ON BEM-FEM BOUNDARY------------*/ + // those displacements will be sent to the BEM code in the non-linear iterative solver + // mapping nodeTag (of node on the boundary) into (u,v) displacements of the node + retrieveBoundaryDisplacements(boundaryDisplacementMap, full_d_vector, nodeIndexMap, groups); -void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews) -{ - /*--------------INIT----------------*/ + // if mesh untangler is activated, all nodal coordinates are updated according to their final + // nodal displacements. It is useful when coupled to the BEM solver in order to untangle + // the BEM domain and compute the potential field in the whole BEM domain adapted to the + // displacement of the FEM domain. + if(untangleMesh) + { + for(size_t i = 0; i < FEM_nodeTags.size(); i++) + { + std::vector<double> coord, parametricCoord; + int dim, tag; + gmsh::model::mesh::getNode(FEM_nodeTags[i], coord, parametricCoord, dim, tag); + std::vector<double> total_disp = {coord[0] + full_d_vector[2*i], coord[1] + full_d_vector[2*i + 1], coord[2]}; + gmsh::model::mesh::setNode(FEM_nodeTags[i], total_disp, {}); + } + } - bool openGUI = false; // Graphical interface of GMSH. + // it is only useful when using "large_rotation_validation.geo" file. + // printing the displacement of "point A" (see report for graph). + if(validation) + { + std::string groupname = "point_A"; + int dim = groups[groupname].first; + int tag = groups[groupname].second; + std::vector<int> tags; + gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); + std::vector<std::size_t> A_nodeTag; + std::vector<double> A_nodecoord; + std::vector<double> A_nodeparametricCoord; + gmsh::model::mesh::getNodes(A_nodeTag, A_nodecoord, A_nodeparametricCoord, dim, tags[0], true); + std::cout << "-----------------------------------------\n"; + std::cout << "point A displacement: u = " << full_d_vector[nodeIndexMap[A_nodeTag[0]]] << ", v = " << full_d_vector[nodeIndexMap[A_nodeTag[0]] + 1] << "\n"; + } +} - //double start = omp_get_wtime(); - int max_threads = omp_get_max_threads(); +// solves the linear elastic problem in the FEM domain. +// "electrostaticPressure" contains the pressure resulting from the electric field computation on the +// BEM_FEM_boundary. "nbViews" is the current number of views already allocated in the gmsh window. +void solverFEM(std::map<int, double> &electrostaticPressure, int &nbViews) +{ + /*--------Integration rule used in the code for surface integration (neumann BC)----------*/ + std::string integration_rule = "CompositeGauss4"; + bool display_time = false; //displays the time performance of the different parts of the code - /*--------Integration rule used in the code----------*/ - // could be useful to pass it as an argument in the .geo file - std::string integration_rule = "CompositeGauss4"; // tested with other methods, OK too. + double start_init = omp_get_wtime(); /*--------get physical groups--------------*/ std::map<std::string, std::pair<int, int>> groups; @@ -435,58 +500,41 @@ void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews) int dim = groups[groupname].first; int tag = groups[groupname].second; - //loop over the entities of the domain to retrieve all nodeTags by taking care not to take some nodes twice - //using sort and set_union methods - std::vector<std::size_t> FEM_nodeTags; - std::vector<double> FEM_nodecoord; - std::vector<double> FEM_nodeparametricCoord; - // Getting entities of the domain to fill FEM_nodeTags, en faire une fonction ? + // Getting entities of the domain to fill FEM_nodeTags std::vector<int> tags; gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - std::vector<std::vector<std::size_t>> tmp_nodeTags(tags.size()); // will store the nodeTags associated to one given entity of the domain - gmsh::model::mesh::getNodes(tmp_nodeTags[0], FEM_nodecoord, FEM_nodeparametricCoord, dim, tags[0], true); - std::sort(tmp_nodeTags[0].begin(), tmp_nodeTags[0].end()); // need to sort the vectors in order to merge them afterwards - for (std::size_t i = 1; i < tags.size(); i++) - { // in the case the domain contains multiple entities - gmsh::model::mesh::getNodes(tmp_nodeTags[i], FEM_nodecoord, FEM_nodeparametricCoord, dim, tags[i], true); - std::sort(tmp_nodeTags[i].begin(), tmp_nodeTags[i].end()); - std::set_union(tmp_nodeTags[i-1].begin(), tmp_nodeTags[i-1].end(), - tmp_nodeTags[i].begin(), tmp_nodeTags[i].end(), std::back_inserter(FEM_nodeTags)); - - } - if(tags.size() == 1){ // if the domain contains one single entity - FEM_nodeTags = tmp_nodeTags[0]; - } - + std::vector<std::size_t> FEM_nodeTags; + std::map<int,std::pair<double,double>> FEM_nodeCoordsMap; // nodeTag -> (x,y) (useless in this linear case) + RetrieveFEMNodeTagsAndCoords(FEM_nodeTags, FEM_nodeCoordsMap, dim, tags); /*-------map between nodeTag and index of first nodal displacement associated to the node (second one is the same +1)------*/ std::map<int, int> nodeIndexMap; for (std::size_t i = 0; i < FEM_nodeTags.size(); ++i) { - int nodeTag = FEM_nodeTags[i];// use i à la place de nodeTag pour traiter cas ou le nodeTag n'est pas une suite continue + int nodeTag = FEM_nodeTags[i]; int node_first_index = 2*i; nodeIndexMap[nodeTag] = node_first_index; } /*-----------get physical properties of domain----------------------*/ - std::vector<std::string> keys; - gmsh::onelab::getNames(keys, "(Volumic Forces|Materials).+"); double E = 0; // Young modulus double nu = 0; // Poisson ratio double rho = 0; // volumic mass double bx = 0; // volumic force along x axis double by = 0; // volumic force along y axis - - getPhysicalProperties(keys, E, nu, rho, bx, by); + getPhysicalProperties(E, nu, rho, bx, by); /*-----------------H matrix involved in stress computation------------------*/ Eigen::Matrix<double, 3, 3> H_matrix = computeHmatrix(E, nu); - //double startbis = omp_get_wtime(); - //std::cout << "preliminary: " << startbis-start << "\n"; + + double end_init = omp_get_wtime(); + std::string step_name = "initialization"; + displayTime(start_init, end_init, step_name, display_time); /*------------computing K matrix and f vector------------------------*/ // we first consider the K matrix and the volumic part of the f vector + // K matrix declared as sparse matrix for efficiency. Eigen::SparseMatrix<double> full_K_matrix(2*FEM_nodeTags.size(),2*FEM_nodeTags.size()); std::vector<double> full_f_vector(2*FEM_nodeTags.size()); for (size_t i = 0; i < full_f_vector.size(); i++) @@ -494,72 +542,30 @@ void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews) full_f_vector[i] = 0; } - std::vector<std::list<Eigen::Triplet <double>>> my_k_list(max_threads); - std::vector<std::list<std::pair<int,double>>> thread_f_vector(max_threads); - - // Looping over entities and compute full K (under tripletlist form) and F - assembleKlistVolumicF(H_matrix, rho, bx, by, integration_rule, dim, tags, nodeIndexMap, my_k_list, thread_f_vector); - - - std::list<Eigen::Triplet <double>> k_tripletList = my_k_list[0]; - - if(max_threads > 1) - { - for (int i = 1; i < max_threads; i++) - { - k_tripletList.insert(k_tripletList.end(), my_k_list[i].begin(), my_k_list[i].end()); - } - } - full_K_matrix.setFromTriplets(k_tripletList.begin(), k_tripletList.end()); - for(int i = 0; i < max_threads; i++){ - std::list<std::pair<int,double>> &tmp_vector = thread_f_vector[i]; - for(auto &p : tmp_vector) { - full_f_vector[p.first] += p.second; - } - } - - //double start2 = omp_get_wtime(); - //std::cout << "time for K assembly: " << start2-startbis << "\n"; + // Looping over entities and compute full K and volumic F + assembleKVolumicF(H_matrix, rho, bx, by, dim, tags, nodeIndexMap, full_K_matrix, full_f_vector); + double end_assembleK = omp_get_wtime(); + step_name = "K assembly"; + displayTime(end_init, end_assembleK, step_name, display_time); + /*-----------------BOUNDARY CONDITIONS------------*/ /*-----------get group_names related to BC's----------------------*/ - gmsh::onelab::getNames(keys, "(Boundary Conditions).+"); + std::vector<std::string> BCkeys; + gmsh::onelab::getNames(BCkeys, "(Boundary Conditions).+"); /*-----------first focus on neumann BC's (surface traction) into full_f_vector------------*/ - includeNeumannBC(keys, integration_rule, nodeIndexMap, groups, full_f_vector); - - //double start3 = omp_get_wtime(); - //std::cout << "time for neumann: " << start3 - start2 << "\n"; + includeNeumannBC(BCkeys, integration_rule, nodeIndexMap, groups, full_f_vector); /* ELECTROSTATIC PRESSURE */ - if(electrostaticPressure.size() != 0) + if(electrostaticPressure.size() != 0) // size is only greater than zero if there was already a BEM solver { - std::string groupnameBoundary = "BEM_FEM_boundary"; - int dimBoundary = groups[groupnameBoundary].first; - int tagBoundary = groups[groupnameBoundary].second; - std::vector<int> tagsBoundary; - gmsh::model::getEntitiesForPhysicalGroup(dimBoundary, tagBoundary, tagsBoundary); - std::vector<int> elementTypes; - std::vector<std::vector<std::size_t>> elementTags; - std::vector<std::vector<std::size_t>> elnodeTags; - - std::map<int,std::pair<double,double>> nodeCoordsMap; - //filling the map with : nodeTag -> (x,y) - for(std::size_t i=0; i< tags.size(); ++i) - { - std::vector<std::size_t> entity_nodeTags; - std::vector<double> entity_nodecoord; - std::vector<double> entity_nodeparametricCoord; - gmsh::model::mesh::getNodes(entity_nodeTags, entity_nodecoord, entity_nodeparametricCoord, dim, tags[i], true); - for ( std::size_t j=0; j < entity_nodeTags.size(); j++){ - nodeCoordsMap[entity_nodeTags[j]] = std::pair<double, double>(entity_nodecoord[3*j], entity_nodecoord[3*j+1]); - } - } - applyElecPressure(integration_rule, nodeCoordsMap, nodeIndexMap, groups, electrostaticPressure, full_f_vector); + applyElecPressure(integration_rule, FEM_nodeCoordsMap, nodeIndexMap, groups, electrostaticPressure, full_f_vector); } - - //double start4 = omp_get_wtime(); - //std::cout << "time for elec pressure: " << start4 - start3 << "\n"; + + double end_neumannBC = omp_get_wtime(); + step_name = "neumann BC and elec pressure"; + displayTime(end_assembleK, end_neumannBC, step_name, display_time); /*------------FOCUS ON DIRICHLET BC'S---------------*/ // new_DOFindices vector will contain the new indices of the K matrix after the rows/columns corresponding @@ -573,29 +579,23 @@ void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews) std::vector<double> dir_BC(2*FEM_nodeTags.size()); // Fill the two vectors defined just above - fillDOFindicesDirBC(keys, nodeIndexMap, groups, new_DOFindices, dir_BC); - int number_removed_lines = 0; - for (std::size_t j = 0; j < new_DOFindices.size(); ++j){ - if(new_DOFindices[j] < 0){ // line has to be removed - number_removed_lines++; - } - else{ - new_DOFindices[j] -= number_removed_lines; - } - } + fillDOFindicesDirBC(BCkeys, nodeIndexMap, groups, new_DOFindices, dir_BC, number_removed_lines); - //double start3 = omp_get_wtime(); - //std::cout << "time for boundary conditions: " << start3 - start2 << "\n"; + double end_dirichletBC = omp_get_wtime(); + step_name = "dirichlet BC"; + displayTime(end_neumannBC, end_dirichletBC, step_name, display_time); /*------------FILLING THE REDUCED K MATRIX AND F VECTOR--------------*/ - //the correction term on the f vector comes from the "FEM" theoretical course (JP Ponthot), Chap2 Slide 38/50 + //the correction term on the f vector comes from the "Finite Element Method" theoretical course (JP Ponthot, ULiege), Chap2 Slide 38/50 Eigen::SparseMatrix<double> reduced_K_matrix(2*FEM_nodeTags.size() - number_removed_lines,2*FEM_nodeTags.size() - number_removed_lines); std::vector<double> reduced_f_vector(2*FEM_nodeTags.size() - number_removed_lines); - std::list<Eigen::Triplet <double>> reduced_k_tripletList; + fillReducedKf(full_f_vector, full_K_matrix, new_DOFindices, dir_BC, reduced_K_matrix, reduced_f_vector); - fillReducedKf(full_f_vector, full_K_matrix, new_DOFindices, dir_BC, reduced_K_matrix, reduced_f_vector, reduced_k_tripletList); + double end_reducedFilling = omp_get_wtime(); + step_name = "filling reduced K and f"; + displayTime(end_dirichletBC, end_reducedFilling, step_name, display_time); /*--------------SOLVING THE REDUCED SYSTEM--------------------*/ Eigen::VectorXd final_reduced_d(2*FEM_nodeTags.size() - number_removed_lines); @@ -606,14 +606,14 @@ void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews) } // solve Kd=f - Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver; + Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver; solver.compute(reduced_K_matrix); final_reduced_d = solver.solve(final_reduced_f); - //double start4 = omp_get_wtime(); - //std::cout << "time to solve system: " << start4 -start3 << "\n"; - + double end_solveSystem = omp_get_wtime(); + step_name = "solving the linear system"; + displayTime(end_reducedFilling, end_solveSystem, step_name, display_time); /*-----------RECONSTRUCTING FULL NODAL VALUES--------------*/ std::vector<double> full_d_vector(2*FEM_nodeTags.size()); @@ -640,21 +640,19 @@ void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews) nodal_forces[i] = nodalForces(i); } - /*--------------REACTION FORCES COMPUTATION------------------*/ - computeReactionForces(groups, nodeIndexMap, nodal_forces, keys); - - //double start5 = omp_get_wtime(); - //std::cout << "time for rest: " << start5 - start4 << "\n"; + double end_reconstructing = omp_get_wtime(); + step_name = "reconstructing full nodal disp and forces"; + displayTime(end_solveSystem, end_reconstructing, step_name, display_time); /*--------------PLOTTING AND SAVING NODAL VALUES------------------*/ std::vector<std::string> names; gmsh::model::list(names); - plotUxUy(FEM_nodeTags, full_d_vector, nbViews, names); + plotUxUy(FEM_nodeTags, full_d_vector, names); /*-------------POST PROCESSING---------------*/ /*-------------Computing and saving strains/stresses-----------------*/ - groupname = "FEM_domain"; // we consider the domain as containing the FEM 2d model + groupname = "FEM_domain"; // we consider the FEM domain as containing the FEM 2d model dim = groups[groupname].first; tag = groups[groupname].second; gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); @@ -673,90 +671,86 @@ void solverFEM(std::map<int, double> &electrostaticPressure, const int nbViews) } } + std::cout << "The FEM domain contains " << nbelems << " element(s) and " << FEM_nodeTags.size() << " nodes\n"; - /*-------------------ELEMENTAL-NODAL VALUES-----------------------*/ - // éventuellement faire un tableau ici qui regroupe tout le bazar pour ne pas avoir la même ligne 7 fois ... - int viewtag3 = gmsh::view::add("nodal_eps_x"); - int viewtag4 = gmsh::view::add("nodal_eps_y"); - int viewtag5 = gmsh::view::add("nodal_2eps_xy"); - int viewtag6 = gmsh::view::add("nodal_eps_z"); - int viewtag7 = gmsh::view::add("nodal_sig_x"); - int viewtag8 = gmsh::view::add("nodal_sig_y"); - int viewtag9 = gmsh::view::add("nodal_sig_xy"); - int viewtag10 = gmsh::view::add("nodal_sig_VM"); - std::vector<std::vector<double>> data3(nbelems); - std::vector<std::vector<double>> data4(nbelems); - std::vector<std::vector<double>> data5(nbelems); - std::vector<std::vector<double>> data6(nbelems); - std::vector<std::vector<double>> data7(nbelems); - std::vector<std::vector<double>> data8(nbelems); - std::vector<std::vector<double>> data9(nbelems); - std::vector<std::vector<double>> data10(nbelems); - std::vector<std::size_t> elems2D(nbelems); - - // computing the elemental nodal data for each physical group of the domain - int k = 0; // current index of data vectors, k is incremented in Compute_Stress_Strain_Elemental_Nodal at each element - for(std::size_t i=0; i< tags.size(); ++i) - { - gmsh::model::mesh::getElements(elementTypes, elementTags, elnodeTags, dim, tags[i]); - computeStressStrainLinearWay(elementTypes, elementTags, elnodeTags, full_d_vector, elems2D, H_matrix, - nu, E, nodeIndexMap, data3, data4, data5, data6, data7, data8, data9, data10, k); - } + // retrieving and displaying maximal nodal displacement + double max_disp = 0; + double max_u = 0; + double max_v = 0; + int max_disp_nodeTag = 0; - gmsh::view::addModelData(viewtag3, 0, names[0], "ElementNodeData", - elems2D, data3, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag4, 0, names[0], "ElementNodeData", - elems2D, data4, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag5, 0, names[0], "ElementNodeData", - elems2D, data5, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag6, 0, names[0], "ElementNodeData", - elems2D, data6, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag7, 0, names[0], "ElementNodeData", - elems2D, data7, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag8, 0, names[0], "ElementNodeData", - elems2D, data8, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag9, 0, names[0], "ElementNodeData", - elems2D, data9, 1); // the last ,1 is important! - gmsh::view::addModelData(viewtag10, 0, names[0], "ElementNodeData", - elems2D, data10, 1); // the last ,1 is important! + for(size_t i = 0; i < FEM_nodeTags.size(); i++) + { + double tmp_index = nodeIndexMap[FEM_nodeTags[i]]; + double tmp_disp = full_d_vector[tmp_index]*full_d_vector[tmp_index] + full_d_vector[tmp_index + 1]*full_d_vector[tmp_index + 1]; + if (tmp_disp > max_disp) + { + max_disp = tmp_disp; + max_disp_nodeTag = FEM_nodeTags[i]; + max_u = full_d_vector[tmp_index]; + max_v = full_d_vector[tmp_index + 1]; + } + } + std::cout << "-----------------------------------------\n"; + std::cout << "maximal nodal displacement (u,v) = (" << max_u << "," << max_v << ") [m], at node " << max_disp_nodeTag << "\n"; + + /*--------------REACTION FORCES COMPUTATION------------------*/ + computeReactionForces(groups, nodeIndexMap, nodal_forces, BCkeys); + + /*-------------------ELEMENTAL-NODAL VALUES-----------------------*/ + double max_VM_stress = 0; + int max_VM_nodeTag; + computeStressStrainLinearWay(dim, tags, full_d_vector, H_matrix, nu, E, nodeIndexMap, nbelems, max_VM_stress, max_VM_nodeTag); + std::cout << "-----------------------------------------\n"; + std::cout << "maximal nodal von Mises stress: " << max_VM_stress << " [Pa], at node " << max_VM_nodeTag << "\n"; // representing vector displacement field and nodal forces - int viewtag11 = gmsh::view::add("u"); - int viewtag12 = gmsh::view::add("f"); + int viewTagU = gmsh::view::add("u"); + int viewTagF = gmsh::view::add("f"); int nodeIndex; - std::vector<std::vector<double>> data11(FEM_nodeTags.size()); - std::vector<std::vector<double>> data12(FEM_nodeTags.size()); + std::vector<std::vector<double>> dataU(FEM_nodeTags.size()); + std::vector<std::vector<double>> dataF(FEM_nodeTags.size()); for (std::size_t i = 0; i < FEM_nodeTags.size(); ++i) { nodeIndex = nodeIndexMap[FEM_nodeTags[i]]; - data11[i].resize(3); - data12[i].resize(3); - data11[i][0] = full_d_vector[nodeIndex]; //ux - data11[i][1] = full_d_vector[nodeIndex+1]; //uy - data11[i][2] = 0.; //uz - data12[i][0] = nodal_forces[nodeIndex]; //fx - data12[i][1] = nodal_forces[nodeIndex+1]; //fy - data12[i][2] = 0.; //fz - } - - gmsh::view::addModelData(viewtag11, 0, names[0], "NodeData", - FEM_nodeTags, data11); //independent of time here - gmsh::view::addModelData(viewtag12, 0, names[0], "NodeData", - FEM_nodeTags, data12); //independent of time here - - - - // empeche que tout se plot l'un sur l'autre - int nb_views = 12 + nbViews; //hardcoded + dataU[i].resize(3); + dataF[i].resize(3); + dataU[i][0] = full_d_vector[nodeIndex]; //ux + dataU[i][1] = full_d_vector[nodeIndex+1]; //uy + dataU[i][2] = 0.; //uz + dataF[i][0] = nodal_forces[nodeIndex]; //fx + dataF[i][1] = nodal_forces[nodeIndex+1]; //fy + dataF[i][2] = 0.; //fz + } + + gmsh::view::addModelData(viewTagU, 0, names[0], "NodeData", + FEM_nodeTags, dataU); //independent of time here + gmsh::view::addModelData(viewTagF, 0, names[0], "NodeData", + FEM_nodeTags, dataF); //independent of time here + + int nb_views = 12 + nbViews; //FEM code adds 12 views for( int i = 0; i < nb_views; ++i){ - std::string my_string = "View[" + std::to_string(i) + "].Visible"; + std::string my_string = "View[" + std::to_string(i) + "].Visible"; // avoids that all views are represented on top of each other gmsh::option::setNumber(my_string, 0); } - //double start6 = omp_get_wtime(); - //std::cout << "time for saving results: " << start6 - start5 << "\n"; + // retrieving work done by external forces + double externalWork = 0; + computeWorkDoneByExternalForces(externalWork, full_d_vector, nodal_forces); + std::cout << "-----------------------------------------\n"; + std::cout << "work done by external forces: " << externalWork << " [J/m].\n"; + + // strain energy + double strainEnergy = 0; + computeStrainEnergyLinearWay(strainEnergy, dim, tags, full_d_vector, H_matrix, nodeIndexMap, integration_rule); + + std::cout << "-----------------------------------------\n"; + std::cout << "strain energy: " << strainEnergy << " [J/m].\n"; + std::cout << "-----------------------------------------\n"; + std::cout << "Total potential energy: " << strainEnergy - externalWork << " [J/m].\n"; - if(openGUI) - gmsh::fltk::run(); // opens the gmsh window + double end_postPro = omp_get_wtime(); + step_name = "post processing"; + displayTime(end_reconstructing, end_postPro, step_name, display_time); } \ No newline at end of file diff --git a/srcs/FEM/uniform_charge.geo b/srcs/FEM/uniform_charge.geo index 1b19a8ee9cef22b003fa155be8fb51442f9bf7ea..930e4410c83958dd777d5c1f19e42af13acb4e13 100644 --- a/srcs/FEM/uniform_charge.geo +++ b/srcs/FEM/uniform_charge.geo @@ -38,3 +38,5 @@ SetNumber("Volumic Forces/FEM_domain/bx",0.); SetNumber("Volumic Forces/FEM_domain/by",0.); //set to -9.81 for gravity Physical Curve("BEM_FEM_boundary", 9) = {1,2,3}; + +SetNumber("Non_linear_solver", 1); \ No newline at end of file diff --git a/srcs/FoldedFlexureBeam.geo b/srcs/FoldedFlexureBeam.geo new file mode 100644 index 0000000000000000000000000000000000000000..1d71824d2c4a7997b4f1c1ae6c3182f5c3a7636b --- /dev/null +++ b/srcs/FoldedFlexureBeam.geo @@ -0,0 +1,293 @@ +scale = 1e-6; + +nBEM = 10; // BEM element density (mettre ça dans quatrième coordonnée) + +nFEM = 0.5; // FEM element density + +phi = 100; +SetNumber("Boundary Conditions/BEM_FEM_boundary/BEM_domain_1/dirichlet", 0); +SetNumber("Boundary Conditions/top_electrode/BEM_domain_1/dirichlet", phi); +SetNumber("Boundary Conditions/rest_of_outside/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity + +// mechanical properties and boundary conditions +SetNumber("Boundary Conditions/anchor/ux", 0.); // encastrement +SetNumber("Boundary Conditions/anchor/uy", 0); +SetNumber("Boundary Conditions/left_edge/ux", 0); +SetNumber("Materials/FEM_domain/Young", 160e9); // A DETERMINER PRECISEMENT +SetNumber("Materials/FEM_domain/Poisson", 0.22); +SetNumber("Materials/FEM_domain/rho",7800); //MODIF +SetNumber("Volumic Forces/FEM_domain/bx",0); +SetNumber("Volumic Forces/FEM_domain/by",0); +SetNumber("Non_linear_solver",1); + +Wc = 4; +g = 8; +Lg = 20; +Ls = 280; +Ht = 40; +Wt = 16; +Ws = 2; +Lc = 30; +y0 = 20; +Hbottom = 50; +Htop = 180; +Wtot = 400; + +// scaled quantities +Wcs = Wc*scale; +gs = g*scale; +Lgs = Lg*scale; +Lss = Ls*scale; +Hts = Ht*scale; +Wts = Wt*scale; +Wss = Ws*scale; +Lcs = Lc*scale; +y0s = y0*scale; +Hbottoms = Hbottom*scale; +Htops = Htop*scale; +Wtots = Wtot*scale; + +Ncombs = 4; // ne pas changer, pas généralisé + +// fixed bottom anchor +y = -(Lg-2-4)*scale; +x = (5*g + 4.5*Wc)*scale; +Point(1) = {x, y-Wss-2*scale, 0, nBEM*scale}; // limite avec suite +Point(2) = {x, y-Wts, 0, nBEM*scale}; +Point(3) = {x-Wts, y-Wts, 0, nBEM*scale}; +Point(4) = {x-Wts, y, 0, nBEM*scale}; +Point(5) = {x, y, 0, nBEM*scale}; +Point(6) = {x, y-2*scale, 0, nBEM*scale}; // limite avec suite +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 5}; +Line(5) = {5, 6}; +Line(6) = {6, 1}; // limite avec suite +Transfinite Curve{1} = (Wt - 2 - Ws)*nFEM+1 Using Progression 1; +Transfinite Curve{2, 3, 4} = Wt*nFEM+1 Using Progression 1; +Transfinite Curve{5} = 2*nFEM+1 Using Progression 1; +Transfinite Curve{6} = Ws*nFEM+1 Using Progression 1; +Curve Loop(1) = {1:6}; +Plane Surface(1) = {1}; +Transfinite Surface{1} = {2:5}; +Recombine Surface{1}; + +// bottom long beam +Point(7) = {x+Lss, y-2*scale, 0, nBEM*scale}; // limite avec suite +Point(8) = {x+Lss, y-Wss-2*scale, 0, nBEM*scale}; // limite avec suite +Line(7) = {6, 7}; +Line(8) = {7, 8}; // limite avec suite +Line(9) = {8, 1}; +Transfinite Curve{7, 9} = Ls*nFEM+1 Using Progression 1; +Transfinite Curve{8} = Ws*nFEM+1 Using Progression 1; +Curve Loop(2) = {-6, 7:9}; +Plane Surface(2) = {2}; +Transfinite Surface{2}; +Recombine Surface{2}; + +//truss +x = x + Lss; +y = y - 10*scale - Wss; +Point(9) = {x, y + 8*scale + Wss + Lgs, 0 , nBEM*scale}; // limite avec suite +Point(10) = {x, y + 8*scale + 2*Wss + Lgs, 0 , nBEM*scale}; // limite avec suite +Point(11) = {x, y + 16*scale + 2*Wss + Lgs, 0 , nBEM*scale}; +Point(12) = {x + Wts, y + 16*scale + 2*Wss + Lgs, 0 , nBEM*scale}; +Point(13) = {x + Wts, y, 0 , nBEM*scale}; +Point(14) = {x, y, 0 , nBEM*scale}; +Line(10) = {7, 9}; +Line(11) = {9, 10}; // limite avec suite +Line(12) = {10, 11}; +Line(13) = {11, 12}; +Line(14) = {12, 13}; +Line(15) = {13, 14}; +Line(16) = {14, 8}; +Transfinite Curve{10} = Lg*nFEM+1 Using Progression 1; +Transfinite Curve{11} = Ws*nFEM+1 Using Progression 1; +Transfinite Curve{12, 16} = 8*nFEM+1 Using Progression 1; +Transfinite Curve{13, 15} = Wt*nFEM+1 Using Progression 1; +Transfinite Curve{14} = (16 + 2*Ws + Lg)*nFEM+1 Using Progression 1; +Curve Loop(3) = {-8, 10:16}; +Plane Surface(3) = {3}; +Transfinite Surface{3} = {11:14}; +Recombine Surface{3}; + +//top long beam +x = (5*g + 4.5*Wc)*scale; +Point(15) = {x, 4*scale, 0 , nBEM*scale}; // limite avec suite +Point(16) = {x, 4*scale + Wss, 0 , nBEM*scale}; // limite avec suite +Line(17) = {9, 15}; +Line(18) = {15, 16}; // limite avec suite +Line(19) = {16, 10}; +Transfinite Curve{17, 19} = Ls*nFEM+1 Using Progression 1; +Transfinite Curve{18} = Ws*nFEM+1 Using Progression 1; +Curve Loop(4) = {-11, 17:19}; +Plane Surface(4) = {4}; +Transfinite Surface{4}; +Recombine Surface{4}; + +//bottom base moveable combs +Point(17) = {x, 0, 0 , nBEM*scale}; +Point(18) = {0, 0, 0 , nBEM*scale}; // roulements +Point(19) = {0, 14*scale + Wss, 0 , nBEM*scale}; // roulements + limite avec suite +Point(20) = {x, 14*scale + Wss, 0 , nBEM*scale}; // limite avec suite +Line(20) = {15, 17}; +Line(21) = {17, 18}; +Line(22) = {18, 19}; // roulements +Line(23) = {19, 20}; // limite avec suite +Line(24) = {20, 16}; +Transfinite Curve{20} = 4*nFEM+1 Using Progression 1; +Transfinite Curve{21, 23} = (5*g + 4.5*Wc)*nFEM+1 Using Progression 1; +Transfinite Curve{22} = (14+Ws)*nFEM+1 Using Progression 1; +Transfinite Curve{24} = 10*nFEM+1 Using Progression 1; +Curve Loop(5) = {-18, 20:24}; +Plane Surface(5) = {5}; +Transfinite Surface{5} = {17:20}; +Recombine Surface{5}; + +//top base moveable combs +y = 26*scale+Wss; +Point(21) = {0, y, 0, nBEM*0.1*scale}; // roulements +Point(22) = {Wcs/2+gs, y, 0, nBEM*0.1*scale}; +Point(23) = {Wcs/2+gs, y+Lcs, 0, nBEM*0.1*scale}; // top comb 1 +Point(24) = {3*Wcs/2+gs, y+Lcs, 0, nBEM*0.1*scale}; // top comb 1 +Point(25) = {3*Wcs/2+gs, y, 0, nBEM*0.1*scale}; +Point(26) = {5*Wcs/2+3*gs, y, 0, nBEM*0.1*scale}; +Point(27) = {5*Wcs/2+3*gs, y+Lcs, 0, nBEM*0.1*scale}; // top comb 2 +Point(28) = {7*Wcs/2+3*gs, y+Lcs, 0, nBEM*0.1*scale}; // top comb 2 +Point(29) = {7*Wcs/2+3*gs, y, 0, nBEM*0.1*scale}; +Point(30) = {9*Wcs/2+5*gs, y, 0, nBEM*0.1*scale}; + +For i In {1:Ncombs-3} + Point(30+4*i-3) = {9*Wcs/2+5*gs + (i-1)*(2*Wcs+2*gs), y+Lcs, 0, nBEM*0.1*scale}; // top comb + Point(30+4*i-2) = {9*Wcs/2+5*gs + (i-1)*(2*Wcs+2*gs) + Wcs, y+Lcs, 0, nBEM*0.1*scale}; // top comb + Point(30+4*i-1) = {9*Wcs/2+5*gs + (i-1)*(2*Wcs+2*gs) + Wcs, y, 0, nBEM*0.1*scale}; + Point(30+4*i) = {9*Wcs/2+5*gs + i*(2*Wcs+2*gs), y, 0, nBEM*0.1*scale}; +EndFor + +nbPts1 = 30 + (Ncombs-3)*4; +x = (5*g + 4.5*Wc)*scale + 2*(Wcs+gs); +Point(nbPts1 + 1) = {x, y+Lcs, 0, nBEM*0.1*scale}; // top last comb +Point(nbPts1 + 2) = {x+Wcs, y+Lcs, 0, nBEM*0.1*scale}; // top last comb +Point(nbPts1 + 3) = {x+Wcs, y, 0, nBEM*0.1*scale}; +Point(nbPts1 + 4) = {x+Wcs+gs, y, 0, nBEM*0.1*scale}; // last point right +Point(nbPts1 + 5) = {x+Wcs+gs, y-12*scale, 0, nBEM*0.4*scale}; // last point right +nbPts2 = nbPts1 + 5; + + +Line(25) = {19, 21}; // roulements +Line(26) = {21, 22}; +Line(27) = {22, 23}; +Line(28) = {23, 24}; // top comb 1 +Line(29) = {24, 25}; +Line(30) = {25, 26}; +Line(31) = {26, 27}; +Line(32) = {27, 28}; // top comb 2 +Line(33) = {28, 29}; +Line(34) = {29, 30}; + +For i In {1:Ncombs-3} + Line(34+4*i-3) = {30+4*i-4, 30+4*i-3}; + Line(34+4*i-2) = {30+4*i-3, 30+4*i-2}; // top comb + Line(34+4*i-1) = {30+4*i-2, 30+4*i-1}; + Line(34+4*i) = {30+4*i-1, 30+4*i}; + Transfinite Curve{34+4*i-3, 34+4*i-1} = Lc*nFEM+1 Using Progression 1; + Transfinite Curve{34+4*i-2} = Wc*nFEM+1 Using Progression 1; + Transfinite Curve{34+4*i} = (Wc+2*g)*nFEM+1 Using Progression 1; +EndFor +nbLines1 = 34 + (Ncombs-3)*4; +Line(nbLines1 + 1) = {nbPts1, nbPts1 + 1}; +Line(nbLines1 + 2) = {nbPts1 + 1, nbPts1 + 2}; //top last comb +Line(nbLines1 + 3) = {nbPts1 + 2, nbPts1 + 3}; +Line(nbLines1 + 4) = {nbPts1 + 3, nbPts1 + 4}; +Line(nbLines1 + 5) = {nbPts1 + 4, nbPts1 + 5}; // last line right +Line(nbLines1 + 6) = {nbPts1 + 5, 20}; +nbLines2 = nbLines1 + 6; + +Transfinite Curve{25, nbLines1 + 5} = 12*nFEM+1 Using Progression 1; +Transfinite Curve{26} = (Wc/2+g)*nFEM+1 Using Progression 1; +Transfinite Curve{27, 29, 31, 33, nbLines1 + 1, nbLines1 + 3} = Lc*nFEM+1 Using Progression 1; +Transfinite Curve{28, 32, nbLines1 + 2} = Wc*nFEM+1 Using Progression 1; +Transfinite Curve{30, 34} = (Wc+2*g)*nFEM+1 Using Progression 1; +Transfinite Curve{nbLines1 + 4} = g*nFEM+1 Using Progression 1; +Transfinite Curve{nbLines1 + 6} = ((Ncombs-2)*(2*Wc+2*g)-g-Wc)*nFEM+1 Using Progression 1; + +// bottom lines +Line(nbLines2 + 1) = {25, 22}; // bottom comb 1 +Line(nbLines2 + 2) = {29, 26}; // bottom comb 2 +For i In {1:Ncombs-3} + Line(nbLines2 + 2 + i) = {30+4*i-1, 30+4*i-4}; // bottom comb +EndFor +nbLines3 = nbLines2 + 2 + Ncombs-2; +Line(nbLines3) = {nbPts1 + 3, nbPts1}; //bottom last comb +Transfinite Curve{nbLines2 + 1: nbLines3} = Wc*nFEM+1 Using Progression 1; + +// top base combs +Curve Loop(6) = {-23, 25, 26, -45,30,-46,34, -47, 38, -48, nbLines1+4:nbLines1+6}; // hardcoded +Plane Surface(6) = {6}; +Transfinite Surface{6} = {19,21,nbPts2-1,nbPts2}; +Recombine Surface{6}; +// hardcoder le nombre de combs à partir d'ici +// four combs +Curve Loop(7) = {27, 28, 29, 45}; +Plane Surface(7) = {7}; +Curve Loop(8) = {31, 32, 33, 46}; +Plane Surface(8) = {8}; +Curve Loop(9) = {35, 36, 37, 47}; +Plane Surface(9) = {9}; +Curve Loop(10) = {39, 40, 41, 48}; +Plane Surface(10) = {10}; +Transfinite Surface{7:10}; +Recombine Surface{7:10}; + +// mechanical physical surfaces +Physical Curve("anchor", 1) = {1:6}; + +Physical Surface("FEM_domain", 2) = {1:10}; +Physical Curve("BEM_FEM_boundary", 3) = {1:5, 7, 10, 17, 20, 21, 26:nbLines2, 24, 19, 12:16, 9}; +Physical Curve("left_edge", 4) = {22,25}; + +//top electrode +y = y + Lcs + (Lcs-y0s) + 12*scale; +xtot = Ncombs*(2*gs+2*Wcs) + Wcs/2; +Point(nbPts2 + 1) = {0, y, 0, nBEM*scale}; +Point(nbPts2 + 2) = {xtot, y, 0, nBEM*scale}; +For i In {1:Ncombs} + Point(nbPts2 + 2 + 4*i - 3) = {xtot-(i-1)*(2*Wcs+2*gs), y-12*scale-Lcs, 0, 0.2*nBEM*scale}; + Point(nbPts2 + 2 + 4*i - 2) = {xtot-(i-1)*(2*Wcs+2*gs) - Wcs, y-12*scale - Lcs, 0, 0.2*nBEM*scale}; + Point(nbPts2 + 2 + 4*i - 1) = {xtot-(i-1)*(2*Wcs+2*gs)-Wcs, y-12*scale, 0, 0.2*nBEM*scale}; + Point(nbPts2 + 2 + 4*i) = {xtot-i*(2*Wcs+2*gs), y-12*scale, 0, 0.2*nBEM*scale}; +EndFor +nbPts3 = nbPts2 + 2 + 4*Ncombs; +Point(nbPts3 + 1) = {Wcs/2, y-12*scale-Lcs, 0, nBEM*scale}; +Point(nbPts3 + 2) = {0, y-12*scale-Lcs, 0, nBEM*scale}; +nbPts4 = nbPts3 + 2; + +For i In {nbPts2+1:nbPts4-1} + Line(nbLines3 + i - nbPts2) = {i, i+1}; +EndFor +Line(nbLines3 + nbPts4 - nbPts2) = {nbPts4, nbPts2+1}; +nbLines4 = nbLines3 + nbPts4 - nbPts2; + +Physical Curve("top_electrode", 5) = {nbLines3+1:nbLines4-1}; + +// rest of outside +Line(nbLines4 + 1) = {nbPts4, 21}; + +Point(nbPts4 + 1) = {0, -Hbottoms, 0, 2*nBEM*scale}; +Point(nbPts4 + 2) = {Wtots, -Hbottoms, 0, 2*nBEM*scale}; +Point(nbPts4 + 3) = {Wtots, Htops, 0, 2*nBEM*scale}; +Point(nbPts4 + 4) = {0, Htops, 0, 2*nBEM*scale}; + +Line(nbLines4 + 2) = {18, nbPts4 + 1}; +Line(nbLines4 + 3) = {nbPts4 + 1, nbPts4 + 2}; +Line(nbLines4 + 4) = {nbPts4 + 2, nbPts4 + 3}; +Line(nbLines4 + 5) = {nbPts4 + 3, nbPts4 + 4}; +Line(nbLines4 + 6) = {nbPts4 + 4, nbPts2 + 1}; + +Curve Loop(11) = {nbLines4 + 2: nbLines4 + 6, nbLines3 + 1: nbLines4 - 1, nbLines4 + 1, 26:nbLines2, 24, 19, 12:16, 9, 1:5, 7, 10, 17, 20, 21}; +Plane Surface(11) = {11}; +Physical Surface("BEM_domain_1", 6) = {11}; + +Physical Curve("rest_of_outside", 7) = {nbLines4+1: nbLines4+6}; \ No newline at end of file diff --git a/srcs/MEMS.geo b/srcs/MEMS.geo index 7ec38557f6c53de26095d06899eb0353a7fb5ba6..a918f61c3068a787a1b17244848dfd096e19f79e 100644 --- a/srcs/MEMS.geo +++ b/srcs/MEMS.geo @@ -103,4 +103,5 @@ Physical Curve("dirichlet", 20) = {3}; phi_top = 100; SetNumber("Boundary Conditions/mass/BEM_domain_1/dirichlet", 0); SetNumber("Boundary Conditions/dirichlet/BEM_domain_1/dirichlet", phi_top); -SetNumber("Boundary Conditions/rest_of_outside/BEM_domain_1/neumann", 0); \ No newline at end of file +SetNumber("Boundary Conditions/rest_of_outside/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity \ No newline at end of file diff --git a/srcs/clampedMicroBeam.geo b/srcs/clampedMicroBeam.geo new file mode 100644 index 0000000000000000000000000000000000000000..5e94f6d3570ef5bd1d8605fdd2833d07b4ee2f59 --- /dev/null +++ b/srcs/clampedMicroBeam.geo @@ -0,0 +1,86 @@ +scale = 1e-6; +Lx_poutre = 25; +Ly_poutre = 1; +h_poutre = 1; +h_tot = 5; +width = 35; + +n = 6; // FEM MESH DENSITY + +// additional parameters given to the solver +SetNumber("Boundary Conditions/left_edge/ux", 0.); +SetNumber("Boundary Conditions/left_edge/uy", 0); +SetNumber("Materials/domain/Young", 150e9); +SetNumber("Materials/domain/Poisson", 0.27); +SetNumber("Materials/domain/rho",2300); +SetNumber("Volumic Forces/FEM_domain/bx",0.); +SetNumber("Volumic Forces/FEM_domain/by",0.); //set to -9.81 for gravity + +phi_top = 112; // à modifier valou +SetNumber("Boundary Conditions/mass/BEM_domain_1/dirichlet", 0); +SetNumber("Boundary Conditions/BEM_FEM_boundary/BEM_domain_1/dirichlet", phi_top); +SetNumber("Boundary Conditions/rest_of_outside/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity + +SetNumber("Non_linear_solver",1); + +Point(1) = {0, h_poutre*scale, 0, 2}; +Point(2) = {Lx_poutre*scale, h_poutre*scale, 0, 2}; +Point(3) = {Lx_poutre*scale, h_poutre*scale + Ly_poutre*scale, 0, 2}; +Point(4) = {0, h_poutre*scale + Ly_poutre*scale, 0, 2}; + +Point(5) = {0, 0, 0, 2}; +Point(6) = {Lx_poutre*scale, 0, 0, 2}; +Point(7) = {width*scale, 0, 0, 2}; +Point(8) = {width*scale, h_tot*scale, 0, 2}; +Point(9) = {0, h_tot*scale, 0, 2}; + +Line(1) = {2, 1}; +Line(2) = {3, 2}; +Line(3) = {4, 3}; +Line(4) = {1, 4}; + +Line(5) = {1, 5}; +Line(6) = {9, 4}; +Line(7) = {8, 9}; +Line(8) = {7, 8}; +Line(9) = {6, 7}; +Line(10) = {5, 6}; + +Curve Loop(1) = {4, 3, 2, 1}; +Plane Surface(1) = {1}; + +Curve Loop(2) = {5, 10, 9, 8, 7, 6, 3, 2, 1}; +Plane Surface(2) = {2}; + +Transfinite Curve {3, 1, 10} = Lx_poutre*n+1 Using Progression 1; +Transfinite Curve {7} = width*n+1 Using Progression 1; +Transfinite Curve {8} = h_tot*n+1 Using Progression 1; +Transfinite Curve {2, 4} = Ly_poutre*n+1 Using Progression 1; +Transfinite Curve {5} = h_poutre*n+1 Using Progression 1; +Transfinite Curve {9} = (width-Lx_poutre)*n+1 Using Progression 1; +Transfinite Curve {6} = (h_tot-h_poutre-Ly_poutre)*n+1 Using Progression 1; +Transfinite Surface {1}; + +//Transfinite Surface {2}; + +Recombine Surface {1}; // quads instead of triangles +//Recombine Surface {2}; + +Mesh.ElementOrder = 1; + +Physical Curve("left_edge", 5) = {4}; +Physical Surface("FEM_domain", 6) = {1}; +Physical Curve("top_edge", 7) = {3}; +Physical Curve("right_edge", 8) = {2}; +Physical Point("fixed_node", 9) = {1}; + +Physical Surface("BEM_domain_1", 10) = {2}; + +// BEM geometry +Physical Curve("BEM_FEM_boundary", 11) = {1,2,3}; +Physical Curve("mass", 12) = {10}; //lower electrode +Physical Curve("rest_of_outside", 13) = {5,6,7,8,9}; +Physical Curve("Electrode", 15) = {1}; +//SetNumber("Boundary Conditions/bottom_edge/tx", 0); +//SetNumber("Boundary Conditions/bottom_edge/ty", -25000); \ No newline at end of file diff --git a/srcs/coupling_validation.geo b/srcs/coupling_validation.geo new file mode 100644 index 0000000000000000000000000000000000000000..e5510d1e2ee35de5eebe1b186d0f0be9839fefe1 --- /dev/null +++ b/srcs/coupling_validation.geo @@ -0,0 +1,65 @@ +scale = 1e-6; + +Lx = 5; +Ly = 2; +l = 3; + +n = 25; + +Point(1) = {0, 0, 0, 0.1}; +Point(2) = {Lx*scale, 0, 0, 0.1}; +Point(3) = {Lx*scale, Ly*scale, 0, 0.1}; +Point(4) = {0, Ly*scale, 0, 0.2}; + +Point(5) = {Lx*scale + l*scale, 0, 0, 0.2}; +Point(6) = {Lx*scale + l*scale, Ly*scale, 0, 0.2}; + +Line(1) = {2, 1}; +Line(2) = {3, 2}; +Line(3) = {4, 3}; +Line(4) = {1, 4}; +Curve Loop(1) = {4, 3, 2, 1}; +Plane Surface(1) = {1}; + +Line(5) = {2, 5}; +Line(6) = {5, 6}; +Line(7) = {6, 3}; +Curve Loop(2) = {2, 5, 6, 7}; +Plane Surface(2) = {2}; + + +Transfinite Curve {3, 1} = n*Lx+1 Using Progression 1; +Transfinite Curve {2, 4, 6} = n*Ly+1 Using Progression 1; +Transfinite Curve {5, 7} = n*l+1 Using Progression 1; +Transfinite Surface {1}; +Transfinite Surface {2}; + +Recombine Surface {1}; // quads instead of triangles +Recombine Surface {2}; + +Mesh.ElementOrder = 1; + +Physical Curve("left_edge", 1) = {4}; +Physical Surface("FEM_domain", 2) = {1}; +Physical Point("fixed_node", 3) = {1}; + +// additional parameters given to the solver +SetNumber("Boundary Conditions/left_edge/ux", 0.); // HERE YOU DO NOT HAVE TO IMPOSE BOTH ux and uy simultaneously ! (permet aussi de simuler appuis à roulettes) +//SetNumber("Boundary Conditions/left_edge/uy", 0.); +SetNumber("Boundary Conditions/fixed_node/uy", 0.); +SetNumber("Materials/FEM_domain/Young", 210e3); +SetNumber("Materials/FEM_domain/Poisson", 0.3); +SetNumber("Materials/FEM_domain/rho",7800); //volumic mass of acier + +Physical Curve("BEM_FEM_boundary", 4) = {2}; +Physical Surface("BEM_domain_1", 5) = {2}; +Physical Curve("right_BEM", 6) = {6}; +Physical Curve("homogeneous_field", 7) = {5, 7}; + +phi = 30; +SetNumber("Boundary Conditions/right_BEM/BEM_domain_1/dirichlet", 0); +SetNumber("Boundary Conditions/BEM_FEM_boundary/BEM_domain_1/dirichlet", phi); +SetNumber("Boundary Conditions/homogeneous_field/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity + +SetNumber("Non_linear_solver", 0); \ No newline at end of file diff --git a/srcs/hybrid_geo.geo b/srcs/hybrid_geo.geo index b7820f20b074ac8e4c74e22527cd72b928dae8e8..53ba5b7907d95934a50e77a778638bc84538074a 100644 --- a/srcs/hybrid_geo.geo +++ b/srcs/hybrid_geo.geo @@ -80,6 +80,7 @@ phi_top = 95; SetNumber("Boundary Conditions/mass/BEM_domain_1/dirichlet", 0); SetNumber("Boundary Conditions/BEM_FEM_boundary/BEM_domain_1/dirichlet", phi_top); SetNumber("Boundary Conditions/rest_of_outside/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity //Physical Curve("BEM_boundary", 14) = {1,3,5,6,7,8,9,10,2}; Physical Curve("Electrode", 15) = {1}; diff --git a/srcs/longitudinalCombDevice.geo b/srcs/longitudinalCombDevice.geo new file mode 100644 index 0000000000000000000000000000000000000000..098922a6252baea88986052ff3e46fad2b5af584 --- /dev/null +++ b/srcs/longitudinalCombDevice.geo @@ -0,0 +1,301 @@ +scale = 2e-6; + +// USE WITH MINIMUM 2 FINS, else use longitudinal_comb.geo +N_fins = 3; // number of fins on one side of the comb // MAX 12 si on change ps la longueur + +// WARNING: when using more fins the pull-in voltage decreases + +n = 1; // FEM elements density +nBEM = 1; // BEM elements density + +// mechanical properties and boundary conditions +SetNumber("Boundary Conditions/left/ux", 0.); // encastrement +SetNumber("Boundary Conditions/left/uy", 0); +SetNumber("Boundary Conditions/right/ux", 0.); // encastrement +SetNumber("Boundary Conditions/right/uy", 0); +SetNumber("Materials/FEM_domain/Young", 150e9); +SetNumber("Materials/FEM_domain/Poisson", 0.27); +SetNumber("Materials/FEM_domain/rho",2300); +SetNumber("Volumic Forces/FEM_domain/bx",0); +SetNumber("Volumic Forces/FEM_domain/by",00); // acceleration of accelerometer + +// BEM properties in bottom domain +phi_1 = 50; +SetNumber("Boundary Conditions/BEM_FEM_boundary_1/BEM_domain_1/dirichlet", 0); +SetNumber("Boundary Conditions/electrode_1/BEM_domain_1/dirichlet", phi_1); +SetNumber("Boundary Conditions/outside_1/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity + +// BEM properties in top domain +phi_2 = 0; +SetNumber("Boundary Conditions/BEM_FEM_boundary_2/BEM_domain_2/dirichlet", 0); +SetNumber("Boundary Conditions/electrode_2/BEM_domain_2/dirichlet", phi_2); +SetNumber("Boundary Conditions/outside_2/BEM_domain_2/neumann", 0); +SetNumber("Materials/BEM_domain_2/Epsilon", 8.8541878128e-12); // dielectric permittivity + +h_tot = 30*scale; +h_base = 0.4*scale; +h_fin = 2.8*scale; +h_space = 1*scale; // space between bout de l'electrode and base of the clamped beam of the comb +h_fin_elec = 2.4*scale; // length of the fins of the electrode, can be longer than the classical fins +// WARNING, abs(h_fin_elec - h_fin) must be lower than h_space + +//l_bord = 10*scale; +//l_tot = 34.4*scale; +l_tot = 40*scale; +l_fin = 0.8*scale; +l_space = 0.8*scale; +t_electrode = 1*scale; // width of one electrode +l_periodic = l_fin + 2*l_space + t_electrode; // distance between two fins +//l_tot = 2*l_bord + l_fin + (N_fins-1)*l_periodic; +l_bord = (l_tot - l_fin - (N_fins-1)*l_periodic)/2; + +unit_l = 0.2*scale; // reference for the transfinite curves + +// définition des points du contour +Point(1) = {0, -h_base/2, 0, nBEM*scale}; +Point(2) = {0, -h_tot/2, 0, nBEM*scale}; +Point(3) = {l_tot, -h_tot/2, 0, nBEM*scale}; +Point(4) = {l_tot, -h_base/2, 0, nBEM*scale}; +Point(5) = {l_tot, h_base/2, 0, nBEM*scale}; +Point(6) = {l_tot, h_tot/2, 0, nBEM*scale}; +Point(7) = {0, h_tot/2, 0, nBEM*scale}; +Point(8) = {0, h_base/2, 0, nBEM*scale}; +// définition des lignes du contour +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 5}; +Line(5) = {5, 6}; +Line(6) = {6, 7}; +Line(7) = {7, 8}; +Line(8) = {8, 1}; +Transfinite Curve {4,8} = (h_base/unit_l)*n+1 Using Progression 1; + + +// définition des points des fins du bas +offsetp1 = 8; +For i In {1:N_fins} + Point(offsetp1+4*i-3) = {(i-1)*l_periodic + l_bord, -h_base/2, 0, 0.2*scale}; + Point(offsetp1+4*i-2) = {(i-1)*l_periodic + l_bord, -h_base/2 - h_fin, 0, 0.2*scale}; + Point(offsetp1+4*i-1) = {(i-1)*l_periodic + l_bord + l_fin, -h_base/2 - h_fin, 0, 0.2*scale}; + Point(offsetp1+4*i) = {(i-1)*l_periodic + l_bord + l_fin, -h_base/2, 0, 0.2*scale}; +EndFor +// définition des lignes des fins du bas +Line(9) = {offsetp1+1, 1}; +Transfinite Curve {9} = (l_bord/unit_l)*n+1 Using Progression 1; +offsetl1 = 9; +For i In {1:N_fins-1} + Line(offsetl1+4*i-3) = {offsetp1+4*i-2, offsetp1+4*i-3}; + Line(offsetl1+4*i-2) = {offsetp1+4*i-1, offsetp1+4*i-2}; + Line(offsetl1+4*i-1) = {offsetp1+4*i, offsetp1+4*i-1}; + Line(offsetl1+4*i) = {offsetp1+4*i+1, offsetp1+4*i}; + Transfinite Curve {offsetl1+4*i-3, offsetl1+4*i-1} = (h_fin/unit_l)*n+1 Using Progression 1; + Transfinite Curve {offsetl1+4*i-2} = (l_fin/unit_l)*n+1 Using Progression 1; + Transfinite Curve {offsetl1+4*i} = ((l_periodic-l_fin)/unit_l)*n+1 Using Progression 1; +EndFor +Line(offsetl1+4*N_fins-3) = {offsetp1+4*N_fins-2, offsetp1+4*N_fins-3}; +Line(offsetl1+4*N_fins-2) = {offsetp1+4*N_fins-1, offsetp1+4*N_fins-2}; +Line(offsetl1+4*N_fins-1) = {offsetp1+4*N_fins, offsetp1+4*N_fins-1}; +Line(offsetl1+4*N_fins) = {4, offsetp1+4*N_fins}; +Transfinite Curve {offsetl1+4*N_fins-3, offsetl1+4*N_fins-1} = (h_fin/unit_l)*n+1 Using Progression 1; +Transfinite Curve {offsetl1+4*N_fins-2} = (l_fin/unit_l)*n+1 Using Progression 1; +Transfinite Curve {offsetl1+4*N_fins} = (l_bord/unit_l)*n+1 Using Progression 1; +// définition des lignes entre les fins du bas et la poutre principale +For i In{1:N_fins} + Line(offsetl1+4*N_fins+i) = {offsetp1+4*i-3, offsetp1+4*i}; + Transfinite Curve {offsetl1+4*N_fins+i} = (l_fin/unit_l)*n+1 Using Progression 1; +EndFor + +// définition des points des fins du haut +offsetp2 = offsetp1 + 4*N_fins; +For i In {1:N_fins} + Point(offsetp2+4*i-3) = {(i-1)*l_periodic + l_bord, h_base/2, 0, 0.2*scale}; + Point(offsetp2+4*i-2) = {(i-1)*l_periodic + l_bord, h_base/2 + h_fin, 0, 0.2*scale}; + Point(offsetp2+4*i-1) = {(i-1)*l_periodic + l_bord + l_fin, +h_base/2 + h_fin, 0, 0.2*scale}; + Point(offsetp2+4*i) = {(i-1)*l_periodic + l_bord + l_fin, +h_base/2, 0, 0.2*scale}; +EndFor +// définition des lignes des fins du haut +offsetl2 = offsetl1 + 5*N_fins + 1; +Line(offsetl2) = {8, offsetp2+1}; +Transfinite Curve {offsetl2} = (l_bord/unit_l)*n+1 Using Progression 1; +For i In {1:N_fins-1} + Line(offsetl2+4*i-3) = {offsetp2+4*i-3, offsetp2+4*i-2}; + Line(offsetl2+4*i-2) = {offsetp2+4*i-2, offsetp2+4*i-1}; + Line(offsetl2+4*i-1) = {offsetp2+4*i-1, offsetp2+4*i}; + Line(offsetl2+4*i) = {offsetp2+4*i, offsetp2+4*i+1}; + Transfinite Curve {offsetl2+4*i-3, offsetl2+4*i-1} = (h_fin/unit_l)*n+1 Using Progression 1; + Transfinite Curve {offsetl2+4*i-2} = (l_fin/unit_l)*n+1 Using Progression 1; + Transfinite Curve {offsetl2+4*i} = ((l_periodic-l_fin)/unit_l)*n+1 Using Progression 1; +EndFor +Line(offsetl2+4*N_fins-3) = {offsetp2+4*N_fins-3, offsetp2+4*N_fins-2}; +Line(offsetl2+4*N_fins-2) = {offsetp2+4*N_fins-2, offsetp2+4*N_fins-1}; +Line(offsetl2+4*N_fins-1) = {offsetp2+4*N_fins-1, offsetp2+4*N_fins}; +Line(offsetl2+4*N_fins) = {offsetp2+4*N_fins, 5}; +Transfinite Curve {offsetl2+4*N_fins-3, offsetl2+4*N_fins-1} = (h_fin/unit_l)*n+1 Using Progression 1; +Transfinite Curve {offsetl2+4*N_fins-2} = (l_fin/unit_l)*n+1 Using Progression 1; +Transfinite Curve {offsetl2+4*N_fins} = (l_bord/unit_l)*n+1 Using Progression 1; +// définition des lignes entre les fins du haut et la poutre principale +For i In{1:N_fins} + Line(offsetl2+4*N_fins+i) = {offsetp2+4*i, offsetp2+4*i-3}; + Transfinite Curve {offsetl2+4*N_fins+i} = (l_fin/unit_l)*n+1 Using Progression 1; +EndFor + +// définition des lignes dans la poutre centrale pour définir sous-domaines +offsetl3 = offsetl2 + 5*N_fins; +For i In {1:N_fins} + Line(offsetl3+2*i-1) = {offsetp2+4*i-3, offsetp1+4*i-3}; + Line(offsetl3+2*i) = {offsetp1+4*i, offsetp2+4*i}; + Transfinite Curve {offsetl3+2*i-1, offsetl3+2*i} = (h_base/unit_l)*n+1 Using Progression 1; +EndFor + +// définition des courbes et surfaces dans les fins du bas +For i In {1:N_fins} + Curve Loop(i) = {offsetl1+4*i-1, offsetl1+4*i-2, offsetl1+4*i-3, offsetl1+4*N_fins+i}; + Plane Surface(i) = {i}; + Recombine Surface {i}; +EndFor + +// définition des courbes et surfaces dans les fins du haut +offsets1 = N_fins; +For i In {1:N_fins} + Curve Loop(offsets1 + i) = {offsetl2+4*i-3, offsetl2+4*i-2, offsetl2+4*i-1, offsetl2+4*N_fins+i}; + Plane Surface(offsets1 + i) = {offsets1 + i}; + Recombine Surface {offsets1 + i}; +EndFor + +// définition des courbes et surfaces dans la poutre centrale +offsets2 = offsets1 + N_fins + 1; +Curve Loop(offsets2) = {-8, offsetl2, offsetl3+1, offsetl1}; +Plane Surface(offsets2) = {offsets2}; +Recombine Surface {offsets2}; +For i In {1:N_fins-1} + Curve Loop(offsets2 + 2*i - 1) = {offsetl3+2*i-1, offsetl1+4*N_fins+i, offsetl3+2*i, offsetl2+4*N_fins+i}; + Plane Surface(offsets2 + 2*i - 1) = {offsets2 + 2*i - 1}; + Recombine Surface {offsets2 + 2*i - 1}; + Curve Loop(offsets2 + 2*i) = {offsetl3+2*i, offsetl2+4*i, offsetl3+2*i+1, offsetl1+4*i}; + Plane Surface(offsets2 + 2*i) = {offsets2 + 2*i}; + Recombine Surface {offsets2 + 2*i}; +EndFor +Curve Loop(offsets2 + 2*N_fins - 1) = {offsetl3+2*N_fins-1, offsetl1+4*N_fins+N_fins, offsetl3+2*N_fins, offsetl2+4*N_fins+N_fins}; +Plane Surface(offsets2 + 2*N_fins - 1) = {offsets2 + 2*N_fins - 1}; +Recombine Surface {offsets2 + 2*N_fins - 1}; +Curve Loop(offsets2 + 2*N_fins) = {offsetl3+2*N_fins, offsetl2+4*N_fins, -4, offsetl1+4*N_fins}; +Plane Surface(offsets2 + 2*N_fins) = {offsets2 + 2*N_fins}; +Recombine Surface {offsets2 + 2*N_fins}; + + +// mechanical physical surfaces +Physical Curve("left", 1) = {8}; +Physical Curve("right", 2) = {4}; + +Physical Surface("FEM_domain", 3) = {1:offsets2 + 2*N_fins}; +Transfinite Surface {1:offsets2 + 2*N_fins}; +Physical Curve("BEM_FEM_boundary", 4) = {offsetl1:offsetl1+4*N_fins, offsetl2:offsetl2+4*N_fins}; + +// définition des points de la bottom electrode +x0_e = l_bord - l_space - t_electrode; // pour faciliter le bazar +y0_e = h_base/2 + h_space; +offsetp3 = offsetp2 + 4*N_fins; +Point(offsetp3 + 1) = {l_tot - x0_e - t_electrode, -y0_e - h_fin_elec, 0, nBEM*0.2*scale}; +Point(offsetp3 + 2) = {l_tot - x0_e - t_electrode, -y0_e, 0, nBEM*0.2*scale}; +Point(offsetp3 + 3) = {l_tot - x0_e, -y0_e, 0, nBEM*0.2*scale}; +Point(offsetp3 + 4) = {l_tot - x0_e, -y0_e - h_fin_elec - t_electrode, 0, nBEM*0.2*scale}; +Point(offsetp3 + 5) = {x0_e, -y0_e - h_fin_elec - t_electrode, 0, nBEM*0.2*scale}; +Point(offsetp3 + 6) = {x0_e, -y0_e, 0, nBEM*0.2*scale}; +Point(offsetp3 + 7) = {x0_e + t_electrode, -y0_e, 0, nBEM*0.2*scale}; +Point(offsetp3 + 8) = {x0_e + t_electrode, -y0_e - h_fin_elec, 0, nBEM*0.2*scale}; + +offsetp4 = offsetp3 + 8; +For i In {1:N_fins-1} + Point(offsetp4 + 4*i - 3) = {x0_e + l_periodic*i, -y0_e - h_fin_elec, 0, nBEM*0.2*scale}; + Point(offsetp4 + 4*i - 2) = {x0_e + l_periodic*i, -y0_e, 0, nBEM*0.2*scale}; + Point(offsetp4 + 4*i - 1) = {x0_e + l_periodic*i + t_electrode, -y0_e, 0, nBEM*0.2*scale}; + Point(offsetp4 + 4*i) = {x0_e + l_periodic*i + t_electrode, -y0_e - h_fin_elec, 0, nBEM*0.2*scale}; +EndFor + +// définition des lignes générales (indépendantes de N_fins) de la bottom electrode +offsetl4 = offsetl3 + N_fins*2; +Line(offsetl4 + 1) = {offsetp3 + 1, offsetp3 + 2}; +Line(offsetl4 + 2) = {offsetp3 + 2, offsetp3 + 3}; +Line(offsetl4 + 3) = {offsetp3 + 3, offsetp3 + 4}; +Line(offsetl4 + 4) = {offsetp3 + 4, offsetp3 + 5}; +Line(offsetl4 + 5) = {offsetp3 + 5, offsetp3 + 6}; +Line(offsetl4 + 6) = {offsetp3 + 6, offsetp3 + 7}; +Line(offsetl4 + 7) = {offsetp3 + 7, offsetp3 + 8}; +Line(offsetl4 + 8) = {offsetp3 + 8, offsetp4 + 1}; +offsetl5 = offsetl4 + 8; +// définition des lignes fins electrode du bas +For i In {1:N_fins-2} + Line(offsetl5 + 4*i - 3) = {offsetp4 + 4*i - 3, offsetp4 + 4*i - 2}; + Line(offsetl5 + 4*i - 2) = {offsetp4 + 4*i - 2, offsetp4 + 4*i - 1}; + Line(offsetl5 + 4*i - 1) = {offsetp4 + 4*i - 1, offsetp4 + 4*i}; + Line(offsetl5 + 4*i) = {offsetp4 + 4*i, offsetp4 + 4*i + 1}; +EndFor +Line(offsetl5 + 4*(N_fins-1) - 3) = {offsetp4 + 4*(N_fins-1) - 3, offsetp4 + 4*(N_fins-1) - 2}; +Line(offsetl5 + 4*(N_fins-1) - 2) = {offsetp4 + 4*(N_fins-1) - 2, offsetp4 + 4*(N_fins-1) - 1}; +Line(offsetl5 + 4*(N_fins-1) - 1) = {offsetp4 + 4*(N_fins-1) - 1, offsetp4 + 4*(N_fins-1)}; +Line(offsetl5 + 4*(N_fins-1)) = {offsetp4 + 4*(N_fins-1), offsetp3+1}; + +// définition des curve loop et surface du BEM_domain1 +offsets3 = offsets2 + 2*N_fins; +Curve Loop(offsets3 + 1) = {offsetl1+4*N_fins:offsetl1:-1,1,2,3}; // exterior boundary of BEM_domain_1 +Curve Loop(offsets3 + 2) = {offsetl4 + 1 : offsetl5 + 4*(N_fins-1)}; +Plane Surface(offsets3 + 1) = {offsets3 + 1, offsets3 + 2}; + +Physical Surface("BEM_domain_1", 5) = {offsets3 + 1}; +Physical Curve("BEM_FEM_boundary_1", 6) = {offsetl1+4*N_fins:offsetl1:-1}; +Physical Curve("electrode_1", 7) = {offsetl4 + 1 : offsetl5 + 4*(N_fins-1)}; +Physical Curve("outside_1", 8) = {1, 2, 3}; + +// définition des points de la top electrode +offsetp5 = offsetp4 + 4*(N_fins-1); +Point(offsetp5 + 1) = {x0_e + t_electrode, y0_e + h_fin_elec, 0, nBEM*0.2*scale}; +Point(offsetp5 + 2) = {x0_e + t_electrode, y0_e, 0, nBEM*0.2*scale}; +Point(offsetp5 + 3) = {x0_e, y0_e, 0, nBEM*0.2*scale}; +Point(offsetp5 + 4) = {x0_e, y0_e + h_fin_elec + t_electrode, 0, nBEM*0.2*scale}; +Point(offsetp5 + 5) = {l_tot - x0_e, y0_e + h_fin_elec + t_electrode, 0, nBEM*0.2*scale}; +Point(offsetp5 + 6) = {l_tot - x0_e, y0_e, 0, nBEM*0.2*scale}; +Point(offsetp5 + 7) = {l_tot - x0_e - t_electrode, y0_e, 0, nBEM*0.2*scale}; +Point(offsetp5 + 8) = {l_tot - x0_e - t_electrode, y0_e + h_fin_elec, 0, nBEM*0.2*scale}; + +offsetp6 = offsetp5 + 8; +For i In {1:N_fins-1} + Point(offsetp6 + 4*i - 3) = {x0_e + l_periodic*i, y0_e + h_fin_elec, 0, nBEM*0.2*scale}; + Point(offsetp6 + 4*i - 2) = {x0_e + l_periodic*i, y0_e, 0, nBEM*0.2*scale}; + Point(offsetp6 + 4*i - 1) = {x0_e + l_periodic*i + t_electrode, y0_e, 0, nBEM*0.2*scale}; + Point(offsetp6 + 4*i) = {x0_e + l_periodic*i + t_electrode, y0_e + h_fin_elec, 0, nBEM*0.2*scale}; +EndFor + +// définition des lignes générales (indépendantes de N_fins) de la top electrode +offsetl6 = offsetl5 + 4*(N_fins-1); +Line(offsetl6 + 1) = {offsetp5 + 1, offsetp5 + 2}; +Line(offsetl6 + 2) = {offsetp5 + 2, offsetp5 + 3}; +Line(offsetl6 + 3) = {offsetp5 + 3, offsetp5 + 4}; +Line(offsetl6 + 4) = {offsetp5 + 4, offsetp5 + 5}; +Line(offsetl6 + 5) = {offsetp5 + 5, offsetp5 + 6}; +Line(offsetl6 + 6) = {offsetp5 + 6, offsetp5 + 7}; +Line(offsetl6 + 7) = {offsetp5 + 7, offsetp5 + 8}; +Line(offsetl6 + 8) = {offsetp5 + 8, offsetp6 + 4*(N_fins-1)}; +offsetl7 = offsetl6 + 8; +// définition des lignes fins electrode du haut +Line(offsetl7 + 1) = {offsetp6 + 4 - 3, offsetp5 + 1}; +Line(offsetl7 + 2) = {offsetp6 + 4 - 2, offsetp6 + 4 - 3}; +Line(offsetl7 + 3) = {offsetp6 + 4 - 1, offsetp6 + 4 - 2}; +Line(offsetl7 + 4) = {offsetp6 + 4, offsetp6 + 4 - 1}; +For i In {2:N_fins-1} + Line(offsetl7 + 4*i - 3) = {offsetp6 + 4*i - 3, offsetp6 + 4*i - 4}; + Line(offsetl7 + 4*i - 2) = {offsetp6 + 4*i - 2, offsetp6 + 4*i - 3}; + Line(offsetl7 + 4*i - 1) = {offsetp6 + 4*i - 1, offsetp6 + 4*i - 2}; + Line(offsetl7 + 4*i) = {offsetp6 + 4*i, offsetp6 + 4*i - 1}; +EndFor + +// définition des curve loop et surface du BEM_domain2 +Curve Loop(offsets3 + 3) = {offsetl2:offsetl2+4*N_fins,5,6,7}; // exterior boundary of BEM_domain_2 +Curve Loop(offsets3 + 4) = {offsetl6 + 1 : offsetl6 + 8, offsetl7 + 4*(N_fins-1):offsetl7+1:-1}; +Plane Surface(offsets3 + 2) = {offsets3 + 3, offsets3 + 4}; + +Physical Surface("BEM_domain_2", 9) = {offsets3 + 2}; +Physical Curve("BEM_FEM_boundary_2", 10) = {offsetl2:offsetl2+4*N_fins}; +Physical Curve("electrode_2", 11) = {offsetl6 + 1 : offsetl6 + 8, offsetl7 + 4*(N_fins-1):offsetl7+1:-1}; +Physical Curve("outside_2", 12) = {5,6,7}; \ No newline at end of file diff --git a/srcs/longitudinal_comb.geo b/srcs/longitudinal_comb.geo new file mode 100644 index 0000000000000000000000000000000000000000..6c89eec081168abdcadd2fbd9403a00c051875fd --- /dev/null +++ b/srcs/longitudinal_comb.geo @@ -0,0 +1,147 @@ +scale = 1e-5; + +h_tot = 20*scale; +h_base = 1*scale; +h_pin = 2.5*scale; +h_space = 1.2*scale; + +l_tot = 20*scale; +l_pin = 0.8*scale; +l_space = 0.5*scale; + +t_electrode = 1*scale; // width of fixed electrodes +// FEM domain +Point(1) = {-l_tot/2, h_base/2, 0, 0.2*scale}; +Point(2) = {-l_pin/2, h_base/2, 0, 0.2*scale}; +Point(3) = {-l_pin/2, h_base/2 + h_pin, 0, 0.2*scale}; +Point(4) = {l_pin/2, h_base/2 + h_pin, 0, 0.2*scale}; +Point(5) = {l_pin/2, h_base/2, 0, 0.2*scale}; +Point(6) = {l_tot/2, h_base/2, 0, 0.2*scale}; +Point(7) = {l_tot/2, -h_base/2, 0, 0.2*scale}; +Point(8) = {l_pin/2, -h_base/2, 0, 0.2*scale}; +Point(9) = {l_pin/2, -(h_base/2 + h_pin), 0, 0.2*scale}; +Point(10) = {-l_pin/2, -(h_base/2 + h_pin), 0, 0.2*scale}; +Point(11) = {-l_pin/2, -h_base/2, 0, 0.2*scale}; +Point(12) = {-l_tot/2, -h_base/2, 0, 0.2*scale}; + +// FEM domain +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 5}; +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, 1}; + +Curve Loop(1) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; +Plane Surface(1) = {1}; + +Recombine Surface {1}; // quads instead of triangles + +Physical Curve("left", 1) = {12}; +Physical Curve("right", 2) = {6}; + +Physical Surface("FEM_domain", 3) = {1}; +Physical Curve("BEM_FEM_boundary", 4) = {1, 2, 3, 4, 5, 7, 8, 9, 10, 11}; + +// mechanical properties and boundary conditions +SetNumber("Boundary Conditions/left/ux", 0.); // encastrement +SetNumber("Boundary Conditions/left/uy", 0); +SetNumber("Boundary Conditions/right/ux", 0.); // encastrement +SetNumber("Boundary Conditions/right/uy", 0); +SetNumber("Materials/domain/Young", 210e3); // A DETERMINER PRECISEMENT +SetNumber("Materials/domain/Poisson", 0.3); +SetNumber("Materials/domain/rho",7800); //volumic mass of acier +SetNumber("Volumic Forces/FEM_domain/bx",0); // acceleration of accelerometer +SetNumber("Volumic Forces/FEM_domain/by",-200.); + +// BEM domain 1 +Point(13) = {-(l_pin/2 + l_space + t_electrode), -(h_base/2 + h_pin + h_space + t_electrode), 0, 0.2*scale}; // first fixed electrode +Point(14) = {-(l_pin/2 + l_space + t_electrode), -(h_base/2 + h_space), 0, 0.2*scale}; +Point(15) = {-(l_pin/2 + l_space), -(h_base/2 + h_space), 0, 0.2*scale}; +Point(16) = {-(l_pin/2 + l_space), -(h_base/2 + h_pin + h_space), 0, 0.2*scale}; +Point(17) = {l_pin/2 + l_space, -(h_base/2 + h_pin + h_space), 0, 0.2*scale}; +Point(18) = {l_pin/2 + l_space, -(h_base/2 + h_space), 0, 0.2*scale}; +Point(19) = {l_pin/2 + l_space + t_electrode, -(h_base/2 + h_space), 0, 0.2*scale}; +Point(20) = {l_pin/2 + l_space + t_electrode, -(h_base/2 + h_pin + h_space + t_electrode), 0, 0.2*scale}; + +Line(13) = {13, 14}; +Line(14) = {14, 15}; +Line(15) = {15, 16}; +Line(16) = {16, 17}; +Line(17) = {17, 18}; +Line(18) = {18, 19}; +Line(19) = {19, 20}; +Line(20) = {20, 13}; + +Point(29) = {-l_tot/2, -h_tot/2, 0, 0.2*scale}; +Point(30) = {l_tot/2, -h_tot/2, 0, 0.2*scale}; + +Line(29) = {12, 29}; +Line(30) = {29, 30}; +Line(31) = {30, 7}; + +Curve Loop(2) = {29, 30, 31, 7, 8, 9, 10, 11}; +Curve Loop(3) = {13, 14, 15, 16, 17, 18, 19, 20}; +Plane Surface(2) = {2, 3}; + +Physical Surface("BEM_domain_1", 5) = {2}; +Physical Curve("BEM_FEM_boundary_1", 6) = {7, 8, 9, 10, 11}; +Physical Curve("electrode_1", 7) = {13, 14, 15, 16, 17, 18, 19, 20}; +Physical Curve("outside_1", 8) = {29, 30, 31}; + +phi_1 = 0.1; +SetNumber("Boundary Conditions/BEM_FEM_boundary_1/BEM_domain_1/dirichlet", 0); +SetNumber("Boundary Conditions/electrode_1/BEM_domain_1/dirichlet", phi_1); +SetNumber("Boundary Conditions/outside_1/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity + +// BEM domain 2 +Point(21) = {-(l_pin/2 + l_space + t_electrode), h_base/2 + h_space, 0, 0.2*scale}; // second fixed electrode +Point(22) = {-(l_pin/2 + l_space + t_electrode), h_base/2 + h_pin + h_space + t_electrode, 0, 0.2*scale}; +Point(23) = {l_pin/2 + l_space + t_electrode, h_base/2 + h_pin + h_space + t_electrode, 0, 0.2*scale}; +Point(24) = {l_pin/2 + l_space + t_electrode, h_base/2 + h_space, 0, 0.2*scale}; +Point(25) = {l_pin/2 + l_space, h_base/2 + h_space, 0, 0.2*scale}; +Point(26) = {l_pin/2 + l_space, h_base/2 + h_pin + h_space, 0, 0.2*scale}; +Point(27) = {-(l_pin/2 + l_space), h_base/2 + h_pin + h_space, 0, 0.2*scale}; +Point(28) = {-(l_pin/2 + l_space), h_base/2 + h_space, 0, 0.2*scale}; + + +Line(21) = {21, 22}; +Line(22) = {22, 23}; +Line(23) = {23, 24}; +Line(24) = {24, 25}; +Line(25) = {25, 26}; +Line(26) = {26, 27}; +Line(27) = {27, 28}; +Line(28) = {28, 21}; + +Point(31) = {l_tot/2, h_tot/2, 0, 0.2*scale}; +Point(32) = {-l_tot/2, h_tot/2, 0, 0.2*scale}; + +Line(32) = {6, 31}; +Line(33) = {31, 32}; +Line(34) = {32, 1}; + +Curve Loop(4) = {1, 2, 3, 4, 5, 32, 33, 34}; +Curve Loop(5) = {21, 22, 23, 24, 25, 26, 27, 28}; +Plane Surface(3) = {4, 5}; + +Physical Surface("BEM_domain_2", 9) = {3}; +Physical Curve("BEM_FEM_boundary_2", 10) = {1, 2, 3, 4, 5}; +Physical Curve("electrode_2", 11) = {21, 22, 23, 24, 25, 26, 27, 28}; +Physical Curve("outside_2", 12) = {32, 33, 34}; + +phi_2 = 25; +SetNumber("Boundary Conditions/BEM_FEM_boundary_2/BEM_domain_2/dirichlet", 0); +SetNumber("Boundary Conditions/electrode_2/BEM_domain_2/dirichlet", phi_2); +SetNumber("Boundary Conditions/outside_2/BEM_domain_2/neumann", 0); +SetNumber("Materials/BEM_domain_2/Epsilon", 8.8541878128e-12); // dielectric permittivity + + +Mesh.Algorithm = 8; \ No newline at end of file diff --git a/srcs/main.cpp b/srcs/main.cpp index e14a68ff713d1d4d4c8d0e2ab0e03695494e3c4c..1bacc6c05934e5e4f838becfe2b4f1a0f656bf6f 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -13,10 +13,11 @@ int main(int argc, char **argv) return 0; } - bool nonLinearSolver = true; // use non-linear solver or not + bool untangleMesh = false; // untangle geometry (deformed geometry, only available for nonLinear) // If compiled with OpenMP support, gmsh::initialize // also sets the number of threads to "General.NumThreads". + double start = omp_get_wtime(); int nthreads = omp_get_max_threads(); gmsh::initialize(); omp_set_num_threads(nthreads); @@ -26,6 +27,9 @@ int main(int argc, char **argv) Eigen::initParallel(); + // determine if non linear solver must be set + bool nonLinearSolver = getNonLinearParameter(); + if(nonLinearSolver) { @@ -42,11 +46,10 @@ int main(int argc, char **argv) int viewTagU = gmsh::view::add("u"); // à modifier plus tard int viewTagF = gmsh::view::add("f"); - - solverBEM(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, 1); - solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, 1, viewTagU, viewTagF); + solverBEM(electrostaticPressure, nbViews, boundaryDisplacementMap, postProcessing, 1, false); + solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, 1, viewTagU, viewTagF, false); std::vector<int> nodeTags(boundaryDisplacementMap.size()); std::vector<double> displacements(boundaryDisplacementMap.size()); @@ -55,7 +58,7 @@ int main(int argc, char **argv) double relativeDisplacement; const double criticalNorm = 0.0000001; - const int maxNbIteration = 10; // à modifier + const int maxNbIteration = 50; // à modifier int i = 0; for(auto p : boundaryDisplacementMap) @@ -67,8 +70,8 @@ int main(int argc, char **argv) for(iteration = 2; iteration <= maxNbIteration; iteration++) { - solverBEM(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration); - solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration, viewTagU, viewTagF); + solverBEM(electrostaticPressure, nbViews, boundaryDisplacementMap, postProcessing, iteration, false); + solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration, viewTagU, viewTagF, false); i = 0; relativeDisplacement = 0; @@ -87,54 +90,26 @@ int main(int argc, char **argv) } relativeDisplacement = sqrt(relativeDisplacement/i); //std::cout << iteration << ", " << relativeDisplacement << ";\n"; - // std::cout << "Iteration: " << iteration << "\t-> Averaged relative displacement = " << relativeDisplacement << "\n"; + std::cout << "Iteration: " << iteration << "\t-> Averaged relative displacement = " << relativeDisplacement << "\n"; if(relativeDisplacement < criticalNorm) break; } nbViews = 0; + solverBEM(electrostaticPressure, nbViews, boundaryDisplacementMap, postProcessing, iteration, false); postProcessing = true; - solverBEM(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration); - solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration, viewTagU, viewTagF); + solverFEMnonLinear(electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration, viewTagU, viewTagF, untangleMesh); - /*--------get physical groups--------------*/ - /*std::map<std::string, std::pair<int, int>> groups; - gmsh::vectorpair dimTags; - gmsh::model::getPhysicalGroups(dimTags); - for (std::size_t i = 0; i < dimTags.size(); ++i) + if(untangleMesh) { - int dim = dimTags[i].first; - int tag = dimTags[i].second; - std::string name; - gmsh::model::getPhysicalName(dim, tag, name); - groups[name] = {dim, tag}; + std::map<int,std::pair<double,double>> boundaryDisplacementMap2; + solverBEM(electrostaticPressure, nbViews, boundaryDisplacementMap2, postProcessing, iteration, untangleMesh); } - - std::string groupname = "BEM_domain"; - int dim = groups[groupname].first; - int tag = groups[groupname].second; - - std::vector<int> tags; - gmsh::model::getEntitiesForPhysicalGroup(dim, tag, tags); - - gmsh::vectorpair dimTagsBis(tags.size()); - for(size_t i = 0; i < tags.size(); i++) + else { - dimTagsBis[i] = std::pair<int,int>(dim, tags[i]); + solverBEM(electrostaticPressure, nbViews, boundaryDisplacementMap, postProcessing, iteration, false); } - - for(auto &p:boundaryDisplacementMap) - { - std::vector<double> coord, parametricCoord; - int dim, tag; - gmsh::model::mesh::getNode(p.first, coord, parametricCoord, dim, tag); - std::vector<double> total_disp = {coord[0] + p.second.first, coord[1] + p.second.second, coord[2]}; - gmsh::model::mesh::setNode(p.first, total_disp, {}); - } - gmsh::model::mesh::optimize("UntangleMeshGeometry", false, 1, dimTagsBis); - std::map<int,std::pair<double,double>> boundaryDisplacementMap2; - solverBEM(argc, argv, electrostaticPressure, boundaryDisplacementMap2, nbViews, postProcessing, iteration);*/ } else { @@ -145,7 +120,7 @@ int main(int argc, char **argv) int nbViews = 0; - solverBEM(electrostaticPressure, boundaryDisplacementMap, nbViews, true, 1); + solverBEM(electrostaticPressure, nbViews, boundaryDisplacementMap, true, 1, false); solverFEM(electrostaticPressure, nbViews); } @@ -153,130 +128,11 @@ int main(int argc, char **argv) //double fem_end = omp_get_wtime(); //std::cout << "time for FEM: " << fem_end - bem_end << "\n"; + double total_time = omp_get_wtime() - start; + std::cout << "total execution time: " << total_time << " [s]. \n"; + gmsh::fltk::run(); gmsh::finalize(); return 0; -} - - - - - - -// #include "functionsBEM.hpp" -// #include "functionsFEM.hpp" - -// #include <gmsh.h> -// #include <iostream> -// #include <omp.h> - -// int main(int argc, char **argv) -// { -// if (argc < 2) -// { -// std::cout << "Usage: " << argv[0] << " <geo_file>\n"; -// return 0; -// } - -// bool nonLinearSolver = true; // use non-linear solver or not - -// // If compiled with OpenMP support, gmsh::initialize -// // also sets the number of threads to "General.NumThreads". -// int nthreads = omp_get_max_threads(); -// gmsh::initialize(); -// omp_set_num_threads(nthreads); - -// gmsh::open(argv[1]); -// gmsh::model::mesh::generate(2); - -// Eigen::initParallel(); - -// if(nonLinearSolver) -// { - -// bool postProcessing = 0; // pass it as an argument to the solver, only compute post processing at last iteration - -// std::map<int, double> electrostaticPressure; -// std::map<int,std::pair<double,double>> boundaryDisplacementMap; - -// int nbViews = 0; -// //double start = omp_get_wtime(); - -// int iteration; - -// int viewTagU = gmsh::view::add("u"); // à modifier plus tard -// int viewTagF = gmsh::view::add("f"); - -// solverBEM(argc, argv, electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, 1); -// solverFEMnonLinear(argc, argv, electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, 1, viewTagU, viewTagF); - -// std::vector<int> nodeTags(boundaryDisplacementMap.size()); -// std::vector<double> displacements(boundaryDisplacementMap.size()); -// std::vector<double> previousDisplacements(boundaryDisplacementMap.size()); -// std::vector<double> relativeDifference(boundaryDisplacementMap.size()); - -// double norm; -// const double criticalNorm = 0.0001; -// const int maxNbIteration = 40; - -// int i = 0; -// for(auto p : boundaryDisplacementMap) -// { -// nodeTags[i] = p.first; -// displacements[i] = sqrt(p.second.first*p.second.first + p.second.second*p.second.second); -// i++; -// } - -// for(iteration = 2; iteration <= maxNbIteration; iteration++) -// { -// solverBEM(argc, argv, electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration); -// solverFEMnonLinear(argc, argv, electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration, viewTagU, viewTagF); - -// i = 0; -// norm = 0; -// for(auto p : boundaryDisplacementMap) -// { -// previousDisplacements[i] = displacements[i]; -// displacements[i] = sqrt(p.second.first*p.second.first + p.second.second*p.second.second); - -// if(previousDisplacements[i] != 0.0) -// relativeDifference[i] = abs( (displacements[i] - previousDisplacements[i]) / previousDisplacements[i] ); -// else -// relativeDifference[i] = 0; - -// norm += relativeDifference[i]*relativeDifference[i]; -// i++; -// } -// norm = sqrt(norm/i); -// std::cout << "Norm (iteration '" << iteration << "'): " << norm << "\n"; -// if(norm < criticalNorm) -// break; -// } - -// postProcessing = true; -// solverBEM(argc, argv, electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration); -// solverFEMnonLinear(argc, argv, electrostaticPressure, boundaryDisplacementMap, nbViews, postProcessing, iteration, viewTagU, viewTagF); -// } -// else -// { - -// std::map<int, double> electrostaticPressure; - -// std::map<int,std::pair<double,double>> boundaryDisplacementMap; - -// int nbViews = 0; - -// solverBEM(argc, argv, electrostaticPressure, boundaryDisplacementMap, nbViews, true, 1); -// solverFEM(argc, argv, electrostaticPressure, nbViews); - -// } - -// //double fem_end = omp_get_wtime(); -// //std::cout << "time for FEM: " << fem_end - bem_end << "\n"; - -// gmsh::fltk::run(); - -// gmsh::finalize(); -// return 0; -// } +} \ No newline at end of file diff --git a/srcs/squeeze.geo b/srcs/squeeze.geo index c5ec269c69880a8dcd24dc3a5edce4bf8e0dd808..ad1a4a9bd13f24d997c7c2e461eb74453df44709 100644 --- a/srcs/squeeze.geo +++ b/srcs/squeeze.geo @@ -96,3 +96,4 @@ phi_top = 20; SetNumber("Boundary Conditions/mass/BEM_domain_1/dirichlet", 0); SetNumber("Boundary Conditions/Electrode/BEM_domain_1/dirichlet", phi_top); SetNumber("Boundary Conditions/rest_of_outside/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity diff --git a/srcs/transverse_comb.geo b/srcs/transverse_comb.geo new file mode 100644 index 0000000000000000000000000000000000000000..21122d65ca96ae9a77466cb6eb8c97cf2f302e65 --- /dev/null +++ b/srcs/transverse_comb.geo @@ -0,0 +1,157 @@ +scale = 1e-5; + +h_tot = 20*scale; +h_base = 3*scale; +h_pin = 2.5*scale; +h_space = 1*scale; + +l_tot = 20*scale; +l_base = 1*scale; +l_pin = 0.8*scale; +l_space = 1.2*scale; + +t_electrode = 1*scale; // width of fixed electrodes +// FEM domain +Point(1) = {-l_tot/2, -h_tot/2, 0, 0.2*scale}; +Point(2) = {-l_tot/2, h_tot/2, 0, 0.2*scale}; +Point(3) = {-(l_tot/2 - l_base), h_tot/2, 0, 0.2*scale}; +Point(4) = {-(l_tot/2 - l_base), h_base/2, 0, 0.2*scale}; +Point(5) = {-l_pin/2, h_base/2, 0, 0.2*scale}; +Point(6) = {-l_pin/2, h_base/2 + h_pin, 0, 0.2*scale}; +Point(7) = {l_pin/2, h_base/2 + h_pin, 0, 0.2*scale}; +Point(8) = {l_pin/2, h_base/2, 0, 0.2*scale}; +Point(9) = {(l_tot/2 - l_base), h_base/2, 0, 0.2*scale}; +Point(10) = {(l_tot/2 - l_base), h_tot/2, 0, 0.2*scale}; +Point(11) = {l_tot/2, h_tot/2, 0, 0.2*scale}; +Point(12) = {l_tot/2, -h_tot/2, 0, 0.2*scale}; +Point(13) = {(l_tot/2 - l_base), -h_tot/2, 0, 0.2*scale}; +Point(14) = {(l_tot/2 - l_base), -h_base/2, 0, 0.2*scale}; +Point(15) = {l_pin/2, -h_base/2, 0, 0.2*scale}; +Point(16) = {l_pin/2, -(h_base/2 + h_pin), 0, 0.2*scale}; +Point(17) = {-l_pin/2, -(h_base/2 + h_pin), 0, 0.2*scale}; +Point(18) = {-l_pin/2, -h_base/2, 0, 0.2*scale}; +Point(19) = {-(l_tot/2 - l_base), -h_base/2, 0, 0.2*scale}; +Point(20) = {-(l_tot/2 - l_base), -h_tot/2, 0, 0.2*scale}; + +// FEM domain +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 5}; +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, 17}; +Line(17) = {17, 18}; +Line(18) = {18, 19}; +Line(19) = {19, 20}; +Line(20) = {20, 1}; + +Curve Loop(1) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}; +Plane Surface(1) = {1}; + +Recombine Surface {1}; // quads instead of triangles + +Physical Curve("bottom_left", 1) = {20}; +Physical Curve("top_left", 2) = {2}; +Physical Curve("top_right", 3) = {10}; +Physical Curve("bottom_right", 4) = {12}; + +Physical Surface("FEM_domain", 5) = {1}; +Physical Curve("BEM_FEM_boundary", 6) = {3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 16, 17, 18, 19}; + +// mechanical properties and boundary conditions +SetNumber("Boundary Conditions/bottom_left/ux", 0.); // encastrement +SetNumber("Boundary Conditions/bottom_left/uy", 0); +SetNumber("Boundary Conditions/top_left/ux", 0.); // encastrement +SetNumber("Boundary Conditions/top_left/uy", 0); +SetNumber("Boundary Conditions/top_right/ux", 0.); // encastrement +SetNumber("Boundary Conditions/top_right/uy", 0); +SetNumber("Boundary Conditions/bottom_right/ux", 0.); // encastrement +SetNumber("Boundary Conditions/bottom_right/uy", 0); +SetNumber("Materials/domain/Young", 210e3); // A DETERMINER PRECISEMENT +SetNumber("Materials/domain/Poisson", 0.3); +SetNumber("Materials/domain/rho",7800); //volumic mass of acier +SetNumber("Volumic Forces/FEM_domain/bx",50); // acceleration of accelerometer +SetNumber("Volumic Forces/FEM_domain/by",0.); + +// BEM domain 1 +Point(21) = {-(l_pin/2 + l_space + t_electrode), -(h_base/2 + h_pin + h_space + t_electrode), 0, 0.2*scale}; // first fixed electrode +Point(22) = {-(l_pin/2 + l_space + t_electrode), -(h_base/2 + h_space), 0, 0.2*scale}; +Point(23) = {-(l_pin/2 + l_space), -(h_base/2 + h_space), 0, 0.2*scale}; +Point(24) = {-(l_pin/2 + l_space), -(h_base/2 + h_pin + h_space), 0, 0.2*scale}; +Point(25) = {l_pin/2 + l_space, -(h_base/2 + h_pin + h_space), 0, 0.2*scale}; +Point(26) = {l_pin/2 + l_space, -(h_base/2 + h_space), 0, 0.2*scale}; +Point(27) = {l_pin/2 + l_space + t_electrode, -(h_base/2 + h_space), 0, 0.2*scale}; +Point(28) = {l_pin/2 + l_space + t_electrode, -(h_base/2 + h_pin + h_space + t_electrode), 0, 0.2*scale}; + +Line(21) = {21, 22}; +Line(22) = {22, 23}; +Line(23) = {23, 24}; +Line(24) = {24, 25}; +Line(25) = {25, 26}; +Line(26) = {26, 27}; +Line(27) = {27, 28}; +Line(28) = {28, 21}; + +Line(37) = {20, 13}; + +Curve Loop(2) = {37, 13, 14, 15, 16, 17, 18, 19}; +Curve Loop(3) = {21, 22, 23, 24, 25, 26, 27, 28}; +Plane Surface(2) = {2, 3}; + +Physical Surface("BEM_domain_1", 7) = {2}; +Physical Curve("BEM_FEM_boundary_1", 8) = {13, 14, 15, 16, 17, 18, 19}; +Physical Curve("electrode_1", 9) = {21, 22, 23, 24, 25, 26, 27, 28}; +Physical Curve("outside_1", 10) = {37}; + +phi_1 = 30; +SetNumber("Boundary Conditions/BEM_FEM_boundary_1/BEM_domain_1/dirichlet", 0); +SetNumber("Boundary Conditions/electrode_1/BEM_domain_1/dirichlet", phi_1); +SetNumber("Boundary Conditions/outside_1/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity + +// BEM domain 2 +Point(29) = {-(l_pin/2 + l_space + t_electrode), h_base/2 + h_space, 0, 0.2*scale}; // second fixed electrode +Point(30) = {-(l_pin/2 + l_space + t_electrode), h_base/2 + h_pin + h_space + t_electrode, 0, 0.2*scale}; +Point(31) = {l_pin/2 + l_space + t_electrode, h_base/2 + h_pin + h_space + t_electrode, 0, 0.2*scale}; +Point(32) = {l_pin/2 + l_space + t_electrode, h_base/2 + h_space, 0, 0.2*scale}; +Point(33) = {l_pin/2 + l_space, h_base/2 + h_space, 0, 0.2*scale}; +Point(34) = {l_pin/2 + l_space, h_base/2 + h_pin + h_space, 0, 0.2*scale}; +Point(35) = {-(l_pin/2 + l_space), h_base/2 + h_pin + h_space, 0, 0.2*scale}; +Point(36) = {-(l_pin/2 + l_space), h_base/2 + h_space, 0, 0.2*scale}; + + +Line(29) = {29, 30}; +Line(30) = {30, 31}; +Line(31) = {31, 32}; +Line(32) = {32, 33}; +Line(33) = {33, 34}; +Line(34) = {34, 35}; +Line(35) = {35, 36}; +Line(36) = {36, 29}; + +Line(38) = {10, 3}; + +Curve Loop(4) = {38, 3, 4, 5, 6, 7, 8, 9}; +Curve Loop(5) = {29, 30, 31, 32, 33, 34, 35, 36}; +Plane Surface(3) = {4, 5}; + +Physical Surface("BEM_domain_2", 11) = {3}; +Physical Curve("BEM_FEM_boundary_2", 12) = {3, 4, 5, 6, 7, 8, 9}; +Physical Curve("electrode_2", 13) = {29, 30, 31, 32, 33, 34, 35, 36}; +Physical Curve("outside_2", 14) = {38}; + +phi_2 = 30; +SetNumber("Boundary Conditions/BEM_FEM_boundary_2/BEM_domain_2/dirichlet", 0); +SetNumber("Boundary Conditions/electrode_2/BEM_domain_2/dirichlet", phi_2); +SetNumber("Boundary Conditions/outside_2/BEM_domain_2/neumann", 0); +SetNumber("Materials/BEM_domain_2/Epsilon", 8.8541878128e-12); // dielectric permittivity \ No newline at end of file diff --git a/srcs/two_BEM_test.geo b/srcs/two_BEM_test.geo index 4b28915da7ee848fdd7038c28ee334b38467eb73..89926c27ade94d3510c858b0f78b71bc8ac2cc14 100644 --- a/srcs/two_BEM_test.geo +++ b/srcs/two_BEM_test.geo @@ -92,5 +92,7 @@ Physical Curve("bottom2", 18) = {10}; Physical Curve("top2", 19) = {5}; SetNumber("Boundary Conditions/left1/BEM_domain_1/neumann", 0); SetNumber("Boundary Conditions/right1/BEM_domain_1/neumann", 0); +SetNumber("Materials/BEM_domain_1/Epsilon", 8.8541878128e-12); // dielectric permittivity SetNumber("Boundary Conditions/bottom2/BEM_domain_2/neumann", 0); SetNumber("Boundary Conditions/top2/BEM_domain_2/neumann", 0); +SetNumber("Materials/BEM_domain_2/Epsilon", 8.8541878128e-12); // dielectric permittivity