/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2021 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Application rhoCentralFoam Group grpCompressibleSolvers Description Density-based compressible flow solver based on central-upwind schemes of Kurganov and Tadmor with support for mesh-motion and topology changes. Chemistry reaction solver for multi-gas. \*---------------------------------------------------------------------------*/ #include "gpufvCFD.H" #include "dynamicFvMesh.H" #include "psiReactionThermo.H" #include "reactingMixture.H" #include "thermoPhysicsTypes.H" #include "CombustionModel.H" #include "gpumultivariateScheme.H" #include "turbulentFluidThermoModel.H" #include "fixedRhoFvPatchScalargpuField.H" #include "directionInterpolate.H" #include "gpulocalEulerDdtScheme.H" #include "gpufvcSmooth.H" #include struct my_timer { struct timeval start_time, end_time; double time_use; void start() { gettimeofday(&start_time, NULL); } void stop() { gettimeofday(&end_time, NULL); time_use = (end_time.tv_sec - start_time.tv_sec) + (double)(end_time.tv_usec - start_time.tv_usec)/1000000.0; } }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { template struct compHsFunctor { ThermoType *speciesData; const label id; compHsFunctor(ThermoType* _speciesData, const label _id):speciesData(_speciesData),id(_id){} __host__ __device__ scalar operator()(const thrust::tuple& t) { const scalar p = thrust::get<0>(t); const scalar T = thrust::get<1>(t); return speciesData[id].Hs(p,T); } }; } int main(int argc, char *argv[]) { argList::addNote ( "Density-based compressible flow solver based on" " central-upwind schemes of Kurganov and Tadmor with" " support for mesh-motion and topology changes." "Chemistry reaction solver for multi-gas." ); #define NO_CONTROL #include "gpupostProcess.H" #include "addCheckCaseOptions.H" #include "setRootCaseLists.H" #include "createTime.H" #include "createDynamicFvMesh.H" #include "gpucreateMesh.H" #include "createFields.H" #include "createFieldRefs.H" #include "createTimeControls.H" #include "thermodata.H" double totaldensitytime=0.0,totalmomentumtime=0.0,totalspeciestime=0.0,totalenergytime=0.0,totalODEtime=0.0,totalturbulencetime=0.0; turbulence->validate(); // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #include "readFluxScheme.H" const dimensionedScalar v_zero(dimVolume/dimTime, Zero); // Courant numbers used to adjust the time-step scalar CoNum = 0.0; scalar meanCoNum = 0.0; Info<< "\nStarting time loop\n" << endl; while (runTime.run()) { #include "readTimeControls.H" if (!LTS) { #include "setDeltaT.H" ++runTime; // Do any mesh changes mesh.update(); } // --- Directed interpolation of primitive fields onto faces surfaceScalargpuField rho_pos(interpolate(rho, pos)); surfaceScalargpuField rho_neg(interpolate(rho, neg)); surfaceVectorgpuField rhoU_pos(interpolate(rhoU, pos, U.name())); surfaceVectorgpuField rhoU_neg(interpolate(rhoU, neg, U.name())); volScalargpuField rPsi("rPsi", 1.0/psi); surfaceScalargpuField rPsi_pos(interpolate(rPsi, pos, T.name())); surfaceScalargpuField rPsi_neg(interpolate(rPsi, neg, T.name())); surfaceScalargpuField e_pos(interpolate(e, pos, T.name())); surfaceScalargpuField e_neg(interpolate(e, neg, T.name())); surfaceVectorgpuField U_pos("U_pos", rhoU_pos/rho_pos); surfaceVectorgpuField U_neg("U_neg", rhoU_neg/rho_neg); surfaceScalargpuField p_pos("p_pos", rho_pos*rPsi_pos); surfaceScalargpuField p_neg("p_neg", rho_neg*rPsi_neg); PtrList Y_pos(Y.size()), Y_neg(Y.size()); forAll(Y,i) { Y_pos.set(i,new surfaceScalargpuField (fvc::interpolate(Y[i], pos, "reconstruct(Y)"))); Y_neg.set(i,new surfaceScalargpuField (fvc::interpolate(Y[i], neg, "reconstruct(Y)"))); } surfaceScalargpuField phiv_pos("phiv_pos", U_pos & devicemesh.Sf()); // Note: extracted out the orientation so becomes unoriented phiv_pos.setOriented(false); surfaceScalargpuField phiv_neg("phiv_neg", U_neg & devicemesh.Sf()); phiv_neg.setOriented(false); // Make fluxes relative to mesh-motion if (mesh.moving()) { surfaceScalargpuField meshPhi(devicemesh.phi()); meshPhi.setOriented(false); phiv_pos -= meshPhi; phiv_neg -= meshPhi; } volScalargpuField c("c", sqrt(thermo.Cp()/thermo.Cv()*rPsi)); surfaceScalargpuField cSf_pos ( "cSf_pos", interpolate(c, pos, T.name())*devicemesh.magSf() ); surfaceScalargpuField cSf_neg ( "cSf_neg", interpolate(c, neg, T.name())*devicemesh.magSf() ); surfaceScalargpuField ap ( "ap", max(max(phiv_pos + cSf_pos, phiv_neg + cSf_neg), v_zero) ); surfaceScalargpuField am ( "am", min(min(phiv_pos - cSf_pos, phiv_neg - cSf_neg), v_zero) ); surfaceScalargpuField a_pos("a_pos", ap/(ap - am)); surfaceScalargpuField amaxSf("amaxSf", max(mag(am), mag(ap))); surfaceScalargpuField aSf("aSf", am*a_pos); if (fluxScheme == "Tadmor") { aSf = -0.5*amaxSf; a_pos = 0.5; } surfaceScalargpuField a_neg("a_neg", 1.0 - a_pos); phiv_pos *= a_pos; phiv_neg *= a_neg; surfaceScalargpuField aphiv_pos("aphiv_pos", phiv_pos - aSf); surfaceScalargpuField aphiv_neg("aphiv_neg", phiv_neg + aSf); // Reuse amaxSf for the maximum positive and negative fluxes // estimated by the central scheme amaxSf = max(mag(aphiv_pos), mag(aphiv_neg)); #include "centralCourantNo.H" if (LTS) { #include "setRDeltaT.H" ++runTime; } Info<< "Time = " << runTime.timeName() << nl << endl; phi = aphiv_pos*rho_pos + aphiv_neg*rho_neg; surfaceVectorgpuField phiU(aphiv_pos*rhoU_pos + aphiv_neg*rhoU_neg); // Note: reassembled orientation from the pos and neg parts so becomes // oriented phiU.setOriented(true); surfaceVectorgpuField phiUp(phiU + (a_pos*p_pos + a_neg*p_neg)*devicemesh.Sf()); surfaceScalargpuField phiEp ( "phiEp", aphiv_pos*(rho_pos*(e_pos + 0.5*magSqr(U_pos)) + p_pos) + aphiv_neg*(rho_neg*(e_neg + 0.5*magSqr(U_neg)) + p_neg) + aSf*p_pos - aSf*p_neg ); // Make flux for pressure-work absolute if (mesh.moving()) { surfaceScalargpuField meshPhi(devicemesh.phi()); meshPhi.setOriented(false); phiEp += meshPhi*(a_pos*p_pos + a_neg*p_neg); } volScalargpuField muEff("muEff", turbulence->muEff()); volTensorgpuField tauMC("tauMC", muEff*dev2(Foam::T(fvc::grad(U)))); my_timer tm_density;tm_density.start(); // --- Solve density solve(fvm::ddt(rho) + fvc::div(phi));Info<<"------Timecost density = "< phiY(Y.size()); forAll(Y, i) { phiY.set ( i, new surfaceScalargpuField ( (aphiv_pos*(rho_pos*Y_pos[i]) + aphiv_neg*(rho_neg*Y_neg[i])) ) ); } Yt=0.0; Y[inertIndex]=1.0; forAll(Y, i) { if (Y[i].name() != inertSpecie) { solve(fvm::ddt(rhoY[i]) + fvc::div(phiY[i])); Y[i] = rhoY[i]/rho; Y[i].correctBoundaryConditions(); Yt += Y[i]; Y[i].min(1.0); } } Y[inertIndex] -=Yt; Y[inertIndex].correctBoundaryConditions(); Yt.correctBoundaryConditions(); Info<< "min/max(Yt after convection) = " << min(Yt).value() << ", " << max(Yt).value() << endl; forAll(Y, i) { Y[i].correctBoundaryConditions(); rhoY[i].boundaryFieldRef() == rho.boundaryField()*Y[i].boundaryField(); } if(!inviscid) { forAll(Y,i) { DiffsY[i]=turbulence->mut()/Sct+turbulence->mu()/Sc[i]; } Y[inertIndex]=1.0; forAll(Y, i) { if (Y[i].name() != inertSpecie) { volScalargpuField& Yi = Y[i]; gpufvScalarMatrix YiEqn ( fvm::ddt(rho, Yi)- fvc::ddt(rho, Yi) == fvm::laplacian(DiffsY[i], Yi) ); YiEqn.relax(); YiEqn.solve(mesh.solver("Yi")); //Yi.max(0.0); Yi.min(1.0); Y[inertIndex] -=Y[i]; } } Yt=0.0; Yt.correctBoundaryConditions(); forAll(Y,i) { Yt +=Y[i]; Y[i].correctBoundaryConditions(); rhoY[i] = rho*Y[i]; } Yt.correctBoundaryConditions(); } Info<< "min/max(Yt after diffusion) = " << min(Yt).value() << ", " << max(Yt).value() << endl;tm_species.stop();Info<<"------Timecost species = "<(raw_pointer_cast(gSpeciesData),i) ); HsY[i].correctBoundaryConditions(); } volVectorgpuField HsDiff("HsDiff",DiffsY[0]*HsY[0]*fvc::grad(Y[0])); for(label i=1;ialphaEff(), e) ); thermo.correct(); rhoE = rho*(e + 0.5*magSqr(U)); } Info<< "min/max(T) after convection & diffusion = " << min(T).value() << ", " << max(T).value() << endl; Info<< "min/max(p) after convection & diffusion = " << min(p).value() << ", " << max(p).value() << endl;tm_energy.stop();Info<<"------Timecost energy = "<correct(); Qdot = combustion->Qdot(); tm_ODE.stop();Info<<"------Timecost ODE = "<Qdot()); e = rhoE/rho - 0.5*magSqr(U); e.correctBoundaryConditions(); thermo.correct(); rhoE.boundaryFieldRef() == rho.boundaryField()* ( e.boundaryField() + 0.5*magSqr(U.boundaryField()) ); } p.ref() = rho() /psi(); p.correctBoundaryConditions(); rho.boundaryFieldRef() == psi.boundaryField()*p.boundaryField(); if(SolveChemistry) { Info<< "min/max(T) after combustion = " << min(T).value() << ", " << max(T).value() << endl; Info<< "min/max(p) after combustion = " << min(p).value() << ", " << max(p).value() << endl; } my_timer tm_turbulence;tm_turbulence.start(); turbulence->correct(); tm_turbulence.stop();Info<<"------Timecost turbulence = "<