// THIS IS A RAW SPARSELIZARD CODE FILE! // VALIDATED CODE BUT NOT CLEANED // PLEASE REFER TO OTHER EXAMPLES FOR A SMOOTH SPARSELIZARD INTRODUCTION // CREDITS: R. HAOUARI // Time simulation of a thermaoacoustic wave propagation // Cylindrical wave created by a volumic heat source ( models laser beam) // Thermoviscouss acoustics assumed // Mechanical coupling with a glass membrane and radiation simulated as well #include "sparselizardbase.h" #include #include #include using namespace std; using namespace mathop; // Arguments are: // r cavity, membrane radius // depth cavity depth // thick membrane thickness // BLth thickness of the boundary layer mesh createmesh(double rmb, double depth, double thick, double BLth); void sparselizard(void) { //Save folder std::string savefolder="./data/"; wallclock clk; clock_t start=clock(); // Axisymmetric assumption: setaxisymmetry(); //Geometry //--------- // Define the geometric dimensions [m]: double r = 500e-6, thick = 5e-6, depth = 750e-6, BLth=10e-6; //axis region set to avoid weird stuff in calculation double caxis=1e-6; // The domain regions as defined in 'createmesh': int membrane = 1, KviT = 2, topair = 3, wall=4, laser=5, BL=6 , clamp=8,axis=9 , outair=10,outrad=11,botcoupl=12, P1=13,P2=14, topcoupl=15; ; // Create the geometry and the mesh: mesh mymesh = createmesh(r,depth,thick,BLth); // Write the mesh for display: mymesh.write(savefolder+"geometry.msh"); // Define additional regions: int fluid = regionunion({KviT,outair}); int mechacoucoupl = regionintersection({fluid,membrane}); int slip = regionunion({botcoupl,wall}); //normal tracking (for better BC setting... if needed) normal(regionunion({axis,wall,botcoupl})).write(regionunion({axis,wall,botcoupl}),savefolder+"normal.vtu"); parameter nsign; nsign|axis=1; nsign|wall=1; nsign|botcoupl=-1; expression nor=(nsign*normal(slip)); nor.write(regionunion({axis,wall,botcoupl}),savefolder+"fixed_normal.vtu"); //Unknown fields defintion //-------------------------- field u("h1xyz"),v("h1xyz"), p("h1"),T("h1"), y("y"),x ("x"),L("h1xyz"); //Setting interpolation order : u.setorder(membrane, 2); v.setorder(KviT, 2); p.setorder(fluid, 1); T.setorder(KviT, 2); //Lagragian multipliers , vectorial form L.setorder(botcoupl,2); //gas material properties around equilibrium ( 293 K and 1 Bar ) - Linear approximation in comment //--------------------------------------------------------------------------------------------- expression rho0, muB,lmb,kappa,gamma,Cp,c,alpha_p,beta,rhot; double R_const=8.3144598,Rs=287; double p0=1.013e5,T0=293; rho0=(p0)*0.02897/(R_const*(T0));//(p+p0)*0.02897/(R_const*(T+T0));//-(T)*0.00431073+1.20494464330308; lmb=-8.38278E-7+8.35717342E-8*(T0)-7.69429583E-11*pow(T0,2)+4.6437266E-14*pow(T0,3)-1.06585607E-17*pow(T0,4);//(T)*4.99221E-08+1.81322817E-05; muB=0.6*lmb;//(T)*2.99532E-08+1.08793690E-05; kappa=-0.00227583562+1.15480022E-4*(T0)-7.90252856E-8*pow(T0,2)+4.11702505E-11*pow(T0,3)-7.43864331E-15*pow(T0,4);//(T)*7.96428E-05+2.57563324E-02; gamma=1.4;//-(T)*1.8214E-05+1.39948988; Cp=1047.63657-0.372589265*(T0)+9.45304214E-4*pow(T0,2)-6.02409443E-7*pow(T0,3)+1.2858961E-10*pow(T0,4);//(T)*0.032741694+1.00541619E+03; c=sqrt(1.4*R_const/0.02897*(T0));//(T)*0.589990819+343.051751; alpha_p=sqrt(Cp*(gamma-1)/T0)/c; beta=gamma/(rho0*pow(c,2)); rhot=rho0*(beta*(p+p0)-alpha_p*(T+T0)); // Membrane properties: Young modulus, Poisson's ratio and volumic mass //---------------------------------------------------------------------- //parameter E, nu, rho; double Es = 73.1e9,nus= 0.17; parameter rho; rho|membrane = 2203; rho|fluid= rho0; //incorporates the fluid volumic mass in the "parameter" container //Creation of the weak form object //----------------------------------- formulation chambre; //Scaling factor for numerical conditionning (if needed) //----------------------------------------------------------- double scaling = 1e0; // Standard isotropic elasticity //------------------------------- chambre += integral(membrane, predefinedelasticity(dof(u), tf(u),Es, nus) ); //Inertial term: chambre += integral(membrane, -rho*dtdt(dof(u))*tf(u) ); //Mass conservation //-------------------- chambre += integral(KviT,(rho*div(dof(v))+rho*(beta*(dt(dof(p)))-alpha_p*(dt(dof(T)))))*tf(p) ); //Navier-Stokes //-------------- chambre += integral(KviT,-rho*dt(dof(v))*tf(v)); chambre += integral(KviT,-grad(dof(p))*tf(v)); chambre += integral(KviT,-lmb*(frobeniusproduct(grad(dof(v)),grad(tf(v)))+frobeniusproduct(transpose(grad(dof(v))),grad(tf(v))))); chambre += integral(KviT,(2*lmb/3-muB)*div(dof(v))*trace(grad(tf(v))) ); //non linearity terms of NS //expression(v).reuseit(); //chambre += integral(fluid,-rho*( grad(v)*dof(v) + grad(dof(v))*v - grad(v)*v )*tf(v)); //thermal process //---------------- chambre+=integral(KviT,kappa*grad(dof(T))*grad(tf(T))); chambre+=integral(KviT,(-alpha_p*T0*dt(dof(p))+rho*Cp*dt(dof(T)))*tf(T)); //laser heat source in the cavity volume //----------------------------------------- double shift=.5e-6,pulsewidth=1e-7,waist=100e-6,absp=1,power=1; //spatial shape expression laser_shape=power*2/(getpi()*pow(waist,2))*pow(2.71828,-2*pow(x/waist,2)); //gausian time pulse expression time_shape=pow(2.71828,-pow(getpi()/pulsewidth*(t()-shift),2));// //square time pulse //expression time_shape(t()-(shift-pulsewidth/2),expression(-t()+(shift+pulsewidth/2),power/pulsewidth,0),0); //Beert-Lambert law for absorption chambre+=integral(KviT,-absp*pow(2.71828,absp*y)*laser_shape*time_shape*tf(T)); // The elastic wave propagation equation //------------------------------------------ chambre += integral(outair, -grad(dof(p))*grad(tf(p)) -1/pow(c,2)*dtdt(dof(p))*tf(p)); // A Sommerfeld condition is used on the fluid boundary to have outgoing waves: chambre += integral(outrad, -1/c*dt(dof(p))*tf(p)); // Elastoacoustic coupling terms. //----------------------------------- //stress transmission from fluid to solid along the normal (carreful normal direction for the sign !!!) chambre += integral(botcoupl, dof(p)*normal(mechacoucoupl)*tf(u) ); //Use of Lagrange multipliers Lx and Ly to link membrane and fluid velocity //Vectorial form for ease of implementation chambre += integral(botcoupl, -dof(L)*tf(u)); chambre += integral(botcoupl, dof(L)*tf(v)); chambre += integral(botcoupl, (dt(dof(u))-dof(v))*tf(L)); //Coupling for the upper region (pure mechanical) chambre += integral(topcoupl, -dof(p)*normal(topcoupl)*tf(u) * scaling); chambre += integral(topcoupl, rho0*normal(topcoupl)*dtdt(dof(u))*tf(p)/scaling); //Constrained type boundary conditions //-------------------------------------- //membrane clamped on the clamp line: u.setconstraint(clamp); //no slip on the wall v.setconstraint(wall); //isothermal on the interfaces T.setconstraint(regionunion({botcoupl,wall})); //symmetry (axial case : for pure 2D, not in axisym) //v.compx().setconstraint(axis); //u.compx().setconstraint(axis); //No Lz Lagrange multiplier L.compz().setconstraint(mechacoucoupl); //Slip BC //------------ // //set non-zero initial values : T0 and p0 //----------------------------------------- //T.setvalue(fluid,T0); //p.setvalue(fluid,p0); vec init(chambre); //init.setdata(fluid,T); //init.setdata(fluid,p); // Define the Gen alpha object to time-solve formulation 'chambre' //------------------------------------------------------------------ genalpha gena(chambre, init, vec(chambre), vec(chambre), {false,true,true,true}); gena.setparameter(0.75); gena.settolerance(1e-10); //variable time stepping resolution //-------------------------------------- //create as many vectors as different time steps //each time the last timestep is not computed, start the next one with the previous last one std::vector> timesteping; timesteping={ //{0,10e-9,4e-6,10} // different time steps {0,.01e-6,4.999e-6,10} ,{5e-6,.05e-6,14.99e-6,2} ,{15e-6,.1e-6,24.99e-6,1} ,{25e-6,.25e-6,99.99e-6,1} //,{100e-6,1e-6,1e-3,10} }; //parsing for file handling //------------------------------------ //evaluate the total amount of steps to be computed and written int tot_steps=0; int tot_steps_rec=0; double temp; for(int i=0; i\n"; timeorder << "\n"; timeorder << " \n"; probes.close(); //initiate solution vectors std::vector> ssol(timesteping.size()); std::vector> solution(timesteping.size());//this one is for the field F std::vector> solution2(timesteping.size());//that one for dF/dt wallclock clk2; int index=0; //initiate a vector for tracking all the saved time steps std::vector times(tot_steps); //extra field for display v_membrane field dtu("h1xyz"); dtu.setorder(membrane, 2); for (int i=0;i\n"; timeorder << " \n"; timeorder << " \n"; timeorder << " \n"; timeorder << " \n"; timeorder << " \n"; timeorder.close(); //compute probes values and record it in the file //open the file probes.open(filename, std::ios_base::app); probes.precision(15); //step and time index are first probes << index <<" "<< times[index] << " "; // put then each expression with the same order than their definition probes << expression(p).max(KviT,5)[0] <<" " ; probes << expression(T).max(KviT,5)[0] <<" " ; probes << expression(sqrt(v.compy()*v.compy()+v.compx()*v.compx())).max(KviT,5)[0] <<" " ; probes << norm(v).integrate(KviT, 5) << " " ; probes << norm(p).integrate(KviT, 5) << " " ; probes << norm(T).integrate(KviT, 5) ; //probes << expression(sqrt(u.compy()*u.compy()+u.compx()*u.compx())).max(membrane,5)[0]<<" " ; //probes << expression(dtu.compy()).max(membrane,5)[0] ; //end the line probes << endl; //close the file probes.close(); index++; std::cout <<" "<< index << std::flush; } std::cout << std::endl; clk2.print("step took: "); } timeorder.open(filename2, std::ios_base::app); timeorder << "\n"; timeorder << "\n"; timeorder.close(); clk.print("Total time elapsed: "); probes.open(filename, std::ios_base::app); probes << endl << endl <<"Total time elapsed: "<< clk.toc()/1e9 << " sec" << endl; probes.close(); } // THE MESH BELOW IS FULLY STRUCTURED AND IS CREATED USING THE (BASIC) SPARSELIZARD GEOMETRY CREATION TOOL. // BOUNDARY LAYER IS ALSO INCLUDED AS WELL AS A CLOSE LINE TO THE Z-AXIS TO ACT AS THE REVOLUTION AXE mesh createmesh(double rmb, double depth, double thick, double BLth) { //closeness of the axis double caxis=1e-6, rarc=2e-3; // Give names to the physical region numbers: int membrane = 1, KviT = 2, topair = 3, wall=4, laser=5, BL=6 , clamp=8,axis=9 , outair=10,outrad=11,botcoupl=12, P1=13,P2=14, topcoupl=15; ; // Number of mesh layers: int nxmb = 49, nzmb = 4, nzKviT = 73, nair = 50, nBLth=10; // define a vector of nodes along a vertical line std::vectorKviT_vpoints(3*(nzKviT+2*nBLth+1)); double step1=sqrt(BLth)/nBLth, step2=(depth-2*BLth)/nzKviT; // nodes are spaced accordignly to have a boundary layer mesh for( int i=0;i nBLth && i<=nBLth+nzKviT) { KviT_vpoints[3*i]=0;KviT_vpoints[3*i+1]=-BLth-(i-nBLth)*step2;KviT_vpoints[3*i+2]=0; } else { // if linear BL :-(i-nzKviT-2*nBLth)*BLth/nBLth KviT_vpoints[3*i]=0;KviT_vpoints[3*i+1]=-depth+std::pow((i-nzKviT-2*nBLth)*step1,2);KviT_vpoints[3*i+2]=0; } } } KviT_vpoints[3*(nzKviT+2*nBLth)]=0;KviT_vpoints[3*(nzKviT+2*nBLth)+1]=-depth;KviT_vpoints[3*(nzKviT+2*nBLth)+2]=0; // define a vector of nodes along a horizontal line std::vectorKviT_hpoints(3*(2+nxmb+nBLth+1)); step1=sqrt(BLth)/nBLth; step2=(rmb-BLth-caxis)/(nxmb); //special node for the axis ; should be smaller than one node KviT_hpoints[0]=0;KviT_hpoints[1]=0;KviT_hpoints[2]=0; KviT_hpoints[3]=caxis;KviT_hpoints[4]=0;KviT_hpoints[5]=0; for( int i=2;i