Calculating Average of Variable at Periodic Boundary

Hello,

I’ve been able to split the periodic faces from the rest of the internal faces, and I use a class similar to the internal interfaces class to handle the periodic interfaces and some mako kernels to decouple the fluxes for select scalars. I’d now like to calculate the average on the LHS and RHS of the periodic boundary in order to make some control loops, but I can’t seem to figure out how to do this from the internal interface classes.

Is there a way to access the solution from the internal interface classes so I can take an integral, similar to in the plugins or BC interfaces? My first thought was to create a class similar to MassFlowBCMixin to do this, but the implementation has proven quite cumbersome.

I’d appreciate any help :slight_smile:

Fred

You will need to do what the mass flow controller boundary condition does. Only difference is what you’ll pass in as the surface list.

Regards, Freddie.

The averaging over the periodic surface is working now :slight_smile:

My next issue is that I can’t seem to be able to pass an external value to the kernels.

I attempted to replicate what was done here (and something similar worked for a plugin I made a while ago), but it throws “invalid argument specification”

My class is similar to the MassFlowBC one, and is structured as follows (I only want to use the external value in the comm_flux kernel):

class ACNavierStokesPintInters(ScalarPeriodic, BaseAdvectionDiffusionIntInters):
    def __init__(self, be, lhs, rhs, elemap, cfg):
        super().__init__(be, lhs, rhs, elemap, cfg)

        # Pointwise template arguments
        rsolver = self.cfg.get('solver-interfaces', 'riemann-solver')
        tplargs = dict(ndims=self.ndims, nvars=self.nvars, rsolver=rsolver,
                       c=self.c)
                       
        kprefix = 'pyfr.solvers.acnavstokes.kernels'
        self._be.pointwise.register(f'{kprefix}.pintconu')
        self._be.pointwise.register(f'{kprefix}.pintcflux')
        
        self.kernels['con_u'] = lambda: self._be.kernel(
            'pintconu', tplargs=tplargs, dims=[self.ninterfpts],
            ulin=self._scal_lhs, urin=self._scal_rhs,
            ulout=self._comm_lhs, urout=self._comm_rhs
        )
        self.kernels['comm_flux'] = lambda: self._be.kernel(
            'pintcflux', tplargs=tplargs, dims=[self.ninterfpts],
            extrns=self._external_args, ul=self._scal_lhs, 
            ur=self._scal_rhs, gradul=self._vect_lhs, 
            gradur=self._vect_rhs, nl=self._pnorm_lhs
        )

and the relevant parts from the ScalarPeriodic class:

class ScalarPeriodic:
    def __init__(self, be, lhs, rhs, elemap, cfg):
        super().__init__(be, lhs, rhs, elemap, cfg)
        
        self.cfgsect = f'scalar-periodic'
        self.name = f'periodic'
        
        # Setting the desired average value of scalar T
        self.T_sp =  self.cfg.getfloat(self.cfgsect, 'T_avg', 1.0)
        
        # Controlling inlet (LHS) scalar avg
        self.cf = be.matrix((1, 1), tags={'align'})
        self.cf.set(np.full((1, 1), 1.0))
        self._set_external('cf', f'in broadcast fpdtype_t[1][1]', value=self.cf)
...

    @classmethod
    def preparefn(cls, pciface, mesh, elemap):
        if pciface:
            return pciface.prepare
        else:
            return None

    def prepare(self, system, ubank, t, kerns): 
        solns = dict(zip(system.ele_types, system.ele_scal_upts(ubank)))
        self.mT = self.calculate_scalar_avg(solns)
        self.cf.set(np.full((1, 1), self.T_sp / self.mT))

Finally, the mako kernel:

...
<%pyfr:kernel name='pintcflux' ndim='1' params='ul, ur, gradul, nl' externs='cf'>
...

When I had tried to use the bind method on a scalar like in the MassFlowBC class, it threw ‘PointwiseKernel’ object has no attribute ‘bind’ so I’m wondering if I did something wrong in my solvers/base/system.py file…

Can you see what I’m doing wrong at a glance?

Thank you,

Fred

Only scalar arguments require binding. In your case you’re using an array, so it doesn’t need to be rebound (the pointer remains constant). See the turbulent inflow plugin for an example of this—it never calls bind.

Regards, Freddie.

1 Like

I got it working. The mako kernel compiler didn’t like missing the parameter definitions in the header when I tried adding the externs keyword. I figured out you can access external values without the using the externs keyword as long as you pass extrns=self._external_args to the kernel. I also forgot gradur, but that wasn’t the issue. For reference, the mako file header in the working version looks like this (i.e., no params or externs keywords):

<%pyfr:kernel name='pintcflux' ndim='1'
              ur='inout view fpdtype_t[${str(nvars)}]'
              ul='inout view fpdtype_t[${str(nvars)}]'
              gradul='in view fpdtype_t[${str(ndims)}][${str(nvars)}]'
              gradur='in view fpdtype_t[${str(ndims)}][${str(nvars)}]'
              nl='in fpdtype_t[${str(ndims)}]'>

I’m off to go run some cases now :cowboy_hat_face:

Thank you for your help.

Fred