detproton中的通过能量和计算射程、临界角的计算、判断径迹形成、判断径迹蚀刻起始点、蚀刻液穿透...

Créé le : 18 août 2025

Répondu en utilisant GPT-4o par Chat01

Question

DetProton.f90
TRACK_COORDINATES .txt
ProtonTrackSimulator - Copy (2).txt
c++ modified1 track_coordinates.txt

detproton中的通过能量和计算射程、临界角的计算、判断径迹形成、判断径迹蚀刻起始点、蚀刻液穿透距离、生成径迹壁坐标点、旋转坐标我已经转完c++,也可以顺利输出。

问题:蚀刻液穿透距离以前与Fortran文件的结果都是可以对的上的。但是现在到了生成坐标这一部分,输出文件如两个txt文件,有几个小数点的误差。

需求:这是两个核心转坐标的源代码文件。其中调用的子函数都已经验证完毕,都是对的上的。请帮我从逻辑上、细节上分析我转换的c++代码是哪里出现了问题,导致生成的坐标对不上。并给出几个解决方案

Réponse

根据你提供的 Fortran 文件 (DetProton.f90)、C++ 源码 (ProtonTrackSimulator) 和两个输出轨迹坐标 .txt 文件的差异分析,我们可以总结如下几个关键点,帮助你定位 C++ 实现中引起小数点误差的可能性问题


🔍 问题分析方向

1. 旋转和平移坐标的数值稳定性误差

rotateAndTranslatePoints() 函数中:

cpp
double x_rot = p.x * cos(rotationAngle) + p.y * sin(rotationAngle); double y_rot = -p.x * sin(rotationAngle) + p.y * cos(rotationAngle);

这些三角函数在 PI - theta 的角度下精度损失容易出现,尤其在 theta 接近 0π 时,cossin 值变化缓慢,极易积累误差,导致坐标对不上。

2. std::sin()asin() 的精度误差

generateTrackPoints() 中:

cpp
double delta = std::asin(1.0 / vt_over_vb); ... p.x = x + overetchedThickness * std::sin(delta); p.y = overetchedThickness * std::cos(delta);

由于 vt_over_vb 接近 1.0 或更大,asin 在小角度时变化迅速,误差容易被放大。Fortran 默认使用高精度浮点运算 (REAL*8) ,C++ 中 double 的精度可能略有损失。

3. 积分函数 dint3() 精度不一致

虽然你说 dint3 已验证无误,但如果 C++ 实现采用了不同的步长或积分方法(如 Simpson vs Trapezoid),导致时间差从而进一步影响坐标。

建议确认:

  • Fortran 使用了多少步积分?多少精度?
  • dint3() 在 C++ 的内部是否和 Fortran 实现使用相同积分策略?尤其是对 VT(y) 的调用是否一致。

4. 步长与取整问题

在轨迹点生成中:

cpp
int NSTEPT = static_cast<int>(RASTD / AINTERVAL) + 1; double step = RASTD / (NSTEPT - 1);

这看起来合理,但如果 Fortran 是按固定间隔截断,C++ 是取浮点除法再取整,极易在后续 x 的累加中产生逐步误差积累。


🛠️ 建议的修复和验证方法

✅ 方法一:使用高精度浮点类型

  • 使用 long double 替代 double 尤其在 delta, sin(delta), cos(delta) 以及 rotateAndTranslatePoints() 的三角函数上。
  • 尽可能使用 std::sinl() / std::cosl() / std::asinl()

✅ 方法二:输出关键中间变量对比 Fortran

打印如下变量并和 Fortran 对比:

  • VT(y) 的每一个值
  • delta
  • overetchedThickness
  • x, y 坐标的最终计算值

可逐行比对,定位误差源。

✅ 方法三:同步坐标旋转方式

Fortran 中旋转可能是绕 底部或中心点旋转,而你的 C++ 中:

cpp
double trackCenter = (x_min + x_max) / 2.0; double y_base = points[0].y;

是否与 Fortran 的基准坐标一致?建议打印原始旋转前的坐标 + 平移后结果,与 Fortran 完整对比。

✅ 方法四:确认 VT() 函数公式是否精确无差

虽然形式一致,但检查:

  • C++ 是否使用 exp() 而 Fortran 用了 DEXP()(双精度)
  • 可能的截断或系数误差,例如 a2 = 7.3736e-3a5 = 1.4120 有无精度影响

🧪 测试建议

  • 取一组典型参数(如能量 = 2MeV, θ = 45°),比较 Fortran vs C++ 各阶段输出(尤其是 rotate 前的坐标)
  • 打印输出中保留至少 10 位有效数字,便于分析
  • 验证两个关键文本输出文件中前 10 个点的误差是否线性放大或常量偏移(对应步长或旋转精度问题)

✅ 总结

问题来源描述建议修复
三角函数精度asin, sin, cos 可能在小角度误差大使用 long doubleasinl/sinl
坐标旋转精度旋转角精度和旋转基准不同确保基准点与 Fortran 一致
穿透厚度计算dint3()积分误差可能影响时间输出中间蚀刻时间 vs 穿透厚度
轨迹点步长差异C++步长可能取整方式不同用与 Fortran 相同逻辑生成 x

如你需要我对比 Fortran 文件的坐标生成部分,或调试具体函数结构,也可以上传该段代码,我能更精确指出每一行差异是否对应。是否要我深入比对 Fortran 源码坐标生成部分?

Partager cette Q&R