⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 variablestepdoubleintegration.cpp

📁 用于求解二阶常微分方程的变步长多步积分法
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			}
			
			// get psi(n-1) and psi(n)
			for(int i=m_iLastIntpNums-1; i>-1; i--)
			{
				m_pPsiNm1[i] = (0==i) ? 0.0 : m_pPsiN[i-1];

				m_pPsiN[i] = m_pPsi[i];
			}

			if(m_iMaxIntpNums == m_iLastIntpNums)
			{			
				// no longer in variable-order mode
				// calculate step for next time
				double dSigma = 1.0;
				for(int i=1; i<m_iLastIntpNums+1; i++)
				{
					dSigma *= i*m_pAlpha[i-1];
				}

				double dSErk = fabs(m_dIntStep*m_pGammaStars[m_iLastIntpNums-1]*dSigma*m_pPhi[m_iLastIntpNums]);
				double dDErk = m_dIntStepSq*fabs(m_pLamdaStars[m_iLastIntpNums-1]*dSigma*m_pPhi[m_iLastIntpNums]);

				// calculate r for single and double integration
				double dSRho = pow(m_dEps/2.0/dSErk, 1.0/(m_iLastIntpNums+1));
				double dDRho = pow(m_dEps/2.0/dDErk, 1.0/(m_iLastIntpNums+2));

				// use smallest r
				m_dRho = __min(dSRho, dDRho);

				// bound r
				if(m_dRho > 2.0)
				{
					m_dRho = 2.0;
				}
				else if(m_dRho < 0.5)
				{
					m_dRho = 0.5;
				}						

				// already using maximum value of k, cycle this value into steps array.
				for(int i=0; i<m_iLastIntpNums-1; i++)
				{
					m_pIntStepArray[i] = m_pIntStepArray[i+1];
				}

				m_iIntpNums = m_iLastIntpNums;
			}
		}

		// change the step size
		m_dIntStep *= m_dRho;
		m_dIntStepSq = m_dIntStep*m_dIntStep;
		
		printf("The step size is :%f\n", m_dIntStep);

		m_pIntStepArray[m_iIntpNums-1] = m_dIntStep;

		// calculate alpha(n+1) and psi(n+1)		
		for(int i=0; i<m_iIntpNums; i++)
		{
			m_pPsi[i] = (0==i) ? m_dIntStep : m_pPsi[i-1]+m_pIntStepArray[m_iIntpNums-1-i];

			m_pAlpha[i] = (0==i) ? 1.0 : m_dIntStep/m_pPsi[i];
		}

		// compute ratio of current step size to last
		double dIntRatio = m_dIntStep / m_pIntStepArray[m_iIntpNums-2];
		double dInvIntRat = 1.0 / dIntRatio;

		// calculate integration coefficients
		for(int i=0; i<m_iIntpNums+1; i++)
		{
			for(int q=0; q<m_iIntpNums+2-i; q++)
			{
				if(0 == i)
				{
					m_pGCoeff[q*(m_iMaxIntpNums+1)+i] = 1.0/(q+1);
					m_pGpCoeff[q*(m_iMaxIntpNums+1)+i] = m_pGCoeff[q*(m_iMaxIntpNums+1)+i] * pow(-dInvIntRat, q+1);
				}
				else if(1 == i)
				{
					m_pGCoeff[q*(m_iMaxIntpNums+1)+i] = 1.0/(q+1)/(q+2);
					m_pGpCoeff[q*(m_iMaxIntpNums+1)+i] = m_pGCoeff[q*(m_iMaxIntpNums+1)+i] * pow(-dInvIntRat, q+2);
				}
				else
				{
					m_pGCoeff[q*(m_iMaxIntpNums+1)+i] = m_pGCoeff[q*(m_iMaxIntpNums+1)+i-1] - m_pAlpha[i-1]*m_pGCoeff[(q+1)*(m_iMaxIntpNums+1)+i-1];
					m_pGpCoeff[q*(m_iMaxIntpNums+1)+i] = m_pPsiNm1[i-2]/m_pPsi[i-1]*m_pGpCoeff[q*(m_iMaxIntpNums+1)+i-1] - m_pAlpha[i-1]*m_pGpCoeff[(q+1)*(m_iMaxIntpNums+1)+i-1];
				}
			}
		}

		// now integrate
		double dSum1, dSum2;
		for(int i=0; i<iEqNums; i++)
		{
			dSum1 = dSum2 = 0.0;
			for(int m=0; m<m_iIntpNums; m++)
			{
				// save differences before multiplying by beta
				m_pPhiNSave[i*m_iMaxIntpNums+m] = m_pPhiN[i*(m_iMaxIntpNums+1)+m];

				// calculate beta(n+1) and only once
				if(0 == i)
				{
					m_pBeta[m] = (0==m) ? 1.0 : m_pBeta[m-1]*m_pPsi[m-1]/m_pPsiN[m-1];
				}

				// calculate phi* = phi*beta
				m_pPhiN[i*(m_iMaxIntpNums+1)+m] *= m_pBeta[m];

				// calculate sums for integration
				dSum1 += m_pGCoeff[0*(m_iMaxIntpNums+1)+m]*m_pPhiN[i*(m_iMaxIntpNums+1)+m];
				dSum2 += (m_pGCoeff[1*(m_iMaxIntpNums+1)+m]+dIntRatio*m_pGpCoeff[1*(m_iMaxIntpNums+1)+m])*m_pPhiN[i*(m_iMaxIntpNums+1)+m];
			}

			// predict velocity and position
			pVel[i] = m_pLastVel[i] + m_dIntStep*dSum1;
			pPos[i] = (1.0+dIntRatio)*m_pLastPos[i] - dIntRatio*m_pPos2Back[i] + m_dIntStepSq*dSum2;
		}

		// update the time
		*pTime = m_dIntTime + m_dIntStep;

		// evaluate second order ODE equation
		_2ndODEs(iEqNums, *pTime, pPos, pVel, m_pAcc);

		// get new differences and error estimate
		m_dSTempErr = m_dDTempErr = 0.0;
		for(int i=0; i<iEqNums; i++)
		{
			// get new differences
			for(int m=0; m<m_iIntpNums+1; m++)
			{
				m_pPhi[i*(m_iMaxIntpNums+1)+m] = (0==m) ? m_pAcc[i] : m_pPhi[i*(m_iMaxIntpNums+1)+m-1]-m_pPhiN[i*(m_iMaxIntpNums+1)+m-1];
			}

			// get error estimate
			m_pSWeight[i] = fabs(m_pLastVel[i])*m_dRelEps + m_dAbsEps;
			m_pDWeight[i] = fabs(m_pLastPos[i])*m_dRelEps + m_dAbsEps;
			m_dSTempErr += (m_pPhi[i*(m_iMaxIntpNums+1)+m_iIntpNums]/m_pSWeight[i])*(m_pPhi[i*(m_iMaxIntpNums+1)+m_iIntpNums]/m_pSWeight[i]);
			m_dDTempErr += (m_pPhi[i*(m_iMaxIntpNums+1)+m_iIntpNums]/m_pDWeight[i])*(m_pPhi[i*(m_iMaxIntpNums+1)+m_iIntpNums]/m_pDWeight[i]);
		}

		m_dSTempErr = sqrt(m_dSTempErr);
		m_dDTempErr = sqrt(m_dDTempErr);

		m_dSErr = fabs(m_dIntStep*(m_pGCoeff[0*(m_iMaxIntpNums+1)+m_iIntpNums]-m_pGCoeff[0*(m_iMaxIntpNums+1)+m_iIntpNums-1])) * m_dSTempErr;
		m_dDErr = m_dIntStepSq*fabs(m_pGCoeff[1*(m_iMaxIntpNums+1)+m_iIntpNums]-m_pGCoeff[1*(m_iMaxIntpNums+1)+m_iIntpNums-1]+dIntRatio*(m_pGpCoeff[1*(m_iMaxIntpNums+1)+m_iIntpNums]-m_pGpCoeff[1*(m_iMaxIntpNums+1)+m_iIntpNums-1])) * m_dDTempErr;
		
		if(m_dSErr>m_dEps || m_dDErr>m_dEps)
		{
			// step failed
			// reset everything and use half this step next time
			m_iFail++;
			m_dRho = 0.5;

			for(int i=0; i<iEqNums; i++)
			{
				for(int m=0; m<m_iIntpNums; m++)
				{
					m_pPhiN[i*(m_iMaxIntpNums+1)+m] = m_pPhiNSave[i*(m_iMaxIntpNums)+m];
				}
			}

			// if 3rd failure, start over
			if(m_iFail >= 3)
			{
				//Init(dInitTime, dReqTime, dInitPos, dInitVel);
				printf("You are wrong!\n");

				return false;
			}

			continue;		
		}
		else
		{
			// step succeeded, reset fail count
			m_iFail = 0;

			// set last used value of k, in case an interpolation is needed now
			m_iLastIntpNums = m_iIntpNums++;
			m_dRho = 2.0;	
		}

		// correct velocity and position
		for(int i=0; i<iEqNums; i++)
		{
			pVel[i] += m_dIntStep*m_pGCoeff[0*(m_iMaxIntpNums+1)+m_iLastIntpNums]*m_pPhi[i*(m_iMaxIntpNums+1)+m_iLastIntpNums];
			pPos[i] += m_dIntStepSq*(m_pGCoeff[1*(m_iMaxIntpNums+1)+m_iLastIntpNums]+dIntRatio*m_pGpCoeff[1*(m_iMaxIntpNums+1)+m_iLastIntpNums])*m_pPhi[i*(m_iMaxIntpNums+1)+m_iLastIntpNums];
		}
		
		// the following "if" test is for stability, because algorithm is on the start-up mode
		if(m_iMaxIntpNums != m_iLastIntpNums)
		{
			// evaluate second order ODE equation
			_2ndODEs(iEqNums, *pTime, pPos, pVel, m_pAcc);

			// get new differences
			for(int i=0; i<iEqNums; i++)
			{
				for(int m=0; m<m_iLastIntpNums+1; m++) 
				{
					m_pPhi[i*(m_iMaxIntpNums+1)+m] = (0==m) ? m_pAcc[i] : m_pPhi[i*(m_iMaxIntpNums+1)+m-1]-m_pPhiN[i*(m_iMaxIntpNums+1)+m-1];
				}
			}
		}

		// get ready for next step, copy latest differences from m_pPhi to m_pPhiN,
		// and set integration state and time to current values.
		for(int i=0; i<iEqNums; i++)
		{
			for(int m=0; m<m_iLastIntpNums+1; m++)
			{
				m_pPhiN[i*(m_iMaxIntpNums+1)+m] = m_pPhi[i*(m_iMaxIntpNums+1)+m];
			}
			
			// set integration state to current values
			m_pIntVel[i] = pVel[i];
			m_pIntPos[i] = pPos[i];
		}		

		// set integration time		
		m_dIntTime = *pTime;

		fprintf_s(m_pStream, "%17.16f\t%17.16f\t%17.16f\n", m_dIntTime, m_pIntPos[0], sin(m_dIntTime)-m_pIntPos[0]);
	}
	// end of integration loop, check to see if interpolation is needed
	
	printf("The time is %f\n", m_dIntTime);

	// the following new function is for interpolation
	m_pGamma1 = new double[m_iMaxIntpNums];
	m_pGammaIntp = new double[m_iMaxIntpNums];

	m_pGIntpCoeff = new double[(m_iMaxIntpNums+2)*(m_iMaxIntpNums+1)];
	m_pGpIntpCoeff = new double[(m_iMaxIntpNums+2)*(m_iMaxIntpNums+1)];

	if(((m_dIntTime>m_dEndTime)&&(1==m_iIntDir)) || ((m_dIntTime<m_dEndTime)&&(-1==m_iIntDir)))
	{
		// integrated too far, interpolate to request time

		// set interpolation step
		m_dIntpStep = m_dEndTime - m_dIntTime;
		m_dIntpStepSq = m_dIntpStep*m_dIntpStep;

		double dIntpRatio = m_dIntpStep / m_pIntStepArray[m_iLastIntpNums-1]; // or dIntpRatio = m_dIntpStep / m_dIntStep
		double dInvIntpRat = 1.0 / dIntpRatio;

		// compute gamma values
		for(int i=0; i<m_iLastIntpNums; i++)
		{
			m_pGamma1[i] = (0==i) ? m_dIntpStep/m_pPsi[i] : (m_dIntpStep+m_pPsi[i-1])/m_pPsi[i];

			m_pGammaIntp[i] = (0==i) ? -1.0 : ((1==i) ? 0.0 : m_pPsiN[i-2]/m_pPsi[i]);
		}

		// calculate interpolation coefficients
		for(int i=0; i<m_iLastIntpNums+1; i++)
		{
			for(int q=0; q<m_iLastIntpNums+2-i; q++)
			{
				if(0 == i)
				{
					m_pGIntpCoeff[q*(m_iMaxIntpNums+1)+i] = 1.0/(q+1);
					m_pGpIntpCoeff[q*(m_iMaxIntpNums+1)+i] = m_pGIntpCoeff[q*(m_iMaxIntpNums+1)+i] * pow(-dInvIntpRat, q+1);
				}
				else
				{
					m_pGIntpCoeff[q*(m_iMaxIntpNums+1)+i] = m_pGamma1[i-1]*m_pGIntpCoeff[q*(m_iMaxIntpNums+1)+i-1] - m_dIntpStep/m_pPsi[i-1]*m_pGIntpCoeff[(q+1)*(m_iMaxIntpNums+1)+i-1];
					m_pGpIntpCoeff[q*(m_iMaxIntpNums+1)+i] = m_pGammaIntp[i-1]*m_pGpIntpCoeff[q*(m_iMaxIntpNums+1)+i-1] - m_dIntpStep/m_pPsi[i-1]*m_pGpIntpCoeff[(q+1)*(m_iMaxIntpNums+1)+i-1];
				}
			}
		}

		// compute interpolation values
		double dSum1, dSum2;
		for(int i=0; i<iEqNums; i++)
		{
			dSum1 = dSum2 = 0.0;
			for(int m=0; m<m_iLastIntpNums+1; m++)
			{
				dSum1 += m_pGIntpCoeff[0*(m_iMaxIntpNums+1)+m]*m_pPhi[i*(m_iMaxIntpNums+1)+m];
				dSum2 += (m_pGIntpCoeff[1*(m_iMaxIntpNums+1)+m]+dIntpRatio*m_pGpIntpCoeff[1*(m_iMaxIntpNums+1)+m])*m_pPhi[i*(m_iMaxIntpNums+1)+m];
			}

			pVel[i] = m_pIntVel[i] + m_dIntpStep*dSum1;
			pPos[i] = (1.0+dIntpRatio)*m_pIntPos[i] - dIntpRatio*m_pLastPos[i] + m_dIntpStepSq*dSum2;
		}
	} 
	// end of interpolation

	fprintf_s(m_pStream, "%17.16f\t%17.16f\t%17.16f\n", m_dEndTime, pPos[0], sin(m_dEndTime)-pPos[0]);

	return true;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -