# Path: pyteltools/slf/interpolation.py
# class Interpolator:
#     """!
#     Wrapper for calculating the barycentric coordinates of 2d points in a 2d triangle
#     """
#     def __init__(self, triangle):
#         p1, p2, p3 = tuple(map(list, list(triangle.exterior.coords)[:-1]))
#         self.x1, self.y1 = p1
#         x2, y2 = p2
#         x3, y3 = p3
#         self.vec_x = np.array([x2-x3, x3-self.x1, self.x1-x2])
#         self.vec_y = np.array([y2-y3, y3-self.y1, self.y1-y2])
#         norm_z = (x2-self.x1) * (y3-self.y1) - (y2-self.y1) * (x3-self.x1)
#         self.vec_norm_z = np.array([norm_z, 0, 0])
#         self.inv_norm_z = 1 / norm_z
# 
#     def get_interpolator_at(self, x, y):
#         """!
#         @brief Return the barycentric coordinates of the point (x, y)
#         """
#         return (self.vec_norm_z + (x-self.x1) * self.vec_y - (y-self.y1) * self.vec_x) * self.inv_norm_z
# 
#     def is_in_triangle(self, x, y):
#         """!
#         @brief Return a boolean indicating if the point (x, y) is in the triangle, and its barycentric coordinates
#         """
#         coord = (self.vec_norm_z + (x-self.x1) * self.vec_y - (y-self.y1) * self.vec_x) * self.inv_norm_z
#         return np.all(coord >= 0) and np.all(coord <= 1), coord
# 
# Path: pyteltools/slf/mesh2D.py
# class Mesh2D:
#     """!
#     The general representation of mesh in Serafin 2D.
#     The basis for interpolation, volume calculations etc.
#     """
#     def __init__(self, input_header, construct_index=False, iter_pbar=lambda x, unit: x):
#         """!
#         @param input_header <slf.Serafin.SerafinHeader>: input Serafin header
#         @param construct_index <bool>: perform the index construction
#         @param iter_pbar: iterable progress bar
#         """
#         self.x, self.y = input_header.x[:input_header.nb_nodes_2d], input_header.y[:input_header.nb_nodes_2d]
#         self.ikle = input_header.ikle_2d - 1  # back to 0-based indexing
#         self.triangles = {}
#         self.nb_points = self.x.shape[0]
#         self.nb_triangles = self.ikle.shape[0]
#         self.points = np.stack([self.x, self.y], axis=1)
#         if not construct_index:
#             self.index = Index()
#         else:
#             self._construct_index(iter_pbar)
# 
#     def _construct_index(self, iter_pbar):
#         """!
#         Separate the index construction from the constructor, allowing a GUI override
#         @param iter_pbar: iterable progress bar
#         """
#         self.index = Index()
#         for i, j, k in iter_pbar(self.ikle, unit='elements'):
#             t = Polygon([self.points[i], self.points[j], self.points[k]])
#             self.triangles[i, j, k] = t
#             self.index.insert(i, t.bounds, obj=(i, j, k))
# 
#     def get_intersecting_elements(self, bounding_box):
#         """!
#         @brief Return the triangles in the mesh intersecting the bounding box
#         @param bounding_box <tuple>: (left, bottom, right, top) of a 2d geometrical object
#         @return <[tuple]>: The list of triangles (i,j,k) intersecting the bounding box
#            Beware: The returned list is not sorted
#         """
#         return list(self.index.intersection(bounding_box, objects='raw'))
# 
# Path: pyteltools/slf/Serafin.py
# SLF_EIT = 'iso-8859-1'
# 
# Path: pyteltools/slf/util.py



import numpy as np
from pyteltools.conf import settings
from .interpolation import Interpolator
from .mesh2D import Mesh2D
from .Serafin import SLF_EIT
from .util import logger
    @staticmethod
    def get_variables(possible_flux):
        """!
        Get variables from a possible flux
        @param possible_flux <str>: text describing a possible flux
        @return <[str]>: list of var_IDs
        """
        return list(possible_flux.split(':')[1].split('(')[1][:-1].split(', '))

    @staticmethod
    def get_flux_type(var_IDs):
        """!
        Get flux type
        @param <[str]>: list of varIDs (between 1 and 4)
        @return <int>: flux type identifier
        """
        nb_vars = len(var_IDs)
        if nb_vars == 1:
            flux_type = FluxCalculator.LINE_INTEGRAL
        elif nb_vars == 2:
            if var_IDs[0] == 'M':
                flux_type = FluxCalculator.DOUBLE_LINE_INTEGRAL
            else:
                flux_type = FluxCalculator.LINE_FLUX
        elif nb_vars == 3:
            flux_type = FluxCalculator.AREA_FLUX
        elif nb_vars == 4:
            flux_type = FluxCalculator.MASS_FLUX
        else:
            NotImplementedError('Flux with more than 4 variables is not possible')

# Path: pyteltools/slf/interpolation.py
# class Interpolator:
#     """!
#     Wrapper for calculating the barycentric coordinates of 2d points in a 2d triangle
#     """
#     def __init__(self, triangle):
#         p1, p2, p3 = tuple(map(list, list(triangle.exterior.coords)[:-1]))
#         self.x1, self.y1 = p1
#         x2, y2 = p2
#         x3, y3 = p3
#         self.vec_x = np.array([x2-x3, x3-self.x1, self.x1-x2])
#         self.vec_y = np.array([y2-y3, y3-self.y1, self.y1-y2])
#         norm_z = (x2-self.x1) * (y3-self.y1) - (y2-self.y1) * (x3-self.x1)
#         self.vec_norm_z = np.array([norm_z, 0, 0])
#         self.inv_norm_z = 1 / norm_z
# 
#     def get_interpolator_at(self, x, y):
#         """!
#         @brief Return the barycentric coordinates of the point (x, y)
#         """
#         return (self.vec_norm_z + (x-self.x1) * self.vec_y - (y-self.y1) * self.vec_x) * self.inv_norm_z
# 
#     def is_in_triangle(self, x, y):
#         """!
#         @brief Return a boolean indicating if the point (x, y) is in the triangle, and its barycentric coordinates
#         """
#         coord = (self.vec_norm_z + (x-self.x1) * self.vec_y - (y-self.y1) * self.vec_x) * self.inv_norm_z
#         return np.all(coord >= 0) and np.all(coord <= 1), coord
# 
# Path: pyteltools/slf/mesh2D.py
# class Mesh2D:
#     """!
#     The general representation of mesh in Serafin 2D.
#     The basis for interpolation, volume calculations etc.
#     """
#     def __init__(self, input_header, construct_index=False, iter_pbar=lambda x, unit: x):
#         """!
#         @param input_header <slf.Serafin.SerafinHeader>: input Serafin header
#         @param construct_index <bool>: perform the index construction
#         @param iter_pbar: iterable progress bar
#         """
#         self.x, self.y = input_header.x[:input_header.nb_nodes_2d], input_header.y[:input_header.nb_nodes_2d]
#         self.ikle = input_header.ikle_2d - 1  # back to 0-based indexing
#         self.triangles = {}
#         self.nb_points = self.x.shape[0]
#         self.nb_triangles = self.ikle.shape[0]
#         self.points = np.stack([self.x, self.y], axis=1)
#         if not construct_index:
#             self.index = Index()
#         else:
#             self._construct_index(iter_pbar)
# 
#     def _construct_index(self, iter_pbar):
#         """!
#         Separate the index construction from the constructor, allowing a GUI override
#         @param iter_pbar: iterable progress bar
#         """
#         self.index = Index()
#         for i, j, k in iter_pbar(self.ikle, unit='elements'):
#             t = Polygon([self.points[i], self.points[j], self.points[k]])
#             self.triangles[i, j, k] = t
#             self.index.insert(i, t.bounds, obj=(i, j, k))
# 
#     def get_intersecting_elements(self, bounding_box):
#         """!
#         @brief Return the triangles in the mesh intersecting the bounding box
#         @param bounding_box <tuple>: (left, bottom, right, top) of a 2d geometrical object
#         @return <[tuple]>: The list of triangles (i,j,k) intersecting the bounding box
#            Beware: The returned list is not sorted
#         """
#         return list(self.index.intersection(bounding_box, objects='raw'))
# 
# Path: pyteltools/slf/Serafin.py
# SLF_EIT = 'iso-8859-1'
# 
# Path: pyteltools/slf/util.py



# Path: pyteltools/slf/flux.py
import numpy as np
from pyteltools.conf import settings
from .interpolation import Interpolator
from .mesh2D import Mesh2D
from .Serafin import SLF_EIT
from .util import logger

    @staticmethod
    def get_variables(possible_flux):
        """!
        Get variables from a possible flux
        @param possible_flux <str>: text describing a possible flux
        @return <[str]>: list of var_IDs
        """
        return list(possible_flux.split(':')[1].split('(')[1][:-1].split(', '))

    @staticmethod
    def get_flux_type(var_IDs):
        """!
        Get flux type
        @param <[str]>: list of varIDs (between 1 and 4)
        @return <int>: flux type identifier
        """
        nb_vars = len(var_IDs)
        if nb_vars == 1:
            flux_type = FluxCalculator.LINE_INTEGRAL
        elif nb_vars == 2:
            if var_IDs[0] == 'M':
                flux_type = FluxCalculator.DOUBLE_LINE_INTEGRAL
            else:
                flux_type = FluxCalculator.LINE_FLUX
        elif nb_vars == 3:
            flux_type = FluxCalculator.AREA_FLUX
        elif nb_vars == 4:
            flux_type = FluxCalculator.MASS_FLUX
        else:
            NotImplementedError('Flux with more than 4 variables is not possible')

        logger.debug('Flux type %s' % flux_type)