• 0 赞同
    1 帖子
    1k 浏览
    use OpenFOAM in docker

    OS: windows 10

    Install docker for windows

    site: https://www.docker.com/

    download: Docker for Windows Installer.exe

    edition: most recent stable, for me, it is Docker version 17.09.0, community edition

    installation instructions: https://docs.docker.com/docker-for-windows/

    test

    after completion of the installation, run Docker for Windows. It will cost some time to start the docker engine.

    right click "Start" button, choose "Windows Powershell"

    docker --version ## Docker version 17.09.0-ce, build afdb6d4 docker-compose --version ## docker-compose version 1.16.1, build 6d1ac219 docker-machine --version ## docker-machine.exe version 0.12.2, build 9371605 docker run hello-world ## ## Hello from Docker! ## This message shows that your installation appears to be working correctly. ## ## To generate this message, Docker took the following steps: ## 1. The Docker client contacted the Docker daemon. ## 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. ## (amd64) ## 3. The Docker daemon created a new container from that image which runs the ## executable that produces the output you are currently reading. ## 4. The Docker daemon streamed that output to the Docker client, which sent it ## to your terminal. ## ## To try something more ambitious, you can run an Ubuntu container with: ## $ docker run -it ubuntu bash ## ## Share images, automate workflows, and more with a free Docker ID: ## https://cloud.docker.com/ ## ## For more examples and ideas, visit: ## https://docs.docker.com/engine/userguide/ docker ps -a ## CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ## 32a621d46d34 hello-world "/hello" 24 seconds ago Exited (0) 23 seconds ago clever_agnesi docker rm 32a621d46d34 #change it to your container ID ## 32a621d46d34 docker ps -a ## CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES download OpenFOAM image

    right click "Start" button, choose "Windows Powershell"

    docker pull openfoamplus/of_v1706_centos73 # OF+ # or docker pull openfoam/openfoam5-paraview54 # OF5 # list images docker image ls run OpenFOAM

    Right click on the "Docker" icon in the system tray, choose "settings"

    Click "Shared drives"

    choose any drive you want to share, in my case, I choose C, then click "apply"

    you may need to input credentials

    use openfoam+1706 as example.

    press "WIN+R", input cmd and enter

    rem test docker run --rm -v c:/Users:/data alpine ls /data rem ONLY `C:/Users` and its subfolders can be mounted docker run ^ -i -t ^ --name myOFplus_1706 ^ -v c:/Users/dic17007/OpenFOAM:/OF ^ openfoamplus/of_v1706_centos73 ^ bash rem press `Ctrl+p`, `Ctrl+q` to return without stop the container docker attach myOFplus_1706 rem press `Ctrl+c` or input `exit` to return and stop the container

    Note: you are root user in docker and the password is ofuser2017. Reference

    setup the environment:

    alias of1706="HOME=/OF source $DOCKER_OPENFOAM_PATH" # add to `~/.bashrc` # echo 'alias of1706="HOME=/OF source $DOCKER_OPENFOAM_PATH"'>>~/.bashrc

    run testcase

    of1706 #activate openfoam mkdir -p $FOAM_RUN run pwd #/OF/OpenFOAM/-v1706/run cp $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity -r . cd cavity foamJob -screen blockMesh foamJob -screen icoFoam touch a.foam ## use Ctrl+P, Ctrl+Q to return to `cmd` ## use `docker attach myOFplus_1706`

    return to windows, use paraview to do post-process.

    0_1513906857278_cavity.png

    modify OpenFOAM solver replication run cd .. mkdir -p applications/solvers cd applications/solvers # I put my solver here. pwd # /OF/OpenFOAM/-v1706/applications/solvers cp $FOAM_SOLVERS/incompressible/icoFoam -r . mv icoFoam myIcoFoam cd myIcoFoam mv icoFoam.C myIcoFoam.C sed -i s/icoFoam/myIcoFoam/g myIcoFoam.C sed -i s/icoFoam/myIcoFoam/g Make/files sed -i s/FOAM_APPBIN/FOAM_USER_APPBIN Make/files

    make

    wmake

    test

    run cd cavity which myIcoFoam foamJob -screen myIcoFoam modification

    I am trying to output the matrix in COO format ( Coordinate Format). It will be consists of three parts:

    AA: non-zero values JR: row index JC: column index

    According to the definition of Foam::lduMatrix::Amul() function, there are 4 part of scalar matrix:

    diagonal terms: JC, JR=1 ... nCells, AA = matrix.diag();

    upper terms: JC > JR

    JR=matrix.lduAddr().upperAddr()[0...mFaces-1]+1 JC=matrix.lduAddr().lowerAddr()[0...mFaces-1]+1 AA=matrix.upper()

    lower terms: JR > JC

    JR=matrix.lduAddr().lowerAddr()[0...mFaces-1]+1 JC=matrix.lduAddr().upperAddr()[0...mFaces-1]+1 AA=matrix.lower()

    boundary term, only considering single processor problem here. There are 3 types of patch types:

    geometric (constraint) type. basic derived

    In the following program, I assume there is not coupled interface such as processor patch or cyclic patch.

    reference: Matrix coupling of different processors

    Here is the code.

    A c++ library cnpy is used to generate npy or npz file for numpy.

    site: https://github.com/rogersce/cnpy command: git clone https://github.com/rogersce/cnpy.git cd cnpy mkdir build cd build cmake .. -DENABLE_STATIC=ON make make install

    dumpFvMatrix.H

    #pragma once // added by CatDog #include<iostream> #include<fstream> #include<string> #include"cnpy.h" void dumpFvMatrix(string path, const fvScalarMatrix& EqnPtr) { const label nCells = EqnPtr.diag().size(); const label nFaces = EqnPtr.lower().size(); const scalar* const __restrict__ diagPtr = EqnPtr.diag().begin(); const label* const __restrict__ uPtr = EqnPtr.lduAddr().upperAddr().begin(); const label* const __restrict__ lPtr = EqnPtr.lduAddr().lowerAddr().begin(); const scalar* const __restrict__ upperPtr = EqnPtr.upper().begin(); const scalar* const __restrict__ lowerPtr = EqnPtr.lower().begin(); std::vector<scalar> AA(nCells+2*nFaces); std::vector<label> JR(nCells+2*nFaces); std::vector<label> JC(nCells+2*nFaces); // diag for(label cell=0;cell<nCells;cell++) { AA[cell]=diagPtr[cell]; JR[cell]=cell; JC[cell]=cell; } for(label face=0;face<nFaces;face++) { AA[face]=upperPtr[face]; JR[face]=lPtr[face]; JC[face]=uPtr[face]; } for(label face=0;face<nFaces;face++) { AA[face]=lowerPtr[face]; JR[face]=uPtr[face]; JC[face]=lPtr[face]; } cnpy::npz_save(path,"nCells",&nCells,{1},"w"); cnpy::npz_save(path,"nFaces",&nFaces,{1},"a"); cnpy::npz_save(path,"AA",&AA[0],{nCells+2*nFaces},"a"); cnpy::npz_save(path,"JR",&JR[0],{nCells+2*nFaces},"a"); cnpy::npz_save(path,"JC",&JC[0],{nCells+2*nFaces},"a"); return; } in myIcoFoam.C // ... #include "fvCFD.H" #include "pisoControl.H" #include "dumpFvMatrix.H" // ... // Non-orthogonal pressure corrector loop while (piso.correctNonOrthogonal()) { // Pressure corrector fvScalarMatrix pEqn ( fvm::laplacian(rAU, p) == fvc::div(phiHbyA) ); pEqn.setReference(pRefCell, pRefValue); pEqn.solve(mesh.solver(p.select(piso.finalInnerIter()))); if (piso.finalNonOrthogonalIter()) { phi = phiHbyA - pEqn.flux(); } if (runTime.timeIndex()==2) { Info<< "TimeIndex = 2, output matrix pEqn"<<endl; dumpFvMatrix("/OF/OpenFOAM/-v1706/run/cavity/pEqn.npz",pEqn); } } // ... options file: EXE_INC = \ -I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude \ -I/usr/local/include EXE_LIBS = \ -lfiniteVolume \ -lmeshTools \ -Wl,-rpath -Wl,/usr/local/lib -lcnpy python script to read the matrix and find LU-SGS's effectiveness. import numpy as np import scipy as sp from scipy.sparse import coo_matrix,tril,triu,diags from scipy.linalg import norm data=np.load('pEqn.npz') nCells=data["nCells"][0] nFaces=data["nFaces"][0] AA=data['AA'] JR=data['JR'] JC=data['JC'] A=coo_matrix((AA,(JR,JC)),shape=(nCells,nCells)) L=tril(A,-1) U=triu(A,1) D=diags(AA[0:nCells],0) Dinv=diags(1.0/AA[0:nCells],0) delta= L.dot(Dinv).dot(U) print "norm of error of LU-SGS: norm(L*Dinv*U)=", norm(delta.toarray())/norm(A.toarray()) # a Laplacian operator # proof of diagonally dominance print abs(np.abs((L+U).toarray()).sum(1)/np.abs(D.toarray()).sum(1)-1).max() # proof of symmetry print abs(L-U.T).sum() ## reference: Jisheng Kou, Yitian Li, A uniparametric LU-SGS method for systems of nonlinear equations, In Applied Mathematics and Computation, Volume 189, Issue 1, 2007, Pages 235-240, ISSN 0096-3003, f=lambda w:norm(((1-w)*(L+U)-w*w*L.dot(Dinv).dot(U)).toarray())/norm(A.toarray()) for w in np.linspace(0,1,100): print f(w)

    最后结果:

    >>> >>> print "norm of error of LU-SGS: norm(L*Dinv*U)=", norm(delta.toarray())/norm(A.toarray()) relative norm of error of LU-SGS: norm(L*Dinv*U)= 0.141875980931 >>> ... # a Laplacian operator ... # proof of diagonally dominance ... print abs(np.abs((L+U).toarray()).sum(1)/np.abs(D.toarray()).sum(1)-1).max() 0.5 >>> # proof of symmetry ... print abs(L-U.T).sum() 0.0