| 稳态计算 | 时间循环直到收敛 |
|---|---|
| 瞬态计算 | 循环到指定的时间步结束 |
elsA kernel包括400个class,分配到26个modules.这些模块又归于6个layer,上层只依赖下层,单向职责.
Fields是elsA最基本的操作对象,作为real,integer,boolean的容器.用后缀表示版本,F代表Float,I,B.
00001: typedef FldFieldF FldCellF
fileld定义为2D结构.
E_Int nfld = 5; FldCellF wCons(ncell, nfld); Construction of a field which stores fluxes: FldIntF flux(3*ncell, nfld);
FldNodeF x(ncell, 3); FldNodeF y(ncell, 3); FldNodeF z(ncell, 3);
FldArrayF TurKO::getModConst() const { FldArrayF modConst (7); modConst[0] = _kappa; modConst1 = _sigma1; modConst2 = _sigmae1; modConst3 = _beta1; modConst4 = _wsig1; modConst5 = _betae; modConst6 = _Sr; }
FldArrayF f(100,2); f(3,2)=3.14159; // assigns pi to the fourth element of component 2 FldArrayF g(100); g[0] = 2.22;
Fld 比c/c++数组的优势
传递数据给Fortran77函数.通过给FldField动态分配的内存地址
10.1.4.1 FldArray 内部结构
FldArray在一个连续的内存空间存储数据,为动态分配的.我们可以认为它是c 指针管理内存的wrapper._data指向这块内存.这种1D的布局和传统的Fortran和c代码一致.
00001: //返回第fld物理变量的第l个节点数据,按_nfld存 00002: inline E_Float 00003: FldArrayF::operator()(E_Int l, E_Int fld) const 00004: { 00005: return (_data[l + (fld-1)*_size]); 00006: } 00007: 00008: //We would have the transpose (or swapped) implementation: 00009: //另外一种的存储索引方式,按l存 00010: inline E_Float 00011: FldArrayF::operator()(E_Int l, E_Int fld) const 00012: { 00013: return (_data[fld-1 + l*_nfld]); 00014: } 00015:
在fortran中定义
00001: extern "C" 00002: { 00003: void 00004: denconvec_(const E_Int& ncell, const E_Int& neqtot, const E_Int& neq, 00005: const E_Int& ro, const E_Int& rou, const E_Int& roe, 00006: const E_Int& rog, const E_Int& roug, const E_Int& roeg, 00007: const E_Float* consvar, const E_Float* press, 00008: E_Float* fdx, E_Float* fdy, E_Float* fdz); 00009: } 00010:
在C++中使用
00001: denconvec_(ncell, neqTot, nbEqMoyComp, 00002: rho, mom, ene, rhoG, momG, eneG, 00003: wCons.begin(), press.begin(), 00004: fdx.begin(), fdy.begin(), fdz.begin() );
00001: fdX( 0,1), fdX(0,2), fdX(0,3),..., fdX( 0,neq), 00002: ..., 00003: fdX(ncell-1,1), ..., fdX(ncell-1,neq)
00001: fdX(0, 1), fdX(1,1),fdX(2,1),..., fdX(ncell-1, 1), 00002: ..., 00003: fdX(0,neq),..., fdX(ncell-1,neq)
00001: SUBROUTINE denconvec(ncell, neqtot, neq, 00002: & ro, rou, roe, 00003: & rog, roug, roeg, 00004: & w, p, 00005: & fdx, fdy, fdz) 00006: IMPLICIT NONE 00007: C_IN 00008: INTEGER_E ncell, neqtot, neq 00009: REAL_E w(0:ncell-1,neqtot) ! Conservative Variables 00010: REAL_E p(0:ncell-1) ! Pressure 00011: C_OUT 00012: REAL_E fdx(0:ncell-1,neq) ! Convective Flux X-Component 00013: REAL_E fdy(0:ncell-1,neq) ! Convective Flux Y-Component 00014: REAL_E fdz(0:ncell-1,neq) ! Convective Flux Z-Component 00015: [.......] 00016: DO icell = 0, ncell-1 00017: roi = ONE / w(icell,rog) 00018: fdx(icell,ro) = w(icell,roug) 00019: fdy(icell,ro) = w(icell,rovg) 00020: fdz(icell,ro) = w(icell,rowg) 00021: [.......]
GeoGrid在kernel中广泛使用,因为很多的CFD类需要一个指向GeoGrid的指针.GeoGrid为GeoGridMetrics和GeoConnect的组合.他们负责
通过如下控制Ghost
• GHOST_I1 ghost cells in IMIN(代表i的最小index), GHOST_I2 ghost cells in IMAX(代表i的最大index), • GHOST_J1 ghost cells in JMIN, GHOST_J2 ghost cells in JMAX, • GHOST_K1 ghost cells in KMIN, GHOST_K2 ghost cells in KMAX.
• GHOST_I1 ghost interfaces in IMIN, GHOST_I2-1 ghost interface in IMAX, • GHOST_J1 ghost interfaces in JMIN, GHOST_J2-1 ghost interface in JMAX, • GHOST_K1 ghost interfaces in KMIN, GHOST_K2-1 ghost interface in KMAX.
• GHOST_I1 ghost nodes in IMIN, GHOST_I2-1 ghost node in IMAX, • GHOST_J1 ghost nodes in JMIN, GHOST_J2-1 ghost node in JMAX, • GHOST_K1 ghost nodes in KMIN, GHOST_K2-1 ghost node in KMAX.
The default values are: GHOST_I1 = 2; GHOST_I2 = 2; GHOST_J1 = 2; GHOST_J2 = 2; GHOST_K1 = 2; GHOST_K2 = 2;
上述定义的好处就是我们在cell,interface和node的index之间关系简化,使得我们在他们中循环很方便.我们在i,j,k方向上的cells,nodes和interface数目完全相同.
00001: DO n=n0cell, nfcell ! loop on cells 00002: ni1 = n ! "i" interface (left) 00003: nj1 = n + ncell ! "j" interface (down),ncell是所有的cell个数,因为先存i,后存j,再存k 00004: nk1 = n + 2*ncell ! "k" interface (back) 00005: .... 00006: ni2 = n + inccell(1,0,0) ! "i" interface (right 00007: nj2 = n + ncell + inccell(0,1,0) ! "j" interface (up) 00008: nk2 = n + 2*ncell + inccell(0,0,1) ! "k" interface (front) 00009:
00001: inline E_Int 00002: GeoConnect::getNbCell() const 00003: { 00004: return ((_im - 1 + GHOST_I1 + GHOST_I2)* 00005: (_jm - 1 + GHOST_J1 + GHOST_J2)* 00006: (_km - 1 + GHOST_K1 + GHOST_K2)); 00007: } 00008: inline E_Int 00009: GeoConnect::getNbInti() const 00010: { 00011: return getNbCell(); 00012: }
其中所有的方法2,3的计算方式都一样
Operator的类主要为空间离散.每一个operator都必须计算一个定义在特殊几何体(cell或者interface)上的Fld-FieldF对象.
OperBase为抽象类.比较重要的属性:
00001: virtual void prepare(const EosSysEq&, EosElemSysType,EosIdealGas* eos, const GeoGridBase* grid);
prepare函数用于初始化这些指针.
继承自OperBase的类有两种
继承自OperBase.
00001: // compute the gradient of the conservative variables 00002: void compute( FldCellF& fldOut, 00003: const list<BndPhys*>& listBnd, 00004: const list<JoinBase*>& listJoin, 00005: AuxField identOfField = MISC); 00006: 00007: // compute the gradient of non conservative variables (?) 00008: virtual void compute( FldCellF& fldOut, 00009: const list<BndPhys*>& listBnd, 00010: const list<JoinBase*>& listJoin, 00011: const FldCellF& fldIn, 00012: AuxField identOfField);
梯度和flux计算在所有的cell和interfaces上使用相同的数值算法计算.但是标准的计算公式会在border区域给出错误的结果.所以operator对象需要和boundary对象协作.
计算OperTerm分为两步
OperTerm::_setOfIdent为list<AuxField>类型,用于识别什么样的附属计算需要进行.computeAllField调用computeFiled()函数计算所有的注册过的附属场.
00001: virtual void computeAllField(const list<BndPhys*>* listBnd = E_NULLPTR, 00002: const list<JoinBase*>* listJoin = E_NULLPTR); 00003: 00004: virtual void computeField(AuxField identOfField, 00005: const list<BndPhys*>* listBnd = E_NULLPTR, 00006: const list<JoinBase*>* listJoin = E_NULLPTR);
Flus和source在这一个阶段还没有计算,下一节介绍.
继承自OperTerm,使用上面介绍的策略1实现了主要的compute()方法.
00001: void OperFlux::compute( FldIntF& fldOut, 00002: const list<BndPhys*>& listBnd, 00003: const list<JoinBase*>* listJoin ) 00004: { 00005: compFlux(...); 00006: computeAllBorders(...); 00007: } 00008:
定义了flux类最重要的抽象方法compFlx.知道了cell center上的守恒变量,这个方法提供了interfaces上的flux.
00001: virtual void compFlux(const FldCellF& fldIn,FldIntF& fldOut) = 0;
OperFlux还定义了另外一个重要的方法:computeAllBorders(),这个方法用于计算边界区域的flux,并且考虑边界条件.所有的物理边界,使用下述的思想:
OperSou是source term的抽象类.这个类继承自OperTerm类.