Tutorial example demonstrating the basic functionalities of the StabFem Software
This tutorial script is designed as a support for chapter 2 of the StabFem manual available here
We show how to compute, plot and manipulate the solution of three simple problems formulated in a L-shaped domain, namely steady and unsteady heat conduction, and Navier-Stokes flow with bottom-driven boundary conditions.
Source code for this program : SCRIPT_Lshape.m
NB in this simple tutorial the DataBase management is disabled. After studying the present example you may have a look at the related example SCRIPT_Lshape_DataBase.m
Contents
- Initialization
- Generation of the mesh
- First problem : steady conduction
- Second problem : unsteady conduction
- Adapts the mesh to both steady and unsteady solutions
- recomputes the solution on new mesh and plot the sum of both temperature fields
- Third problem : Loop over a range of omega
- Fourth problem : Navier-Stokes flow
- Final remark :
Initialization
close all; addpath([fileparts(fileparts(pwd)) '/SOURCES_MATLAB']); SF_Start('verbosity',3); % higest levels of verbosity results in more messages. % recommended values are 2 (minimal notice) and 4 (notice + freefem output). 6 and more is debug mode. SF_DataBase('disable'); % (optional :) this is to initialize the database management. % NB you may use 'create' instead of 'open' to clean up mkdir('FIGURES'); set(0,'defaulttextfontsize',16); % set font size for figures set(0,'defaultaxesfontsize',14); % idem
NOTICE - Initialization already done NOTICE - Verbosity set to 3 : Notice messages NOTICE - Database directory :./WORK/ NOTICE - This directory already exists NOTICE - Please type "SF_Status" to see what is available in this dir NOTICE - or type "SF_core_arborescence('cleanall')" to erase any previous data WARNING - Disabling database management. Some advanced functionalities may not work properly Warning: Directory already exists.
Generation of the mesh
The program Lshape_Mesh.edp is a simple mesh generator producing a mesh.msh file. We launch this program and import the mesh as a structure using the SF_Mesh.m driver :
Ndensity =40; ffmesh = SF_Mesh('Lshape_Mesh.edp','Options',{'meshdensity',Ndensity})
NOTICE - ### INITIAL MESH CREATED WITH np = 1429 vertices ffmesh = struct with fields: points: [3x1429 double] bounds: [3x160 double] tri: [4x2696 double] np: 1429 nbe: 160 nt: 2696 labels: [1 2] problemtype: 'unspecified' filename: './mesh.msh' meshtype: '2D' datatype: 'mesh' DataDescription: 'Mesh (generated by generic macro)' generationmode: 'initial' datastoragemode: 'unknown' TriangleSize: [0x1 double] status: 'loaded' np2: 5553 Vh_P2P2P1: [40440x1 double] Vh_P2P2P2P1: [56616x1 double] Vh_P2: [16176x1 double] meshgeneration: 0 symmetry: 'N'
NB this sequence is equivalent to executing the program with FreeFem++ in a shell terminal as follows :
> FreeFem++ Lshape_Mesh.edp -meshdensity 40
(but in addition the function returns a "handle' to the mesh which can be used for subsequent computations, plotted, etc...)
How to plot the mesh
figure();SF_Plot(ffmesh,'mesh','title','Mesh for L-shape body'); saveas(gca,'FIGURES/Lshape_Mesh','png'); % to save the figure pause(0.1);
NB the SF_Plot.m function, which is built upon the ffpdeplot.m function developped by Markus Meisinger, allows a variety of plots, including mesh plots, data plots using color levels, contour plots, or quiver plots. A large number of options are available, see the function or type "help SF_Plot".
First problem : steady conduction
- Steady thermal problem : on domain, T = 0 along boundary
Here is how to launch a simple FreeFem++ program Lshape_Steady.edp and import the data as a structure using the SF_Launch.m driver. Have a look at these programs to understand how it works !
heatS=SF_Launch('Lshape_Steady.edp','Mesh',ffmesh)
heatS = struct with fields: mesh: [1x1 struct] filename: 'Data.txt' DataDescription: 'Temperature in a L-Shape domain' datatype: 'HeatSteady' datastoragemode: 'ReP2' datadescriptors: 'T' T: [5553x1 double] status: 'loaded'
NB this sequence is equivalent to executing the program with FreeFem++ in a shell terminal as follows :
> FreeFem++ Lshape_Steady.edp
(but in addition the data is imported as an object which can be used for subsequent computations, plotted, etc...)
Note that the data is imported as a structure witch includes plottable fields (here "T", "dxT", "dyT"), numerical fields (here "HeatFlux") along as a number of string-valued descriptor fields. All this data is read from the file Data.ff2m generated by the FreeFem program ; the .ff2m format is designed for easy customization.
Plot the temperature field
figure(1);SF_Plot(heatS,'T','xlim',[0 1],'ylim',[0 1],'title', 'Steady conduction on a L-shaped domain: Temperature field '); % add one line on the figure hold on; plot([0 1],[.25,.25],'r--') saveas(gca,'FIGURES/Lshape_T0','png'); hold off;
Here is how to extract data along a 1D line and plot this data
Ycut = 0.25;Xcut = 0:.01:1; Tcut = SF_ExtractData(heatS,'T',Xcut,Ycut); figure(2);plot(Xcut,real(Tcut),'r-',Xcut,imag(Tcut),'b--'); title('Temperature along a line : T(x,0.25)');xlabel('x');ylabel('T'); saveas(gca,'FIGURES/Lshape_T0_Cut','png') pause(0.1);
Note: To improve runtime build MEX function fftri2gridfast() from fftri2gridfast.c
Second problem : unsteady conduction
- Unsteady thermal problem : on domain, along boundary.
Assuming harmonic dependance as , this leads to:
on domain, along boundary
Have a look at the program Lshape_Unsteady.edp to see how this problem is solved by FreeFem++ !
The program computes the field as well as the complex heat flux such as ; namely : .
First we solve the problem for a single value of :
omega = 100; heatU=SF_Launch('Lshape_Unsteady.edp','Options',{'omega',omega,'kappa',1},'Mesh',ffmesh,'DataFile','Heat_Unsteady.ff2m')
heatU = struct with fields: mesh: [1x1 struct] filename: 'Heat_Unsteady.txt' DataDescription: 'Temperature field in a L-shaped region ; Unsteady conduction with harmonic forcing at boundaries' datatype: 'HeatUnsteady' datastoragemode: 'CxP2' datadescriptors: 'T' omega: 100 INDEXING: [1x1 struct] HeatFlux: 17.1650 -21.3108i normGradT: [1429x1 double] T: [5553x1 double] status: 'loaded'
NB this sequence is equivalent to executing the program with FreeFem++ in a shell terminal as follows :
> FreeFem++ Lshape_Unsteady.edp -omega 40 -kappa 1
the parameters passed as "-omega 40 -kappa 1" are detected within the program using the "getARGV" Freefem function.
We plot the results
figure(); SF_Plot(heatU,'T.re','colormap','redblue','title',{'Unsteady heat condition problem ' , 'real(colors) and imaginary(levels) parts of T_1(x)'}); hold on; SF_Plot(heatU,'T.im','contour','on','xystyle','off'); saveas(gca,'FIGURES/Lshape_Tc','png');
Note that resulting value 'heatU' has a field 'HeatFlux' corresponding to
heatU.HeatFlux
ans = 17.1650 -21.3108i
Adapts the mesh to both steady and unsteady solutions
We now use the SF_Adapt.m function to adapt the mesh to the results. This function (which is a wrapper for the FreeFem++ program AdaptMesh.edp) allows to perform mesh adaptation using up to 8 fields with various data type (scalar P1 or P2 data ; composite data for instance [P2xP2xP1] ,...) Have a look at these programs to understand how it works !
ffmesh_adapted = SF_Adapt(ffmesh,heatS,heatU)
WARNING - When using SF_Adapd it is advised to define a database folder. NOTICE - SF_Adapt : created new mesh ; np = 3331 vertices ffmesh_adapted = struct with fields: points: [3x3331 double] bounds: [3x236 double] tri: [4x6424 double] np: 3331 nbe: 236 nt: 6424 labels: [1 2] problemtype: 'unspecified' filename: './mesh_adapt.msh' meshtype: '2D' datatype: 'mesh' DataDescription: 'Mesh (generated by generic macro)' generationmode: 'adapted' datastoragemode: 'unknown' TriangleSize: [0x1 double] status: 'loaded' np2: 13085 Vh_P2P2P1: [96360x1 double] Vh_P2P2P2P1: [134904x1 double] Vh_P2: [38544x1 double] meshgeneration: NaN symmetry: 'N'
NB here the first argument is the mesh handle and the return object is a handle to the new mesh. We could also have used the alternative syntax: [heatS,heatU] = SF_Adapt(heatS,heatU) which, in addition, will project back the two fields on the new mesh and return a handle to them. It is not mandatory to specify the mesh as first argument since the mesh is also a sub-object of the fields.
figure; subplot(1,2,1); SF_Plot(ffmesh,'mesh','title','Initial mesh'); subplot(1,2,2); SF_Plot(ffmesh_adapted,'mesh','title','Adapted mesh');
recomputes the solution on new mesh and plot the sum of both temperature fields
heatS=SF_Launch('Lshape_Steady.edp','Mesh',ffmesh_adapted); heatU=SF_Launch('Lshape_Unsteady.edp','Options',{'omega',omega},'Mesh',ffmesh_adapted,'DataFile','Heat_Unsteady.ff2m'); heatSum = SF_Add({heatS,heatU},'coefs',[1 1])
WARNING - in SFcore_AddMESHFilenameToFF2M : File Addition.ff2m exists in root directory ! this may lead to incorrect behavior WARNING - When using SF_Add it is advised to define a database folder. NOTICE - in SF_Add : processsing data from txt files : T heatSum = struct with fields: mesh: [1x1 struct] filename: 'Addition.txt' DataDescription: '(no description provided when creating file)' datatype: 'Addition' datastoragemode: 'ReP2' datadescriptors: 'T' meshfilename: './mesh_adapt.msh' T: [13085x1 double] status: 'loaded'
plot the results
figure();SF_Plot(heatSum,'T','colormap','redblue','title','Temperature (sum of two problems)'); saveas(gca,'FIGURES/Lshape_Tc','png');
Third problem : Loop over a range of omega
The next program Lshape_Impedance.edp solves the unsteady heat conduction problem over a range of and returns the corresponding values of .
res = SF_Launch('Lshape_Impedance.edp','Mesh',ffmesh_adapted,'Options',{'kappa',1},'DataFile','Heat_Unsteady_loop.ff2m')
res = struct with fields: mesh: [1x1 struct] filename: 'Heat_Unsteady_loop.txt' DataDescription: 'Solution of the unsteady thermal problem over a range of omega' datatype: 'EXAMPLE' datastoragemode: 'columns' datadescriptors: 'omega,Flux_r,Flux_i' kappa: 1 INDEXING: [1x1 struct] omega: [50x1 double] Flux: [50x1 double] status: 'loaded'
We plot the 'thermal impedance' defined as . We compare with the asymptotic solutions in the low-frequency and high-frequency limits.
figure;loglog(res.omega,real(1./res.Flux),'r','LineWidth',2); hold on;loglog(res.omega,imag(1./res.Flux),'b','LineWidth',2); rangeomegaLOW = logspace(-1,0,10); loglog(rangeomegaLOW,2./rangeomegaLOW,'k--','LineWidth',2); rangeomegaHIGH = logspace(2,3,10); loglog(rangeomegaHIGH,.25.*rangeomegaHIGH.^(-.5),'k:','LineWidth',2); xlabel('\omega');ylabel('Re(Z_\theta), Im(Z_\theta)'); title('Thermal impedance Z_\theta(\omega)') legend('$Re(Z_\theta$)', '$Im(Z_\theta)$','Low-$\omega$ asymptotics','High-$\omega$ asymptotics','Interpreter','latex'); saveas(gca,'FIGURES/Z_omega','png');
Fourth problem : Navier-Stokes flow
Eventually we call a third program Lshape_NavierStokes.edp which computes the flow in the L-shape domain (with bottom-driven boundary conditions). by solving the Navier-Stokes Flow using Newton iteration.
- Navier-Stokes problem : $ %% \nabla \cdot \vec u = 0;$$ on bottom, and on other boundaries
Ndensity =30; ffmesh = SF_Mesh('Lshape_Mesh.edp','Options',{'meshdensity',Ndensity}); viscosity = 1;Umax = 1; Flow = SF_Launch('Lshape_NavierStokes.edp','Mesh',ffmesh,'Options',{'Re',10})
NOTICE - ### INITIAL MESH CREATED WITH np = 826 vertices Flow = struct with fields: mesh: [1x1 struct] filename: 'Data.txt' DataDescription: 'Navier-Stokes flow in a L-shaped bottom-driven cavity' datatype: 'StokesFlow' datastoragemode: 'ReP2P2P1.1' datadescriptors: 'ux,uy,p,Re' Re: 10 INDEXING: [1x1 struct] Fx: -1.7808 vorticity: [826x1 double] ux: [9180x1 double] uy: [9180x1 double] p: [4590x1 double] status: 'loaded'
Remarks : - Here one option is specified. The FreeFem program is launched as follows: > FreeFem++ Lshape_NavierStokes.edpc -Re 10
- In this case the data is a vectorial dataset (ux,uy,p) defined using (P2,P2,P1) mixed elements by FreeFem. Note that the SF_Launch driver is able to recognize this and import the fields (ux,uy,p) along with the vorticity.
We adapt the mesh and recompute, this time for Re=20
ffmesh = SF_Adapt(ffmesh,Flow); Flow = SF_Launch('Lshape_NavierStokes.edp','Mesh',ffmesh,'Options',{'Re',20})
WARNING - When using SF_Adapd it is advised to define a database folder. NOTICE - SF_Adapt : created new mesh ; np = 1933 vertices Flow = struct with fields: mesh: [1x1 struct] filename: 'Data.txt' DataDescription: 'Navier-Stokes flow in a L-shaped bottom-driven cavity' datatype: 'StokesFlow' datastoragemode: 'ReP2P2P1.1' datadescriptors: 'ux,uy,p,Re' Re: 20 INDEXING: [1x1 struct] Fx: -1.3219 vorticity: [1933x1 double] ux: [21984x1 double] uy: [21984x1 double] p: [10992x1 double] status: 'loaded'
We plot the vorticity fields with isocontours; We then add the velocity field using quiver plot
figure;SF_Plot(Flow,'vorticity','colorrange',[-20 20]); hold on;SF_Plot(Flow,{'ux','uy'},'ylim',[0 1],'xlim',[0 1],'title','Navier-Stokes flow (vorticity and velocity fields)'); saveas(gca,'FIGURES/StokesFlow','png');
Final remark :
To understand what the FreeFem++ programs actually do behind the interface, you may have a look to the file ".stabfem_log.bash" generated at the end of this script, which regroups all the calls to FreeFem programs and file manipulations !
% [[PUBLISH]] -> this tag is here to tell the git runner to automatically generate a web page from this script % fclose(fopen('SCRIPT_Lshape_NoDB.success','w+'));