openfoam学习心得——自定义6Dof库计算欧拉角并将其写入文件中

补充C++知识:
类的前向声明
友元类与函数
版本:of4.0
sixDoFRigidBodyDisplacementPointPatchVectorField边界条件

void mysixDoFRigidBodyDisplacementPointPatchVectorField::updateCoeffs()
{
	...............前面次要部分省略
    motion_.update
    (
        firstIter,
        ramp*(f.forceEff() + motion_.mass()*g_),
        ramp*(f.momentEff() + motion_.mass()*(motion_.momentArm() ^ g_)),
        t.deltaTValue(),
        t.deltaT0Value()
    );

    Field<vector>::operator=
    (
        motion_.transform(initialPoints_) - initialPoints_
    );

    fixedValuePointPatchField<vector>::updateCoeffs();
}

首先根据当前时刻的状态计算出力–然后调用 motion_.update方法根据力计算出下一个时刻的加速度、速度、角动量、旋转中心位置、旋转矩阵update方法如下所示:

void Foam::sixDoFRigidBodyMotion::update
(
    bool firstIter,
    const vector& fGlobal,
    const vector& tauGlobal,
    scalar deltaT,
    scalar deltaT0
)
{
    if (Pstream::master())
    {
        solver_->solve(firstIter, fGlobal, tauGlobal, deltaT, deltaT0);

        if (report_)
        {
            status();
        }
    }

    Pstream::scatter(motionState_);
}

void Foam::sixDoFRigidBodyMotion::status() const
{
    Info<< "6-DoF rigid body motion" << nl
        << "    Centre of rotation: " << centreOfRotation() << nl
        << "    Centre of mass: " << centreOfMass() << nl
        << "    Orientation: " << orientation() << nl
        << "    Linear velocity: " << v() << nl
        << "    Angular velocity: " << omega()
        << endl;
}

update方法中调用了solver函数,RTS机制来选择solver所使用的方法,下面是Newmark方法中的solver函数,可以看到,其主要作用就是更新状态量。我们要求解欧拉角,并将其储存在文件中,需要拓展的接口是status

void Foam::sixDoFSolvers::Newmark::solve
(
    bool firstIter,
    const vector& fGlobal,
    const vector& tauGlobal,
    scalar deltaT,
    scalar deltaT0
)
{
    // Update the linear acceleration and torque
    updateAcceleration(fGlobal, tauGlobal);

    // Correct linear velocity
    v() =
        tConstraints()
      & (v0() + aDamp()*deltaT*(gamma_*a() + (1 - gamma_)*a0()));

    // Correct angular momentum
    pi() =
        rConstraints()
      & (pi0() + aDamp()*deltaT*(gamma_*tau() + (1 - gamma_)*tau0()));

    // Correct position
    centreOfRotation() =
        centreOfRotation0()
      + (
            tConstraints()
          & (
                deltaT*v0()
              + aDamp()*sqr(deltaT)*(beta_*a() + (0.5 - beta_)*a0())
            )
        );

    // Correct orientation
    vector piDeltaT =
        rConstraints()
      & (
            deltaT*pi0()
          + aDamp()*sqr(deltaT)*(beta_*tau() + (0.5 - beta_)*tau0())
        );
    Tuple2<tensor, vector> Qpi = rotate(Q0(), piDeltaT, 1);
    Q() = Qpi.first();
}

利用四元素类从旋转矩阵中计算欧拉角:

 //- Construct a quaternion from a rotation tensor
 inline explicit quaternion(const tensor& rotationTensor);
 使用到的成员函数如下:
 //- Return a vector of euler angles corresponding to the
//  specified rotation sequence
 inline vector eulerAngles(const rotationSequence rs) const;
 类中的枚举类
 enum rotationSequence
    {
        ZYX, ZYZ, ZXY, ZXZ, YXZ, YXY, YZX, YZY, XYZ, XYX, XZY, XZX
    };

inline Foam::vector Foam::quaternion::eulerAngles
(
    const rotationSequence rs
) const
{
    const scalar w2 = sqr(w());
    const scalar x2 = sqr(v().x());
    const scalar y2 = sqr(v().y());
    const scalar z2 = sqr(v().z());

    switch(rs)
    {
        case ZYX:
            return threeAxes
            (
                2*(v().x()*v().y() + w()*v().z()),
                w2 + x2 - y2 - z2,
                2*(w()*v().y() - v().x()*v().z()),
                2*(v().y()*v().z() + w()*v().x()),
                w2 - x2 - y2 + z2
            );
            break;

        case ZYZ:
            return twoAxes
            (
                2*(v().y()*v().z() - w()*v().x()),
                2*(v().x()*v().z() + w()*v().y()),
                w2 - x2 - y2 + z2,
                2*(v().y()*v().z() + w()*v().x()),
                2*(w()*v().y() - v().x()*v().z())
            );
            break;

        case ZXY:
            return threeAxes
            (
                2*(w()*v().z() - v().x()*v().y()),
                w2 - x2 + y2 - z2,
                2*(v().y()*v().z() + w()*v().x()),
                2*(w()*v().y() - v().x()*v().z()),
                w2 - x2 - y2 + z2
            );
            break;

        case ZXZ:
            return twoAxes
            (
                2*(v().x()*v().z() + w()*v().y()),
                2*(w()*v().x() - v().y()*v().z()),
                w2 - x2 - y2 + z2,
                2*(v().x()*v().z() - w()*v().y()),
                2*(v().y()*v().z() + w()*v().x())
            );
            break;

        case YXZ:
            return threeAxes
            (
                2*(v().x()*v().z() + w()*v().y()),
                w2 - x2 - y2 + z2,
                2*(w()*v().x() - v().y()*v().z()),
                2*(v().x()*v().y() + w()*v().z()),
                w2 - x2 + y2 - z2
            );
            break;

        case YXY:
            return twoAxes
            (
                2*(v().x()*v().y() - w()*v().z()),
                2*(v().y()*v().z() + w()*v().x()),
                w2 - x2 + y2 - z2,
                2*(v().x()*v().y() + w()*v().z()),
                2*(w()*v().x() - v().y()*v().z())
            );
            break;

        case YZX:
            return threeAxes
            (
                2*(w()*v().y() - v().x()*v().z()),
                w2 + x2 - y2 - z2,
                2*(v().x()*v().y() + w()*v().z()),
                2*(w()*v().x() - v().y()*v().z()),
                w2 - x2 + y2 - z2
            );
            break;

        case YZY:
            return twoAxes
            (
                2*(v().y()*v().z() + w()*v().x()),
                2*(w()*v().z() - v().x()*v().y()),
                w2 - x2 + y2 - z2,
                2*(v().y()*v().z() - w()*v().x()),
                2*(v().x()*v().y() + w()*v().z())
            );
            break;

        case XYZ:
            return threeAxes
            (
                2*(w()*v().x() - v().y()*v().z()),
                w2 - x2 - y2 + z2,
                2*(v().x()*v().z() + w()*v().y()),
                2*(w()*v().z() - v().x()*v().y()),
                w2 + x2 - y2 - z2
            );
            break;

        case XYX:
            return twoAxes
            (
                2*(v().x()*v().y() + w()*v().z()),
                2*(w()*v().y() - v().x()*v().z()),
                w2 + x2 - y2 - z2,
                2*(v().x()*v().y() - w()*v().z()),
                2*(v().x()*v().z() + w()*v().y())
            );
            break;

        case XZY:
            return threeAxes
            (
                2*(v().y()*v().z() + w()*v().x()),
                w2 - x2 + y2 - z2,
                2*(w()*v().z() - v().x()*v().y()),
                2*(v().x()*v().z() + w()*v().y()),
                w2 + x2 - y2 - z2
            );
            break;

        case XZX:
            return twoAxes
            (
                2*(v().x()*v().z() - w()*v().y()),
                2*(v().x()*v().y() + w()*v().z()),
                w2 + x2 - y2 - z2,
                2*(v().x()*v().z() + w()*v().y()),
                2*(w()*v().z() - v().x()*v().y())
            );
            break;
        default:
            FatalErrorInFunction
                << "Unknown rotation sequence " << rs << abort(FatalError);
            return Zero;
            break;
    }
}

可以看到,要计算欧拉角,首先要指定旋转顺序,固计算欧拉角要添加这三行:函数形参为类quaternion中的枚举类rotationSequence对象

  quaternion b = quaternion(orientation());
  quaternion::rotationSequence aa=quaternion::rotationSequence (0);
  vector ang = b.eulerAngles(aa);

接下来最后一步,定义文件的输出流,将欧拉角保存以追加的形式保存在文件中,openfoam有相关的类库,为了减少学习成本,笔者直接用C++的标准库来实现这个功能:

std::ofstream fout("Euler.txt",ios_base::out | ios_base::app);
fout << ang.x()<< " " << ang.y() << " "<<ang.z() <<'\n';
fout.close();

至此,这一功能便实现了,6Dof库的开发并不困难,首先是自定义边界条件,然后再更改边界条件中使用到的其他类的相应接口便可。

你可能感兴趣的:(openfoam学习心得——自定义6Dof库计算欧拉角并将其写入文件中)