Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【快乐开源】为 PaddleScience 添加 SDF 计算函数 #376

Closed
HydrogenSulfate opened this issue Jun 16, 2023 · 2 comments
Closed

【快乐开源】为 PaddleScience 添加 SDF 计算函数 #376

HydrogenSulfate opened this issue Jun 16, 2023 · 2 comments
Assignees

Comments

@HydrogenSulfate
Copy link
Collaborator

HydrogenSulfate commented Jun 16, 2023

This project will be mentored by @HydrogenSulfate

1. 背景

坐标点是科学计算问题求解时常用的输入数据对象,这些坐标点从指定的几何计算域中采样得到。从训练优化的角度来看,给所有样本点(坐标点)设置一样的权重并不是一个最优的方法,因此在一些优化 trick 中会将每个点的 SDF(signed distance function) 值作为其权重,以此来加强难样本(靠近计算域中心)的权重,减少简单样本(靠近计算域边界)的权重,最终进一步提升模型训练的精度。

PaddleScience 目前的几何模块由简单几何和复杂几何组成,复杂几何由 ppsci.geometry.Mesh 类来表示,并基于 pymesh 库进行 SDF 值的计算;而简单几何(如 ppsci.geometry.Disk)还未具备 SDF 计算功能,因此我们希望给所有的简单几何类,添加 SDF 计算功能。

Tips: SDF 函数一般用于计算一个点(多个点同理)到某一个几何边界的最短(欧式)距离(内部为负,外部为正),而在科学计算套件中,这些计算点通常来自几何内部,因此根据 SDF 的定义,其值往往是负数。如 $[l, r]$ 的一维线段内部一个点 $x$ 的 sdf 函数就是

$$ sdf(x)=-min(x-\rm l,\rm r-x)=-(\dfrac{r-l}{2}-\vert{x-\dfrac{l+r}{2}}\vert) $$

2. 收益 (整体进度:7/7)

使得简单几何具备 SDF 加权功能,从功能上与复杂几何更为统一,提升基于简单几何的案例优化空间,熟悉 PaddleScience 套件

按 merge 的时间顺序,排名不分先后: @Liyulingyue (2), @AndPuQing (2), @jjyaoao (1), @jiamingkong (1) @mrcangye (1)

序号 几何类 认领人 PR号
1 Interval✅(2023/6/20)  @jiamingkong  #403
2 Disk✅(2023/6/17) @jjyaoao    #391
3 Polygon✅(2023/6/27) @mrcangye     #376
4 Rectangle✅(2023/6/17) @AndPuQing  #387
5 Triangle✅(2023/6/17) @AndPuQing  #387
6 Cuboid✅(2023/6/17) @Liyulingyue  #384
7 Sphere✅(2023/6/17) @Liyulingyue  #386

3. 开发流程

3.1 安装 PaddleScience

下载安装 PaddleScience 套件:https://paddlescience-docs.readthedocs.io/zh/latest/zh/install_setup/#121-git

3.2 代码开发

以为 ppsci.geometry.Disk 模块添加 SDF 函数为例

class Disk(geometry.Geometry):
    ...
    ...

    def sdf_func(self, points: np.ndarray) -> np.ndarray:
        """Compute signed distance field.

        Args:
            points (np.ndarray): The coordinate points used to calculate the SDF value,
                the shape is [N, 2]

        Returns:
            np.ndarray: Unsquared SDF values of input points, the shape is [N, 1].

        NOTE: This function usually returns ndarray with negative values, because
        according to the definition of SDF, the SDF value of the coordinate point inside
        the object(interior points) is negative, the outside is positive, and the edge
        is 0. Therefore, when used for weighting, a negative sign is often added before
        the result of this function.
        """
        # 在此处编写代码,为传入的 points,计算对应的 sdf_value 并返回
        return sdf_value

还需修改一下:ppsci/geometry/geometry.py 的代码,

def sample_interior(self, n, random="pseudo", criteria=None, evenly=False):
    """Sample random points in the geometry and return those meet criteria."""
    x = np.empty(shape=(n, self.ndim), dtype=paddle.get_default_dtype())
    _size, _ntry, _nsuc = 0, 0, 0
    while _size < n:
        if evenly:
            points = self.uniform_points(n)
        else:
            if misc.typename(self) == "TimeXGeometry":
                points = self.random_points(n, random, criteria)
            else:
                points = self.random_points(n, random)

        if criteria is not None:
            criteria_mask = criteria(*np.split(points, self.ndim, axis=1)).flatten()
            points = points[criteria_mask]

        if len(points) > n - _size:
            points = points[: n - _size]
        x[_size : _size + len(points)] = points

        _size += len(points)
        _ntry += 1
        if len(points) > 0:
            _nsuc += 1

        if _ntry >= 1000 and _nsuc == 0:
            raise ValueError(
                "Sample interior points failed, "
                "please check correctness of geometry and given creteria."
            )
    # 以下为新增代码:内部点 x 采样完之后计算其 sdf 值,并和 x 一起转换为字典返回
    if hasattr(self, 'sdf_func'):
        sdf = -self.sdf_func(x)
        sdf_dict = misc.convert_to_dict(sdf, ("sdf", ))
        x_dict = misc.convert_to_dict(x, self.dim_keys)
        return {**x_dict, **sdf_dict}
    else:
        return misc.convert_to_dict(x, self.dim_keys)

3.4 SDF 可视化验证

在编写完 SDF 代码之后,我们需要对 SDF 计算结果进行验证,可以按照以下代码手动实例化一个几何对象,然后在其内部进行采样,再调用 sdf_func 对内部采样点计算其 sdf 值,最后用 ppsci 的可视化接口保存为 vtu 文件。用 ParaView 软件打开查看。vtu 文件生成的示例代码如下:

import ppsci
from ppsci.utils import logger
from ppsci import visualize

logger.init_logger()

geo = ppsci.geometry.实现了sdf_func的几何类(...)
points_dict = geo.sample_interior(n=10000) # 可视化10000个点
visualize.vtu.save_vtu_from_dict("./visualize_sdf.vtu", points_dict, geo.dim_keys, ("sdf", ))

3.5 整理代码并提交PR

参考 PaddleScience文档-贡献指南-整理代码并提交

4. 参考资料

@mrcangye
Copy link
Contributor

认领3

@luotao1
Copy link
Collaborator

luotao1 commented Jun 27, 2023

为 PaddleScience 添加 SDF 计算函数 已全部完成,感谢参与的小伙伴们!

@Liyulingyue (2), @AndPuQing (2), @jjyaoao (1), @jiamingkong (1) @mrcangye (1)

欢迎继续参与 科学计算快乐开源的其他任务!

@luotao1 luotao1 closed this as completed Jun 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

No branches or pull requests

3 participants