Load time series array with Expression

Hello!

So months ago i asked about mesh formulation for use in hydrodynamic simulation using OpenTidalFarm that depends on Fenics. I could simulate the hydrodynamic model with JIT-compiled sinusoidal equation at the boundary. However, i want to use real time-series data as a boundary condition.

Suppose i have time-series data such as :

0.3209
0.3209
0.1209
-0.1291
-0.3791
...

with specified time interval per data.
Then suppose i have a time variable t that increase by dt over time. How can i load this data in the Expression function so that when the time variable updates it reads to the next index?

Thank you in advance!

Consider the following minimal example:

from dolfin import *
import numpy as np

mesh = UnitSquareMesh(10, 10)

time_series = [0, 0.3, -0.4, 0.2, 0.5]

expr = Expression("t", t=time_series[0], degree=1)

a = expr * dx(domain=mesh)

for i, time in enumerate(time_series):
    expr.t = time
    A = assemble(a)
    print(A)

returns:

0.0
0.3000000000000002
-0.4000000000000003
0.20000000000000015
0.5000000000000003

Hi, dokken. Sorry for replying late as i only got to try it now!

Thank you for your suggestion! Although the assemble() result doesn’t show the exact time series data as the input…

This is what happens when i print assemble(a)

1188286524.36
1429657224.62
1726728855.71
2037725719.5
2288379908.23

I wonder what makes this happen…

(Edit : i tried this directly using my own domain mesh, would that be the problem?)

The expected output should be the volume of your mesh times the input value. The only reason for assembling it in a loop was to highlight that the form changes in time dependent problems without redefining it explicitly

I see, so does that mean just defining the list of data should do the trick?

Although, i tried just directly using the list and it shows an error like this :

TypeError: in method 'Expression_097464b5e61d068b0849dc47522abe90cd94dd9a_t_set', argument 2 of type 'double'

This is all you need to update your expression.

Thank you for your answers, dokken!
Yes you’re correct, i did try with a simpler mesh and using only Fenics module.
The problem i had was that OpenTidalFarm has its own boundary condition reading mechanics from Expression so somehow i had to get the time update inside the Expression.

Which lead me to use subclass Expression such as follows :

class TopExpr(Expression):
    def eval(self,value,x):
        value[0]=top[0] #top is the timeseries variable i used
    def update(self, t):
        top[0].t = t

But it doesn’t update the Expression value.
I tried reading other posts about updating UserExpression but i can’t really comprehend the implementation on my own…

You need to produce a minimal working example, i.e. A short code that reproduces the issue. It can use builtnin meshes, and made up data.

Hello again.

I’m a little bit confused at making the MWE from a module made by someone else, but i found a small example in the Fenics tutorial that probably could capture what i intend to do in a simple manner. I got it from here and below is the modified code (i only changed the u_D variable from the original example and add a random time_series list):

from fenics import *
import numpy as np

T = 2.0            # final time
num_steps = 10     # number of time steps
dt = T / num_steps # time step size
alpha = 3          # parameter alpha
beta = 1.2         # parameter beta

# Create mesh and define function space
nx = ny = 8
mesh = UnitSquareMesh(nx, ny)
V = FunctionSpace(mesh, 'P', 1)

# Random timeseries data
time_series = [0.1, 0.4, 0.5, -0.2, -0.6, 0.3, 0.7, 0, -0.1, -0.8]

# Define boundary condition
u_D = Expression("t", t=time_series[0], degree=1)

def boundary(x, on_boundary):
    return on_boundary

bc = DirichletBC(V, u_D, boundary)

# Define initial value
u_n = interpolate(u_D, V)
#u_n = project(u_D, V)

# Define variational problem
u = TrialFunction(V)
v = TestFunction(V)
f = Constant(beta - 2 - 2*alpha)

F = u*v*dx + dt*dot(grad(u), grad(v))*dx - (u_n + dt*f)*v*dx
a, L = lhs(F), rhs(F)

# Time-stepping
u = Function(V)
t = 0
for n in range(num_steps):

    # Update current time
    t += dt
    u_D.t = t

    # Compute solution
    solve(a == L, u, bc)

    # Plot solution
    plot(u)

    # Compute error at vertices
    u_e = interpolate(u_D, V)
    error = np.abs(u_e.vector().array() - u.vector().array()).max()
    print('t = %.2f: error = %.3g' % (t, error))

    # Update previous solution
    u_n.assign(u)

This works (i don’t know how to print Expression values in given time to check if it’s updating, but it shows result until the end). But in OpenTidalFarm it has a different time-updating class in boundary condition definition (fully here, but i just want to highlight this part from the full class) :

def update_time(self, t, only_type=None, exclude_type=None):
        ''' Update the time attribute for all boundary conditions '''

        if exclude_type is None:
            exclude_type = []

        for bc in self:
            if only_type is not None and bc[-1] not in only_type:
                continue
            if bc[-1] in exclude_type:
                continue

            if hasattr(bc[1], "t"):
                bc[1].t = t

So it only updates when the Expression() has attribute “t” in it. I tried using a similar Expression like u_D above (named top_expr) for boundary condition :

top_expr = Expression("t", t=time_series[0], degree=1)

But this is what i get :

TypeError: in method 'Expression_097464b5e61d068b0849dc47522abe90cd94dd9a_t_set', argument 2 of type 'double'

Probably due to “t” here refers to the variable time_series[0] being a double

So what do i actually want?

I want to make an Expression() that :

  • could be detected to have attribute “t”
  • will update time variable and can access index based on the time update (e.g. with dt=3600, at t=0 the Expression would give time_series[0/dt] as the value; at t=3600 the Expression would give times_series[3600/dt] as the value)

Is that possible to do? Sorry for the long post, i just hope i could make it clear. Any help is appreciated!