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

OCP curves from data #600

Closed
brosaplanella opened this issue Aug 20, 2019 · 10 comments
Closed

OCP curves from data #600

brosaplanella opened this issue Aug 20, 2019 · 10 comments
Assignees

Comments

@brosaplanella
Copy link
Sponsor Member

Summary
It would be useful to define a function within PyBaMM that, given a data file, produces the interpolating function and also its Jacobian within autograd. That would be useful for OCPs, but shouldn't limit to that as some other parameter function might be provided as a dataset of experimental measurements (e.g. the entropic change).

I have already the code that produces this in the main script, but I think it would be a good idea to have it as a PyBaMM function that deals with it behind the scenes.

Motivation
In many cases, the parameter functions come from experimental data so interpolation is a straightforward way to include them in the simulations.

Additional context
The code in my main script looks like

data_cathode = pd.read_csv("my_data.csv")

interpolated_OCV_cathode = interpolate.CubicSpline(
    data_cathode.to_numpy()[:,0], 
    data_cathode.to_numpy()[:,1], 
    extrapolate=True
)

dOCV_cathode = interpolated_OCV_cathode.derivative()

@primitive
def OCV_cathode(sto):
    out = interpolated_OCV_cathode(sto)
    if np.size(out) == 1:
        out = np.array([out])[0]
    return out

def OCV_cathode_vjp(ans,sto):
    sto_shape = sto.shape
    return lambda g: np.full(sto_shape, g) * dOCV_cathode(sto)

defvjp(OCV_cathode, OCV_cathode_vjp)
@valentinsulzer
Copy link
Member

Nice! Yeah this would be useful to have as core functionality. I guess something similar to the GetConstantCurrent function.
Btw, I think pchip is slightly better than spline as it preserves shape (matlab example). It looks like you can still take the derivative.

@brosaplanella
Copy link
Sponsor Member Author

Yes, PChip would be better. What I don't see is in which folder this function would be defined. GetConstantCurrent seems to be very specific for the current and I guess this one should be more generic.

@valentinsulzer
Copy link
Member

This should be just like the other functions in input/parameters/lithium-ion, except it should be a class with a __call__ method instead of a function. You'll need to give the class the same name as the file so that pybamm.load_function can find it.

@TomTranter
Copy link
Contributor

Hi guys, I would also like to make use of this function. Is there any chance you can push this to master? I understand it may be part of a bigger development project you are working on but would really help

@brosaplanella
Copy link
Sponsor Member Author

Hi Tom. The only progress I have done on that is including the interpolating functions in the main script and calling them from there, but it is not integrated into PyBaMM. Not sure if @tinosulzer has done anything on it. If you want to add it to the main script you only need to add this lines to the code

data_cathode = pd.read_csv(
    pybamm.root_dir() + "/input/parameters/lithium-ion/nmc_LGM50_ocp_CC3.csv"
)

interpolated_OCP_cathode = interpolate.CubicSpline(
    data_cathode.to_numpy()[:, 0],
    data_cathode.to_numpy()[:, 1],
    extrapolate=True
)

dOCP_cathode = interpolated_OCP_cathode.derivative()

@primitive
def OCP_cathode(sto):
    out = interpolated_OCP_cathode(sto)
    if np.size(out) == 1:
        out = np.array([out])[0]
    return out

def OCP_cathode_vjp(ans, sto):
    sto_shape = sto.shape
    return lambda g: np.full(sto_shape, g) * dOCP_cathode(sto)

defvjp(OCP_cathode, OCP_cathode_vjp)

There is some fudging with the formatting that could be possibly improved. The command @primitive tells autograd not to calculate the Jacobian of what comes after (as it would crash) and later, the Jacobian is defined manually using defvjp.

@TomTranter
Copy link
Contributor

So how do you just update the OCV parameter to point to new function. It would be a good utility function to be able to do this more generically for any interpolation from a dataset

@brosaplanella
Copy link
Sponsor Member Author

You just update the parameters like this:

param.update({
    "Positive electrode OCV": OCP_cathode,
})

It would be good to have it in a more general form, so it could be assigned just doing

param.update({
    "Positive electrode OCV": interpolation_1D("some_cathode_OCV_data.csv"),
})

where interpolation_1D reads the data in the file, returns the interpolated function and defines the Jacobian. However, I am not sure where this function should be defined to prevent PyBaMM from running several instances of the intepolation which might slow down the code. Tino suggested defining the functions in `input/parameters/lithium-ion' but maybe it would be good to have it in a more generic place (like the averaging functions).

@valentinsulzer
Copy link
Member

You would have to make interpolation_1D a class which does the interpolation during the __init__ and then acts like a function (by defining the __call__ method). I haven't done anything on this, agreed now it can be somewhere more generic.

@brosaplanella
Copy link
Sponsor Member Author

I see. Then it should be a script similar to the GetUserCurrent one, which we could call something like GetUserFunction (please suggest better names). Does it matter where this script is saver, or as long as it is in pybamm/parameters it is fine?

I can give it a go, but not sure I will be able to do any proper work on it in the next week and a half. If it is urgent, feel free to give it a go and I can review the pull request later.

@valentinsulzer
Copy link
Member

I'd put it in the expression tree folder in a new file interpolant.py with a class called Interpolant.
Then in input/parameters/lithium-ion you would have the data and call pybamm.Interpolant with that data. I'll try to have a go this week after #563

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants