<jupyter_start><jupyter_text>libCEED for Python examplesThis is a tutorial to illustrate the main feautures of the Python interface for [libCEED](https://github.com/CEED/libCEED/), the low-level API library for efficient high-order discretization methods developed by the co-design [Center for Efficient Exascale Discretizations](https://ceed.exascaleproject.org/) (CEED) of the [Exascale Computing Project](https://www.exascaleproject.org/) (ECP).While libCEED's focus is on high-order finite/spectral element method implementations, the approach is mostly algebraic and thus applicable to other discretizations in factored form, as explained in the [user manual](https://libceed.readthedocs.io/).  Setting up libCEED for PythonInstall libCEED for Python by running<jupyter_code>! python -m pip install libceed<jupyter_output><empty_output><jupyter_text>CeedOperatorHere we show some basic examples to illustrate the `libceed.Operator` class. In libCEED, a `libceed.Operator` defines the finite/spectral element operator associated to a `libceed.QFunction` (see [the API documentation](https://libceed.readthedocs.io/en/latest/libCEEDapi.htmlfinite-element-operator-decomposition)). * In the following example, we create and apply a CeedOperator for the mass matrix in 1D. By applying this operator to a vector of 1's, we compute the length of this 1D domain, similar to Ex1-Volume in the [tutorial-6-shell tutorial](./tutorial-6-shell.ipynb)<jupyter_code>import libceed
import numpy as np

ceed = libceed.Ceed()

nelem = 15
p = 5
q = 8
nx = nelem + 1
nu = nelem*(p-1) + 1

# Vectors
x = ceed.Vector(nx)
x_array = np.zeros(nx)
for i in range(nx):
  x_array[i] = i / (nx - 1.0)
x.set_array(x_array, cmode=libceed.USE_POINTER)

qdata = ceed.Vector(nelem*q)
u = ceed.Vector(nu)
v = ceed.Vector(nu)

# Restrictions
indx = np.zeros(nx*2, dtype="int32")
for i in range(nx):
  indx[2*i+0] = i
  indx[2*i+1] = i+1
rx = ceed.ElemRestriction(nelem, 2, 1, 1, nx, indx, cmode=libceed.USE_POINTER)

indu = np.zeros(nelem*p, dtype="int32")
for i in range(nelem):
  for j in range(p):
    indu[p*i+j] = i*(p-1) + j
ru = ceed.ElemRestriction(nelem, p, 1, 1, nu, indu, cmode=libceed.USE_POINTER)
strides = np.array([1, q, q], dtype="int32")
rui = ceed.StridedElemRestriction(nelem, q, 1, q*nelem, strides)

# Bases
bx = ceed.BasisTensorH1Lagrange(1, 1, 2, q, libceed.GAUSS)
bu = ceed.BasisTensorH1Lagrange(1, 1, p, q, libceed.GAUSS)

# QFunctions
qf_setup = ceed.QFunctionByName("Mass1DBuild")
qf_mass = ceed.QFunctionByName("MassApply")

# Setup operator
op_setup = ceed.Operator(qf_setup)
op_setup.set_field("dx", rx, bx, libceed.VECTOR_ACTIVE)
op_setup.set_field("weights", libceed.ELEMRESTRICTION_NONE, bx,
                   libceed.VECTOR_NONE)
op_setup.set_field("qdata", rui, libceed.BASIS_COLLOCATED,
                   libceed.VECTOR_ACTIVE)
print('Setup operator: ', op_setup)

# Mass operator
op_mass = ceed.Operator(qf_mass)
op_mass.set_field("u", ru, bu, libceed.VECTOR_ACTIVE)
op_mass.set_field("qdata", rui, libceed.BASIS_COLLOCATED, qdata)
op_mass.set_field("v", ru, bu, libceed.VECTOR_ACTIVE)
print('Mass operator: ', op_mass)

# Setup
op_setup.apply(x, qdata)

# Apply mass matrix
u.set_value(1)
op_mass.apply(u, v)

# Check
with v.array_read() as v_array:
  print('The length of the domain is l = %4.2f'%np.sum(v_array))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12283840190816935, 'fraction_numerical': 0.013714967203339297, 'mean_word_length': 5.212962962962963, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 5, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '30018', 'license': 'BSD-2-Clause', 'n_tokens_mistral': 1280, 'n_tokens_neox': 1243, 'n_words': 325, 'path': 'examples/tutorials/tutorial-5-operator.ipynb', 'repo_name': 'rscohn2/libCEED', 'size': '3354'}