docs: def reinforce_branches_overvoltage(network, grid, crit_nodes):
      """
      Reinforce MV and LV grid due to voltage issues.
  
      Parameters
      ----------
      network : :class:`~.grid.network.Network`
      grid : :class:`~.grid.grids.MVGrid` or :class:`~.grid.grids.LVGrid`
      crit_nodes : :pandas:`pandas.DataFrame<dataframe>`
          Dataframe with critical nodes, sorted descending by voltage deviation.
          Index of the dataframe are nodes (of type
          :class:`~.grid.components.Generator`, :class:`~.grid.components.Load`,
          etc.) with over-voltage issues. Columns are 'v_mag_pu' containing the
          maximum voltage deviation as float and 'time_index' containing the
          corresponding time step the over-voltage occured in as
          :pandas:`pandas.Timestamp<timestamp>`.
  
      Returns
      -------
      Dictionary with :class:`~.grid.components.Line` and the number of lines
      added.
  
      Notes
      -----
      Reinforce measures:
  
      1. Disconnect line at 2/3 of the length between station and critical node
      farthest away from the station and install new standard line
      2. Install parallel standard line
  
      In LV grids only lines outside buildings are reinforced; loads and
      generators in buildings cannot be directly connected to the MV/LV station.
  
      In MV grids lines can only be disconnected at LVStations because they
      have switch disconnectors needed to operate the lines as half rings (loads
      in MV would be suitable as well because they have a switch bay (Schaltfeld)
      but loads in dingo are only connected to MV busbar). If there is no
      suitable LV station the generator is directly connected to the MV busbar.
      There is no need for a switch disconnector in that case because generators
      don't need to be n-1 safe.
  
      """
  
      # load standard line data
      if isinstance(grid, LVGrid):
          try:
              standard_line = network.equipment_data['lv_cables'].loc[
                  network.config['grid_expansion_standard_equipment']['lv_line']]
          except KeyError:
              print('Chosen standard LV line is not in equipment list.')
      else:
          try:
              standard_line = network.equipment_data['mv_cables'].loc[
                  network.config['grid_expansion_standard_equipment']['mv_line']]
          except KeyError:
              print('Chosen standard MV line is not in equipment list.')
  
      # find first nodes of every main line as representatives
      rep_main_line = list(
          nx.predecessor(grid.graph, grid.station, cutoff=1).keys())
      # list containing all representatives of main lines that have already been
      # reinforced
      main_line_reinforced = []
  
      lines_changes = {}
      for node in crit_nodes.index:
          path = nx.shortest_path(grid.graph, grid.station, node)
          # raise exception if voltage issue occurs at station's secondary side
          # because voltage issues should have been solved during extension of
          # distribution substations due to overvoltage issues.
          if len(path) == 1:
              logging.error("Voltage issues at busbar in LV grid {} should have "
                            "been solved in previous steps.".format(grid))
          else:
              # check if representative of line is already in list
              # main_line_reinforced; if it is, the main line the critical node
              # is connected to has already been reinforced in this iteration
              # step
              if not path[1] in main_line_reinforced:
  
                  main_line_reinforced.append(path[1])
                  # get path length from station to critical node
                  get_weight = lambda u, v, data: data['line'].length
                  path_length = dijkstra_shortest_path_length(
                      grid.graph, grid.station, get_weight, target=node)
                  # find first node in path that exceeds 2/3 of the line length
                  # from station to critical node farthest away from the station
                  node_2_3 = next(j for j in path if
                                  path_length[j] >= path_length[node] * 2 / 3)
  
                  # if LVGrid: check if node_2_3 is outside of a house
                  # and if not find next BranchTee outside the house
                  if isinstance(grid, LVGrid):
                      if isinstance(node_2_3, BranchTee):
                          if node_2_3.in_building:
                              # ToDo more generic (new function)
                              try:
                                  node_2_3 = path[path.index(node_2_3) - 1]
                              except IndexError:
                                  print('BranchTee outside of building is not ' +
                                        'in path.')
                      elif (isinstance(node_2_3, Generator) or
                                isinstance(node_2_3, Load)):
                          pred_node = path[path.index(node_2_3) - 1]
                          if isinstance(pred_node, BranchTee):
                              if pred_node.in_building:
                                  # ToDo more generic (new function)
                                  try:
                                      node_2_3 = path[path.index(node_2_3) - 2]
                                  except IndexError:
                                      print('BranchTee outside of building is ' +
                                            'not in path.')
                      else:
                          logging.error("Not implemented for {}.".format(
                              str(type(node_2_3))))
                  # if MVGrid: check if node_2_3 is LV station and if not find
                  # next LV station
                  else:
                      if not isinstance(node_2_3, LVStation):
                          next_index = path.index(node_2_3) + 1
                          try:
                              # try to find LVStation behind node_2_3
                              while not isinstance(node_2_3, LVStation):
                                  node_2_3 = path[next_index]
                                  next_index += 1
                          except IndexError:
                              # if no LVStation between node_2_3 and node with
                              # voltage problem, connect node directly to
                              # MVStation
                              node_2_3 = node
  
                  # if node_2_3 is a representative (meaning it is already
                  # directly connected to the station), line cannot be
                  # disconnected and must therefore be reinforced
                  if node_2_3 in rep_main_line:
                      crit_line = grid.graph.get_edge_data(
                          grid.station, node_2_3)['line']
  
                      # if critical line is already a standard line install one
                      # more parallel line
                      if crit_line.type.name == standard_line.name:
                          crit_line.quantity += 1
                          lines_changes[crit_line] = 1
  
                      # if critical line is not yet a standard line replace old
                      # line by a standard line
                      else:
                          # number of parallel standard lines could be calculated
                          # following [2] p.103; for now number of parallel
                          # standard lines is iterated
                          crit_line.type = standard_line.copy()
                          crit_line.quantity = 1
                          crit_line.kind = 'cable'
                          lines_changes[crit_line] = 1
  
                  # if node_2_3 is not a representative, disconnect line
                  else:
                      # get line between node_2_3 and predecessor node (that is
                      # closer to the station)
                      pred_node = path[path.index(node_2_3) - 1]
                      crit_line = grid.graph.get_edge_data(
                          node_2_3, pred_node)['line']
                      # add new edge between node_2_3 and station
                      new_line_data = {'line': crit_line,
                                       'type': 'line'}
                      grid.graph.add_edge(grid.station, node_2_3, new_line_data)
                      # remove old edge
                      grid.graph.remove_edge(pred_node, node_2_3)
                      # change line length and type
                      crit_line.length = path_length[node_2_3]
                      crit_line.type = standard_line.copy()
                      crit_line.kind = 'cable'
                      crit_line.quantity = 1
                      lines_changes[crit_line] = 1
                      # add node_2_3 to representatives list to not further
                      # reinforce this part off the grid in this iteration step
                      rep_main_line.append(node_2_3)
                      main_line_reinforced.append(node_2_3)
  
              else:
                  logger.debug(
                      '==> Main line of node {} in grid {} '.format(
                          repr(node), str(grid)) +
                      'has already been reinforced.')
  
      if main_line_reinforced:
          logger.debug('==> {} branche(s) was/were reinforced '.format(
              str(len(lines_changes))) + 'due to over-voltage issues.')
  
      return lines_changes