From 1b0c42f08af68f397d5caeeaf8fdc8290d6ec06a Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Thu, 15 Mar 2018 17:38:47 +0100 Subject: [PATCH] use DOS end of lines --- CircuitCoupling/RLC_circuit.geo | 66 +- CircuitCoupling/RLC_circuit.pro | 730 +++++++-------- CircuitCoupling/RLC_circuit_common.pro | 24 +- CircuitCoupling/R_circuit.geo | 78 +- CircuitCoupling/R_circuit.pro | 684 +++++++------- CircuitCoupling/R_circuit_common.pro | 30 +- Elasticity/wrench2D.geo | 144 +-- Elasticity/wrench2D.pro | 731 ++++++++------- Elasticity/wrench2D_common.pro | 58 +- Electrostatics/microstrip.geo | 116 +-- Electrostatics/microstrip.pro | 651 +++++++------- Magnetodynamics/Lib_MagStaDyn_av_2D_Cir.pro | 936 ++++++++++---------- Magnetodynamics/electromagnet.geo | 108 +-- Magnetodynamics/electromagnet.pro | 178 ++-- Magnetodynamics/electromagnet_common.pro | 8 +- Magnetodynamics/transfo.geo | 346 ++++---- Magnetodynamics/transfo.pro | 518 +++++------ Magnetodynamics/transfo_common.pro | 98 +- Magnetostatics/electromagnet.geo | 108 +-- Magnetostatics/electromagnet.pro | 534 +++++------ Magnetostatics/electromagnet_common.pro | 8 +- PotentialFlow/magnus.geo | 142 +-- PotentialFlow/magnus.pro | 849 +++++++++--------- PotentialFlow/magnus_common.pro | 54 +- PotentialFlow/nacaAirfoil.geo | 444 +++++----- Thermics/brick.geo | 222 ++--- Thermics/brick.pro | 906 ++++++++++--------- Thermics/brick_common.pro | 74 +- 28 files changed, 4415 insertions(+), 4430 deletions(-) diff --git a/CircuitCoupling/RLC_circuit.geo b/CircuitCoupling/RLC_circuit.geo index 2bb9299..cd10b79 100644 --- a/CircuitCoupling/RLC_circuit.geo +++ b/CircuitCoupling/RLC_circuit.geo @@ -1,33 +1,33 @@ -// Just 3 cubes - -Include "RLC_circuit_common.pro"; - -lc = 0.25; // Characteristic length - -Point(1) = {0, 0, 0, lc}; -Extrude {1, 0, 0} { - Point{1}; -} -Extrude {0, 1, 0} { - Line{1}; -} -Extrude {0, 0, 1} { - Surface{5}; -} -Translate {2, 0, 0} { - Duplicata { Volume{1}; } -} -Translate {4, 0, 0} { - Duplicata { Volume{1}; } -} - -Physical Surface(Cube1Top) = {27}; -Physical Surface(Cube1Bottom) = {5}; -Physical Surface(Cube2Top) = {34}; -Physical Surface(Cube2Bottom) = {29}; -Physical Surface(Cube3Top) = {61}; -Physical Surface(Cube3Bottom) = {56}; - -Physical Volume(Cube1) = {1}; -Physical Volume(Cube2) = {28}; -Physical Volume(Cube3) = {55}; +// Just 3 cubes + +Include "RLC_circuit_common.pro"; + +lc = 0.25; // Characteristic length + +Point(1) = {0, 0, 0, lc}; +Extrude {1, 0, 0} { + Point{1}; +} +Extrude {0, 1, 0} { + Line{1}; +} +Extrude {0, 0, 1} { + Surface{5}; +} +Translate {2, 0, 0} { + Duplicata { Volume{1}; } +} +Translate {4, 0, 0} { + Duplicata { Volume{1}; } +} + +Physical Surface(Cube1Top) = {27}; +Physical Surface(Cube1Bottom) = {5}; +Physical Surface(Cube2Top) = {34}; +Physical Surface(Cube2Bottom) = {29}; +Physical Surface(Cube3Top) = {61}; +Physical Surface(Cube3Bottom) = {56}; + +Physical Volume(Cube1) = {1}; +Physical Volume(Cube2) = {28}; +Physical Volume(Cube3) = {55}; diff --git a/CircuitCoupling/RLC_circuit.pro b/CircuitCoupling/RLC_circuit.pro index ff8fae3..9f76616 100644 --- a/CircuitCoupling/RLC_circuit.pro +++ b/CircuitCoupling/RLC_circuit.pro @@ -1,365 +1,365 @@ -/* ------------------------------------------------------------------- - Tutorial 8b : circuit coupling - RLC circuit - - Features: - - Electrokinetic formulation coupled with RLC circuit - - Transient resolution - - To compute the solution in a terminal: - getdp RLC_circuit -solve dynamic -pos Cube_Top_Values_ASCII - - To compute the solution interactively from the Gmsh GUI: - File > Open > RLC_circuit.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -/* - This example shows how to implement a circuit with discrete resistors, - capacitors, inductors, voltage- and current-sources in a transient finite - element simulation. There are three separate cubes, each with a certain - conductivity. The bottom of all cubes is kept at 0V via the constraint - Voltage_3D. The cubes are connected according the `RLC_circuit.jpg` schematic. -*/ - -Include "RLC_circuit_common.pro"; - -// FEM domain group data -Group { - // Surfaces - Top1 = Region[Cube1Top]; - Bottom1 = Region[Cube1Bottom]; - Top2 = Region[Cube2Top]; - Bottom2 = Region[Cube2Bottom]; - Top3 = Region[Cube3Top]; - Bottom3 = Region[Cube3Bottom]; - - // Volumes - Cube1 = Region[Cube1]; - Cube2 = Region[Cube2]; - Cube3 = Region[Cube3]; - - // FEM Electrical regions - // * all volumes - Vol_Ele = Region[{Cube1, Cube2, Cube3}]; - // * all surfaces connected to the lumped element circuit - Sur_Ele = Region[{Top1, Bottom1, Top2, Bottom2, Top3, Bottom3}]; - // * total electrical computation domain - VolWithSur_Ele = Region[{Vol_Ele, Sur_Ele}]; -} - -// Circuit group data - Fictive regions for the circuit elements -Group { - - // Sources - CurrentSource1 = Region[{3001}]; - VoltageSource1 = Region[{3002}]; - - // Resistors - R1 = Region[{4001}]; - R2 = Region[{4002}]; - - // Inductors - L1 = Region[{4003}]; - - // Capacitors - C1 = Region[{4004}]; - - Resistance_Cir = Region[{R1, R2}]; // All resistors - Inductance_Cir = Region[{L1}]; // All inductors - Capacitance_Cir = Region[{C1}]; // All capacitors - SourceI_Cir = Region[{CurrentSource1}]; // All current sources - SourceV_Cir = Region[{VoltageSource1}]; // All voltage sources - - // Complete circuit domain containing all circuit elements - Domain_Cir = Region[{Resistance_Cir, Inductance_Cir, Capacitance_Cir, - SourceI_Cir, SourceV_Cir}]; -} - -Function { - // Simulation parameters - tStop = 10.0e-6; // Stop time [s] - tStep = 100e-9; // Time step [s] - nStrobe= 1; // Strobe periode for saving the result - - SaveFct[] = !($TimeStep % nStrobe); // Only each nStrobe-th time-step is saved - - // FEM domain function data - // ------------------------ - - Vbottom = 0.0; // Absolute voltage at the bottom of all cubes - - // Geometry of a cube - w = 1.0; // Width [m] - l = 1.0; // Length [m] - h = 1.0; // Height [m] - - // Resistance - Rcube1 = 10.0; // Resistance of cube 1 [Ohm] - Rcube2 = 40.0; // Resistance of cube 2 [Ohm] - Rcube3 = 20.0; // Resistance of cube 3 [Ohm] - - // Specific electrical conductivity [S*m/m^2] - kappa[Cube1] = h / (w * l * Rcube1); - kappa[Cube2] = h / (w * l * Rcube2); - kappa[Cube3] = h / (w * l * Rcube3); - - // Circuit domain function data - // ---------------------------- - - // Resistors - R[R1] = 30.0; // Resistance of R1 [Ohm] - R[R2] = 40.0; // Resistance of R2 [Ohm] - - // Inductors - L[L1] = 100.0e-6; // Inductance of L1 [H] - - // Capacitors - C[C1] = 250.0e-9; // Capacitance of C1 [F] - - // Note: All voltages and currents are assigned / initialized in the - // Constraint-block -} - -// FEM domain constraint data -Constraint { - { Name Current_3D ; Type Assign ; - Case { - } - } - { Name Voltage_3D ; Type Assign ; - Case { - { Region Bottom1; Type Assign; Value Vbottom; } - { Region Bottom2; Type Assign; Value Vbottom; } - { Region Bottom3; Type Assign; Value Vbottom; } - } - } -} - -// Circuit domain constraint data -Constraint { - { Name Current_Cir ; - Case { - { Region CurrentSource1; Type Assign; Value 1.0; } // CurrentSource1 has 1.0 A - { Region L1; Type Init; Value 1.0; } // Initial current of L1 is 1.0 A - } - } - { Name Voltage_Cir ; - Case { - { Region VoltageSource1; Type Assign; Value 80.0; } // VoltageSource1 has 80.0 V - { Region C1; Type Init; Value 0.0; } // Initial voltage of C1 = 0.0 V - } - } - - { Name ElectricalCircuit ; Type Network ; - Case Circuit1 { - // Circuit for cube 1: - { Region VoltageSource1; Branch{ 1, 10};} - { Region R1; Branch{ 1, 2};} - // The voltage between nodes 2 and 3 corresponds to the absolute voltage - // of the surface Top1: - { Region Top1; Branch{ 2, 3};} - // Note the reverse order of the nodes in the next branch: it's for - // subtracting the bottom voltage. - { Region Bottom1; Branch{ 10, 3};} - // With the two lines above, the voltage between node 2 and 10 corresponds - // to the voltage drop over the cube regardless what the absolute voltages - // are. The current between node 2 and 3 corresponds to the absolute - // current flowing through Top1. The same is valid for Bottom1. Due to the - // reverse order here the current has the opposite sign. This is correct - // because the current flowing IN Top1 is flowing OUT of Bottom1. Note - // that in this particular circuit it is actually not necessary to include - // the bottom faces in the netlist, because all bottoms are kept at 0 V - // via constraint Voltage_3D... But then all Bottom faces have to be - // excluded also in the region Sur_Ele! - - // Circuit for cube 2: - { Region L1; Branch{ 4, 10};} - { Region R2; Branch{ 4, 10};} - { Region Top2; Branch{ 4, 5};} - { Region Bottom2; Branch{10, 5};} - - // Circuit for cube 3 - { Region CurrentSource1; Branch{ 6, 10};} - { Region C1; Branch{ 6, 10};} - { Region Top3; Branch{ 6, 7};} - { Region Bottom3; Branch{10, 7};} - } - } -} - -Jacobian { - { Name JVol ; - Case { - { Region Region[{Vol_Ele}]; Jacobian Vol; } - { Region Region[{Sur_Ele}]; Jacobian Sur; } - } - } -} - -Integration { - { Name I1 ; - Case { - { Type Gauss ; - Case { - { GeoElement Point ; NumberOfPoints 1 ; } - { GeoElement Line ; NumberOfPoints 5 ; } - { GeoElement Triangle ; NumberOfPoints 6 ; } - { GeoElement Quadrangle ; NumberOfPoints 7 ; } - { GeoElement Tetrahedron ; NumberOfPoints 15 ; } - { GeoElement Hexahedron ; NumberOfPoints 34 ; } - { GeoElement Prism ; NumberOfPoints 21 ; } - } - } - } - } -} - -FunctionSpace { - // Function space for the FEM domain - { Name Hgrad_V; Type Form0; - BasisFunction { - // All nodes but the grouped nodes of the surfaces for connecting the - // circuitry - { Name sn; NameOfCoef vn; Function BF_Node; - Support VolWithSur_Ele; Entity NodesOf[ All, Not Sur_Ele ]; } - // Grouped nodes: Each surface of Sur_Ele has just one single voltage - { Name sf; NameOfCoef vf; Function BF_GroupOfNodes; - Support VolWithSur_Ele; Entity GroupsOfNodesOf[ Sur_Ele ]; } - } - GlobalQuantity { - { Name U; Type AliasOf; NameOfCoef vf; } - { Name I; Type AssociatedWith; NameOfCoef vf; } - } - Constraint { - { NameOfCoef vn; EntityType NodesOf ; NameOfConstraint Voltage_3D; } - { NameOfCoef U; EntityType GroupsOfNodesOf ; NameOfConstraint Voltage_3D; } - { NameOfCoef I; EntityType GroupsOfNodesOf ; NameOfConstraint Current_3D; } - } - } - - // Function space for the circuit domain - { Name Hregion_Cir; Type Scalar; - BasisFunction { - { Name sn; NameOfCoef ir; Function BF_Region; - Support Domain_Cir; Entity Domain_Cir; } - } - GlobalQuantity { - { Name Iz; Type AliasOf; NameOfCoef ir; } - { Name Uz; Type AssociatedWith; NameOfCoef ir; } - } - Constraint { - { NameOfCoef Uz ; EntityType Region ; NameOfConstraint Voltage_Cir ; } - { NameOfCoef Iz ; EntityType Region ; NameOfConstraint Current_Cir ; } - } - } - -} - - -Formulation { - { Name dynamic; Type FemEquation; - Quantity { - { Name V; Type Local; NameOfSpace Hgrad_V; } - { Name U; Type Global; NameOfSpace Hgrad_V [U]; } - { Name I; Type Global; NameOfSpace Hgrad_V [I]; } - { Name Uz; Type Global; NameOfSpace Hregion_Cir [Uz]; } - { Name Iz; Type Global; NameOfSpace Hregion_Cir [Iz]; } - } - Equation { - // FEM domain - Galerkin { [ kappa[] * Dof{d V}, {d V} ]; In Vol_Ele; - Integration I1; Jacobian JVol; } - GlobalTerm{ [ Dof{I}, {U} ]; In Sur_Ele; } - - // Circuit related terms - // Resistance equation - GlobalTerm{ [ Dof{Uz}, {Iz} ]; In Resistance_Cir; } - GlobalTerm{ [ R[] * Dof{Iz}, {Iz} ]; In Resistance_Cir; } - - // Inductance equation - GlobalTerm{ [ Dof{Uz}, {Iz} ]; In Inductance_Cir; } - GlobalTerm{ DtDof[ L[] * Dof{Iz}, {Iz} ]; In Inductance_Cir; } - - // Capacitance equation - GlobalTerm{ [ Dof{Iz}, {Iz} ]; In Capacitance_Cir; } - GlobalTerm{ DtDof[ C[] * Dof{Uz}, {Iz} ]; In Capacitance_Cir; } - - // Inserting the network - GlobalEquation { Type Network; NameOfConstraint ElectricalCircuit; - { Node {I}; Loop {U}; Equation {I}; In Sur_Ele; } - { Node {Iz}; Loop {Uz}; Equation {Uz}; In Domain_Cir; } - } - } - } -} - -Resolution { - { Name dynamic; - System { - { Name A; NameOfFormulation dynamic; } - } - Operation { - InitSolution[A]; - TimeLoopTheta[0.0, tStop, tStep, 1.0]{ - Generate[A]; - Solve[A]; - Test[SaveFct[]] { SaveSolution[A]; } - } - } - } -} - -PostProcessing { - { Name Ele; NameOfFormulation dynamic; - Quantity { - { Name V; Value{ Local{ [ {V} ]; In Vol_Ele; Jacobian JVol;} } } - { Name Jv; Value{ Local{ [ -kappa[]*{d V} ]; In Vol_Ele; Jacobian JVol;} } } - { Name J; Value{ Local{ [ Norm[kappa[]*{d V}] ]; In Vol_Ele; Jacobian JVol;} } } - { Name U; Value { Term { [ {U} ]; In Sur_Ele; } } } - // The minus sign here is for getting positive currents at the top of the - // cubes. This is because incomming currents are negative. - { Name I; Value { Term { [ -{I} ]; In Sur_Ele; } } } - } - } -} - -PostOperation { - // Absolute voltage everywhere [V] - { Name V; NameOfPostProcessing Ele; - Operation { - Print[ V, OnElementsOf Vol_Ele, TimeLegend, File "Result_V.pos"]; - } - } - // Current through the top surfaces of the cubes [A] - { Name I_Top; NameOfPostProcessing Ele; - Operation { - Print[ I, OnElementsOf Region[{Top1, Top2, Top3}], TimeLegend, - File "Result_I_Top.pos"]; - } - } - // Current density vectors everywhere [A/m^2] - { Name J_vectors; NameOfPostProcessing Ele; - Operation { - Print[ Jv, OnElementsOf Vol_Ele, TimeLegend, File "Result_J_vectors.pos"]; - } - } - // Magnitude of current density everywhere [A/m^2] - { Name J_magnitude; NameOfPostProcessing Ele; - Operation { - Print[ J, OnElementsOf Vol_Ele, TimeLegend, File "Result_J.pos"]; - } - } - // Store the results in an ASCII file - { Name Cube_Top_Values_ASCII; NameOfPostProcessing Ele; - Operation { - Print[U, OnRegion Top1, File "Result_Cube1TopValues.txt", Format TimeTable]; - Print[U, OnRegion Top2, File "Result_Cube2TopValues.txt", Format TimeTable]; - Print[U, OnRegion Top3, File "Result_Cube3TopValues.txt", Format TimeTable]; - - Print[I, OnRegion Top1, File > "Result_Cube1TopValues.txt", Format TimeTable]; - Print[I, OnRegion Top2, File > "Result_Cube2TopValues.txt", Format TimeTable]; - Print[I, OnRegion Top3, File > "Result_Cube3TopValues.txt", Format TimeTable]; - } - } - -} +/* ------------------------------------------------------------------- + Tutorial 8b : circuit coupling - RLC circuit + + Features: + - Electrokinetic formulation coupled with RLC circuit + - Transient resolution + + To compute the solution in a terminal: + getdp RLC_circuit -solve dynamic -pos Cube_Top_Values_ASCII + + To compute the solution interactively from the Gmsh GUI: + File > Open > RLC_circuit.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +/* + This example shows how to implement a circuit with discrete resistors, + capacitors, inductors, voltage- and current-sources in a transient finite + element simulation. There are three separate cubes, each with a certain + conductivity. The bottom of all cubes is kept at 0V via the constraint + Voltage_3D. The cubes are connected according the `RLC_circuit.jpg` schematic. +*/ + +Include "RLC_circuit_common.pro"; + +// FEM domain group data +Group { + // Surfaces + Top1 = Region[Cube1Top]; + Bottom1 = Region[Cube1Bottom]; + Top2 = Region[Cube2Top]; + Bottom2 = Region[Cube2Bottom]; + Top3 = Region[Cube3Top]; + Bottom3 = Region[Cube3Bottom]; + + // Volumes + Cube1 = Region[Cube1]; + Cube2 = Region[Cube2]; + Cube3 = Region[Cube3]; + + // FEM Electrical regions + // * all volumes + Vol_Ele = Region[{Cube1, Cube2, Cube3}]; + // * all surfaces connected to the lumped element circuit + Sur_Ele = Region[{Top1, Bottom1, Top2, Bottom2, Top3, Bottom3}]; + // * total electrical computation domain + VolWithSur_Ele = Region[{Vol_Ele, Sur_Ele}]; +} + +// Circuit group data - Fictive regions for the circuit elements +Group { + + // Sources + CurrentSource1 = Region[{3001}]; + VoltageSource1 = Region[{3002}]; + + // Resistors + R1 = Region[{4001}]; + R2 = Region[{4002}]; + + // Inductors + L1 = Region[{4003}]; + + // Capacitors + C1 = Region[{4004}]; + + Resistance_Cir = Region[{R1, R2}]; // All resistors + Inductance_Cir = Region[{L1}]; // All inductors + Capacitance_Cir = Region[{C1}]; // All capacitors + SourceI_Cir = Region[{CurrentSource1}]; // All current sources + SourceV_Cir = Region[{VoltageSource1}]; // All voltage sources + + // Complete circuit domain containing all circuit elements + Domain_Cir = Region[{Resistance_Cir, Inductance_Cir, Capacitance_Cir, + SourceI_Cir, SourceV_Cir}]; +} + +Function { + // Simulation parameters + tStop = 10.0e-6; // Stop time [s] + tStep = 100e-9; // Time step [s] + nStrobe= 1; // Strobe periode for saving the result + + SaveFct[] = !($TimeStep % nStrobe); // Only each nStrobe-th time-step is saved + + // FEM domain function data + // ------------------------ + + Vbottom = 0.0; // Absolute voltage at the bottom of all cubes + + // Geometry of a cube + w = 1.0; // Width [m] + l = 1.0; // Length [m] + h = 1.0; // Height [m] + + // Resistance + Rcube1 = 10.0; // Resistance of cube 1 [Ohm] + Rcube2 = 40.0; // Resistance of cube 2 [Ohm] + Rcube3 = 20.0; // Resistance of cube 3 [Ohm] + + // Specific electrical conductivity [S*m/m^2] + kappa[Cube1] = h / (w * l * Rcube1); + kappa[Cube2] = h / (w * l * Rcube2); + kappa[Cube3] = h / (w * l * Rcube3); + + // Circuit domain function data + // ---------------------------- + + // Resistors + R[R1] = 30.0; // Resistance of R1 [Ohm] + R[R2] = 40.0; // Resistance of R2 [Ohm] + + // Inductors + L[L1] = 100.0e-6; // Inductance of L1 [H] + + // Capacitors + C[C1] = 250.0e-9; // Capacitance of C1 [F] + + // Note: All voltages and currents are assigned / initialized in the + // Constraint-block +} + +// FEM domain constraint data +Constraint { + { Name Current_3D ; Type Assign ; + Case { + } + } + { Name Voltage_3D ; Type Assign ; + Case { + { Region Bottom1; Type Assign; Value Vbottom; } + { Region Bottom2; Type Assign; Value Vbottom; } + { Region Bottom3; Type Assign; Value Vbottom; } + } + } +} + +// Circuit domain constraint data +Constraint { + { Name Current_Cir ; + Case { + { Region CurrentSource1; Type Assign; Value 1.0; } // CurrentSource1 has 1.0 A + { Region L1; Type Init; Value 1.0; } // Initial current of L1 is 1.0 A + } + } + { Name Voltage_Cir ; + Case { + { Region VoltageSource1; Type Assign; Value 80.0; } // VoltageSource1 has 80.0 V + { Region C1; Type Init; Value 0.0; } // Initial voltage of C1 = 0.0 V + } + } + + { Name ElectricalCircuit ; Type Network ; + Case Circuit1 { + // Circuit for cube 1: + { Region VoltageSource1; Branch{ 1, 10};} + { Region R1; Branch{ 1, 2};} + // The voltage between nodes 2 and 3 corresponds to the absolute voltage + // of the surface Top1: + { Region Top1; Branch{ 2, 3};} + // Note the reverse order of the nodes in the next branch: it's for + // subtracting the bottom voltage. + { Region Bottom1; Branch{ 10, 3};} + // With the two lines above, the voltage between node 2 and 10 corresponds + // to the voltage drop over the cube regardless what the absolute voltages + // are. The current between node 2 and 3 corresponds to the absolute + // current flowing through Top1. The same is valid for Bottom1. Due to the + // reverse order here the current has the opposite sign. This is correct + // because the current flowing IN Top1 is flowing OUT of Bottom1. Note + // that in this particular circuit it is actually not necessary to include + // the bottom faces in the netlist, because all bottoms are kept at 0 V + // via constraint Voltage_3D... But then all Bottom faces have to be + // excluded also in the region Sur_Ele! + + // Circuit for cube 2: + { Region L1; Branch{ 4, 10};} + { Region R2; Branch{ 4, 10};} + { Region Top2; Branch{ 4, 5};} + { Region Bottom2; Branch{10, 5};} + + // Circuit for cube 3 + { Region CurrentSource1; Branch{ 6, 10};} + { Region C1; Branch{ 6, 10};} + { Region Top3; Branch{ 6, 7};} + { Region Bottom3; Branch{10, 7};} + } + } +} + +Jacobian { + { Name JVol ; + Case { + { Region Region[{Vol_Ele}]; Jacobian Vol; } + { Region Region[{Sur_Ele}]; Jacobian Sur; } + } + } +} + +Integration { + { Name I1 ; + Case { + { Type Gauss ; + Case { + { GeoElement Point ; NumberOfPoints 1 ; } + { GeoElement Line ; NumberOfPoints 5 ; } + { GeoElement Triangle ; NumberOfPoints 6 ; } + { GeoElement Quadrangle ; NumberOfPoints 7 ; } + { GeoElement Tetrahedron ; NumberOfPoints 15 ; } + { GeoElement Hexahedron ; NumberOfPoints 34 ; } + { GeoElement Prism ; NumberOfPoints 21 ; } + } + } + } + } +} + +FunctionSpace { + // Function space for the FEM domain + { Name Hgrad_V; Type Form0; + BasisFunction { + // All nodes but the grouped nodes of the surfaces for connecting the + // circuitry + { Name sn; NameOfCoef vn; Function BF_Node; + Support VolWithSur_Ele; Entity NodesOf[ All, Not Sur_Ele ]; } + // Grouped nodes: Each surface of Sur_Ele has just one single voltage + { Name sf; NameOfCoef vf; Function BF_GroupOfNodes; + Support VolWithSur_Ele; Entity GroupsOfNodesOf[ Sur_Ele ]; } + } + GlobalQuantity { + { Name U; Type AliasOf; NameOfCoef vf; } + { Name I; Type AssociatedWith; NameOfCoef vf; } + } + Constraint { + { NameOfCoef vn; EntityType NodesOf ; NameOfConstraint Voltage_3D; } + { NameOfCoef U; EntityType GroupsOfNodesOf ; NameOfConstraint Voltage_3D; } + { NameOfCoef I; EntityType GroupsOfNodesOf ; NameOfConstraint Current_3D; } + } + } + + // Function space for the circuit domain + { Name Hregion_Cir; Type Scalar; + BasisFunction { + { Name sn; NameOfCoef ir; Function BF_Region; + Support Domain_Cir; Entity Domain_Cir; } + } + GlobalQuantity { + { Name Iz; Type AliasOf; NameOfCoef ir; } + { Name Uz; Type AssociatedWith; NameOfCoef ir; } + } + Constraint { + { NameOfCoef Uz ; EntityType Region ; NameOfConstraint Voltage_Cir ; } + { NameOfCoef Iz ; EntityType Region ; NameOfConstraint Current_Cir ; } + } + } + +} + + +Formulation { + { Name dynamic; Type FemEquation; + Quantity { + { Name V; Type Local; NameOfSpace Hgrad_V; } + { Name U; Type Global; NameOfSpace Hgrad_V [U]; } + { Name I; Type Global; NameOfSpace Hgrad_V [I]; } + { Name Uz; Type Global; NameOfSpace Hregion_Cir [Uz]; } + { Name Iz; Type Global; NameOfSpace Hregion_Cir [Iz]; } + } + Equation { + // FEM domain + Integral { [ kappa[] * Dof{d V}, {d V} ]; In Vol_Ele; + Integration I1; Jacobian JVol; } + GlobalTerm{ [ Dof{I}, {U} ]; In Sur_Ele; } + + // Circuit related terms + // Resistance equation + GlobalTerm{ [ Dof{Uz}, {Iz} ]; In Resistance_Cir; } + GlobalTerm{ [ R[] * Dof{Iz}, {Iz} ]; In Resistance_Cir; } + + // Inductance equation + GlobalTerm{ [ Dof{Uz}, {Iz} ]; In Inductance_Cir; } + GlobalTerm{ DtDof[ L[] * Dof{Iz}, {Iz} ]; In Inductance_Cir; } + + // Capacitance equation + GlobalTerm{ [ Dof{Iz}, {Iz} ]; In Capacitance_Cir; } + GlobalTerm{ DtDof[ C[] * Dof{Uz}, {Iz} ]; In Capacitance_Cir; } + + // Inserting the network + GlobalEquation { Type Network; NameOfConstraint ElectricalCircuit; + { Node {I}; Loop {U}; Equation {I}; In Sur_Ele; } + { Node {Iz}; Loop {Uz}; Equation {Uz}; In Domain_Cir; } + } + } + } +} + +Resolution { + { Name dynamic; + System { + { Name A; NameOfFormulation dynamic; } + } + Operation { + InitSolution[A]; + TimeLoopTheta[0.0, tStop, tStep, 1.0]{ + Generate[A]; + Solve[A]; + Test[SaveFct[]] { SaveSolution[A]; } + } + } + } +} + +PostProcessing { + { Name Ele; NameOfFormulation dynamic; + Quantity { + { Name V; Value{ Local{ [ {V} ]; In Vol_Ele; Jacobian JVol;} } } + { Name Jv; Value{ Local{ [ -kappa[]*{d V} ]; In Vol_Ele; Jacobian JVol;} } } + { Name J; Value{ Local{ [ Norm[kappa[]*{d V}] ]; In Vol_Ele; Jacobian JVol;} } } + { Name U; Value { Term { [ {U} ]; In Sur_Ele; } } } + // The minus sign here is for getting positive currents at the top of the + // cubes. This is because incomming currents are negative. + { Name I; Value { Term { [ -{I} ]; In Sur_Ele; } } } + } + } +} + +PostOperation { + // Absolute voltage everywhere [V] + { Name V; NameOfPostProcessing Ele; + Operation { + Print[ V, OnElementsOf Vol_Ele, TimeLegend, File "Result_V.pos"]; + } + } + // Current through the top surfaces of the cubes [A] + { Name I_Top; NameOfPostProcessing Ele; + Operation { + Print[ I, OnElementsOf Region[{Top1, Top2, Top3}], TimeLegend, + File "Result_I_Top.pos"]; + } + } + // Current density vectors everywhere [A/m^2] + { Name J_vectors; NameOfPostProcessing Ele; + Operation { + Print[ Jv, OnElementsOf Vol_Ele, TimeLegend, File "Result_J_vectors.pos"]; + } + } + // Magnitude of current density everywhere [A/m^2] + { Name J_magnitude; NameOfPostProcessing Ele; + Operation { + Print[ J, OnElementsOf Vol_Ele, TimeLegend, File "Result_J.pos"]; + } + } + // Store the results in an ASCII file + { Name Cube_Top_Values_ASCII; NameOfPostProcessing Ele; + Operation { + Print[U, OnRegion Top1, File "Result_Cube1TopValues.txt", Format TimeTable]; + Print[U, OnRegion Top2, File "Result_Cube2TopValues.txt", Format TimeTable]; + Print[U, OnRegion Top3, File "Result_Cube3TopValues.txt", Format TimeTable]; + + Print[I, OnRegion Top1, File > "Result_Cube1TopValues.txt", Format TimeTable]; + Print[I, OnRegion Top2, File > "Result_Cube2TopValues.txt", Format TimeTable]; + Print[I, OnRegion Top3, File > "Result_Cube3TopValues.txt", Format TimeTable]; + } + } + +} diff --git a/CircuitCoupling/RLC_circuit_common.pro b/CircuitCoupling/RLC_circuit_common.pro index 65360ad..cfa9d02 100644 --- a/CircuitCoupling/RLC_circuit_common.pro +++ b/CircuitCoupling/RLC_circuit_common.pro @@ -1,12 +1,12 @@ -// Physical numbers for volumes -Cube1 = 1001; -Cube2 = 1002; -Cube3 = 1003; - -// Physical numbers for surfaces -Cube1Top = 2001; -Cube1Bottom = 2002; -Cube2Top = 2003; -Cube2Bottom = 2004; -Cube3Top = 2005; -Cube3Bottom = 2006; +// Physical numbers for volumes +Cube1 = 1001; +Cube2 = 1002; +Cube3 = 1003; + +// Physical numbers for surfaces +Cube1Top = 2001; +Cube1Bottom = 2002; +Cube2Top = 2003; +Cube2Bottom = 2004; +Cube3Top = 2005; +Cube3Bottom = 2006; diff --git a/CircuitCoupling/R_circuit.geo b/CircuitCoupling/R_circuit.geo index 77d9838..cc4e527 100644 --- a/CircuitCoupling/R_circuit.geo +++ b/CircuitCoupling/R_circuit.geo @@ -1,39 +1,39 @@ -// Just 4 cubes - -Include "R_circuit_common.pro"; - -lc = 0.25; // Cjaracteristic length - -Point(1) = {0, 0, 0, lc}; -Extrude {1, 0, 0} { - Point{1}; -} -Extrude {0, 1, 0} { - Line{1}; // Layers{10}; Recombine; -} -Extrude {0, 0, 1} { - Surface{5}; // Layers{10}; Recombine; -} -Translate {2, 0, 0} { - Duplicata { Volume{1}; } -} -Translate {0, 4, 0} { - Duplicata { Volume{1}; } -} -Translate {2, 4, 0} { - Duplicata { Volume{1}; } -} - -Physical Surface(Cube1Top) = {27}; -Physical Surface(Cube1Bottom) = {5}; -Physical Surface(Cube2Top) = {34}; -Physical Surface(Cube2Bottom) = {29}; -Physical Surface(Cube3Top) = {61}; -Physical Surface(Cube3Bottom) = {56}; -Physical Surface(Cube4Top) = {88}; -Physical Surface(Cube4Bottom) = {83}; - -Physical Volume(Cube1) = {1}; -Physical Volume(Cube2) = {28}; -Physical Volume(Cube3) = {55}; -Physical Volume(Cube4) = {82}; +// Just 4 cubes + +Include "R_circuit_common.pro"; + +lc = 0.25; // Cjaracteristic length + +Point(1) = {0, 0, 0, lc}; +Extrude {1, 0, 0} { + Point{1}; +} +Extrude {0, 1, 0} { + Line{1}; // Layers{10}; Recombine; +} +Extrude {0, 0, 1} { + Surface{5}; // Layers{10}; Recombine; +} +Translate {2, 0, 0} { + Duplicata { Volume{1}; } +} +Translate {0, 4, 0} { + Duplicata { Volume{1}; } +} +Translate {2, 4, 0} { + Duplicata { Volume{1}; } +} + +Physical Surface(Cube1Top) = {27}; +Physical Surface(Cube1Bottom) = {5}; +Physical Surface(Cube2Top) = {34}; +Physical Surface(Cube2Bottom) = {29}; +Physical Surface(Cube3Top) = {61}; +Physical Surface(Cube3Bottom) = {56}; +Physical Surface(Cube4Top) = {88}; +Physical Surface(Cube4Bottom) = {83}; + +Physical Volume(Cube1) = {1}; +Physical Volume(Cube2) = {28}; +Physical Volume(Cube3) = {55}; +Physical Volume(Cube4) = {82}; diff --git a/CircuitCoupling/R_circuit.pro b/CircuitCoupling/R_circuit.pro index 8ec804b..0fabf0e 100644 --- a/CircuitCoupling/R_circuit.pro +++ b/CircuitCoupling/R_circuit.pro @@ -1,342 +1,342 @@ -/* ------------------------------------------------------------------- - Tutorial 8a : circuit coupling - resistive circuit - - Features: - - Electrokinetic formulation coupled with resistive circuit - - Definition of circuit elements (sources, resistances) - - Implementation of a netlist - - To compute the solution in a terminal: - getdp R_circuit -solve static -pos Cube_Top_Values_ASCII - - To compute the solution interactively from the Gmsh GUI: - File > Open > R_circuit.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -/* - This example shows how to implement a circuit with discrete elements in a - finite element simulation. Only lumped resistors, voltage- and current-sources - are used. There are four separate cubes, each with a certain conductivity. The - bottom of all cubes is kept at a constant voltage via the constraint - Voltage_3D. The top of the cubes are connected with a circuit according the - `R_circuit.jpg' schematic. -*/ - -Include "R_circuit_common.pro"; - -// FEM domain group data -Group { - // Surfaces - Top1 = Region[Cube1Top]; - Bottom1 = Region[Cube1Bottom]; - Top2 = Region[Cube2Top]; - Bottom2 = Region[Cube2Bottom]; - Top3 = Region[Cube3Top]; - Bottom3 = Region[Cube3Bottom]; - Top4 = Region[Cube4Top]; - Bottom4 = Region[Cube4Bottom]; - - // Volumes - Cube1 = Region[Cube1]; - Cube2 = Region[Cube2]; - Cube3 = Region[Cube3]; - Cube4 = Region[Cube4]; - - // FEM Electrical regions - // * all volumes: - Vol_Ele = Region[{Cube1, Cube2, Cube3, Cube4}]; - // * all surfaces connected to the lumped element circuit - Sur_Ele = Region[{Top1, Bottom1, Top2, Bottom2, Top3, Bottom3, Top4, Bottom4}]; - // * total electrical computation domain: - VolWithSur_Ele = Region[{Vol_Ele, Sur_Ele}]; -} - -// Circuit group data (fictive regions for the circuit elements) -Group { - // Sources - CurrentSource1 = Region[{3001}]; - VoltageSource1 = Region[{3002}]; - - SourceI_Cir = Region[{CurrentSource1}]; // all current sources - SourceV_Cir = Region[{VoltageSource1}]; // all voltage sources - Sources_Cir = Region[{SourceI_Cir, SourceV_Cir}]; - - // Resistors - Res1 = Region[{4001}]; - Res2 = Region[{4002}]; - Res3 = Region[{4003}]; - Res4 = Region[{4004}]; - - Resistance_Cir = Region[{Res1, Res2, Res3, Res4}]; // All resistors - - // Complete circuit domain containing all circuit elements - Domain_Cir = Region[{Resistance_Cir, SourceI_Cir, SourceV_Cir}]; -} - -// FEM domain function data -Function { - // Absolute voltage at the bottom of all cubes; set via constraint Voltage_3D, - // not via a voltage source - Vbottom = 4.0; - - // Geometry of a cube - w = 1.0; // Width [m] - l = 1.0; // Length [m] - h = 1.0; // Height [m] - - // Resistance - Rcube1 = 20.0; // Resistance of cube 1 [Ohm] - Rcube2 = 40.0; // Resistance of cube 2 [Ohm] - Rcube3 = 60.0; // Resistance of cube 3 [Ohm] - Rcube4 = 10.0; // Resistance of cube 4 [Ohm] - - // Specific electrical conductivity [S*m/m^2] - kappa[Cube1] = h / (w * l * Rcube1); - kappa[Cube2] = h / (w * l * Rcube2); - kappa[Cube3] = h / (w * l * Rcube3); - kappa[Cube4] = h / (w * l * Rcube4); -} - -// Circuit domain function data -Function { - // External impedances functions - R[Res1] = 10.0; - R[Res2] = 20.0; - R[Res3] = 15.0; - R[Res4] = 10.0; -} - -// FEM domain constraint data -Constraint { - { Name Current_3D ; Type Assign ; - Case { - } - } - { Name Voltage_3D ; Type Assign ; - Case { - { Region Bottom1; Type Assign; Value Vbottom; } - { Region Bottom2; Type Assign; Value Vbottom; } - { Region Bottom3; Type Assign; Value Vbottom; } - { Region Bottom4; Type Assign; Value Vbottom; } - } - } -} - -// Circuit domain constraint data -Constraint { - { Name Current_Cir ; - Case { - { Region CurrentSource1; Value 1.0; } // CurrentSource1 has 1.0 A - } - } - { Name Voltage_Cir ; - Case { - { Region VoltageSource1; Value 10.0; } // VoltageSource1 has 10.0 V - } - } - { Name ElectricalCircuit ; Type Network ; - Case Circuit1 { - // Here the circuit netlist is implemented. The important thing is that - // each surface of the 3D geometry which is connected to the circuit - // (Sur_Ele) has a single voltage and current, but in the netlist they - // appear with two terminals (two nodes). The voltage between the two - // nodes corresponds to the absolute voltage of the surface. The current - // through the two nodes is the current flowing through the surface. In - // this simple case here we need the voltage drop across a cube (e.g. cube - // 1) in the netlist rather than the absolute voltage. Therefore the - // bottom-voltage has to be subtracted from the top-voltage. This is - // accomplished by connecting both surfaces anti-serial (e.g. at node 4; - // The voltage drop across cube 1 is then between node 2 and node 10). - - { Region VoltageSource1; Branch{1, 10}; } - { Region Res1; Branch{1, 2}; } - // Voltage between node 2 and node 4 corresponds to the absolute voltage - // of Top1: - { Region Top1; Branch{2, 4}; } - // Note the reverse order of the nodes here - it's for subtracting the - // bottom voltage: - { Region Bottom1; Branch{10, 4}; } - // Voltage between node 3 and node 5 corresponds to the absolute voltage - // of Top2: - { Region Res2; Branch{2, 3}; } - { Region Top2; Branch{3, 5}; } - // Note the reverse order of the nodes here! It's for subtracting the - // bottom voltage.: - { Region Bottom2; Branch{10, 5}; } - - { Region CurrentSource1; Branch{6, 10}; } - { Region Res3; Branch{6, 10}; } - // Voltage between node 6 and node 8 corresponds to the absolute voltage - // of Top3: - { Region Top3; Branch{6, 8}; } - // Note the reverse order of the nodes here! It's for subtracting the - // bottom voltage.: - { Region Bottom3; Branch{10, 8}; } - { Region Res4; Branch{6, 7}; } - // Voltage between node 7 and node 9 corresponds to the absolute voltage - // of Top4: - { Region Top4; Branch{7, 9}; } - // Note the reverse order of the nodes here! It's for subtracting the - // bottom voltage: - { Region Bottom4; Branch{10, 9}; } - } - } -} - -Jacobian { - { Name JVol ; - Case { - { Region Region[{Vol_Ele}]; Jacobian Vol; } - { Region Region[{Sur_Ele}]; Jacobian Sur; } - } - } -} - -Integration { - { Name I1 ; - Case { - { Type Gauss ; - Case { - { GeoElement Point ; NumberOfPoints 1 ; } - { GeoElement Line ; NumberOfPoints 5 ; } - { GeoElement Triangle ; NumberOfPoints 6 ; } - { GeoElement Quadrangle ; NumberOfPoints 7 ; } - { GeoElement Tetrahedron ; NumberOfPoints 15 ; } - { GeoElement Hexahedron ; NumberOfPoints 34 ; } - { GeoElement Prism ; NumberOfPoints 21 ; } - } - } - } - } -} - - -FunctionSpace { - { Name Hgrad_V; Type Form0; - BasisFunction { - // All nodes but the grouped nodes of the surfaces for connecting the - // circuitry - { Name sn; NameOfCoef vn; Function BF_Node; - Support VolWithSur_Ele; Entity NodesOf[ All, Not Sur_Ele ]; } - // Grouped nodes: Each surface of Sur_Ele has just one single voltage -> - // each surface is just one node effectively - { Name sf; NameOfCoef vf; Function BF_GroupOfNodes; - Support VolWithSur_Ele; Entity GroupsOfNodesOf[ Sur_Ele ]; } - } - GlobalQuantity { - // Voltage of the surfaces of Sur_Ele - { Name U; Type AliasOf; NameOfCoef vf; } - // Current flowing through the surfaces - { Name I; Type AssociatedWith; NameOfCoef vf; } - } - Constraint { - { NameOfCoef vn; EntityType NodesOf ; NameOfConstraint Voltage_3D; } - { NameOfCoef U; EntityType GroupsOfNodesOf ; NameOfConstraint Voltage_3D; } - { NameOfCoef I; EntityType GroupsOfNodesOf ; NameOfConstraint Current_3D; } - } - } - - { Name Hregion_Cir; Type Scalar; - BasisFunction { - { Name sn; NameOfCoef ir; Function BF_Region; - Support Domain_Cir; Entity Domain_Cir; } - } - GlobalQuantity { - { Name Iz; Type AliasOf; NameOfCoef ir; } - { Name Uz; Type AssociatedWith; NameOfCoef ir; } - } - Constraint { - { NameOfCoef Uz ; EntityType Region ; NameOfConstraint Voltage_Cir ; } - { NameOfCoef Iz ; EntityType Region ; NameOfConstraint Current_Cir ; } - } - } -} - -Formulation { - { Name static; Type FemEquation; - Quantity { - { Name V; Type Local; NameOfSpace Hgrad_V; } - { Name U; Type Global; NameOfSpace Hgrad_V [U]; } - { Name I; Type Global; NameOfSpace Hgrad_V [I]; } - { Name Uz; Type Global; NameOfSpace Hregion_Cir [Uz]; } - { Name Iz; Type Global; NameOfSpace Hregion_Cir [Iz]; } - } - Equation { - // FEM domain - Galerkin { [ kappa[] * Dof{d V}, {d V} ]; - In Vol_Ele; Integration I1; Jacobian JVol; } - GlobalTerm { [ Dof{I} , {U} ]; In Sur_Ele; } - - // Circuit related terms: Resistance equation - GlobalTerm { [ Dof{Uz}, {Iz} ]; In Resistance_Cir; } - GlobalTerm { [ R[] * Dof{Iz}, {Iz} ]; In Resistance_Cir; } - - // Here is the connection between the circuit and the finite element simulation - GlobalEquation { Type Network; NameOfConstraint ElectricalCircuit; - { Node {I}; Loop {U}; Equation {I}; In Sur_Ele; } - { Node {Iz}; Loop {Uz}; Equation {Uz}; In Domain_Cir; } - } - } - } -} - -Resolution { - { Name static; - System { - { Name A; NameOfFormulation static; } - } - Operation { - Generate[A]; - Solve[A]; - SaveSolution[A]; - } - } -} - -PostProcessing { - { Name Ele; NameOfFormulation static; - Quantity { - { Name V; Value{ Local{ [ {V} ]; In Vol_Ele; Jacobian JVol;} } } - { Name Jv; Value{ Local{ [ -kappa[]*{d V} ]; In Vol_Ele; Jacobian JVol;} } } - { Name J; Value{ Local{ [ Norm[kappa[]*{d V}] ]; In Vol_Ele; Jacobian JVol;} } } - { Name U; Value { Term { [ {U} ]; In Sur_Ele; } } } - { Name I; Value { Term { [ {I} ]; In Sur_Ele; } } } - } - } -} - -PostOperation { - // Absolute voltage [V] - { Name V; NameOfPostProcessing Ele; - Operation { - Print[ V, OnElementsOf Vol_Ele, File "Result_V.pos"]; - } - } - // Current density vectors [A/m^2] - { Name J_vectors; NameOfPostProcessing Ele; - Operation { - Print[ Jv, OnElementsOf Vol_Ele, File "Result_J_vectors.pos"]; - } - } - // Magnitude of current density [A/m^2] - { Name J_magnitude; NameOfPostProcessing Ele; - Operation { - Print[ J, OnElementsOf Vol_Ele, File "Result_J.pos"]; - } - } - // Store the results in an ASCII file - { Name Cube_Top_Values_ASCII; NameOfPostProcessing Ele; - Operation { - Print[U, OnRegion Top1, File "Result_CubeTopValues.txt", Format SimpleTable]; - Print[U, OnRegion Top2, File > "Result_CubeTopValues.txt", Format SimpleTable]; - Print[U, OnRegion Top3, File > "Result_CubeTopValues.txt", Format SimpleTable]; - Print[U, OnRegion Top4, File > "Result_CubeTopValues.txt", Format SimpleTable]; - - Print[I, OnRegion Top1, File > "Result_CubeTopValues.txt", Format SimpleTable]; - Print[I, OnRegion Top2, File > "Result_CubeTopValues.txt", Format SimpleTable]; - Print[I, OnRegion Top3, File > "Result_CubeTopValues.txt", Format SimpleTable]; - Print[I, OnRegion Top4, File > "Result_CubeTopValues.txt", Format SimpleTable]; - } - } -} +/* ------------------------------------------------------------------- + Tutorial 8a : circuit coupling - resistive circuit + + Features: + - Electrokinetic formulation coupled with resistive circuit + - Definition of circuit elements (sources, resistances) + - Implementation of a netlist + + To compute the solution in a terminal: + getdp R_circuit -solve static -pos Cube_Top_Values_ASCII + + To compute the solution interactively from the Gmsh GUI: + File > Open > R_circuit.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +/* + This example shows how to implement a circuit with discrete elements in a + finite element simulation. Only lumped resistors, voltage- and current-sources + are used. There are four separate cubes, each with a certain conductivity. The + bottom of all cubes is kept at a constant voltage via the constraint + Voltage_3D. The top of the cubes are connected with a circuit according the + `R_circuit.jpg' schematic. +*/ + +Include "R_circuit_common.pro"; + +// FEM domain group data +Group { + // Surfaces + Top1 = Region[Cube1Top]; + Bottom1 = Region[Cube1Bottom]; + Top2 = Region[Cube2Top]; + Bottom2 = Region[Cube2Bottom]; + Top3 = Region[Cube3Top]; + Bottom3 = Region[Cube3Bottom]; + Top4 = Region[Cube4Top]; + Bottom4 = Region[Cube4Bottom]; + + // Volumes + Cube1 = Region[Cube1]; + Cube2 = Region[Cube2]; + Cube3 = Region[Cube3]; + Cube4 = Region[Cube4]; + + // FEM Electrical regions + // * all volumes: + Vol_Ele = Region[{Cube1, Cube2, Cube3, Cube4}]; + // * all surfaces connected to the lumped element circuit + Sur_Ele = Region[{Top1, Bottom1, Top2, Bottom2, Top3, Bottom3, Top4, Bottom4}]; + // * total electrical computation domain: + VolWithSur_Ele = Region[{Vol_Ele, Sur_Ele}]; +} + +// Circuit group data (fictive regions for the circuit elements) +Group { + // Sources + CurrentSource1 = Region[{3001}]; + VoltageSource1 = Region[{3002}]; + + SourceI_Cir = Region[{CurrentSource1}]; // all current sources + SourceV_Cir = Region[{VoltageSource1}]; // all voltage sources + Sources_Cir = Region[{SourceI_Cir, SourceV_Cir}]; + + // Resistors + Res1 = Region[{4001}]; + Res2 = Region[{4002}]; + Res3 = Region[{4003}]; + Res4 = Region[{4004}]; + + Resistance_Cir = Region[{Res1, Res2, Res3, Res4}]; // All resistors + + // Complete circuit domain containing all circuit elements + Domain_Cir = Region[{Resistance_Cir, SourceI_Cir, SourceV_Cir}]; +} + +// FEM domain function data +Function { + // Absolute voltage at the bottom of all cubes; set via constraint Voltage_3D, + // not via a voltage source + Vbottom = 4.0; + + // Geometry of a cube + w = 1.0; // Width [m] + l = 1.0; // Length [m] + h = 1.0; // Height [m] + + // Resistance + Rcube1 = 20.0; // Resistance of cube 1 [Ohm] + Rcube2 = 40.0; // Resistance of cube 2 [Ohm] + Rcube3 = 60.0; // Resistance of cube 3 [Ohm] + Rcube4 = 10.0; // Resistance of cube 4 [Ohm] + + // Specific electrical conductivity [S*m/m^2] + kappa[Cube1] = h / (w * l * Rcube1); + kappa[Cube2] = h / (w * l * Rcube2); + kappa[Cube3] = h / (w * l * Rcube3); + kappa[Cube4] = h / (w * l * Rcube4); +} + +// Circuit domain function data +Function { + // External impedances functions + R[Res1] = 10.0; + R[Res2] = 20.0; + R[Res3] = 15.0; + R[Res4] = 10.0; +} + +// FEM domain constraint data +Constraint { + { Name Current_3D ; Type Assign ; + Case { + } + } + { Name Voltage_3D ; Type Assign ; + Case { + { Region Bottom1; Type Assign; Value Vbottom; } + { Region Bottom2; Type Assign; Value Vbottom; } + { Region Bottom3; Type Assign; Value Vbottom; } + { Region Bottom4; Type Assign; Value Vbottom; } + } + } +} + +// Circuit domain constraint data +Constraint { + { Name Current_Cir ; + Case { + { Region CurrentSource1; Value 1.0; } // CurrentSource1 has 1.0 A + } + } + { Name Voltage_Cir ; + Case { + { Region VoltageSource1; Value 10.0; } // VoltageSource1 has 10.0 V + } + } + { Name ElectricalCircuit ; Type Network ; + Case Circuit1 { + // Here the circuit netlist is implemented. The important thing is that + // each surface of the 3D geometry which is connected to the circuit + // (Sur_Ele) has a single voltage and current, but in the netlist they + // appear with two terminals (two nodes). The voltage between the two + // nodes corresponds to the absolute voltage of the surface. The current + // through the two nodes is the current flowing through the surface. In + // this simple case here we need the voltage drop across a cube (e.g. cube + // 1) in the netlist rather than the absolute voltage. Therefore the + // bottom-voltage has to be subtracted from the top-voltage. This is + // accomplished by connecting both surfaces anti-serial (e.g. at node 4; + // The voltage drop across cube 1 is then between node 2 and node 10). + + { Region VoltageSource1; Branch{1, 10}; } + { Region Res1; Branch{1, 2}; } + // Voltage between node 2 and node 4 corresponds to the absolute voltage + // of Top1: + { Region Top1; Branch{2, 4}; } + // Note the reverse order of the nodes here - it's for subtracting the + // bottom voltage: + { Region Bottom1; Branch{10, 4}; } + // Voltage between node 3 and node 5 corresponds to the absolute voltage + // of Top2: + { Region Res2; Branch{2, 3}; } + { Region Top2; Branch{3, 5}; } + // Note the reverse order of the nodes here! It's for subtracting the + // bottom voltage.: + { Region Bottom2; Branch{10, 5}; } + + { Region CurrentSource1; Branch{6, 10}; } + { Region Res3; Branch{6, 10}; } + // Voltage between node 6 and node 8 corresponds to the absolute voltage + // of Top3: + { Region Top3; Branch{6, 8}; } + // Note the reverse order of the nodes here! It's for subtracting the + // bottom voltage.: + { Region Bottom3; Branch{10, 8}; } + { Region Res4; Branch{6, 7}; } + // Voltage between node 7 and node 9 corresponds to the absolute voltage + // of Top4: + { Region Top4; Branch{7, 9}; } + // Note the reverse order of the nodes here! It's for subtracting the + // bottom voltage: + { Region Bottom4; Branch{10, 9}; } + } + } +} + +Jacobian { + { Name JVol ; + Case { + { Region Region[{Vol_Ele}]; Jacobian Vol; } + { Region Region[{Sur_Ele}]; Jacobian Sur; } + } + } +} + +Integration { + { Name I1 ; + Case { + { Type Gauss ; + Case { + { GeoElement Point ; NumberOfPoints 1 ; } + { GeoElement Line ; NumberOfPoints 5 ; } + { GeoElement Triangle ; NumberOfPoints 6 ; } + { GeoElement Quadrangle ; NumberOfPoints 7 ; } + { GeoElement Tetrahedron ; NumberOfPoints 15 ; } + { GeoElement Hexahedron ; NumberOfPoints 34 ; } + { GeoElement Prism ; NumberOfPoints 21 ; } + } + } + } + } +} + + +FunctionSpace { + { Name Hgrad_V; Type Form0; + BasisFunction { + // All nodes but the grouped nodes of the surfaces for connecting the + // circuitry + { Name sn; NameOfCoef vn; Function BF_Node; + Support VolWithSur_Ele; Entity NodesOf[ All, Not Sur_Ele ]; } + // Grouped nodes: Each surface of Sur_Ele has just one single voltage -> + // each surface is just one node effectively + { Name sf; NameOfCoef vf; Function BF_GroupOfNodes; + Support VolWithSur_Ele; Entity GroupsOfNodesOf[ Sur_Ele ]; } + } + GlobalQuantity { + // Voltage of the surfaces of Sur_Ele + { Name U; Type AliasOf; NameOfCoef vf; } + // Current flowing through the surfaces + { Name I; Type AssociatedWith; NameOfCoef vf; } + } + Constraint { + { NameOfCoef vn; EntityType NodesOf ; NameOfConstraint Voltage_3D; } + { NameOfCoef U; EntityType GroupsOfNodesOf ; NameOfConstraint Voltage_3D; } + { NameOfCoef I; EntityType GroupsOfNodesOf ; NameOfConstraint Current_3D; } + } + } + + { Name Hregion_Cir; Type Scalar; + BasisFunction { + { Name sn; NameOfCoef ir; Function BF_Region; + Support Domain_Cir; Entity Domain_Cir; } + } + GlobalQuantity { + { Name Iz; Type AliasOf; NameOfCoef ir; } + { Name Uz; Type AssociatedWith; NameOfCoef ir; } + } + Constraint { + { NameOfCoef Uz ; EntityType Region ; NameOfConstraint Voltage_Cir ; } + { NameOfCoef Iz ; EntityType Region ; NameOfConstraint Current_Cir ; } + } + } +} + +Formulation { + { Name static; Type FemEquation; + Quantity { + { Name V; Type Local; NameOfSpace Hgrad_V; } + { Name U; Type Global; NameOfSpace Hgrad_V [U]; } + { Name I; Type Global; NameOfSpace Hgrad_V [I]; } + { Name Uz; Type Global; NameOfSpace Hregion_Cir [Uz]; } + { Name Iz; Type Global; NameOfSpace Hregion_Cir [Iz]; } + } + Equation { + // FEM domain + Integral { [ kappa[] * Dof{d V}, {d V} ]; + In Vol_Ele; Integration I1; Jacobian JVol; } + GlobalTerm { [ Dof{I} , {U} ]; In Sur_Ele; } + + // Circuit related terms: Resistance equation + GlobalTerm { [ Dof{Uz}, {Iz} ]; In Resistance_Cir; } + GlobalTerm { [ R[] * Dof{Iz}, {Iz} ]; In Resistance_Cir; } + + // Here is the connection between the circuit and the finite element simulation + GlobalEquation { Type Network; NameOfConstraint ElectricalCircuit; + { Node {I}; Loop {U}; Equation {I}; In Sur_Ele; } + { Node {Iz}; Loop {Uz}; Equation {Uz}; In Domain_Cir; } + } + } + } +} + +Resolution { + { Name static; + System { + { Name A; NameOfFormulation static; } + } + Operation { + Generate[A]; + Solve[A]; + SaveSolution[A]; + } + } +} + +PostProcessing { + { Name Ele; NameOfFormulation static; + Quantity { + { Name V; Value{ Local{ [ {V} ]; In Vol_Ele; Jacobian JVol;} } } + { Name Jv; Value{ Local{ [ -kappa[]*{d V} ]; In Vol_Ele; Jacobian JVol;} } } + { Name J; Value{ Local{ [ Norm[kappa[]*{d V}] ]; In Vol_Ele; Jacobian JVol;} } } + { Name U; Value { Term { [ {U} ]; In Sur_Ele; } } } + { Name I; Value { Term { [ {I} ]; In Sur_Ele; } } } + } + } +} + +PostOperation { + // Absolute voltage [V] + { Name V; NameOfPostProcessing Ele; + Operation { + Print[ V, OnElementsOf Vol_Ele, File "Result_V.pos"]; + } + } + // Current density vectors [A/m^2] + { Name J_vectors; NameOfPostProcessing Ele; + Operation { + Print[ Jv, OnElementsOf Vol_Ele, File "Result_J_vectors.pos"]; + } + } + // Magnitude of current density [A/m^2] + { Name J_magnitude; NameOfPostProcessing Ele; + Operation { + Print[ J, OnElementsOf Vol_Ele, File "Result_J.pos"]; + } + } + // Store the results in an ASCII file + { Name Cube_Top_Values_ASCII; NameOfPostProcessing Ele; + Operation { + Print[U, OnRegion Top1, File "Result_CubeTopValues.txt", Format SimpleTable]; + Print[U, OnRegion Top2, File > "Result_CubeTopValues.txt", Format SimpleTable]; + Print[U, OnRegion Top3, File > "Result_CubeTopValues.txt", Format SimpleTable]; + Print[U, OnRegion Top4, File > "Result_CubeTopValues.txt", Format SimpleTable]; + + Print[I, OnRegion Top1, File > "Result_CubeTopValues.txt", Format SimpleTable]; + Print[I, OnRegion Top2, File > "Result_CubeTopValues.txt", Format SimpleTable]; + Print[I, OnRegion Top3, File > "Result_CubeTopValues.txt", Format SimpleTable]; + Print[I, OnRegion Top4, File > "Result_CubeTopValues.txt", Format SimpleTable]; + } + } +} diff --git a/CircuitCoupling/R_circuit_common.pro b/CircuitCoupling/R_circuit_common.pro index 3384474..80415a6 100644 --- a/CircuitCoupling/R_circuit_common.pro +++ b/CircuitCoupling/R_circuit_common.pro @@ -1,15 +1,15 @@ -// Physical numbers for volumes -Cube1 = 1001; -Cube2 = 1002; -Cube3 = 1003; -Cube4 = 1004; - -// Physical numbers for surfaces -Cube1Top = 2001; -Cube1Bottom = 2002; -Cube2Top = 2003; -Cube2Bottom = 2004; -Cube3Top = 2005; -Cube3Bottom = 2006; -Cube4Top = 2007; -Cube4Bottom = 2008; +// Physical numbers for volumes +Cube1 = 1001; +Cube2 = 1002; +Cube3 = 1003; +Cube4 = 1004; + +// Physical numbers for surfaces +Cube1Top = 2001; +Cube1Bottom = 2002; +Cube2Top = 2003; +Cube2Bottom = 2004; +Cube3Top = 2005; +Cube3Bottom = 2006; +Cube4Top = 2007; +Cube4Bottom = 2008; diff --git a/Elasticity/wrench2D.geo b/Elasticity/wrench2D.geo index 782b701..d107af1 100644 --- a/Elasticity/wrench2D.geo +++ b/Elasticity/wrench2D.geo @@ -1,72 +1,72 @@ - -Include "wrench2D_common.pro"; - -Solver.AutoMesh = 2; - -lc = Refine; -lc2 = lc; // nut region -lc3 = lc/5; // edge grip region - -Ri = 0.494*in; -Re = 0.8*in; -L = LLength; -LL = 1*in; -E = 0.625*in; -F = Width; -D = 0.45*in; // Nut - -theta = Inclination; - -Point(1) = { 0, 0, 0, lc2}; -Point(2) = { -Ri, 0, 0, lc2}; -th1 = Asin[E/2./Ri]; -Point(3) = { -Ri + Ri*Cos[th1], Ri*Sin[th1], 0, lc2}; -th2 = Asin[E/2./Re]; -Point(4) = { -Re*Cos[th2]+D, Re*Sin[th2], 0, lc3}; -Point(5) = { -Re*Cos[th2], Re*Sin[th2], 0, lc2}; -th3 = th2 - theta; -Point(6) = { Re*Cos[th3], Re*Sin[th3], 0, lc}; -Point(7) = { (L-LL)*Cos[theta]+F/2.*Sin[theta], - -(L-LL)*Sin[theta]+F/2.*Cos[theta], 0, lc}; -Point(8) = { L*Cos[theta]+F/2.*Sin[theta], - -L*Sin[theta]+F/2.*Cos[theta], 0, lc}; -Point(9) = { L*Cos[theta]-F/2.*Sin[theta], - -L*Sin[theta]-F/2.*Cos[theta], 0, lc}; -th4 = -th2 - theta; -Point(10) = { Re*Cos[th4], Re*Sin[th4], 0, lc}; -Point(11) = { -Re*Cos[th2], -Re*Sin[th2], 0, lc2}; -Point(12) = { -Re*Cos[th2]+D, -Re*Sin[th2], 0, lc3}; -Point(13) = { -Ri + Ri*Cos[th1], -Ri*Sin[th1], 0, lc2}; - -contour[] = {}; -contour[] += newl; Circle(newl) = {1,2,3}; -contour[] += newl; Line(newl) = {3,4}; -contour[] += newl; cl1=newl; Line(newl) = {4,5}; -contour[] += newl; Circle(newl) = {5,1,6}; -contour[] += newl; Line(newl) = {6,7}; -contour[] += newl; cl2=newl; Line(newl) = {7,8}; -contour[] += newl; Line(newl) = {8,9}; -contour[] += newl; Line(newl) = {9,10}; -contour[] += newl; Circle(newl) = {10,1,11}; -contour[] += newl; cl3=newl; Line(newl) = {11,12}; -contour[] += newl; Line(newl) = {12,13}; -contour[] += newl; Circle(newl) = {13,2,1}; -ll=newll; Line Loop(ll) = { contour[] }; - -wrench=news; Plane Surface(wrench) = {-ll}; - -/* Using quadrangular elements instead of triangular elements is pretty simple. - You just have to invoke the Recombine command at this place. - GetDP deals will all the rest by itself. - */ -If(Recomb==1) - Recombine Surface{wrench}; -EndIf - -Physical Surface(1)= wrench; -Physical Line(2)= {cl1, cl3}; -Physical Line(3)= {cl2}; - - - - + +Include "wrench2D_common.pro"; + +Solver.AutoMesh = 2; + +lc = Refine; +lc2 = lc; // nut region +lc3 = lc/5; // edge grip region + +Ri = 0.494*in; +Re = 0.8*in; +L = LLength; +LL = 1*in; +E = 0.625*in; +F = Width; +D = 0.45*in; // Nut + +theta = Inclination; + +Point(1) = { 0, 0, 0, lc2}; +Point(2) = { -Ri, 0, 0, lc2}; +th1 = Asin[E/2./Ri]; +Point(3) = { -Ri + Ri*Cos[th1], Ri*Sin[th1], 0, lc2}; +th2 = Asin[E/2./Re]; +Point(4) = { -Re*Cos[th2]+D, Re*Sin[th2], 0, lc3}; +Point(5) = { -Re*Cos[th2], Re*Sin[th2], 0, lc2}; +th3 = th2 - theta; +Point(6) = { Re*Cos[th3], Re*Sin[th3], 0, lc}; +Point(7) = { (L-LL)*Cos[theta]+F/2.*Sin[theta], + -(L-LL)*Sin[theta]+F/2.*Cos[theta], 0, lc}; +Point(8) = { L*Cos[theta]+F/2.*Sin[theta], + -L*Sin[theta]+F/2.*Cos[theta], 0, lc}; +Point(9) = { L*Cos[theta]-F/2.*Sin[theta], + -L*Sin[theta]-F/2.*Cos[theta], 0, lc}; +th4 = -th2 - theta; +Point(10) = { Re*Cos[th4], Re*Sin[th4], 0, lc}; +Point(11) = { -Re*Cos[th2], -Re*Sin[th2], 0, lc2}; +Point(12) = { -Re*Cos[th2]+D, -Re*Sin[th2], 0, lc3}; +Point(13) = { -Ri + Ri*Cos[th1], -Ri*Sin[th1], 0, lc2}; + +contour[] = {}; +contour[] += newl; Circle(newl) = {1,2,3}; +contour[] += newl; Line(newl) = {3,4}; +contour[] += newl; cl1=newl; Line(newl) = {4,5}; +contour[] += newl; Circle(newl) = {5,1,6}; +contour[] += newl; Line(newl) = {6,7}; +contour[] += newl; cl2=newl; Line(newl) = {7,8}; +contour[] += newl; Line(newl) = {8,9}; +contour[] += newl; Line(newl) = {9,10}; +contour[] += newl; Circle(newl) = {10,1,11}; +contour[] += newl; cl3=newl; Line(newl) = {11,12}; +contour[] += newl; Line(newl) = {12,13}; +contour[] += newl; Circle(newl) = {13,2,1}; +ll=newll; Line Loop(ll) = { contour[] }; + +wrench=news; Plane Surface(wrench) = {-ll}; + +/* Using quadrangular elements instead of triangular elements is pretty simple. + You just have to invoke the Recombine command at this place. + GetDP deals will all the rest by itself. + */ +If(Recomb==1) + Recombine Surface{wrench}; +EndIf + +Physical Surface(1)= wrench; +Physical Line(2)= {cl1, cl3}; +Physical Line(3)= {cl2}; + + + + diff --git a/Elasticity/wrench2D.pro b/Elasticity/wrench2D.pro index fab3a7f..ce97783 100644 --- a/Elasticity/wrench2D.pro +++ b/Elasticity/wrench2D.pro @@ -1,366 +1,365 @@ -/* ------------------------------------------------------------------- - Tutorial 3 : linear elastic model of a wrench - - Features: - - "Grad u" GetDP specific formulation for linear elasticity - - first and second order elements - - triangular and quadrangular elements - - To compute the solution interactively from the Gmsh GUI: - File > Open > wrench.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -/* Linear elasticity with GetDP: - - GetDP has a peculiar way to deal with linear elasticity. - Instead of vector field "u = Vector[ ux, uy, uz ]", - the displacement field is regarded as two (2D case) or 3 (3D case) scalar fields. - Unlike conventional formulations, GetDP's formulation is written - in terms of the gradient "Grad u" of the displacement field, - which is a non-symmetric tensor, and the needed symmetrization - (to define the strain tensor and relate it to the stress tensor) - is done through the constitutive relationship (Hooke law). - The reason for this unusual formulation is to be able to use also for elastic problems - the powerful geometrical and homological kernel of GetDP, - which relies on the operators Grad, Curl and Div. - - The "Grad u" formulation entails a small increase of assembly work - but makes in counterpart lots of geometrical features - implemented in GetDP (change of coordinates, function spaces, etc...) - applicable to elastic problems out-of-the-box, - since the scalar fields { ux, uy, uz } have exactly the same geometrical properties - as, e.g. a scalar electrip potential or a temperature field. -*/ - - -Include "wrench2D_common.pro"; - -Young = 1e9 * - DefineNumber[ 200, Name "Material/Young modulus [GPa]"]; -Poisson = - DefineNumber[ 0.3, Name "Material/Poisson coefficient []"]; -AppliedForce = - DefineNumber[ 100, Name "Material/Applied force [N]"]; - -// Approximation of the maximum deflection by an analytical model: -// Deflection = PL^3/(3EI) with I = Width^3*Thickness/12 -Deflection = - DefineNumber[4*AppliedForce*((LLength-0.018)/Width)^3/(Young*Thickness)*1e3, - Name "Solution/Deflection (analytical) [mm]", ReadOnly 1]; - -Group { - // Physical regions: Give explicit labels to the regions defined in the .geo file - Wrench = Region[ 1 ]; - Grip = Region[ 2 ]; - Force = Region[ 3 ]; - - // Abstract regions: - Vol_Elast_Mec = Region[ { Wrench } ]; - Vol_Force_Mec = Region[ { Wrench } ]; - Sur_Clamp_Mec = Region[ { Grip } ]; - Sur_Force_Mec = Region[ { Force } ]; -/* - Signification of the abstract regions: - Vol_Elast_Mec Elastic domain - Vol_Force_Mec Region with imposed volumic force - Sur_Force_Mec Surface with imposed surface traction - Sur_Clamp_Mec Surface with imposed zero displacements (all components) -*/ -} - -Function { - /* Material coefficients. - No need to define them regionwise here ( E[{Wrench}] = ... ; ) - as there is only one region in this model. */ - E[] = Young; - nu[] = Poisson; - /* Components of the volumic force applied to the region "Vol_Force_Mec" - Gravity could be defined here ( force_y[] = 7000*9.81; ) ; */ - force_x[] = 0; - force_y[] = 0; - /* Components of the surface traction force applied to the region "Sur_Force_Mec" */ - pressure_x[] = 0; - pressure_y[] = -AppliedForce/(SurfaceArea[]*Thickness); // downward vertical force -} - - -/* Hooke law - - The material law - - sigma_ij = C_ijkl epsilon_ij - - is represented in 2D by 4 2x2 tensors C_ij[], i,j=1,2 - depending on the Lamé coefficients of the isotropic linear material, - - lambda = E[]*nu[]/(1.+nu[])/(1.-2.*nu[]); - mu = E[]/2./(1.+nu[]); - - as follows - - EPC: a[] = E/(1-nu^2) b[] = mu c[] = E nu/(1-nu^2) - EPD: a[] = lambda + 2 mu b[] = mu c[] = lambda - 3D: a[] = lambda + 2 mu b[] = mu c[] = lambda - - respectively for the 2D plane strain (EPD), 2D plane stress (EPS) and 3D cases. -*/ - -Function { - Flag_EPC = 1; - If(Flag_EPC) // Plane stress - a[] = E[]/(1.-nu[]^2); - c[] = E[]*nu[]/(1.-nu[]^2); - Else // Plane strain or 3D - a[] = E[]*(1.-nu[])/(1.+nu[])/(1.-2.*nu[]); - c[] = E[]*nu[]/(1.+nu[])/(1.-2.*nu[]); - EndIf - b[] = E[]/2./(1.+nu[]); - - C_xx[] = Tensor[ a[],0 ,0 , 0 ,b[],0 , 0 ,0 ,b[] ]; - C_xy[] = Tensor[ 0 ,c[],0 , b[],0 ,0 , 0 ,0 ,0 ]; - - C_yx[] = Tensor[ 0 ,b[],0 , c[],0 ,0 , 0 ,0 ,0 ]; - C_yy[] = Tensor[ b[],0 ,0 , 0 ,a[],0 , 0 ,0 ,b[] ]; -} - -/* Clamping boundary condition */ -Constraint { - { Name Displacement_x; - Case { - { Region Sur_Clamp_Mec ; Type Assign ; Value 0; } - } - } - { Name Displacement_y; - Case { - { Region Sur_Clamp_Mec ; Type Assign ; Value 0; } - } - } -} - -/* As explained above, the displacement field is discretized - as two scalar fields "ux" and "uy", which are the spatial components - of the vector field "u" in a fixed Cartesian coordinate system. - - Boundary conditions like - - ux = ... ; - uy = ... ; - - translate naturally into Dirichlet constraints - on the scalar "ux" and "uy" FunctionSpaces. - Conditions like, however, - - u . n = ux Cos [th] + uy Sin [th] = ... ; - - are less naturally accounted for within the "Grad u" formulation. - Fortunately, they are rather uncommon. - - Finite element shape (triangles or quadrangles) makes no difference - in the definition of the FunctionSpaces. The appropriate shape functions to be used - are determined by GetDP at a much lower level on basis of the information - contained in the *.msh file. - - Second order elements, on the other hand, are implemented in the hierarchical fashion - by adding to the first order node-based shape functions - a set of second order edge-based functions - to complete a basis for 2d order polynomials on the reference element. - */ - - -// Domain of definition of the "ux" and "uy" FunctionSpaces -Group { - Dom_H_u_Mec = Region[ { Vol_Elast_Mec, - Sur_Force_Mec, - Sur_Clamp_Mec} ]; -} - -Flag_Degree = - DefineNumber[ 0, Name "Geometry/Use degree 2 (hierarch.)", Choices{0,1}, Visible 1]; -FE_Degree = ( Flag_Degree == 0 ) ? 1 : 2; // Convert flag value into polynomial degree - -FunctionSpace { - { Name H_ux_Mec ; Type Form0 ; - BasisFunction { - { Name sxn ; NameOfCoef uxn ; Function BF_Node ; - Support Dom_H_u_Mec ; Entity NodesOf[ All ] ; } - If ( FE_Degree == 2 ) - { Name sxn2 ; NameOfCoef uxn2 ; Function BF_Node_2E ; - Support Dom_H_u_Mec; Entity EdgesOf[ All ] ; } - EndIf - } - Constraint { - { NameOfCoef uxn ; - EntityType NodesOf ; NameOfConstraint Displacement_x ; } - If ( FE_Degree == 2 ) - { NameOfCoef uxn2 ; - EntityType EdgesOf ; NameOfConstraint Displacement_x ; } - EndIf - } - } - { Name H_uy_Mec ; Type Form0 ; - BasisFunction { - { Name syn ; NameOfCoef uyn ; Function BF_Node ; - Support Dom_H_u_Mec ; Entity NodesOf[ All ] ; } - If ( FE_Degree == 2 ) - { Name syn2 ; NameOfCoef uyn2 ; Function BF_Node_2E ; - Support Dom_H_u_Mec; Entity EdgesOf[ All ] ; } - EndIf - } - Constraint { - { NameOfCoef uyn ; - EntityType NodesOf ; NameOfConstraint Displacement_y ; } - If ( FE_Degree == 2 ) - { NameOfCoef uyn2 ; - EntityType EdgesOf ; NameOfConstraint Displacement_y ; } - EndIf - } - } -} - - -Jacobian { - { Name Vol; - Case { - { Region All; Jacobian Vol; } - } - } - { Name Sur; - Case { - { Region All; Jacobian Sur; } - } - } -} - -/* Adapt the number of Gauss points to the polynomial degree of the finite elements -is as simple as this: */ -If (FE_Degree == 1) -Integration { - { Name Gauss_v; - Case { - {Type Gauss; - Case { - { GeoElement Line ; NumberOfPoints 3; } - { GeoElement Triangle ; NumberOfPoints 3; } - { GeoElement Quadrangle ; NumberOfPoints 4; } - } - } - } - } -} -ElseIf (FE_Degree == 2) -Integration { - { Name Gauss_v; - Case { - {Type Gauss; - Case { - { GeoElement Line ; NumberOfPoints 5; } - { GeoElement Triangle ; NumberOfPoints 7; } - { GeoElement Quadrangle ; NumberOfPoints 7; } - } - } - } - } -} -EndIf - -Formulation { - { Name Elast_u ; Type FemEquation ; - Quantity { - { Name ux ; Type Local ; NameOfSpace H_ux_Mec ; } - { Name uy ; Type Local ; NameOfSpace H_uy_Mec ; } - } - Equation { - Galerkin { [ -C_xx[] * Dof{d ux}, {d ux} ] ; - In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } - Galerkin { [ -C_xy[] * Dof{d uy}, {d ux} ] ; - In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } - Galerkin { [ -C_yx[] * Dof{d ux}, {d uy} ] ; - In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } - Galerkin { [ -C_yy[] * Dof{d uy}, {d uy} ] ; - In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } - - Galerkin { [ force_x[] , {ux} ]; - In Vol_Force_Mec ; Jacobian Vol ; Integration Gauss_v ; } - Galerkin { [ force_y[] , {uy} ]; - In Vol_Force_Mec ; Jacobian Vol ; Integration Gauss_v ; } - - Galerkin { [ pressure_x[] , {ux} ]; - In Sur_Force_Mec ; Jacobian Sur ; Integration Gauss_v ; } - Galerkin { [ pressure_y[] , {uy} ]; - In Sur_Force_Mec ; Jacobian Sur ; Integration Gauss_v ; } - } - } -} - -Resolution { - { Name Elast_u ; - System { - { Name Sys_Mec ; NameOfFormulation Elast_u; } - } - Operation { - InitSolution [Sys_Mec]; - Generate[Sys_Mec]; - Solve[Sys_Mec]; - SaveSolution[Sys_Mec] ; - } - } -} - -PostProcessing { - { Name Elast_u ; NameOfFormulation Elast_u ; - PostQuantity { - { Name u ; Value { Term { [ Vector[ {ux}, {uy}, 0 ]]; - In Vol_Elast_Mec ; Jacobian Vol ; } } } - { Name uy ; Value { Term { [ 1e3*{uy} ]; - In Vol_Elast_Mec ; Jacobian Vol ; } } } - { Name sig_xx ; Value { Term { - [ CompX[ C_xx[]*{d ux} + C_xy[]*{d uy} ] ]; - In Vol_Elast_Mec ; Jacobian Vol ; } } } - { Name sig_xy ; Value { Term { - [ CompY[ C_xx[]*{d ux} + C_xy[]*{d uy} ] ]; - In Vol_Elast_Mec ; Jacobian Vol ; } } } - { Name sig_yy ; Value { Term { - [ CompY [ C_yx[]*{d ux} + C_yy[]*{d uy} ] ]; - In Vol_Elast_Mec ; Jacobian Vol ; } } } - } - } -} - - - -PostOperation { - { Name pos; NameOfPostProcessing Elast_u; - Operation { - - If(FE_Degree == 1) - Print[ sig_xx, OnElementsOf Wrench, File "sigxx.pos" ]; - Print[ u, OnElementsOf Wrench, File "u.pos" ]; - Else - Print[ sig_xx, OnElementsOf Wrench, File "sigxx2.pos" ]; - Print[ u, OnElementsOf Wrench, File "u2.pos" ]; - EndIf - Echo[ StrCat["l=PostProcessing.NbViews-1; ", - "View[l].VectorType = 5; ", - "View[l].ExternalView = l; ", - "View[l].DisplacementFactor = 200; ", - "View[l-1].IntervalsType = 3; " - ], - File "tmp.geo", LastTimeStepOnly] ; - //Print[ sig_yy, OnElementsOf Wrench, File "sigyy.pos" ]; - //Print[ sig_xy, OnElementsOf Wrench, File "sigxy.pos" ]; - Print[ uy, OnPoint{probe_x, probe_y, 0}, - File > "deflection.pos", Format TimeTable, - SendToServer "Solution/Deflection (computed) [mm]", Color "AliceBlue" ]; - } - } -} - - -// Tell Gmsh which GetDP commands to execute when running the model. -DefineConstant[ - R_ = {"Elast_u", Name "GetDP/1ResolutionChoices", Visible 0}, - P_ = {"pos", Name "GetDP/2PostOperationChoices", Visible 0}, - C_ = {"-solve -pos -v2", Name "GetDP/9ComputeCommand", Visible 0} -]; - +/* ------------------------------------------------------------------- + Tutorial 3 : linear elastic model of a wrench + + Features: + - "Grad u" GetDP specific formulation for linear elasticity + - first and second order elements + - triangular and quadrangular elements + + To compute the solution interactively from the Gmsh GUI: + File > Open > wrench.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +/* Linear elasticity with GetDP: + + GetDP has a peculiar way to deal with linear elasticity. + Instead of vector field "u = Vector[ ux, uy, uz ]", + the displacement field is regarded as two (2D case) or 3 (3D case) scalar fields. + Unlike conventional formulations, GetDP's formulation is written + in terms of the gradient "Grad u" of the displacement field, + which is a non-symmetric tensor, and the needed symmetrization + (to define the strain tensor and relate it to the stress tensor) + is done through the constitutive relationship (Hooke law). + The reason for this unusual formulation is to be able to use also for elastic problems + the powerful geometrical and homological kernel of GetDP, + which relies on the operators Grad, Curl and Div. + + The "Grad u" formulation entails a small increase of assembly work + but makes in counterpart lots of geometrical features + implemented in GetDP (change of coordinates, function spaces, etc...) + applicable to elastic problems out-of-the-box, + since the scalar fields { ux, uy, uz } have exactly the same geometrical properties + as, e.g. a scalar electrip potential or a temperature field. +*/ + + +Include "wrench2D_common.pro"; + +Young = 1e9 * + DefineNumber[ 200, Name "Material/Young modulus [GPa]"]; +Poisson = + DefineNumber[ 0.3, Name "Material/Poisson coefficient []"]; +AppliedForce = + DefineNumber[ 100, Name "Material/Applied force [N]"]; + +// Approximation of the maximum deflection by an analytical model: +// Deflection = PL^3/(3EI) with I = Width^3*Thickness/12 +Deflection = + DefineNumber[4*AppliedForce*((LLength-0.018)/Width)^3/(Young*Thickness)*1e3, + Name "Solution/Deflection (analytical) [mm]", ReadOnly 1]; + +Group { + // Physical regions: Give explicit labels to the regions defined in the .geo file + Wrench = Region[ 1 ]; + Grip = Region[ 2 ]; + Force = Region[ 3 ]; + + // Abstract regions: + Vol_Elast_Mec = Region[ { Wrench } ]; + Vol_Force_Mec = Region[ { Wrench } ]; + Sur_Clamp_Mec = Region[ { Grip } ]; + Sur_Force_Mec = Region[ { Force } ]; +/* + Signification of the abstract regions: + Vol_Elast_Mec Elastic domain + Vol_Force_Mec Region with imposed volumic force + Sur_Force_Mec Surface with imposed surface traction + Sur_Clamp_Mec Surface with imposed zero displacements (all components) +*/ +} + +Function { + /* Material coefficients. + No need to define them regionwise here ( E[{Wrench}] = ... ; ) + as there is only one region in this model. */ + E[] = Young; + nu[] = Poisson; + /* Components of the volumic force applied to the region "Vol_Force_Mec" + Gravity could be defined here ( force_y[] = 7000*9.81; ) ; */ + force_x[] = 0; + force_y[] = 0; + /* Components of the surface traction force applied to the region "Sur_Force_Mec" */ + pressure_x[] = 0; + pressure_y[] = -AppliedForce/(SurfaceArea[]*Thickness); // downward vertical force +} + + +/* Hooke law + + The material law + + sigma_ij = C_ijkl epsilon_ij + + is represented in 2D by 4 2x2 tensors C_ij[], i,j=1,2 + depending on the Lamé coefficients of the isotropic linear material, + + lambda = E[]*nu[]/(1.+nu[])/(1.-2.*nu[]); + mu = E[]/2./(1.+nu[]); + + as follows + + EPC: a[] = E/(1-nu^2) b[] = mu c[] = E nu/(1-nu^2) + EPD: a[] = lambda + 2 mu b[] = mu c[] = lambda + 3D: a[] = lambda + 2 mu b[] = mu c[] = lambda + + respectively for the 2D plane strain (EPD), 2D plane stress (EPS) and 3D cases. +*/ + +Function { + Flag_EPC = 1; + If(Flag_EPC) // Plane stress + a[] = E[]/(1.-nu[]^2); + c[] = E[]*nu[]/(1.-nu[]^2); + Else // Plane strain or 3D + a[] = E[]*(1.-nu[])/(1.+nu[])/(1.-2.*nu[]); + c[] = E[]*nu[]/(1.+nu[])/(1.-2.*nu[]); + EndIf + b[] = E[]/2./(1.+nu[]); + + C_xx[] = Tensor[ a[],0 ,0 , 0 ,b[],0 , 0 ,0 ,b[] ]; + C_xy[] = Tensor[ 0 ,c[],0 , b[],0 ,0 , 0 ,0 ,0 ]; + + C_yx[] = Tensor[ 0 ,b[],0 , c[],0 ,0 , 0 ,0 ,0 ]; + C_yy[] = Tensor[ b[],0 ,0 , 0 ,a[],0 , 0 ,0 ,b[] ]; +} + +/* Clamping boundary condition */ +Constraint { + { Name Displacement_x; + Case { + { Region Sur_Clamp_Mec ; Type Assign ; Value 0; } + } + } + { Name Displacement_y; + Case { + { Region Sur_Clamp_Mec ; Type Assign ; Value 0; } + } + } +} + +/* As explained above, the displacement field is discretized + as two scalar fields "ux" and "uy", which are the spatial components + of the vector field "u" in a fixed Cartesian coordinate system. + + Boundary conditions like + + ux = ... ; + uy = ... ; + + translate naturally into Dirichlet constraints + on the scalar "ux" and "uy" FunctionSpaces. + Conditions like, however, + + u . n = ux Cos [th] + uy Sin [th] = ... ; + + are less naturally accounted for within the "Grad u" formulation. + Fortunately, they are rather uncommon. + + Finite element shape (triangles or quadrangles) makes no difference + in the definition of the FunctionSpaces. The appropriate shape functions to be used + are determined by GetDP at a much lower level on basis of the information + contained in the *.msh file. + + Second order elements, on the other hand, are implemented in the hierarchical fashion + by adding to the first order node-based shape functions + a set of second order edge-based functions + to complete a basis for 2d order polynomials on the reference element. + */ + + +// Domain of definition of the "ux" and "uy" FunctionSpaces +Group { + Dom_H_u_Mec = Region[ { Vol_Elast_Mec, + Sur_Force_Mec, + Sur_Clamp_Mec} ]; +} + +Flag_Degree = + DefineNumber[ 0, Name "Geometry/Use degree 2 (hierarch.)", Choices{0,1}, Visible 1]; +FE_Degree = ( Flag_Degree == 0 ) ? 1 : 2; // Convert flag value into polynomial degree + +FunctionSpace { + { Name H_ux_Mec ; Type Form0 ; + BasisFunction { + { Name sxn ; NameOfCoef uxn ; Function BF_Node ; + Support Dom_H_u_Mec ; Entity NodesOf[ All ] ; } + If ( FE_Degree == 2 ) + { Name sxn2 ; NameOfCoef uxn2 ; Function BF_Node_2E ; + Support Dom_H_u_Mec; Entity EdgesOf[ All ] ; } + EndIf + } + Constraint { + { NameOfCoef uxn ; + EntityType NodesOf ; NameOfConstraint Displacement_x ; } + If ( FE_Degree == 2 ) + { NameOfCoef uxn2 ; + EntityType EdgesOf ; NameOfConstraint Displacement_x ; } + EndIf + } + } + { Name H_uy_Mec ; Type Form0 ; + BasisFunction { + { Name syn ; NameOfCoef uyn ; Function BF_Node ; + Support Dom_H_u_Mec ; Entity NodesOf[ All ] ; } + If ( FE_Degree == 2 ) + { Name syn2 ; NameOfCoef uyn2 ; Function BF_Node_2E ; + Support Dom_H_u_Mec; Entity EdgesOf[ All ] ; } + EndIf + } + Constraint { + { NameOfCoef uyn ; + EntityType NodesOf ; NameOfConstraint Displacement_y ; } + If ( FE_Degree == 2 ) + { NameOfCoef uyn2 ; + EntityType EdgesOf ; NameOfConstraint Displacement_y ; } + EndIf + } + } +} + + +Jacobian { + { Name Vol; + Case { + { Region All; Jacobian Vol; } + } + } + { Name Sur; + Case { + { Region All; Jacobian Sur; } + } + } +} + +/* Adapt the number of Gauss points to the polynomial degree of the finite elements +is as simple as this: */ +If (FE_Degree == 1) +Integration { + { Name Gauss_v; + Case { + {Type Gauss; + Case { + { GeoElement Line ; NumberOfPoints 3; } + { GeoElement Triangle ; NumberOfPoints 3; } + { GeoElement Quadrangle ; NumberOfPoints 4; } + } + } + } + } +} +ElseIf (FE_Degree == 2) +Integration { + { Name Gauss_v; + Case { + {Type Gauss; + Case { + { GeoElement Line ; NumberOfPoints 5; } + { GeoElement Triangle ; NumberOfPoints 7; } + { GeoElement Quadrangle ; NumberOfPoints 7; } + } + } + } + } +} +EndIf + +Formulation { + { Name Elast_u ; Type FemEquation ; + Quantity { + { Name ux ; Type Local ; NameOfSpace H_ux_Mec ; } + { Name uy ; Type Local ; NameOfSpace H_uy_Mec ; } + } + Equation { + Integral { [ -C_xx[] * Dof{d ux}, {d ux} ] ; + In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } + Integral { [ -C_xy[] * Dof{d uy}, {d ux} ] ; + In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } + Integral { [ -C_yx[] * Dof{d ux}, {d uy} ] ; + In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } + Integral { [ -C_yy[] * Dof{d uy}, {d uy} ] ; + In Vol_Elast_Mec ; Jacobian Vol ; Integration Gauss_v ; } + + Integral { [ force_x[] , {ux} ]; + In Vol_Force_Mec ; Jacobian Vol ; Integration Gauss_v ; } + Integral { [ force_y[] , {uy} ]; + In Vol_Force_Mec ; Jacobian Vol ; Integration Gauss_v ; } + + Integral { [ pressure_x[] , {ux} ]; + In Sur_Force_Mec ; Jacobian Sur ; Integration Gauss_v ; } + Integral { [ pressure_y[] , {uy} ]; + In Sur_Force_Mec ; Jacobian Sur ; Integration Gauss_v ; } + } + } +} + +Resolution { + { Name Elast_u ; + System { + { Name Sys_Mec ; NameOfFormulation Elast_u; } + } + Operation { + InitSolution [Sys_Mec]; + Generate[Sys_Mec]; + Solve[Sys_Mec]; + SaveSolution[Sys_Mec] ; + } + } +} + +PostProcessing { + { Name Elast_u ; NameOfFormulation Elast_u ; + PostQuantity { + { Name u ; Value { Term { [ Vector[ {ux}, {uy}, 0 ]]; + In Vol_Elast_Mec ; Jacobian Vol ; } } } + { Name uy ; Value { Term { [ 1e3*{uy} ]; + In Vol_Elast_Mec ; Jacobian Vol ; } } } + { Name sig_xx ; Value { Term { + [ CompX[ C_xx[]*{d ux} + C_xy[]*{d uy} ] ]; + In Vol_Elast_Mec ; Jacobian Vol ; } } } + { Name sig_xy ; Value { Term { + [ CompY[ C_xx[]*{d ux} + C_xy[]*{d uy} ] ]; + In Vol_Elast_Mec ; Jacobian Vol ; } } } + { Name sig_yy ; Value { Term { + [ CompY [ C_yx[]*{d ux} + C_yy[]*{d uy} ] ]; + In Vol_Elast_Mec ; Jacobian Vol ; } } } + } + } +} + + + +PostOperation { + { Name pos; NameOfPostProcessing Elast_u; + Operation { + + If(FE_Degree == 1) + Print[ sig_xx, OnElementsOf Wrench, File "sigxx.pos" ]; + Print[ u, OnElementsOf Wrench, File "u.pos" ]; + Else + Print[ sig_xx, OnElementsOf Wrench, File "sigxx2.pos" ]; + Print[ u, OnElementsOf Wrench, File "u2.pos" ]; + EndIf + Echo[ StrCat["l=PostProcessing.NbViews-1; ", + "View[l].VectorType = 5; ", + "View[l].ExternalView = l; ", + "View[l].DisplacementFactor = 200; ", + "View[l-1].IntervalsType = 3; " + ], + File "tmp.geo", LastTimeStepOnly] ; + //Print[ sig_yy, OnElementsOf Wrench, File "sigyy.pos" ]; + //Print[ sig_xy, OnElementsOf Wrench, File "sigxy.pos" ]; + Print[ uy, OnPoint{probe_x, probe_y, 0}, + File > "deflection.pos", Format TimeTable, + SendToServer "Solution/Deflection (computed) [mm]", Color "AliceBlue" ]; + } + } +} + + +// Tell Gmsh which GetDP commands to execute when running the model. +DefineConstant[ + R_ = {"Elast_u", Name "GetDP/1ResolutionChoices", Visible 0}, + P_ = {"pos", Name "GetDP/2PostOperationChoices", Visible 0}, + C_ = {"-solve -pos -v2", Name "GetDP/9ComputeCommand", Visible 0} +]; diff --git a/Elasticity/wrench2D_common.pro b/Elasticity/wrench2D_common.pro index 578f64f..b9b045e 100644 --- a/Elasticity/wrench2D_common.pro +++ b/Elasticity/wrench2D_common.pro @@ -1,29 +1,29 @@ -// Some useful conversion coefficients -mm = 1.e-3; // millimeters to meters -cm = 1.e-2; // centimeters to meters -in = 0.0254; // inches to meters -deg = Pi/180.; // degrees to radians - -Refine = - mm*DefineNumber[ 2, Name "Geometry/2Main characteristic length"]; -Recomb = - DefineNumber[ 0, Name "Geometry/1Recombine", Choices{0,1}]; -Thickness = - mm*DefineNumber[ 10, Name "Geometry/4Thickness (mm)"]; -Width = - mm*DefineNumber[ 0.625*in/mm, Name "Geometry/5Arm Width (mm)"]; -LLength = - cm*DefineNumber[ 6.0*in/cm, Name "Geometry/6Arm Length (cm)"]; - -// Definition of the coordinates of the arm end -// at which the maximal deflection will be evaluated. -Inclination = 14*deg; // Arm angle with x-axis -eps = 1e-6; -probe_x = (LLength-eps)*Cos[Inclination]; -probe_y =-(LLength-eps)*Sin[Inclination]; - -// a useful Print command to debug a model or communicate with the user -Printf("Maximal deflection calculated at point (%f,%f)", probe_x, probe_y); - - - +// Some useful conversion coefficients +mm = 1.e-3; // millimeters to meters +cm = 1.e-2; // centimeters to meters +in = 0.0254; // inches to meters +deg = Pi/180.; // degrees to radians + +Refine = + mm*DefineNumber[ 2, Name "Geometry/2Main characteristic length"]; +Recomb = + DefineNumber[ 0, Name "Geometry/1Recombine", Choices{0,1}]; +Thickness = + mm*DefineNumber[ 10, Name "Geometry/4Thickness (mm)"]; +Width = + mm*DefineNumber[ 0.625*in/mm, Name "Geometry/5Arm Width (mm)"]; +LLength = + cm*DefineNumber[ 6.0*in/cm, Name "Geometry/6Arm Length (cm)"]; + +// Definition of the coordinates of the arm end +// at which the maximal deflection will be evaluated. +Inclination = 14*deg; // Arm angle with x-axis +eps = 1e-6; +probe_x = (LLength-eps)*Cos[Inclination]; +probe_y =-(LLength-eps)*Sin[Inclination]; + +// a useful Print command to debug a model or communicate with the user +Printf("Maximal deflection calculated at point (%f,%f)", probe_x, probe_y); + + + diff --git a/Electrostatics/microstrip.geo b/Electrostatics/microstrip.geo index 04ecbf5..0d0d855 100644 --- a/Electrostatics/microstrip.geo +++ b/Electrostatics/microstrip.geo @@ -1,58 +1,58 @@ -/* ------------------------------------------------------------------- - File "microstrip.geo" - - This file is the geometrical description used by Gmsh to produce the mesh - file "microstrip.msh", which is read by GetDP when analysing the file - "microstrip.pro". - ------------------------------------------------------------------- */ - -/* Definition of some parameters for geometrical dimensions, i.e. h (height of - 'Diel1'), w (width of 'Line'), t (thickness of 'Line') xBox (width of the air - box) and yBox (height of the air box) */ - -h = 1.e-3 ; w = 4.72e-3 ; t = 0.035e-3 ; -xBox = w/2. * 6. ; yBox = h * 12. ; - -/* Definition of parameters for local mesh dimensions */ - -s = 1. ; -p0 = h / 10. * s ; -pLine0 = w/2. / 10. * s ; pLine1 = w/2. / 50. * s ; -pxBox = xBox / 10. * s ; pyBox = yBox / 8. * s ; - -/* Definition of gemetrical points */ - -Point(1) = { 0 , 0, 0, p0} ; -Point(2) = { xBox, 0, 0, pxBox} ; -Point(3) = { xBox, h, 0, pxBox} ; -Point(4) = { 0 , h, 0, pLine0} ; -Point(5) = { w/2., h, 0, pLine1} ; -Point(6) = { 0 , h+t, 0, pLine0} ; -Point(7) = { w/2., h+t, 0, pLine1} ; -Point(8) = { 0 , yBox, 0, pyBox} ; -Point(9) = { xBox, yBox, 0, pyBox} ; - -/* Definition of gemetrical lines */ - -Line(1) = {1,2}; Line(2) = {2,3}; Line(3) = {3,9}; -Line(4) = {9,8}; Line(5) = {8,6}; Line(7) = {4,1}; -Line(8) = {5,3}; Line(9) = {4,5}; Line(10) = {6,7}; -Line(11) = {5,7}; - -/* Definition of geometrical surfaces */ - -Curve Loop(12) = {1, 2, -8, -9, 7}; Plane Surface(13) = {12}; -Curve Loop(14) = {10,-11,8,3,4,5}; Plane Surface(15) = {14}; - -/* Definition of Physical entities. The definition of Physical entities - (Surfaces and Curves) tells Gmsh the elements and associated region numbers - that have to be saved in the mesh file 'microstrip.msh'. For example, Region - 111 is made of the triangle elements of the geometric surface 13, whereas - Region 121 is made of line elements of the geometric curves 9, 10 and 11. */ - -Physical Surface("Air", 101) = {15}; -Physical Surface("Dielectric", 111) = {13}; - -Physical Curve("Ground", 120) = {1} ; -Physical Curve("Electrode", 121) = {9,10,11} ; -Physical Curve("Surface infinity", 130) = {2,3,4} ; +/* ------------------------------------------------------------------- + File "microstrip.geo" + + This file is the geometrical description used by Gmsh to produce the mesh + file "microstrip.msh", which is read by GetDP when analysing the file + "microstrip.pro". + ------------------------------------------------------------------- */ + +/* Definition of some parameters for geometrical dimensions, i.e. h (height of + 'Diel1'), w (width of 'Line'), t (thickness of 'Line') xBox (width of the air + box) and yBox (height of the air box) */ + +h = 1.e-3 ; w = 4.72e-3 ; t = 0.035e-3 ; +xBox = w/2. * 6. ; yBox = h * 12. ; + +/* Definition of parameters for local mesh dimensions */ + +s = 1. ; +p0 = h / 10. * s ; +pLine0 = w/2. / 10. * s ; pLine1 = w/2. / 50. * s ; +pxBox = xBox / 10. * s ; pyBox = yBox / 8. * s ; + +/* Definition of gemetrical points */ + +Point(1) = { 0 , 0, 0, p0} ; +Point(2) = { xBox, 0, 0, pxBox} ; +Point(3) = { xBox, h, 0, pxBox} ; +Point(4) = { 0 , h, 0, pLine0} ; +Point(5) = { w/2., h, 0, pLine1} ; +Point(6) = { 0 , h+t, 0, pLine0} ; +Point(7) = { w/2., h+t, 0, pLine1} ; +Point(8) = { 0 , yBox, 0, pyBox} ; +Point(9) = { xBox, yBox, 0, pyBox} ; + +/* Definition of gemetrical lines */ + +Line(1) = {1,2}; Line(2) = {2,3}; Line(3) = {3,9}; +Line(4) = {9,8}; Line(5) = {8,6}; Line(7) = {4,1}; +Line(8) = {5,3}; Line(9) = {4,5}; Line(10) = {6,7}; +Line(11) = {5,7}; + +/* Definition of geometrical surfaces */ + +Curve Loop(12) = {1, 2, -8, -9, 7}; Plane Surface(13) = {12}; +Curve Loop(14) = {10,-11,8,3,4,5}; Plane Surface(15) = {14}; + +/* Definition of Physical entities. The definition of Physical entities + (Surfaces and Curves) tells Gmsh the elements and associated region numbers + that have to be saved in the mesh file 'microstrip.msh'. For example, Region + 111 is made of the triangle elements of the geometric surface 13, whereas + Region 121 is made of line elements of the geometric curves 9, 10 and 11. */ + +Physical Surface("Air", 101) = {15}; +Physical Surface("Dielectric", 111) = {13}; + +Physical Curve("Ground", 120) = {1} ; +Physical Curve("Electrode", 121) = {9,10,11} ; +Physical Curve("Surface infinity", 130) = {2,3,4} ; diff --git a/Electrostatics/microstrip.pro b/Electrostatics/microstrip.pro index bdf89a6..f194945 100644 --- a/Electrostatics/microstrip.pro +++ b/Electrostatics/microstrip.pro @@ -1,327 +1,324 @@ -/* ------------------------------------------------------------------- - Tutorial 1 : electrostatic field of a microstrip - - Features: - - Physical and abstract regions - - Scalar FunctionSpace with Dirichlet constraint - - Galerkin term for stiffness matrix - - To compute the solution in a terminal: - getdp microstrip -solve EleSta_v - getdp microstrip -pos Map - getdp microstrip -pos Cut - - To compute the solution interactively from the Gmsh GUI: - File > Open > microstrip.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -/* In this first tutorial we consider the calculation of the electric field - given a static distribution of electric potential. This corresponds to an - "electrostatic" physical model, obtained by combining the time-invariant - Maxwell-Ampere equation (Curl e = 0, with e the electric field) with Gauss' - law (Div d = rho, with d the displacement field and rho the charge density) - and the dielectric constitutive law (d = epsilon e, with epsilon the - dielectric permittivity). - - Since Curl e = 0, e can be derived from a scalar electric potential v, such - that e = -Grad v. Plugging this potential in Gauss' law and using the - constitutive law leads to a scalar Poisson equation in terms of the electric - potential: -Div(epsilon Grad v) = rho. - - We consider here the special case where rho = 0, to model a conducting - microstrip line on top of a dielectric substrate. A Dirichlet boundary - condition sets the potential to 1 mV on the boundary of the microstrip line - (called "Electrode" below) and 0 V on the ground. A homogeneous Neumann - boundary condition (zero flux of the displacement field, i.e. n.d = 0) is - imposed on the left boundary of the domain to account for the symmetry of the - problem, as well as on the top and right boundaries that truncate the - modelling domain. */ - -Group { - /* One starts by giving explicit meaningful names to the Physical regions - defined in the "microstrip.msh" mesh file. We only use 2 volume regions and - 2 surface regions in this model. */ - - Air = Region[101]; - Diel1 = Region[111]; - - Ground = Region[120]; - Electrode = Region[121]; - - /* We now define abstract regions to be used below in the definition of the - scalar electric potential formulation: - - Vol_Ele : volume where -Div(epsilon Grad v) = 0 is solved - Sur_Neumann_Ele: surface where non homogeneous Neumann boundary conditions - (on n.d == epsilon n.Grad v) are imposed - - Vol_xxx groups contain only volume elements of the mesh (triangles here). - Sur_xxx groups contain only surface elements of the mesh (lines here). - - Since there are no non-homogeneous Neumann conditions in the model, - Sur_Neumann_Ele is defined as empty. - */ - - Vol_Ele = Region[ {Air, Diel1} ]; - Sur_Neumann_Ele = Region[ {} ]; -} - -Function { - /* Material laws (here the dielectric permittivity) are defined as piecewise - functions (note the square brackets), in terms of the above defined - physical regions. */ - - eps0 = 8.854187818e-12; - epsilon[Air] = 1. * eps0; - epsilon[Diel1] = 9.8 * eps0; -} - -Constraint { - /* As for material laws, the Dirichlet boundary condition is defined - piecewise. The constraint "Dirichlet_Ele" is invoked in the FunctionSpace - below. */ - - { Name Dirichlet_Ele; Type Assign; - Case { - { Region Ground; Value 0.; } - { Region Electrode; Value 1.e-3; } - } - } -} - -Group{ - /* The domain of definition of a FunctionSpace lists all regions on which a - field is defined. - - Contrary to Vol_xxx and Sur_xxx regions, which contain only volume or - surface regions, resp., domains of definition Dom_xxx regions may contain - both volume and surface regions. Hence the use of the prefixes Vol_, Sur_ - and Dom_ to avoid confusions.*/ - - Dom_Hgrad_v_Ele = Region[ {Vol_Ele, Sur_Neumann_Ele} ]; -} - -FunctionSpace { - /* The function space in which we shall pick the electric scalar potential "v" - solution is definied by - - a domain of definition (the "Support": "Dom_Hgrad_v_Ele") - - a type ("Form0" means scalar field) - - a set of scalar basis functions ("BF_Node" means nodal basis functions) - - a set of entities to which the basis functions are associated ("Entity": - here all the nodes of the domain of definition "NodesOf[All]") - - a constraint (here the Dirichlet boundary conditions) - - The FE expansion of the unknown field "v" reads - - v(x,y) = Sum_k vn_k sn_k(x,y) - - where the "vn_k" are the nodal values (connectors) and "sn_k(x,y)" the - nodal basis functions. Not all connectors are unknowns of the FE problem, - due to the "Constraint", which assigns particular values to the nodes of - the Ground and Electrode regions. GetDP deals with that automatically on - basis of the definition of the FunctionSpace. */ - - { Name Hgrad_v_Ele; Type Form0; - BasisFunction { - { Name sn; NameOfCoef vn; Function BF_Node; - Support Dom_Hgrad_v_Ele; Entity NodesOf[ All ]; } - // using "NodesOf[All]" instead of "NodesOf[Dom_Hgrad_v_Ele]" is an - // optimization, which allows GetDP to not explicitly build the list of - // all nodes - } - Constraint { - { NameOfCoef vn; EntityType NodesOf; NameOfConstraint Dirichlet_Ele; } - } - } -} - -Jacobian { - /* Jacobians are used to specify the mapping between elements in the mesh and - the reference elements (defined in standardized unit cells) over which - integration is performed. "Vol" represents the classical 1-to-1 mapping - between elements of identical geometrical dimension, i.e. in this case a - reference triangle/quadrangle onto triangles/quadrangles in the z=0 plane - (2D <-> 2D). "Sur" would be used to map the reference triangle/quadrangle - onto triangles/quadrangles in a 3D space (2D <-> 3D), or to map the - reference line segment onto segments in 2D space (1D <-> 2D). "Lin" would - be used to map the reference line segment onto segments in 3D space (1D <-> - 3D). */ - - { Name Vol ; - Case { - { Region All ; Jacobian Vol ; } - } - } -} - -Integration { - /* A Gauss quadrature rule with 4 points is used for all integrations below. */ - - { Name Int ; - Case { { Type Gauss ; - Case { { GeoElement Triangle ; NumberOfPoints 4 ; } - { GeoElement Quadrangle ; NumberOfPoints 4 ; } } - } - } - } -} - -Formulation { - /* The syntax of the Formulation section is a harder nut to crack. So let's - deal with it carefully. - - A GetDP Formulation encodes a so-called weak formulation of the original - partial differential equation, i.e. of -Div(epsilon Grad v) = 0. This weak - formulation involves finding v such that - - (-Div(epsilon Grad v) , v')_Vol_Ele = 0 - - holds for all so-called "test-functions" v', where (.,.)_D denotes an inner - product over the domain D. If the test-functions v' are differentiable, - integration by parts using Green's identity leads to finding v such that - - (epsilon Grad v, Grad v')_Vol_Ele + (epsilon n.Grad v, v')_Sur_Neumann_Ele = 0 - - holds for all v'. - - In our microstrip example the Neumann boundary term vanishes and we are - looking for functions v in the function space Hgrad_v_Ele such that - - (epsilon Grad v, Grad v')_Vol_Ele = 0 - - holds for all v', where the test functions v' are the same basis functions - ("sn_k") as the ones used to interpolate the unknown potential v. - - The Galerkin statement in the Formulation is a symbolic representation of - this weak formulation. It has got 4 semicolon separated arguments: - * the density [.,.] to be integrated (note the square brackets instead of - the parentheses), with the test-functions (always) after the comma - * the domain of integration, - * the Jacobian of the transformation reference element <-> real element, - * the integration method to be used. - - In the density, braces around a quantity (such as "{v}") indicate that this - quantity belongs to a FunctionSpace. Differential operators can be applied - within braces (such as "{Grad v}"); in particular the symbol "d" represents - the exterior derivative, and it is a synonym of "Grad" when applied to a - scalar function (such as "{d v}"). - - What can be a bit confusing is that the two comma-separated terms of the - density are not interpreted exactly in the same way. Let us unravel this in - detail. - - As the Galerkin method uses as test functions the basis functions "sn_k" of - the unknown field "v", the second term in the density should be something - like this [ ... , basis_functions_of {d v} ]. However, since the second - term is always devoted to test functions, the operator "basis_functions_of" - would always be there. It can therefore be made implicit, and, according - to the GetDP syntax, it is omitted. So, one writes simply [ ... , {d v} ]. - - The first term, on the other hand, can contain a much wider variety of - expressions than the second one. In our case it should be expressed in - terms of the FE expansion of "v" at the present system solution, i.e. when - the coefficients vn_k in the expansion of "v = Sum_k vn_k sn_k" are - unknown. This is indicated by prefixing the braces with "Dof", which leads - to the following density: - - [ epsilon[] * Dof{d v} , {d v} ], - - a so-called bilinear term that will contribute to the stiffness matrix of - the electrostatic problem at hand. - - Another option, which would not work here, is to evaluate the first - argument with the last available already computed solution, i.e. simply - perform the interpolation with known coefficients vn_k. For this the Dof - prefix operator would be omitted and we would have: - - [ epsilon[] * {d v} , {d v} ], - - a so-called linear term that will contribute to the right-hand side of the - linear system. - - Both choices are commonly used in different contexts, and we shall come - back on this often in subsequent tutorials. */ - { Name Electrostatics_v; Type FemEquation; - Quantity { - { Name v; Type Local; NameOfSpace Hgrad_v_Ele; } - } - Equation { - Galerkin { [ epsilon[] * Dof{d v} , {d v} ]; - In Vol_Ele; Jacobian Vol; Integration Int; } - } - } -} - -Resolution { - { Name EleSta_v; - System { - { Name Sys_Ele; NameOfFormulation Electrostatics_v; } - } - Operation { - Generate[Sys_Ele]; Solve[Sys_Ele]; SaveSolution[Sys_Ele]; - } - } -} - -/* Post-processing is done in two parts. - - The first part defines, in terms of the Formulation, which itself refers to - the FunctionSpace, a number of quantities that can be evaluated at the - postprocessing stage. The three quantities defined here are: - - the scalar vector potential, - - the electric field, - - the electric displacement. - - The second part consists in defining groups of post-processing operations, - which can be invoked separately. The first group is invoked by default when - Gmsh is run interactively. Each Operation specifies - - a quantity to be eveluated, - - the region on which the evaluation is done, - - the name of the output file. - The generated post-processing files are automatically displayed by Gmsh if - the "Merge result automatically" option is enabled (which is the default). */ - -PostProcessing { - { Name EleSta_v; NameOfFormulation Electrostatics_v; - Quantity { - { Name v; - Value { - Local { [ {v} ]; - In Dom_Hgrad_v_Ele; Jacobian Vol; } - } - } - { Name e; - Value { - Local { [ -{d v} ]; - In Dom_Hgrad_v_Ele; Jacobian Vol; } - } - } - { Name d; - Value { - Local { [ -epsilon[] * {d v} ]; - In Dom_Hgrad_v_Ele; Jacobian Vol; } - } - } - } - } -} - -e = 1.e-7; // tolerance to ensure that the cut is inside the simulation domain -h = 2.e-3; // vertical position of the cut - -PostOperation { - { Name Map; NameOfPostProcessing EleSta_v; - Operation { - Print [ v, OnElementsOf Dom_Hgrad_v_Ele, File "mStrip_v.pos" ]; - Print [ e, OnElementsOf Dom_Hgrad_v_Ele, File "mStrip_e.pos" ]; - Print [ e, OnLine {{e,h,0}{14.e-3,h,0}}{60}, File "Cut_e.pos" ]; - } - } - { Name Cut; NameOfPostProcessing EleSta_v; - // same cut as above, with more points and exported in raw text format - Operation { - Print [ e, OnLine {{e,e,0}{14.e-3,e,0}} {500}, Format TimeTable, File "Cut_e.txt" ]; - } - } -} +/* ------------------------------------------------------------------- + Tutorial 1 : electrostatic field of a microstrip + + Features: + - Physical and abstract regions + - Scalar FunctionSpace with Dirichlet constraint + - Galerkin term for stiffness matrix + + To compute the solution in a terminal: + getdp microstrip -solve EleSta_v + getdp microstrip -pos Map + getdp microstrip -pos Cut + + To compute the solution interactively from the Gmsh GUI: + File > Open > microstrip.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +/* In this first tutorial we consider the calculation of the electric field + given a static distribution of electric potential. This corresponds to an + "electrostatic" physical model, obtained by combining the time-invariant + Maxwell-Ampere equation (Curl e = 0, with e the electric field) with Gauss' + law (Div d = rho, with d the displacement field and rho the charge density) + and the dielectric constitutive law (d = epsilon e, with epsilon the + dielectric permittivity). + + Since Curl e = 0, e can be derived from a scalar electric potential v, such + that e = -Grad v. Plugging this potential in Gauss' law and using the + constitutive law leads to a scalar Poisson equation in terms of the electric + potential: -Div(epsilon Grad v) = rho. + + We consider here the special case where rho = 0, to model a conducting + microstrip line on top of a dielectric substrate. A Dirichlet boundary + condition sets the potential to 1 mV on the boundary of the microstrip line + (called "Electrode" below) and 0 V on the ground. A homogeneous Neumann + boundary condition (zero flux of the displacement field, i.e. n.d = 0) is + imposed on the left boundary of the domain to account for the symmetry of the + problem, as well as on the top and right boundaries that truncate the + modelling domain. */ + +Group { + /* One starts by giving explicit meaningful names to the Physical regions + defined in the "microstrip.msh" mesh file. We only use 2 volume regions and + 2 surface regions in this model. */ + + Air = Region[101]; + Diel1 = Region[111]; + + Ground = Region[120]; + Electrode = Region[121]; + + /* We now define abstract regions to be used below in the definition of the + scalar electric potential formulation: + + Vol_Ele : volume where -Div(epsilon Grad v) = 0 is solved + Sur_Neumann_Ele: surface where non homogeneous Neumann boundary conditions + (on n.d == epsilon n.Grad v) are imposed + + Vol_xxx groups contain only volume elements of the mesh (triangles here). + Sur_xxx groups contain only surface elements of the mesh (lines here). + + Since there are no non-homogeneous Neumann conditions in the model, + Sur_Neumann_Ele is defined as empty. + */ + + Vol_Ele = Region[ {Air, Diel1} ]; + Sur_Neumann_Ele = Region[ {} ]; +} + +Function { + /* Material laws (here the dielectric permittivity) are defined as piecewise + functions (note the square brackets), in terms of the above defined + physical regions. */ + + eps0 = 8.854187818e-12; + epsilon[Air] = 1. * eps0; + epsilon[Diel1] = 9.8 * eps0; +} + +Constraint { + /* As for material laws, the Dirichlet boundary condition is defined + piecewise. The constraint "Dirichlet_Ele" is invoked in the FunctionSpace + below. */ + + { Name Dirichlet_Ele; Type Assign; + Case { + { Region Ground; Value 0.; } + { Region Electrode; Value 1.e-3; } + } + } +} + +Group{ + /* The domain of definition of a FunctionSpace lists all regions on which a + field is defined. + + Contrary to Vol_xxx and Sur_xxx regions, which contain only volume or + surface regions, resp., domains of definition Dom_xxx regions may contain + both volume and surface regions. Hence the use of the prefixes Vol_, Sur_ + and Dom_ to avoid confusions.*/ + + Dom_Hgrad_v_Ele = Region[ {Vol_Ele, Sur_Neumann_Ele} ]; +} + +FunctionSpace { + /* The function space in which we shall pick the electric scalar potential "v" + solution is definied by + - a domain of definition (the "Support": "Dom_Hgrad_v_Ele") + - a type ("Form0" means scalar field) + - a set of scalar basis functions ("BF_Node" means nodal basis functions) + - a set of entities to which the basis functions are associated ("Entity": + here all the nodes of the domain of definition "NodesOf[All]") + - a constraint (here the Dirichlet boundary conditions) + + The FE expansion of the unknown field "v" reads + + v(x,y) = Sum_k vn_k sn_k(x,y) + + where the "vn_k" are the nodal values (connectors) and "sn_k(x,y)" the + nodal basis functions. Not all connectors are unknowns of the FE problem, + due to the "Constraint", which assigns particular values to the nodes of + the Ground and Electrode regions. GetDP deals with that automatically on + basis of the definition of the FunctionSpace. */ + + { Name Hgrad_v_Ele; Type Form0; + BasisFunction { + { Name sn; NameOfCoef vn; Function BF_Node; + Support Dom_Hgrad_v_Ele; Entity NodesOf[ All ]; } + // using "NodesOf[All]" instead of "NodesOf[Dom_Hgrad_v_Ele]" is an + // optimization, which allows GetDP to not explicitly build the list of + // all nodes + } + Constraint { + { NameOfCoef vn; EntityType NodesOf; NameOfConstraint Dirichlet_Ele; } + } + } +} + +Jacobian { + /* Jacobians are used to specify the mapping between elements in the mesh and + the reference elements (defined in standardized unit cells) over which + integration is performed. "Vol" represents the classical 1-to-1 mapping + between elements of identical geometrical dimension, i.e. in this case a + reference triangle/quadrangle onto triangles/quadrangles in the z=0 plane + (2D <-> 2D). "Sur" would be used to map the reference triangle/quadrangle + onto triangles/quadrangles in a 3D space (2D <-> 3D), or to map the + reference line segment onto segments in 2D space (1D <-> 2D). "Lin" would + be used to map the reference line segment onto segments in 3D space (1D <-> + 3D). */ + + { Name Vol ; + Case { + { Region All ; Jacobian Vol ; } + } + } +} + +Integration { + /* A Gauss quadrature rule with 4 points is used for all integrations below. */ + + { Name Int ; + Case { { Type Gauss ; + Case { { GeoElement Triangle ; NumberOfPoints 4 ; } + { GeoElement Quadrangle ; NumberOfPoints 4 ; } } + } + } + } +} + +Formulation { + /* The syntax of the Formulation section is a harder nut to crack. So let's + deal with it carefully. + + A GetDP Formulation encodes a so-called weak formulation of the original + partial differential equation, i.e. of -Div(epsilon Grad v) = 0. This weak + formulation involves finding v such that + + (-Div(epsilon Grad v) , v')_Vol_Ele = 0 + + holds for all so-called "test-functions" v', where (.,.)_D denotes an inner + product over the domain D. If the test-functions v' are differentiable, + integration by parts using Green's identity leads to finding v such that + + (epsilon Grad v, Grad v')_Vol_Ele + (epsilon n.Grad v, v')_Bnd_Vol_Ele = 0 + + holds for all v', where Bnd_Vol_Ele is the boundary of Vol_Ele. In our + microstrip example this surface term vanishes, as either there is no test + function v' (on the Dirichlet boundary) or the "epsilon n.Grad v" is zero + (on the homogeneous Neumann boundary). We are thus eventually looking for + functions v in the function space Hgrad_v_Ele such that + + (epsilon Grad v, Grad v')_Vol_Ele = 0 + + holds for all v'. Finally, our choice here is to use a Gakerkin method, + where the test functions v' are the same basis functions ("sn_k") as the + ones used to interpolate the unknown potential v. + + The "Integral" statement in the Formulation is a symbolic representation of + this weak formulation. It has got 4 semicolon separated arguments: + * the density [.,.] to be integrated (note the square brackets instead of + the parentheses), with the test-functions (always) after the comma + * the domain of integration, + * the Jacobian of the transformation reference element <-> real element, + * the integration method to be used. + + In the density, braces around a quantity (such as "{v}") indicate that this + quantity belongs to a FunctionSpace. Differential operators can be applied + within braces (such as "{Grad v}"); in particular the symbol "d" represents + the exterior derivative, and it is a synonym of "Grad" when applied to a + scalar function (such as "{d v}"). + + What can be a bit confusing is that the two comma-separated terms of the + density are not interpreted exactly in the same way. Let us unravel this in + detail. + + As the Galerkin method uses as test functions the same basis functions + "sn_k" as for the unknown field "v", the second term in the density should + be something like this [ ... , basis_functions_of {d v} ]. However, since + the second term is always devoted to test functions, the operator + "basis_functions_of" would always be there. It can therefore be made + implicit, and, according to the GetDP syntax, it is omitted. So, one writes + simply [ ... , {d v} ]. + + The first term, on the other hand, can contain a much wider variety of + expressions than the second one. In our case it should be expressed in + terms of the FE expansion of "v" at the present system solution, i.e. when + the coefficients vn_k in the expansion of "v = Sum_k vn_k sn_k" are + unknown. This is indicated by prefixing the braces with "Dof", which leads + to the following density: + + [ epsilon[] * Dof{d v} , {d v} ], + + a so-called bilinear term that will contribute to the stiffness matrix of + the electrostatic problem at hand. + + Another option, which would not work here, is to evaluate the first + argument with the last available already computed solution, i.e. simply + perform the interpolation with known coefficients vn_k. For this the Dof + prefix operator would be omitted and we would have: + + [ epsilon[] * {d v} , {d v} ], + + a so-called linear term that will contribute to the right-hand side of the + linear system. + + Both choices are commonly used in different contexts, and we shall come + back on this often in subsequent tutorials. */ + { Name Electrostatics_v; Type FemEquation; + Quantity { + { Name v; Type Local; NameOfSpace Hgrad_v_Ele; } + } + Equation { + Integral { [ epsilon[] * Dof{d v} , {d v} ]; + In Vol_Ele; Jacobian Vol; Integration Int; } + } + } +} + +Resolution { + { Name EleSta_v; + System { + { Name Sys_Ele; NameOfFormulation Electrostatics_v; } + } + Operation { + Generate[Sys_Ele]; Solve[Sys_Ele]; SaveSolution[Sys_Ele]; + } + } +} + +/* Post-processing is done in two parts. + + The first part defines, in terms of the Formulation, which itself refers to + the FunctionSpace, a number of quantities that can be evaluated at the + postprocessing stage. The three quantities defined here are: + - the scalar vector potential, + - the electric field, + - the electric displacement. + + The second part consists in defining groups of post-processing operations, + which can be invoked separately. The first group is invoked by default when + Gmsh is run interactively. Each Operation specifies + - a quantity to be eveluated, + - the region on which the evaluation is done, + - the name of the output file. + The generated post-processing files are automatically displayed by Gmsh if + the "Merge result automatically" option is enabled (which is the default). */ + +PostProcessing { + { Name EleSta_v; NameOfFormulation Electrostatics_v; + Quantity { + { Name v; Value { + Local { [ {v} ]; In Dom_Hgrad_v_Ele; Jacobian Vol; } + } + } + { Name e; Value { + Local { [ -{d v} ]; In Dom_Hgrad_v_Ele; Jacobian Vol; } + } + } + { Name d; Value { + Local { [ -epsilon[] * {d v} ]; In Dom_Hgrad_v_Ele; Jacobian Vol; } + } + } + } + } +} + +e = 1.e-7; // tolerance to ensure that the cut is inside the simulation domain +h = 2.e-3; // vertical position of the cut + +PostOperation { + { Name Map; NameOfPostProcessing EleSta_v; + Operation { + Print [ v, OnElementsOf Dom_Hgrad_v_Ele, File "mStrip_v.pos" ]; + Print [ e, OnElementsOf Dom_Hgrad_v_Ele, File "mStrip_e.pos" ]; + Print [ e, OnLine {{e,h,0}{14.e-3,h,0}}{60}, File "Cut_e.pos" ]; + } + } + { Name Cut; NameOfPostProcessing EleSta_v; + // same cut as above, with more points and exported in raw text format + Operation { + Print [ e, OnLine {{e,e,0}{14.e-3,e,0}} {500}, Format TimeTable, File "Cut_e.txt" ]; + } + } +} diff --git a/Magnetodynamics/Lib_MagStaDyn_av_2D_Cir.pro b/Magnetodynamics/Lib_MagStaDyn_av_2D_Cir.pro index 3a05f85..e0122eb 100644 --- a/Magnetodynamics/Lib_MagStaDyn_av_2D_Cir.pro +++ b/Magnetodynamics/Lib_MagStaDyn_av_2D_Cir.pro @@ -1,468 +1,468 @@ -// This is a template .pro file containing a general formulation for 2D -// magnetostatic and magnetodynamic problems in terms of the magnetic vector -// potential a (potentially coupled with the electric scalar potential v), with -// optional circuit coupling. - -// Below are definitions of the constants (inside "DefineConstant"), groups -// (inside "DefineGroup") and functions (inside "DefineFunction") that can be -// redefined from outside this template. - -DefineConstant[ - Flag_FrequencyDomain = 1, // frequency-domain or time-domain simulation - Flag_CircuitCoupling = 0 // consider coupling with external electric circuit - CoefPower = 0.5, // coefficient for power calculations - Freq = 50, // frequency (for harmonic simulations) - TimeInit = 0, // intial time (for time-domain simulations) - TimeFinal = 1/50, // final time (for time-domain simulations) - DeltaTime = 1/500, // time step (for time-domain simulations) - InterpolationOrder = 1 // finite element order - Val_Rint = 0, // interior radius of annulus shell transformation region (VolInf_Mag) - Val_Rext = 0 // exterior radius of annulus shell transformation region (VolInf_Mag) -]; - -Group { - DefineGroup[ - VolCC_Mag, // the non-conducting part - VolC_Mag, // the conducting part - VolV_Mag, // a moving conducting part, with invariant mesh - VolM_Mag, // permanent magnets - VolS0_Mag, // current source domain with imposed current densities js0 - VolS_Mag, // current source domain with imposed current, imposed voltage or - // circuit coupling - VolInf_Mag, // annulus where a infinite shell transformation is applied - SurFluxTube_Mag, // boundary with Neumann BC - SurPerfect_Mag, // boundary of perfect conductors (i.e. non-meshed) - SurImped_Mag // boundary of conductors approximated by a surface impedance - // (i.e. non-meshed) - ]; - If(Flag_CircuitCoupling) - DefineGroup[ - SourceV_Cir, // voltage sources - SourceI_Cir, // current sources - Resistance_Cir, // resistors (linear) - Inductance_Cir, // inductors - Capacitance_Cir, // capacitors - Diode_Cir // diodes (treated as nonlinear resistors) - ]; - EndIf -} - -Function { - DefineFunction[ - nu, // reluctivity (in Vol_Mag) - sigma, // conductivity (in VolC_Mag and VolS_Mag) - br, // remanent magnetic flux density (in VolM_Mag) - js0, // source current density (in VolS0_Mag) - nxh, // n x magnetic field (on SurFluxTube_Mag) - Velocity, // velocity of moving part VolV_Moving - Ns, // number of turns (in VolS_Mag) - Sc, // cross-section of windings (in VolS_Mag) - CoefGeos, // geometrical coefficient for 2D or 2D axi model - Ysur // surface admittance (inverse of surface impedance Zsur) on SurImped_Mag - ]; - If(Flag_CircuitCoupling) - DefineFunction[ - Resistance, // resistance values - Inductance, // inductance values - Capacitance // capacitance values - ]; - EndIf -} - -// End of definitions. - -Group{ - // all volumes - Vol_Mag = Region[ {VolCC_Mag, VolC_Mag, VolV_Mag, VolM_Mag, VolS0_Mag, VolS_Mag} ]; - // all volumes + surfaces on which integrals will be computed - VolWithSur_Mag = Region[ {Vol_Mag, SurFluxTube_Mag, SurPerfect_Mag, SurImped_Mag} ]; - If(Flag_CircuitCoupling) - // all circuit impedances - DomainZ_Cir = Region[ {Resistance_Cir, Inductance_Cir, Capacitance_Cir} ]; - // all circuit sources - DomainSource_Cir = Region[ {SourceV_Cir, SourceI_Cir} ]; - // all circuit elements - Domain_Cir = Region[ {DomainZ_Cir, DomainSource_Cir} ]; - EndIf -} - -Jacobian { - { Name Vol; - Case { - { Region VolInf_Mag ; - Jacobian VolSphShell {Val_Rint, Val_Rext} ; } - { Region All; Jacobian Vol; } - } - } - { Name Sur; - Case { - { Region All; Jacobian Sur; } - } - } -} - -Integration { - { Name Gauss_v; - Case { - { Type Gauss; - Case { - { GeoElement Point; NumberOfPoints 1; } - { GeoElement Line; NumberOfPoints 5; } - { GeoElement Triangle; NumberOfPoints 7; } - { GeoElement Quadrangle; NumberOfPoints 4; } - { GeoElement Tetrahedron; NumberOfPoints 15; } - { GeoElement Hexahedron; NumberOfPoints 14; } - { GeoElement Prism; NumberOfPoints 21; } - } - } - } - } -} - -// Same FunctionSpace for both static and dynamic formulations -FunctionSpace { - { Name Hcurl_a_2D; Type Form1P; // 1-form (circulations) on edges - // perpendicular to the plane of study - BasisFunction { - // \vec{a}(x) = \sum_{n \in N(Domain)} a_n \vec{s}_n(x) - // without nodes on perfect conductors (where a is constant) - { Name s_n; NameOfCoef a_n; Function BF_PerpendicularEdge; - Support VolWithSur_Mag; Entity NodesOf[All, Not SurPerfect_Mag]; } - - // global basis function on boundary of perfect conductors - { Name s_skin; NameOfCoef a_skin; Function BF_GroupOfPerpendicularEdges; - Support VolWithSur_Mag; Entity GroupsOfNodesOf[SurPerfect_Mag]; } - - // additional basis functions for 2nd order interpolation - If(InterpolationOrder == 2) - { Name s_e; NameOfCoef a_e; Function BF_PerpendicularEdge_2E; - Support Vol_Mag; Entity EdgesOf[All]; } - EndIf - } - GlobalQuantity { - { Name A; Type AliasOf; NameOfCoef a_skin; } - { Name I; Type AssociatedWith; NameOfCoef a_skin; } - } - Constraint { - { NameOfCoef a_n; - EntityType NodesOf; NameOfConstraint MagneticVectorPotential_2D; } - - { NameOfCoef I; - EntityType GroupsOfNodesOf; NameOfConstraint Current_2D; } - - If(InterpolationOrder == 2) - { NameOfCoef a_e; - EntityType EdgesOf; NameOfConstraint MagneticVectorPotential_2D_0; } - EndIf - } - } -} - -FunctionSpace { - // Gradient of Electric scalar potential (2D) - { Name Hregion_u_2D; Type Form1P; // same as for \vec{a} - BasisFunction { - { Name sr; NameOfCoef ur; Function BF_RegionZ; - // constant vector (over the region) with nonzero z-component only - Support Region[{VolC_Mag, SurImped_Mag}]; - Entity Region[{VolC_Mag, SurImped_Mag}]; } - } - GlobalQuantity { - { Name U; Type AliasOf; NameOfCoef ur; } - { Name I; Type AssociatedWith; NameOfCoef ur; } - } - Constraint { - { NameOfCoef U; - EntityType Region; NameOfConstraint Voltage_2D; } - { NameOfCoef I; - EntityType Region; NameOfConstraint Current_2D; } - } - } - - // Current in stranded coil (2D) - { Name Hregion_i_2D; Type Vector; - BasisFunction { - { Name sr; NameOfCoef ir; Function BF_RegionZ; - Support VolS_Mag; Entity VolS_Mag; } - } - GlobalQuantity { - { Name Is; Type AliasOf; NameOfCoef ir; } - { Name Us; Type AssociatedWith; NameOfCoef ir; } - } - Constraint { - { NameOfCoef Us; - EntityType Region; NameOfConstraint Voltage_2D; } - { NameOfCoef Is; - EntityType Region; NameOfConstraint Current_2D; } - } - } -} - -If(Flag_CircuitCoupling) - // UZ and IZ for impedances - FunctionSpace { - { Name Hregion_Z; Type Scalar; - BasisFunction { - { Name sr; NameOfCoef ir; Function BF_Region; - Support Domain_Cir; Entity Domain_Cir; } - } - GlobalQuantity { - { Name Iz; Type AliasOf; NameOfCoef ir; } - { Name Uz; Type AssociatedWith; NameOfCoef ir; } - } - Constraint { - { NameOfCoef Uz; - EntityType Region; NameOfConstraint Voltage_Cir; } - { NameOfCoef Iz; - EntityType Region; NameOfConstraint Current_Cir; } - } - } - } -EndIf - - -// Static Formulation -Formulation { - { Name MagSta_a_2D; Type FemEquation; - Quantity { - { Name a; Type Local; NameOfSpace Hcurl_a_2D; } - { Name ir; Type Local; NameOfSpace Hregion_i_2D; } - } - Equation { - Galerkin { [ nu[] * Dof{d a} , {d a} ]; - In Vol_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { [ -nu[] * br[] , {d a} ]; - In VolM_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { [ -js0[] , {a} ]; - In VolS0_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { [ - (js0[]*Vector[0,0,1]) * Dof{ir} , {a} ]; - In VolS_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { [ nxh[] , {a} ]; - In SurFluxTube_Mag; Jacobian Sur; Integration Gauss_v; } - } - } -} - -// Dynamic Formulation (eddy currents) -Formulation { - { Name MagDyn_a_2D; Type FemEquation; - Quantity { - { Name a; Type Local; NameOfSpace Hcurl_a_2D; } - { Name A_floating; Type Global; NameOfSpace Hcurl_a_2D [A]; } - { Name I_perfect; Type Global; NameOfSpace Hcurl_a_2D [I]; } - - { Name ur; Type Local; NameOfSpace Hregion_u_2D; } - { Name I; Type Global; NameOfSpace Hregion_u_2D [I]; } - { Name U; Type Global; NameOfSpace Hregion_u_2D [U]; } - - { Name ir; Type Local; NameOfSpace Hregion_i_2D; } - { Name Us; Type Global; NameOfSpace Hregion_i_2D [Us]; } - { Name Is; Type Global; NameOfSpace Hregion_i_2D [Is]; } - - If(Flag_CircuitCoupling) - { Name Uz; Type Global; NameOfSpace Hregion_Z [Uz]; } - { Name Iz; Type Global; NameOfSpace Hregion_Z [Iz]; } - EndIf - } - Equation { - Galerkin { [ nu[] * Dof{d a} , {d a} ]; - In Vol_Mag; Jacobian Vol; Integration Gauss_v; } - Galerkin { [ -nu[] * br[] , {d a} ]; - In VolM_Mag; Jacobian Vol; Integration Gauss_v; } - - // Electric field e = -Dt[{a}]-{ur}, - // with {ur} = Grad v constant in each region of VolC - Galerkin { DtDof [ sigma[] * Dof{a} , {a} ]; - In VolC_Mag; Jacobian Vol; Integration Gauss_v; } - Galerkin { [ sigma[] * Dof{ur} / CoefGeos[] , {a} ]; - In VolC_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { [ - sigma[] * (Velocity[] /\ Dof{d a}) , {a} ]; - In VolV_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { [ -js0[] , {a} ]; - In VolS0_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { [ nxh[] , {a} ]; - In SurFluxTube_Mag; Jacobian Sur; Integration Gauss_v; } - - Galerkin { DtDof [ Ysur[] * Dof{a} , {a} ]; - In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } - Galerkin { [ Ysur[] * Dof{ur} / CoefGeos[] , {a} ]; - In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } - - // When {ur} act as a test function, one obtains the circuits relations, - // relating the voltage and the current of each region in VolC - Galerkin { DtDof [ sigma[] * Dof{a} , {ur} ]; - In VolC_Mag; Jacobian Vol; Integration Gauss_v; } - Galerkin { [ sigma[] * Dof{ur} / CoefGeos[] , {ur} ]; - In VolC_Mag; Jacobian Vol; Integration Gauss_v; } - GlobalTerm { [ Dof{I} *(CoefGeos[]/Fabs[CoefGeos[]]) , {U} ]; In VolC_Mag; } - - Galerkin { DtDof [ Ysur[] * Dof{a} , {ur} ]; - In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } - Galerkin { [ Ysur[] * Dof{ur} / CoefGeos[] , {ur} ]; - In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } - GlobalTerm { [ Dof{I} *(CoefGeos[]/Fabs[CoefGeos[]]) , {U} ]; In SurImped_Mag; } - - // js[0] should be of the form: Ns[]/Sc[] * Vector[0,0,1] - Galerkin { [ - (js0[]*Vector[0,0,1]) * Dof{ir} , {a} ]; - In VolS_Mag; Jacobian Vol; Integration Gauss_v; } - - Galerkin { DtDof [ Ns[]/Sc[] * Dof{a} , {ir} ]; - In VolS_Mag; Jacobian Vol; Integration Gauss_v; } - Galerkin { [ Ns[]/Sc[] / sigma[] * (js0[]*Vector[0,0,1]) * Dof{ir} , {ir} ]; - In VolS_Mag; Jacobian Vol; Integration Gauss_v; } - GlobalTerm { [ Dof{Us} / CoefGeos[] , {Is} ]; In VolS_Mag; } - // Attention: CoefGeo[.] = 2*Pi for Axi - - GlobalTerm { [ -Dof{I_perfect} , {A_floating} ]; In SurPerfect_Mag; } - - If(Flag_CircuitCoupling) - GlobalTerm { NeverDt[ Dof{Uz} , {Iz} ]; In Resistance_Cir; } - GlobalTerm { NeverDt[ Resistance[] * Dof{Iz} , {Iz} ]; In Resistance_Cir; } - - GlobalTerm { [ Dof{Uz} , {Iz} ]; In Inductance_Cir; } - GlobalTerm { DtDof [ Inductance[] * Dof{Iz} , {Iz} ]; In Inductance_Cir; } - - GlobalTerm { NeverDt[ Dof{Iz} , {Iz} ]; In Capacitance_Cir; } - GlobalTerm { DtDof [ Capacitance[] * Dof{Uz} , {Iz} ]; In Capacitance_Cir; } - - GlobalTerm { NeverDt[ Dof{Uz} , {Iz} ]; In Diode_Cir; } - GlobalTerm { NeverDt[ Resistance[{Uz}] * Dof{Iz} , {Iz} ]; In Diode_Cir; } - - GlobalTerm { [ 0. * Dof{Iz} , {Iz} ]; In DomainSource_Cir; } - - GlobalEquation { - Type Network; NameOfConstraint ElectricalCircuit; - { Node {I}; Loop {U}; Equation {I}; In VolC_Mag; } - { Node {Is}; Loop {Us}; Equation {Us}; In VolS_Mag; } - { Node {Iz}; Loop {Uz}; Equation {Uz}; In Domain_Cir; } - } - EndIf - - } - } -} - -Resolution { - { Name MagDyn_a_2D; - System { - { Name Sys; NameOfFormulation MagDyn_a_2D; - If(Flag_FrequencyDomain) - Type ComplexValue; Frequency Freq; - EndIf - } - } - Operation { - If(Flag_FrequencyDomain) - Generate[Sys]; Solve[Sys]; SaveSolution[Sys]; - Else - InitSolution[Sys]; // provide initial condition - TimeLoopTheta[TimeInit, TimeFinal, DeltaTime, 1.]{ - // Euler implicit (1) -- Crank-Nicolson (0.5) - Generate[Sys]; Solve[Sys]; SaveSolution[Sys]; - } - EndIf - } - } - { Name MagSta_a_2D; - System { - { Name Sys; NameOfFormulation MagSta_a_2D; } - } - Operation { - Generate[Sys]; Solve[Sys]; SaveSolution[Sys]; - } - } -} - -// Same PostProcessing for both static and dynamic formulations (both refer to -// the same FunctionSpace from which the solution is obtained) -PostProcessing { - { Name MagDyn_a_2D; NameOfFormulation MagDyn_a_2D; - PostQuantity { - // In 2D, a is a vector with only a z-component: (0,0,az) - { Name a; Value { Term { [ {a} ]; In Vol_Mag; Jacobian Vol; } } } - // The equilines of az are field lines (giving the magnetic field direction) - { Name az; Value { Term { [ CompZ[{a}] ]; In Vol_Mag; Jacobian Vol; } } } - { Name b; Value { Term { [ {d a} ]; In Vol_Mag; Jacobian Vol; } } } - { Name h; Value { - Term { [ nu[] * {d a} ]; In Vol_Mag; Jacobian Vol; } - Term { [ -nu[] * br[] ]; In VolM_Mag; Jacobian Vol; } - } - } - { Name js; Value { - Term { [ js0[] ]; In VolS0_Mag; Jacobian Vol; } - Term { [ (js0[]*Vector[0,0,1])*{ir} ]; In VolS_Mag; Jacobian Vol; } - Term { [ Vector[0,0,0] ]; In Vol_Mag; Jacobian Vol; } // to force a vector result out of sources - } - } - { Name j; - // Only correct in MagDyn - Value { - Term { [ -sigma[] * (Dt[{a}]+{ur}/CoefGeos[]) ]; In VolC_Mag; Jacobian Vol; } - Term { [ js0[] ]; In VolS0_Mag; Jacobian Vol; } - Term { [ (js0[]*Vector[0,0,1])*{ir} ]; In VolS_Mag; Jacobian Vol; } - Term { [ Vector[0,0,0] ]; In Vol_Mag; Jacobian Vol; } - // Current density in A/m - Term { [ -Ysur[] * (Dt[{a}]+{ur}/CoefGeos[]) ]; In SurImped_Mag; Jacobian Sur; } - } - } - - { Name JouleLosses; - Value { - Integral { [ CoefPower * sigma[]*SquNorm[Dt[{a}]+{ur}/CoefGeos[]] ]; - In VolC_Mag; Jacobian Vol; Integration Gauss_v; } - Integral { [ CoefPower * 1./sigma[]*SquNorm[js0[]] ]; - In VolS0_Mag; Jacobian Vol; Integration Gauss_v; } - - Integral { [ CoefPower * 1./sigma[]*SquNorm[(js0[]*Vector[0,0,1])*{ir}] ]; - In VolS_Mag; Jacobian Vol; Integration Gauss_v; } - - Integral { [ CoefPower * Ysur[]*SquNorm[Dt[{a}]+{ur}/CoefGeos[]] ]; - In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } - } - } - - { Name U; Value { - Term { [ {U} ]; In VolC_Mag; } - Term { [ {Us} ]; In VolS_Mag; } - If(Flag_CircuitCoupling) - Term { [ {Uz} ]; In Domain_Cir; } - EndIf - } - } - - { Name I; Value { - Term { [ {I} ]; In VolC_Mag; } - Term { [ {Is} ]; In VolS_Mag; } - If(Flag_CircuitCoupling) - Term { [ {Iz} ]; In Domain_Cir; } - EndIf - } - } - - } - } - - { Name MagSta_a_2D; NameOfFormulation MagSta_a_2D; - PostQuantity { - // In 2D, a is a vector with only a z-component: (0,0,az) - { Name a; Value { Term { [ {a} ]; In Vol_Mag; Jacobian Vol; } } } - // The equilines of az are field lines (giving the magnetic field direction) - { Name az; Value { Term { [ CompZ[{a}] ]; In Vol_Mag; Jacobian Vol; } } } - { Name b; Value { Term { [ {d a} ]; In Vol_Mag; Jacobian Vol; } } } - { Name h; Value { Term { [ nu[] * {d a} ]; In Vol_Mag; Jacobian Vol; } } } - { Name j; - Value { - Term { [ js0[] ]; In VolS0_Mag; Jacobian Vol; } - Term { [ Vector[0,0,0] ]; In Vol_Mag; Jacobian Vol; } - } - } - } - } -} +// This is a template .pro file containing a general formulation for 2D +// magnetostatic and magnetodynamic problems in terms of the magnetic vector +// potential a (potentially coupled with the electric scalar potential v), with +// optional circuit coupling. + +// Below are definitions of the constants (inside "DefineConstant"), groups +// (inside "DefineGroup") and functions (inside "DefineFunction") that can be +// redefined from outside this template. + +DefineConstant[ + Flag_FrequencyDomain = 1, // frequency-domain or time-domain simulation + Flag_CircuitCoupling = 0 // consider coupling with external electric circuit + CoefPower = 0.5, // coefficient for power calculations + Freq = 50, // frequency (for harmonic simulations) + TimeInit = 0, // intial time (for time-domain simulations) + TimeFinal = 1/50, // final time (for time-domain simulations) + DeltaTime = 1/500, // time step (for time-domain simulations) + InterpolationOrder = 1 // finite element order + Val_Rint = 0, // interior radius of annulus shell transformation region (VolInf_Mag) + Val_Rext = 0 // exterior radius of annulus shell transformation region (VolInf_Mag) +]; + +Group { + DefineGroup[ + VolCC_Mag, // the non-conducting part + VolC_Mag, // the conducting part + VolV_Mag, // a moving conducting part, with invariant mesh + VolM_Mag, // permanent magnets + VolS0_Mag, // current source domain with imposed current densities js0 + VolS_Mag, // current source domain with imposed current, imposed voltage or + // circuit coupling + VolInf_Mag, // annulus where a infinite shell transformation is applied + SurFluxTube_Mag, // boundary with Neumann BC + SurPerfect_Mag, // boundary of perfect conductors (i.e. non-meshed) + SurImped_Mag // boundary of conductors approximated by a surface impedance + // (i.e. non-meshed) + ]; + If(Flag_CircuitCoupling) + DefineGroup[ + SourceV_Cir, // voltage sources + SourceI_Cir, // current sources + Resistance_Cir, // resistors (linear) + Inductance_Cir, // inductors + Capacitance_Cir, // capacitors + Diode_Cir // diodes (treated as nonlinear resistors) + ]; + EndIf +} + +Function { + DefineFunction[ + nu, // reluctivity (in Vol_Mag) + sigma, // conductivity (in VolC_Mag and VolS_Mag) + br, // remanent magnetic flux density (in VolM_Mag) + js0, // source current density (in VolS0_Mag) + nxh, // n x magnetic field (on SurFluxTube_Mag) + Velocity, // velocity of moving part VolV_Moving + Ns, // number of turns (in VolS_Mag) + Sc, // cross-section of windings (in VolS_Mag) + CoefGeos, // geometrical coefficient for 2D or 2D axi model + Ysur // surface admittance (inverse of surface impedance Zsur) on SurImped_Mag + ]; + If(Flag_CircuitCoupling) + DefineFunction[ + Resistance, // resistance values + Inductance, // inductance values + Capacitance // capacitance values + ]; + EndIf +} + +// End of definitions. + +Group{ + // all volumes + Vol_Mag = Region[ {VolCC_Mag, VolC_Mag, VolV_Mag, VolM_Mag, VolS0_Mag, VolS_Mag} ]; + // all volumes + surfaces on which integrals will be computed + VolWithSur_Mag = Region[ {Vol_Mag, SurFluxTube_Mag, SurPerfect_Mag, SurImped_Mag} ]; + If(Flag_CircuitCoupling) + // all circuit impedances + DomainZ_Cir = Region[ {Resistance_Cir, Inductance_Cir, Capacitance_Cir} ]; + // all circuit sources + DomainSource_Cir = Region[ {SourceV_Cir, SourceI_Cir} ]; + // all circuit elements + Domain_Cir = Region[ {DomainZ_Cir, DomainSource_Cir} ]; + EndIf +} + +Jacobian { + { Name Vol; + Case { + { Region VolInf_Mag ; + Jacobian VolSphShell {Val_Rint, Val_Rext} ; } + { Region All; Jacobian Vol; } + } + } + { Name Sur; + Case { + { Region All; Jacobian Sur; } + } + } +} + +Integration { + { Name Gauss_v; + Case { + { Type Gauss; + Case { + { GeoElement Point; NumberOfPoints 1; } + { GeoElement Line; NumberOfPoints 5; } + { GeoElement Triangle; NumberOfPoints 7; } + { GeoElement Quadrangle; NumberOfPoints 4; } + { GeoElement Tetrahedron; NumberOfPoints 15; } + { GeoElement Hexahedron; NumberOfPoints 14; } + { GeoElement Prism; NumberOfPoints 21; } + } + } + } + } +} + +// Same FunctionSpace for both static and dynamic formulations +FunctionSpace { + { Name Hcurl_a_2D; Type Form1P; // 1-form (circulations) on edges + // perpendicular to the plane of study + BasisFunction { + // \vec{a}(x) = \sum_{n \in N(Domain)} a_n \vec{s}_n(x) + // without nodes on perfect conductors (where a is constant) + { Name s_n; NameOfCoef a_n; Function BF_PerpendicularEdge; + Support VolWithSur_Mag; Entity NodesOf[All, Not SurPerfect_Mag]; } + + // global basis function on boundary of perfect conductors + { Name s_skin; NameOfCoef a_skin; Function BF_GroupOfPerpendicularEdges; + Support VolWithSur_Mag; Entity GroupsOfNodesOf[SurPerfect_Mag]; } + + // additional basis functions for 2nd order interpolation + If(InterpolationOrder == 2) + { Name s_e; NameOfCoef a_e; Function BF_PerpendicularEdge_2E; + Support Vol_Mag; Entity EdgesOf[All]; } + EndIf + } + GlobalQuantity { + { Name A; Type AliasOf; NameOfCoef a_skin; } + { Name I; Type AssociatedWith; NameOfCoef a_skin; } + } + Constraint { + { NameOfCoef a_n; + EntityType NodesOf; NameOfConstraint MagneticVectorPotential_2D; } + + { NameOfCoef I; + EntityType GroupsOfNodesOf; NameOfConstraint Current_2D; } + + If(InterpolationOrder == 2) + { NameOfCoef a_e; + EntityType EdgesOf; NameOfConstraint MagneticVectorPotential_2D_0; } + EndIf + } + } +} + +FunctionSpace { + // Gradient of Electric scalar potential (2D) + { Name Hregion_u_2D; Type Form1P; // same as for \vec{a} + BasisFunction { + { Name sr; NameOfCoef ur; Function BF_RegionZ; + // constant vector (over the region) with nonzero z-component only + Support Region[{VolC_Mag, SurImped_Mag}]; + Entity Region[{VolC_Mag, SurImped_Mag}]; } + } + GlobalQuantity { + { Name U; Type AliasOf; NameOfCoef ur; } + { Name I; Type AssociatedWith; NameOfCoef ur; } + } + Constraint { + { NameOfCoef U; + EntityType Region; NameOfConstraint Voltage_2D; } + { NameOfCoef I; + EntityType Region; NameOfConstraint Current_2D; } + } + } + + // Current in stranded coil (2D) + { Name Hregion_i_2D; Type Vector; + BasisFunction { + { Name sr; NameOfCoef ir; Function BF_RegionZ; + Support VolS_Mag; Entity VolS_Mag; } + } + GlobalQuantity { + { Name Is; Type AliasOf; NameOfCoef ir; } + { Name Us; Type AssociatedWith; NameOfCoef ir; } + } + Constraint { + { NameOfCoef Us; + EntityType Region; NameOfConstraint Voltage_2D; } + { NameOfCoef Is; + EntityType Region; NameOfConstraint Current_2D; } + } + } +} + +If(Flag_CircuitCoupling) + // UZ and IZ for impedances + FunctionSpace { + { Name Hregion_Z; Type Scalar; + BasisFunction { + { Name sr; NameOfCoef ir; Function BF_Region; + Support Domain_Cir; Entity Domain_Cir; } + } + GlobalQuantity { + { Name Iz; Type AliasOf; NameOfCoef ir; } + { Name Uz; Type AssociatedWith; NameOfCoef ir; } + } + Constraint { + { NameOfCoef Uz; + EntityType Region; NameOfConstraint Voltage_Cir; } + { NameOfCoef Iz; + EntityType Region; NameOfConstraint Current_Cir; } + } + } + } +EndIf + + +// Static Formulation +Formulation { + { Name MagSta_a_2D; Type FemEquation; + Quantity { + { Name a; Type Local; NameOfSpace Hcurl_a_2D; } + { Name ir; Type Local; NameOfSpace Hregion_i_2D; } + } + Equation { + Integral { [ nu[] * Dof{d a} , {d a} ]; + In Vol_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ -nu[] * br[] , {d a} ]; + In VolM_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ -js0[] , {a} ]; + In VolS0_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ - (js0[]*Vector[0,0,1]) * Dof{ir} , {a} ]; + In VolS_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ nxh[] , {a} ]; + In SurFluxTube_Mag; Jacobian Sur; Integration Gauss_v; } + } + } +} + +// Dynamic Formulation (eddy currents) +Formulation { + { Name MagDyn_a_2D; Type FemEquation; + Quantity { + { Name a; Type Local; NameOfSpace Hcurl_a_2D; } + { Name A_floating; Type Global; NameOfSpace Hcurl_a_2D [A]; } + { Name I_perfect; Type Global; NameOfSpace Hcurl_a_2D [I]; } + + { Name ur; Type Local; NameOfSpace Hregion_u_2D; } + { Name I; Type Global; NameOfSpace Hregion_u_2D [I]; } + { Name U; Type Global; NameOfSpace Hregion_u_2D [U]; } + + { Name ir; Type Local; NameOfSpace Hregion_i_2D; } + { Name Us; Type Global; NameOfSpace Hregion_i_2D [Us]; } + { Name Is; Type Global; NameOfSpace Hregion_i_2D [Is]; } + + If(Flag_CircuitCoupling) + { Name Uz; Type Global; NameOfSpace Hregion_Z [Uz]; } + { Name Iz; Type Global; NameOfSpace Hregion_Z [Iz]; } + EndIf + } + Equation { + Integral { [ nu[] * Dof{d a} , {d a} ]; + In Vol_Mag; Jacobian Vol; Integration Gauss_v; } + Integral { [ -nu[] * br[] , {d a} ]; + In VolM_Mag; Jacobian Vol; Integration Gauss_v; } + + // Electric field e = -Dt[{a}]-{ur}, + // with {ur} = Grad v constant in each region of VolC + Integral { DtDof [ sigma[] * Dof{a} , {a} ]; + In VolC_Mag; Jacobian Vol; Integration Gauss_v; } + Integral { [ sigma[] * Dof{ur} / CoefGeos[] , {a} ]; + In VolC_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ - sigma[] * (Velocity[] /\ Dof{d a}) , {a} ]; + In VolV_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ -js0[] , {a} ]; + In VolS0_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ nxh[] , {a} ]; + In SurFluxTube_Mag; Jacobian Sur; Integration Gauss_v; } + + Integral { DtDof [ Ysur[] * Dof{a} , {a} ]; + In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } + Integral { [ Ysur[] * Dof{ur} / CoefGeos[] , {a} ]; + In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } + + // When {ur} act as a test function, one obtains the circuits relations, + // relating the voltage and the current of each region in VolC + Integral { DtDof [ sigma[] * Dof{a} , {ur} ]; + In VolC_Mag; Jacobian Vol; Integration Gauss_v; } + Integral { [ sigma[] * Dof{ur} / CoefGeos[] , {ur} ]; + In VolC_Mag; Jacobian Vol; Integration Gauss_v; } + GlobalTerm { [ Dof{I} *(CoefGeos[]/Fabs[CoefGeos[]]) , {U} ]; In VolC_Mag; } + + Integral { DtDof [ Ysur[] * Dof{a} , {ur} ]; + In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } + Integral { [ Ysur[] * Dof{ur} / CoefGeos[] , {ur} ]; + In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } + GlobalTerm { [ Dof{I} *(CoefGeos[]/Fabs[CoefGeos[]]) , {U} ]; In SurImped_Mag; } + + // js[0] should be of the form: Ns[]/Sc[] * Vector[0,0,1] + Integral { [ - (js0[]*Vector[0,0,1]) * Dof{ir} , {a} ]; + In VolS_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { DtDof [ Ns[]/Sc[] * Dof{a} , {ir} ]; + In VolS_Mag; Jacobian Vol; Integration Gauss_v; } + Integral { [ Ns[]/Sc[] / sigma[] * (js0[]*Vector[0,0,1]) * Dof{ir} , {ir} ]; + In VolS_Mag; Jacobian Vol; Integration Gauss_v; } + GlobalTerm { [ Dof{Us} / CoefGeos[] , {Is} ]; In VolS_Mag; } + // Attention: CoefGeo[.] = 2*Pi for Axi + + GlobalTerm { [ -Dof{I_perfect} , {A_floating} ]; In SurPerfect_Mag; } + + If(Flag_CircuitCoupling) + GlobalTerm { NeverDt[ Dof{Uz} , {Iz} ]; In Resistance_Cir; } + GlobalTerm { NeverDt[ Resistance[] * Dof{Iz} , {Iz} ]; In Resistance_Cir; } + + GlobalTerm { [ Dof{Uz} , {Iz} ]; In Inductance_Cir; } + GlobalTerm { DtDof [ Inductance[] * Dof{Iz} , {Iz} ]; In Inductance_Cir; } + + GlobalTerm { NeverDt[ Dof{Iz} , {Iz} ]; In Capacitance_Cir; } + GlobalTerm { DtDof [ Capacitance[] * Dof{Uz} , {Iz} ]; In Capacitance_Cir; } + + GlobalTerm { NeverDt[ Dof{Uz} , {Iz} ]; In Diode_Cir; } + GlobalTerm { NeverDt[ Resistance[{Uz}] * Dof{Iz} , {Iz} ]; In Diode_Cir; } + + GlobalTerm { [ 0. * Dof{Iz} , {Iz} ]; In DomainSource_Cir; } + + GlobalEquation { + Type Network; NameOfConstraint ElectricalCircuit; + { Node {I}; Loop {U}; Equation {I}; In VolC_Mag; } + { Node {Is}; Loop {Us}; Equation {Us}; In VolS_Mag; } + { Node {Iz}; Loop {Uz}; Equation {Uz}; In Domain_Cir; } + } + EndIf + + } + } +} + +Resolution { + { Name MagDyn_a_2D; + System { + { Name Sys; NameOfFormulation MagDyn_a_2D; + If(Flag_FrequencyDomain) + Type ComplexValue; Frequency Freq; + EndIf + } + } + Operation { + If(Flag_FrequencyDomain) + Generate[Sys]; Solve[Sys]; SaveSolution[Sys]; + Else + InitSolution[Sys]; // provide initial condition + TimeLoopTheta[TimeInit, TimeFinal, DeltaTime, 1.]{ + // Euler implicit (1) -- Crank-Nicolson (0.5) + Generate[Sys]; Solve[Sys]; SaveSolution[Sys]; + } + EndIf + } + } + { Name MagSta_a_2D; + System { + { Name Sys; NameOfFormulation MagSta_a_2D; } + } + Operation { + Generate[Sys]; Solve[Sys]; SaveSolution[Sys]; + } + } +} + +// Same PostProcessing for both static and dynamic formulations (both refer to +// the same FunctionSpace from which the solution is obtained) +PostProcessing { + { Name MagDyn_a_2D; NameOfFormulation MagDyn_a_2D; + PostQuantity { + // In 2D, a is a vector with only a z-component: (0,0,az) + { Name a; Value { Term { [ {a} ]; In Vol_Mag; Jacobian Vol; } } } + // The equilines of az are field lines (giving the magnetic field direction) + { Name az; Value { Term { [ CompZ[{a}] ]; In Vol_Mag; Jacobian Vol; } } } + { Name b; Value { Term { [ {d a} ]; In Vol_Mag; Jacobian Vol; } } } + { Name h; Value { + Term { [ nu[] * {d a} ]; In Vol_Mag; Jacobian Vol; } + Term { [ -nu[] * br[] ]; In VolM_Mag; Jacobian Vol; } + } + } + { Name js; Value { + Term { [ js0[] ]; In VolS0_Mag; Jacobian Vol; } + Term { [ (js0[]*Vector[0,0,1])*{ir} ]; In VolS_Mag; Jacobian Vol; } + Term { [ Vector[0,0,0] ]; In Vol_Mag; Jacobian Vol; } // to force a vector result out of sources + } + } + { Name j; + // Only correct in MagDyn + Value { + Term { [ -sigma[] * (Dt[{a}]+{ur}/CoefGeos[]) ]; In VolC_Mag; Jacobian Vol; } + Term { [ js0[] ]; In VolS0_Mag; Jacobian Vol; } + Term { [ (js0[]*Vector[0,0,1])*{ir} ]; In VolS_Mag; Jacobian Vol; } + Term { [ Vector[0,0,0] ]; In Vol_Mag; Jacobian Vol; } + // Current density in A/m + Term { [ -Ysur[] * (Dt[{a}]+{ur}/CoefGeos[]) ]; In SurImped_Mag; Jacobian Sur; } + } + } + + { Name JouleLosses; + Value { + Integral { [ CoefPower * sigma[]*SquNorm[Dt[{a}]+{ur}/CoefGeos[]] ]; + In VolC_Mag; Jacobian Vol; Integration Gauss_v; } + Integral { [ CoefPower * 1./sigma[]*SquNorm[js0[]] ]; + In VolS0_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ CoefPower * 1./sigma[]*SquNorm[(js0[]*Vector[0,0,1])*{ir}] ]; + In VolS_Mag; Jacobian Vol; Integration Gauss_v; } + + Integral { [ CoefPower * Ysur[]*SquNorm[Dt[{a}]+{ur}/CoefGeos[]] ]; + In SurImped_Mag; Jacobian Sur; Integration Gauss_v; } + } + } + + { Name U; Value { + Term { [ {U} ]; In VolC_Mag; } + Term { [ {Us} ]; In VolS_Mag; } + If(Flag_CircuitCoupling) + Term { [ {Uz} ]; In Domain_Cir; } + EndIf + } + } + + { Name I; Value { + Term { [ {I} ]; In VolC_Mag; } + Term { [ {Is} ]; In VolS_Mag; } + If(Flag_CircuitCoupling) + Term { [ {Iz} ]; In Domain_Cir; } + EndIf + } + } + + } + } + + { Name MagSta_a_2D; NameOfFormulation MagSta_a_2D; + PostQuantity { + // In 2D, a is a vector with only a z-component: (0,0,az) + { Name a; Value { Term { [ {a} ]; In Vol_Mag; Jacobian Vol; } } } + // The equilines of az are field lines (giving the magnetic field direction) + { Name az; Value { Term { [ CompZ[{a}] ]; In Vol_Mag; Jacobian Vol; } } } + { Name b; Value { Term { [ {d a} ]; In Vol_Mag; Jacobian Vol; } } } + { Name h; Value { Term { [ nu[] * {d a} ]; In Vol_Mag; Jacobian Vol; } } } + { Name j; + Value { + Term { [ js0[] ]; In VolS0_Mag; Jacobian Vol; } + Term { [ Vector[0,0,0] ]; In Vol_Mag; Jacobian Vol; } + } + } + } + } +} diff --git a/Magnetodynamics/electromagnet.geo b/Magnetodynamics/electromagnet.geo index 7bd410c..b24c084 100644 --- a/Magnetodynamics/electromagnet.geo +++ b/Magnetodynamics/electromagnet.geo @@ -1,54 +1,54 @@ -/* ------------------------------------------------------------------- - File "electromagnet.geo" - - This file is the geometrical description used by GMSH to produce - the file "electromagnet.msh". - ------------------------------------------------------------------- */ - -dxCore = 50.e-3; dyCore = 100.e-3; -xInd = 75.e-3; dxInd = 25.e-3; dyInd = 50.e-3; - -Include "electromagnet_common.pro"; - -s = DefineNumber[1, Name "Model parameters/Global mesh size", - Help "Reduce for finer mesh"]; -p0 = 12.e-3 *s; -pCorex = 4.e-3 *s; pCorey0 = 8.e-3 *s; pCorey = 4.e-3 *s; -pIndx = 5.e-3 *s; pIndy = 5.e-3 *s; -pInt = 12.5e-3*s; pExt = 12.5e-3*s; - -Point(1) = {0,0,0,p0}; -Point(2) = {dxCore,0,0,pCorex}; -Point(3) = {dxCore,dyCore,0,pCorey}; -Point(4) = {0,dyCore,0,pCorey0}; -Point(5) = {xInd,0,0,pIndx}; -Point(6) = {xInd+dxInd,0,0,pIndx}; -Point(7) = {xInd+dxInd,dyInd,0,pIndy}; -Point(8) = {xInd,dyInd,0,pIndy}; -Point(9) = {rInt,0,0,pInt}; -Point(10) = {rExt,0,0,pExt}; -Point(11) = {0,rInt,0,pInt}; -Point(12) = {0,rExt,0,pExt}; - -Line(1) = {1,2}; Line(2) = {2,5}; Line(3) = {5,6}; -Line(4) = {6,9}; Line(5) = {9,10}; Line(6) = {1,4}; -Line(7) = {4,11}; Line(8) = {11,12}; Line(9) = {2,3}; -Line(10) = {3,4}; Line(11) = {6,7}; Line(12) = {7,8}; -Line(13) = {8,5}; - -Circle(14) = {9,1,11}; Circle(15) = {10,1,12}; - -Line Loop(16) = {-6,1,9,10}; Plane Surface(17) = {16}; -Line Loop(18) = {11,12,13,3}; Plane Surface(19) = {18}; -Line Loop(20) = {7,-14,-4,11,12,13,-2,9,10}; Plane Surface(21) = {-20}; // "-" for orientation -Line Loop(22) = {8,-15,-5,14}; Plane Surface(23) = {-22}; - -Physical Surface(101) = {21}; /* Air */ -Physical Surface(102) = {17}; /* Core */ -Physical Surface(103) = {19}; /* Ind */ -Physical Surface(111) = {23}; /* AirInf */ - -Physical Line(1100) = {1,2,3,4,5}; /* Surface ht = 0 */ -Physical Line(1101) = {6,7,8}; /* Surface bn = 0 */ -Physical Line(1102) = {15}; /* Surface Inf */ - +/* ------------------------------------------------------------------- + File "electromagnet.geo" + + This file is the geometrical description used by GMSH to produce + the file "electromagnet.msh". + ------------------------------------------------------------------- */ + +dxCore = 50.e-3; dyCore = 100.e-3; +xInd = 75.e-3; dxInd = 25.e-3; dyInd = 50.e-3; + +Include "electromagnet_common.pro"; + +s = DefineNumber[1, Name "Model parameters/Global mesh size", + Help "Reduce for finer mesh"]; +p0 = 12.e-3 *s; +pCorex = 4.e-3 *s; pCorey0 = 8.e-3 *s; pCorey = 4.e-3 *s; +pIndx = 5.e-3 *s; pIndy = 5.e-3 *s; +pInt = 12.5e-3*s; pExt = 12.5e-3*s; + +Point(1) = {0,0,0,p0}; +Point(2) = {dxCore,0,0,pCorex}; +Point(3) = {dxCore,dyCore,0,pCorey}; +Point(4) = {0,dyCore,0,pCorey0}; +Point(5) = {xInd,0,0,pIndx}; +Point(6) = {xInd+dxInd,0,0,pIndx}; +Point(7) = {xInd+dxInd,dyInd,0,pIndy}; +Point(8) = {xInd,dyInd,0,pIndy}; +Point(9) = {rInt,0,0,pInt}; +Point(10) = {rExt,0,0,pExt}; +Point(11) = {0,rInt,0,pInt}; +Point(12) = {0,rExt,0,pExt}; + +Line(1) = {1,2}; Line(2) = {2,5}; Line(3) = {5,6}; +Line(4) = {6,9}; Line(5) = {9,10}; Line(6) = {1,4}; +Line(7) = {4,11}; Line(8) = {11,12}; Line(9) = {2,3}; +Line(10) = {3,4}; Line(11) = {6,7}; Line(12) = {7,8}; +Line(13) = {8,5}; + +Circle(14) = {9,1,11}; Circle(15) = {10,1,12}; + +Line Loop(16) = {-6,1,9,10}; Plane Surface(17) = {16}; +Line Loop(18) = {11,12,13,3}; Plane Surface(19) = {18}; +Line Loop(20) = {7,-14,-4,11,12,13,-2,9,10}; Plane Surface(21) = {-20}; // "-" for orientation +Line Loop(22) = {8,-15,-5,14}; Plane Surface(23) = {-22}; + +Physical Surface(101) = {21}; /* Air */ +Physical Surface(102) = {17}; /* Core */ +Physical Surface(103) = {19}; /* Ind */ +Physical Surface(111) = {23}; /* AirInf */ + +Physical Line(1100) = {1,2,3,4,5}; /* Surface ht = 0 */ +Physical Line(1101) = {6,7,8}; /* Surface bn = 0 */ +Physical Line(1102) = {15}; /* Surface Inf */ + diff --git a/Magnetodynamics/electromagnet.pro b/Magnetodynamics/electromagnet.pro index 7cf6322..1daf5af 100644 --- a/Magnetodynamics/electromagnet.pro +++ b/Magnetodynamics/electromagnet.pro @@ -1,89 +1,89 @@ -/* ------------------------------------------------------------------- - Tutorial 7a : magnetic fields of an electromagnet - - Features: - - Use of a template formulation library - - Identical to Tutorial 2 for a static current source - - Frequency-domain solution (phasor) for a dynamic current source - - To compute the static solution in a terminal: - getdp electromagnet -solve MagSta_a_2D -pos Map_a - - To compute the time-harmonic dynamic solution in a terminal: - getdp electromagnet -solve MagDyn_a_2D -pos Map_a - - To compute the solution interactively from the Gmsh GUI: - File > Open > electromagnet.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -Include "electromagnet_common.pro"; - -Group { - // Physical regions - Air = Region[ 101 ]; Core = Region[ 102 ]; - Ind = Region[ 103 ]; AirInf = Region[ 111 ]; - Surface_ht0 = Region[ 1100 ]; - Surface_bn0 = Region[ 1101 ]; - Surface_Inf = Region[ 1102 ]; - - // Abstract regions used in the "Lib_MagStaDyn_av_2D_Cir.pro" template file - // that is included below: - VolCC_Mag = Region[{Air, AirInf}]; // Non-conducting regions - VolC_Mag = Region[{Core}]; // Massive conducting regions - VolS_Mag = Region[{Ind}]; // Stranded conductors, i.e., coils - VolInf_Mag = Region[{AirInf}]; // Annulus for infinite shell transformation - Val_Rint = rInt; Val_Rext = rExt; // Interior and exterior radii of annulus -} - -Function { - DefineConstant[ - murCore = {100, Name "Model parameters/Mur core"}, - Current = {0.01, Name "Model parameters/Current"} - ]; - - mu0 = 4.e-7 * Pi; - nu[ Region[{Air, Ind, AirInf}] ] = 1. / mu0; - nu[ Core ] = 1. / (murCore * mu0); - - sigma[ Core ] = 1e6 / 10; - sigma[ Ind ] = 5e7; - - Ns[ Ind ] = 1000 ; // number of turns in coil - Sc[ Ind ] = SurfaceArea[] ; // surface (cross section) of coil - // Current density in each coil portion for a unit current (will be multiplied - // by the actual total current in the coil) - js0[ Ind ] = Ns[]/Sc[] * Vector[0,0,-1]; - CoefGeos[] = 1; -} - -Constraint { - { Name MagneticVectorPotential_2D; - Case { - { Region Surface_bn0; Value 0; } - { Region Surface_Inf; Value 0; } - } - } - { Name Current_2D; - Case { - // represents the phasor amplitude for a dynamic analysis - { Region Ind; Value Current; } - } - } - { Name Voltage_2D; - Case { - { Region Core; Value 0; } - } - } -} - -Include "Lib_MagStaDyn_av_2D_Cir.pro"; - -PostOperation { - { Name Map_a; NameOfPostProcessing MagDyn_a_2D; - Operation { - Print[ a, OnElementsOf Vol_Mag, File "a.pos" ]; - Print[ b, OnElementsOf Vol_Mag, File "b.pos" ]; - } - } -} +/* ------------------------------------------------------------------- + Tutorial 7a : magnetic fields of an electromagnet + + Features: + - Use of a template formulation library + - Identical to Tutorial 2 for a static current source + - Frequency-domain solution (phasor) for a dynamic current source + + To compute the static solution in a terminal: + getdp electromagnet -solve MagSta_a_2D -pos Map_a + + To compute the time-harmonic dynamic solution in a terminal: + getdp electromagnet -solve MagDyn_a_2D -pos Map_a + + To compute the solution interactively from the Gmsh GUI: + File > Open > electromagnet.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +Include "electromagnet_common.pro"; + +Group { + // Physical regions + Air = Region[ 101 ]; Core = Region[ 102 ]; + Ind = Region[ 103 ]; AirInf = Region[ 111 ]; + Surface_ht0 = Region[ 1100 ]; + Surface_bn0 = Region[ 1101 ]; + Surface_Inf = Region[ 1102 ]; + + // Abstract regions used in the "Lib_MagStaDyn_av_2D_Cir.pro" template file + // that is included below: + VolCC_Mag = Region[{Air, AirInf}]; // Non-conducting regions + VolC_Mag = Region[{Core}]; // Massive conducting regions + VolS_Mag = Region[{Ind}]; // Stranded conductors, i.e., coils + VolInf_Mag = Region[{AirInf}]; // Annulus for infinite shell transformation + Val_Rint = rInt; Val_Rext = rExt; // Interior and exterior radii of annulus +} + +Function { + DefineConstant[ + murCore = {100, Name "Model parameters/Mur core"}, + Current = {0.01, Name "Model parameters/Current"} + ]; + + mu0 = 4.e-7 * Pi; + nu[ Region[{Air, Ind, AirInf}] ] = 1. / mu0; + nu[ Core ] = 1. / (murCore * mu0); + + sigma[ Core ] = 1e6 / 10; + sigma[ Ind ] = 5e7; + + Ns[ Ind ] = 1000 ; // number of turns in coil + Sc[ Ind ] = SurfaceArea[] ; // surface (cross section) of coil + // Current density in each coil portion for a unit current (will be multiplied + // by the actual total current in the coil) + js0[ Ind ] = Ns[]/Sc[] * Vector[0,0,-1]; + CoefGeos[] = 1; +} + +Constraint { + { Name MagneticVectorPotential_2D; + Case { + { Region Surface_bn0; Value 0; } + { Region Surface_Inf; Value 0; } + } + } + { Name Current_2D; + Case { + // represents the phasor amplitude for a dynamic analysis + { Region Ind; Value Current; } + } + } + { Name Voltage_2D; + Case { + { Region Core; Value 0; } + } + } +} + +Include "Lib_MagStaDyn_av_2D_Cir.pro"; + +PostOperation { + { Name Map_a; NameOfPostProcessing MagDyn_a_2D; + Operation { + Print[ a, OnElementsOf Vol_Mag, File "a.pos" ]; + Print[ b, OnElementsOf Vol_Mag, File "b.pos" ]; + } + } +} diff --git a/Magnetodynamics/electromagnet_common.pro b/Magnetodynamics/electromagnet_common.pro index 56879cd..f0dd285 100644 --- a/Magnetodynamics/electromagnet_common.pro +++ b/Magnetodynamics/electromagnet_common.pro @@ -1,4 +1,4 @@ -// Parameters shared by Gmsh and GetDP - -rInt = 200.e-3; -rExt = 250.e-3; +// Parameters shared by Gmsh and GetDP + +rInt = 200.e-3; +rExt = 250.e-3; diff --git a/Magnetodynamics/transfo.geo b/Magnetodynamics/transfo.geo index 072bc9b..6243d4b 100644 --- a/Magnetodynamics/transfo.geo +++ b/Magnetodynamics/transfo.geo @@ -1,173 +1,173 @@ - -Include "transfo_common.pro"; - -Solver.AutoShowLastStep = 0; // don't automatically show the last time step - -// CORE - -p_Leg_1_L_0=newp; Point(newp) = {-width_Core/2., 0, 0, c_Core}; -p_Leg_1_R_0=newp; Point(newp) = {-width_Core/2.+width_Core_Leg, 0, 0, c_Core}; - -p_Leg_1_L_1=newp; Point(newp) = {-width_Core/2., height_Core/2., 0, c_Core}; -p_Leg_1_R_1=newp; Point(newp) = {-width_Core/2.+width_Core_Leg, height_Core/2.-width_Core_Leg, 0, c_Core}; - - -p_Leg_2_L_0=newp; Point(newp) = {width_Core/2.-width_Core_Leg, 0, 0, c_Core}; -p_Leg_2_R_0=newp; Point(newp) = {width_Core/2., 0, 0, c_Core}; - -p_Leg_2_L_1=newp; Point(newp) = {width_Core/2.-width_Core_Leg, height_Core/2.-width_Core_Leg, 0, c_Core}; -p_Leg_2_R_1=newp; Point(newp) = {width_Core/2., height_Core/2., 0, c_Core}; - - -l_Core_In[]={}; -l_Core_In[]+=newl; Line(newl) = {p_Leg_1_R_0, p_Leg_1_R_1}; -l_Core_In[]+=newl; Line(newl) = {p_Leg_1_R_1, p_Leg_2_L_1}; -l_Core_In[]+=newl; Line(newl) = {p_Leg_2_L_1, p_Leg_2_L_0}; - -l_Core_Out[]={}; -l_Core_Out[]+=newl; Line(newl) = {p_Leg_2_R_0, p_Leg_2_R_1}; -l_Core_Out[]+=newl; Line(newl) = {p_Leg_2_R_1, p_Leg_1_L_1}; -l_Core_Out[]+=newl; Line(newl) = {p_Leg_1_L_1, p_Leg_1_L_0}; - -l_Core_Leg_1_Y0[]={}; -l_Core_Leg_1_Y0[]+=newl; Line(newl) = {p_Leg_1_L_0, p_Leg_1_R_0}; - -l_Core_Leg_2_Y0[]={}; -l_Core_Leg_2_Y0[]+=newl; Line(newl) = {p_Leg_2_L_0, p_Leg_2_R_0}; - - -ll_Core=newll; Line Loop(newll) = {l_Core_In[], l_Core_Leg_2_Y0[], l_Core_Out[], l_Core_Leg_1_Y0[]}; -s_Core=news; Plane Surface(news) = {ll_Core}; - -Physical Surface("CORE", CORE) = {s_Core}; - -// COIL_1_PLUS - -x_[]=Point{p_Leg_1_R_0}; -p_Coil_1_p_int_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_1, 0, 0, c_Coil_1}; -p_Coil_1_p_ext_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_1+width_Coil_1, 0, 0, c_Coil_1}; -p_Coil_1_p_int_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_1, height_Coil_1/2, 0, c_Coil_1}; -p_Coil_1_p_ext_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_1+width_Coil_1, height_Coil_1/2, 0, c_Coil_1}; - -l_Coil_1_p[]={}; -l_Coil_1_p[]+=newl; Line(newl) = {p_Coil_1_p_ext_0, p_Coil_1_p_ext_1}; -l_Coil_1_p[]+=newl; Line(newl) = {p_Coil_1_p_ext_1, p_Coil_1_p_int_1}; -l_Coil_1_p[]+=newl; Line(newl) = {p_Coil_1_p_int_1, p_Coil_1_p_int_0}; - -l_Coil_1_p_Y0[]={}; -l_Coil_1_p_Y0[]+=newl; Line(newl) = {p_Coil_1_p_int_0, p_Coil_1_p_ext_0}; - -ll_Coil_1_p=newll; Line Loop(newll) = {l_Coil_1_p[], l_Coil_1_p_Y0[]}; -s_Coil_1_p=news; Plane Surface(news) = {ll_Coil_1_p}; - -Physical Surface("COIL_1_PLUS", COIL_1_PLUS) = {s_Coil_1_p}; - - -// COIL_1_MINUS - -x_[]=Point{p_Leg_1_L_0}; -p_Coil_1_m_int_0=newp; Point(newp) = {x_[0]-gap_Core_Coil_1, 0, 0, c_Coil_1}; -p_Coil_1_m_ext_0=newp; Point(newp) = {x_[0]-(gap_Core_Coil_1+width_Coil_1), 0, 0, c_Coil_1}; -p_Coil_1_m_int_1=newp; Point(newp) = {x_[0]-gap_Core_Coil_1, height_Coil_1/2, 0, c_Coil_1}; -p_Coil_1_m_ext_1=newp; Point(newp) = {x_[0]-(gap_Core_Coil_1+width_Coil_1), height_Coil_1/2, 0, c_Coil_1}; - -l_Coil_1_m[]={}; -l_Coil_1_m[]+=newl; Line(newl) = {p_Coil_1_m_ext_0, p_Coil_1_m_ext_1}; -l_Coil_1_m[]+=newl; Line(newl) = {p_Coil_1_m_ext_1, p_Coil_1_m_int_1}; -l_Coil_1_m[]+=newl; Line(newl) = {p_Coil_1_m_int_1, p_Coil_1_m_int_0}; - -l_Coil_1_m_Y0[]={}; -l_Coil_1_m_Y0[]+=newl; Line(newl) = {p_Coil_1_m_int_0, p_Coil_1_m_ext_0}; - -ll_Coil_1_m=newll; Line Loop(newll) = {l_Coil_1_m[], l_Coil_1_m_Y0[]}; -s_Coil_1_m=news; Plane Surface(news) = {ll_Coil_1_m}; - -Physical Surface("COIL_1_MINUS", COIL_1_MINUS) = {s_Coil_1_m}; - - -// COIL_2_PLUS - -x_[]=Point{p_Leg_2_R_0}; -p_Coil_2_p_int_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_2, 0, 0, c_Coil_2}; -p_Coil_2_p_ext_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_2+width_Coil_2, 0, 0, c_Coil_2}; -p_Coil_2_p_int_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_2, height_Coil_2/2, 0, c_Coil_2}; -p_Coil_2_p_ext_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_2+width_Coil_2, height_Coil_2/2, 0, c_Coil_2}; - -l_Coil_2_p[]={}; -l_Coil_2_p[]+=newl; Line(newl) = {p_Coil_2_p_ext_0, p_Coil_2_p_ext_1}; -l_Coil_2_p[]+=newl; Line(newl) = {p_Coil_2_p_ext_1, p_Coil_2_p_int_1}; -l_Coil_2_p[]+=newl; Line(newl) = {p_Coil_2_p_int_1, p_Coil_2_p_int_0}; - -l_Coil_2_p_Y0[]={}; -l_Coil_2_p_Y0[]+=newl; Line(newl) = {p_Coil_2_p_int_0, p_Coil_2_p_ext_0}; - -ll_Coil_2_p=newll; Line Loop(newll) = {l_Coil_2_p[], l_Coil_2_p_Y0[]}; -s_Coil_2_p=news; Plane Surface(news) = {ll_Coil_2_p}; - -Physical Surface("COIL_2_PLUS", COIL_2_PLUS) = {s_Coil_2_p}; - - -// COIL_2_MINUS - -x_[]=Point{p_Leg_2_L_0}; -p_Coil_2_m_int_0=newp; Point(newp) = {x_[0]-gap_Core_Coil_2, 0, 0, c_Coil_2}; -p_Coil_2_m_ext_0=newp; Point(newp) = {x_[0]-(gap_Core_Coil_2+width_Coil_2), 0, 0, c_Coil_2}; -p_Coil_2_m_int_1=newp; Point(newp) = {x_[0]-gap_Core_Coil_2, height_Coil_2/2, 0, c_Coil_2}; -p_Coil_2_m_ext_1=newp; Point(newp) = {x_[0]-(gap_Core_Coil_2+width_Coil_2), height_Coil_2/2, 0, c_Coil_2}; - -l_Coil_2_m[]={}; -l_Coil_2_m[]+=newl; Line(newl) = {p_Coil_2_m_ext_0, p_Coil_2_m_ext_1}; -l_Coil_2_m[]+=newl; Line(newl) = {p_Coil_2_m_ext_1, p_Coil_2_m_int_1}; -l_Coil_2_m[]+=newl; Line(newl) = {p_Coil_2_m_int_1, p_Coil_2_m_int_0}; - -l_Coil_2_m_Y0[]={}; -l_Coil_2_m_Y0[]+=newl; Line(newl) = {p_Coil_2_m_int_0, p_Coil_2_m_ext_0}; - -ll_Coil_2_m=newll; Line Loop(newll) = {l_Coil_2_m[], l_Coil_2_m_Y0[]}; -s_Coil_2_m=news; Plane Surface(news) = {ll_Coil_2_m}; - -Physical Surface("COIL_2_MINUS", COIL_2_MINUS) = {s_Coil_2_m}; - - -// AIR_WINDOW - -l_Air_Window_Y0[]={}; -l_Air_Window_Y0[]+=newl; Line(newl) = {p_Leg_1_R_0, p_Coil_1_p_int_0}; -l_Air_Window_Y0[]+=newl; Line(newl) = {p_Coil_1_p_ext_0, p_Coil_2_m_ext_0}; -l_Air_Window_Y0[]+=newl; Line(newl) = {p_Coil_2_m_int_0, p_Leg_2_L_0}; - -ll_Air_Window=newll; Line Loop(newll) = {-l_Core_In[], -l_Coil_1_p[], l_Coil_2_m[], l_Air_Window_Y0[]}; -s_Air_Window=news; Plane Surface(news) = {ll_Air_Window}; - -Physical Surface("AIR_WINDOW", AIR_WINDOW) = {s_Air_Window}; - - -// AIR_EXT - -x_[]=Point{p_Leg_2_R_1}; -p_Air_Ext_1_R_0=newp; Point(newp) = {x_[0]+gap_Core_Box_X, 0, 0, c_Box}; -p_Air_Ext_1_R_1=newp; Point(newp) = {x_[0]+gap_Core_Box_X, x_[1]+gap_Core_Box_Y, 0, c_Box}; - -x_[]=Point{p_Leg_1_L_1}; -p_Air_Ext_1_L_0=newp; Point(newp) = {x_[0]-gap_Core_Box_X, 0, 0, c_Box}; -p_Air_Ext_1_L_1=newp; Point(newp) = {x_[0]-gap_Core_Box_X, x_[1]+gap_Core_Box_Y, 0, c_Box}; - -l_Air_Ext[]={}; -l_Air_Ext[]+=newl; Line(newl) = {p_Air_Ext_1_R_0, p_Air_Ext_1_R_1}; -l_Air_Ext[]+=newl; Line(newl) = {p_Air_Ext_1_R_1, p_Air_Ext_1_L_1}; -l_Air_Ext[]+=newl; Line(newl) = {p_Air_Ext_1_L_1, p_Air_Ext_1_L_0}; - - -l_Air_Ext_Y0[]={}; -l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Leg_2_R_0, p_Coil_2_p_int_0}; -l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Coil_2_p_ext_0, p_Air_Ext_1_R_0}; - -l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Air_Ext_1_L_0, p_Coil_1_m_ext_0}; -l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Coil_1_m_int_0, p_Leg_1_L_0}; - - -ll_Air_Ext=newll; Line Loop(newll) = {-l_Core_Out[], -l_Coil_2_p[], l_Coil_1_m[], l_Air_Ext[], l_Air_Ext_Y0[]}; -s_Air_Ext=news; Plane Surface(news) = {ll_Air_Ext}; - -Physical Surface("AIR_EXT", AIR_EXT) = {s_Air_Ext}; -Physical Line("SUR_AIR_EXT", SUR_AIR_EXT) = {l_Air_Ext[]}; + +Include "transfo_common.pro"; + +Solver.AutoShowLastStep = 0; // don't automatically show the last time step + +// CORE + +p_Leg_1_L_0=newp; Point(newp) = {-width_Core/2., 0, 0, c_Core}; +p_Leg_1_R_0=newp; Point(newp) = {-width_Core/2.+width_Core_Leg, 0, 0, c_Core}; + +p_Leg_1_L_1=newp; Point(newp) = {-width_Core/2., height_Core/2., 0, c_Core}; +p_Leg_1_R_1=newp; Point(newp) = {-width_Core/2.+width_Core_Leg, height_Core/2.-width_Core_Leg, 0, c_Core}; + + +p_Leg_2_L_0=newp; Point(newp) = {width_Core/2.-width_Core_Leg, 0, 0, c_Core}; +p_Leg_2_R_0=newp; Point(newp) = {width_Core/2., 0, 0, c_Core}; + +p_Leg_2_L_1=newp; Point(newp) = {width_Core/2.-width_Core_Leg, height_Core/2.-width_Core_Leg, 0, c_Core}; +p_Leg_2_R_1=newp; Point(newp) = {width_Core/2., height_Core/2., 0, c_Core}; + + +l_Core_In[]={}; +l_Core_In[]+=newl; Line(newl) = {p_Leg_1_R_0, p_Leg_1_R_1}; +l_Core_In[]+=newl; Line(newl) = {p_Leg_1_R_1, p_Leg_2_L_1}; +l_Core_In[]+=newl; Line(newl) = {p_Leg_2_L_1, p_Leg_2_L_0}; + +l_Core_Out[]={}; +l_Core_Out[]+=newl; Line(newl) = {p_Leg_2_R_0, p_Leg_2_R_1}; +l_Core_Out[]+=newl; Line(newl) = {p_Leg_2_R_1, p_Leg_1_L_1}; +l_Core_Out[]+=newl; Line(newl) = {p_Leg_1_L_1, p_Leg_1_L_0}; + +l_Core_Leg_1_Y0[]={}; +l_Core_Leg_1_Y0[]+=newl; Line(newl) = {p_Leg_1_L_0, p_Leg_1_R_0}; + +l_Core_Leg_2_Y0[]={}; +l_Core_Leg_2_Y0[]+=newl; Line(newl) = {p_Leg_2_L_0, p_Leg_2_R_0}; + + +ll_Core=newll; Line Loop(newll) = {l_Core_In[], l_Core_Leg_2_Y0[], l_Core_Out[], l_Core_Leg_1_Y0[]}; +s_Core=news; Plane Surface(news) = {ll_Core}; + +Physical Surface("CORE", CORE) = {s_Core}; + +// COIL_1_PLUS + +x_[]=Point{p_Leg_1_R_0}; +p_Coil_1_p_int_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_1, 0, 0, c_Coil_1}; +p_Coil_1_p_ext_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_1+width_Coil_1, 0, 0, c_Coil_1}; +p_Coil_1_p_int_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_1, height_Coil_1/2, 0, c_Coil_1}; +p_Coil_1_p_ext_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_1+width_Coil_1, height_Coil_1/2, 0, c_Coil_1}; + +l_Coil_1_p[]={}; +l_Coil_1_p[]+=newl; Line(newl) = {p_Coil_1_p_ext_0, p_Coil_1_p_ext_1}; +l_Coil_1_p[]+=newl; Line(newl) = {p_Coil_1_p_ext_1, p_Coil_1_p_int_1}; +l_Coil_1_p[]+=newl; Line(newl) = {p_Coil_1_p_int_1, p_Coil_1_p_int_0}; + +l_Coil_1_p_Y0[]={}; +l_Coil_1_p_Y0[]+=newl; Line(newl) = {p_Coil_1_p_int_0, p_Coil_1_p_ext_0}; + +ll_Coil_1_p=newll; Line Loop(newll) = {l_Coil_1_p[], l_Coil_1_p_Y0[]}; +s_Coil_1_p=news; Plane Surface(news) = {ll_Coil_1_p}; + +Physical Surface("COIL_1_PLUS", COIL_1_PLUS) = {s_Coil_1_p}; + + +// COIL_1_MINUS + +x_[]=Point{p_Leg_1_L_0}; +p_Coil_1_m_int_0=newp; Point(newp) = {x_[0]-gap_Core_Coil_1, 0, 0, c_Coil_1}; +p_Coil_1_m_ext_0=newp; Point(newp) = {x_[0]-(gap_Core_Coil_1+width_Coil_1), 0, 0, c_Coil_1}; +p_Coil_1_m_int_1=newp; Point(newp) = {x_[0]-gap_Core_Coil_1, height_Coil_1/2, 0, c_Coil_1}; +p_Coil_1_m_ext_1=newp; Point(newp) = {x_[0]-(gap_Core_Coil_1+width_Coil_1), height_Coil_1/2, 0, c_Coil_1}; + +l_Coil_1_m[]={}; +l_Coil_1_m[]+=newl; Line(newl) = {p_Coil_1_m_ext_0, p_Coil_1_m_ext_1}; +l_Coil_1_m[]+=newl; Line(newl) = {p_Coil_1_m_ext_1, p_Coil_1_m_int_1}; +l_Coil_1_m[]+=newl; Line(newl) = {p_Coil_1_m_int_1, p_Coil_1_m_int_0}; + +l_Coil_1_m_Y0[]={}; +l_Coil_1_m_Y0[]+=newl; Line(newl) = {p_Coil_1_m_int_0, p_Coil_1_m_ext_0}; + +ll_Coil_1_m=newll; Line Loop(newll) = {l_Coil_1_m[], l_Coil_1_m_Y0[]}; +s_Coil_1_m=news; Plane Surface(news) = {ll_Coil_1_m}; + +Physical Surface("COIL_1_MINUS", COIL_1_MINUS) = {s_Coil_1_m}; + + +// COIL_2_PLUS + +x_[]=Point{p_Leg_2_R_0}; +p_Coil_2_p_int_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_2, 0, 0, c_Coil_2}; +p_Coil_2_p_ext_0=newp; Point(newp) = {x_[0]+gap_Core_Coil_2+width_Coil_2, 0, 0, c_Coil_2}; +p_Coil_2_p_int_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_2, height_Coil_2/2, 0, c_Coil_2}; +p_Coil_2_p_ext_1=newp; Point(newp) = {x_[0]+gap_Core_Coil_2+width_Coil_2, height_Coil_2/2, 0, c_Coil_2}; + +l_Coil_2_p[]={}; +l_Coil_2_p[]+=newl; Line(newl) = {p_Coil_2_p_ext_0, p_Coil_2_p_ext_1}; +l_Coil_2_p[]+=newl; Line(newl) = {p_Coil_2_p_ext_1, p_Coil_2_p_int_1}; +l_Coil_2_p[]+=newl; Line(newl) = {p_Coil_2_p_int_1, p_Coil_2_p_int_0}; + +l_Coil_2_p_Y0[]={}; +l_Coil_2_p_Y0[]+=newl; Line(newl) = {p_Coil_2_p_int_0, p_Coil_2_p_ext_0}; + +ll_Coil_2_p=newll; Line Loop(newll) = {l_Coil_2_p[], l_Coil_2_p_Y0[]}; +s_Coil_2_p=news; Plane Surface(news) = {ll_Coil_2_p}; + +Physical Surface("COIL_2_PLUS", COIL_2_PLUS) = {s_Coil_2_p}; + + +// COIL_2_MINUS + +x_[]=Point{p_Leg_2_L_0}; +p_Coil_2_m_int_0=newp; Point(newp) = {x_[0]-gap_Core_Coil_2, 0, 0, c_Coil_2}; +p_Coil_2_m_ext_0=newp; Point(newp) = {x_[0]-(gap_Core_Coil_2+width_Coil_2), 0, 0, c_Coil_2}; +p_Coil_2_m_int_1=newp; Point(newp) = {x_[0]-gap_Core_Coil_2, height_Coil_2/2, 0, c_Coil_2}; +p_Coil_2_m_ext_1=newp; Point(newp) = {x_[0]-(gap_Core_Coil_2+width_Coil_2), height_Coil_2/2, 0, c_Coil_2}; + +l_Coil_2_m[]={}; +l_Coil_2_m[]+=newl; Line(newl) = {p_Coil_2_m_ext_0, p_Coil_2_m_ext_1}; +l_Coil_2_m[]+=newl; Line(newl) = {p_Coil_2_m_ext_1, p_Coil_2_m_int_1}; +l_Coil_2_m[]+=newl; Line(newl) = {p_Coil_2_m_int_1, p_Coil_2_m_int_0}; + +l_Coil_2_m_Y0[]={}; +l_Coil_2_m_Y0[]+=newl; Line(newl) = {p_Coil_2_m_int_0, p_Coil_2_m_ext_0}; + +ll_Coil_2_m=newll; Line Loop(newll) = {l_Coil_2_m[], l_Coil_2_m_Y0[]}; +s_Coil_2_m=news; Plane Surface(news) = {ll_Coil_2_m}; + +Physical Surface("COIL_2_MINUS", COIL_2_MINUS) = {s_Coil_2_m}; + + +// AIR_WINDOW + +l_Air_Window_Y0[]={}; +l_Air_Window_Y0[]+=newl; Line(newl) = {p_Leg_1_R_0, p_Coil_1_p_int_0}; +l_Air_Window_Y0[]+=newl; Line(newl) = {p_Coil_1_p_ext_0, p_Coil_2_m_ext_0}; +l_Air_Window_Y0[]+=newl; Line(newl) = {p_Coil_2_m_int_0, p_Leg_2_L_0}; + +ll_Air_Window=newll; Line Loop(newll) = {-l_Core_In[], -l_Coil_1_p[], l_Coil_2_m[], l_Air_Window_Y0[]}; +s_Air_Window=news; Plane Surface(news) = {ll_Air_Window}; + +Physical Surface("AIR_WINDOW", AIR_WINDOW) = {s_Air_Window}; + + +// AIR_EXT + +x_[]=Point{p_Leg_2_R_1}; +p_Air_Ext_1_R_0=newp; Point(newp) = {x_[0]+gap_Core_Box_X, 0, 0, c_Box}; +p_Air_Ext_1_R_1=newp; Point(newp) = {x_[0]+gap_Core_Box_X, x_[1]+gap_Core_Box_Y, 0, c_Box}; + +x_[]=Point{p_Leg_1_L_1}; +p_Air_Ext_1_L_0=newp; Point(newp) = {x_[0]-gap_Core_Box_X, 0, 0, c_Box}; +p_Air_Ext_1_L_1=newp; Point(newp) = {x_[0]-gap_Core_Box_X, x_[1]+gap_Core_Box_Y, 0, c_Box}; + +l_Air_Ext[]={}; +l_Air_Ext[]+=newl; Line(newl) = {p_Air_Ext_1_R_0, p_Air_Ext_1_R_1}; +l_Air_Ext[]+=newl; Line(newl) = {p_Air_Ext_1_R_1, p_Air_Ext_1_L_1}; +l_Air_Ext[]+=newl; Line(newl) = {p_Air_Ext_1_L_1, p_Air_Ext_1_L_0}; + + +l_Air_Ext_Y0[]={}; +l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Leg_2_R_0, p_Coil_2_p_int_0}; +l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Coil_2_p_ext_0, p_Air_Ext_1_R_0}; + +l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Air_Ext_1_L_0, p_Coil_1_m_ext_0}; +l_Air_Ext_Y0[]+=newl; Line(newl) = {p_Coil_1_m_int_0, p_Leg_1_L_0}; + + +ll_Air_Ext=newll; Line Loop(newll) = {-l_Core_Out[], -l_Coil_2_p[], l_Coil_1_m[], l_Air_Ext[], l_Air_Ext_Y0[]}; +s_Air_Ext=news; Plane Surface(news) = {ll_Air_Ext}; + +Physical Surface("AIR_EXT", AIR_EXT) = {s_Air_Ext}; +Physical Line("SUR_AIR_EXT", SUR_AIR_EXT) = {l_Air_Ext[]}; diff --git a/Magnetodynamics/transfo.pro b/Magnetodynamics/transfo.pro index b3b1ece..88f0dba 100644 --- a/Magnetodynamics/transfo.pro +++ b/Magnetodynamics/transfo.pro @@ -1,259 +1,259 @@ -/* ------------------------------------------------------------------- - Tutorial 7b : magnetodyamic model of a single-phase transformer - - Features: - - Use of a generic template formulation library - - Frequency- and time-domain dynamic solutions - - Circuit coupling used as a black-box (see Tutorial 8 for details) - - To compute the solution in a terminal: - getdp transfo -solve MagDyn_a_2D -pos Map_a - - To compute the solution interactively from the Gmsh GUI: - File > Open > transfo.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -Include "transfo_common.pro"; - -DefineConstant[ - type_Conds = {2, Choices{1 = "Massive", 2 = "Coil"}, Highlight "Blue", - Name "Parameters/01Conductor type"} - type_Source = {2, Choices{1 = "Current", 2 = "Voltage"}, Highlight "Blue", - Name "Parameters/02Source type"} - type_Analysis = {1, Choices{1 = "Frequency-domain", 2 = "Time-domain"}, Highlight "Blue", - Name "Parameters/03Analysis type"} - Freq = {50, Min 0, Max 1e3, Step 1, - Name "Parameters/Frequency"} -]; - -Group { - /* Abstract regions that will be used in the "Lib_MagStaDyn_av_2D_Cir.pro" - template file included below; the regions are first intialized as empty, - before being filled with physical groups */ - - VolCC_Mag = Region[{}]; // Non-conducting regions - VolC_Mag = Region[{}]; // Massive conductors - VolS_Mag = Region[{}]; // Stranded conductors, i.e., coils - - // air physical groups - Air = Region[{AIR_WINDOW, AIR_EXT}]; - VolCC_Mag += Region[Air]; - - // exterior boundary - Sur_Air_Ext = Region[{SUR_AIR_EXT}]; - - // magnetic core of the transformer, assumed to be non-conducting - Core = Region[CORE]; - VolCC_Mag += Region[Core]; - - Coil_1_P = Region[COIL_1_PLUS]; - Coil_1_M = Region[COIL_1_MINUS]; - Coil_1 = Region[{Coil_1_P, Coil_1_M}]; - - Coil_2_P = Region[COIL_2_PLUS]; - Coil_2_M = Region[COIL_2_MINUS]; - Coil_2 = Region[{Coil_2_P, Coil_2_M}]; - - Coils = Region[{Coil_1, Coil_2}]; - - If (type_Conds == 1) - VolC_Mag += Region[{Coils}]; - ElseIf (type_Conds == 2) - VolS_Mag += Region[{Coils}]; - VolCC_Mag += Region[{Coils}]; - EndIf -} - - -Function { - mu0 = 4e-7*Pi; - - mu[Air] = 1 * mu0; - - mur_Core = 100; - mu[Core] = mur_Core * mu0; - - mu[Coils] = 1 * mu0; - sigma[Coils] = 1e7; - - // For a correct definition of the voltage - CoefGeo = thickness_Core; - - // To be defined separately for each coil portion - Sc[Coil_1_P] = SurfaceArea[]; - SignBranch[Coil_1_P] = 1; // To fix the convention of positive current (1: - // along Oz, -1: along -Oz) - - Sc[Coil_1_M] = SurfaceArea[]; - SignBranch[Coil_1_M] = -1; - - Sc[Coil_2_P] = SurfaceArea[]; - SignBranch[Coil_2_P] = 1; - - Sc[Coil_2_M] = SurfaceArea[]; - SignBranch[Coil_2_M] = -1; - - // Number of turns (same for PLUS and MINUS portions) (half values because - // half coils are defined) - Ns[Coil_1] = 1; - Ns[Coil_2] = 1; - - // Global definitions (nothing to change): - - // Current density in each coil portion for a unit current (will be multiplied - // by the actual total current in the coil) - js0[Coils] = Ns[]/Sc[] * Vector[0,0,SignBranch[]]; - CoefGeos[Coils] = SignBranch[] * CoefGeo; - - // The reluctivity will be used - nu[] = 1/mu[]; -} - -If(type_Analysis == 1) - Flag_FrequencyDomain = 1; -Else - Flag_FrequencyDomain = 0; -EndIf - -If (type_Source == 1) // current - - Flag_CircuitCoupling = 0; - -ElseIf (type_Source == 2) // voltage - - // PLUS and MINUS coil portions to be connected in series, with applied - // voltage on the resulting branch - Flag_CircuitCoupling = 1; - - // Here is the definition of the circuits on primary and secondary sides: - Group { - // Empty Groups to be filled - Resistance_Cir = Region[{}]; - Inductance_Cir = Region[{}] ; - Capacitance_Cir = Region[{}] ; - SourceV_Cir = Region[{}]; // Voltage sources - SourceI_Cir = Region[{}]; // Current sources - - // Primary side - E_in = Region[10001]; // arbitrary region number (not linked to the mesh) - SourceV_Cir += Region[{E_in}]; - - // Secondary side - R_out = Region[10101]; // arbitrary region number (not linked to the mesh) - Resistance_Cir += Region[{R_out}]; - } - - Function { - deg = Pi/180; - // Input RMS voltage (half of the voltage because of symmetry; half coils - // are defined) - val_E_in = 1.; - phase_E_in = 90 *deg; // Phase in radian (from phase in degree) - // High value for an open-circuit test; Low value for a short-circuit test; - // any value in-between for any charge - Resistance[R_out] = 1e6; - } - - Constraint { - - { Name Current_Cir ; - Case { - } - } - - { Name Voltage_Cir ; - Case { - { Region E_in; Value val_E_in; TimeFunction F_Cos_wt_p[]{2*Pi*Freq, phase_E_in}; } - } - } - - { Name ElectricalCircuit ; Type Network ; - Case Circuit_1 { - // PLUS and MINUS coil portions to be connected in series, together with - // E_in (an additional resistor should be defined to represent the - // Coil_1 end-winding (not considered in the 2D model)) - { Region E_in; Branch {1,2}; } - - { Region Coil_1_P; Branch {2,3} ; } - { Region Coil_1_M; Branch {3,1} ; } - } - Case Circuit_2 { - // PLUS and MINUS coil portions to be connected in series, together with - // R_out (an additional resistor should be defined to represent the - // Coil_2 end-winding (not considered in the 2D model)) - { Region R_out; Branch {1,2}; } - - { Region Coil_2_P; Branch {2,3} ; } - { Region Coil_2_M; Branch {3,1} ; } - } - } - - } - -EndIf - -Constraint { - { Name MagneticVectorPotential_2D; - Case { - { Region Sur_Air_Ext; Value 0; } - } - } - { Name Current_2D; - Case { - If (type_Source == 1) - // Current in each coil (same for PLUS and MINUS portions) - { Region Coil_1; Value 1; TimeFunction F_Sin_wt_p[]{2*Pi*Freq, 0}; } - { Region Coil_2; Value 0; } - EndIf - } - } - { Name Voltage_2D; - Case { - } - } -} - -Include "Lib_MagStaDyn_av_2D_Cir.pro"; - -PostOperation { - { Name Map_a; NameOfPostProcessing MagDyn_a_2D; - Operation { - Print[ j, OnElementsOf Region[{VolC_Mag, VolS_Mag}], Format Gmsh, File "j.pos" ]; - Print[ b, OnElementsOf Vol_Mag, Format Gmsh, File "b.pos" ]; - Print[ az, OnElementsOf Vol_Mag, Format Gmsh, File "az.pos" ]; - - If (type_Source == 1) // current - // In text file UI.txt: voltage and current for each coil portion (note - // that the voltage is not equally distributed in PLUS and MINUS - // portions, which is the reason why we must apply the total voltage - // through a circuit -> type_Source == 2) - Echo[ "Coil_1_P", Format Table, File "UI.txt" ]; - Print[ U, OnRegion Coil_1_P, Format FrequencyTable, File > "UI.txt" ]; - Print[ I, OnRegion Coil_1_P, Format FrequencyTable, File > "UI.txt"]; - Echo[ "Coil_1_M", Format Table, File > "UI.txt" ]; - Print[ U, OnRegion Coil_1_M, Format FrequencyTable, File > "UI.txt" ]; - Print[ I, OnRegion Coil_1_M, Format FrequencyTable, File > "UI.txt"]; - - Echo[ "Coil_2_P", Format Table, File > "UI.txt" ]; - Print[ U, OnRegion Coil_2_P, Format FrequencyTable, File > "UI.txt" ]; - Print[ I, OnRegion Coil_2_P, Format FrequencyTable, File > "UI.txt"]; - Echo[ "Coil_2_M", Format Table, File > "UI.txt" ]; - Print[ U, OnRegion Coil_2_M, Format FrequencyTable, File > "UI.txt" ]; - Print[ I, OnRegion Coil_2_M, Format FrequencyTable, File > "UI.txt"]; - - ElseIf (type_Source == 2) - // In text file UI.txt: voltage and current of the primary coil (from E_in) - // (real and imaginary parts!) - Echo[ "E_in", Format Table, File "UI.txt" ]; - Print[ U, OnRegion E_in, Format FrequencyTable, File > "UI.txt" ]; - Print[ I, OnRegion E_in, Format FrequencyTable, File > "UI.txt"]; - - // In text file UI.txt: voltage and current of the secondary coil (from R_out) - Echo[ "R_out", Format Table, File > "UI.txt" ]; - Print[ U, OnRegion R_out, Format FrequencyTable, File > "UI.txt" ]; - Print[ I, OnRegion R_out, Format FrequencyTable, File > "UI.txt"]; - EndIf - } - } -} +/* ------------------------------------------------------------------- + Tutorial 7b : magnetodyamic model of a single-phase transformer + + Features: + - Use of a generic template formulation library + - Frequency- and time-domain dynamic solutions + - Circuit coupling used as a black-box (see Tutorial 8 for details) + + To compute the solution in a terminal: + getdp transfo -solve MagDyn_a_2D -pos Map_a + + To compute the solution interactively from the Gmsh GUI: + File > Open > transfo.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +Include "transfo_common.pro"; + +DefineConstant[ + type_Conds = {2, Choices{1 = "Massive", 2 = "Coil"}, Highlight "Blue", + Name "Parameters/01Conductor type"} + type_Source = {2, Choices{1 = "Current", 2 = "Voltage"}, Highlight "Blue", + Name "Parameters/02Source type"} + type_Analysis = {1, Choices{1 = "Frequency-domain", 2 = "Time-domain"}, Highlight "Blue", + Name "Parameters/03Analysis type"} + Freq = {50, Min 0, Max 1e3, Step 1, + Name "Parameters/Frequency"} +]; + +Group { + /* Abstract regions that will be used in the "Lib_MagStaDyn_av_2D_Cir.pro" + template file included below; the regions are first intialized as empty, + before being filled with physical groups */ + + VolCC_Mag = Region[{}]; // Non-conducting regions + VolC_Mag = Region[{}]; // Massive conductors + VolS_Mag = Region[{}]; // Stranded conductors, i.e., coils + + // air physical groups + Air = Region[{AIR_WINDOW, AIR_EXT}]; + VolCC_Mag += Region[Air]; + + // exterior boundary + Sur_Air_Ext = Region[{SUR_AIR_EXT}]; + + // magnetic core of the transformer, assumed to be non-conducting + Core = Region[CORE]; + VolCC_Mag += Region[Core]; + + Coil_1_P = Region[COIL_1_PLUS]; + Coil_1_M = Region[COIL_1_MINUS]; + Coil_1 = Region[{Coil_1_P, Coil_1_M}]; + + Coil_2_P = Region[COIL_2_PLUS]; + Coil_2_M = Region[COIL_2_MINUS]; + Coil_2 = Region[{Coil_2_P, Coil_2_M}]; + + Coils = Region[{Coil_1, Coil_2}]; + + If (type_Conds == 1) + VolC_Mag += Region[{Coils}]; + ElseIf (type_Conds == 2) + VolS_Mag += Region[{Coils}]; + VolCC_Mag += Region[{Coils}]; + EndIf +} + + +Function { + mu0 = 4e-7*Pi; + + mu[Air] = 1 * mu0; + + mur_Core = 100; + mu[Core] = mur_Core * mu0; + + mu[Coils] = 1 * mu0; + sigma[Coils] = 1e7; + + // For a correct definition of the voltage + CoefGeo = thickness_Core; + + // To be defined separately for each coil portion + Sc[Coil_1_P] = SurfaceArea[]; + SignBranch[Coil_1_P] = 1; // To fix the convention of positive current (1: + // along Oz, -1: along -Oz) + + Sc[Coil_1_M] = SurfaceArea[]; + SignBranch[Coil_1_M] = -1; + + Sc[Coil_2_P] = SurfaceArea[]; + SignBranch[Coil_2_P] = 1; + + Sc[Coil_2_M] = SurfaceArea[]; + SignBranch[Coil_2_M] = -1; + + // Number of turns (same for PLUS and MINUS portions) (half values because + // half coils are defined) + Ns[Coil_1] = 1; + Ns[Coil_2] = 1; + + // Global definitions (nothing to change): + + // Current density in each coil portion for a unit current (will be multiplied + // by the actual total current in the coil) + js0[Coils] = Ns[]/Sc[] * Vector[0,0,SignBranch[]]; + CoefGeos[Coils] = SignBranch[] * CoefGeo; + + // The reluctivity will be used + nu[] = 1/mu[]; +} + +If(type_Analysis == 1) + Flag_FrequencyDomain = 1; +Else + Flag_FrequencyDomain = 0; +EndIf + +If (type_Source == 1) // current + + Flag_CircuitCoupling = 0; + +ElseIf (type_Source == 2) // voltage + + // PLUS and MINUS coil portions to be connected in series, with applied + // voltage on the resulting branch + Flag_CircuitCoupling = 1; + + // Here is the definition of the circuits on primary and secondary sides: + Group { + // Empty Groups to be filled + Resistance_Cir = Region[{}]; + Inductance_Cir = Region[{}] ; + Capacitance_Cir = Region[{}] ; + SourceV_Cir = Region[{}]; // Voltage sources + SourceI_Cir = Region[{}]; // Current sources + + // Primary side + E_in = Region[10001]; // arbitrary region number (not linked to the mesh) + SourceV_Cir += Region[{E_in}]; + + // Secondary side + R_out = Region[10101]; // arbitrary region number (not linked to the mesh) + Resistance_Cir += Region[{R_out}]; + } + + Function { + deg = Pi/180; + // Input RMS voltage (half of the voltage because of symmetry; half coils + // are defined) + val_E_in = 1.; + phase_E_in = 90 *deg; // Phase in radian (from phase in degree) + // High value for an open-circuit test; Low value for a short-circuit test; + // any value in-between for any charge + Resistance[R_out] = 1e6; + } + + Constraint { + + { Name Current_Cir ; + Case { + } + } + + { Name Voltage_Cir ; + Case { + { Region E_in; Value val_E_in; TimeFunction F_Cos_wt_p[]{2*Pi*Freq, phase_E_in}; } + } + } + + { Name ElectricalCircuit ; Type Network ; + Case Circuit_1 { + // PLUS and MINUS coil portions to be connected in series, together with + // E_in (an additional resistor should be defined to represent the + // Coil_1 end-winding (not considered in the 2D model)) + { Region E_in; Branch {1,2}; } + + { Region Coil_1_P; Branch {2,3} ; } + { Region Coil_1_M; Branch {3,1} ; } + } + Case Circuit_2 { + // PLUS and MINUS coil portions to be connected in series, together with + // R_out (an additional resistor should be defined to represent the + // Coil_2 end-winding (not considered in the 2D model)) + { Region R_out; Branch {1,2}; } + + { Region Coil_2_P; Branch {2,3} ; } + { Region Coil_2_M; Branch {3,1} ; } + } + } + + } + +EndIf + +Constraint { + { Name MagneticVectorPotential_2D; + Case { + { Region Sur_Air_Ext; Value 0; } + } + } + { Name Current_2D; + Case { + If (type_Source == 1) + // Current in each coil (same for PLUS and MINUS portions) + { Region Coil_1; Value 1; TimeFunction F_Sin_wt_p[]{2*Pi*Freq, 0}; } + { Region Coil_2; Value 0; } + EndIf + } + } + { Name Voltage_2D; + Case { + } + } +} + +Include "Lib_MagStaDyn_av_2D_Cir.pro"; + +PostOperation { + { Name Map_a; NameOfPostProcessing MagDyn_a_2D; + Operation { + Print[ j, OnElementsOf Region[{VolC_Mag, VolS_Mag}], Format Gmsh, File "j.pos" ]; + Print[ b, OnElementsOf Vol_Mag, Format Gmsh, File "b.pos" ]; + Print[ az, OnElementsOf Vol_Mag, Format Gmsh, File "az.pos" ]; + + If (type_Source == 1) // current + // In text file UI.txt: voltage and current for each coil portion (note + // that the voltage is not equally distributed in PLUS and MINUS + // portions, which is the reason why we must apply the total voltage + // through a circuit -> type_Source == 2) + Echo[ "Coil_1_P", Format Table, File "UI.txt" ]; + Print[ U, OnRegion Coil_1_P, Format FrequencyTable, File > "UI.txt" ]; + Print[ I, OnRegion Coil_1_P, Format FrequencyTable, File > "UI.txt"]; + Echo[ "Coil_1_M", Format Table, File > "UI.txt" ]; + Print[ U, OnRegion Coil_1_M, Format FrequencyTable, File > "UI.txt" ]; + Print[ I, OnRegion Coil_1_M, Format FrequencyTable, File > "UI.txt"]; + + Echo[ "Coil_2_P", Format Table, File > "UI.txt" ]; + Print[ U, OnRegion Coil_2_P, Format FrequencyTable, File > "UI.txt" ]; + Print[ I, OnRegion Coil_2_P, Format FrequencyTable, File > "UI.txt"]; + Echo[ "Coil_2_M", Format Table, File > "UI.txt" ]; + Print[ U, OnRegion Coil_2_M, Format FrequencyTable, File > "UI.txt" ]; + Print[ I, OnRegion Coil_2_M, Format FrequencyTable, File > "UI.txt"]; + + ElseIf (type_Source == 2) + // In text file UI.txt: voltage and current of the primary coil (from E_in) + // (real and imaginary parts!) + Echo[ "E_in", Format Table, File "UI.txt" ]; + Print[ U, OnRegion E_in, Format FrequencyTable, File > "UI.txt" ]; + Print[ I, OnRegion E_in, Format FrequencyTable, File > "UI.txt"]; + + // In text file UI.txt: voltage and current of the secondary coil (from R_out) + Echo[ "R_out", Format Table, File > "UI.txt" ]; + Print[ U, OnRegion R_out, Format FrequencyTable, File > "UI.txt" ]; + Print[ I, OnRegion R_out, Format FrequencyTable, File > "UI.txt"]; + EndIf + } + } +} diff --git a/Magnetodynamics/transfo_common.pro b/Magnetodynamics/transfo_common.pro index a116935..53034cc 100644 --- a/Magnetodynamics/transfo_common.pro +++ b/Magnetodynamics/transfo_common.pro @@ -1,49 +1,49 @@ - -// Dimensions - -width_Core = 1.; -height_Core = 1.; - -// Thickness along Oz (to be considered for a correct definition of voltage) -thickness_Core = 1.; - -width_Window = 0.5; -height_Window = 0.5; - -width_Core_Leg = (width_Core-width_Window)/2.; - -width_Coil_1 = 0.10; -height_Coil_1 = 0.25; -gap_Core_Coil_1 = 0.05; - -width_Coil_2 = 0.10; -height_Coil_2 = 0.25; -gap_Core_Coil_2 = 0.05; - -gap_Core_Box_X = 1.; -gap_Core_Box_Y = 1.; - -// Characteristic lenghts (for mesh sizes) - -s = 1; - -c_Core = width_Core_Leg/10. *s; - -c_Coil_1 = height_Coil_1/2/5 *s; -c_Coil_2 = height_Coil_2/2/5 *s; - -c_Box = gap_Core_Box_X/6. *s; - -// Physical regions - -AIR_EXT = 1001; -SUR_AIR_EXT = 1002; -AIR_WINDOW = 1011; - -CORE = 1050; - -COIL_1_PLUS = 1101; -COIL_1_MINUS = 1102; - -COIL_2_PLUS = 1201; -COIL_2_MINUS = 1202; + +// Dimensions + +width_Core = 1.; +height_Core = 1.; + +// Thickness along Oz (to be considered for a correct definition of voltage) +thickness_Core = 1.; + +width_Window = 0.5; +height_Window = 0.5; + +width_Core_Leg = (width_Core-width_Window)/2.; + +width_Coil_1 = 0.10; +height_Coil_1 = 0.25; +gap_Core_Coil_1 = 0.05; + +width_Coil_2 = 0.10; +height_Coil_2 = 0.25; +gap_Core_Coil_2 = 0.05; + +gap_Core_Box_X = 1.; +gap_Core_Box_Y = 1.; + +// Characteristic lenghts (for mesh sizes) + +s = 1; + +c_Core = width_Core_Leg/10. *s; + +c_Coil_1 = height_Coil_1/2/5 *s; +c_Coil_2 = height_Coil_2/2/5 *s; + +c_Box = gap_Core_Box_X/6. *s; + +// Physical regions + +AIR_EXT = 1001; +SUR_AIR_EXT = 1002; +AIR_WINDOW = 1011; + +CORE = 1050; + +COIL_1_PLUS = 1101; +COIL_1_MINUS = 1102; + +COIL_2_PLUS = 1201; +COIL_2_MINUS = 1202; diff --git a/Magnetostatics/electromagnet.geo b/Magnetostatics/electromagnet.geo index 7bd410c..b24c084 100644 --- a/Magnetostatics/electromagnet.geo +++ b/Magnetostatics/electromagnet.geo @@ -1,54 +1,54 @@ -/* ------------------------------------------------------------------- - File "electromagnet.geo" - - This file is the geometrical description used by GMSH to produce - the file "electromagnet.msh". - ------------------------------------------------------------------- */ - -dxCore = 50.e-3; dyCore = 100.e-3; -xInd = 75.e-3; dxInd = 25.e-3; dyInd = 50.e-3; - -Include "electromagnet_common.pro"; - -s = DefineNumber[1, Name "Model parameters/Global mesh size", - Help "Reduce for finer mesh"]; -p0 = 12.e-3 *s; -pCorex = 4.e-3 *s; pCorey0 = 8.e-3 *s; pCorey = 4.e-3 *s; -pIndx = 5.e-3 *s; pIndy = 5.e-3 *s; -pInt = 12.5e-3*s; pExt = 12.5e-3*s; - -Point(1) = {0,0,0,p0}; -Point(2) = {dxCore,0,0,pCorex}; -Point(3) = {dxCore,dyCore,0,pCorey}; -Point(4) = {0,dyCore,0,pCorey0}; -Point(5) = {xInd,0,0,pIndx}; -Point(6) = {xInd+dxInd,0,0,pIndx}; -Point(7) = {xInd+dxInd,dyInd,0,pIndy}; -Point(8) = {xInd,dyInd,0,pIndy}; -Point(9) = {rInt,0,0,pInt}; -Point(10) = {rExt,0,0,pExt}; -Point(11) = {0,rInt,0,pInt}; -Point(12) = {0,rExt,0,pExt}; - -Line(1) = {1,2}; Line(2) = {2,5}; Line(3) = {5,6}; -Line(4) = {6,9}; Line(5) = {9,10}; Line(6) = {1,4}; -Line(7) = {4,11}; Line(8) = {11,12}; Line(9) = {2,3}; -Line(10) = {3,4}; Line(11) = {6,7}; Line(12) = {7,8}; -Line(13) = {8,5}; - -Circle(14) = {9,1,11}; Circle(15) = {10,1,12}; - -Line Loop(16) = {-6,1,9,10}; Plane Surface(17) = {16}; -Line Loop(18) = {11,12,13,3}; Plane Surface(19) = {18}; -Line Loop(20) = {7,-14,-4,11,12,13,-2,9,10}; Plane Surface(21) = {-20}; // "-" for orientation -Line Loop(22) = {8,-15,-5,14}; Plane Surface(23) = {-22}; - -Physical Surface(101) = {21}; /* Air */ -Physical Surface(102) = {17}; /* Core */ -Physical Surface(103) = {19}; /* Ind */ -Physical Surface(111) = {23}; /* AirInf */ - -Physical Line(1100) = {1,2,3,4,5}; /* Surface ht = 0 */ -Physical Line(1101) = {6,7,8}; /* Surface bn = 0 */ -Physical Line(1102) = {15}; /* Surface Inf */ - +/* ------------------------------------------------------------------- + File "electromagnet.geo" + + This file is the geometrical description used by GMSH to produce + the file "electromagnet.msh". + ------------------------------------------------------------------- */ + +dxCore = 50.e-3; dyCore = 100.e-3; +xInd = 75.e-3; dxInd = 25.e-3; dyInd = 50.e-3; + +Include "electromagnet_common.pro"; + +s = DefineNumber[1, Name "Model parameters/Global mesh size", + Help "Reduce for finer mesh"]; +p0 = 12.e-3 *s; +pCorex = 4.e-3 *s; pCorey0 = 8.e-3 *s; pCorey = 4.e-3 *s; +pIndx = 5.e-3 *s; pIndy = 5.e-3 *s; +pInt = 12.5e-3*s; pExt = 12.5e-3*s; + +Point(1) = {0,0,0,p0}; +Point(2) = {dxCore,0,0,pCorex}; +Point(3) = {dxCore,dyCore,0,pCorey}; +Point(4) = {0,dyCore,0,pCorey0}; +Point(5) = {xInd,0,0,pIndx}; +Point(6) = {xInd+dxInd,0,0,pIndx}; +Point(7) = {xInd+dxInd,dyInd,0,pIndy}; +Point(8) = {xInd,dyInd,0,pIndy}; +Point(9) = {rInt,0,0,pInt}; +Point(10) = {rExt,0,0,pExt}; +Point(11) = {0,rInt,0,pInt}; +Point(12) = {0,rExt,0,pExt}; + +Line(1) = {1,2}; Line(2) = {2,5}; Line(3) = {5,6}; +Line(4) = {6,9}; Line(5) = {9,10}; Line(6) = {1,4}; +Line(7) = {4,11}; Line(8) = {11,12}; Line(9) = {2,3}; +Line(10) = {3,4}; Line(11) = {6,7}; Line(12) = {7,8}; +Line(13) = {8,5}; + +Circle(14) = {9,1,11}; Circle(15) = {10,1,12}; + +Line Loop(16) = {-6,1,9,10}; Plane Surface(17) = {16}; +Line Loop(18) = {11,12,13,3}; Plane Surface(19) = {18}; +Line Loop(20) = {7,-14,-4,11,12,13,-2,9,10}; Plane Surface(21) = {-20}; // "-" for orientation +Line Loop(22) = {8,-15,-5,14}; Plane Surface(23) = {-22}; + +Physical Surface(101) = {21}; /* Air */ +Physical Surface(102) = {17}; /* Core */ +Physical Surface(103) = {19}; /* Ind */ +Physical Surface(111) = {23}; /* AirInf */ + +Physical Line(1100) = {1,2,3,4,5}; /* Surface ht = 0 */ +Physical Line(1101) = {6,7,8}; /* Surface bn = 0 */ +Physical Line(1102) = {15}; /* Surface Inf */ + diff --git a/Magnetostatics/electromagnet.pro b/Magnetostatics/electromagnet.pro index 629379f..1e1c1c4 100644 --- a/Magnetostatics/electromagnet.pro +++ b/Magnetostatics/electromagnet.pro @@ -1,267 +1,267 @@ -/* ------------------------------------------------------------------- - Tutorial 2 : magnetostatic field of an electromagnet - - Features: - - Infinite ring geometrical transformation - - Parameters shared by Gmsh and GetDp, and Onelab parameters - - FunctionSpaces for the 2D vector potential formulation - - To compute the solution in a terminal: - getdp electromagnet -solve MagSta_a - getdp electromagnet -pos Map_a - - To compute the solution interactively from the Gmsh GUI: - File > Open > electromagnet.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -/* Electromagnetic fields expand to infinity. - The corresponding boundary condition can be imposed rigorously - by means of a gometrical transformation that maps a ring (or shell) of finite elements - to the complementary of its interior. - As this is a mere geometric transformation, - it is enough in the model description to attribute a special jacobian - to the ring region ("AirInf"). See Jacobian{} section below. - With this information, GetDP is able to deal with the correct transformation - of all quantities involved in the model. - - The special jacobian "VolSphShell" has parameters. - There are 2 parameters in this case, "Val_Rint" and "Val_Rext", - which represent the inner and outer radii of the transformed ring region - and whose value must match those used - in the geometrical description of the model (.geo file). - This is a typical case where Gmsh and GetDP must consistently share parameter values. - To ensure consistency in all cases, common parameters are defined - is a specific file "electromagnet_common.pro", - which is included in both the .geo and .pro file of the model. - - Besides sharing parameters between Gmsh and GetDP, - it is also useful to share some parameters (not all) with the user of the model, - i.e., to make them editable in the GUI before running the model. - Such variables are called Onelab variables (because the sharing mechanism - between the model and the GUI uses the Onelab interface). - Onelab parameters are defined with a "DefineNumber" statement, - which can be invoked in the .geo, .pro, or _common.pro files. - */ - - -Group { - // Physical regions: - Air = Region[ 101 ]; Core = Region[ 102 ]; - Ind = Region[ 103 ]; AirInf = Region[ 111 ]; - - Surface_ht0 = Region[ 1100 ]; - Surface_bn0 = Region[ 1101 ]; - Surface_Inf = Region[ 1102 ]; - - - /* Abstract regions : - The purpose of abstract regions is to allow a generic definition of - the FunctionSpace, Formulation and PostProcessing fields - with no reference to model-specific Physical regions. - We will show in a later tutorial how abstract formulations can then be isolated - in geometry independent template files, thanks to an appropriate declaration mechanism - (using DefineConstant[], DefineGroup[] and DefineFunction[]). - - The abstract regions in this model have the following interpretation: - - Vol_Nu_Mag = region where the term [ nu[] * Dof{d a} , {d a} ] is assembled - - Vol_Js_Mag = region where the term [ - Dof{js} , {a} ] is assembled - - Vol_Inf_Mag = region where the infinite ring geometric transformation is applied - - Sur_Dir_Mag = Homogeneous Dirichlet part of the model's boundary; - - Sur_Neu_Mag = Homogeneous Neumann part of the model's boundary; - */ - Vol_Nu_Mag = Region[ {Air, AirInf, Core, Ind} ]; - Vol_Js_Mag = Region[ Ind ]; - Vol_Inf_Mag = Region[ {AirInf} ]; - Sur_Dir_Mag = Region[ {Surface_bn0, Surface_Inf} ]; - Sur_Neu_Mag = Region[ {Surface_ht0} ]; -} - -Function { - mu0 = 4.e-7 * Pi; - murCore = DefineNumber[100, Name "Model parameters/Mur core", - Help "Magnetic relative permeability of Core"]; - - nu [ Region[{Air, Ind, AirInf}] ] = 1. / mu0; - nu [ Core ] = 1. / (murCore * mu0); - - NbTurns = 1000 ; - Current = DefineNumber[0.01, Name "Model parameters/Current", - Help "Current injected in coil [A]"]; - Js_fct[ Ind ] = -NbTurns*Current/SurfaceArea[]; - /* The minus sign is to have the current in -e_z direction, - so that the magnetic induction field is in +e_y direction */ -} - -/* In the 2D approximation, the magnetic vector potential A and the current density Js - are not scalars, but vectors with a z-component only: - A = Vector [ 0, 0, az(x,y,t) ] - Js = Vector [ 0, 0, jsz(x,y,t) ] - In order to compute derivatives and apply geometric transformations adequately, - GetDP needs this information. - Regarding discretization, now, A is node-based, whereas Js is region-wise constant. - Considering all this, one ends then up with the FunctionSpaces - "Hcurl_a_Mag_2D" and "Hregion_j_Mag_2D" as they are defined below. - - The function space "Hregion_j_Mag_2D" provides one basis function, - and hence one degree of freedom, per physical region in the abstract region "Vol_Js_Mag". - The constraint "SourceCurrentDensityZ" fixes all these dofs, - so the FunctionSpace "Hregion_j_Mag_2D" is fully fixed and has no FE unknowns. - One could thus have replaced it by a simple function - and the Galerkin term would have been - - Galerkin { [ Vector[ 0,0,-Js_fct[] ] , {a} ]; In Vol_Js_Mag; - Jacobian Vol; Integration Int; } - - instead of - - Galerkin { [ - Dof{js} , {a} ]; In Vol_Js_Mag; - Jacobian Vol; Integration Int; } - - Thechosen implementation below is however more effeicient - as it avoids evaluating repeatedly the function Js_fct[] during assembly. - */ - - -Constraint { - { Name Dirichlet_a_Mag; - Case { - { Region Sur_Dir_Mag ; Value 0.; } - } - } - { Name SourceCurrentDensityZ; - Case { - { Region Vol_Js_Mag ; Value Js_fct[]; } - } - } -} - -Group { - Dom_Hcurl_a_Mag_2D = Region[ {Vol_Nu_Mag, Sur_Neu_Mag} ]; -} -FunctionSpace { - { Name Hcurl_a_Mag_2D; Type Form1P; // Magnetic vector potential A - BasisFunction { - { Name se; NameOfCoef ae; Function BF_PerpendicularEdge; - Support Dom_Hcurl_a_Mag_2D ; Entity NodesOf[ All ]; } - } - Constraint { - { NameOfCoef ae; EntityType NodesOf; - NameOfConstraint Dirichlet_a_Mag; } - } - } - - { Name Hregion_j_Mag_2D; Type Vector; // Electric current density Js - BasisFunction { - { Name sr; NameOfCoef jsr; Function BF_RegionZ; - Support Vol_Js_Mag; Entity Vol_Js_Mag; } - } - Constraint { - { NameOfCoef jsr; EntityType Region; - NameOfConstraint SourceCurrentDensityZ; } - } - } - -} - -Include "electromagnet_common.pro"; -Val_Rint = rInt; Val_Rext = rExt; -Jacobian { - { Name Vol ; - Case { { Region Vol_Inf_Mag ; - Jacobian VolSphShell {Val_Rint, Val_Rext} ; } - { Region All ; Jacobian Vol ; } - } - } -} - -Integration { - { Name Int ; - Case { {Type Gauss ; - Case { { GeoElement Triangle ; NumberOfPoints 4 ; } - { GeoElement Quadrangle ; NumberOfPoints 4 ; } - } - } - } - } -} - -Formulation { - { Name Magnetostatics_a_2D; Type FemEquation; - Quantity { - { Name a ; Type Local; NameOfSpace Hcurl_a_Mag_2D; } - { Name js; Type Local; NameOfSpace Hregion_j_Mag_2D; } - } - Equation { - Galerkin { [ nu[] * Dof{d a} , {d a} ]; In Vol_Nu_Mag; - Jacobian Vol; Integration Int; } - Galerkin { [ -Dof{js} , {a} ]; In Vol_Js_Mag; - Jacobian Vol; Integration Int; } - } - } -} - -Resolution { - { Name MagSta_a; - System { - { Name Sys_Mag; NameOfFormulation Magnetostatics_a_2D; } - } - Operation { - Generate[Sys_Mag]; Solve[Sys_Mag]; SaveSolution[Sys_Mag]; - } - } -} - -PostProcessing { - { Name MagSta_a_2D; NameOfFormulation Magnetostatics_a_2D; - Quantity { - { Name a; - Value { - Local { [ {a} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } - } - } - { Name az; - Value { - Local { [ CompZ[{a}] ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } - } - } - { Name b; - Value { - Local { [ {d a} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } - } - } - { Name h; - Value { - Local { [ nu[] * {d a} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } - } - } - { Name js; - Value { - Local { [ {js} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } - } - } - } - } -} - -e = 1.e-5; -h = 0.02; -p1 = {e,h,0}; -p2 = {0.25-e,h,0}; // horizontal cut through model, just above x-axis. - -PostOperation { - - { Name Map_a; NameOfPostProcessing MagSta_a_2D; - Operation { - Echo[ Str["l=PostProcessing.NbViews-1;", - "View[l].IntervalsType = 1;", - "View[l].NbIso = 40;"], - File "tmp.geo", LastTimeStepOnly] ; - Print[ a, OnElementsOf Dom_Hcurl_a_Mag_2D, File "a.pos" ]; - Print[ js, OnElementsOf Dom_Hcurl_a_Mag_2D, File "js.pos" ]; - Print[ az, OnElementsOf Dom_Hcurl_a_Mag_2D, File "az.pos" ]; - Print[ b, OnElementsOf Dom_Hcurl_a_Mag_2D, File "b.pos" ]; - Print[ b, OnLine{{List[p1]}{List[p2]}} {50}, File "by.pos" ]; - } - } -} +/* ------------------------------------------------------------------- + Tutorial 2 : magnetostatic field of an electromagnet + + Features: + - Infinite ring geometrical transformation + - Parameters shared by Gmsh and GetDp, and Onelab parameters + - FunctionSpaces for the 2D vector potential formulation + + To compute the solution in a terminal: + getdp electromagnet -solve MagSta_a + getdp electromagnet -pos Map_a + + To compute the solution interactively from the Gmsh GUI: + File > Open > electromagnet.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +/* Electromagnetic fields expand to infinity. + The corresponding boundary condition can be imposed rigorously + by means of a gometrical transformation that maps a ring (or shell) of finite elements + to the complementary of its interior. + As this is a mere geometric transformation, + it is enough in the model description to attribute a special jacobian + to the ring region ("AirInf"). See Jacobian{} section below. + With this information, GetDP is able to deal with the correct transformation + of all quantities involved in the model. + + The special jacobian "VolSphShell" has parameters. + There are 2 parameters in this case, "Val_Rint" and "Val_Rext", + which represent the inner and outer radii of the transformed ring region + and whose value must match those used + in the geometrical description of the model (.geo file). + This is a typical case where Gmsh and GetDP must consistently share parameter values. + To ensure consistency in all cases, common parameters are defined + is a specific file "electromagnet_common.pro", + which is included in both the .geo and .pro file of the model. + + Besides sharing parameters between Gmsh and GetDP, + it is also useful to share some parameters (not all) with the user of the model, + i.e., to make them editable in the GUI before running the model. + Such variables are called Onelab variables (because the sharing mechanism + between the model and the GUI uses the Onelab interface). + Onelab parameters are defined with a "DefineNumber" statement, + which can be invoked in the .geo, .pro, or _common.pro files. + */ + + +Group { + // Physical regions: + Air = Region[ 101 ]; Core = Region[ 102 ]; + Ind = Region[ 103 ]; AirInf = Region[ 111 ]; + + Surface_ht0 = Region[ 1100 ]; + Surface_bn0 = Region[ 1101 ]; + Surface_Inf = Region[ 1102 ]; + + + /* Abstract regions : + The purpose of abstract regions is to allow a generic definition of + the FunctionSpace, Formulation and PostProcessing fields + with no reference to model-specific Physical regions. + We will show in a later tutorial how abstract formulations can then be isolated + in geometry independent template files, thanks to an appropriate declaration mechanism + (using DefineConstant[], DefineGroup[] and DefineFunction[]). + + The abstract regions in this model have the following interpretation: + - Vol_Nu_Mag = region where the term [ nu[] * Dof{d a} , {d a} ] is assembled + - Vol_Js_Mag = region where the term [ - Dof{js} , {a} ] is assembled + - Vol_Inf_Mag = region where the infinite ring geometric transformation is applied + - Sur_Dir_Mag = Homogeneous Dirichlet part of the model's boundary; + - Sur_Neu_Mag = Homogeneous Neumann part of the model's boundary; + */ + Vol_Nu_Mag = Region[ {Air, AirInf, Core, Ind} ]; + Vol_Js_Mag = Region[ Ind ]; + Vol_Inf_Mag = Region[ {AirInf} ]; + Sur_Dir_Mag = Region[ {Surface_bn0, Surface_Inf} ]; + Sur_Neu_Mag = Region[ {Surface_ht0} ]; +} + +Function { + mu0 = 4.e-7 * Pi; + murCore = DefineNumber[100, Name "Model parameters/Mur core", + Help "Magnetic relative permeability of Core"]; + + nu [ Region[{Air, Ind, AirInf}] ] = 1. / mu0; + nu [ Core ] = 1. / (murCore * mu0); + + NbTurns = 1000 ; + Current = DefineNumber[0.01, Name "Model parameters/Current", + Help "Current injected in coil [A]"]; + Js_fct[ Ind ] = -NbTurns*Current/SurfaceArea[]; + /* The minus sign is to have the current in -e_z direction, + so that the magnetic induction field is in +e_y direction */ +} + +/* In the 2D approximation, the magnetic vector potential A and the current density Js + are not scalars, but vectors with a z-component only: + A = Vector [ 0, 0, az(x,y,t) ] + Js = Vector [ 0, 0, jsz(x,y,t) ] + In order to compute derivatives and apply geometric transformations adequately, + GetDP needs this information. + Regarding discretization, now, A is node-based, whereas Js is region-wise constant. + Considering all this, one ends then up with the FunctionSpaces + "Hcurl_a_Mag_2D" and "Hregion_j_Mag_2D" as they are defined below. + + The function space "Hregion_j_Mag_2D" provides one basis function, + and hence one degree of freedom, per physical region in the abstract region "Vol_Js_Mag". + The constraint "SourceCurrentDensityZ" fixes all these dofs, + so the FunctionSpace "Hregion_j_Mag_2D" is fully fixed and has no FE unknowns. + One could thus have replaced it by a simple function + and the Integral term would have been + + Integral { [ Vector[ 0,0,-Js_fct[] ] , {a} ]; In Vol_Js_Mag; + Jacobian Vol; Integration Int; } + + instead of + + Integral { [ - Dof{js} , {a} ]; In Vol_Js_Mag; + Jacobian Vol; Integration Int; } + + Thechosen implementation below is however more effeicient + as it avoids evaluating repeatedly the function Js_fct[] during assembly. + */ + + +Constraint { + { Name Dirichlet_a_Mag; + Case { + { Region Sur_Dir_Mag ; Value 0.; } + } + } + { Name SourceCurrentDensityZ; + Case { + { Region Vol_Js_Mag ; Value Js_fct[]; } + } + } +} + +Group { + Dom_Hcurl_a_Mag_2D = Region[ {Vol_Nu_Mag, Sur_Neu_Mag} ]; +} +FunctionSpace { + { Name Hcurl_a_Mag_2D; Type Form1P; // Magnetic vector potential A + BasisFunction { + { Name se; NameOfCoef ae; Function BF_PerpendicularEdge; + Support Dom_Hcurl_a_Mag_2D ; Entity NodesOf[ All ]; } + } + Constraint { + { NameOfCoef ae; EntityType NodesOf; + NameOfConstraint Dirichlet_a_Mag; } + } + } + + { Name Hregion_j_Mag_2D; Type Vector; // Electric current density Js + BasisFunction { + { Name sr; NameOfCoef jsr; Function BF_RegionZ; + Support Vol_Js_Mag; Entity Vol_Js_Mag; } + } + Constraint { + { NameOfCoef jsr; EntityType Region; + NameOfConstraint SourceCurrentDensityZ; } + } + } + +} + +Include "electromagnet_common.pro"; +Val_Rint = rInt; Val_Rext = rExt; +Jacobian { + { Name Vol ; + Case { { Region Vol_Inf_Mag ; + Jacobian VolSphShell {Val_Rint, Val_Rext} ; } + { Region All ; Jacobian Vol ; } + } + } +} + +Integration { + { Name Int ; + Case { {Type Gauss ; + Case { { GeoElement Triangle ; NumberOfPoints 4 ; } + { GeoElement Quadrangle ; NumberOfPoints 4 ; } + } + } + } + } +} + +Formulation { + { Name Magnetostatics_a_2D; Type FemEquation; + Quantity { + { Name a ; Type Local; NameOfSpace Hcurl_a_Mag_2D; } + { Name js; Type Local; NameOfSpace Hregion_j_Mag_2D; } + } + Equation { + Integral { [ nu[] * Dof{d a} , {d a} ]; In Vol_Nu_Mag; + Jacobian Vol; Integration Int; } + Integral { [ -Dof{js} , {a} ]; In Vol_Js_Mag; + Jacobian Vol; Integration Int; } + } + } +} + +Resolution { + { Name MagSta_a; + System { + { Name Sys_Mag; NameOfFormulation Magnetostatics_a_2D; } + } + Operation { + Generate[Sys_Mag]; Solve[Sys_Mag]; SaveSolution[Sys_Mag]; + } + } +} + +PostProcessing { + { Name MagSta_a_2D; NameOfFormulation Magnetostatics_a_2D; + Quantity { + { Name a; + Value { + Local { [ {a} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + { Name az; + Value { + Local { [ CompZ[{a}] ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + { Name b; + Value { + Local { [ {d a} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + { Name h; + Value { + Local { [ nu[] * {d a} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + { Name js; + Value { + Local { [ {js} ]; In Dom_Hcurl_a_Mag_2D; Jacobian Vol; } + } + } + } + } +} + +e = 1.e-5; +h = 0.02; +p1 = {e,h,0}; +p2 = {0.25-e,h,0}; // horizontal cut through model, just above x-axis. + +PostOperation { + + { Name Map_a; NameOfPostProcessing MagSta_a_2D; + Operation { + Echo[ Str["l=PostProcessing.NbViews-1;", + "View[l].IntervalsType = 1;", + "View[l].NbIso = 40;"], + File "tmp.geo", LastTimeStepOnly] ; + Print[ a, OnElementsOf Dom_Hcurl_a_Mag_2D, File "a.pos" ]; + Print[ js, OnElementsOf Dom_Hcurl_a_Mag_2D, File "js.pos" ]; + Print[ az, OnElementsOf Dom_Hcurl_a_Mag_2D, File "az.pos" ]; + Print[ b, OnElementsOf Dom_Hcurl_a_Mag_2D, File "b.pos" ]; + Print[ b, OnLine{{List[p1]}{List[p2]}} {50}, File "by.pos" ]; + } + } +} diff --git a/Magnetostatics/electromagnet_common.pro b/Magnetostatics/electromagnet_common.pro index 56879cd..f0dd285 100644 --- a/Magnetostatics/electromagnet_common.pro +++ b/Magnetostatics/electromagnet_common.pro @@ -1,4 +1,4 @@ -// Parameters shared by Gmsh and GetDP - -rInt = 200.e-3; -rExt = 250.e-3; +// Parameters shared by Gmsh and GetDP + +rInt = 200.e-3; +rExt = 250.e-3; diff --git a/PotentialFlow/magnus.geo b/PotentialFlow/magnus.geo index c78c6ac..3d477a7 100644 --- a/PotentialFlow/magnus.geo +++ b/PotentialFlow/magnus.geo @@ -1,71 +1,71 @@ -Include "magnus_common.pro"; - -A = (BoxSize-1)/2.; -B = A; -R = 0.5; -lc = A/10; - - -If( Flag_Object == 0 ) // Cylinder - -lcr = 0.1; -Point(1) = { 2*R, 0.0, 0.0, lcr}; -Point(2) = { R, -R, 0.0, lcr}; -Point(3) = { 0.0, 0.0, 0.0, lcr}; -Point(4) = { R, R, 0.0 , lcr}; -Point(5) = { R, 0.0, 0.0 , lcr}; -Circle(1) = {1,5,2}; -Circle(2) = {2,5,3}; -Circle(3) = {3,5,4}; -Circle(4) = {4,5,1}; - -// Points to be connected with the outer boundary -PtA = 4; -PtB = 2; - -Else // naca airfoil - -lca = 0.03; -Include "nacaAirFoil.geo"; -PtA = 121; -PtB = 81; - -EndIf - -Point(306) = { 0, B, 0, lc}; -Point(307) = { 0,-B, 0, lc}; - -Line(5) = { PtA, 306 }; -Line(6) = { PtB, 307 }; - -Point(308) = {-A,-B, 0, lc}; -Point(309) = {-A, B, 0, lc}; -Point(310) = { A+1, B, 0, lc}; -Point(311) = { A+1,-B, 0, lc}; - -Line( 7) = { 306, 309 }; -Line( 8) = { 309, 308 }; -Line( 9) = { 308, 307 }; -Line(10) = { 307, 311 }; -Line(11) = { 311, 310 }; -Line(12) = { 310, 306 }; - -Line Loop(21) = { 7, 8, 9, -6, 2, 3, 5 }; // aire a gauche -Line Loop(22) = { 10, 11, 12, -5, 4, 1, 6 }; - -Plane Surface(24) = { 21 }; -Plane Surface(25) = { 22 }; - -Physical Surface("Fluid", 2) = { 24, 25 }; -Physical Line("UpStream", 10) = { 8 }; -Physical Line("DownStream", 11) = { 11 }; -Physical Line("Airfoil", 12) = { 1 ... 4 }; -Physical Line("Wake", 13) = { 5 }; - - - -//Line Loop(20) = {1,2,3,4}; -//Plane Surface(23) = {20}; -//Physical Surface("Cylinder", 1) = {23}; -//Physical Line("Outer", 10) = { 7 ... 12 }; - +Include "magnus_common.pro"; + +A = (BoxSize-1)/2.; +B = A; +R = 0.5; +lc = A/10; + + +If( Flag_Object == 0 ) // Cylinder + +lcr = 0.1; +Point(1) = { 2*R, 0.0, 0.0, lcr}; +Point(2) = { R, -R, 0.0, lcr}; +Point(3) = { 0.0, 0.0, 0.0, lcr}; +Point(4) = { R, R, 0.0 , lcr}; +Point(5) = { R, 0.0, 0.0 , lcr}; +Circle(1) = {1,5,2}; +Circle(2) = {2,5,3}; +Circle(3) = {3,5,4}; +Circle(4) = {4,5,1}; + +// Points to be connected with the outer boundary +PtA = 4; +PtB = 2; + +Else // naca airfoil + +lca = 0.03; +Include "nacaAirFoil.geo"; +PtA = 121; +PtB = 81; + +EndIf + +Point(306) = { 0, B, 0, lc}; +Point(307) = { 0,-B, 0, lc}; + +Line(5) = { PtA, 306 }; +Line(6) = { PtB, 307 }; + +Point(308) = {-A,-B, 0, lc}; +Point(309) = {-A, B, 0, lc}; +Point(310) = { A+1, B, 0, lc}; +Point(311) = { A+1,-B, 0, lc}; + +Line( 7) = { 306, 309 }; +Line( 8) = { 309, 308 }; +Line( 9) = { 308, 307 }; +Line(10) = { 307, 311 }; +Line(11) = { 311, 310 }; +Line(12) = { 310, 306 }; + +Line Loop(21) = { 7, 8, 9, -6, 2, 3, 5 }; // aire a gauche +Line Loop(22) = { 10, 11, 12, -5, 4, 1, 6 }; + +Plane Surface(24) = { 21 }; +Plane Surface(25) = { 22 }; + +Physical Surface("Fluid", 2) = { 24, 25 }; +Physical Line("UpStream", 10) = { 8 }; +Physical Line("DownStream", 11) = { 11 }; +Physical Line("Airfoil", 12) = { 1 ... 4 }; +Physical Line("Wake", 13) = { 5 }; + + + +//Line Loop(20) = {1,2,3,4}; +//Plane Surface(23) = {20}; +//Physical Surface("Cylinder", 1) = {23}; +//Physical Line("Outer", 10) = { 7 ... 12 }; + diff --git a/PotentialFlow/magnus.pro b/PotentialFlow/magnus.pro index 8319076..d3fa9a0 100644 --- a/PotentialFlow/magnus.pro +++ b/PotentialFlow/magnus.pro @@ -1,429 +1,420 @@ -/* ------------------------------------------------------------------- - Tutorial 6 : Potential flow and Magnus effect - - Features: - - Potential flow, irrotational flow - - Multivalued scalar field - - Lift and Magnus effect, stagnation points - - Run-time variables - - Elementary algorithms in the Resolution section - - Non-linear iteration to achieve Kutta's condition - - To compute the solution in a terminal: - getdp magnus.pro -solve PotentialFlow -pos PotentialFlow - gmsh magnus.geo velocity.pos - - To compute the solution interactively from the Gmsh GUI: - File > Open > magnus.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ -/* - This model solves a 2D potential flow around a cylinder or a naca airfoil - placed in a uniform "V_infinity" flow. - Potential flows are defined by - - V = grad phi => curl V = 0 - - where the multivalued scalar potential "phi" - presents a discontinuity of magnitude "deltaPhi" - across a cut "Sur_Cut". - In consequence, the velocity field "V" is curl-free - over the wole domain of analysis "Vol_rho" - but its circulation over any closed curve circling around the object, - a quantity often noted "Gamma" in the literature, - gives "deltaPhi" as a result. - The circulation of "V" over closed curves - not circling around the object is zero. - - In the getDP model, the discontinuity "deltaPhi" [m^2/s] - is defined as a global quantity in the Functional space of "phi". - The associated (dual) global quantity is the mass flow density, - noted "Dmdt", which has [kg/s] as a unit. - - Governing equations are - - div ( rho[] grad phi ) = 0 in Vol_rho - rho[] grad phi . n = rho[] Vn = 0 on Sur_Neu - - whereas the uniform velocity field "V_infinity" is imposed - by means of Dirichlet boundary conditions - on the upstream and downstream surfaces "GammaUp" and "GammaDown". - - Momentum equation is decoupled in case of stationary potential flows. - The velocity filed can be solved first, and the pressure - is obtained afterwards by invoking Bernoulli's theorem: - - p = -0.5 * rho[] * SquNorm [ {d phi} ] - - The "Lift" force in "Y" direction is then evaluated - either by integrating "p * CompY[Normal[]]" - over the contour of the object, - or by the Kutta-Jukowski theorem - - Lift = - L_z rho[] V_infinity Gamma - - which is a first order approximation of the former. - - "Cylinder" case: - Either the circulation "deltaPhi" or the mass flow rate "Dmdt" - can be imposed, according to the "Flag_Circ" flag. - The Lift is evaluated by both the integration of pressure - and the Kutta-Jukowski approximation. - - "Airfoil" case: - If "Flag_Circ == 1", the model works similar to the "Cylinder" case. - If "Flag_Circ == 0", the mass flow rate is not directly imposed - in this case. - It is determined so that the Kutta condition is verified. - This condition states that the actual value of "Dmdt" - is the one for which the stagnation point - (singularity of the velocity field) - is located at the trailing edge of the airfoil,. - This is true when the function - - argVTrail[] = ( Atan2[CompY[$1], CompX[$1] ] - Incidence ) / deg ; - - returns zero when evaluated for the velocity at a point "P_edge" - close to the trailing edge of the airfoil. - A non linear iteration is thus done by means of a pseudo-newton scheme, - updating the value of the imposed "Dmdt" until the norm of the residual - - f(V) = argVTrail[ {d phi } ] OnPoint {1.0001,0,0} - - comes below a fixed tolerance. - */ - -Include "magnus_common.pro"; - -Group{ - // Physical regions - Fluid = Region[ 2 ]; - GammaUp = Region[ 10 ]; - GammaDown = Region[ 11 ]; - GammaAirf = Region[ 12 ]; - GammaCut = Region[ 13 ]; - - // Abstract regions - Vol_rho = Region[ { Fluid } ]; - Sur_Dir = Region[ { GammaUp, GammaDown } ]; - Sur_Neu = Region[ { GammaAirf } ]; - Sur_Cut = Region[ { GammaCut } ]; -} - -Function{ - rho[] = 1.225; // kg/m^3 - MassFlowRate[] = MassFlowRate; // kg/s - DeltaPhi[] = DeltaPhi; // m^2/s - argVTrail[] = ( Atan2[CompY[$1], CompX[$1] ] - Incidence ) / deg ; -} - -Jacobian { - { Name Vol ; - Case { - { Region All ; Jacobian Vol ; } - } - } - { Name Sur ; - Case { - { Region All ; Jacobian Sur ; } - } - } -} - -Integration { - { Name Int ; - Case { - { Type Gauss ; - Case { - { GeoElement Point ; NumberOfPoints 1 ; } - { GeoElement Line ; NumberOfPoints 4 ; } - { GeoElement Triangle ; NumberOfPoints 6 ; } - { GeoElement Quadrangle ; NumberOfPoints 7 ; } - { GeoElement Tetrahedron ; NumberOfPoints 15 ; } - { GeoElement Hexahedron ; NumberOfPoints 34 ; } - } - } - } - } -} - -Constraint{ - { Name Dirichlet; Type Assign; - Case{ - // Boundary conditions for the V_infinity uniform flow - { Region GammaDown; Value Velocity*BoxSize; } - { Region GammaUp ; Value 0; } - } - } - { Name DeltaPhi; Type Assign; - Case{ - { Region Sur_Cut; Value DeltaPhi[]; } - } - } - { Name MassFlowRate; Type Assign; - Case{ - { Region Sur_Cut; Value MassFlowRate[]; } - } - } -} - -// Domains of definition used in the description of the function space -// These groups contain both volume and surface regions/elements. -Group{ - Dom_Vh = Region[ { Vol_rho, Sur_Dir, Sur_Neu, Sur_Cut } ]; - Dom_Cut = ElementsOf[ Dom_Vh, OnPositiveSideOf Sur_Cut ]; -} -FunctionSpace{ - { Name Vh; Type Form0; - BasisFunction{ - { Name vn; NameOfCoef phin; Function BF_Node; - Support Dom_Vh; Entity NodesOf[All]; } - { Name vc; NameOfCoef dphi; Function BF_GroupOfNodes; - Support Dom_Cut; Entity GroupsOfNodesOf[ Sur_Cut ];} - } - SubSpace { - { Name phiCont ; NameOfBasisFunction { vn } ; } - { Name phiDisc ; NameOfBasisFunction { vc } ; } - } - GlobalQuantity { - { Name Circ ; Type AliasOf ; NameOfCoef dphi ; } - { Name Dmdt ; Type AssociatedWith ; NameOfCoef dphi ; } - } - Constraint{ - {NameOfCoef phin; EntityType NodesOf; - NameOfConstraint Dirichlet;} - If( Flag_Circ ) - {NameOfCoef Circ; EntityType GroupsOfNodesOf; - NameOfConstraint DeltaPhi;} - Else - If( Flag_Object == 0 ) // if Cylinder only - // In case of the Airfoil, the contraint on Dmdt is omitted - // and replaced by an equation "Dmdt=$newDmdt" - // See the "Resolution" section. - {NameOfCoef Dmdt; EntityType GroupsOfNodesOf; - NameOfConstraint MassFlowRate;} - EndIf - EndIf - } - } -} - -Formulation{ - {Name PotentialFlow; Type FemEquation; - Quantity{ - {Name phi; Type Local; NameOfSpace Vh;} - { Name phiCont ; Type Local ; NameOfSpace Vh[phiCont] ; } - { Name phiDisc ; Type Local ; NameOfSpace Vh[phiDisc] ; } - { Name Circ ; Type Global ; NameOfSpace Vh[Circ] ; } - { Name Dmdt ; Type Global ; NameOfSpace Vh[Dmdt] ; } - } - Equation{ - Galerkin{[ rho[] * Dof{d phi}, {d phi}]; - In Vol_rho; Jacobian Vol; Integration Int;} - If( !Flag_Circ ) - GlobalTerm { [ -Dof{Dmdt} , {Circ} ] ; In Sur_Cut ; } - If( Flag_Object == 1 ) - GlobalTerm { [ -Dof{Dmdt} , {Dmdt} ] ; In Sur_Cut ; } - GlobalTerm { [ $newDmdt , {Dmdt} ] ; In Sur_Cut ; } - EndIf - EndIf - } - } -} - -Resolution{ - {Name PotentialFlow; - System{ - {Name A; NameOfFormulation PotentialFlow;} - } - Operation{ - InitSolution[A]; - - If( Flag_Circ || ( Flag_Object == 0 ) ) - - Generate[A]; Solve[A]; SaveSolution[A]; - PostOperation[Trailing]; - - Else - // A resolution can contain elementary algorithms. - // Available commands are: - // Evaluate[] : affectation of a run-time variable - // Test[]{}{} : logical test - // While[]{} : iteration - // Print[{}, Format ..., File ...] : formatted display - - // A pseudo-Newton iteration is implemented here - // to determine the value of Dmdt (in the Airfoil case) - // that verifies Kutta's condition. - // The run-time variable $newDmdt is used in Generate[A] - // whereas $circ, $dmdt, $argV and $phiTrailing are evaluated - // by the PostOperation[Trailing]. - - DeleteFile["KJiter.txt"]; - - Evaluate[$newDmdt = MassFlowRate]; - Evaluate[ $syscount = 0 ]; - Generate[A]; Solve[A]; SaveSolution[A]; - - Evaluate[$dmdtp = MassFlowRate]; - Evaluate[$argVp = DeltaPhi]; - PostOperation[Trailing]; - - Print[{$syscount, $circ, $dmdt, $argV}, - Format "iter = %3g Circ = %5.2f Dmdt = %5.2f argV = %5.2e"]; - - While[ Norm[ $argV ] > 1e-3 && $syscount < 50] { - Test[ $syscount && Norm[$argV-$argVp] > 1e-3 ] - {Evaluate[$jac = Min[ ($dmdt-$dmdtp)/($argV-$argVp), 0.2 ] ] ;} - {Evaluate[$jac = 0.2];} - - Evaluate[$newDmdt = $dmdt - $jac * $argV]; - Evaluate[ $syscount = $syscount + 1 ]; - Generate[A]; Solve[A]; SaveSolution[A]; - - Evaluate[$dmdtp = $dmdt]; - Evaluate[$argVp = $argV]; - PostOperation[Trailing]; - - Print[{$syscount, $circ, $dmdt, $jac, $argV}, - Format "iter = %3g Circ = %5.2f Dmdt = %5.2f jac=%5.2f argV = %5.3e"]; - } - EndIf - } - } -} - -PostProcessing{ - {Name PotentialFlow; NameOfFormulation PotentialFlow; - Quantity{ - {Name phi; Value { - Local{ [ {phi} ] ; In Dom_Vh; Jacobian Vol; } } } - { Name phiCont ; Value { - Local { [ { phiCont } ] ; In Dom_Vh ; Jacobian Vol ; } } } - { Name phiDisc ; Value { - Local { [ { phiDisc } ] ; In Dom_Vh ; Jacobian Vol ; } } } - {Name velocity; Value { - Local { [ {d phi} ]; In Dom_Vh; Jacobian Vol; } } } - {Name normVelocity; Value { - Local { [ Norm[{d phi}] ]; In Dom_Vh; Jacobian Vol; } } } - {Name pressure; Value { - Local { [-0.5*rho[]*SquNorm[ {d phi} ]]; - In Dom_Vh; Jacobian Vol; } } } - {Name Angle; Value { - Local{ [ argVTrail[{d phi}] ]; - In Dom_Vh; Jacobian Vol; } } } - - { Name Circ; Value { Local { [ {Circ} ]; In Sur_Cut; } } } - - { Name Dmdt; Value { Local { [ {Dmdt} ]; In Sur_Cut; } } } - - // Kutta-Jukowski approximation for Lift - { Name LiftKJ; Value { Local { [ -rho[]*{Circ}*Velocity ]; - In Sur_Cut; } } } - - // Lift computed with the real pressure field - { Name Lift; - Value { - Integral { [ -0.5*rho[]*SquNorm[{d phi}]*CompY[Normal[]] ]; - In Dom_Vh ; Jacobian Sur ; Integration Int; } - } - } - - { Name circulation; - Value { - Integral { [ {d phi} * Tangent[] ] ; - In Dom_Vh ; Jacobian Sur ; Integration Int; } - } - } - - } - } -} - -PostOperation{ - {Name PotentialFlow; NameOfPostProcessing PotentialFlow; - Operation{ - - Print[Circ, OnRegion Sur_Cut, File > "output.txt", Color "Ivory", - Format Table, SendToServer "Output/Circ" ]; - - Print[Dmdt, OnRegion Sur_Cut, File > "output.txt", Color "Ivory", - Format Table, SendToServer "Output/Dmdt" ]; - - Print[LiftKJ, OnRegion Sur_Cut, File > "output.txt", Color "Ivory", - Format Table, SendToServer "Output/LiftKJ" ]; - - Print[Lift[GammaAirf], OnGlobal, Format Table, - File > "output.txt", Color "Ivory", - SendToServer "Output/Lift"]; - - // Uncomment these lines to have more color maps - //Print[phi, OnElementsOf Vol_rho, File "phi.pos"]; - //Print[phiDisc, OnElementsOf Vol_rho, File "phiDisc.pos"]; - //Print[phiCont, OnElementsOf Vol_rho, File "phiCont.pos"]; - //Print[pressure, OnElementsOf Vol_rho, File "p.pos"]; - - Print[ velocity, OnElementsOf Vol_rho, File "velocity.pos"]; - Echo[ Str["l=PostProcessing.NbViews-1;", - "View[l].VectorType = 1;", - "View[l].LineWidth = 2;", - "View[l].ArrowSizeMax = 100;", - "View[l].CenterGlyphs = 1;"], - File "tmp.geo", LastTimeStepOnly] ; - - // Stagnation points are points where Norm[{d phi}] is zero - // This is better seen in log scale. - Print[normVelocity, OnElementsOf Vol_rho, File "p.pos"]; - Echo[Str["l=PostProcessing.NbViews-1;", - "View[l].Name = 'stagnation points';", - "View[l].ScaleType = 2; // log scale"], - File "tmp.geo"] ; - - If( Flag_Object == 0 ) - Print[phi, OnElementsOf Vol_rho, File "phi.pos"]; - Else - // Show the isovalue "phi=$PhiTrailing" - // which is perpendicular to the airfoil - // iff the Kutta condition is fulfilled - Print[phi, OnElementsOf Vol_rho, File "KJ.pos"]; - Print[{$phiTrailing, 1.001*$phiTrailing}, Format - Str["l=PostProcessing.NbViews-1;", - "View[l].Name = 'isovalue phiTrailing';", - "View[l].IntervalsType = 3;", - "Mesh.SurfaceEdges = 0; // hide mesh", - "View[l].RangeType = 2; // custom range", - "View[l].CustomMin = %g;", - "View[l].CustomMax = %g;"], - File "tmp.geo"] ; - EndIf - } - } -} - -PostOperation{ // for the Airfoil model - {Name Trailing; NameOfPostProcessing PotentialFlow; - Operation{ - Print[Circ, OnRegion Sur_Cut, File > "KJiter.txt", Format Table, - StoreInVariable $circ, - SendToServer "Output/Circ" ]; - Print[Dmdt, OnRegion Sur_Cut, File > "KJiter.txt", Format Table, - StoreInVariable $dmdt, - SendToServer "Output/Dmdt" ]; - // P_edge = {1.0001,0,0} - Print[phi, OnPoint {1.0001,0,0}, File > "KJiter.txt", Color "Ivory", - StoreInVariable $phiTrailing, - Format Table, SendToServer "Output/PhiTrailing"]; - - Print[Angle, OnPoint{1.0001,0,0}, File > "KJiter.txt", Color "Ivory", - StoreInVariable $argV, - Format Table, SendToServer "Output/argVTrailing"]; - } - } -} - -DefineConstant[ - R_ = {"PotentialFlow", Name "GetDP/1ResolutionChoices", Visible 0}, - C_ = {"-solve -pos", Name "GetDP/9ComputeCommand", Visible 0}, - P_ = {"PotentialFlow", Name "GetDP/2PostOperationChoices", Visible 0} -]; - +/* ------------------------------------------------------------------- + Tutorial 6 : Potential flow and Magnus effect + + Features: + - Potential flow, irrotational flow + - Multivalued scalar field + - Lift and Magnus effect, stagnation points + - Run-time variables + - Elementary algorithms in the Resolution section + - Non-linear iteration to achieve Kutta's condition + + To compute the solution in a terminal: + getdp magnus.pro -solve PotentialFlow -pos PotentialFlow + gmsh magnus.geo velocity.pos + + To compute the solution interactively from the Gmsh GUI: + File > Open > magnus.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ +/* + This model solves a 2D potential flow around a cylinder or a naca airfoil + placed in a uniform "V_infinity" flow. Potential flows are defined by + + V = grad phi => curl V = 0 + + where the multivalued scalar potential "phi" presents a discontinuity of + magnitude "deltaPhi" across a cut "Sur_Cut". In consequence, the velocity + field "V" is curl-free over the wole domain of analysis "Vol_rho" but its + circulation over any closed curve circling around the object, a quantity + often noted "Gamma" in the literature, gives "deltaPhi" as a result. The + circulation of "V" over closed curves not circling around the object is zero. + + In the GetDP model, the discontinuity "deltaPhi" [m^2/s] is defined as a + global quantity in the Functional space of "phi". The associated (dual) + global quantity is the mass flow density, noted "Dmdt", which has [kg/s] as a + unit. + + Governing equations are + + div ( rho[] grad phi ) = 0 in Vol_rho + rho[] grad phi . n = rho[] Vn = 0 on Sur_Neu + + whereas the uniform velocity field "V_infinity" is imposed by means of + Dirichlet boundary conditions on the upstream and downstream surfaces + "GammaUp" and "GammaDown". + + Momentum equation is decoupled in case of stationary potential flows. The + velocity filed can be solved first, and the pressure is obtained afterwards + by invoking Bernoulli's theorem: + + p = -0.5 * rho[] * SquNorm [ {d phi} ] + + The "Lift" force in "Y" direction is then evaluated either by integrating "p + * CompY[Normal[]]" over the contour of the object, or by the Kutta-Jukowski + theorem + + Lift = - L_z rho[] V_infinity Gamma + + which is a first order approximation of the former. + + "Cylinder" case: + + Either the circulation "deltaPhi" or the mass flow rate "Dmdt" can be + imposed, according to the "Flag_Circ" flag. The Lift is evaluated by both + the integration of pressure and the Kutta-Jukowski approximation. + + "Airfoil" case: + + - If "Flag_Circ == 1", the model works similar to the "Cylinder" case. + + - If "Flag_Circ == 0", the mass flow rate is not directly imposed in this + case. It is determined so that the Kutta condition is verified. This + condition states that the actual value of "Dmdt" is the one for which the + stagnation point (singularity of the velocity field) is located at the + trailing edge of the airfoil,. This is true when the function + + argVTrail[] = ( Atan2[CompY[$1], CompX[$1] ] - Incidence ) / deg ; + + returns zero when evaluated for the velocity at a point "P_edge" close to + the trailing edge of the airfoil. A non linear iteration is thus done by + means of a pseudo-newton scheme, updating the value of the imposed "Dmdt" + until the norm of the residual + + f(V) = argVTrail[ {d phi } ] OnPoint {1.0001,0,0} + + comes below a fixed tolerance. */ + +Include "magnus_common.pro"; + +Group{ + // Physical regions + Fluid = Region[ 2 ]; + GammaUp = Region[ 10 ]; + GammaDown = Region[ 11 ]; + GammaAirf = Region[ 12 ]; + GammaCut = Region[ 13 ]; + + // Abstract regions + Vol_rho = Region[ { Fluid } ]; + Sur_Dir = Region[ { GammaUp, GammaDown } ]; + Sur_Neu = Region[ { GammaAirf } ]; + Sur_Cut = Region[ { GammaCut } ]; +} + +Function{ + rho[] = 1.225; // kg/m^3 + MassFlowRate[] = MassFlowRate; // kg/s + DeltaPhi[] = DeltaPhi; // m^2/s + argVTrail[] = ( Atan2[CompY[$1], CompX[$1] ] - Incidence ) / deg ; +} + +Jacobian { + { Name Vol ; + Case { + { Region All ; Jacobian Vol ; } + } + } + { Name Sur ; + Case { + { Region All ; Jacobian Sur ; } + } + } +} + +Integration { + { Name Int ; + Case { + { Type Gauss ; + Case { + { GeoElement Point ; NumberOfPoints 1 ; } + { GeoElement Line ; NumberOfPoints 4 ; } + { GeoElement Triangle ; NumberOfPoints 6 ; } + { GeoElement Quadrangle ; NumberOfPoints 7 ; } + { GeoElement Tetrahedron ; NumberOfPoints 15 ; } + { GeoElement Hexahedron ; NumberOfPoints 34 ; } + } + } + } + } +} + +Constraint{ + { Name Dirichlet; Type Assign; + Case{ + // Boundary conditions for the V_infinity uniform flow + { Region GammaDown; Value Velocity*BoxSize; } + { Region GammaUp ; Value 0; } + } + } + { Name DeltaPhi; Type Assign; + Case{ + { Region Sur_Cut; Value DeltaPhi[]; } + } + } + { Name MassFlowRate; Type Assign; + Case{ + { Region Sur_Cut; Value MassFlowRate[]; } + } + } +} + +// Domains of definition used in the description of the function space +// These groups contain both volume and surface regions/elements. +Group{ + Dom_Vh = Region[ { Vol_rho, Sur_Dir, Sur_Neu, Sur_Cut } ]; + Dom_Cut = ElementsOf[ Dom_Vh, OnPositiveSideOf Sur_Cut ]; +} +FunctionSpace{ + { Name Vh; Type Form0; + BasisFunction{ + { Name vn; NameOfCoef phin; Function BF_Node; + Support Dom_Vh; Entity NodesOf[All]; } + { Name vc; NameOfCoef dphi; Function BF_GroupOfNodes; + Support Dom_Cut; Entity GroupsOfNodesOf[ Sur_Cut ];} + } + SubSpace { + { Name phiCont ; NameOfBasisFunction { vn } ; } + { Name phiDisc ; NameOfBasisFunction { vc } ; } + } + GlobalQuantity { + { Name Circ ; Type AliasOf ; NameOfCoef dphi ; } + { Name Dmdt ; Type AssociatedWith ; NameOfCoef dphi ; } + } + Constraint{ + {NameOfCoef phin; EntityType NodesOf; + NameOfConstraint Dirichlet;} + If( Flag_Circ ) + {NameOfCoef Circ; EntityType GroupsOfNodesOf; + NameOfConstraint DeltaPhi;} + Else + If( Flag_Object == 0 ) // if Cylinder only + // In case of the Airfoil, the contraint on Dmdt is omitted + // and replaced by an equation "Dmdt=$newDmdt" + // See the "Resolution" section. + {NameOfCoef Dmdt; EntityType GroupsOfNodesOf; + NameOfConstraint MassFlowRate;} + EndIf + EndIf + } + } +} + +Formulation{ + {Name PotentialFlow; Type FemEquation; + Quantity{ + {Name phi; Type Local; NameOfSpace Vh;} + { Name phiCont ; Type Local ; NameOfSpace Vh[phiCont] ; } + { Name phiDisc ; Type Local ; NameOfSpace Vh[phiDisc] ; } + { Name Circ ; Type Global ; NameOfSpace Vh[Circ] ; } + { Name Dmdt ; Type Global ; NameOfSpace Vh[Dmdt] ; } + } + Equation{ + Integral{[ rho[] * Dof{d phi}, {d phi}]; + In Vol_rho; Jacobian Vol; Integration Int;} + If( !Flag_Circ ) + GlobalTerm { [ -Dof{Dmdt} , {Circ} ] ; In Sur_Cut ; } + If( Flag_Object == 1 ) + GlobalTerm { [ -Dof{Dmdt} , {Dmdt} ] ; In Sur_Cut ; } + GlobalTerm { [ $newDmdt , {Dmdt} ] ; In Sur_Cut ; } + EndIf + EndIf + } + } +} + +Resolution{ + {Name PotentialFlow; + System{ + {Name A; NameOfFormulation PotentialFlow;} + } + Operation{ + InitSolution[A]; + + If( Flag_Circ || ( Flag_Object == 0 ) ) + + Generate[A]; Solve[A]; SaveSolution[A]; + PostOperation[Trailing]; + + Else + // A resolution can contain elementary algorithms. + // Available commands are: + // Evaluate[] : affectation of a run-time variable + // Test[]{}{} : logical test + // While[]{} : iteration + // Print[{}, Format ..., File ...] : formatted display + + // A pseudo-Newton iteration is implemented here + // to determine the value of Dmdt (in the Airfoil case) + // that verifies Kutta's condition. + // The run-time variable $newDmdt is used in Generate[A] + // whereas $circ, $dmdt, $argV and $phiTrailing are evaluated + // by the PostOperation[Trailing]. + + DeleteFile["KJiter.txt"]; + + Evaluate[$newDmdt = MassFlowRate]; + Evaluate[ $syscount = 0 ]; + Generate[A]; Solve[A]; SaveSolution[A]; + + Evaluate[$dmdtp = MassFlowRate]; + Evaluate[$argVp = DeltaPhi]; + PostOperation[Trailing]; + + Print[{$syscount, $circ, $dmdt, $argV}, + Format "iter = %3g Circ = %5.2f Dmdt = %5.2f argV = %5.2e"]; + + While[ Norm[ $argV ] > 1e-3 && $syscount < 50] { + Test[ $syscount && Norm[$argV-$argVp] > 1e-3 ] + {Evaluate[$jac = Min[ ($dmdt-$dmdtp)/($argV-$argVp), 0.2 ] ] ;} + {Evaluate[$jac = 0.2];} + + Evaluate[$newDmdt = $dmdt - $jac * $argV]; + Evaluate[ $syscount = $syscount + 1 ]; + Generate[A]; Solve[A]; SaveSolution[A]; + + Evaluate[$dmdtp = $dmdt]; + Evaluate[$argVp = $argV]; + PostOperation[Trailing]; + + Print[{$syscount, $circ, $dmdt, $jac, $argV}, + Format "iter = %3g Circ = %5.2f Dmdt = %5.2f jac=%5.2f argV = %5.3e"]; + } + EndIf + } + } +} + +PostProcessing{ + {Name PotentialFlow; NameOfFormulation PotentialFlow; + Quantity{ + {Name phi; Value { + Local{ [ {phi} ] ; In Dom_Vh; Jacobian Vol; } } } + { Name phiCont ; Value { + Local { [ { phiCont } ] ; In Dom_Vh ; Jacobian Vol ; } } } + { Name phiDisc ; Value { + Local { [ { phiDisc } ] ; In Dom_Vh ; Jacobian Vol ; } } } + {Name velocity; Value { + Local { [ {d phi} ]; In Dom_Vh; Jacobian Vol; } } } + {Name normVelocity; Value { + Local { [ Norm[{d phi}] ]; In Dom_Vh; Jacobian Vol; } } } + {Name pressure; Value { + Local { [-0.5*rho[]*SquNorm[ {d phi} ]]; + In Dom_Vh; Jacobian Vol; } } } + {Name Angle; Value { + Local{ [ argVTrail[{d phi}] ]; + In Dom_Vh; Jacobian Vol; } } } + + { Name Circ; Value { Local { [ {Circ} ]; In Sur_Cut; } } } + + { Name Dmdt; Value { Local { [ {Dmdt} ]; In Sur_Cut; } } } + + // Kutta-Jukowski approximation for Lift + { Name LiftKJ; Value { Local { [ -rho[]*{Circ}*Velocity ]; + In Sur_Cut; } } } + + // Lift computed with the real pressure field + { Name Lift; + Value { + Integral { [ -0.5*rho[]*SquNorm[{d phi}]*CompY[Normal[]] ]; + In Dom_Vh ; Jacobian Sur ; Integration Int; } + } + } + + { Name circulation; + Value { + Integral { [ {d phi} * Tangent[] ] ; + In Dom_Vh ; Jacobian Sur ; Integration Int; } + } + } + + } + } +} + +PostOperation{ + {Name PotentialFlow; NameOfPostProcessing PotentialFlow; + Operation{ + + Print[Circ, OnRegion Sur_Cut, File > "output.txt", Color "Ivory", + Format Table, SendToServer "Output/Circ" ]; + + Print[Dmdt, OnRegion Sur_Cut, File > "output.txt", Color "Ivory", + Format Table, SendToServer "Output/Dmdt" ]; + + Print[LiftKJ, OnRegion Sur_Cut, File > "output.txt", Color "Ivory", + Format Table, SendToServer "Output/LiftKJ" ]; + + Print[Lift[GammaAirf], OnGlobal, Format Table, + File > "output.txt", Color "Ivory", + SendToServer "Output/Lift"]; + + // Uncomment these lines to have more color maps + //Print[phi, OnElementsOf Vol_rho, File "phi.pos"]; + //Print[phiDisc, OnElementsOf Vol_rho, File "phiDisc.pos"]; + //Print[phiCont, OnElementsOf Vol_rho, File "phiCont.pos"]; + //Print[pressure, OnElementsOf Vol_rho, File "p.pos"]; + + Print[ velocity, OnElementsOf Vol_rho, File "velocity.pos"]; + Echo[ Str["l=PostProcessing.NbViews-1;", + "View[l].VectorType = 1;", + "View[l].LineWidth = 2;", + "View[l].ArrowSizeMax = 100;", + "View[l].CenterGlyphs = 1;"], + File "tmp.geo", LastTimeStepOnly] ; + + // Stagnation points are points where Norm[{d phi}] is zero + // This is better seen in log scale. + Print[normVelocity, OnElementsOf Vol_rho, File "p.pos"]; + Echo[Str["l=PostProcessing.NbViews-1;", + "View[l].Name = 'stagnation points';", + "View[l].ScaleType = 2; // log scale"], + File "tmp.geo"] ; + + If( Flag_Object == 0 ) + Print[phi, OnElementsOf Vol_rho, File "phi.pos"]; + Else + // Show the isovalue "phi=$PhiTrailing" + // which is perpendicular to the airfoil + // iff the Kutta condition is fulfilled + Print[phi, OnElementsOf Vol_rho, File "KJ.pos"]; + Print[{$phiTrailing, 1.001*$phiTrailing}, Format + Str["l=PostProcessing.NbViews-1;", + "View[l].Name = 'isovalue phiTrailing';", + "View[l].IntervalsType = 3;", + "Mesh.SurfaceEdges = 0; // hide mesh", + "View[l].RangeType = 2; // custom range", + "View[l].CustomMin = %g;", + "View[l].CustomMax = %g;"], + File "tmp.geo"] ; + EndIf + } + } +} + +PostOperation{ // for the Airfoil model + {Name Trailing; NameOfPostProcessing PotentialFlow; + Operation{ + Print[Circ, OnRegion Sur_Cut, File > "KJiter.txt", Format Table, + StoreInVariable $circ, + SendToServer "Output/Circ" ]; + Print[Dmdt, OnRegion Sur_Cut, File > "KJiter.txt", Format Table, + StoreInVariable $dmdt, + SendToServer "Output/Dmdt" ]; + // P_edge = {1.0001,0,0} + Print[phi, OnPoint {1.0001,0,0}, File > "KJiter.txt", Color "Ivory", + StoreInVariable $phiTrailing, + Format Table, SendToServer "Output/PhiTrailing"]; + + Print[Angle, OnPoint{1.0001,0,0}, File > "KJiter.txt", Color "Ivory", + StoreInVariable $argV, + Format Table, SendToServer "Output/argVTrailing"]; + } + } +} + +DefineConstant[ + R_ = {"PotentialFlow", Name "GetDP/1ResolutionChoices", Visible 0}, + C_ = {"-solve -pos", Name "GetDP/9ComputeCommand", Visible 0}, + P_ = {"PotentialFlow", Name "GetDP/2PostOperationChoices", Visible 0} +]; diff --git a/PotentialFlow/magnus_common.pro b/PotentialFlow/magnus_common.pro index b9c659b..f1c65c4 100644 --- a/PotentialFlow/magnus_common.pro +++ b/PotentialFlow/magnus_common.pro @@ -1,27 +1,27 @@ -cm = 1e-2; -deg = Pi/180; -kmh = 10./36.; - -Flag_Circ = - DefineNumber[0, Name "Model/Impose circulation", Choices {0, 1} ]; -Flag_Object = - DefineNumber[1, Name "Model/Object", - Choices {0="Cylinder", 1="Airfoil"} ]; - -BoxSize = - DefineNumber[7, Name "Model/Air box size [m]", Help "In flow direction."]; -Velocity = kmh* - DefineNumber[100, Name "Model/V", Label "Model/Flow velocity [km/h]"]; -Incidence = -deg* - DefineNumber[10, Name "Model/Angle of attack [deg]", Visible Flag_Object]; - -// Negative circulation for a positive lift. -DeltaPhi = (-1)* - DefineNumber[10, Name "Model/Circ", Visible Flag_Circ, - Min 0, Max 20, Step 2, - Label "Circulation around foil [m^2/s]"]; - -MassFlowRate = - DefineNumber[-100, Name "Model/Dmdt", Visible !Flag_Circ, - Label "Mass flow rate [kg/s]"]; - +cm = 1e-2; +deg = Pi/180; +kmh = 10./36.; + +Flag_Circ = + DefineNumber[0, Name "Model/Impose circulation", Choices {0, 1} ]; +Flag_Object = + DefineNumber[1, Name "Model/Object", + Choices {0="Cylinder", 1="Airfoil"} ]; + +BoxSize = + DefineNumber[7, Name "Model/Air box size [m]", Help "In flow direction."]; +Velocity = kmh* + DefineNumber[100, Name "Model/V", Label "Model/Flow velocity [km/h]"]; +Incidence = -deg* + DefineNumber[10, Name "Model/Angle of attack [deg]", Visible Flag_Object]; + +// Negative circulation for a positive lift. +DeltaPhi = (-1)* + DefineNumber[10, Name "Model/Circ", Visible Flag_Circ, + Min 0, Max 20, Step 2, + Label "Circulation around foil [m^2/s]"]; + +MassFlowRate = + DefineNumber[-100, Name "Model/Dmdt", Visible !Flag_Circ, + Label "Mass flow rate [kg/s]"]; + diff --git a/PotentialFlow/nacaAirfoil.geo b/PotentialFlow/nacaAirfoil.geo index 9ef6199..764a17d 100644 --- a/PotentialFlow/nacaAirfoil.geo +++ b/PotentialFlow/nacaAirfoil.geo @@ -1,222 +1,222 @@ - - -Point(1) = {1.000000,0.000000,0,lca}; -Point(2) = {0.999753,-0.000035,0,lca}; -Point(3) = {0.999013,-0.000141,0,lca}; -Point(4) = {0.997781,-0.000317,0,lca}; -Point(5) = {0.996057,-0.000562,0,lca}; -Point(6) = {0.993844,-0.000876,0,lca}; -Point(7) = {0.991144,-0.001258,0,lca}; -Point(8) = {0.987958,-0.001707,0,lca}; -Point(9) = {0.984292,-0.002222,0,lca}; -Point(10) = {0.980147,-0.002801,0,lca}; -Point(11) = {0.975528,-0.003443,0,lca}; -Point(12) = {0.970440,-0.004147,0,lca}; -Point(13) = {0.964888,-0.004909,0,lca}; -Point(14) = {0.958877,-0.005729,0,lca}; -Point(15) = {0.952414,-0.006603,0,lca}; -Point(16) = {0.945503,-0.007531,0,lca}; -Point(17) = {0.938153,-0.008510,0,lca}; -Point(18) = {0.930371,-0.009537,0,lca}; -Point(19) = {0.922164,-0.010610,0,lca}; -Point(20) = {0.913540,-0.011726,0,lca}; -Point(21) = {0.904508,-0.012883,0,lca}; -Point(22) = {0.895078,-0.014079,0,lca}; -Point(23) = {0.885257,-0.015310,0,lca}; -Point(24) = {0.875056,-0.016574,0,lca}; -Point(25) = {0.864484,-0.017868,0,lca}; -Point(26) = {0.853553,-0.019189,0,lca}; -Point(27) = {0.842274,-0.020535,0,lca}; -Point(28) = {0.830656,-0.021904,0,lca}; -Point(29) = {0.818712,-0.023291,0,lca}; -Point(30) = {0.806454,-0.024694,0,lca}; -Point(31) = {0.793893,-0.026111,0,lca}; -Point(32) = {0.781042,-0.027539,0,lca}; -Point(33) = {0.767913,-0.028974,0,lca}; -Point(34) = {0.754521,-0.030414,0,lca}; -Point(35) = {0.740877,-0.031856,0,lca}; -Point(36) = {0.726995,-0.033296,0,lca}; -Point(37) = {0.712890,-0.034733,0,lca}; -Point(38) = {0.698574,-0.036163,0,lca}; -Point(39) = {0.684062,-0.037582,0,lca}; -Point(40) = {0.669369,-0.038988,0,lca}; -Point(41) = {0.654508,-0.040378,0,lca}; -Point(42) = {0.639496,-0.041747,0,lca}; -Point(43) = {0.624345,-0.043094,0,lca}; -Point(44) = {0.609072,-0.044414,0,lca}; -Point(45) = {0.593691,-0.045705,0,lca}; -Point(46) = {0.578217,-0.046962,0,lca}; -Point(47) = {0.562667,-0.048182,0,lca}; -Point(48) = {0.547054,-0.049362,0,lca}; -Point(49) = {0.531395,-0.050499,0,lca}; -Point(50) = {0.515705,-0.051587,0,lca}; -Point(51) = {0.500000,-0.052625,0,lca}; -Point(52) = {0.484295,-0.053608,0,lca}; -Point(53) = {0.468605,-0.054534,0,lca}; -Point(54) = {0.452946,-0.055397,0,lca}; -Point(55) = {0.437333,-0.056195,0,lca}; -Point(56) = {0.421783,-0.056924,0,lca}; -Point(57) = {0.406309,-0.057581,0,lca}; -Point(58) = {0.390928,-0.058163,0,lca}; -Point(59) = {0.375655,-0.058666,0,lca}; -Point(60) = {0.360504,-0.059087,0,lca}; -Point(61) = {0.345492,-0.059424,0,lca}; -Point(62) = {0.330631,-0.059674,0,lca}; -Point(63) = {0.315938,-0.059834,0,lca}; -Point(64) = {0.301426,-0.059902,0,lca}; -Point(65) = {0.287110,-0.059876,0,lca}; -Point(66) = {0.273005,-0.059754,0,lca}; -Point(67) = {0.259123,-0.059535,0,lca}; -Point(68) = {0.245479,-0.059217,0,lca}; -Point(69) = {0.232087,-0.058799,0,lca}; -Point(70) = {0.218958,-0.058280,0,lca}; -Point(71) = {0.206107,-0.057661,0,lca}; -Point(72) = {0.193546,-0.056940,0,lca}; -Point(73) = {0.181288,-0.056119,0,lca}; -Point(74) = {0.169344,-0.055197,0,lca}; -Point(75) = {0.157726,-0.054176,0,lca}; -Point(76) = {0.146447,-0.053056,0,lca}; -Point(77) = {0.135516,-0.051839,0,lca}; -Point(78) = {0.124944,-0.050527,0,lca}; -Point(79) = {0.114743,-0.049121,0,lca}; -Point(80) = {0.104922,-0.047624,0,lca}; -Point(81) = {0.095492,-0.046037,0,lca}; -Point(82) = {0.086460,-0.044364,0,lca}; -Point(83) = {0.077836,-0.042608,0,lca}; -Point(84) = {0.069629,-0.040770,0,lca}; -Point(85) = {0.061847,-0.038854,0,lca}; -Point(86) = {0.054497,-0.036863,0,lca}; -Point(87) = {0.047586,-0.034800,0,lca}; -Point(88) = {0.041123,-0.032668,0,lca}; -Point(89) = {0.035112,-0.030471,0,lca}; -Point(90) = {0.029560,-0.028212,0,lca}; -Point(91) = {0.024472,-0.025893,0,lca}; -Point(92) = {0.019853,-0.023517,0,lca}; -Point(93) = {0.015708,-0.021088,0,lca}; -Point(94) = {0.012042,-0.018607,0,lca}; -Point(95) = {0.008856,-0.016078,0,lca}; -Point(96) = {0.006156,-0.013503,0,lca}; -Point(97) = {0.003943,-0.010884,0,lca}; -Point(98) = {0.002219,-0.008223,0,lca}; -Point(99) = {0.000987,-0.005521,0,lca}; -Point(100) = {0.000247,-0.002779,0,lca}; -Point(101) = {0.000000,0.000000,0,lca}; -Point(102) = {0.000247,0.002779,0,lca}; -Point(103) = {0.000987,0.005521,0,lca}; -Point(104) = {0.002219,0.008223,0,lca}; -Point(105) = {0.003943,0.010884,0,lca}; -Point(106) = {0.006156,0.013503,0,lca}; -Point(107) = {0.008856,0.016078,0,lca}; -Point(108) = {0.012042,0.018607,0,lca}; -Point(109) = {0.015708,0.021088,0,lca}; -Point(110) = {0.019853,0.023517,0,lca}; -Point(111) = {0.024472,0.025893,0,lca}; -Point(112) = {0.029560,0.028212,0,lca}; -Point(113) = {0.035112,0.030471,0,lca}; -Point(114) = {0.041123,0.032668,0,lca}; -Point(115) = {0.047586,0.034800,0,lca}; -Point(116) = {0.054497,0.036863,0,lca}; -Point(117) = {0.061847,0.038854,0,lca}; -Point(118) = {0.069629,0.040770,0,lca}; -Point(119) = {0.077836,0.042608,0,lca}; -Point(120) = {0.086460,0.044364,0,lca}; -Point(121) = {0.095492,0.046037,0,lca}; -Point(122) = {0.104922,0.047624,0,lca}; -Point(123) = {0.114743,0.049121,0,lca}; -Point(124) = {0.124944,0.050527,0,lca}; -Point(125) = {0.135516,0.051839,0,lca}; -Point(126) = {0.146447,0.053056,0,lca}; -Point(127) = {0.157726,0.054176,0,lca}; -Point(128) = {0.169344,0.055197,0,lca}; -Point(129) = {0.181288,0.056119,0,lca}; -Point(130) = {0.193546,0.056940,0,lca}; -Point(131) = {0.206107,0.057661,0,lca}; -Point(132) = {0.218958,0.058280,0,lca}; -Point(133) = {0.232087,0.058799,0,lca}; -Point(134) = {0.245479,0.059217,0,lca}; -Point(135) = {0.259123,0.059535,0,lca}; -Point(136) = {0.273005,0.059754,0,lca}; -Point(137) = {0.287110,0.059876,0,lca}; -Point(138) = {0.301426,0.059902,0,lca}; -Point(139) = {0.315938,0.059834,0,lca}; -Point(140) = {0.330631,0.059674,0,lca}; -Point(141) = {0.345492,0.059424,0,lca}; -Point(142) = {0.360504,0.059087,0,lca}; -Point(143) = {0.375655,0.058666,0,lca}; -Point(144) = {0.390928,0.058163,0,lca}; -Point(145) = {0.406309,0.057581,0,lca}; -Point(146) = {0.421783,0.056924,0,lca}; -Point(147) = {0.437333,0.056195,0,lca}; -Point(148) = {0.452946,0.055397,0,lca}; -Point(149) = {0.468605,0.054534,0,lca}; -Point(150) = {0.484295,0.053608,0,lca}; -Point(151) = {0.500000,0.052625,0,lca}; -Point(152) = {0.515705,0.051587,0,lca}; -Point(153) = {0.531395,0.050499,0,lca}; -Point(154) = {0.547054,0.049362,0,lca}; -Point(155) = {0.562667,0.048182,0,lca}; -Point(156) = {0.578217,0.046962,0,lca}; -Point(157) = {0.593691,0.045705,0,lca}; -Point(158) = {0.609072,0.044414,0,lca}; -Point(159) = {0.624345,0.043094,0,lca}; -Point(160) = {0.639496,0.041747,0,lca}; -Point(161) = {0.654508,0.040378,0,lca}; -Point(162) = {0.669369,0.038988,0,lca}; -Point(163) = {0.684062,0.037582,0,lca}; -Point(164) = {0.698574,0.036163,0,lca}; -Point(165) = {0.712890,0.034733,0,lca}; -Point(166) = {0.726995,0.033296,0,lca}; -Point(167) = {0.740877,0.031856,0,lca}; -Point(168) = {0.754521,0.030414,0,lca}; -Point(169) = {0.767913,0.028974,0,lca}; -Point(170) = {0.781042,0.027539,0,lca}; -Point(171) = {0.793893,0.026111,0,lca}; -Point(172) = {0.806454,0.024694,0,lca}; -Point(173) = {0.818712,0.023291,0,lca}; -Point(174) = {0.830656,0.021904,0,lca}; -Point(175) = {0.842274,0.020535,0,lca}; -Point(176) = {0.853553,0.019189,0,lca}; -Point(177) = {0.864484,0.017868,0,lca}; -Point(178) = {0.875056,0.016574,0,lca}; -Point(179) = {0.885257,0.015310,0,lca}; -Point(180) = {0.895078,0.014079,0,lca}; -Point(181) = {0.904508,0.012883,0,lca}; -Point(182) = {0.913540,0.011726,0,lca}; -Point(183) = {0.922164,0.010610,0,lca}; -Point(184) = {0.930371,0.009537,0,lca}; -Point(185) = {0.938153,0.008510,0,lca}; -Point(186) = {0.945503,0.007531,0,lca}; -Point(187) = {0.952414,0.006603,0,lca}; -Point(188) = {0.958877,0.005729,0,lca}; -Point(189) = {0.964888,0.004909,0,lca}; -Point(190) = {0.970440,0.004147,0,lca}; -Point(191) = {0.975528,0.003443,0,lca}; -Point(192) = {0.980147,0.002801,0,lca}; -Point(193) = {0.984292,0.002222,0,lca}; -Point(194) = {0.987958,0.001707,0,lca}; -Point(195) = {0.991144,0.001258,0,lca}; -Point(196) = {0.993844,0.000876,0,lca}; -Point(197) = {0.996057,0.000562,0,lca}; -Point(198) = {0.997781,0.000317,0,lca}; -Point(199) = {0.999013,0.000141,0,lca}; -Point(200) = {0.999753,0.000035,0,lca}; - -//Points numerotation: -numberLeadingEgde = 101 ; -numberLowerSurface = 81 ; -numberUpperSurface = 121 ; - -//Distances: -distanceTrailingLowerPoint = 0.908262 ; -distanceLowerUpperPoint = 0.222905 ; -distanceUpperTrailingPoint = 0.908262 ; - -Line(1) = { 1 ... 81 }; -Line(2) = { 81 ... 101 }; -Line(3) = { 101 ... 121 }; -Line(4) = { 121 ... 200, 1 }; - -Rotate { {0,0,1}, {1,0,0}, Incidence } { Line { 1 ... 4 } ; } - -/* Line Loop(1) = {1,2,3,4}; */ -/* Plane Surface(1) = {1}; */ + + +Point(1) = {1.000000,0.000000,0,lca}; +Point(2) = {0.999753,-0.000035,0,lca}; +Point(3) = {0.999013,-0.000141,0,lca}; +Point(4) = {0.997781,-0.000317,0,lca}; +Point(5) = {0.996057,-0.000562,0,lca}; +Point(6) = {0.993844,-0.000876,0,lca}; +Point(7) = {0.991144,-0.001258,0,lca}; +Point(8) = {0.987958,-0.001707,0,lca}; +Point(9) = {0.984292,-0.002222,0,lca}; +Point(10) = {0.980147,-0.002801,0,lca}; +Point(11) = {0.975528,-0.003443,0,lca}; +Point(12) = {0.970440,-0.004147,0,lca}; +Point(13) = {0.964888,-0.004909,0,lca}; +Point(14) = {0.958877,-0.005729,0,lca}; +Point(15) = {0.952414,-0.006603,0,lca}; +Point(16) = {0.945503,-0.007531,0,lca}; +Point(17) = {0.938153,-0.008510,0,lca}; +Point(18) = {0.930371,-0.009537,0,lca}; +Point(19) = {0.922164,-0.010610,0,lca}; +Point(20) = {0.913540,-0.011726,0,lca}; +Point(21) = {0.904508,-0.012883,0,lca}; +Point(22) = {0.895078,-0.014079,0,lca}; +Point(23) = {0.885257,-0.015310,0,lca}; +Point(24) = {0.875056,-0.016574,0,lca}; +Point(25) = {0.864484,-0.017868,0,lca}; +Point(26) = {0.853553,-0.019189,0,lca}; +Point(27) = {0.842274,-0.020535,0,lca}; +Point(28) = {0.830656,-0.021904,0,lca}; +Point(29) = {0.818712,-0.023291,0,lca}; +Point(30) = {0.806454,-0.024694,0,lca}; +Point(31) = {0.793893,-0.026111,0,lca}; +Point(32) = {0.781042,-0.027539,0,lca}; +Point(33) = {0.767913,-0.028974,0,lca}; +Point(34) = {0.754521,-0.030414,0,lca}; +Point(35) = {0.740877,-0.031856,0,lca}; +Point(36) = {0.726995,-0.033296,0,lca}; +Point(37) = {0.712890,-0.034733,0,lca}; +Point(38) = {0.698574,-0.036163,0,lca}; +Point(39) = {0.684062,-0.037582,0,lca}; +Point(40) = {0.669369,-0.038988,0,lca}; +Point(41) = {0.654508,-0.040378,0,lca}; +Point(42) = {0.639496,-0.041747,0,lca}; +Point(43) = {0.624345,-0.043094,0,lca}; +Point(44) = {0.609072,-0.044414,0,lca}; +Point(45) = {0.593691,-0.045705,0,lca}; +Point(46) = {0.578217,-0.046962,0,lca}; +Point(47) = {0.562667,-0.048182,0,lca}; +Point(48) = {0.547054,-0.049362,0,lca}; +Point(49) = {0.531395,-0.050499,0,lca}; +Point(50) = {0.515705,-0.051587,0,lca}; +Point(51) = {0.500000,-0.052625,0,lca}; +Point(52) = {0.484295,-0.053608,0,lca}; +Point(53) = {0.468605,-0.054534,0,lca}; +Point(54) = {0.452946,-0.055397,0,lca}; +Point(55) = {0.437333,-0.056195,0,lca}; +Point(56) = {0.421783,-0.056924,0,lca}; +Point(57) = {0.406309,-0.057581,0,lca}; +Point(58) = {0.390928,-0.058163,0,lca}; +Point(59) = {0.375655,-0.058666,0,lca}; +Point(60) = {0.360504,-0.059087,0,lca}; +Point(61) = {0.345492,-0.059424,0,lca}; +Point(62) = {0.330631,-0.059674,0,lca}; +Point(63) = {0.315938,-0.059834,0,lca}; +Point(64) = {0.301426,-0.059902,0,lca}; +Point(65) = {0.287110,-0.059876,0,lca}; +Point(66) = {0.273005,-0.059754,0,lca}; +Point(67) = {0.259123,-0.059535,0,lca}; +Point(68) = {0.245479,-0.059217,0,lca}; +Point(69) = {0.232087,-0.058799,0,lca}; +Point(70) = {0.218958,-0.058280,0,lca}; +Point(71) = {0.206107,-0.057661,0,lca}; +Point(72) = {0.193546,-0.056940,0,lca}; +Point(73) = {0.181288,-0.056119,0,lca}; +Point(74) = {0.169344,-0.055197,0,lca}; +Point(75) = {0.157726,-0.054176,0,lca}; +Point(76) = {0.146447,-0.053056,0,lca}; +Point(77) = {0.135516,-0.051839,0,lca}; +Point(78) = {0.124944,-0.050527,0,lca}; +Point(79) = {0.114743,-0.049121,0,lca}; +Point(80) = {0.104922,-0.047624,0,lca}; +Point(81) = {0.095492,-0.046037,0,lca}; +Point(82) = {0.086460,-0.044364,0,lca}; +Point(83) = {0.077836,-0.042608,0,lca}; +Point(84) = {0.069629,-0.040770,0,lca}; +Point(85) = {0.061847,-0.038854,0,lca}; +Point(86) = {0.054497,-0.036863,0,lca}; +Point(87) = {0.047586,-0.034800,0,lca}; +Point(88) = {0.041123,-0.032668,0,lca}; +Point(89) = {0.035112,-0.030471,0,lca}; +Point(90) = {0.029560,-0.028212,0,lca}; +Point(91) = {0.024472,-0.025893,0,lca}; +Point(92) = {0.019853,-0.023517,0,lca}; +Point(93) = {0.015708,-0.021088,0,lca}; +Point(94) = {0.012042,-0.018607,0,lca}; +Point(95) = {0.008856,-0.016078,0,lca}; +Point(96) = {0.006156,-0.013503,0,lca}; +Point(97) = {0.003943,-0.010884,0,lca}; +Point(98) = {0.002219,-0.008223,0,lca}; +Point(99) = {0.000987,-0.005521,0,lca}; +Point(100) = {0.000247,-0.002779,0,lca}; +Point(101) = {0.000000,0.000000,0,lca}; +Point(102) = {0.000247,0.002779,0,lca}; +Point(103) = {0.000987,0.005521,0,lca}; +Point(104) = {0.002219,0.008223,0,lca}; +Point(105) = {0.003943,0.010884,0,lca}; +Point(106) = {0.006156,0.013503,0,lca}; +Point(107) = {0.008856,0.016078,0,lca}; +Point(108) = {0.012042,0.018607,0,lca}; +Point(109) = {0.015708,0.021088,0,lca}; +Point(110) = {0.019853,0.023517,0,lca}; +Point(111) = {0.024472,0.025893,0,lca}; +Point(112) = {0.029560,0.028212,0,lca}; +Point(113) = {0.035112,0.030471,0,lca}; +Point(114) = {0.041123,0.032668,0,lca}; +Point(115) = {0.047586,0.034800,0,lca}; +Point(116) = {0.054497,0.036863,0,lca}; +Point(117) = {0.061847,0.038854,0,lca}; +Point(118) = {0.069629,0.040770,0,lca}; +Point(119) = {0.077836,0.042608,0,lca}; +Point(120) = {0.086460,0.044364,0,lca}; +Point(121) = {0.095492,0.046037,0,lca}; +Point(122) = {0.104922,0.047624,0,lca}; +Point(123) = {0.114743,0.049121,0,lca}; +Point(124) = {0.124944,0.050527,0,lca}; +Point(125) = {0.135516,0.051839,0,lca}; +Point(126) = {0.146447,0.053056,0,lca}; +Point(127) = {0.157726,0.054176,0,lca}; +Point(128) = {0.169344,0.055197,0,lca}; +Point(129) = {0.181288,0.056119,0,lca}; +Point(130) = {0.193546,0.056940,0,lca}; +Point(131) = {0.206107,0.057661,0,lca}; +Point(132) = {0.218958,0.058280,0,lca}; +Point(133) = {0.232087,0.058799,0,lca}; +Point(134) = {0.245479,0.059217,0,lca}; +Point(135) = {0.259123,0.059535,0,lca}; +Point(136) = {0.273005,0.059754,0,lca}; +Point(137) = {0.287110,0.059876,0,lca}; +Point(138) = {0.301426,0.059902,0,lca}; +Point(139) = {0.315938,0.059834,0,lca}; +Point(140) = {0.330631,0.059674,0,lca}; +Point(141) = {0.345492,0.059424,0,lca}; +Point(142) = {0.360504,0.059087,0,lca}; +Point(143) = {0.375655,0.058666,0,lca}; +Point(144) = {0.390928,0.058163,0,lca}; +Point(145) = {0.406309,0.057581,0,lca}; +Point(146) = {0.421783,0.056924,0,lca}; +Point(147) = {0.437333,0.056195,0,lca}; +Point(148) = {0.452946,0.055397,0,lca}; +Point(149) = {0.468605,0.054534,0,lca}; +Point(150) = {0.484295,0.053608,0,lca}; +Point(151) = {0.500000,0.052625,0,lca}; +Point(152) = {0.515705,0.051587,0,lca}; +Point(153) = {0.531395,0.050499,0,lca}; +Point(154) = {0.547054,0.049362,0,lca}; +Point(155) = {0.562667,0.048182,0,lca}; +Point(156) = {0.578217,0.046962,0,lca}; +Point(157) = {0.593691,0.045705,0,lca}; +Point(158) = {0.609072,0.044414,0,lca}; +Point(159) = {0.624345,0.043094,0,lca}; +Point(160) = {0.639496,0.041747,0,lca}; +Point(161) = {0.654508,0.040378,0,lca}; +Point(162) = {0.669369,0.038988,0,lca}; +Point(163) = {0.684062,0.037582,0,lca}; +Point(164) = {0.698574,0.036163,0,lca}; +Point(165) = {0.712890,0.034733,0,lca}; +Point(166) = {0.726995,0.033296,0,lca}; +Point(167) = {0.740877,0.031856,0,lca}; +Point(168) = {0.754521,0.030414,0,lca}; +Point(169) = {0.767913,0.028974,0,lca}; +Point(170) = {0.781042,0.027539,0,lca}; +Point(171) = {0.793893,0.026111,0,lca}; +Point(172) = {0.806454,0.024694,0,lca}; +Point(173) = {0.818712,0.023291,0,lca}; +Point(174) = {0.830656,0.021904,0,lca}; +Point(175) = {0.842274,0.020535,0,lca}; +Point(176) = {0.853553,0.019189,0,lca}; +Point(177) = {0.864484,0.017868,0,lca}; +Point(178) = {0.875056,0.016574,0,lca}; +Point(179) = {0.885257,0.015310,0,lca}; +Point(180) = {0.895078,0.014079,0,lca}; +Point(181) = {0.904508,0.012883,0,lca}; +Point(182) = {0.913540,0.011726,0,lca}; +Point(183) = {0.922164,0.010610,0,lca}; +Point(184) = {0.930371,0.009537,0,lca}; +Point(185) = {0.938153,0.008510,0,lca}; +Point(186) = {0.945503,0.007531,0,lca}; +Point(187) = {0.952414,0.006603,0,lca}; +Point(188) = {0.958877,0.005729,0,lca}; +Point(189) = {0.964888,0.004909,0,lca}; +Point(190) = {0.970440,0.004147,0,lca}; +Point(191) = {0.975528,0.003443,0,lca}; +Point(192) = {0.980147,0.002801,0,lca}; +Point(193) = {0.984292,0.002222,0,lca}; +Point(194) = {0.987958,0.001707,0,lca}; +Point(195) = {0.991144,0.001258,0,lca}; +Point(196) = {0.993844,0.000876,0,lca}; +Point(197) = {0.996057,0.000562,0,lca}; +Point(198) = {0.997781,0.000317,0,lca}; +Point(199) = {0.999013,0.000141,0,lca}; +Point(200) = {0.999753,0.000035,0,lca}; + +//Points numerotation: +numberLeadingEgde = 101 ; +numberLowerSurface = 81 ; +numberUpperSurface = 121 ; + +//Distances: +distanceTrailingLowerPoint = 0.908262 ; +distanceLowerUpperPoint = 0.222905 ; +distanceUpperTrailingPoint = 0.908262 ; + +Line(1) = { 1 ... 81 }; +Line(2) = { 81 ... 101 }; +Line(3) = { 101 ... 121 }; +Line(4) = { 121 ... 200, 1 }; + +Rotate { {0,0,1}, {1,0,0}, Incidence } { Line { 1 ... 4 } ; } + +/* Line Loop(1) = {1,2,3,4}; */ +/* Plane Surface(1) = {1}; */ diff --git a/Thermics/brick.geo b/Thermics/brick.geo index 0dbaa0e..3b56f06 100644 --- a/Thermics/brick.geo +++ b/Thermics/brick.geo @@ -1,111 +1,111 @@ -/* ------------------------------------------------------------------- - File "brick.geo" - - This file is the geometrical description used by GMSH to produce - the file "brick.msh". - ------------------------------------------------------------------- */ - -/* Gmsh options can be set directly in the .geo file. - Setting "Solver.AutoMesh" to 2 ensures that GMSH systematically - regenerates the mesh at each model execution, and does not reuse - the mesh on disk if it exists (which is the default option). - This option is needed in this model, because the interactive - model parameters "Flag_Regularization" has an effect - on the definition of the regions, which makes remeshing mandatory. */ - -Solver.AutoMesh = 2; - -Include "brick_common.pro"; - -/* The (very) simple geometry of this thermal model only contains - rectangles. It is the opportunity to illustrate - the function definition capabilities of Gmsh. */ - -Function Def_Rectangle -p1=newp; Point(newp)={xc_, yc_, 0, lc_}; -p2=newp; Point(newp)={xc_+dx_, yc_, 0, lc_}; -p3=newp; Point(newp)={xc_+dx_, yc_+dy_, 0, lc_}; -p4=newp; Point(newp)={xc_, yc_+dy_, 0, lc_}; - -l1=newl; Line(newl)={p1,p2}; -l2=newl; Line(newl)={p2,p3}; -l3=newl; Line(newl)={p3,p4}; -l4=newl; Line(newl)={p4,p1}; - -lines_[] = {l1, l2, l3, l4}; - -ll1 = newll; Line Loop(ll1) = {lines_[]}; -s_ = news; Plane Surface(news) = {ll1, ll_Holes_[]}; -Return // end of Function Def_Rectangle - -/* Note that the code above is not parsed before it is called. - Good practice for readability (but by no means mandatory) - is to distinguish function variables from other variables. - This is done here with a trailing "_" in the variable name. */ - - -// Window 1 (with optional layer of thickness "e_layer") -dx_ = dx_Win1; -dy_ = dy_Win1; -lc_ = lc_Win1; -xc_ = xc_Win1-dx_/2; yc_=yc_Win1-dy_/2; -ll_Holes_[]={}; -Call Def_Rectangle; -s_Win1 = s_; -l_Win1[] = lines_[]; - -If( !Flag_Regularization ) - ll_HolesForBrick[] += ll1; -Else - ll_HolesForLayer[] += ll1; - dx_ = dx_Win1+2*e_layer; - dy_ = dy_Win1+2*e_layer; - lc_ = lc_Win1; - xc_ = xc_Win1-dx_/2; yc_=yc_Win1-dy_/2; - - ll_Holes_[] = {ll_HolesForLayer[]}; - Call Def_Rectangle; - s_Win1_Layer = s_; - l_Win1_Layer[] = lines_[]; - ll_HolesForBrick[] += ll1; -EndIf - -// Window 2 -dx_ = dx_Win2; -dy_ = dy_Win2; -lc_ = lc_Win2; -xc_ = xc_Win2-dx_/2; yc_=yc_Win2-dy_/2; -ll_Holes_[]={}; -Call Def_Rectangle; -s_Win2 = s_; -l_Win2[] = lines_[]; -ll_HolesForBrick[] += ll1; - -// Brick -dx_ = dx_Brick; dy_ = dy_Brick; -lc_ = lc_Brick; -xc_ = 0; yc_ = 0; -ll_Holes_[] = {ll_HolesForBrick[]}; -Call Def_Rectangle; -s_Brick = s_; -l_Brick[] = lines_[]; - -//Printf("l_Brick", l_Brick[]); - - -// Physical regions - -Physical Surface("Brick", 100) = {s_Brick}; -Physical Surface("Window1", 111) = {s_Win1}; -Physical Surface("Window2", 112) = {s_Win2}; -If( Flag_Regularization ) - Physical Surface("LayerWindow1", 115) = {s_Win1_Layer}; -EndIf - -Physical Line("Surface1", 201) = { l_Brick[{3}] }; -Physical Line("Surface2", 202) = { l_Brick[{1}] }; -Physical Line("Surface3", 203) = { l_Brick[{0}], l_Brick[{2}] }; - -Physical Line("SurfWindow1", 211) = {l_Win1[]}; -Physical Line("SurfWindow2", 212) = {l_Win2[]}; - +/* ------------------------------------------------------------------- + File "brick.geo" + + This file is the geometrical description used by GMSH to produce + the file "brick.msh". + ------------------------------------------------------------------- */ + +/* Gmsh options can be set directly in the .geo file. + Setting "Solver.AutoMesh" to 2 ensures that GMSH systematically + regenerates the mesh at each model execution, and does not reuse + the mesh on disk if it exists (which is the default option). + This option is needed in this model, because the interactive + model parameters "Flag_Regularization" has an effect + on the definition of the regions, which makes remeshing mandatory. */ + +Solver.AutoMesh = 2; + +Include "brick_common.pro"; + +/* The (very) simple geometry of this thermal model only contains + rectangles. It is the opportunity to illustrate + the function definition capabilities of Gmsh. */ + +Function Def_Rectangle +p1=newp; Point(newp)={xc_, yc_, 0, lc_}; +p2=newp; Point(newp)={xc_+dx_, yc_, 0, lc_}; +p3=newp; Point(newp)={xc_+dx_, yc_+dy_, 0, lc_}; +p4=newp; Point(newp)={xc_, yc_+dy_, 0, lc_}; + +l1=newl; Line(newl)={p1,p2}; +l2=newl; Line(newl)={p2,p3}; +l3=newl; Line(newl)={p3,p4}; +l4=newl; Line(newl)={p4,p1}; + +lines_[] = {l1, l2, l3, l4}; + +ll1 = newll; Line Loop(ll1) = {lines_[]}; +s_ = news; Plane Surface(news) = {ll1, ll_Holes_[]}; +Return // end of Function Def_Rectangle + +/* Note that the code above is not parsed before it is called. + Good practice for readability (but by no means mandatory) + is to distinguish function variables from other variables. + This is done here with a trailing "_" in the variable name. */ + + +// Window 1 (with optional layer of thickness "e_layer") +dx_ = dx_Win1; +dy_ = dy_Win1; +lc_ = lc_Win1; +xc_ = xc_Win1-dx_/2; yc_=yc_Win1-dy_/2; +ll_Holes_[]={}; +Call Def_Rectangle; +s_Win1 = s_; +l_Win1[] = lines_[]; + +If( !Flag_Regularization ) + ll_HolesForBrick[] += ll1; +Else + ll_HolesForLayer[] += ll1; + dx_ = dx_Win1+2*e_layer; + dy_ = dy_Win1+2*e_layer; + lc_ = lc_Win1; + xc_ = xc_Win1-dx_/2; yc_=yc_Win1-dy_/2; + + ll_Holes_[] = {ll_HolesForLayer[]}; + Call Def_Rectangle; + s_Win1_Layer = s_; + l_Win1_Layer[] = lines_[]; + ll_HolesForBrick[] += ll1; +EndIf + +// Window 2 +dx_ = dx_Win2; +dy_ = dy_Win2; +lc_ = lc_Win2; +xc_ = xc_Win2-dx_/2; yc_=yc_Win2-dy_/2; +ll_Holes_[]={}; +Call Def_Rectangle; +s_Win2 = s_; +l_Win2[] = lines_[]; +ll_HolesForBrick[] += ll1; + +// Brick +dx_ = dx_Brick; dy_ = dy_Brick; +lc_ = lc_Brick; +xc_ = 0; yc_ = 0; +ll_Holes_[] = {ll_HolesForBrick[]}; +Call Def_Rectangle; +s_Brick = s_; +l_Brick[] = lines_[]; + +//Printf("l_Brick", l_Brick[]); + + +// Physical regions + +Physical Surface("Brick", 100) = {s_Brick}; +Physical Surface("Window1", 111) = {s_Win1}; +Physical Surface("Window2", 112) = {s_Win2}; +If( Flag_Regularization ) + Physical Surface("LayerWindow1", 115) = {s_Win1_Layer}; +EndIf + +Physical Line("Surface1", 201) = { l_Brick[{3}] }; +Physical Line("Surface2", 202) = { l_Brick[{1}] }; +Physical Line("Surface3", 203) = { l_Brick[{0}], l_Brick[{2}] }; + +Physical Line("SurfWindow1", 211) = {l_Win1[]}; +Physical Line("SurfWindow2", 212) = {l_Win2[]}; + diff --git a/Thermics/brick.pro b/Thermics/brick.pro index 88694ac..f2720fb 100644 --- a/Thermics/brick.pro +++ b/Thermics/brick.pro @@ -1,454 +1,452 @@ -/* ------------------------------------------------------------------- - Tutorial 5 : thermal problem with contact resistances - - Features: - - Contact resistances: scalar FunctionSpace with a surface discontinuity - - Region with a uniform temperature (infinite thermal conductivity) - - Computation of the heat flux through surfaces - - Import a source field from a file - - To compute the solution in a terminal: - getdp brick.pro -solve Thermal_T -pos Map_T - - To compute the solution interactively from the Gmsh GUI: - File > Open > brick.pro - Run (button at the bottom of the left panel) - ------------------------------------------------------------------- */ - -/* This model is a rectangular brick with two windows, - where various kinds of thermal constraints can be set. - Dirichlet, Neumann and convection boundary conditions are imposed - on different parts of the surface of the brick. - The model is rather academic but it - demonstrates some useful high-level GetDP features. - - Governing eqations are - - div ( -lambda[] grad T ) = Q in Vol_Lambda_The - -lambda[] grad T . n = qn = 0 on Sur_Neumann_The - - Contact thermal resistance: - First, it is shown how to implement contact thermal resistances - with surface elements. The surface elements are associated with a - thickness and a thermal conductivity (typically much lower than that - of surrounding regions). The implementation takes advantage - of the powerful FunctionSpace definition in GetDP. - - With the flag "Flag_Regularization", the contact surface - can be, for the sake of comparison, replaced - by a thin volume conducting region. - - Thermal "electrode": - The floating potential idea (introduced in tutorial 4) - is reconsidered here in a thermal context to represent a region - with a very large thermal conductivity where, consequently, - the temperature field is uniform (exactly like the electric potential - is uniform on an electrode). - The dual quantity of this uniform temperature "T_electrode" [K] - (which is the "associated global quantity" in GetDP language) - is the heat flux "Q_electrode" [W] injected in the electrode - by the agent that maintains the temperature equal - to the prescribed value. - - The value of Q_electrode is a by-product of the system resolution - provided the term - - GlobalTerm { [-Dof{Q_electrode} , {T_electrode} ] ; In Tfloating_The ; } - - is present in the "Resolution" section. This term triggers the writing - in the linear system of a supplementary equation associated - with the global basis function BF{T_electrode}. - All integrations are automatically done by getDP, - and the value of Q_electrode is obtained in postprocessing - with the PostOperation - - Print[ Q_electrode, OnRegion Tfloating_The, ... ] - - Heat flux through surfaces: - The purpose of a thermal simulation usually goes beyond - the mere calculation of a temperature distribution. - One is in general also interested in evaluating - the heat flux q(S) through some specific surface S: - - q(S) = ( -lambda[] grad T . n )_S - - This quantity cannot be computed from the temperature - distribution available on the surface S only. - As heat flux is related with the gradient of temperature - in the direction normal to the surface, its computation relies on - the temperature distribution in a neighborhood of the surface. - This means that volume elements in contact with the considered surface - need be involved in the computation. - To achieve this with getDP, a good method proceeds - by the definition a smooth auxiliary function g(S), - with g(S)=1 on S, and g(S)=0 outside a finite neighborhood of S. - Typically, g(S) is the sum of the shape functions of the nodes on S. - Let w(S) be the support of g(S), - and let dw(S) denote the boundary of w(S). - We then have, just adding and substracting dw(S) - to the surface of integration S - - q(S) = ( -lambda[] grad T . n g(S) )_{ dw(S) - ( dw(S)-S ) }. - - dw(S) being a boundary, Stokes theorem can be invoked and, - after an integration by part one ends up with - - q(S) = ( -lambda[] grad T . grad g(S) )_w(S) - - ( -lambda[] grad T . n g(S) )_{dw(S)-S}. - + ( Q g(S) )_w(S) - - Now, g(S) is zero on {dw(S)-S}, except maybe at some surface elements - adjacents to dS, but not in dS. - The second terme vanishes then if either S is closed, - or adjacent to a homogeneous Neumann boundary condition. - - The third term also vanishes, except if a region - with a nonzero heatsource Q is in contact with the surface S. - - So we have nearly always the following practical formula - to evaluate the heat flux across a surface S, - in terms of a well-chosen auxiliary scalar function g(S). - - q(S) = ( -lambda[] grad T . grad g(S) )_{support of g(S)} - - - Particular cases: - - For the heat flux through the boundary of a thermal electrode, - one uses g(S) = BF(T_electrode). - Note that this heat flux is equal to Q_electrode - in the stationary case. - This is the case for the heat flux through the boundary of Window2 - - Auxiliary functions g(S) are also generated - for the surfaces named "Surface_i", i=1,2,3 in the model. - Note that the flux computed through Surface_3 is incorrect - because this surface is not adjacent to surfaces - with homogeneous Neumann boundary conditions. -*/ - -Include "brick_common.pro"; - -QWindow1 = - DefineNumber[1e3, Name "Window1/Heat source [W]"]; - -/* The user is given the choice of setting either the global temperature - or the global heat flux in Window2. - Check how the variable "Flag_ConstraintWin2" is used at different - places to alter the model according to that choice - and to manage the visibility of related input and output data.*/ -QWindow2 = - DefineNumber[1e3, Name "Window2/Heat source [W]", - Visible Flag_ConstraintWin2]; -TWindow2 = - DefineNumber[50, Name "Window2/Temperature [degC]", - Visible !Flag_ConstraintWin2]; -outQWindow2 = - DefineNumber[0, Name "Output/Q window 2 [degC]", - Visible !Flag_ConstraintWin2, Highlight "Ivory"]; -outTWindow2 = - DefineNumber[0, Name "Output/T window 2 [degC]", - Visible Flag_ConstraintWin2, Highlight "Ivory"]; - - -ConvectionCoef = - DefineNumber[1000, Name"Surface2/hconv", - Label "Convection coefficient [W/(m^2K)]"]; -T_Ambiance = - DefineNumber[20, Name"Surface2/Ambiance temperature [degC]"]; -T_Dirichlet = - DefineNumber[20, Name"Surface1/Imposed temperature [degC]"]; - -Group { - /* Geometrical regions: */ - Brick = Region[100]; - LayerWindow1 = Region[115]; - Window1 = Region[111]; - Window2 = Region[112]; - SurfWindow1 = Region[211]; - SurfWindow2 = Region[212]; - - Surface_1 = Region[201]; - Surface_2 = Region[202]; - Surface_3 = Region[203]; - NbSurface = 3; - - /* Abstract regions: - - Vol_Lambda_Ele : volume regions with a thermal conductivity lambda[] - Sur_Dirichlet_The : Dirichlet bondary condition surface - Sur_Neu_Ele : Neumann bondary condition surface - Sur_Convection_The : convective surface q.n = h ( T-Tinf ) - Vol_Qsource_The : volume heat source regions - Tfloating_The : thermal electrodes - */ - - Vol_Lambda_The = Region[ {Brick, Window1, Window2, LayerWindow1} ]; - Sur_Dirichlet_The = Region[ Surface_1 ]; - Sur_Neumann_The = Region[ Surface_3 ]; - Sur_Convection_The = Region[ Surface_2 ]; - - Vol_Qsource_The = Region[ Window1 ]; - Tfloating_The = Region[ Window2 ]; - - If( !Flag_Regularization ) - Vol_OneSide_The = Region[ Brick ]; - Sur_Tdisc_The = Region[ SurfWindow1 ]; - Else - Vol_OneSide_The = Region[ {} ]; - Sur_Tdisc_The = Region[ {} ]; - EndIf -} - - -Function { - lambda_Brick = 50.; // steel - lambda[ Brick ] = lambda_Brick; - lambda[ Region[ {Window1, Window2} ] ] = lambda_Brick ; // comment - - lambda_Layer = 1.0; // 50 time smaller than surrounding regions - If( Flag_Regularization ) - lambda[ LayerWindow1 ] = lambda_Layer; - EndIf - lambda[ Sur_Tdisc_The ] = lambda_Layer; - thickness[ Sur_Tdisc_The ] = e_layer; - - h[ Surface_2 ] = ConvectionCoef; - Tinf[ Surface_2 ] = T_Ambiance; - - If( Flag_QFromFile ) - Qsource[ Window1 ] = ScalarField[XYZ[],0,1]{1}; - Else - Qsource[ Window1 ] = 0*QWindow1/SurfaceArea[]; - EndIf -} - -Constraint { - { Name Dirichlet_The ; - Case { - { Region Sur_Dirichlet_The ; Value T_Dirichlet ; } - } - } - { Name T_Discontinuity ; - Case { - { Region SurfWindow1 ; Value 20 ; } - } - } - { Name T_electrode; - Case { - If( !Flag_ConstraintWin2 ) - { Region Window2 ; Value TWindow2 ; } - EndIf - } - } - { Name Q_electrode; - Case { - If( Flag_ConstraintWin2 ) - { Region Window2 ; Value QWindow2 ; } - EndIf - } - } - For i In {1:NbSurface} - { Name FluxLayer~{i} ; - Case { - { Region Surface~{i} ; Value 1. ; } - } - } - EndFor -} - -Integration { - { Name Int ; - Case { - { - Type Gauss ; - Case { - { GeoElement Triangle ; NumberOfPoints 4 ; } - { GeoElement Quadrangle ; NumberOfPoints 4 ; } - { GeoElement Line ; NumberOfPoints 4 ; } - } - } - } - } -} - -Jacobian { - { Name Vol ; - Case { - { Region All ; Jacobian Vol ; } - } - } - { Name Sur ; - Case { - { Region All ; Jacobian Sur ; } - } - } -} - -Group { - Dom_Hgrad_T = Region[ {Vol_Lambda_The, - Sur_Convection_The, - Sur_Tdisc_The} ]; - DomainWithSurf_TL_The = - ElementsOf[ {Vol_OneSide_The, Sur_Tdisc_The}, - OnOneSideOf Sur_Tdisc_The ]; -} - -FunctionSpace { - { Name Hgrad_T; Type Form0 ; - BasisFunction { - { Name sn ; NameOfCoef Tn ; Function BF_Node ; - Support Dom_Hgrad_T ; - Entity NodesOf[All, Not Tfloating_The] ; } - { Name sf ; NameOfCoef Tf ; Function BF_GroupOfNodes ; - Support Dom_Hgrad_T ; Entity GroupsOfNodesOf[ Tfloating_The ] ; } - { Name sdn ; NameOfCoef Tdn ; Function BF_Node ; - Support DomainWithSurf_TL_The ; Entity NodesOf[ Sur_Tdisc_The ] ; } - } - SubSpace { - { Name Tcont ; NameOfBasisFunction { sn, sf } ; } - { Name Tdisc ; NameOfBasisFunction { sdn } ; } - } - GlobalQuantity { - { Name T_electrode ; Type AliasOf ; NameOfCoef Tf ; } - { Name Q_electrode ; Type AssociatedWith ; NameOfCoef Tf ; } - } - Constraint { - { NameOfCoef Tn ; EntityType NodesOf ; - NameOfConstraint Dirichlet_The ; } - // { NameOfCoef Tdn ; EntityType NodesOf ; // - // NameOfConstraint T_Discontinuity ; } // - { NameOfCoef T_electrode ; EntityType GroupsOfNodesOf ; - NameOfConstraint T_electrode ; } - { NameOfCoef Q_electrode ; EntityType GroupsOfNodesOf ; - NameOfConstraint Q_electrode ; } - } - } - For i In {1:NbSurface} - { Name FluxLayer~{i} ; Type Form0 ; - BasisFunction { - { Name gn ; NameOfCoef un ; Function BF_GroupOfNodes; - Support Dom_Hgrad_T ; Entity GroupsOfNodesOf[ Surface~{i} ] ; } - } - Constraint { - { NameOfCoef un ; EntityType GroupsOfNodesOf ; - NameOfConstraint FluxLayer~{i} ; } - } - } - EndFor - -} - -Formulation { - { Name Thermal_T ; Type FemEquation ; - Quantity { - { Name T ; Type Local ; NameOfSpace Hgrad_T ; } - { Name Tcont ; Type Local ; NameOfSpace Hgrad_T[Tcont] ; } - { Name Tdisc ; Type Local ; NameOfSpace Hgrad_T[Tdisc] ; } - { Name Tglob ; Type Global ; NameOfSpace Hgrad_T[T_electrode] ; } - { Name Qglob ; Type Global ; NameOfSpace Hgrad_T[Q_electrode] ; } - For i In {1:NbSurface} - { Name un~{i} ; Type Local ; NameOfSpace FluxLayer~{i} ; } - EndFor - - } - Equation { - - Galerkin { [ lambda[] * Dof{d T} , {d T} ] ; - In Vol_Lambda_The; Integration Int ; Jacobian Vol ; } - - Galerkin { [ ( lambda[]/thickness[] ) * Dof{Tdisc} , {Tdisc} ] ; - In Sur_Tdisc_The; Integration Int ; Jacobian Sur ; } - - Galerkin { [ -Qsource[] , {T} ] ; - In Vol_Qsource_The ; Integration Int ; Jacobian Vol ; } - - Galerkin { [ h[] * Dof{T} , {T} ] ; - In Sur_Convection_The ; Integration Int ; Jacobian Sur ; } - - Galerkin { [ -h[] * Tinf[] , {T} ] ; - In Sur_Convection_The ; Integration Int ; Jacobian Sur ; } - - GlobalTerm { [-Dof{Qglob} , {Tglob} ] ; In Tfloating_The ; } - - For i In {1:NbSurface} - Galerkin { [ 0 * Dof{un~{i}} , {un~{i}} ] ; - In Vol_Lambda_The ; Integration Int ; Jacobian Vol ; } - EndFor - } - } -} - - -Resolution { - { Name Thermal_T ; - System { - { Name Sys_The ; NameOfFormulation Thermal_T ; } - } - Operation { - If( Flag_QFromFile ) - GmshRead[ "Q.pos", 1]; - EndIf - DeleteFile["output.txt"]; - Generate Sys_The ; Solve Sys_The ; SaveSolution Sys_The ; - } - } -} - -PostProcessing { - { Name Thermal_T ; NameOfFormulation Thermal_T ; - PostQuantity { - { Name T ; Value { Term { [ {T} ] ; - In Dom_Hgrad_T ; Jacobian Vol ; } } } - { Name q ; Value { Term { [ -lambda[] * {d T} ] ; - In Dom_Hgrad_T ; Jacobian Vol ; } } } - { Name Tcont ; Value { Term { [ {Tcont} ] ; - In Dom_Hgrad_T ; Jacobian Vol ; } } } - { Name Tdisc ; Value { Term { [ {Tdisc} ] ; - In Dom_Hgrad_T ; Jacobian Vol ; } } } - { Name Qglob; Value { Term { [ {Qglob} ]; In Tfloating_The; } } } - { Name Tglob; Value { Term { [ {Tglob} ]; In Tfloating_The; } } } - - For i In {1:NbSurface} - { Name un~{i} ; Value { Local { [ {un~{i}} ] ; - In Vol_Lambda_The ; Jacobian Vol ; } } } - { Name IFlux~{i} ; Value { Integral { [ -lambda[]*{d T} * {d un~{i}} ]; - In Vol_Lambda_The ; Jacobian Vol ; Integration Int ; } } } - EndFor - - } - } -} - -PostOperation Map_T UsingPost Thermal_T { - If( !Flag_Regularization ) - Print[ Tcont, OnElementsOf Vol_Lambda_The, File "Tcont.pos"] ; - Print[ Tdisc, OnElementsOf Vol_Lambda_The, File "Tdisc.pos"] ; - EndIf - - If(Flag_ConstraintWin2) - Print[ Tglob, OnRegion Tfloating_The, File > "output.txt", Color "Ivory", - Format Table, SendToServer "Output/T window 2 [degC]" ]; - Else - Print[ Qglob, OnRegion Tfloating_The, File > "output.txt", Color "Ivory", - Format Table, SendToServer "Output/Q window 2 [degC]" ]; - EndIf - - For i In {1:NbSurface} - Print[un~{i}, OnElementsOf Vol_Lambda_The, - File Sprintf("FluxLayer_%g.pos",i)]; - Print[ IFlux~{i}[Vol_Lambda_The], OnGlobal, - Format TimeTable, File > "Fluxes.dat", Color "Ivory", - SendToServer Sprintf("Output/Heat flux surface %g [W]", i)]; - EndFor - Print[ T, OnElementsOf Vol_Lambda_The, File "T.pos" ] ; - Echo[ StrCat["l=PostProcessing.NbViews-1;", - "View[l].IntervalsType = 3;", - "View[l].NbIso = 30;", - "View[l].NormalRaise = 0.0005;"], - File "tmp.geo", LastTimeStepOnly] ; - Print [ q, OnLine {{0.02,0.0001,0}{0.02,0.05,0}} {200}, - Format SimpleTable, File "Cut.txt" ]; -} - - +/* ------------------------------------------------------------------- + Tutorial 5 : thermal problem with contact resistances + + Features: + - Contact resistances: scalar FunctionSpace with a surface discontinuity + - Region with a uniform temperature (infinite thermal conductivity) + - Computation of the heat flux through surfaces + - Import a source field from a file + + To compute the solution in a terminal: + getdp brick.pro -solve Thermal_T -pos Map_T + + To compute the solution interactively from the Gmsh GUI: + File > Open > brick.pro + Run (button at the bottom of the left panel) + ------------------------------------------------------------------- */ + +/* This model is a rectangular brick with two windows, + where various kinds of thermal constraints can be set. + Dirichlet, Neumann and convection boundary conditions are imposed + on different parts of the surface of the brick. + The model is rather academic but it + demonstrates some useful high-level GetDP features. + + Governing eqations are + + div ( -lambda[] grad T ) = Q in Vol_Lambda_The + -lambda[] grad T . n = qn = 0 on Sur_Neumann_The + + Contact thermal resistance: + First, it is shown how to implement contact thermal resistances + with surface elements. The surface elements are associated with a + thickness and a thermal conductivity (typically much lower than that + of surrounding regions). The implementation takes advantage + of the powerful FunctionSpace definition in GetDP. + + With the flag "Flag_Regularization", the contact surface + can be, for the sake of comparison, replaced + by a thin volume conducting region. + + Thermal "electrode": + The floating potential idea (introduced in tutorial 4) + is reconsidered here in a thermal context to represent a region + with a very large thermal conductivity where, consequently, + the temperature field is uniform (exactly like the electric potential + is uniform on an electrode). + The dual quantity of this uniform temperature "T_electrode" [K] + (which is the "associated global quantity" in GetDP language) + is the heat flux "Q_electrode" [W] injected in the electrode + by the agent that maintains the temperature equal + to the prescribed value. + + The value of Q_electrode is a by-product of the system resolution + provided the term + + GlobalTerm { [-Dof{Q_electrode} , {T_electrode} ] ; In Tfloating_The ; } + + is present in the "Resolution" section. This term triggers the writing + in the linear system of a supplementary equation associated + with the global basis function BF{T_electrode}. + All integrations are automatically done by getDP, + and the value of Q_electrode is obtained in postprocessing + with the PostOperation + + Print[ Q_electrode, OnRegion Tfloating_The, ... ] + + Heat flux through surfaces: + The purpose of a thermal simulation usually goes beyond + the mere calculation of a temperature distribution. + One is in general also interested in evaluating + the heat flux q(S) through some specific surface S: + + q(S) = ( -lambda[] grad T . n )_S + + This quantity cannot be computed from the temperature + distribution available on the surface S only. + As heat flux is related with the gradient of temperature + in the direction normal to the surface, its computation relies on + the temperature distribution in a neighborhood of the surface. + This means that volume elements in contact with the considered surface + need be involved in the computation. + To achieve this with getDP, a good method proceeds + by the definition a smooth auxiliary function g(S), + with g(S)=1 on S, and g(S)=0 outside a finite neighborhood of S. + Typically, g(S) is the sum of the shape functions of the nodes on S. + Let w(S) be the support of g(S), + and let dw(S) denote the boundary of w(S). + We then have, just adding and substracting dw(S) + to the surface of integration S + + q(S) = ( -lambda[] grad T . n g(S) )_{ dw(S) - ( dw(S)-S ) }. + + dw(S) being a boundary, Stokes theorem can be invoked and, + after an integration by part one ends up with + + q(S) = ( -lambda[] grad T . grad g(S) )_w(S) + - ( -lambda[] grad T . n g(S) )_{dw(S)-S}. + + ( Q g(S) )_w(S) + + Now, g(S) is zero on {dw(S)-S}, except maybe at some surface elements + adjacents to dS, but not in dS. + The second terme vanishes then if either S is closed, + or adjacent to a homogeneous Neumann boundary condition. + + The third term also vanishes, except if a region + with a nonzero heatsource Q is in contact with the surface S. + + So we have nearly always the following practical formula + to evaluate the heat flux across a surface S, + in terms of a well-chosen auxiliary scalar function g(S). + + q(S) = ( -lambda[] grad T . grad g(S) )_{support of g(S)} + + + Particular cases: + + For the heat flux through the boundary of a thermal electrode, + one uses g(S) = BF(T_electrode). + Note that this heat flux is equal to Q_electrode + in the stationary case. + This is the case for the heat flux through the boundary of Window2 + + Auxiliary functions g(S) are also generated + for the surfaces named "Surface_i", i=1,2,3 in the model. + Note that the flux computed through Surface_3 is incorrect + because this surface is not adjacent to surfaces + with homogeneous Neumann boundary conditions. +*/ + +Include "brick_common.pro"; + +QWindow1 = + DefineNumber[1e3, Name "Window1/Heat source [W]"]; + +/* The user is given the choice of setting either the global temperature + or the global heat flux in Window2. + Check how the variable "Flag_ConstraintWin2" is used at different + places to alter the model according to that choice + and to manage the visibility of related input and output data.*/ +QWindow2 = + DefineNumber[1e3, Name "Window2/Heat source [W]", + Visible Flag_ConstraintWin2]; +TWindow2 = + DefineNumber[50, Name "Window2/Temperature [degC]", + Visible !Flag_ConstraintWin2]; +outQWindow2 = + DefineNumber[0, Name "Output/Q window 2 [degC]", + Visible !Flag_ConstraintWin2, Highlight "Ivory"]; +outTWindow2 = + DefineNumber[0, Name "Output/T window 2 [degC]", + Visible Flag_ConstraintWin2, Highlight "Ivory"]; + + +ConvectionCoef = + DefineNumber[1000, Name"Surface2/hconv", + Label "Convection coefficient [W/(m^2K)]"]; +T_Ambiance = + DefineNumber[20, Name"Surface2/Ambiance temperature [degC]"]; +T_Dirichlet = + DefineNumber[20, Name"Surface1/Imposed temperature [degC]"]; + +Group { + /* Geometrical regions: */ + Brick = Region[100]; + LayerWindow1 = Region[115]; + Window1 = Region[111]; + Window2 = Region[112]; + SurfWindow1 = Region[211]; + SurfWindow2 = Region[212]; + + Surface_1 = Region[201]; + Surface_2 = Region[202]; + Surface_3 = Region[203]; + NbSurface = 3; + + /* Abstract regions: + + Vol_Lambda_Ele : volume regions with a thermal conductivity lambda[] + Sur_Dirichlet_The : Dirichlet bondary condition surface + Sur_Neu_Ele : Neumann bondary condition surface + Sur_Convection_The : convective surface q.n = h ( T-Tinf ) + Vol_Qsource_The : volume heat source regions + Tfloating_The : thermal electrodes + */ + + Vol_Lambda_The = Region[ {Brick, Window1, Window2, LayerWindow1} ]; + Sur_Dirichlet_The = Region[ Surface_1 ]; + Sur_Neumann_The = Region[ Surface_3 ]; + Sur_Convection_The = Region[ Surface_2 ]; + + Vol_Qsource_The = Region[ Window1 ]; + Tfloating_The = Region[ Window2 ]; + + If( !Flag_Regularization ) + Vol_OneSide_The = Region[ Brick ]; + Sur_Tdisc_The = Region[ SurfWindow1 ]; + Else + Vol_OneSide_The = Region[ {} ]; + Sur_Tdisc_The = Region[ {} ]; + EndIf +} + + +Function { + lambda_Brick = 50.; // steel + lambda[ Brick ] = lambda_Brick; + lambda[ Region[ {Window1, Window2} ] ] = lambda_Brick ; // comment + + lambda_Layer = 1.0; // 50 time smaller than surrounding regions + If( Flag_Regularization ) + lambda[ LayerWindow1 ] = lambda_Layer; + EndIf + lambda[ Sur_Tdisc_The ] = lambda_Layer; + thickness[ Sur_Tdisc_The ] = e_layer; + + h[ Surface_2 ] = ConvectionCoef; + Tinf[ Surface_2 ] = T_Ambiance; + + If( Flag_QFromFile ) + Qsource[ Window1 ] = ScalarField[XYZ[],0,1]{1}; + Else + Qsource[ Window1 ] = 0*QWindow1/SurfaceArea[]; + EndIf +} + +Constraint { + { Name Dirichlet_The ; + Case { + { Region Sur_Dirichlet_The ; Value T_Dirichlet ; } + } + } + { Name T_Discontinuity ; + Case { + { Region SurfWindow1 ; Value 20 ; } + } + } + { Name T_electrode; + Case { + If( !Flag_ConstraintWin2 ) + { Region Window2 ; Value TWindow2 ; } + EndIf + } + } + { Name Q_electrode; + Case { + If( Flag_ConstraintWin2 ) + { Region Window2 ; Value QWindow2 ; } + EndIf + } + } + For i In {1:NbSurface} + { Name FluxLayer~{i} ; + Case { + { Region Surface~{i} ; Value 1. ; } + } + } + EndFor +} + +Integration { + { Name Int ; + Case { + { + Type Gauss ; + Case { + { GeoElement Triangle ; NumberOfPoints 4 ; } + { GeoElement Quadrangle ; NumberOfPoints 4 ; } + { GeoElement Line ; NumberOfPoints 4 ; } + } + } + } + } +} + +Jacobian { + { Name Vol ; + Case { + { Region All ; Jacobian Vol ; } + } + } + { Name Sur ; + Case { + { Region All ; Jacobian Sur ; } + } + } +} + +Group { + Dom_Hgrad_T = Region[ {Vol_Lambda_The, + Sur_Convection_The, + Sur_Tdisc_The} ]; + DomainWithSurf_TL_The = + ElementsOf[ {Vol_OneSide_The, Sur_Tdisc_The}, + OnOneSideOf Sur_Tdisc_The ]; +} + +FunctionSpace { + { Name Hgrad_T; Type Form0 ; + BasisFunction { + { Name sn ; NameOfCoef Tn ; Function BF_Node ; + Support Dom_Hgrad_T ; + Entity NodesOf[All, Not Tfloating_The] ; } + { Name sf ; NameOfCoef Tf ; Function BF_GroupOfNodes ; + Support Dom_Hgrad_T ; Entity GroupsOfNodesOf[ Tfloating_The ] ; } + { Name sdn ; NameOfCoef Tdn ; Function BF_Node ; + Support DomainWithSurf_TL_The ; Entity NodesOf[ Sur_Tdisc_The ] ; } + } + SubSpace { + { Name Tcont ; NameOfBasisFunction { sn, sf } ; } + { Name Tdisc ; NameOfBasisFunction { sdn } ; } + } + GlobalQuantity { + { Name T_electrode ; Type AliasOf ; NameOfCoef Tf ; } + { Name Q_electrode ; Type AssociatedWith ; NameOfCoef Tf ; } + } + Constraint { + { NameOfCoef Tn ; EntityType NodesOf ; + NameOfConstraint Dirichlet_The ; } + // { NameOfCoef Tdn ; EntityType NodesOf ; // + // NameOfConstraint T_Discontinuity ; } // + { NameOfCoef T_electrode ; EntityType GroupsOfNodesOf ; + NameOfConstraint T_electrode ; } + { NameOfCoef Q_electrode ; EntityType GroupsOfNodesOf ; + NameOfConstraint Q_electrode ; } + } + } + For i In {1:NbSurface} + { Name FluxLayer~{i} ; Type Form0 ; + BasisFunction { + { Name gn ; NameOfCoef un ; Function BF_GroupOfNodes; + Support Dom_Hgrad_T ; Entity GroupsOfNodesOf[ Surface~{i} ] ; } + } + Constraint { + { NameOfCoef un ; EntityType GroupsOfNodesOf ; + NameOfConstraint FluxLayer~{i} ; } + } + } + EndFor + +} + +Formulation { + { Name Thermal_T ; Type FemEquation ; + Quantity { + { Name T ; Type Local ; NameOfSpace Hgrad_T ; } + { Name Tcont ; Type Local ; NameOfSpace Hgrad_T[Tcont] ; } + { Name Tdisc ; Type Local ; NameOfSpace Hgrad_T[Tdisc] ; } + { Name Tglob ; Type Global ; NameOfSpace Hgrad_T[T_electrode] ; } + { Name Qglob ; Type Global ; NameOfSpace Hgrad_T[Q_electrode] ; } + For i In {1:NbSurface} + { Name un~{i} ; Type Local ; NameOfSpace FluxLayer~{i} ; } + EndFor + + } + Equation { + + Integral { [ lambda[] * Dof{d T} , {d T} ] ; + In Vol_Lambda_The; Integration Int ; Jacobian Vol ; } + + Integral { [ ( lambda[]/thickness[] ) * Dof{Tdisc} , {Tdisc} ] ; + In Sur_Tdisc_The; Integration Int ; Jacobian Sur ; } + + Integral { [ -Qsource[] , {T} ] ; + In Vol_Qsource_The ; Integration Int ; Jacobian Vol ; } + + Integral { [ h[] * Dof{T} , {T} ] ; + In Sur_Convection_The ; Integration Int ; Jacobian Sur ; } + + Integral { [ -h[] * Tinf[] , {T} ] ; + In Sur_Convection_The ; Integration Int ; Jacobian Sur ; } + + GlobalTerm { [-Dof{Qglob} , {Tglob} ] ; In Tfloating_The ; } + + For i In {1:NbSurface} + Integral { [ 0 * Dof{un~{i}} , {un~{i}} ] ; + In Vol_Lambda_The ; Integration Int ; Jacobian Vol ; } + EndFor + } + } +} + + +Resolution { + { Name Thermal_T ; + System { + { Name Sys_The ; NameOfFormulation Thermal_T ; } + } + Operation { + If( Flag_QFromFile ) + GmshRead[ "Q.pos", 1]; + EndIf + DeleteFile["output.txt"]; + Generate Sys_The ; Solve Sys_The ; SaveSolution Sys_The ; + } + } +} + +PostProcessing { + { Name Thermal_T ; NameOfFormulation Thermal_T ; + PostQuantity { + { Name T ; Value { Term { [ {T} ] ; + In Dom_Hgrad_T ; Jacobian Vol ; } } } + { Name q ; Value { Term { [ -lambda[] * {d T} ] ; + In Dom_Hgrad_T ; Jacobian Vol ; } } } + { Name Tcont ; Value { Term { [ {Tcont} ] ; + In Dom_Hgrad_T ; Jacobian Vol ; } } } + { Name Tdisc ; Value { Term { [ {Tdisc} ] ; + In Dom_Hgrad_T ; Jacobian Vol ; } } } + { Name Qglob; Value { Term { [ {Qglob} ]; In Tfloating_The; } } } + { Name Tglob; Value { Term { [ {Tglob} ]; In Tfloating_The; } } } + + For i In {1:NbSurface} + { Name un~{i} ; Value { Local { [ {un~{i}} ] ; + In Vol_Lambda_The ; Jacobian Vol ; } } } + { Name IFlux~{i} ; Value { Integral { [ -lambda[]*{d T} * {d un~{i}} ]; + In Vol_Lambda_The ; Jacobian Vol ; Integration Int ; } } } + EndFor + + } + } +} + +PostOperation Map_T UsingPost Thermal_T { + If( !Flag_Regularization ) + Print[ Tcont, OnElementsOf Vol_Lambda_The, File "Tcont.pos"] ; + Print[ Tdisc, OnElementsOf Vol_Lambda_The, File "Tdisc.pos"] ; + EndIf + + If(Flag_ConstraintWin2) + Print[ Tglob, OnRegion Tfloating_The, File > "output.txt", Color "Ivory", + Format Table, SendToServer "Output/T window 2 [degC]" ]; + Else + Print[ Qglob, OnRegion Tfloating_The, File > "output.txt", Color "Ivory", + Format Table, SendToServer "Output/Q window 2 [degC]" ]; + EndIf + + For i In {1:NbSurface} + Print[un~{i}, OnElementsOf Vol_Lambda_The, + File Sprintf("FluxLayer_%g.pos",i)]; + Print[ IFlux~{i}[Vol_Lambda_The], OnGlobal, + Format TimeTable, File > "Fluxes.dat", Color "Ivory", + SendToServer Sprintf("Output/Heat flux surface %g [W]", i)]; + EndFor + Print[ T, OnElementsOf Vol_Lambda_The, File "T.pos" ] ; + Echo[ StrCat["l=PostProcessing.NbViews-1;", + "View[l].IntervalsType = 3;", + "View[l].NbIso = 30;", + "View[l].NormalRaise = 0.0005;"], + File "tmp.geo", LastTimeStepOnly] ; + Print [ q, OnLine {{0.02,0.0001,0}{0.02,0.05,0}} {200}, + Format SimpleTable, File "Cut.txt" ]; +} diff --git a/Thermics/brick_common.pro b/Thermics/brick_common.pro index 09a999c..4efa98e 100644 --- a/Thermics/brick_common.pro +++ b/Thermics/brick_common.pro @@ -1,37 +1,37 @@ - -// Onelab parameters - -Flag_Regularization = - DefineNumber[0, Name "Options/Regularize field", Choices {0,1} ]; -Flag_QFromFile = - DefineNumber[0, Name "Options/Heat source from file", Choices {0,1} ]; -Flag_ConstraintWin2 = - DefineNumber[0, Name "Options/Constraint in Window2", - Choices {0="Fixed temperature", 1="Fixed heat flux"} ]; -MeshRefinement = - DefineNumber[1, Name "Options/0Mesh refinement", - Help "Choose 1 for a coarse mesh and 0.1 for a fine mesh."]; - -// Geometrical dimensions - -mm=1e-3; // mm to m conversion factor - -dx_Brick=100*mm; dy_Brick= 50*mm; -e_layer = 1*mm; -dx_Win1 = 20*mm; dy_Win1 = 20*mm; -If( Flag_Regularization ) - dx_Win1 += e_layer; - dy_Win1 += e_layer; -EndIf - -dx_Win2 = 20*mm; dy_Win2 = 20*mm; -xc_Win1 = 25*mm; yc_Win1 = dy_Brick/2; -xc_Win2 = 75*mm; yc_Win2 = dy_Brick/2; - -// Element sizes - -s=1; -lc_Brick = dy_Brick/20 *s; -lc_Win1 = dx_Win1/10 *s; -lc_Win2 = dx_Win2/10 *s; - + +// Onelab parameters + +Flag_Regularization = + DefineNumber[0, Name "Options/Regularize field", Choices {0,1} ]; +Flag_QFromFile = + DefineNumber[0, Name "Options/Heat source from file", Choices {0,1} ]; +Flag_ConstraintWin2 = + DefineNumber[0, Name "Options/Constraint in Window2", + Choices {0="Fixed temperature", 1="Fixed heat flux"} ]; +MeshRefinement = + DefineNumber[1, Name "Options/0Mesh refinement", + Help "Choose 1 for a coarse mesh and 0.1 for a fine mesh."]; + +// Geometrical dimensions + +mm=1e-3; // mm to m conversion factor + +dx_Brick=100*mm; dy_Brick= 50*mm; +e_layer = 1*mm; +dx_Win1 = 20*mm; dy_Win1 = 20*mm; +If( Flag_Regularization ) + dx_Win1 += e_layer; + dy_Win1 += e_layer; +EndIf + +dx_Win2 = 20*mm; dy_Win2 = 20*mm; +xc_Win1 = 25*mm; yc_Win1 = dy_Brick/2; +xc_Win2 = 75*mm; yc_Win2 = dy_Brick/2; + +// Element sizes + +s=1; +lc_Brick = dy_Brick/20 *s; +lc_Win1 = dx_Win1/10 *s; +lc_Win2 = dx_Win2/10 *s; + -- GitLab