Symbolic Geometry definition for PINN

Dear all,

I’m trying to solve the Reynolds-Averaged Navier Stokes (RANS) equations in a channel with periodic hills (see Figure below).

The hill geometry is defined by a third order polynomial, here assumed to be computed in the function shape_hill(x). Is it possible to use the present symbolic function shape_hill(x) to define the parameters domains ?

# Parameters
@parameters x, y
@variables u(..), v(..), uu(..), uv(..), vv(..), p(..)
rho = 1.2
nu = 0.000015

# 2D RANS Partial Differential Equations
Dx = Differential(x)
Dxx = Differential(x)^2
Dy = Differential(y)
Dyy = Differential(y)^2

eqs  = [u(x,y)*Dx(u(x,y)) + v(x,y)*Dy(u(x,y)) + (1/rho)*Dx(p(x,y)) - nu*(Dxx(u(x,y)) + Dyy(u(x,y))) + Dx(uu(x,y)) + Dy(uv(x,y)) ~ 0. ,
        u(x,y)*Dx(v(x,y)) + v(x,y)*Dy(v(x,y)) + (1/rho)*Dy(p(x,y)) - nu*(Dxx(v(x,y)) + Dyy(v(x,y))) + Dx(uv(x,y)) + Dy(vv(x,y)) ~ 0. ,
        Dx(u(x,y)) + Dy(v(x,y)) ~ 0.0]

function shape_hill(x)
...
end

domains = [x ∈ [0.,9.], y ∈ [shape_hill(x),3.]]

If yes, could it also be used for the boundary conditions (e.g zero velocity on the ground) ?

Something like:

bcs = [u(x,shape_hill(x)) ~ 0., v(x,shape_hill(x)) ~ 0.]

When I tried to use shape_hill(x) for the domain definition I had the following error message TypeError: non-boolean (Num) used in boolean context.

Thanks in advance!

Hard to say for sure without seeing the code for shape_hill, but This is most likely due to something like this: Frequently Asked Questions · Symbolics.jl

It may also be a simple conditional, if you can replace if-else control flow with IfElse.ifelse, you can sometimes fix this.

Thanks @contradict for your answer, I’ll have a look to the links!

Here is the shape_hill(x) function :

function shape_hill(x)

        if x > 126.0
                x = 252.0 - x
        end
        
        if x>=0 && x<9
                return  min(28., 2.8e+01 + 0.0e+00*x + 6.775070969851e-03*x^2 - 2.124527775800e-03*x^3)/H
        elseif x>=9 && x<14
                return  (2.507355893131e+01 + 9.754803562315e-01*x - 1.016116352781e-01*x^2 + 1.889794677828e-03*x^3)/H
        elseif x>=14 && x<20
                return  (2.579601052357e+01 + 8.206693007457e-01*x - 9.055370274339e-02*x^2 + 1.626510569859e-03*x^3)/H
        elseif x>=20 && x<30
                return  (4.046435022819e+01 - 1.379581654948e+00*x + 1.945884504128e-02*x^2 - 2.070318932190e-04*x^3)/H
        elseif x>=30 && x<40
                return  (1.792461334664e+01 + 8.743920332081e-01*x - 5.567361123058e-02*x^2 + 6.277731764683e-04*x^3)/H
        elseif x>=40 && x<=54
                return  max(0., 5.639011190988e+01 - 2.010520359035e+00*x + 1.644919857549e-02*x^2 + 2.674976141766e-05*x^3)/H
        elseif x>54 && x<=126
                return  0
        end

end

It is based on the DNS work from Breuer et al. (2009).

Yeah, either @register_symbolic shape_hill(x) to entirely prevent tracing that or re-write it to use ifelse should fix this problem.

Indeed, thanks a lot @contradict, I tested both methods and that got rid of the error. However I performed some checks and I am not sure it gives what I want, e.g:

@register_symbolic shape_hill(x)
domains = [x ∈ Interval(0.,9.), y ∈ Interval(shape_hill(x),3.)]
[3. 2.] in domains **False**

But [3. 2.] should be in the domain. I also checked shape_hill(x) and it works properly.

Moreover, I tried to pursue the PINN implementation following the different tutorials

# Initial and boundary conditions
bcs = [u(x,wall_bottom(x)) ~ 0., v(x,wall_bottom(x)) ~ 0.,
       uu(x,wall_bottom(x)) ~ 0., uv(x,wall_bottom(x)) ~ 0.,
       vv(x,wall_bottom(x)) ~ 0.]

# Neural network
inner = 16
chain =[FastChain(FastDense(2,inner,Flux.σ),
                 FastDense(inner,inner,Flux.σ),
                 FastDense(inner,1))
                 for _ in 1:6]

strategy = GridTraining(0.1)
discretization = PhysicsInformedNN(chain,strategy)

@named pde_system = PDESystem(eqs,bcs,domains,[x,y],[u,v,uu,uv,vv, p])
prob = discretize(pde_system,discretization)

But I had an issue regarding the use of the discretize function : TypeError: non-boolean (Num) used in boolean context.

To overcome it, I used symbolic_discretize but had an issue when solving the optimization problem : MethodError: no method matching init(::Tuple{Vector{Expr}, Vector{Expr}}, ::ADAM; cb=var"#23#24" (), maxiters=500)

res = GalacticOptim.solve(prob,ADAM(0.01);cb=cb,maxiters=500)

I don’t expect the symbolic interval to work as written, but you could probably write a function to test that with some Expression Manipulation · Symbolics.jl

The error from symbolic_discretize is not one I recognize, but just from the signature it is looking for, I suspect you forgot a step. It looks like prob is actually a tuple, no a problem instance. Perhaps you need to call some kind of problem constructor between discretize and solve.

Can you turn this into an issue?