# Tutorial¶

In this tutorial, we will show the use of NodeFinder with a simple example. We will find the nodal line given by the following function:

```
In [1]: import numpy as np
In [2]: def gap_function(pos):
...: x, y, z = pos
...: return np.sqrt((y - np.sin(np.pi * x))**2 + z**2)
...:
```

## Search¶

The NodeFinder module consists of two parts: In the first part, a Nelder-Mead optimization is performed from many starting points. If nodes are found, a local refinement is done to check if there are more nodal points nearby, such as when there is a nodal line. The goal of this first step is to find nodal positions which lie densely in the object which should be identified.

This first step is performed using the `search`

submodule:

```
In [3]: import nodefinder as nf
In [4]: search_result = nf.search.run(
...: gap_function,
...: limits=[(-1, 1)] * 3,
...: initial_mesh_size=3,
...: gap_threshold=1e-4,
...: feature_size=0.1,
...: use_fake_potential=True,
...: )
...:
In [5]: print(search_result)
SearchResultContainer(coordinate_system=CoordinateSystem(limits=array([[-1, 1],
[-1, 1],
[-1, 1]]), periodic=True), minimization_results=<1548 values>, gap_threshold=0.0001, dist_cutoff=0.03333333333333333)
In [6]: nf.search.plot.points(search_result);
```

The main logic is in the `search.run()`

method. As you can see, this function can take some additional keyword arguments, which are described in the `reference section`

.

Of note here is the `use_fake_potential`

flag. When this flag is set, each minimization step first adds a “fake” potential to the function to be minimized, which repels the minimization from nodes which have already been found. This is especially useful for nodal lines, because it helps covering the whole line.

## Identify¶

The second step in the process is to identify the nodal features from the point clouds calculated in the search step. For this purpose, the `identify`

submodule is used.

This process works by first clustering the points into connected components. Next, the dimension of each cluster is determined. Finally, the shape of the object is determined.

```
In [7]: identify_result = nf.identify.run(search_result)
In [8]: print(identify_result)
IdentificationResultContainer(coordinate_system=CoordinateSystem(limits=array([[-1, 1],
[-1, 1],
[-1, 1]]), periodic=True), feature_size=0.1, results=[IdentificationResult(dimension=1, shape=NodalLine(graph=<1468 nodes, 1468 edges>, degree_count=Counter(), shape_name='CLOSED LOOP'), positions=<1533 values>)])
In [9]: nf.identify.plot.result(identify_result);
```