docs: def homogenize_grid(grid_old, dx, dy):
      """
      1) fit line through electrodes
      2) rotate electrodes so that line lies in the horizontal plane
      3) translate z-coordinates so that all z-coordinates are negative
      """
  
      # 1 line fit
      x = grid_old.electrodes[:, 0]
      y = grid_old.electrodes[:, 1]
      sort_indices = np.argsort(x)
      x_sort = x[sort_indices]
      y_sort = y[sort_indices]
      p = np.polyfit(x_sort, y_sort, 1)
  
      # 2. rotate around first electrode
      offsetx = x_sort[0]
      offsety = y_sort[0]
  
      alpha = -np.arctan2(p[0], 1.0)  # * 180 / np.pi
  
      xn = []
      yn = []
      for xc, yc in zip(x, y):
          rotx, roty = rotate_point(offsetx, offsety, xc, yc, alpha)
          xn.append(rotx + offsetx)
          yn.append(roty + offsety)
  
      new_coordinates = np.vstack((xn, yn)).T
  
      # move vertically
  
      # this line is a horizontal line
      p_rot = np.polyfit(
          new_coordinates[:, 0],
          new_coordinates[:, 1],
          1
      )
      y_rot = np.polyval(
          p_rot,
          new_coordinates[:, 0],
      )
      ymax = y_rot[0]
  
      new_coordinates_trans = np.copy(new_coordinates)
      new_coordinates_trans[:, 1] -= ymax
  
      #
      fig, ax = plt.subplots(1, 1)
      ax.scatter(x, y, color='r', label='original')
  
      ax.plot(
          x,
          np.polyval(p, x),
          '-',
          label='fit',
          color='r',
      )
  
      ax.scatter(
          xn, yn,
          color='c',
          label='rotated',
      )
  
      ax.plot(
          xn,
          y_rot,
          '-',
          label='fit',
          color='c',
      )
  
      ax.scatter(
          new_coordinates_trans[:, 0],
          new_coordinates_trans[:, 1],
          label='homog',
      )
  
      # plot the line through the new coordintes
      pnew = np.polyfit(
          new_coordinates_trans[:, 0],
          new_coordinates_trans[:, 1],
          1
      )
      ax.plot(
          new_coordinates_trans[:, 0],
          np.polyval(pnew, new_coordinates_trans[:, 0]),
          '-',
          label='fit homogenized',
      )
  
      ax.legend(loc='best')
  
      ax.set_xlabel('x [m]')
      ax.set_ylabel('y [m]')
  
      fig.tight_layout()
      fig.savefig('output_electrodes.png', dpi=300)
  
      # electrodes = np.hstack((
      # boundaries
      bx = new_coordinates_trans[sort_indices, 0]
      by = new_coordinates_trans[sort_indices, 1]
      btype = [12 for i in bx]
  
      # add boundary
      # get deepest boundary coordinate
      y1 = by[-1] - dy
      y2 = by[0] - dy
  
      ymin = min(y1, y2)
  
      bx = np.hstack(
          (bx[0] - dx,
           bx,
           [bx[-1] + dx, bx[-1] + dx, bx[0] - dx])
      )
  
      by = np.hstack(
          (by[0],
           by,
           [by[-1], ymin, ymin]
           )
      )
  
      btype = np.hstack((12,
                         btype,
                         [11, 11, 11]))
  
      boundaries = np.vstack((bx, by, btype)).T
  
      # fig, ax = plt.subplots(1, 1)
      # ax.scatter(bx, by)
      # ax.set_aspect('equal')
      # fig.tight_layout()
      # fig.savefig('boundaries.png', dpi=300)
  
      grid_new = grid_container(None, None, grid_old.char_length_file)
      grid_new.boundaries = np.copy(boundaries)
      grid_new.electrodes = np.copy(new_coordinates_trans)
  
      fig, ax = plt.subplots(1, 1)
      ax.scatter(bx, by, color='g', label='boundaries')
      ax.scatter(new_coordinates[:, 0], new_coordinates[:, 1], color='g',
                 label='electrodes')
      ax.set_aspect('equal')
      ax.legend()
      fig.tight_layout()
      fig.savefig('output_boundaries.png', dpi=300)
  
      def transform_back(data):
          new_data = np.copy(data)
          new_data[:, 1] += ymax
          new_data[:, 0] -= offsetx
          new_data[:, 1] -= offsety
  
          tmpx = (new_data[:, 0]) * np.cos(-alpha) - (new_data[:, 1]) * np.sin(
              -alpha)
          tmpy = (new_data[:, 0]) * np.sin(-alpha) + (new_data[:, 1]) * np.cos(
              -alpha)
          tmpx += offsetx
          tmpy += offsety
          return tmpx, tmpy
  
      shell_script = ''
      shell_script += '#!/bin/bash\n'
      shell_script += 'cr_trig_create grid\n'
  
      cmd1 = ''.join((
          'grid_translate -e grid/elem.dat ',
          '--dx {0} --dz {1} -o elem_trans1.dat'.format(
              offsetx, ymax - offsety)
      ))
      cmd2 = ''.join((
          'grid_rotate -e elem_trans1.dat ',
          '-a {0} -o elem_trans1_rot1.dat'.format(-alpha * 180 / np.pi)
      ))
      cmd3 = ''.join((
          'grid_translate -e elem_trans1_rot1.dat ',
          '--dx {0} --dz {1} -o elem_trans1_rot1_trans2.dat'.format(
              offsetx, offsety)
      ))
      shell_script += cmd1 + '\n'
      shell_script += cmd2 + '\n'
      shell_script += cmd3 + '\n'
  
      shell_script += ''.join((
          'grid_plot_wireframe --fancy -t grid/elec.dat ',
          '-e elem_trans1_rot1_trans2.dat -o trans1_rot1_trans2.png'
      ))
  
      grid_new.script = shell_script
  
      tmpx, tmpy = transform_back(grid_new.electrodes)
      bx, by = transform_back(grid_new.boundaries[:, 0:2])
  
      grid_map = grid_container(char_length_file=grid_old.char_length_file)
      grid_map.electrodes = np.vstack((tmpx, tmpy)).T
      grid_map.boundaries = np.vstack((bx, by, grid_new.boundaries[:, 2])).T
  
      fig, ax = plt.subplots(1, 1)
      ax.scatter(tmpx, tmpy, color='r', label='new')
      ax.scatter(x, y, color='b', label='old')
      ax.scatter(bx, by, color='g', label='boundaries')
      ax.set_aspect('equal')
      ax.legend()
      fig.tight_layout()
      fig.savefig('output_map.png', dpi=300)
  
      return grid_new, grid_map