# %matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

"""
Explanation: <a href="http://landlab.github.io"><img style="float: left" src="../../landlab_header.png"></a>
Using the Landlab 1D flexure component
<hr>
<small>For more Landlab tutorials, click here: <a href="https://landlab.readthedocs.io/en/latest/user_guide/tutorials.html">https://landlab.readthedocs.io/en/latest/user_guide/tutorials.html</a></small>
<hr>

In this example we will:
* create a Landlab component that solves the (1D) flexure equation
* apply a point load
* run the component
* plot some output
* apply a distributed load
(Note that this tutorial uses the one-dimensional flexure component, Flexure1D. A separate tutorial notebook, "lots_of_loads", explores the two-dimensional elastic flexure component Flexure.)
A bit of magic so that we can plot within this notebook.
End of explanation
"""


from landlab import RasterModelGrid

"""
Explanation: Create the grid
We are going to build a uniform rectilinear grid with a node spacing of 100 km in the y-direction and 10 km in the x-direction on which we will solve the flexure equation.
First we need to import RasterModelGrid.
End of explanation
"""


grid = RasterModelGrid((3, 800), xy_spacing=(100e3, 10e3))

grid.dy, grid.dx

"""
Explanation: Create a rectilinear grid with a spacing of 100 km between rows and 10 km between columns. The numbers of rows and columms are provided as a tuple of (n_rows, n_cols), in the same manner as similar numpy functions. The spacing is also a tuple, (dy, dx).
End of explanation
"""


from landlab.components import Flexure1D

"""
Explanation: Create the component
Now we create the flexure component and tell it to use our newly created grid. First, though, we'll examine the Flexure component a bit.
End of explanation
"""


Flexure1D.input_var_names

"""
Explanation: The Flexure1D component, as with most landlab components, will require our grid to have some data that it will use. We can get the names of these data fields with the input_var_names attribute of the component class.
End of explanation
"""


Flexure1D.var_units('lithosphere__increment_of_overlying_pressure')

"""
Explanation: We see that flexure uses just one data field: the change in lithospheric loading. Landlab component classes can provide additional information about each of these fields. For instance, to see the units for a field, use the var_units method.
End of explanation
"""


Flexure1D.var_help('lithosphere__increment_of_overlying_pressure')

"""
Explanation: To print a more detailed description of a field, use var_help.
End of explanation
"""


Flexure1D.output_var_names

Flexure1D.var_help('lithosphere_surface__increment_of_elevation')

"""
Explanation: What about the data that Flexure1D provides? Use the output_var_names attribute.
End of explanation
"""


grid.add_zeros("lithosphere__increment_of_overlying_pressure", at="node")

flex = Flexure1D(grid, method='flexure')

"""
Explanation: Now that we understand the component a little more, create it using our grid.
End of explanation
"""


flex.load_at_node[1, 200] = 1e6
flex.update()
plt.plot(flex.x_at_node[1, :400] / 1000., flex.dz_at_node[1, :400])

"""
Explanation: Add a point load
First we'll add just a single point load to the grid. We need to call the update method of the component to calculate the resulting deflection (if we don't run update the deflections would still be all zeros).
Use the load_at_node attribute of Flexure1D to set the loads. Notice that load_at_node has the same shape as the grid. Likewise, x_at_node and dz_at_node also reshaped.
End of explanation
"""


flex.dz_at_node[:] = 0.

"""
Explanation: Before we make any changes, reset the deflections to zero.
End of explanation
"""


flex.eet *= 2.
flex.update()
plt.plot(flex.x_at_node[1, :400] / 1000., flex.dz_at_node[1, :400])

"""
Explanation: Now we will double the effective elastic thickness but keep the same point load. Notice that, as expected, the deflections are more spread out.
End of explanation
"""


flex.load_at_node[1, :100] = 0.
flex.load_at_node[1, 100:300] = np.arange(200) * 1e6 / 200.
flex.load_at_node[1, 300:] = 1e6

plt.plot(flex.load_at_node[1, :400])

"""
Explanation: Add some loading
We will now add a distributed load. As we saw above, for this component, the name of the attribute that holds the applied loads is load_at_node. For this example we create a loading that increases linearly of the center portion of the grid until some maximum. This could by thought of as the water load following a sea-level rise over a (linear) continental shelf.
End of explanation
"""


flex.dz_at_node[:] = 0.
flex.update()

plt.plot(flex.x_at_node[1, :400] / 1000., flex.dz_at_node[1, :400])

"""
Explanation: Update the component to solve for deflection
Clear the current deflections, and run update to get the new deflections.
End of explanation
"""


