tum-pbs / PhiFlow

A differentiable PDE solving framework for machine learning
MIT License
1.39k stars 189 forks source link

Would PhiFlow support C++ Api in the future? #162

Closed Xayah-Hina closed 1 month ago

Xayah-Hina commented 1 month ago

I want to integrate a differentiable fluid simulator into Houdini HDK, since I need Houdini as a better viewer and get better performance by PDG.

So would phiflow support C++ Api in the future like pytorch? Reading results simulated by Python and converting it as Houdini Goometry are too time-consuming. So, it would be better if we can directly run pure c++ codes and get the results without converting process.

Btw, I would appreciate it if there are any share-worthy experiences for embeding python code inside c++ just like mantaflow did... ?

Thanks for your awesome work : )

holl- commented 1 month ago

Hi!

Usually we embed C/C++ code so it can be called by Python, e.g. with pybind11. Likewise, PyTorch is written in C++ and exposes the functionality to Python in that way. However, as PhiFlow is written mostly in Python, it's unlikely, we'll add a C++ API.

Maybe you could wrap your C++ calls with pybind and use Python for the top-level execution?

Xayah-Hina commented 1 month ago

Hi!

Usually we embed C/C++ code so it can be called by Python, e.g. with pybind11. Likewise, PyTorch is written in C++ and exposes the functionality to Python in that way. However, as PhiFlow is written mostly in Python, it's unlikely, we'll add a C++ API.

Maybe you could wrap your C++ calls with pybind and use Python for the top-level execution?

Hi holl~ Thanks for your quick reply~

I found a convenient header in Houdini HDK #include <PY/PY_Python.h>, so we can easily embed python into Houdini context. The usage (In HDK DOP context) would be like below:

bool GAS_TestPhiFlow::solveGasSubclass(SIM_Engine& engine, SIM_Object* obj, SIM_Time time, SIM_Time timestep)
{
    SIM_ScalarField* D = getScalarField(obj, GAS_NAME_DENSITY);
    SIM_VectorField* V = getVectorField(obj, GAS_NAME_VELOCITY);
    if (!D || !V)
    {
        addError(obj, SIM_MESSAGE, "Missing GAS fields", UT_ERROR_FATAL);
        return false;
    }

    UT_WorkBuffer expr;
    PY_Result result;

    expr.sprintf(R"(
from phi.torch.flow import *

velocity = StaggeredGrid((0, 0, 0), 0, x=50, y=50, z=50, bounds=Box(x=1, y=1, z=1))  # or CenteredGrid(...)
smoke = CenteredGrid(0, ZERO_GRADIENT, x=50, y=50, z=50, bounds=Box(x=1, y=1, z=1))
INFLOW = 0.5 * resample(Sphere(x=0.5, y=0.5, z=0.5, radius=0.1), to=smoke, soft=True)
pressure = None

@jit_compile  # Only for PyTorch, TensorFlow and Jax
def step(v, s, p, dt=1.):
    s = advect.mac_cormack(s, v, dt) + INFLOW
    buoyancy = resample(s * (0, 0, 0.1), to=v)
    v = advect.semi_lagrangian(v, v, dt) + buoyancy * dt
    v, p = fluid.make_incompressible(v, (), Solve('auto', 1e-5, x0=p))
    return v, s, p

velocity, smoke, pressure = step(velocity, smoke, pressure)
)");
    PYrunPythonStatementsAndExpectNoErrors(expr.buffer());
    expr.sprintf("[CODES TO EXTRACT PHIFLOW FIELDS TO DOUBLE ARRAY]\n");
    result = PYrunPythonExpressionAndExpectNoErrors(expr.buffer(), PY_Result::DOUBLE_ARRAY);
    if (result.myResultType != PY_Result::DOUBLE_ARRAY)
    {
        printf("Error: %s\n", result.myErrValue.buffer());
        return false;
    }

// convert result array to Houdini's Fields...

    return true;
}

Maybe this can help others who also want to use PhiFlow inside Houdini HDK context.

By the way, since Houdini HDK itself already contain a Python context, It seems that we can't directly use pybind to embed python inside c++ context. The reason maybe comes from the initializaiton of Python context, I've tried a lot to solve it but at last in vain). Finally, I found #include <PY/PY_Python.h>, this is so powerful~

holl- commented 1 month ago

Oh nice, that seems promissing!