-
Notifications
You must be signed in to change notification settings - Fork 81
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
skfem.ivp #531
Comments
It's fine if most of the functionality are wrappers to stuff like https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.RK45.html but I think having a consistent interface (easy to experiment with the methods and parameters) which is specifically designed for finite element calculations (e.g. use of mass matrices in Mu'(t) = Au(t) and especially sparse matrices) would be beneficial. |
This is quite a big issue. I think getting the right abstraction could be very helpful but I fear that it's hard; not many packages get this right. Some of the big questions:
All of the above should really be outside the scope of scikit-fem but although I've been looking for a couple of decades, I haven't really found anything suitable. There's PETSc but it's a bit heavy. There was GarlicSim but it had already been abandoned before I found it. |
On the
In Python this is naturally a generator, like def evolve(t: float,
u: np.ndarray) -> Iterator[Tuple[float, np.ndarray]]:
t, u = step(t, u)
yield t, u As mentioned in #529, this is a lot like the iteration of the (problem-specific) function I'm not sure why this isn't in while True:
yield x
x = func(x) (Here using this would involve packing the time |
On the question of implicit dynamical systems, if one begins with the general implicit system defined by the function This can be solved howsoever (#119). This often involves the jacobian For linear systems, In general the idea would be to define a dynamical system by the function f (the residual) and its two partial derivatives with respect to its second and third arguments; i.e. the stiffness and mass matrices, K and M. |
Solid mechanical problems often involve the second derivative with respect to time. These can always be reduced to larger first-order systems by appending the first derivative to the state. In practice, it is common though to treat the second-order system directly; e.g. as in the Newmark-beta method. I'm not sure whether the latter really offer much benefit. If so, the previous could be augmented by defining |
In pacopy 0.1.2, as used in exx 23 and 27, a steady nonlinear system is defined by an object with
The closeness of this Generally though I prefer functions to methods and I've had to replace pacopy with something taking residual and jacobian (or jacobian-solver) functions as arguments rather than an object with those methods; otherwise I find myself always having to construct temporary objects on the fly. |
I don't think this'll work will it? Does it assume dividing through by the mass matrix? As in converting Mu'(t) = Au(t) to u'(t) = M−1 Au(t)? This is a possibility, but not if the mass matrix is singular, as in incompressible Stokes flow. |
Another consideration: coupling. Can one drive one system with the output of another? Can two or more systems be strongly coupled? The latter might lead to the concept of hierarchical systems. |
Alright, that may not make sense. Would it work by caching the LU-decomposition of |
If we are able to make interesting progress then we could eventually spin it off into a separate package. |
So based on this, would the simple use of from skfem.ivp import evolve
for (k, u) in evolve(M, A, I=I, x=x, dt=1e-2):
if k > 10:
break
# possibly plot u or check convergence criteria Then various parameters to |
A brief comment before getting back to this properly in the new year.
Actually I generally leave the class DynamicalSystem:
def step(h: float, t: float, x: ndarray) -> Tuple[float, ndarray]:
raise NotImplementedError
def evolve(h: float, t: float, x: ndarray):
while True:
yield t, x
t, x = self.step(h, t, x)
class LinearDynamicalSystem(DynamicalSystem):
M, L: spmatrix
theta: float = 0.5
def step(h, t, x):
x = ... # take a generalized trapezoidal step as in ex19
return t + h, x |
One case in which the |
Should we have
Edit: I suppose it doesn't matter because
is just as simple and maybe even more descriptive. |
Sure, why not.
Later the class might have other methods alongside `evolve` like:
* steady state
* harmonic response
* eigenanalysis
but I think the transient response is the fundamental one so it's reasonable to make it the default.
Envoyé depuis ProtonMail mobile
…-------- Message d'origine --------
Le 27 déc. 2020 à 22:24, T. Gustafsson a écrit :
> class
>
> DynamicalSystem
>
> :
>
> def
>
> step
>
> (
>
> h
>
> :
>
> float
>
> ,
>
> t
>
> :
>
> float
>
> ,
>
> x
>
> :
>
> ndarray
>
> )
>
> ->
>
> Tuple
>
> [
>
> float
>
> ,
>
> ndarray
>
> ]:
>
> raise
>
> NotImplementedError
>
> def
>
> evolve
>
> (
>
> h
>
> :
>
> float
>
> ,
>
> t
>
> :
>
> float
>
> ,
>
> x
>
> :
>
> ndarray
>
> ):
>
> while
>
> True
>
> :
>
> yield
>
> t
>
> ,
>
> x
>
> t
>
> ,
>
> x
>
> =
>
> self
>
> .
>
> step
>
> (
>
> h
>
> ,
>
> t
>
> ,
>
> x
>
> )
>
> class
>
> LinearDynamicalSystem
>
> (
>
> DynamicalSystem
>
> ):
>
> M
>
> ,
>
> L
>
> :
>
> spmatrix
>
> theta
>
> :
>
> float
>
> =
>
> 0.5
>
> def
>
> step
>
> (
>
> h
>
> ,
>
> t
>
> ,
>
> x
>
> ):
>
> x
>
> =
>
> ...
>
> # take a generalized trapezoidal step as in ex19
>
> return
>
> t
>
> +
>
> h
>
> ,
>
> x
Should we have DynamicalSystem.__call__ = DynamicalSystem.evolve? So that one could use it like this:
for (t, x) in DynamicalSystem(...):
if t > 1.:
break
—
You are receiving this because you authored the thread.
Reply to this email directly, [view it on GitHub](#531 (comment)), or [unsubscribe](https://github.com/notifications/unsubscribe-auth/AAMD5U6PTXH4MBRMPBHW5GLSW4KNNANCNFSM4VHSAUKQ).
|
I suppose if a time limit is the most common way to terminate a simulation, it might be reasonable to give |
A default steady state method can be obtained from a backward Euler step of infinite length. |
One design decision is how to handle forcing. Is it part of the system or an input? It was implicitly left in the system above.but having it separate is often more physical and is more flexible. |
The whole nonlinear framework above does stumble at the moment because it relies on #119 having being solved which it hasn't despite considerable effort. |
Besides inputs, another important feature is outputs. Common uses:
These outputs and transformations should be composable. I have used (I wonder whether one day Python's |
I remembered over the break that back on 2019-05-07 I'd solved a textbook example exactly like the one asked about by @nikosmatsa . Here's the old source code, verbatim. N. B.:—This won't work as is! """
Reproducing Carslaw & Jaeger's 1959 figure 20: 'Temperatures in the slab -l < x < l with constant heat production at the rate A0 per unit volume and zero surface temperatures. The numbers on the curves are values of kappa t / l**2.'
"""
from matplotlib.pyplot import subplots, pause
import numpy as np
from scipy.sparse import csr_matrix
from sksparse.cholmod import cholesky
import skfem
from skfem.models.poisson import laplace, mass, unit_load
from dysys import SparseDySys
Q_in = 1.0 # mW
length = 911.0 # mm
area = 17.0
n_lumps = 2**6 // 2
thermal_conductivity = 2.0 # mW / K mm
density = 3.0 # mg / uL
specific_heat = 5.0 # uJ / mg K
mesh = skfem.MeshLine(np.linspace(0., length / 2, n_lumps + 1))
basis = skfem.InteriorBasis(mesh, skfem.ElementLineP1())
A0 = Q_in / area / length
f1 = skfem.asm(unit_load, basis)
def heating(*_) -> np.ndarray:
return A0 * f1
sys = SparseDySys(
density * specific_heat * skfem.asm(mass, basis),
thermal_conductivity * skfem.asm(laplace, basis),
heating).constrain([-1])
RC = (length / thermal_conductivity) * length * density * specific_heat
T_norm = A0 * length**2 / 8 / thermal_conductivity
t_final = 1.0 * RC / 4.0
dt = t_final / 1e2
def record(_, t, u, __):
"""put the nodal values in the dict and tag with time"""
return u, {'time': t, 'temperature': sys.reconstitute(u)}
samples = [0.02, 0.06, 0.1, 0.2, 0.3, 0.4, 0.6, 0.8, 1.0]
temperature = {}
for t, _, d in sys.march_till(t_final + dt / 2, dt, d={},
events=[(tstar * RC / 4, record)
for tstar in samples]):
if d.get('time') == t:
temperature[4 * t / RC] = d['temperature'] / T_norm
def exact(t, x, l, A0, k, alpha):
return (1 - (x / l)**2 - 32 / np.pi**3 *
sum((-1)**i / (2 * i + 1)**3 *
np.cos((2 * i + 1) * np.pi * x / 2 / l) *
np.exp(-alpha * (2 * i + 1)**2 * np.pi**2 * t / 4 / l**2)
for i in range(100)))
fig, ax = subplots()
fig.suptitle('constant heat load to slab, by scikit-fem')
x_cj = np.linspace(0, 1) * length / 2
for t in temperature:
line = ax.plot(2 * mesh.p[0] / length,
temperature[t],
label=f'{t:.2g}',
marker='o', linestyle='None')
ax.plot(x_cj / length * 2,
exact(t * RC / 4, x_cj,
0.5 * length, A0, thermal_conductivity,
thermal_conductivity / density / specific_heat),
color=line[0].get_color())
ax.legend(loc=1)
ax.set_xlim((0, 1))
ax.set_xlabel(r'$x/\ell$')
ax.set_ylim((0, 1))
ax.set_ylabel(r'$2 k A T / \ell Q$')
fig.savefig('slab.png') It won't work because:
I'll revise this to work with current master after I finish reviewing #530, but it might give some ideas. Here's the plot, like the one in
|
This line x = solve(*condense(L+M, b, I=m.interior_nodes())) needs to be changed; What's to be solved to take a step Δ t then is La = M a old + b Δ t, so the first argument of condense should be L and the second the right-hand side, which includes both the actual generation term b and the thermal inertia terms from the old value of a. Since in your example (like ex19) the Dirichlet conditions and source term (absent in ex19) are independent of time, the condensation doesn't need to be done at every step. Anyway the solve needs to be called repeatedly with updated right-hand side; i.e. it needs to be iterated. |
Based on ex19 what the "u_init" will be? 0? |
Is your initial condition zero? If so, you need an array of zeros, one for each degree of freedom. The number is given by the .N attribute of the scikit-fem/docs/examples/ex13.py Line 42 in 6e31b46
|
u = np.zeros(basis.N) |
Here's a minimal modification of ex19 to include steady uniform volumetric (areal) generation: https://gist.github.com/gdmcbain/253b75c25af1daf286b2e66be21c9d8a |
i can change in the unit_load to loading def loading(v, w): |
Yes, s for source. |
You do have to call for t, u in evolve(0.0, u_init):
print(t, u.max()) |
`
|
and making a 3d plot? |
Traceback (most recent call last): |
scikit-fem/docs/examples/ex10.py Lines 47 to 49 in 6e31b46
|
Yeah, scikit-fem/docs/examples/ex19.py Line 73 in 6e31b46
|
`if name == 'main':
|
plt3(what, what) |
As in ex10 cited above, the two arguments are the mesh and the solution. (Or in this unsteady case a snapshot of the solution.) |
`NameError Traceback (most recent call last) NameError: name 'u' is not defined |
How can I change the theta rule method in order to implement to the CN or backward Ba^{n}+\frac{1}{2}t Aa^{n}=Ba^{n-1}-\frac{1}{2}t Aa^{n-1}+tb^{n-1/2} or Ba^{n} =& Ba^{n-1}-t A^{n} + t b^{n} |
In ex10 the mesh is called m and the unknown deflection x; in ex19 the mesh is called mesh and the unknown temperature at any given time step is called u. The names are more or less arbitrary, as usual in mathematics and computation. |
The theta method is already implemented in ex19; theta = 1/2 gives Crank–Nicholson, theta = 1 gives backward Euler. scikit-fem/docs/examples/ex19.py Lines 65 to 67 in 6e31b46
|
I didn't put it right.I don't want theta rule |
Crank–Nicolson and backward Euler are just special cases of the θ-rule. If you want to hard-code them, you could; e.g.
or
respectively. |
`if name == 'main':
plots me all the graphs but I want only the last one |
Try moving the plotting outside the for t, u in evolve(0.0, u_init):
pass
plot3(m,u)
plt.show() |
Oh, I don't think you want show() |
close the issue.thnka for everything.you are awesome |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
From #529 at 2020-12-24:
The text was updated successfully, but these errors were encountered: