Foam::activeBaffleVelocityFvPatchVectorField::
activeBaffleVelocityFvPatchVectorField
(
    const fvPatch& p,
    const DimensionedField<vector, volMesh>& iF,
    const dictionary& dict
)
:
    fixedValueFvPatchVectorField(p, iF),
    pName_(dict.lookupOrDefault<word>("p", "p")),
    cyclicPatchName_(dict.lookup("cyclicPatch")),
    cyclicPatchLabel_(p.patch().boundaryMesh().findPatchID(cyclicPatchName_)),
    orientation_(readLabel(dict.lookup("orientation"))),
    initWallSf_(p.Sf()),
    initCyclicSf_(p.boundaryMesh()[cyclicPatchLabel_].Sf()),
    nbrCyclicSf_
    (
        refCast<const cyclicFvPatch>
        (
            p.boundaryMesh()[cyclicPatchLabel_]
        ).neighbFvPatch().Sf()
    ),
    openFraction_(readScalar(dict.lookup("openFraction"))),
    openingTime_(readScalar(dict.lookup("openingTime"))),
    maxOpenFractionDelta_(readScalar(dict.lookup("maxOpenFractionDelta"))),
    curTimeIndex_(-1)
{
    fvPatchVectorField::operator=(vector::zero);
}
thermalBaffle1DFvPatchScalarField<solidType>::
thermalBaffle1DFvPatchScalarField
(
    const fvPatch& p,
    const DimensionedField<scalar, volMesh>& iF,
    const dictionary& dict
)
:
    mappedPatchBase
    (
        p.patch(),
        p.boundaryMesh().mesh().name(),
        NEARESTPATCHFACE,
        dict.lookup("samplePatch"),
        0.0
    ),
    mixedFvPatchScalarField(p, iF),
    TName_("T"),
    baffleActivated_(dict.lookupOrDefault<bool>("baffleActivated", true)),
    thickness_(),
    Qs_(p.size(), 0),
    solidDict_(dict),
    solidPtr_(),
    QrPrevious_(p.size(), 0.0),
    QrRelaxation_(dict.lookupOrDefault<scalar>("relaxation", 0)),
    QrName_(dict.lookupOrDefault<word>("Qr", "none"))
{
    fvPatchScalarField::operator=(scalarField("value", dict, p.size()));

    if (dict.found("thickness"))
    {
        thickness_ = scalarField("thickness", dict, p.size());
    }

    if (dict.found("Qs"))
    {
        Qs_ = scalarField("Qs", dict, p.size());
    }

    if (dict.found("QrPrevious"))
    {
        QrPrevious_ = scalarField("QrPrevious", dict, p.size());
    }

    if (dict.found("refValue") && baffleActivated_)
    {
        // Full restart
        refValue() = scalarField("refValue", dict, p.size());
        refGrad() = scalarField("refGradient", dict, p.size());
        valueFraction() = scalarField("valueFraction", dict, p.size());
    }
    else
    {
        // Start from user entered data. Assume zeroGradient.
        refValue() = *this;
        refGrad() = 0.0;
        valueFraction() = 0.0;
    }

}
void implicitExtrapolationFvPatchField<Type>::setExtraData(const fvPatch& p){

    const fvMesh& m = p.boundaryMesh().mesh();
    const faceList& meshFaces = m.faces();
    const cellList cells = m.cells();
    const labelList& faceCells = p.faceCells();
    const volVectorField& centers = m.C();

    forAll(faceCells,i){

        const label curCellLabel = faceCells[i];
        const label curPatchFaceLabel = p.patch().start() + i;

        const label secondFace = cells[curCellLabel].opposingFaceLabel(curPatchFaceLabel,meshFaces);
        secondFacesIDs[i] = secondFace;
        const label ownerSecondFace = m.owner()[secondFace];
        const label neighbourSecondFace = m.neighbour()[secondFace];

        if (curCellLabel == ownerSecondFace){
            secondNormalCellIsOwner[i] = 0;
        }
        else{
            secondNormalCellIsOwner[i] = 1;
        }

        secondDeltas[i] = mag(centers[ownerSecondFace] - centers[neighbourSecondFace]);

    }

}
Foam::activePressureForceBaffleVelocityFvPatchVectorField::
activePressureForceBaffleVelocityFvPatchVectorField
(
    const fvPatch& p,
    const DimensionedField<vector, volMesh>& iF,
    const dictionary& dict
)
:
    fixedValueFvPatchVectorField(p, iF),
    pName_(dict.lookupOrDefault<word>("p", "p")),
    cyclicPatchName_(dict.lookup("cyclicPatch")),
    cyclicPatchLabel_(p.patch().boundaryMesh().findPatchID(cyclicPatchName_)),
    orientation_(readLabel(dict.lookup("orientation"))),
    initWallSf_(0),
    initCyclicSf_(0),
    nbrCyclicSf_(0),
    openFraction_(readScalar(dict.lookup("openFraction"))),
    openingTime_(readScalar(dict.lookup("openingTime"))),
    maxOpenFractionDelta_(readScalar(dict.lookup("maxOpenFractionDelta"))),
    curTimeIndex_(-1),
    minThresholdValue_(readScalar(dict.lookup("minThresholdValue"))),
    fBased_(readBool(dict.lookup("forceBased"))),
    baffleActivated_(0)
{
    fvPatchVectorField::operator=(vector::zero);

    if (p.size() > 0)
    {
        initWallSf_ = p.Sf();
        initCyclicSf_ = p.boundaryMesh()[cyclicPatchLabel_].Sf();
        nbrCyclicSf_ =  refCast<const cyclicFvPatch>
        (
            p.boundaryMesh()[cyclicPatchLabel_]
        ).neighbFvPatch().Sf();
    }

    if (dict.found("p"))
    {
        dict.lookup("p") >> pName_;
    }
//template<class type>
secondNormalBoundaryCells::secondNormalBoundaryCells(const fvPatch& p):
    secondNormalFaceIsOwner(p.size()),
    secondDeltas(p.size()),
    secondFaces(p.size()),
    secondInternalCoeffs(p.size()){

    const fvMesh& m = p.boundaryMesh().mesh();
    const faceList& meshFaces = m.faces();
    const cellList cells = m.cells();
    const labelList& faceCells = p.faceCells();
    const volVectorField& centers = m.C();
    const labelList& neighbours = m.neighbour();
    const labelList& owners = m.owner();

    forAll(faceCells,i){

        const label curCellLabel = faceCells[i];
        const label curPatchFaceLabel = p.patch().start() + i;

        const label secondFace = cells[curCellLabel].opposingFaceLabel(curPatchFaceLabel,meshFaces);
        secondFaces[i] = secondFace;

        if (curCellLabel == m.owner()[secondFace]){

            secondNormalFaceIsOwner[i] = false;
            secondDeltas[i] = mag(centers[curCellLabel] - centers[neighbours[secondFace]]);

        }
        else{

            secondNormalFaceIsOwner[i] = true;
            secondDeltas[i] = mag(centers[curCellLabel] - centers[owners[secondFace]]);

        }

    }



}
// Construct from dictionary
Foam::dirichletNeumannFriction::dirichletNeumannFriction
(
    const word& name,
    const fvPatch& patch,
    const dictionary& dict,
    const label masterPatchID,
    const label slavePatchID,
    const label masterFaceZoneID,
    const label slaveFaceZoneID
)
    :
    frictionContactModel
    (
       name,
       patch,
       dict,
       masterPatchID,
       slavePatchID,
       masterFaceZoneID,
       slaveFaceZoneID
    ),
    frictionContactModelDict_(dict.subDict(name+"FrictionModelDict")),
    frictionLawPtr_(NULL),
    mesh_(patch.boundaryMesh().mesh()),
    slaveDisp_(mesh().boundaryMesh()[slavePatchID].size(), vector::zero),
    oldSlaveDisp_(slaveDisp_),
    oldSlip_(slaveDisp_.size(), vector::zero),
    slaveTraction_(mesh().boundaryMesh()[slavePatchID].size(), vector::zero),
    oldSlaveTraction_(slaveTraction_),
    slaveValueFrac_(mesh_.boundaryMesh()[slavePatchID].size(), symmTensor::zero),
    oldSlaveValueFrac_(slaveValueFrac_),
    relaxationFactor_
    (readScalar(frictionContactModelDict_.lookup("relaxationFactor"))),
    contactIterNum_(0),
    infoFreq_(readInt(frictionContactModelDict_.lookup("infoFrequency"))),
    oscillationCorr_(frictionContactModelDict_.lookup("oscillationCorrection")),
    smoothingSteps_(readInt(frictionContactModelDict_.lookup("smoothingSteps"))),
    oldStickSlip_(slaveDisp_.size(), 0.0),
    contactFilePtr_(NULL)
{
    // create friction law
    frictionLawPtr_ = frictionLaw::New(
                          frictionContactModelDict_.lookup("frictionLaw"),
                          frictionContactModelDict_
                      ).ptr();

    // master proc open contact info file
    if (Pstream::master())
    {
        word masterName = mesh_.boundary()[masterPatchID].name();
        word slaveName = mesh_.boundary()[slavePatchID].name();
        contactFilePtr_ =
            new OFstream
        (fileName("frictionContact_"+masterName+"_"+slaveName+".txt"));
        OFstream& contactFile = *contactFilePtr_;
        int width = 20;
        contactFile << "time";
        contactFile.width(width);
        contactFile << "iterNum";
        contactFile.width(width);
        contactFile << "relaxationFactor";
        contactFile.width(width);
        contactFile << "slipFaces";
        contactFile.width(width);
        contactFile << "stickFaces";
        contactFile.width(width);
        contactFile << "maxMagSlaveTraction" << endl;
    }
}
void epsilonLowReWallFunctionFvPatchScalarField::calculate
(
    const turbulenceModel& turbulence,
    const gpuList<scalar>& cornerWeights,
    const fvPatch& patch,
    scalargpuField& G,
    scalargpuField& epsilon
)
{
    const label patchi = patch.index();

    const scalargpuField& y = turbulence.y()[patchi];

    const scalar Cmu25 = pow025(Cmu_);
    const scalar Cmu75 = pow(Cmu_, 0.75);

    const tmp<volScalarField> tk = turbulence.k();
    const volScalarField& k = tk();

    const tmp<scalargpuField> tnuw = turbulence.nu(patchi);
    const scalargpuField& nuw = tnuw();

    const tmp<scalargpuField> tnutw = turbulence.nut(patchi);
    const scalargpuField& nutw = tnutw();

    const fvPatchVectorField& Uw = turbulence.U().boundaryField()[patchi];

    const scalargpuField magGradUw(mag(Uw.snGrad()));

    matrixPatchOperation
    (
        patchi,
        epsilon,
        patch.boundaryMesh().mesh().lduAddr(),
        EpsilonLowReCalculateEpsilonFunctor
        (
            yPlusLam_,
            Cmu25,
            Cmu75,
            kappa_,
            cornerWeights.data(),
            y.data(),
            k.getField().data(),
            nuw.data()
        )
    );
	
    matrixPatchOperation
    (
        patchi,
        G,
        patch.boundaryMesh().mesh().lduAddr(),
        EpsilonLowReCalculateGFunctor
        (
            Cmu25,
            kappa_,
            cornerWeights.data(),
            y.data(),
            k.getField().data(),
            nuw.data(),
            nutw.data(),
            magGradUw.data()
        )
    );
}