[OpenFOAM 소스코드 파해치기] 경계조건
작성일 : 2012년 9월 17일
번역일 : 2016년 4월 4일
크롬 브라우저로 보시는 것을 권장해 드립니다.
------------------------------------------------------------
----- OpenFOAM 소스코드를 다루는 문법 기본 -----
------------------------------------------------------------
들어가기 |
경계조건 (Boundary Condition)에 대해 알아보자
사용 버전 |
OpenFOAM 2.1.1
경계조건의 종류 |
방정식의 경계조건은 주로 2종류로 구분할 수 있다.
- Dirichlet boundary condiiton : 값을 지정
- Neumann boundary condition : 구배를 지정
OpenFOAM의 경계조건 클래셍는, 기본경계조건과, 그것들로부터 도출되는(derived) 경계조건이 있다.
기본 경계조건
- fixedValue : 값을 지정한다 (Dirichlet boundary condition)
- fixedGradient : 구배를 지정한다 (Neumann boundary condition)
- mixed : Dirichlet boundry condition과 Neumann boundary condition 의 혼합
- zeroGradient : 구배 0
- calculated : 값을 별도의 필드에서 계산
도출되는 경계조건 (Derived boundary condition) |
도출되는 경계조건 클래스는, 기본경계조건클래스를 계승하여 작성된다. 몇종류의 코드를 살펴보도록 하자.
코드는 $FOAM_SRC/finiteVolume/fields/fvPatchField/derived 에 있다.
기본 경계조건
class buoyantPressureFvPatchScalarField
:
public fixedGradientFvPatchScalarField
buoyantPressure 는 fixedGradient 를 기반으로 한다.
buoyantPressureFvPatchScalarField.C
void Foam::buoyantPressureFvPatchScalarField::updateCoeffs() { if (updated()) { return; } const uniformDimensionedVectorField& g = db().lookupObject<uniformDimensionedVectorField>
("g"); const fvPatchField<scalar> & rho = patch().lookupPatchField<volScalarField, scalar> (rhoName_); // If the variable name is "p_rgh", "ph_rgh" or "pd" // assume it is p? - rho*g.h and set the gradient appropriately. // Otherwise assume the variable is the static pressure. if ( dimensionedInternalField().name() == "p_rgh" || dimensionedInternalField().name() == "ph_rgh" || dimensionedInternalField().name() == "pd" ) { gradient() = -rho.snGrad()*(g.value() & patch().Cf()); } else { gradient() = rho*(g.value() & patch().nf()); } fixedGradientFvPatchScalarField::updateCoeffs(); }
압력의 변수명을 통해 거동을 바꾸고 있는 것을 알 수 있다. "gradien() = ..."으로 구배를 지정하고 있다. 여기서 ρgh 의 구배를 주고 있다.
flowRateInletVelocity
class flowRateInletVelocityFvPatchVectorField
:
public fixedValueFvPatchVectorField
fixedVlue 가 기반이 되어있다.
void Foam::flowRateInletVelocityFvPatchVectorField::updateCoeffs() { if (updated()) { return; } const scalar t = db().time().timeOutputValue(); // a simpler way of doing this would be nice const scalar avgU = -flowRate_->value(t)/gSum(patch().magSf()); tmp<vectorField>
n = patch().nf(); const surfaceScalarField& phi = db().lookupObject<surfaceScalarField> (phiName_); if (phi.dimensions() == dimVelocity*dimArea) { // volumetric flow-rate operator==(n*avgU); } else if (phi.dimensions() == dimDensity*dimVelocity*dimArea) { if (rhoName_ == "none") { // volumetric flow-rate operator==(n*avgU); } else { // mass flow-rate const fvPatchField<scalar> & rhop = patch().lookupPatchField<volScalarField, scalar> (rhoName_); operator==(n*avgU/rhop); } } else { ... } fixedValueFvPatchField ::updateCoeffs(); }
유체플럭스(flux) phi 의 단위로부터 체적유량인지 질량유량인지를 판단하고 있다. operator==() 으로 값을 지정하고 있다.
inletOutlet
template<class Type>
class inletOutletFvPatchField
:
public mixedFvPatchField<Type>
mixed 가 기반이 된다.
inletOutletFvPatchField.C
template<class Type>
Foam::inletOutletFvPatchField<Type> ::inletOutletFvPatchField ( const fvPatch& p, const DimensionedField<Type, volMesh> & iF, const dictionary& dict ) : mixedFvPatchField<Type> (p, iF), phiName_(dict.lookupOrDefault<word> ("phi", "phi")) { this->refValue() = Field<Type> ("inletValue", dict, p.size()); if (dict.found("value")) { fvPatchField<Type> ::operator= ( Field<Type> ("value", dict, p.size()) ); } else { fvPatchField<Type> ::operator=(this->refValue()); } this->refGrad() = pTraits<Type> ::zero; this->valueFraction() = 0.0; } ... template<class Type> void Foam::inletOutletFvPatchField<Type> ::updateCoeffs() { if (this->updated()) { return; } const Field<scalar> & phip = this->patch().template lookupPatchField<surfaceScalarField, scalar> ( phiName_ ); this->valueFraction() = 1.0 - pos(phip); mixedFvPatchField<Type> ::updateCoeffs(); }
mixed 에서는 값지정과 구배지정을 혼합하고 있다. "this->refValue()" 로 값지정, "this->refGrad() =" 으로 구배지정을 수행하고 있다. "this->valueFraction() = "은 혼합정도를 지정하며, 0에서 1까지의 범위의 값을 가진다. 0으로 Neumann boundary condition(구배지정), 1 으로 Dirichlet boundary condition(값지정) 이 된다.
아래와 같이 되어있다.
this->valueFraction() = 1.0 - pos(phip);
pos() 는 부호를 찾아내는 함수로, 양수이면 1, 음수이면 0이 된다. phip 가 양수이면 valueFraction() 가 0, phip 가 음수부터 1 이 된다. 유체 플럭스 phip 는 유체가 흘러나올때 양수, 들어갈때가 음수이므로, 여기서 유체가 밖으로 나가면 Neumann boundary condition, 들어가면 dirichlet boundary condition 이 된다. 스칼라변수의 경계조건으로 유입일때는 값지정, 유출일때는 구배 0을 지정하므로, inletOutlet 는 유입,유출 어느쪽에도 대응하도록 유체 흘럭스의 방향에 의해 처리를 바꾸고 있다.
outletInlet
template<class Type>
class outletInletFvPatchField
:
public mixedFvPatchField<Type>
outletInletFvPatchField.C
template<class Type>
Foam::outletInletFvPatchField<Type> ::outletInletFvPatchField ( const fvPatch& p, const DimensionedField<Type, volMesh> & iF, const dictionary& dict ) : mixedFvPatchField<Type> (p, iF), phiName_(dict.lookupOrDefault<word> ("phi", "phi")) { this->refValue() = Field<Type> ("outletValue", dict, p.size()); if (dict.found("value")) { fvPatchField<Type> ::operator= ( Field<Type> ("value", dict, p.size()) ); } else { fvPatchField<Type> ::operator=(this->refValue()); } this->refGrad() = pTraits<Type> ::zero; this->valueFraction() = 0.0; } ,.. template<class Type> void Foam::outletInletFvPatchField<Type> ::updateCoeffs() { if (this->updated()) { return; } const fvsPatchField<scalar> & phip = this->patch().template lookupPatchField<surfaceScalarField, scalar> ( phiName_ ); this->valueFraction() = pos(phip); mixedFvPatchField<Type> ::updateCoeffs(); }
outletInlet 은 inletOutlet 과 닮아있으나 Neumann 조건, Dirichlet 조건의 변환이 반대로 되어있다. 즉, 유입일때는 구배가 0, 유출일때는 값지정을 수행한다.
경계조건의 커스터마이징 |
자신의 문제에 맞게 경계조건을 커스터마이징하고 싶을 경우, 아래와 같이 한다.
1. 사용하는 솔버의 코드를 복사한다.
2. 만들고 싶은 경계조건에 가까운 경계조건을 $FOAM_SRC/finiteVolume/fields/fvPatchFields/derived 에서 폴더를 복사한다.
3. 솔버의 Make/files 에 복사한 경계조건의 .C 파일을 경로에 추가한다. 참고로 솔버의 바이너리 경로 (EXE = ...)를 원래의 것과 같게 변경해 둔다.
4. 이 시점에서 문제가 없는지 wmake 를 실행해 본다.
5. 경계조건 파일을 커스터마이징 한다.