"""Contains the class object.

Used to create two-dimensional thermal objects, and apply some methods.

"""

from ... import mats
import os
import copy
import numpy as np


class Object:
    """Object class.

    This class creates thermal objects at 2D to be used in more complex
    systems.

    """

    def __init__(self, amb_temperature, material='Cu', dx=0.01, dy=0.01,
                 dt=0.1, size=(10, 10), file_name=None,
                 boundaries=(0, 0, 0, 0), Q=[], Q0=[], initial_state=False,
                 heat_save=False, materials_path=False):
        """Thermal object initialization.

        amb_temperature: ambient temperature of the whole system
        material: background material present at materials_path
        dx: space step along the x-axis
        dy: space step along the y-axis
        dt: the times step
        file_name: file name where the temperature is saved
        boundaries: list of four entries that define the boundary condition
            for temperature (left, right, bottom, top). If 0 the boundary
            condition is insulation
        Q: list in the form of matrix of fixed heat source coefficient.
        Q0: list in the form of matrix of temperature dependent heat source
            coefficient.
        initial_state: initial state of the materials. True if applied field
            and False is removed field.
        heat_save: True if saving the heat at the two borders.
        materials_path: absolute path of the materials database.

        """
        # check the validity of inputs
        boundaries = tuple(boundaries)
        Q = list(Q)
        Q0 = list(Q0)
        cond01 = isinstance(amb_temperature, float)
        cond01 = cond01 or isinstance(amb_temperature, int)
        cond05 = isinstance(dx, int) or isinstance(dx, float)
        cond06 = isinstance(dt, int) or isinstance(dt, float)
        cond07 = isinstance(file_name, str)
        cond07 = cond07 or (file_name is None)
        cond08 = isinstance(boundaries, tuple)
        cond09 = isinstance(Q, list)
        cond10 = isinstance(Q0, list)
        cond11 = isinstance(initial_state, bool)
        cond12 = isinstance(heat_save, bool)
        condition = cond01 and cond05
        condition = condition and cond06 and cond07 and cond08 and cond09
        condition = condition and cond10 and cond11 and cond12
        if not condition:
            raise ValueError

        self.materials = [material]
        self.materials_name = [material]
        self.boundaries = boundaries
        self.amb_temperature = amb_temperature

        if materials_path is False:
            tadi = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'tadi.txt'
            tadd = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'tadd.txt'
            cpa = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'cpa.txt'
            cp0 = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'cp0.txt'
            k0 = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'k0.txt'
            ka = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'ka.txt'
            rho0 = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'rho0.txt'
            rhoa = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'rhoa.txt'
            lheat0 = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'lheat0.txt'
            lheata = os.path.dirname(os.path.realpath(__file__)) + \
                '/../../database/' + self.materials[0] + '/' + 'lheata.txt'
            self.materials[0] = mats.CalMatPro(
                tadi, tadd, cpa, cp0, k0, ka, rho0, rhoa, lheat0, lheata)
        else:
            tadi = materials_path + self.materials[0] + '/' + 'tadi.txt'
            tadd = materials_path + self.materials[0] + '/' + 'tadd.txt'
            cpa = materials_path + self.materials[0] + '/' + 'cpa.txt'
            cp0 = materials_path + self.materials[0] + '/' + 'cp0.txt'
            k0 = materials_path + self.materials[0] + '/' + 'k0.txt'
            ka = materials_path + self.materials[0] + '/' + 'ka.txt'
            rho0 = materials_path + self.materials[0] + '/' + 'rho0.txt'
            rhoa = materials_path + self.materials[0] + '/' + 'rhoa.txt'
            lheat0 = materials_path + self.materials[0] + '/' + 'lheat0.txt'
            lheata = materials_path + self.materials[0] + '/' + 'lheata.txt'
            self.materials[0] = mats.CalMatPro(
                tadi, tadd, cpa, cp0, k0, ka, rho0, rhoa, lheat0, lheata)

        self.materials_index = [None]
        self.size = size
        self.file_name = file_name
        self.dx = dx
        self.dy = dy
        self.dt = dt
        self.temperature = []
        self.latent_heat = []
        self.lheat = []
        self.Cp = []
        self.rho = []
        self.Q = []
        self.Q0 = []
        self.k = []
        self.materials_index = []
        self.state = []
        for i in range(self.size[0]):
            self.state.append([])
            self.materials_index.append([])
            self.temperature.append([])
            self.latent_heat.append([])
            self.lheat.append([])
            self.Cp.append([])
            self.rho.append([])
            self.Q.append([0. for i in range(self.size[1])])
            self.Q0.append([0. for i in range(self.size[1])])
            self.k.append([])
            for j in range(self.size[1]):
                self.materials_index[-1].append(0)
                self.temperature[-1].append([amb_temperature, amb_temperature])
                self.state[-1].append(initial_state)
                if initial_state:
                    value = self.materials[self.materials_index[i][j]]
                    self.Cp[-1].append(value.cpa(self.amb_temperature))
                    value = self.materials[self.materials_index[i][j]]
                    self.rho[-1].append(value.rhoa(self.amb_temperature))
                    value = self.materials[self.materials_index[i][j]]
                    self.k[-1].append(value.ka(self.amb_temperature))
                    self.latent_heat[-1].append(
                        self.materials[self.materials_index[i][j]].lheata()
                    )
                    self.lheat[-1].append([])
                    value = self.materials[self.materials_index[i][j]]
                    for lh in value.lheata():
                        if self.temperature[i][j][1] < lh[0] and lh[1] > 0.:
                            self.lheat[-1].append([lh[0], 0.])
                        if self.temperature[i][j][1] > lh[0] and lh[1] > 0.:
                            self.lheat[-1].append([lh[0], lh[1]])
                        if self.temperature[i][j][1] < lh[0] and lh[1] < 0.:
                            self.lheat[-1].append([lh[0], -lh[1]])
                        if self.temperature[i][j][1] > lh[0] and lh[1] < 0.:
                            self.lheat[-1].append([lh[0], 0.])
                else:
                    value = self.materials[self.materials_index[i][j]]
                    self.Cp[-1].append(value.cp0(self.amb_temperature))
                    value = self.materials[self.materials_index[i][j]]
                    self.rho[-1].append(value.rho0(self.amb_temperature))
                    value = self.materials[self.materials_index[i][j]]
                    self.k[-1].append(value.k0(self.amb_temperature))
                    self.latent_heat[-1].append(
                        self.materials[self.materials_index[i][j]].lheat0()
                    )
                    self.lheat[-1].append([])
                    value = self.materials[self.materials_index[i][j]]
                    for lh in value.lheat0():
                        if self.temperature[i][j][1] < lh[0] and lh[1] > 0.:
                            self.lheat[-1].append([lh[0], 0.])
                        if self.temperature[i][j][1] > lh[0] and lh[1] > 0.:
                            self.lheat[-1].append([lh[0], lh[1]])
                        if self.temperature[i][j][1] < lh[0] and lh[1] < 0.:
                            self.lheat[-1].append([lh[0], -lh[1]])
                        if self.temperature[i][j][1] > lh[0] and lh[1] < 0.:
                            self.lheat[-1].append([lh[0], 0.])

        if Q != []:
            self.Q = Q
        if Q0 != []:
            self.Q0 = Q0

        self.time_passed = 0.

        self.Q_ref = copy.copy(self.Q)
        self.Q0_ref = copy.copy(self.Q0)

        if file_name:
            line = 'time(s)'
            for i in range(size[0]):
                for j in range(size[1]):
                    line = line + ',T[' + str(i) + '][' + str(j) + '] (K)'
            if heat_save:
                line = line + ',Q (J/m)'
            line = line + '\n'
            f = open(self.file_name, 'a')
            f.write(line)
            f.close()

    def activate(self, initial_point, final_point, shape='square'):
        """Activation of the material.

        Activates a given piece of material. If shape is 'square', then the
        initial_point is the tuple (x,y) of the bottom left point and the
        final_point is the tuple (x,y) of the top right point. If the shape is
        'circle', the initial_point is the tuple (x,y) of the center of the
        circle and final_point is its radius.

        """
        # check the validity of inputs
        if isinstance(shape, str):
            if shape == 'square':
                value = isinstance(initial_point, tuple)
                if value and isinstance(final_point, tuple):
                    condition = len(initial_point) == 2
                    condition = condition and len(final_point) == 2
                else:
                    condition = False
            elif shape == 'circle':
                value = isinstance(final_point, int)
                value = value or isinstance(final_point, float)
                value = value and isinstance(initial_point, tuple)
                if value:
                    condition = len(initial_point) == 2
                else:
                    condition = False
            else:
                condition = False
        else:
            condition = False
        if not condition:
            raise ValueError

        if shape == 'square':
            initial_point_x = int(initial_point[0])
            initial_point_y = int(initial_point[1])
            final_point_x = int(final_point[0])
            final_point_y = int(final_point[1])
            for i in range(initial_point_x, final_point_x):
                for j in range(initial_point_y, final_point_y):
                    if self.state[i][j] is False:
                        value = self.temperature[i][j][0]
                        self.temperature[i][j][0] = value + \
                            self.materials[self.materials_index[i][j]].tadi(
                                self.temperature[i][j][0])
                        value = self.materials_index[i][j]
                        self.rho[i][j] = self.materials[value].rhoa(
                            self.temperature[i][j][0])
                        self.Cp[i][j] = self.materials[value].cpa(
                            self.temperature[i][j][0])
                        self.k[i][j] = self.materials[value].ka(
                            self.temperature[i][j][0])
                        self.lheat[i][j] = []
                        valh = self.materials[value].lheata()
                        self.latent_heat[i][j] = valh
                        for lh in self.latent_heat[i][j]:
                            cond = self.temperature[i][j][0] < lh[0]
                            if cond and lh[1] > 0.:
                                self.lheat[i][j].append([lh[0], 0.])
                            cond = self.temperature[i][j][0] > lh[0]
                            if cond and lh[1] > 0.:
                                self.lheat[i][j].append([lh[0], lh[1]])
                            cond = self.temperature[i][j][0] < lh[0]
                            if cond and lh[1] < 0.:
                                self.lheat[i][j].append([lh[0], -lh[1]])
                            cond = self.temperature[i][j][0] > lh[0]
                            if cond and lh[1] < 0.:
                                self.lheat[i][j].append([lh[0], 0.])
                        self.state[i][j] = True
                    else:
                        message = 'point ({:d},{:d})'.format(i, j)
                        message = message + ' already activated'
                        print(message)

        if shape == 'circle':
            initial_point_x = int(initial_point[0])
            initial_point_y = int(initial_point[1])
            radius = int(final_point)
            for i in range(self.size[0]):
                for j in range(self.size[1]):
                    value = (i-initial_point_x)**2+(j-initial_point_y)**2
                    length = np.sqrt(value)
                    if length <= radius:
                        if self.state[i][j] is False:
                            value = self.temperature[i][j][0]
                            index_value = self.materials_index[i][j]
                            self.temperature[i][j][0] = value + \
                                self.materials[index_value].tadi(
                                    self.temperature[i][j][0])
                            self.rho[i][j] = self.materials[index_value].rhoa(
                                self.temperature[i][j][0])
                            self.Cp[i][j] = self.materials[index_value].cpa(
                                self.temperature[i][j][0])
                            self.k[i][j] = self.materials[index_value].ka(
                                self.temperature[i][j][0])
                            self.lheat[i][j] = []
                            valh = self.materials[index_value].lheata()
                            self.latent_heat[i][j] = valh
                            for lh in self.latent_heat[i][j]:
                                value = self.temperature[i][j][0] < lh[0]
                                if value and lh[1] > 0.:
                                    self.lheat[i][j].append([lh[0], 0.])
                                value = self.temperature[i][j][0] > lh[0]
                                if value and lh[1] > 0.:
                                    self.lheat[i][j].append([lh[0], lh[1]])
                                value = self.temperature[i][j][0] < lh[0]
                                if value and lh[1] < 0.:
                                    self.lheat[i][j].append([lh[0], -lh[1]])
                                value = self.temperature[i][j][0] > lh[0]
                                if value and lh[1] < 0.:
                                    self.lheat[i][j].append([lh[0], 0.])
                            self.state[i][j] = True
                        else:
                            message = 'point ({:d},{:d})'.format(i, j)
                            message = message + ' already activated'
                            print(message)

    def deactivate(self, initial_point, final_point, shape='square'):
        """Deactivation of the material.

        Deactivates a given piece of material. If shape is 'square', then the
        initial_point is the tuple (x,y) of the bottom left point and the
        final_point is the tuple (x,y) of the top right point. If the shape is
        'circle', the initial_point is the tuple (x,y) of the center of the
        circle and final_point is its radius.

        """
        # check the validity of inputs
        if isinstance(shape, str):
            if shape == 'square':
                value = isinstance(initial_point, tuple)
                if value and isinstance(final_point, tuple):
                    condition = len(initial_point) == 2
                    condition = condition and len(final_point) == 2
                else:
                    condition = False
            elif shape == 'circle':
                value = isinstance(final_point, int)
                value = value or isinstance(final_point, float)
                value = value and isinstance(initial_point, tuple)
                if value:
                    condition = len(initial_point) == 2
                else:
                    condition = False
            else:
                condition = False
        else:
            condition = False
        if not condition:
            raise ValueError

        if shape == 'square':
            initial_point_x = int(initial_point[0])
            initial_point_y = int(initial_point[1])
            final_point_x = int(final_point[0])
            final_point_y = int(final_point[1])
            for i in range(initial_point_x, final_point_x):
                for j in range(initial_point_y, final_point_y):
                    if self.state[i][j] is True:
                        value = self.temperature[i][j][0]
                        self.temperature[i][j][0] = value - \
                            self.materials[self.materials_index[i][j]].tadd(
                                self.temperature[i][j][0])
                        value = self.materials_index[i][j]
                        self.rho[i][j] = self.materials[value].rho0(
                            self.temperature[i][j][0])
                        self.Cp[i][j] = self.materials[value].cp0(
                            self.temperature[i][j][0])
                        self.k[i][j] = self.materials[value].k0(
                            self.temperature[i][j][0])
                        self.lheat[i][j] = []
                        valh = self.materials[value].lheat0()
                        self.latent_heat[i][j] = valh
                        for lh in self.latent_heat[i][j]:
                            cond = self.temperature[i][j][0] < lh[0]
                            if cond and lh[1] > 0.:
                                self.lheat[i][j].append([lh[0], 0.])
                            cond = self.temperature[i][j][0] > lh[0]
                            if cond and lh[1] > 0.:
                                self.lheat[i][j].append([lh[0], lh[1]])
                            cond = self.temperature[i][j][0] < lh[0]
                            if cond and lh[1] < 0.:
                                self.lheat[i][j].append([lh[0], -lh[1]])
                            cond = self.temperature[i][j][0] > lh[0]
                            if cond and lh[1] < 0.:
                                self.lheat[i][j].append([lh[0], 0.])
                        self.state[i][j] = False
                    else:
                        message = 'point ({:d},{:d})'.format(i, j)
                        message = message + ' already deactivated'
                        print(message)

        if shape == 'circle':
            initial_point_x = int(initial_point[0])
            initial_point_y = int(initial_point[1])
            radius = int(final_point)
            for i in range(self.size[0]):
                for j in range(self.size[1]):
                    value = (i-initial_point_x)**2+(j-initial_point_y)**2
                    length = np.sqrt(value)
                    if length <= radius:
                        if self.state[i][j] is False:
                            value = self.temperature[i][j][0]
                            index_value = self.materials_index[i][j]
                            self.temperature[i][j][0] = value - \
                                self.materials[index_value].tadd(
                                    self.temperature[i][j][0])
                            self.rho[i][j] = self.materials[index_value].rho0(
                                self.temperature[i][j][0])
                            self.Cp[i][j] = self.materials[index_value].cp0(
                                self.temperature[i][j][0])
                            self.k[i][j] = self.materials[index_value].k0(
                                self.temperature[i][j][0])
                            self.lheat[i][j] = []
                            valh = self.materials[index_value].lheat0()
                            self.latent_heat[i][j] = valh
                            for lh in self.latent_heat[i][j]:
                                value = self.temperature[i][j][0] < lh[0]
                                if value and lh[1] > 0.:
                                    self.lheat[i][j].append([lh[0], 0.])
                                value = self.temperature[i][j][0] > lh[0]
                                if value and lh[1] > 0.:
                                    self.lheat[i][j].append([lh[0], lh[1]])
                                value = self.temperature[i][j][0] < lh[0]
                                if value and lh[1] < 0.:
                                    self.lheat[i][j].append([lh[0], -lh[1]])
                                value = self.temperature[i][j][0] > lh[0]
                                if value and lh[1] < 0.:
                                    self.lheat[i][j].append([lh[0], 0.])
                            self.state[i][j] = False
                        else:
                            message = 'point ({:d},{:d})'.format(i, j)
                            message = message + ' already deactivated'
                            print(message)

    def square(self, material='Gd', initial_point=(3, 3), length=(3, 3),
               state=False, materials_path=False):
        """Material adding with rectangle shape.

        Adds a new material with a rectangel shape, where initial_point is the
        bottom left (x,y) tuple, length is the length along the two axis, state
        is the initial state of the material and materials_path is the absolute
        path of the materials database.

        """
        # check the validity of inputs
        value = isinstance(initial_point, tuple)
        if value and isinstance(length, tuple):
            cond1 = len(initial_point) == 2
            cond1 = cond1 and len(length) == 2
        else:
            cond1 = False
        cond2 = isinstance(material, str)
        cond3 = isinstance(state, bool)
        cond4 = isinstance(materials_path, str) or materials_path is False
        if not cond1 and cond2 and cond3 and cond4:
            raise ValueError

        initial_point_x = int(initial_point[0])
        initial_point_y = int(initial_point[1])
        final_point_x = initial_point_x + int(length[0])
        final_point_y = initial_point_y + int(length[1])
        if material in self.materials_name:
            index = self.materials_name.index(material)
        else:
            index = len(self.materials)
            self.materials_name.append(material)
            if materials_path is False:
                value = self.materials_name[index]
                tadi = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'tadi.txt'
                tadd = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'tadd.txt'
                cpa = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'cpa.txt'
                cp0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'cp0.txt'
                k0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'k0.txt'
                ka = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'ka.txt'
                rho0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'rho0.txt'
                rhoa = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'rhoa.txt'
                lheat0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'lheat0.txt'
                lheata = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'lheata.txt'
                self.materials.append(mats.CalMatPro(
                    tadi, tadd, cpa, cp0, k0, ka, rho0, rhoa, lheat0, lheata))
            else:
                value = self.materials_name[index]
                tadi = materials_path + value + '/' + 'tadi.txt'
                tadd = materials_path + value + '/' + 'tadd.txt'
                cpa = materials_path + value + '/' + 'cpa.txt'
                cp0 = materials_path + value + '/' + 'cp0.txt'
                k0 = materials_path + value + '/' + 'k0.txt'
                ka = materials_path + value + '/' + 'ka.txt'
                rho0 = materials_path + value + '/' + 'rho0.txt'
                rhoa = materials_path + value + '/' + 'rhoa.txt'
                lheat0 = materials_path + value + '/' + 'lheat0.txt'
                lheata = materials_path + value + '/' + 'lheata.txt'
                self.materials.append(mats.CalMatPro(
                    tadi, tadd, cpa, cp0, k0, ka, rho0, rhoa, lheat0, lheata))

        for i in range(initial_point_x, final_point_x):
            for j in range(initial_point_y, final_point_y):
                if state is False:
                    self.state[i][j] = False
                    self.materials_index[i][j] = index
                    self.rho[i][j] = self.materials[index].rho0(
                        self.temperature[i][j][0])
                    self.Cp[i][j] = self.materials[index].cp0(
                        self.temperature[i][j][0])
                    self.k[i][j] = self.materials[index].k0(
                        self.temperature[i][j][0])
                    self.lheat[i][j] = []
                    valh = self.materials[index].lheat0()
                    self.latent_heat[i][j] = valh
                    for lh in self.latent_heat[i][j]:
                        if self.temperature[i][j][0] < lh[0] and lh[1] > 0:
                            self.lheat[i][j].append([lh[0], 0.])
                        if self.temperature[i][j][0] > lh[0] and lh[1] > 0:
                            self.lheat[i][j].append([lh[0], lh[1]])
                        if self.temperature[i][j][0] < lh[0] and lh[1] < 0:
                            self.lheat[i][j].append([lh[0], -lh[1]])
                        if self.temperature[i][j][0] > lh[0] and lh[1] < 0:
                            self.lheat[i][j].append([lh[0], 0.])

                else:
                    self.state[i][j] = True
                    self.materials_index[i][j] = index
                    self.rho[i][j] = self.materials[index].rhoa(
                        self.temperature[i][j][0])
                    self.Cp[i][j] = self.materials[index].cpa(
                        self.temperature[i][j][0])
                    self.k[i][j] = self.materials[index].ka(
                        self.temperature[i][j][0])
                    self.lheat[i][j] = []
                    valh = self.materials[index].lheata()
                    self.latent_heat[i][j] = valh
                    for lh in self.latent_heat[i][j]:
                        if self.temperature[i][j][0] < lh[0] and lh[1] > 0:
                            self.lheat[i][j].append([lh[0], 0.])
                        if self.temperature[i][j][0] > lh[0] and lh[1] > 0:
                            self.lheat[i][j].append([lh[0], lh[1]])
                        if self.temperature[i][j][0] < lh[0] and lh[1] < 0:
                            self.lheat[i][j].append([lh[0], -lh[1]])
                        if self.temperature[i][j][0] > lh[0] and lh[1] < 0:
                            self.lheat[i][j].append([lh[0], 0.])

    def circle(self, material='Gd', initial_point=(3, 3), radius=3,
               state=False, materials_path=False):
        """Material adding with circle shape.

        Adds a new material with a circle shape, where initial_point is the
        (x,y) tuple of the center of the circle, radius is the radius of the
        circle, state is the initial state of the material and materials_path
        is the absolute path of the materials database.

        """
        # check the validity of inputs
        if isinstance(initial_point, tuple):
            cond1 = len(initial_point) == 2
        else:
            cond1 = False
        cond2 = isinstance(radius, int) or isinstance(radius, float)
        cond3 = isinstance(material, str)
        cond4 = isinstance(state, bool)
        cond5 = isinstance(materials_path, str) or materials_path is False
        if not cond1 and cond2 and cond3 and cond4 and cond5:
            raise ValueError

        initial_point_x = int(initial_point[0])
        initial_point_y = int(initial_point[1])
        if material in self.materials_name:
            index = self.materials_name.index(material)
        else:
            index = len(self.materials)
            self.materials_name.append(material)
            if materials_path is False:
                value = self.materials_name[index]
                tadi = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'tadi.txt'
                tadd = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'tadd.txt'
                cpa = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'cpa.txt'
                cp0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'cp0.txt'
                k0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'k0.txt'
                ka = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'ka.txt'
                rho0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'rho0.txt'
                rhoa = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'rhoa.txt'
                lheat0 = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'lheat0.txt'
                lheata = os.path.dirname(os.path.realpath(__file__)) + \
                    '/../../database/' + value + '/' + 'lheata.txt'
                self.materials.append(mats.CalMatPro(
                    tadi, tadd, cpa, cp0, k0, ka, rho0, rhoa, lheat0, lheata))
            else:
                value = self.materials_name[index]
                tadi = materials_path + value + '/' + 'tadi.txt'
                tadd = materials_path + value + '/' + 'tadd.txt'
                cpa = materials_path + value + '/' + 'cpa.txt'
                cp0 = materials_path + value + '/' + 'cp0.txt'
                k0 = materials_path + value + '/' + 'k0.txt'
                ka = materials_path + value + '/' + 'ka.txt'
                rho0 = materials_path + value + '/' + 'rho0.txt'
                rhoa = materials_path + value + '/' + 'rhoa.txt'
                lheat0 = materials_path + value + '/' + 'lheat0.txt'
                lheata = materials_path + value + '/' + 'lheata.txt'
                self.materials.append(mats.CalMatPro(
                    tadi, tadd, cpa, cp0, k0, ka, rho0, rhoa, lheat0, lheata))

        for i in range(self.size[0]):
            for j in range(self.size[1]):
                length = np.sqrt((i-initial_point_x)**2+(j-initial_point_y)**2)
                if length <= radius:
                    if state is False:
                        self.state[i][j] = False
                        self.materials_index[i][j] = index
                        self.rho[i][j] = self.materials[index].rho0(
                            self.temperature[i][j][0])
                        self.Cp[i][j] = self.materials[index].cp0(
                            self.temperature[i][j][0])
                        self.k[i][j] = self.materials[index].k0(
                            self.temperature[i][j][0])
                        self.lheat[i][j] = []
                        valh = self.materials[index].lheat0()
                        self.latent_heat[i][j] = valh
                        for lh in self.latent_heat[i][j]:
                            if self.temperature[i][j][0] < lh[0] and lh[1] > 0:
                                self.lheat[i][j].append([lh[0], 0.])
                            if self.temperature[i][j][0] > lh[0] and lh[1] > 0:
                                self.lheat[i][j].append([lh[0], lh[1]])
                            if self.temperature[i][j][0] < lh[0] and lh[1] < 0:
                                self.lheat[i][j].append([lh[0], -lh[1]])
                            if self.temperature[i][j][0] > lh[0] and lh[1] < 0:
                                self.lheat[i][j].append([lh[0], 0.])

                    else:
                        self.state[i][j] = True
                        self.materials_index[i][j] = index
                        self.rho[i][j] = self.materials[index].rhoa(
                            self.temperature[i][j][0])
                        self.Cp[i][j] = self.materials[index].cpa(
                            self.temperature[i][j][0])
                        self.k[i][j] = self.materials[index].ka(
                            self.temperature[i][j][0])
                        self.lheat[i][j] = []
                        valh = self.materials[index].lheata()
                        self.latent_heat[i][j] = valh
                        for lh in self.latent_heat[i][j]:
                            if self.temperature[i][j][0] < lh[0] and lh[1] > 0:
                                self.lheat[i][j].append([lh[0], 0.])
                            if self.temperature[i][j][0] > lh[0] and lh[1] > 0:
                                self.lheat[i][j].append([lh[0], lh[1]])
                            if self.temperature[i][j][0] < lh[0] and lh[1] < 0:
                                self.lheat[i][j].append([lh[0], -lh[1]])
                            if self.temperature[i][j][0] > lh[0] and lh[1] < 0:
                                self.lheat[i][j].append([lh[0], 0.])

    def power_add(self, initial_point, final_point, power, shape='square',
                  power_type='Q'):
        """Power adding.

        Adds a power matrix to the thermal object. If shape is 'square', then
        the initial_point is the tuple (x,y) of the bottom left point and the
        final_point is the tuple (x,y) of the top right point. If the shape is
        'circle', the initial_point is the tuple (x,y) of the center of the
        circle and final_point is its radius. power is the value of the power
        to add, and power type is the type of power to be introduced, which has
        the value 'Q' if it is temperature dependent and 'Q0' if it is
        temperature independent.

        """
        # check the validity of inputs
        if isinstance(shape, str):
            if shape == 'square':
                value = isinstance(initial_point, tuple)
                if value and isinstance(final_point, tuple):
                    cond1 = len(initial_point) == 2
                    cond1 = cond1 and len(final_point) == 2
                else:
                    cond1 = False
            elif shape == 'circle':
                value = isinstance(final_point, int)
                value = value or isinstance(final_point, float)
                value = value and isinstance(initial_point, tuple)
                if value:
                    cond1 = len(initial_point) == 2
                else:
                    cond1 = False
            else:
                cond1 = False
        else:
            cond1 = False
        cond2 = isinstance(power, int) or isinstance(power, float)
        if isinstance(power_type, str):
            if power_type == 'Q' or power_type == 'Q0':
                cond3 = True
            else:
                cond3 = False
        else:
            cond3 = False
        if not cond1 and cond2 and cond3:
            raise ValueError

        if power_type == 'Q':
            if shape == 'square':
                initial_point_x = int(initial_point[0])
                initial_point_y = int(initial_point[1])
                final_point_x = int(final_point[0])
                final_point_y = int(final_point[1])
                for i in range(initial_point_x, final_point_x):
                    for j in range(initial_point_y, final_point_y):
                        self.Q[i][j] = power
            if shape == 'circle':
                initial_point_x = int(initial_point[0])
                initial_point_y = int(initial_point[1])
                radius = int(final_point)
                for i in range(self.size[0]):
                    for j in range(self.size[1]):
                        value = (i-initial_point_x)**2+(j-initial_point_y)**2
                        length = np.sqrt(value)
                        if length <= radius:
                            self.Q[i][j] = power

        if power_type == 'Q0':
            if shape == 'square':
                initial_point_x = int(initial_point[0])
                initial_point_y = int(initial_point[1])
                final_point_x = int(final_point[0])
                final_point_y = int(final_point[1])
                for i in range(initial_point_x, final_point_x):
                    for j in range(initial_point_y, final_point_y):
                        self.Q0[i][j] = power
            if shape == 'circle':
                initial_point_x = int(initial_point[0])
                initial_point_y = int(initial_point[1])
                radius = int(final_point)
                for i in range(self.size[0]):
                    for j in range(self.size[1]):
                        value = (i-initial_point_x)**2+(j-initial_point_y)**2
                        length = np.sqrt(value)
                        if length <= radius:
                            self.Q0[i][j] = power

    def power_reset(self, power_type='Q'):
        """Power reset.

        Resets the power matrix with power_type 'Q' or 'Q0', which corresponds
        to the power temperature dependent and temperature independent,
        respectively.

        """
        # check the validity of inputs
        if isinstance(power_type, str):
            if power_type == 'Q' or power_type == 'Q0':
                condition = True
            else:
                condition = False
        else:
            condition = False
        if not condition:
            raise ValueError

        self.Q = []
        self.Q0 = []
