/* This file is part of the OpenLB library * * Copyright (C) 2018 Robin Trunk, Sam Avis * E-mail contact: info@openlb.net * The most recent release of OpenLB can be downloaded at * * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef FREE_ENERGY_POST_PROCESSOR_2D_HH #define FREE_ENERGY_POST_PROCESSOR_2D_HH #include "freeEnergyPostProcessor2D.h" #include "core/blockLattice2D.h" namespace olb { //////// FreeEnergyChemicalPotentialCoupling2D /////////////////////////////////// template FreeEnergyChemicalPotentialCoupling2D ::FreeEnergyChemicalPotentialCoupling2D ( int x0_, int x1_, int y0_, int y1_, T alpha_, T kappa1_, T kappa2_, T kappa3_, std::vector partners_) : x0(x0_), x1(x1_), y0(y0_), y1(y1_), alpha(alpha_), kappa1(kappa1_), kappa2(kappa2_), kappa3(kappa3_), partners(partners_) { } template FreeEnergyChemicalPotentialCoupling2D ::FreeEnergyChemicalPotentialCoupling2D ( T alpha_, T kappa1_, T kappa2_, T kappa3_, std::vector partners_) : x0(0), x1(0), y0(0), y1(0), alpha(alpha_), kappa1(kappa1_), kappa2(kappa2_), kappa3(kappa3_), partners(partners_) { } template void FreeEnergyChemicalPotentialCoupling2D::processSubDomain ( BlockLattice2D& blockLattice, int x0_, int x1_, int y0_, int y1_ ) { // If partners.size() == 1: two fluid components // If partners.size() == 2: three fluid components BlockLattice2D *partnerLattice1 = dynamic_cast *>(partners[0]); BlockLattice2D *partnerLattice2 = 0; if (partners.size() > 1) { partnerLattice2 = dynamic_cast *>(partners[1]); } int newX0, newX1, newY0, newY1; if ( util::intersect ( x0, x1, y0, y1, x0_, x1_, y0_, y1_, newX0, newX1, newY0, newY1 ) ) { int nx = newX1-newX0+3; // include a one-cell boundary int ny = newY1-newY0+3; // include a one-cell boundary int offsetX = newX0-1; int offsetY = newY0-1; // compute the density fields for each lattice BlockData2D rhoField1(nx, ny); BlockData2D rhoField2(nx, ny); BlockData2D rhoField3(nx, ny); for (int iX=newX0-1; iX<=newX1+1; ++iX) for (int iY=newY0-1; iY<=newY1+1; ++iY) rhoField1.get(iX-offsetX, iY-offsetY) = blockLattice.get(iX,iY).computeRho(); for (int iX=newX0-1; iX<=newX1+1; ++iX) for (int iY=newY0-1; iY<=newY1+1; ++iY) rhoField2.get(iX-offsetX, iY-offsetY) = partnerLattice1->get(iX,iY).computeRho(); if (partners.size() > 1) { for (int iX=newX0-1; iX<=newX1+1; ++iX) for (int iY=newY0-1; iY<=newY1+1; ++iY) rhoField3.get(iX-offsetX, iY-offsetY) = partnerLattice2->get(iX,iY).computeRho(); } // calculate chemical potential for (int iX=newX0; iX<=newX1; ++iX) { for (int iY=newY0; iY<=newY1; ++iY) { T densitySum = rhoField1.get(iX-offsetX, iY-offsetY) + rhoField2.get(iX-offsetX, iY-offsetY); T densityDifference = rhoField1.get(iX-offsetX, iY-offsetY) - rhoField2.get(iX-offsetX, iY-offsetY); if (partners.size() > 1) { densitySum -= rhoField3.get(iX-offsetX, iY-offsetY); densityDifference -= rhoField3.get(iX-offsetX, iY-offsetY); } T term1 = 0.125 * kappa1 * (densitySum) * (densitySum-1.) * (densitySum-2.); T term2 = 0.125 * kappa2 * (densityDifference) * (densityDifference-1.) * (densityDifference-2.); T term3 = 0.; if (partners.size() > 1) { T rho3 = rhoField3.get(iX-offsetX, iY-offsetY); term3 = kappa3 * rho3 * (rho3 - 1.) * (2.*rho3 - 1.); } T laplaceRho1 = 0.25 * ( rhoField1.get(iX-offsetX-1, iY-offsetY-1) + 2. * rhoField1.get(iX-offsetX, iY-offsetY-1) + rhoField1.get(iX-offsetX+1, iY-offsetY-1) + 2. * rhoField1.get(iX-offsetX-1, iY-offsetY) -12. * rhoField1.get(iX-offsetX, iY-offsetY) + 2. * rhoField1.get(iX-offsetX+1, iY-offsetY) + rhoField1.get(iX-offsetX-1, iY-offsetY+1) + 2. * rhoField1.get(iX-offsetX, iY-offsetY+1) + rhoField1.get(iX-offsetX+1, iY-offsetY+1) ); T laplaceRho2 = 0.25 * ( rhoField2.get(iX-offsetX-1, iY-offsetY-1) + 2. * rhoField2.get(iX-offsetX, iY-offsetY-1) + rhoField2.get(iX-offsetX+1, iY-offsetY-1) + 2. * rhoField2.get(iX-offsetX-1, iY-offsetY) -12. * rhoField2.get(iX-offsetX, iY-offsetY) + 2. * rhoField2.get(iX-offsetX+1, iY-offsetY) + rhoField2.get(iX-offsetX-1, iY-offsetY+1) + 2. * rhoField2.get(iX-offsetX, iY-offsetY+1) + rhoField2.get(iX-offsetX+1, iY-offsetY+1) ); T laplaceRho3 = 0.; if (partners.size() > 1) { laplaceRho3 = 0.25 * ( rhoField3.get(iX-offsetX-1, iY-offsetY-1) + 2. * rhoField3.get(iX-offsetX, iY-offsetY-1) + rhoField3.get(iX-offsetX+1, iY-offsetY-1) + 2. * rhoField3.get(iX-offsetX-1, iY-offsetY) -12. * rhoField3.get(iX-offsetX, iY-offsetY) + 2. * rhoField3.get(iX-offsetX+1, iY-offsetY) + rhoField3.get(iX-offsetX-1, iY-offsetY+1) + 2. * rhoField3.get(iX-offsetX, iY-offsetY+1) + rhoField3.get(iX-offsetX+1, iY-offsetY+1) ); } // setting chemical potential to the respective lattices blockLattice.get(iX, iY).template setField(term1 + term2 + 0.25*alpha*alpha*( (kappa2 - kappa1) * laplaceRho2 +(kappa2 + kappa1) * (laplaceRho3 - laplaceRho1) )); partnerLattice1->get(iX, iY).template setField(term1 - term2 + 0.25*alpha*alpha*( (kappa2 - kappa1) * (laplaceRho1 - laplaceRho3) -(kappa2 + kappa1) * laplaceRho2 )); if (partners.size() > 1) { partnerLattice2->get(iX, iY).template setField(- term1 - term2 + term3 + 0.25*alpha*alpha*( (kappa2 + kappa1) * laplaceRho1 -(kappa2 - kappa1) * laplaceRho2 -(kappa2 + kappa1 + 4.*kappa3) * laplaceRho3 )); } } } } } template void FreeEnergyChemicalPotentialCoupling2D::process ( BlockLattice2D& blockLattice) { processSubDomain(blockLattice, x0, x1, y0, y1); } //////// FreeEnergyForceCoupling2D /////////////////////////////////// template FreeEnergyForceCoupling2D ::FreeEnergyForceCoupling2D ( int x0_, int x1_, int y0_, int y1_, std::vector partners_) : x0(x0_), x1(x1_), y0(y0_), y1(y1_), partners(partners_) { } template FreeEnergyForceCoupling2D ::FreeEnergyForceCoupling2D ( std::vector partners_) : x0(0), x1(0), y0(0), y1(0), partners(partners_) { } template void FreeEnergyForceCoupling2D::processSubDomain ( BlockLattice2D& blockLattice, int x0_, int x1_, int y0_, int y1_ ) { // If partners.size() == 1: two fluid components // If partners.size() == 2: three fluid components BlockLattice2D *partnerLattice1 = dynamic_cast *>(partners[0]); BlockLattice2D *partnerLattice2 = 0; if (partners.size() > 1) { partnerLattice2 = dynamic_cast *>(partners[1]); } int newX0, newX1, newY0, newY1; if ( util::intersect ( x0, x1, y0, y1, x0_, x1_, y0_, y1_, newX0, newX1, newY0, newY1 ) ) { for (int iX=newX0; iX<=newX1; ++iX) { for (int iY=newY0; iY<=newY1; ++iY) { T phi = blockLattice.get(iX,iY).computeRho(); T rho = partnerLattice1->get(iX,iY).computeRho(); T gradMuPhiX = 1./12. * ( -blockLattice.get(iX-1,iY-1).template getField() - 4.* blockLattice.get(iX-1,iY ).template getField() - blockLattice.get(iX-1,iY+1).template getField() + blockLattice.get(iX+1,iY-1).template getField() + 4.* blockLattice.get(iX+1,iY ).template getField() + blockLattice.get(iX+1,iY+1).template getField() ); T gradMuPhiY = 1./12. * ( -blockLattice.get(iX-1,iY-1).template getField() - 4.* blockLattice.get(iX ,iY-1).template getField() - blockLattice.get(iX+1,iY-1).template getField() + blockLattice.get(iX-1,iY+1).template getField() + 4.* blockLattice.get(iX ,iY+1).template getField() + blockLattice.get(iX+1,iY+1).template getField() ); T gradMuRhoX = 1./12. * ( -partnerLattice1->get(iX-1,iY-1).template getField() - 4.* partnerLattice1->get(iX-1,iY ).template getField() - partnerLattice1->get(iX-1,iY+1).template getField() + partnerLattice1->get(iX+1,iY-1).template getField() + 4.* partnerLattice1->get(iX+1,iY ).template getField() + partnerLattice1->get(iX+1,iY+1).template getField() ); T gradMuRhoY = 1./12. * ( -partnerLattice1->get(iX-1,iY-1).template getField() - 4.* partnerLattice1->get(iX ,iY-1).template getField() - partnerLattice1->get(iX+1,iY-1).template getField() + partnerLattice1->get(iX-1,iY+1).template getField() + 4.* partnerLattice1->get(iX ,iY+1).template getField() + partnerLattice1->get(iX+1,iY+1).template getField() ); T psi = 0.; T gradMuPsiX = 0.; T gradMuPsiY = 0.; if (partners.size() > 1) { psi = partnerLattice2->get(iX,iY).computeRho(); gradMuPsiX = 1./12. * ( -partnerLattice2->get(iX-1,iY-1).template getField() - 4.* partnerLattice2->get(iX-1,iY ).template getField() - partnerLattice2->get(iX-1,iY+1).template getField() + partnerLattice2->get(iX+1,iY-1).template getField() + 4.* partnerLattice2->get(iX+1,iY ).template getField() + partnerLattice2->get(iX+1,iY+1).template getField() ); gradMuPsiY = 1./12. * ( -partnerLattice2->get(iX-1,iY-1).template getField() - 4.* partnerLattice2->get(iX ,iY-1).template getField() - partnerLattice2->get(iX+1,iY-1).template getField() + partnerLattice2->get(iX-1,iY+1).template getField() + 4.* partnerLattice2->get(iX ,iY+1).template getField() + partnerLattice2->get(iX+1,iY+1).template getField() ); } T forceX = -rho*gradMuRhoX - phi*gradMuPhiX - psi*gradMuPsiX; T forceY = -rho*gradMuRhoY - phi*gradMuPhiY - psi*gradMuPsiY; partnerLattice1->get(iX, iY).template setField({forceX, forceY}); T u[2]; partnerLattice1->get(iX,iY).computeU(u); blockLattice.get(iX, iY).template setField(u); if (partners.size() > 1) { partnerLattice2->get(iX, iY).template setField(u); } } } } } template void FreeEnergyForceCoupling2D::process( BlockLattice2D& blockLattice) { processSubDomain(blockLattice, x0, x1, y0, y1); } //////// FreeEnergyInletOutletCoupling2D /////////////////////////////////// template FreeEnergyInletOutletCoupling2D ::FreeEnergyInletOutletCoupling2D ( int x0_, int x1_, int y0_, int y1_, std::vector partners_) : x0(x0_), x1(x1_), y0(y0_), y1(y1_), partners(partners_) { } template FreeEnergyInletOutletCoupling2D ::FreeEnergyInletOutletCoupling2D ( std::vector partners_) : x0(0), x1(0), y0(0), y1(0), partners(partners_) { } template void FreeEnergyInletOutletCoupling2D::processSubDomain ( BlockLattice2D& blockLattice, int x0_, int x1_, int y0_, int y1_ ) { // If partners.size() == 1: two fluid components // If partners.size() == 2: three fluid components BlockLattice2D *partnerLattice1 = dynamic_cast *>(partners[0]); BlockLattice2D *partnerLattice2 = 0; if (partners.size() > 1) { partnerLattice2 = dynamic_cast *>(partners[1]); } int newX0, newX1, newY0, newY1; if ( util::intersect ( x0, x1, y0, y1, x0_, x1_, y0_, y1_, newX0, newX1, newY0, newY1 ) ) { for (int iX=newX0; iX<=newX1; ++iX) { for (int iY=newY0; iY<=newY1; ++iY) { T u[DESCRIPTOR::d]; partnerLattice1->get(iX,iY).computeU(u); blockLattice.get(iX,iY).defineU(u); if (partners.size() > 1) { partnerLattice2->get(iX,iY).defineU(u); } } } } } template void FreeEnergyInletOutletCoupling2D::process( BlockLattice2D& blockLattice) { processSubDomain(blockLattice, x0, x1, y0, y1); } //////// FreeEnergyDensityOutletCoupling2D /////////////////////////////////// template FreeEnergyDensityOutletCoupling2D ::FreeEnergyDensityOutletCoupling2D ( int x0_, int x1_, int y0_, int y1_, T rho_, std::vector partners_) : x0(x0_), x1(x1_), y0(y0_), y1(y1_), rho(rho_), partners(partners_) { } template FreeEnergyDensityOutletCoupling2D ::FreeEnergyDensityOutletCoupling2D ( T rho_, std::vector partners_) : x0(0), x1(0), y0(0), y1(0), rho(rho_), partners(partners_) { } template void FreeEnergyDensityOutletCoupling2D::processSubDomain ( BlockLattice2D& blockLattice, int x0_, int x1_, int y0_, int y1_ ) { // If partners.size() == 1: two fluid components // If partners.size() == 2: three fluid components BlockLattice2D *partnerLattice1 = dynamic_cast *>(partners[0]); BlockLattice2D *partnerLattice2 = 0; if (partners.size() > 1) { partnerLattice2 = dynamic_cast *>(partners[1]); } int newX0, newX1, newY0, newY1; if ( util::intersect ( x0, x1, y0, y1, x0_, x1_, y0_, y1_, newX0, newX1, newY0, newY1 ) ) { for (int iX=newX0; iX<=newX1; ++iX) { for (int iY=newY0; iY<=newY1; ++iY) { T rho0, phi, psi; rho0 = blockLattice.get(iX,iY).computeRho(); phi = partnerLattice1->get(iX,iY).computeRho(); blockLattice.get(iX,iY).defineRho(rho); partnerLattice1->get(iX,iY).defineRho(phi * rho / rho0); if (partners.size() > 1) { psi = partnerLattice2->get(iX,iY).computeRho(); partnerLattice2->get(iX,iY).defineRho(psi * rho / rho0); } } } } } template void FreeEnergyDensityOutletCoupling2D::process( BlockLattice2D& blockLattice) { processSubDomain(blockLattice, x0, x1, y0, y1); } //////// FreeEnergyChemicalPotentialGenerator2D /////////////////////////////////// template FreeEnergyChemicalPotentialGenerator2D::FreeEnergyChemicalPotentialGenerator2D ( int x0_, int x1_, int y0_, int y1_, T alpha_, T kappa1_, T kappa2_) : LatticeCouplingGenerator2D(x0_, x1_, y0_, y1_), alpha(alpha_), kappa1(kappa1_), kappa2(kappa2_), kappa3(0) { } template FreeEnergyChemicalPotentialGenerator2D::FreeEnergyChemicalPotentialGenerator2D ( T alpha_, T kappa1_, T kappa2_ ) : LatticeCouplingGenerator2D(0, 0, 0, 0), alpha(alpha_), kappa1(kappa1_), kappa2(kappa2_), kappa3(0) { } template FreeEnergyChemicalPotentialGenerator2D::FreeEnergyChemicalPotentialGenerator2D ( int x0_, int x1_, int y0_, int y1_, T alpha_, T kappa1_, T kappa2_, T kappa3_) : LatticeCouplingGenerator2D(x0_, x1_, y0_, y1_), alpha(alpha_), kappa1(kappa1_), kappa2(kappa2_), kappa3(kappa3_) { } template FreeEnergyChemicalPotentialGenerator2D::FreeEnergyChemicalPotentialGenerator2D ( T alpha_, T kappa1_, T kappa2_, T kappa3_ ) : LatticeCouplingGenerator2D(0, 0, 0, 0), alpha(alpha_), kappa1(kappa1_), kappa2(kappa2_), kappa3(kappa3_) { } template PostProcessor2D* FreeEnergyChemicalPotentialGenerator2D::generate ( std::vector partners) const { return new FreeEnergyChemicalPotentialCoupling2D( this->x0,this->x1,this->y0,this->y1, alpha, kappa1, kappa2, kappa3, partners); } template LatticeCouplingGenerator2D* FreeEnergyChemicalPotentialGenerator2D::clone() const { return new FreeEnergyChemicalPotentialGenerator2D(*this); } //////// FreeEnergyForceGenerator2D /////////////////////////////////// template FreeEnergyForceGenerator2D::FreeEnergyForceGenerator2D ( int x0_, int x1_, int y0_, int y1_) : LatticeCouplingGenerator2D(x0_, x1_, y0_, y1_) { } template FreeEnergyForceGenerator2D::FreeEnergyForceGenerator2D ( ) : LatticeCouplingGenerator2D(0, 0, 0, 0) { } template PostProcessor2D* FreeEnergyForceGenerator2D::generate ( std::vector partners) const { return new FreeEnergyForceCoupling2D( this->x0,this->x1,this->y0,this->y1, partners); } template LatticeCouplingGenerator2D* FreeEnergyForceGenerator2D::clone() const { return new FreeEnergyForceGenerator2D(*this); } //////// FreeEnergyInletOutletGenerator2D /////////////////////////////////// template FreeEnergyInletOutletGenerator2D::FreeEnergyInletOutletGenerator2D ( int x0_, int x1_, int y0_, int y1_) : LatticeCouplingGenerator2D(x0_, x1_, y0_, y1_) { } template FreeEnergyInletOutletGenerator2D::FreeEnergyInletOutletGenerator2D ( ) : LatticeCouplingGenerator2D(0, 0, 0, 0) { } template PostProcessor2D* FreeEnergyInletOutletGenerator2D::generate ( std::vector partners) const { return new FreeEnergyInletOutletCoupling2D( this->x0,this->x1,this->y0,this->y1, partners); } template LatticeCouplingGenerator2D* FreeEnergyInletOutletGenerator2D::clone() const { return new FreeEnergyInletOutletGenerator2D(*this); } //////// FreeEnergyDensityOutletGenerator2D /////////////////////////////////// template FreeEnergyDensityOutletGenerator2D::FreeEnergyDensityOutletGenerator2D ( int x0_, int x1_, int y0_, int y1_, T rho_) : LatticeCouplingGenerator2D(x0_, x1_, y0_, y1_), rho(rho_) { } template FreeEnergyDensityOutletGenerator2D::FreeEnergyDensityOutletGenerator2D ( T rho_) : LatticeCouplingGenerator2D(0, 0, 0, 0), rho(rho_) { } template PostProcessor2D* FreeEnergyDensityOutletGenerator2D::generate ( std::vector partners) const { return new FreeEnergyDensityOutletCoupling2D( this->x0,this->x1,this->y0,this->y1, rho, partners); } template LatticeCouplingGenerator2D* FreeEnergyDensityOutletGenerator2D::clone() const { return new FreeEnergyDensityOutletGenerator2D(*this); } } // namespace olb #endif