/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     | Website:  https://openfoam.org
    \\  /    A nd           | Copyright (C) 2025 OpenFOAM Foundation
     \\/     M anipulation  |
-------------------------------------------------------------------------------
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 <http://www.gnu.org/licenses/>.

Class
    Foam::LagrangianAverage

Description
    Lagrangian averaging process in which values are averaged onto the mesh
    cell-centres and points using the basis functions associated with the
    tetrahedral decomposition. Interpolation back to the Lagrangian points is
    then done with the same basis functions.

SourceFiles
    cellPoint_LagrangianAverage.C
    cellPoint_LagrangianAverages.C

\*---------------------------------------------------------------------------*/

#ifndef cellPoint_LagrangianAverage_H
#define cellPoint_LagrangianAverage_H

#include "LagrangianAverage.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace Foam
{

class polyMesh;

namespace LagrangianAverages
{

/*---------------------------------------------------------------------------*\
                      Class LagrangianAverage Declaration
\*---------------------------------------------------------------------------*/

template<class Type>
class cellPoint
:
    public LagrangianAverage<Type>
{
private:

    // Private Classes

        //- Data structure for an average
        struct data
        {
            //- Map from the cell to the cell average
            List<label> cellCellAvg_;

            //- Map from the point to the point average
            List<label> pointPointAvg_;

            //- Map from the cell average to the cell
            DynamicList<label> cellAvgCell_;

            //- Map from the point average to the point
            DynamicList<label> pointAvgPoint_;

            //- Number of samples in each cell average
            DynamicList<label> cellAvgCount_;

            //- Number of samples in each point average
            DynamicList<label> pointAvgCount_;

            //- Weight sums for each cell average
            autoPtr<DynamicList<scalar>> cellAvgWeightSumPtr_;

            //- Weight sums for each point average
            autoPtr<DynamicList<scalar>> pointAvgWeightSumPtr_;

            //- Value sums for each cell average
            DynamicList<Type> cellAvgSum_;

            //- Value sums for each point average
            DynamicList<Type> pointAvgSum_;

            //- Construct given a number of cells and points and a flag to
            //  specify whether or not weight sums need to be stored
            data
            (
                const label nCells,
                const label nPoints,
                const bool hasWeightSum
            );
        };


    // Private Data

        //- Constant cell weight sums. E.g., the volume of the cell basis
        //  function. Might be empty.
        const autoPtr<Field<scalar>> cellWeightSumPtr_;

        //- Constant point weight sums. E.g., the volume of the point basis
        //  function. Might be empty.
        const autoPtr<Field<scalar>> pointWeightSumPtr_;

        //- Base data
        data data_;

        //- Flag to indicate whether or not difference data is available
        bool dDataIsValid_;

        //- Difference data for correction later
        data dData_;


    // Private Member Functions

        //-  Calculate a volume-weighted sum over the cells
        template<class CellWeight>
        static tmp<Field<scalar>> cellVolumeWeightedSum
        (
            const polyMesh& pMesh,
            const CellWeight& cellWeight
        );

        //-  Calculate a volume-weighted sum over the points
        static tmp<Field<scalar>> cellWeightSum
        (
            const polyMesh& pMesh,
            const Field<scalar>& weightSum
        );

        //-  Calculate the cell constant weight sum
        template<class CellWeight>
        static tmp<Field<scalar>> pointVolumeWeightedSum
        (
            const polyMesh& pMesh,
            const CellWeight& cellWeight
        );

        //-  Calculate the point constant weight sum
        static tmp<Field<scalar>> pointWeightSum
        (
            const polyMesh& pMesh,
            const Field<scalar>& weightSum
        );

        //- Remove all values from the average data
        static void clear(data& d);

        //- Remove values from the cell average data
        static void removeFromCells
        (
            const LagrangianSubSubField<scalar>& weight,
            const LagrangianSubSubField<Type>& psi,
            data& d
        );

        //- Add values to the cell average data
        static void addToCells
        (
            const LagrangianSubSubField<scalar>& weight,
            const LagrangianSubSubField<Type>& psi,
            data& d
        );

        //- Add values to the point average data
        static void addToPoints
        (
            const LagrangianSubSubField<scalar>& weight,
            const LagrangianSubSubField<Type>& psi,
            data& d
        );

        //- Remove values from the point average data
        static void removeFromPoints(const data& dd, data& d);

        //- Add values to the point average data
        static void addToPoints(const data& dd, data& d);

        //- Interpolate into a sub-field, where possible. Calling code deals
        //  with default values where no elements are available to interpolate.
        virtual void interpolate(LagrangianSubField<Type>& result) const;


public:

    //- Runtime type information
    TypeName("cellPoint");


    // Constructors

        //- Construct with a name, for a mesh and with given dimensions
        cellPoint
        (
            const word& name,
            const LagrangianMesh& mesh,
            const dimensionSet& dimensions,
            const Field<scalar>& weightSum
        );


    //- Destructor
    virtual ~cellPoint();


    // Member Functions

        //- Remove weighted values from the average
        virtual void remove
        (
            const LagrangianSubSubField<scalar>& weight,
            const LagrangianSubSubField<Type>& psi
        );

        //- Add weighted values to the average
        virtual void add
        (
            const LagrangianSubSubField<scalar>& weight,
            const LagrangianSubSubField<Type>& psi,
            const bool cache
        );

        //- Correct weighted values in the average
        virtual void correct
        (
            const LagrangianSubSubField<scalar>& weight,
            const LagrangianSubSubField<Type>& psi,
            const bool cache
        );
};


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

} // End namespace LagrangianAverages
} // End namespace Foam

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#ifdef NoRepository
    #include "cellPoint_LagrangianAverage.C"
#endif

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#endif

// ************************************************************************* //
