بازی، اپنفوم به جای بازی، ریاضی!

تست شده در OF 3.0.1

در این قسمت قصد داریم کمی از کار با اُپنفوم لذت ببریم! برای این کار تصمیم گرفتیم یک مساله دو فازی حل کنیم. در اُپنفوم ساده ترین و معروفترین حلگر دوفازی interFoam هست. در این مساله یاد خواهیم گرفت:

  • تنظیم یک مساله دو فازی در اُپنفوم و استفاده از حلگر interFoam
  • وارد کردن یک شبکه دو بعدی به اُپنفوم
  • استفاده از ابزار setFields
  • حل موازی در اُپنفوم

شاید مساله شکست سد رو در فایل های آموزشی (tutorials) اُپنفوم دیده باشید. شکست سد یک مساله بنچمارک (Benchmark) و یا همون معیار برای صحت سنجی بسیاری از مسائل دوفازی هست. می تونید این مساله رو در آدرس زیر پیدا کنید.:

tutorials\multiphase\interFoam\laminar\damBreak

اما برای حل یک مساله دوفازی قبل از هرچیز لازم هست تا شرایط اولیه و مرزی تعیین شوند. شرایط اولیه، مربوط به گام زمانی صفر می شود؛ اینکه چگونه دو فاز در ابتدا در کنار هم قرار دارند. برای این کار اُپنفوم کاران (!) از ابزار setFields استفاده می کنند. این ابزار می تواند دامنه را بر حسب مقادیر مختلف پارامترها مقدار دهی کند.

همانطور که شاید بدانید، حلگر interFoam از روش VOF یا Volume Of Fluid برای حل مسائل دوفازی استفاده می کند. این یعنی پارامتری به نام آلفا تعریف شده که مقدار آن از 0 (فاز اول) تا 1 (فاز دوم) در حال تغییر هست. بنابراین هرکجا از میدان که مقدار آلفا برابر با 0 بود، بعنی در این قسمت از میدان، فاز اول قرار گرفته و مشابه همین، اگر مقدار آن 1 بود، یعنی فاز دوم در آنجا قرار دارد. با استفاده از setFields در حقیقت کافیست همین پارامتر آلفا را در میدان مقداردهی کنیم.

در مثال حاضر، می خواهیم پاشیدن یک سیال روی کلمه OpenFOAM.ir را بررسی کنیم! شبکه مساله قبلا در نرم افزار گمبیت آماده شده و فقط در اینجا از آن استفاده خواهد شد.

mesh

شماتیک کلی مساله هم به شکل زیر هست. دقیقا در بالای کلمه OpenFOAM.ir یک قطره بزرگ سیال قرار گرفته که در زمان 0، رها می شود. به دلیل نیروی جاذبه، قطره روی کلمه خواهد افتاد و سپس ما از این کار خود بسی لذت خواهیم برد!

schemاما برای شروع کار از همان کیس شکست سد استفاده خواهیم کرد. همانند گذشته یک کپی از این کیس که آدرس آن در بالا گفته شد، در داخل پوشه run کپی می کنیم. نام آن را هم مثلا به openfoamIr تغییر می دهیم. حال لازم هست تا شرایط مرزی و بقیه تنظیماتی را که لازم است تا مساله شکست سد به مساله حاضر تبدیل شود، انجام گیرد. مرحله اول وارد کردن شبکه به مساله است. نام شبکه، openfoamTet.msh هست. این فایل رو در داخل پوشه مساله قرار می دهیم و دستور زیر را برای تبدیل این شبکه به شبکه اُپنفوم وارد می کنیم:

fluent3DMeshToFoam openfoamTet.msh

دقت کنید که این یک شبکه دو بعدی است، بنابراین باید از دستور fluentMeshToFoam به جای دستور fluent3DMeshToFoam استفاده شود. با وارد کردن شبکه، اُپنفوم خود، به شبکه دو بعدی ضخامتی به اندازه یک المان می دهد و سطوح بالایی و پایینی تازه تشکیل شده آن را frontAndBackPlanes نام گذاری می کند. می توان بعد از وارد کردن شبکه، به فایل boundary آن که در پوشه polyMesh قرار گرفته، یک سری زد.

5
(
    openfoam
    {
        type            wall;
        inGroups        1(wall);
        nFaces          950;
        startFace       60575;
    }
    walls
    {
        type            wall;
        inGroups        1(wall);
        nFaces          170;
        startFace       61525;
    }
    top
    {
        type            wall;
        inGroups        1(wall);
        nFaces          25;
        startFace       61695;
    }
    bottom
    {
        type            wall;
        inGroups        1(wall);
        nFaces          39;
        startFace       61720;
    }
    frontAndBackPlanes
    {
        type            empty;
        inGroups        1(empty);
        nFaces          81556;
        startFace       61759;
    }
)

در اینجا نام شرایط مرزی که در گمبیت به مرزها داده شده، مشاهده می شود. همچنین شرط مرزی frontAndBackPlanes هم که توسط اُپنفوم اضافه شده در اینجا دیده می شود. می توان نام شرایط مرزی را به دلخواه تغییر داد. مثلا برای سادگی نام مرز frontAndBackPlanes را به frontAndBack تغییر می دهیم و فایل را ذخیره می کنیم.

    frontAndBack
    {
        type            empty;
        inGroups        1(empty);
        nFaces          81556;
        startFace       61759;
    }

خب حالا لازم است تا شرایط مرزی تعیین شوند. در این مساله در کل سه پارامتر موجود است که عبارتند از فشار، سرعت و آلفا. برای همه مرزها به جز مرز بالایی شرط مرزی دیوار در نظر گرفته خواهد شد و برای مرز بالایی، یک دریچه قرار می دهیم که سیال ها قادر به خروج و ورود باشند. بنابراین شرایط مرزی به شکل زیر خواهند بود.

برای سرعت:

dimensions      [0 1 -1 0 0 0 0];

internalField   uniform (0 0 0);

boundaryField
{
    walls
    {
        type            slip;
    }

    openfoam
    {
        type            fixedValue;
        value           uniform (0 0 0);
    }

    bottom
    {
        type            fixedValue;
        value           uniform (0 0 0);
    }

    top
    {
        type            zeroGradient;
    }

    frontAndBack
    {
        type            empty;
    }
}

برای فشار:

dimensions      [1 -1 -2 0 0 0 0];

internalField   uniform 0;

boundaryField
{
    walls
    {
        type            fixedFluxPressure;
        value           uniform 0;
    }

    openfoam
    {
        type            fixedFluxPressure;
        value           uniform 0;
    }

    bottom
    {
        type            fixedFluxPressure;
        value           uniform 0;
    }

    top
    {
        type            fixedValue;
        value           uniform 0;
    }

    frontAndBack
    {
        type            empty;
    }
}

برای آلفا:

dimensions      [0 0 0 0 0 0 0];

internalField   uniform 0;

boundaryField
{
    walls
    {
        type            zeroGradient;
    }

    openfoam
    {
        type            zeroGradient;
    }

    bottom
    {
        type            zeroGradient;
    }

    top
    {
        type            zeroGradient;
    }

    frontAndBack
    {
        type            empty;
    }
}

در پوشه constant تغییر خاصی نیاز نیست. فقط مثلا در این مثال مقدار کشش سطحی بین دو سیال (Sigma) برابر با 7 در نظر گرفته شده که برای مقایسه حدود صد برابر کشش سطحی بین آب و هواست. بنابراین در فایل transportProperties:

phases (water air);

water
{
    transportModel  Newtonian;
    nu              [0 2 -1 0 0 0 0] 1e-06;
    rho             [1 -3 0 0 0 0 0] 1000;
}

air
{
    transportModel  Newtonian;
    nu              [0 2 -1 0 0 0 0] 1.48e-05;
    rho             [1 -3 0 0 0 0 0] 1;
}

sigma           [1 0 -2 0 0 0 0] 7;

در پوشه system، دیگر نیازی به فایل از پیش تنظیم شده blockMeshDict نیست، چرا که این فایل برای تولید شبکه مربوط به مساله شکست سد بوده. بنابراین برای تمیز شدن مساله از فایل های اضافی، این فایل را حذف می کنیم. فایل controlDict حاوی تنظیماتی از جمله مقدار گام زمانی، زمان شروع و اتمام حل است. مقدار گام زمانی را برای تست همان 0.001 قرار می دهیم که از قبل برای مساله شکست سد تعیین شده بود. اما دقت کنید که در پایین گزینه ای به نام adjustTimeStep موجود است. این گزینه اگر فعال باشد، با توجه به مقدار عدد Courant ای که کاربر مد نظر دارد، به صورت خودکار و در هر گام زمانی، مقدار گام زمانی جدید را تعیین می کند. در چنین مسائلی که پایداری زیادی در مسائل دیده نمی شود، استفاده از این تکنیک باعث افزایش قابل توجه پایداری خواهد شد. معمولا فیکس کردن گام زمانی به یک عدد خاص در چنین مسائلی باعث واگرایی سریع حل خواهد شد. در واقع مقدار 0.001 هم چیزی حز یک حدس اولیه نیست و به مرور زمان در حین حل، مقدار گام زمانی با توجه به عدد Co تعیین می شود. مقدار استاندارد عدد Co معمولا 1 هست، اما برای پایداری بیشتر می توان این مقدار را تا 0.1 هم کاهش داد. در بعضی مسائل دیگر که پایداری زیادی مشاهده می شود، می توان برای افزایش سرعت حل، مقدار این عدد را حتی شاید تا 5 یا 10 نیز افزایش داد. همچنین زمان نهایی حل (stopTime) نیز برابر با 5 ثانیه در نظر گرفته شده. از طرفی برای داشتن یک انیمیشن خوب در انتهای حل، به اُپنفوم گفته شده تا در هر 0.015 ثانیه از حل، یک بار نتایج را روی دیسک ذخیره کند. این مورد در کلیدواژه writeControl و writeInterval تعیین می شود.

application     interFoam;

startFrom       latestTime;

startTime       0;

stopAt          endTime;

endTime         5;

deltaT          0.001;

writeControl    adjustableRunTime;

writeInterval   0.015;

purgeWrite      0;

writeFormat     ascii;

writePrecision  6;

writeCompression uncompressed;

timeFormat      general;

timePrecision   6;

runTimeModifiable yes;

adjustTimeStep  yes;

maxCo           1;
maxAlphaCo      1;

maxDeltaT       1;

اما قبل از حل گفته شد که باید از دستور setFields برای تعیین شرط اولیه مربوط به آلفا استفاده شود. در داخل این دستور گفته شده که همه میدان حل به جز یک ناحیه مستطیلی در بالای عبارت OpenFOAM.ir فاز دوم و در داخل این ناحیه فاز اول قرار گیرد:

defaultFieldValues
(
    volScalarFieldValue alpha.water 0
);

regions
(
    boxToCell
    {
        box (0.1 0.3 -1) (0.4 0.4 1);
        fieldValues
        (
            volScalarFieldValue alpha.water 1
        );
    }
);

اما شرط اولیه در کجا ذخیره شده است؟ در واقع عبارت internalField که در هر پارامتر موجود در پوشه 0 قرار گرفته، همان شرط اولیه است! در اکثر مسائل اُپنفوم دیده اید که این مقدار برابر با یک مقدار ثابت در نظر گرفته شده. در واقع این همان شرط اولیه یکنواخت برای همه میدان است. مثلا در همین مثال برای فشار (واقع در پوشه 0) اینگونه نوشته شده بود:

internalField   uniform 0;

یعنی در شروع حل، حدس اولیه در تمام میدان برای فشار برابر با صفر در نظر گرفته شده. اما برای پارامتر آلفا این موضوع برقرار نیست. چرا که می خواهیم دقیقا در بالای عبارت OpenFOAM.ir سیال فاز دوم قرار داشته باشد. بنابراین از دستور setFields برای تنظیم internalField استفاده می کنیم. توجه کنید که نمی توان به صورت دستی مقدار هر سلول را در کلیدواژه internalField وارد کرد!

اما نکته ای که باید به آن اشاره کرد، این است که دستور setFields باعث تغییر قسمت internalField در داخل فایل alpha.water خواهد شد. اما شاید کاربر در آینده نیازی به این فایل تغییر داده شده نداشته باشد و بخواهد دوباره مساله را از صفر (با شرط اولیه یکنواخت) طور دیگری حل کند. اگر دستور setFields بدون داشتن یک کپی از فایل قبلی (alpha.water) اجرا شود، تمام تغییرات روی این فایل انجام شده و عملا فایل قبلی از بین خواهد رفت. بنابراین معمولا قبل از اعمال دستور setFields یک کپی از فایل alpha.water می گیرند و مثلا نام آن را alpha.water.org مخفف کلمه original قرار می دهند. سپس می توان با خیال راحت دستور setFields را اجرا کرد.

setFields

پس از اجرای این دستور نگاهی به فایل alpha.water بیاندازید و تغییرات ایجاد شده در این فایل را مشاهده کنید. قسمت internalField به صورت non-uniiform (غیر یکنواخت) تنظیم شده (دقیقا همان طور که می خواستیم). البته فقط قسمتی از کد در اینجا آورده شده.

internalField   nonuniform List<scalar> 
40778
(
0
0
0
0
0
0
0
0
0
0
0

...
)
;

خب حالا تقریبا مساله آماده حل هست، شاید بخواهید این مساله را با چند پردازنده حل کنید بنابراین کافیست فایل decomposeParDict رو به درستی بر حسب تعداد پردازنده های مورد نظر خود تنظیم کنید. مثلا در زیر این فایل برای استفاده از دو 8 پردازنده تنظیم شده:

numberOfSubdomains 8;

method          simple;

simpleCoeffs
{
    n               (2 4 1);
    delta           0.001;
}

توجه کنید که هنگام استفاده از روش Simple حتما باید ضرب مقادیر موجود در بردار n، برابر با تعداد پردازنده های شما باشد. برای مثال می توان از بردارهای (1 8 1)، (2 4 1) و … استفاده کرد. توجه کنید که در هنگام حل یک مساله دو بعدی، به بعد سوم پردازنده اختصاص ندهید (مقدار 1 باشد). در غیر این صورت پردازنده خود را به هدر داده اید!

حال برای حل موازی می توان به راحتی از اسکریپت foamJob استفاده کرد:

foamJob -s -p interFoam

در اینجا آپشن p به معنای Parallel (حل موازی) و s به معنای Screen (صفحه نمایش) است. اگر آپشن s استفاده نشود، چیزی در صفحه نمایش هنگام حل نشان داده نخواهد شد.

در انتهای حل می توانید از نتایج آن لذت ببرید!

resultدانلود فایل های اُپنفوم مساله بدون شبکه:

این قسمت فقط برای اعضا قابل مشاهده است. لطفا وارد شوید.

دانلود فایل شبکه

این قسمت فقط برای اعضا قابل مشاهده است. لطفا وارد شوید.

مشاهده انیمشن نهایی:

آموزشی, اسلایدر

1 دیدگاه. ارسال دیدگاه جدید

برای نوشتن دیدگاه باید وارد بشوید.
فهرست
X