简体   繁体   English

触发根 function 时更改 R 的 deSolve 中的参数值

[英]Changing value of parameters in R's deSolve when root function is triggered

Short version简洁版本

As suggested in comments, I am leaving a summarized, short version of the problem I found here.正如评论中所建议的那样,我留下了我在这里发现的问题的简短版本。 The original complete explanation can be found below.原始的完整解释可以在下面找到。

In summary, I am currently using the deSolve package and am interested in implementing events in response to root functions.总而言之,我目前正在使用 deSolve package 并且有兴趣实现响应根函数的事件。 I understand that I can use such events to introduce sudden changes in the state variables of the model, but I would like to also modify parameter values of the model in response to such root functions.我知道我可以使用此类事件来引入 model 的 state 变量的突然变化,但我还想修改 model 的参数值以响应此类根函数。

Is this possible?这可能吗?

Long version长版

I have implemented an orbital numerical propagator (a function to calculate the position of a space satellite given an initial position and velocity state) in R. The problem is formulated as a set of 6 ODEs (X, Y and Z components for position and velocity).我已经在 R 中实现了一个轨道数值传播器(一个 function 来计算给定初始 position 和速度状态的太空卫星的 position)。该问题被表述为一组 6 个常微分方程(position 和速度的 X、Y 和 Z 分量) ). My implemented models calculate the acceleration at any given time, and then I use the deSolve package to perform integration and calculate the trajectory.我实施的模型在任何给定时间计算加速度,然后我使用 deSolve package 执行积分并计算轨迹。

A key parameter that must be decided when performing such calculation is the center of the frame of reference, which is usually placed at the center of mass of the celestial object that exerts the most significant gravitational influence on the satellite.进行此类计算时必须确定的一个关键参数是参考系的中心,参考系的中心通常位于对卫星产生最显着引力影响的天体 object 的质心。 This is because, even though in principle it is possible to perform integration and calculate the trajectory using any arbitrary frame of reference, in practice we only obtain reasonable results when the center of coordinates is placed on the celestial object that exerts the main gravitational influence (ie, Earth for Earth-orbiting satellites, Moon for Moon-orbiting satellites, and so on), as discussed in this SE question .这是因为,尽管原则上可以使用任意参考系进行积分和计算轨迹,但实际上我们只有在坐标中心位于施加主要引力影响的天体 object 上时才能获得合理的结果(即地球轨道卫星的地球,月球轨道卫星的月球等等),如本 SE 问题中所讨论的

Initially, my implementation used a constant center of coordinates, either provided by the user or automatically determined from the sphere of influence of the different main celestial objects.最初,我的实现使用了一个恒定的坐标中心,由用户提供或根据不同主要天体的影响范围自动确定。

However, this is not appropriate for modeling interpl.netary space missions, since the celestial object that exerts the main gravitational influence changes during the trajectory.然而,这不适合为国际空间任务建模,因为在轨道期间施加主要引力影响的天体 object 会发生变化。 A good example is the Apollo missions, where satellites started in an Earth orbit, and then moved to a Moon orbit.一个很好的例子是阿波罗任务,卫星从地球轨道开始,然后移动到月球轨道。

I have managed to detect when such changes of the central celestial object happen, and return it as part of the results of the integrator.我设法检测到中央天体 object 的这种变化何时发生,并将其作为积分器结果的一部分返回。 However, in order to actually perform the correct modeling, the central body being used during integration needs to be changed when these changes are detected.然而,为了实际执行正确的建模,在检测到这些变化时需要更改集成期间使用的中心体。 This process of "changing the central body" involves two tasks (note that it is just a shift of the center of coordinates, with no rotations involved):这个“换中心体”的过程涉及两个任务(注意只是坐标中心的移动,不涉及旋转):

  1. Subtracting the coordinates of the celestial body to be used as the new center of coordinates from the coordinates of the satellite (by doing so, the coordinates of the satellite are now referred to the new celestial body).从卫星坐标中减去要作为新坐标中心的天体坐标(这样,卫星坐标即为新天体坐标)。
  2. Modifying the value of the argument specifying the central celestial body that is passed to the function calculating acceleration, which is one of the elements of the list of parameters provided to the function defining the ODE model.修改传递给 function 计算加速度的指定中央天体的参数值,这是提供给 function 定义 ODE model 的参数列表的元素之一。

I believe Task 1 can be easily solved by using a root-activated event.我相信任务 1 可以通过使用根激活事件轻松解决。 In order to do so, I define a variable in an environment specifically created for this purpose that stores the value of the automatically calculated celestial body that exerts the main gravitational influence in each iteration of the integrator.为此,我在为此目的专门创建的环境中定义了一个变量,用于存储自动计算的天体的值,该天体在积分器的每次迭代中发挥主要的引力影响。 At a new iteration, a new value is calculated, and is compared with the previous value.在新的迭代中,将计算一个新值,并将其与先前的值进行比较。 If it is the same, nothing happens.如果相同,则什么也不会发生。 But if it is different, a root function would return 0, triggering an event function. The event function would then return the position minus the coordinates of the new central celestial body.但如果不同,根function会返回0,触发事件function。然后事件function会返回position减去新的中央天体的坐标。

However, I am unsure about how to perform Task 2, since this would involve changing one of the initial parameters provided to the ODE model. Any ideas on this would be greatly appreciated, (either a continuation of my approach. or a completely different one).但是,我不确定如何执行任务 2,因为这将涉及更改提供给 ODE model 的初始参数之一。对此的任何想法将不胜感激,(我的方法的延续。或完全不同的方法) ).

I am leaving a simplified version of the involved code.我将留下所涉及代码的简化版本。

My main function is called hpop , and is the user-level function to which the initial state vector and other parameters are passed.我的主要 function 称为hpop ,是用户级 function ,初始 state 向量和其他参数传递给它。 It looks like this:它看起来像这样:

hpop <- function(position, velocity, dateTime, times, satelliteMass, dragArea, 
                 radiationArea, dragCoefficient, radiationCoefficient, 
                 earthSphericalHarmonicsDegree = 130, solidEarthTides=TRUE,
                 oceanTides=TRUE, moonSphericalHarmonicsDegree = 150, 
                 centralBody="Earth", ...) {
    extraArgs <- list(...)
    ## This is the environment used to hold the variable that keeps track of what
    ## the central body should be at each iteration
    propagationGlobalVars <- new.env()
    ## This is the initial value of such variable, which is the user-provided central body, by default Earth
    propagationGlobalVars$latestCentralBody <- centralBody
    ## This is the initial state, composed by 6 variables (X, Y and Z components of position and velocity)
    initial_state <- c(position, velocity)
    ## This is the list of parameters required for trajectory calculation
    ## There is quite a few, but the 2 most relevant for this question are the last 2
    ## centralBody is the body that will be used as the center of coordinates, and
    ## globalVarsEnv is the environment that will be containing the variable that keeps track of what the central body should be
    parameters = list(
        dateTime = dateTime,
        solarArea = radiationArea,
        satelliteMass = satelliteMass,
        satelliteArea = dragArea,
        Cr = radiationCoefficient,
        Cd = dragCoefficient,
        earthSPHDegree = earthSphericalHarmonicsDegree,
        moonSPHDegree = moonSphericalHarmonicsDegree,
        SETcorrections = solidEarthTides,
        OTcorrections = oceanTides,
        centralBody = centralBody,
        globalVarsEnv = propagationGlobalVars)
    ## This calles function ode from the deSolve package, passing the previously defined initial state, 
    ## integration times and the function defining the ode model (code below)
    integration_results <- ode(y=initial_state, times=times, func=odeModel,
                               parms=parameters, method="radau", rtol=1e-13,
                               atol=1e-16, hini=0.01, ...)
    numeric_results <- integration_results[, 1:7]
    central_bodies <- names(centralBodiesNum[integration_results[, 8]])
    output <- cbind(as.data.frame(numeric_results), central_bodies)
    colnames(output) <- c("time", "X", "Y", "Z", "dX", "dY", "dZ", "Central body")
    return(output)
}

A simplified version of the code for the ODE model, called odeModel and which I pass as the func argument to function ode from the deSolve package, is: ODE model 代码的简化版本称为odeModel ,我将其作为func参数传递给 deSolve package 中的 function ode ,它是:

odeModel <- function(t, state, parameters) {
    with(as.list(c(state, parameters)), {
        state_vector <- state
        ## Function accel calculates the acceleration and velocity at time t. It returns a list with
        ## two elements. The first is a numeric vector with the X, Y and Z components of velocity,
        ## and the X, Y and Z components of acceleration, in this order. 
        ## The second element is the celestial body that, given the position at that iteration,
        ## exerts the main gravitational influence on the satellite
        results <- accel(t, state_vector, dateTime, solarArea, satelliteMass, 
                              satelliteArea, Cr, Cd, earthSPHDegree, SETcorrections,
                              OTcorrections, moonSPHDegree, centralBody)
        centralBody <- results[[2]]
        ## Now we can compare the central body with that of the previous iteration,
        ## and assign the new value to the tracking variable
        if(centralBody != globalVarsEnv$latestCentralBody) {
            message(strwrap(paste("A transition from the sphere of influence of ",
                                  globalVarsEnv$latestCentralBody, " to that of ",
                                  centralBody, " has been detected.", sep=""), initial="", prefix="\n"))
            assign("latestCentralBody", centralBody, envir = globalVarsEnv)
        ## here I would also trigger the root function, to perform Task 1 of the two 
        ## tasks required to change the central body as described above. And also,
        ## I would need a way to change the value of centralBody in the parameters argument, which is the main issue of this question
        }
        acceleration <- results[[1]]
        dx <- acceleration[1, 1]
        dy <- acceleration[1, 2]
        dz <- acceleration[1, 3]
        d2x <- acceleration[2, 1]
        d2y <- acceleration[2, 2]
        d2z <- acceleration[2, 3]
        ## This is the return value of the odeModel function. As specified in the
        ## documentation for the func argument of the ode function, the first element
        ## of the list are the values of the derivatives of the model, and the
        ## second one can be any other variable. Note that since such other variables
        ## must be numeric, I actually access a named vector of numbers, and then convert
        ## back to the proper names when outputting final results to the users.
        ## It is important to provide the central body of each output step so that
        ## we know what the center of coordinates are at each step
        list(c(dx, dy, dz, d2x, d2y, d2z),
             centralBodiesNum[centralBody])
    })
}

To change a parameter depending on a root function, one can use an additional state variable ( y3 below) that has a derivative zero in the model function and can only be changed by an event.要根据根 function 更改参数,可以使用额外的 state 变量(下面的y3 ),该变量在 model function 中具有导数零,并且只能通过事件更改。 Modifying the bouncing ball example from a tutorial example ( Example3 ) we get:修改教程示例 ( Example3 ) 中的弹跳球示例,我们得到:

library(deSolve)
ball <- function(t, y, p) {
  dy1 <- y[2]
  dy2 <- y[3]
  dy3 <- 0  # emulates a parameter, derivative = 0 but can be changed by event
  list(c(dy1, dy2, dy3))
}

## gravity is essentially a parameter
yini <- c(height = 0, velocity = 10, gravity = -9.8)

rootfunc <- function(t, y, p){
  return (y[1])
}

eventfunc <- function(t, y, p) {
  y[1] <- 0
  y[2] <- -0.9 * y[2]
  y[3] <-  0.5 * y[3] # 0.5 just for technical demonstration
  return(y)
}

times <- seq(from = 0, to = 20, by = 0.01)

out <- ode(times = times, y = yini, func = ball,
           parms = NULL, rootfun = rootfunc,
           events = list(func = eventfunc, root = TRUE))

plot(out)

This works of course also for more than one parameter.这当然也适用于不止一个参数。 It can also be extended with forcings or lookup tables.它还可以使用强制或查找表进行扩展。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM