def save_mesh_and_kappa_to_h5(mesh_to_h5,subdomains_to_h5,boundaries_to_h5,Field_calc_param):
    print("Number of mesh elements: ",mesh_to_h5.num_cells())
    #due to the glitch with the ghost model and subdomains. Used only for c-c multicontact, so always with floating
    V0_r=FunctionSpace(mesh_to_h5,'DG',0)
    kappa_r=Function(V0_r)
    default_material=Field_calc_param.default_material

    [cond_GM, perm_GM]=DielectricProperties(3).get_dielectrics(Field_calc_param.frequenc)        #3 for grey matter and so on (numeration as in voxel_data)
    [cond_WM, perm_WM]=DielectricProperties(2).get_dielectrics(Field_calc_param.frequenc)
    [cond_CSF, perm_CSF]=DielectricProperties(1).get_dielectrics(Field_calc_param.frequenc)
    [cond_default,perm_default]=DielectricProperties(default_material).get_dielectrics(Field_calc_param.frequenc)

    from GUI_inp_dict import d as d_encap
    [cond_encap, perm_encap]=DielectricProperties(d_encap['encap_tissue_type']).get_dielectrics(Field_calc_param.frequenc)
    cond_encap=cond_encap*d_encap['encap_scaling_cond']
    perm_encap=perm_encap*d_encap['encap_scaling_perm']

    k_val_r=[cond_default*0.001,cond_CSF*0.001,cond_WM*0.001,cond_GM*0.001,cond_encap*0.001,1000.0]
    help = np.asarray(subdomains_to_h5.array(), dtype=np.int32)
    kappa_r.vector()[:] = np.choose(help, k_val_r)

    hdf = HDF5File(mesh_to_h5.mpi_comm(), os.environ['PATIENTDIR']+'/Results_adaptive/Mesh_to_solve.h5', 'w')
    hdf.write(mesh_to_h5, "/mesh")
    hdf.write(subdomains_to_h5, "/subdomains")
    hdf.write(boundaries_to_h5, "/boundaries")
    hdf.write(kappa_r, "/kappa_r")

    file=File(os.environ['PATIENTDIR']+'/Results_adaptive/Last_subdomains_map.pvd')
    file<<subdomains_to_h5
    file=File(os.environ['PATIENTDIR']+'/Results_adaptive/Last_conductivity_map.pvd')
    file<<kappa_r

    if Field_calc_param.EQS_mode == 'EQS':
        V0_i=FunctionSpace(mesh_to_h5,'DG',0)
        kappa_i=Function(V0_i)
        omega_eps0=2*np.pi*130.0*8.854e-12           #2*pi*f*eps0
        k_val_i=[omega_eps0*perm_default*0.001,omega_eps0*perm_CSF*0.001,omega_eps0*perm_WM*0.001,omega_eps0*perm_GM*0.001,1*omega_eps0*perm_encap*0.001,1000000000*omega_eps0]
        help = np.asarray(subdomains_to_h5.array(), dtype=np.int32)
        kappa_i.vector()[:] = np.choose(help, k_val_i)

        hdf.write(kappa_i, "/kappa_i")
        file=File(os.environ['PATIENTDIR']+'/Results_adaptive/Last_permittivity_map.pvd')
        file<<kappa_i

    if Field_calc_param.anisotropy == 1:

        #we get unscaled tensors and scale them with conductivity here. This approach is needed only for MPI
        c00 = MeshFunction("double", mesh_to_h5, 3, 0.0)
        c01 = MeshFunction("double", mesh_to_h5, 3, 0.0)
        c02 = MeshFunction("double", mesh_to_h5, 3, 0.0)
        c11 = MeshFunction("double", mesh_to_h5, 3, 0.0)
        c12 = MeshFunction("double", mesh_to_h5, 3, 0.0)
        c22 = MeshFunction("double", mesh_to_h5, 3, 0.0)

        hdf2 = HDF5File(mesh_to_h5.mpi_comm(), os.environ['PATIENTDIR']+"/Results_adaptive/Tensors_to_solve_num_el_"+str(mesh_to_h5.num_cells())+".h5", "r")
        hdf2.read(c00, "/c00")
        hdf2.read(c01, "/c01")
        hdf2.read(c02, "/c02")
        hdf2.read(c11, "/c11")
        hdf2.read(c12, "/c12")
        hdf2.read(c22, "/c22")
        hdf2.close()

        cell_Anis = MeshFunction('bool',mesh_to_h5,3)
        cell_Anis.set_all(False)

        for cell in cells(mesh_to_h5):

            scale_cond=k_val_r[subdomains_to_h5[cell]]

            if c00[cell]!=1.0:
                cell_Anis[cell]=True

            c00[cell]=c00[cell]*scale_cond
            c01[cell]=c01[cell]*scale_cond
            c02[cell]=c02[cell]*scale_cond
            c11[cell]=c11[cell]*scale_cond
            c12[cell]=c12[cell]*scale_cond
            c22[cell]=c22[cell]*scale_cond


        file=File(os.environ['PATIENTDIR']+'/Tensors/c00_mapped.pvd')
        file<<c00,mesh_to_h5
        file=File(os.environ['PATIENTDIR']+'/Tensors/c01_mapped.pvd')
        file<<c01,mesh_to_h5
        file=File(os.environ['PATIENTDIR']+'/Tensors/c02_mapped.pvd')
        file<<c02,mesh_to_h5
        file=File(os.environ['PATIENTDIR']+'/Tensors/c11_mapped.pvd')
        file<<c11,mesh_to_h5
        file=File(os.environ['PATIENTDIR']+'/Tensors/c12_mapped.pvd')
        file<<c12,mesh_to_h5
        file=File(os.environ['PATIENTDIR']+'/Tensors/c22_mapped.pvd')
        file<<c22,mesh_to_h5

        file=File(os.environ['PATIENTDIR']+'/Tensors/Anis_cells.pvd')
        file<<cell_Anis,mesh_to_h5

        hdf.write(c00, "/c00")
        hdf.write(c01, "/c01")
        hdf.write(c02, "/c02")
        hdf.write(c11, "/c11")
        hdf.write(c12, "/c12")
        hdf.write(c22, "/c22")

    hdf.close()

    return True
Example #2
0
def get_field(mesh_sol, Domains, subdomains, boundaries_sol, Field_calc_param):

    set_log_active(False)  #turns off debugging info
    print("_________________________")
    parameters['linear_algebra_backend'] = 'PETSc'

    [cond_GM, perm_GM] = DielectricProperties(3).get_dielectrics(
        Field_calc_param.frequenc
    )  #3 for grey matter and so on (numeration as in voxel_data)
    [cond_WM, perm_WM
     ] = DielectricProperties(2).get_dielectrics(Field_calc_param.frequenc)
    [cond_CSF, perm_CSF
     ] = DielectricProperties(1).get_dielectrics(Field_calc_param.frequenc)

    [cond_default, perm_default] = DielectricProperties(
        Field_calc_param.default_material).get_dielectrics(
            Field_calc_param.frequenc)

    from GUI_inp_dict import d as d_encap
    [cond_encap, perm_encap
     ] = DielectricProperties(d_encap['encap_tissue_type']).get_dielectrics(
         Field_calc_param.frequenc)
    cond_encap = cond_encap * d_encap['encap_scaling_cond']
    perm_encap = perm_encap * d_encap['encap_scaling_perm']

    if Field_calc_param.Solver_type == 'Default':
        Solver_type = choose_solver_for_me(
            Field_calc_param.EQS_mode, Domains.Float_contacts
        )  #choses solver basing on the Laplace formulation and whether the floating conductors are used
    else:
        Solver_type = Field_calc_param.Solver_type  # just get the solver directly

    conductivities = [cond_default, cond_GM, cond_WM, cond_CSF, cond_encap]
    rel_permittivities = [perm_default, perm_GM, perm_WM, perm_CSF, perm_encap]

    # to get conductivity (and permittivity if EQS formulation) mapped accrodingly to the subdomains. k_val_r is just a list of conductivities (S/mm!) in a specific order to scale the cond. tensor
    from FEM_in_spectrum import get_dielectric_properties_from_subdomains
    kappa, k_val_r = get_dielectric_properties_from_subdomains(
        mesh_sol, subdomains, Field_calc_param.EQS_mode,
        Domains.Float_contacts, conductivities, rel_permittivities,
        Field_calc_param.frequenc)
    file = File('/opt/Patient/Results_adaptive/Last_subdomains_map.pvd')
    file << subdomains
    file = File('/opt/Patient/Results_adaptive/Last_conductivity_map.pvd')
    file << kappa[0]
    if Field_calc_param.EQS_mode == 'EQS':
        file = File('/opt/Patient/Results_adaptive/Last_permittivity_map.pvd')
        file << kappa[1]

    if Field_calc_param.anisotropy == 1:
        # order xx,xy,xz,yy,yz,zz
        c00 = MeshFunction("double", mesh_sol, 3, 0.0)
        c01 = MeshFunction("double", mesh_sol, 3, 0.0)
        c02 = MeshFunction("double", mesh_sol, 3, 0.0)
        c11 = MeshFunction("double", mesh_sol, 3, 0.0)
        c12 = MeshFunction("double", mesh_sol, 3, 0.0)
        c22 = MeshFunction("double", mesh_sol, 3, 0.0)

        # load the diffusion tensor (should be normalized beforehand)
        hdf = HDF5File(
            mesh_sol.mpi_comm(),
            "/opt/Patient/Results_adaptive/Tensors_to_solve_num_el_" +
            str(mesh_sol.num_cells()) + ".h5", "r")
        hdf.read(c00, "/c00")
        hdf.read(c01, "/c01")
        hdf.read(c02, "/c02")
        hdf.read(c11, "/c11")
        hdf.read(c12, "/c12")
        hdf.read(c22, "/c22")
        hdf.close()

        unscaled_tensor = [c00, c01, c02, c11, c12, c22]

        # to get tensor scaled by the conductivity map (twice send Field_calc_param.frequenc to always get unscaled ellipsoid tensor for visualization)
        from FEM_in_spectrum import get_scaled_cond_tensor
        Cond_tensor = get_scaled_cond_tensor(mesh_sol,
                                             subdomains,
                                             Field_calc_param.frequenc,
                                             Field_calc_param.frequenc,
                                             unscaled_tensor,
                                             k_val_r,
                                             plot_tensors=True)
    else:
        Cond_tensor = False  #just to initialize

    #In case of current-controlled stimulation, Dirichlet_bc or the whole potential distribution will be scaled afterwards (due to the system's linearity)
    from FEM_in_spectrum import get_solution_space_and_Dirichlet_BC
    V_space, Dirichlet_bc, ground_index, facets = get_solution_space_and_Dirichlet_BC(
        Field_calc_param.external_grounding, Field_calc_param.c_c, mesh_sol,
        subdomains, boundaries_sol, Field_calc_param.element_order,
        Field_calc_param.EQS_mode, Domains.Contacts, Domains.fi)
    #ground index refers to the ground in .med/.msh file

    print("dofs: ", (max(V_space.dofmap().dofs()) + 1))
    print("N of elements: ", mesh_sol.num_cells())

    #facets = MeshFunction('size_t',mesh_sol,2)
    #facets.set_all(0)
    if Field_calc_param.external_grounding == False:  # otherwise we have it already from get_solution_space_and_Dirichlet_BC()
        facets.array()[boundaries_sol.array() ==
                       Domains.Contacts[ground_index]] = 1
    dsS = Measure("ds", domain=mesh_sol, subdomain_data=facets)
    Ground_surface_size = assemble(1.0 * dsS(1))
    dx = Measure("dx", domain=mesh_sol)

    # to solve the Laplace equation div(kappa*grad(phi))=0   (variational form: a(u,v)=L(v))
    start_math = tm.time()
    from FEM_in_spectrum import define_variational_form_and_solve
    phi_sol = define_variational_form_and_solve(V_space, Dirichlet_bc, kappa,
                                                Field_calc_param.EQS_mode,
                                                Cond_tensor, Solver_type)
    minutes = int((tm.time() - start_math) / 60)
    secnds = int(tm.time() - start_math) - minutes * 60
    print("--- assembled and solved in ", minutes, " min ", secnds, " s ---")

    if Field_calc_param.EQS_mode == 'EQS':
        (phi_r_sol, phi_i_sol) = phi_sol.split(deepcopy=True)
    else:
        phi_r_sol = phi_sol
        phi_i_sol = Function(V_space)
        phi_i_sol.vector()[:] = 0.0

    # get current flowing through the grounded contact and the electric field in the whole domain
    from FEM_in_spectrum import get_current
    J_ground, E_field, E_field_im = get_current(mesh_sol,
                                                facets,
                                                boundaries_sol,
                                                Field_calc_param.element_order,
                                                Field_calc_param.EQS_mode,
                                                Domains.Contacts,
                                                kappa,
                                                Cond_tensor,
                                                phi_r_sol,
                                                phi_i_sol,
                                                ground_index,
                                                get_E_field=True)

    #print("J_ground_unscaled: ",J_ground)
    # If EQS, J_ground is a complex number. If QS, E_field_im is a null function

    # to get current density function which is required for mesh refinement when checking current convergence
    j_dens_real, j_dens_im = get_current_density(
        mesh_sol, Field_calc_param.element_order, Field_calc_param.EQS_mode,
        kappa, Cond_tensor, E_field, E_field_im)
    # If QS, j_dens_im is null function

    # will be used for mesh refinement
    j_dens_real_unscaled = j_dens_real.copy(deepcopy=True)
    j_dens_im_unscaled = j_dens_im.copy(deepcopy=True)  #  null function if QS
    import copy
    J_real_unscaled = copy.deepcopy(np.real(J_ground))
    J_im_unscaled = copy.deepcopy(np.imag(J_ground))  # 0 if QS
    # to project the E-field magnitude
    if Field_calc_param.element_order > 1:
        V_normE = FunctionSpace(mesh_sol, "CG",
                                Field_calc_param.element_order - 1)
    else:
        V_normE = FunctionSpace(mesh_sol, "CG", Field_calc_param.element_order)

    #V_across=max(Domains.fi[:], key=abs)    #actually, not across, but against ground!!!

    if Field_calc_param.external_grounding == True and (
            Field_calc_param.c_c == 1 or len(Domains.fi) == 1):
        V_max = max(Domains.fi[:], key=abs)
        V_min = 0.0
    elif -1 * Domains.fi[0] == Domains.fi[
            1]:  # V_across is needed only for 2 active contact systems
        V_min = -1 * abs(Domains.fi[0])
        V_max = abs(Domains.fi[0])
    else:
        V_min = min(Domains.fi[:], key=abs)
        V_max = max(Domains.fi[:], key=abs)
    V_across = V_max - V_min  # this can be negative

    Vertices_get = read_csv(
        '/opt/Patient/Neuron_model_arrays/Vert_of_Neural_model_NEURON.csv',
        delimiter=' ',
        header=None)
    Vertices_array = Vertices_get.values

    Phi_ROI = np.zeros((Vertices_array.shape[0], 4), float)

    for inx in range(Vertices_array.shape[0]):
        pnt = Point(Vertices_array[inx, 0], Vertices_array[inx, 1],
                    Vertices_array[inx, 2])

        Phi_ROI[inx, 0] = Vertices_array[inx, 0]
        Phi_ROI[inx, 1] = Vertices_array[inx, 1]
        Phi_ROI[inx, 2] = Vertices_array[inx, 2]
        if Field_calc_param.c_c == 1:
            phi_r_sol_scaled_on_point = V_across * np.real(
                (phi_r_sol(pnt) + 1j * phi_i_sol(pnt)) / J_ground)
            phi_i_sol_scaled_on_point = V_across * np.imag(
                (phi_r_sol(pnt) + 1j * phi_i_sol(pnt)) / J_ground)
            Phi_ROI[inx, 3] = np.sqrt(
                phi_r_sol_scaled_on_point * phi_r_sol_scaled_on_point +
                phi_i_sol_scaled_on_point * phi_i_sol_scaled_on_point)
        else:
            Phi_ROI[inx, 3] = np.sqrt(
                phi_r_sol(pnt) * phi_r_sol(pnt) +
                phi_i_sol(pnt) * phi_i_sol(pnt))

    np.savetxt('/opt/Patient/Results_adaptive/Phi_' +
               str(Field_calc_param.frequenc) + '.csv',
               Phi_ROI,
               delimiter=" ")  # this is amplitude, actually

    #    #Probe_of_potential
    #    probe_z=np.zeros((100,4),float)
    #    for inx in range(100):
    #        pnt=Point(75.5,78.5,27.865+inx/10.0)
    #        probe_z[inx,0]=75.5
    #        probe_z[inx,1]=78.5
    #        probe_z[inx,2]=27.865+inx/10.0
    #        if Field_calc_param.c_c==1:
    #            phi_r_sol_scaled_on_point=V_across*np.real((phi_r_sol(pnt)+1j*phi_i_sol(pnt))/(J_real_unscaled+1j*J_im_unscaled))
    #            phi_i_sol_scaled_on_point=V_across*np.imag((phi_r_sol(pnt)+1j*phi_i_sol(pnt))/(J_real_unscaled+1j*J_im_unscaled))
    #            probe_z[inx,3]=np.sqrt(phi_r_sol_scaled_on_point*phi_r_sol_scaled_on_point+phi_i_sol_scaled_on_point*phi_i_sol_scaled_on_point)
    #        else:
    #            probe_z[inx,3]=np.sqrt(phi_r_sol(pnt)*phi_r_sol(pnt)+phi_i_sol(pnt)*phi_i_sol(pnt))
    #    np.savetxt('Results_adaptive/Phi_Zprobe'+str(Field_calc_param.frequenc)+'.csv',  probe_z, delimiter=" ")

    #print("Tissue impedance: ", Z_tis)

    #=============================================================================#
    if Field_calc_param.c_c == 1 or Field_calc_param.CPE == 1:

        Z_tissue = V_across / J_ground  # Tissue impedance
        print("Tissue impedance: ", Z_tissue)

        if Field_calc_param.CPE == 1:

            if len(Domains.fi) > 2:
                print(
                    "Currently, CPE can be used only for simulations with two contacts. Please, assign the rest to 'None'"
                )
                raise SystemExit

            from GUI_inp_dict import d as d_cpe
            CPE_param = [
                d_cpe["K_A"], d_cpe["beta"], d_cpe["K_A_ground"],
                d_cpe["beta_ground"]
            ]

            from FEM_in_spectrum import get_CPE_corrected_Dirichlet_BC
            Dirichlet_bc_with_CPE, total_impedance = get_CPE_corrected_Dirichlet_BC(
                Field_calc_param.external_grounding, facets, boundaries_sol,
                CPE_param, Field_calc_param.EQS_mode,
                Field_calc_param.frequenc, Field_calc_param.frequenc,
                Domains.Contacts, Domains.fi, V_across, Z_tissue, V_space)

            print(
                "Solving for an adjusted potential on contacts to account for CPE"
            )
            start_math = tm.time()
            # to solve the Laplace equation for the adjusted Dirichlet
            phi_sol_CPE = define_variational_form_and_solve(
                V_space, Dirichlet_bc_with_CPE, kappa,
                Field_calc_param.EQS_mode, Cond_tensor, Solver_type)
            minutes = int((tm.time() - start_math) / 60)
            secnds = int(tm.time() - start_math) - minutes * 60
            print("--- assembled and solved in ", minutes, " min ", secnds,
                  " s ")
            if Field_calc_param.EQS_mode == 'EQS':
                (phi_r_CPE, phi_i_CPE) = phi_sol_CPE.split(deepcopy=True)
            else:
                phi_r_CPE = phi_sol_CPE
                phi_i_CPE = Function(V_space)
                phi_i_CPE.vector()[:] = 0.0

            # get current flowing through the grounded contact and the electric field in the whole domain
            J_ground_CPE, E_field_CPE, E_field_im_CPE = get_current(
                mesh_sol,
                facets,
                boundaries_sol,
                Field_calc_param.element_order,
                Field_calc_param.EQS_mode,
                Domains.Contacts,
                kappa,
                Cond_tensor,
                phi_r_CPE,
                phi_i_CPE,
                ground_index,
                get_E_field=True)
            # If EQS, J_ground is a complex number. If QS, E_field_CPE is a null function

            # to get current density function which is required for mesh refinement when checking current convergence
            j_dens_real_CPE, j_dens_im_CPE = get_current_density(
                mesh_sol, Field_calc_param.element_order,
                Field_calc_param.EQS_mode, kappa, Cond_tensor, E_field_CPE,
                E_field_im_CPE)
            # If QS, j_dens_im is null function

            # will be used for mesh refinement
            j_dens_real_unscaled = j_dens_real_CPE.copy(deepcopy=True)
            j_dens_im_unscaled = j_dens_im_CPE.copy(deepcopy=True)
            J_real_unscaled = copy.deepcopy(np.real(J_ground))
            J_im_unscaled = copy.deepcopy(np.imag(J_ground))

            E_norm = project(sqrt(
                inner(E_field_CPE, E_field_CPE) +
                inner(E_field_im_CPE, E_field_im_CPE)),
                             V_normE,
                             solver_type="cg",
                             preconditioner_type="amg")
            max_E = E_norm.vector().max()

            file = File('/opt/Patient/Results_adaptive/E_ampl_' +
                        str(Field_calc_param.EQS_mode) + '.pvd')
            file << E_norm, mesh_sol
            file = File('/opt/Patient/Results_adaptive/Last_Phi_r_field_' +
                        str(Field_calc_param.EQS_mode) + '.pvd')
            file << phi_r_CPE, mesh_sol
            if Field_calc_param.EQS_mode == 'EQS':
                file = File(
                    '/opt/Patient/Results_adaptive/Last_Phi_im_field_' +
                    str(Field_calc_param.EQS_mode) + '.pvd')
                file << phi_i_CPE, mesh_sol

            return phi_r_CPE, phi_i_CPE, E_field_CPE, E_field_im_CPE, max_E, J_real_unscaled, J_im_unscaled, j_dens_real_unscaled, j_dens_im_unscaled

        if Field_calc_param.c_c == 1:
            if Field_calc_param.EQS_mode == 'EQS':  # For EQS, we need to scale the potential on boundaries (because the error is absolute) and recompute field, etc. Maybe we can scale them also directly?
                Dirichlet_bc_scaled = []
                for bc_i in range(
                        len(Domains.Contacts)
                ):  #CPE estimation is valid only for one activa and one ground contact configuration
                    if Field_calc_param.EQS_mode == 'EQS':
                        if Domains.fi[bc_i] != 0.0:
                            Active_with_CC = V_across * V_across / J_ground  #(impedance * current through the contact (V_across coincides with the assigned current magnitude))
                            Dirichlet_bc_scaled.append(
                                DirichletBC(V_space.sub(0),
                                            np.real(Active_with_CC),
                                            boundaries_sol,
                                            Domains.Contacts[bc_i]))
                            Dirichlet_bc_scaled.append(
                                DirichletBC(V_space.sub(1),
                                            np.imag(Active_with_CC),
                                            boundaries_sol,
                                            Domains.Contacts[bc_i]))
                        else:
                            Dirichlet_bc_scaled.append(
                                DirichletBC(V_space.sub(0), Constant(0.0),
                                            boundaries_sol,
                                            Domains.Contacts[bc_i]))
                            Dirichlet_bc_scaled.append(
                                DirichletBC(V_space.sub(1), Constant(0.0),
                                            boundaries_sol,
                                            Domains.Contacts[bc_i]))

                if Field_calc_param.external_grounding == True:
                    if Field_calc_param.EQS_mode == 'EQS':
                        Dirichlet_bc_scaled.append(
                            DirichletBC(V_space.sub(0), 0.0, facets, 1))
                        Dirichlet_bc_scaled.append(
                            DirichletBC(V_space.sub(1), 0.0, facets, 1))
                    else:
                        Dirichlet_bc_scaled.append(
                            DirichletBC(V_space, 0.0, facets, 1))

                print(
                    "Solving for a scaled potential on contacts (to match the desired current)"
                )
                start_math = tm.time()
                # to solve the Laplace equation for the adjusted Dirichlet
                phi_sol_scaled = define_variational_form_and_solve(
                    V_space, Dirichlet_bc_scaled, kappa,
                    Field_calc_param.EQS_mode, Cond_tensor, Solver_type)
                minutes = int((tm.time() - start_math) / 60)
                secnds = int(tm.time() - start_math) - minutes * 60
                print("--- assembled and solved in ", minutes, " min ", secnds,
                      " s ---")

                (phi_r_sol_scaled,
                 phi_i_sol_scaled) = phi_sol_scaled.split(deepcopy=True)

                # get current flowing through the grounded contact and the electric field in the whole domain
                J_ground_scaled, E_field_scaled, E_field_im_scaled = get_current(
                    mesh_sol,
                    facets,
                    boundaries_sol,
                    Field_calc_param.element_order,
                    Field_calc_param.EQS_mode,
                    Domains.Contacts,
                    kappa,
                    Cond_tensor,
                    phi_r_sol_scaled,
                    phi_i_sol_scaled,
                    ground_index,
                    get_E_field=True)
                # If EQS, J_ground is a complex number. If QS, E_field_im is 0
            else:  # here we can simply scale the potential in the domain and recompute the E-field
                phi_i_sol_scaled = Function(V_space)
                phi_i_sol_scaled.vector()[:] = 0.0
                phi_r_sol_scaled = Function(V_space)
                phi_r_sol_scaled.vector(
                )[:] = V_across * phi_r_sol.vector()[:] / J_ground

                J_ground_scaled, E_field_scaled, E_field_im_scaled = get_current(
                    mesh_sol,
                    facets,
                    boundaries_sol,
                    Field_calc_param.element_order,
                    Field_calc_param.EQS_mode,
                    Domains.Contacts,
                    kappa,
                    Cond_tensor,
                    phi_r_sol_scaled,
                    phi_i_sol_scaled,
                    ground_index,
                    get_E_field=True)
                #E_field_im_scale is a null function

            E_norm = project(sqrt(
                inner(E_field_scaled, E_field_scaled) +
                inner(E_field_im_scaled, E_field_im_scaled)),
                             V_normE,
                             solver_type="cg",
                             preconditioner_type="amg")
            max_E = E_norm.vector().max()

            file = File('/opt/Patient/Results_adaptive/E_ampl_' +
                        str(Field_calc_param.EQS_mode) + '.pvd')
            file << E_norm, mesh_sol
            file = File('/opt/Patient/Results_adaptive/Last_Phi_r_field_' +
                        str(Field_calc_param.EQS_mode) + '.pvd')
            file << phi_r_sol_scaled, mesh_sol
            if Field_calc_param.EQS_mode == 'EQS':
                file = File(
                    '/opt/Patient/Results_adaptive/Last_Phi_im_field_' +
                    str(Field_calc_param.EQS_mode) + '.pvd')
                file << phi_i_sol_scaled, mesh_sol

            return phi_r_sol_scaled, phi_i_sol_scaled, E_field_scaled, E_field_im_scaled, max_E, J_real_unscaled, J_im_unscaled, j_dens_real_unscaled, j_dens_im_unscaled

    else:
        E_norm = project(
            sqrt(inner(E_field, E_field) + inner(E_field_im, E_field_im)),
            V_normE,
            solver_type="cg",
            preconditioner_type="amg")
        max_E = E_norm.vector().max()
        file = File('/opt/Patient/Results_adaptive/E_ampl_' +
                    str(Field_calc_param.EQS_mode) + '.pvd')
        file << E_norm, mesh_sol
        file = File('/opt/Patient/Results_adaptive/Last_Phi_r_field_' +
                    str(Field_calc_param.EQS_mode) + '.pvd')
        file << phi_r_sol, mesh_sol
        if Field_calc_param.EQS_mode == 'EQS':
            file = File('/opt/Patient/Results_adaptive/Last_Phi_im_field_' +
                        str(Field_calc_param.EQS_mode) + '.pvd')
            file << phi_i_sol, mesh_sol

        return phi_r_sol, phi_i_sol, E_field, E_field_im, max_E, J_real_unscaled, J_im_unscaled, j_dens_real_unscaled, j_dens_im_unscaled
def get_field_with_scaled_BC(mesh_sol,
                             Domains,
                             Phi_scaled,
                             subdomains,
                             boundaries_sol,
                             default_material,
                             element_order,
                             Laplace_mode,
                             anisotropy,
                             frequenc,
                             Solver_type,
                             calc_with_MPI=False,
                             kappa=False):

    set_log_active(False)  #turns off debugging info
    parameters['linear_algebra_backend'] = 'PETSc'

    if calc_with_MPI == False or MPI.comm_world.rank == 1:
        print("Calculating field with scaled voltage on contacts")

    if calc_with_MPI == False:

        [cond_GM, perm_GM] = DielectricProperties(3).get_dielectrics(
            frequenc
        )  #3 for grey matter and so on (numeration as in voxel_data)
        [cond_WM, perm_WM] = DielectricProperties(2).get_dielectrics(frequenc)
        [cond_CSF,
         perm_CSF] = DielectricProperties(1).get_dielectrics(frequenc)

        [cond_default, perm_default
         ] = DielectricProperties(default_material).get_dielectrics(frequenc)

        from GUI_inp_dict import d as d_encap
        [cond_encap, perm_encap] = DielectricProperties(
            d_encap['encap_tissue_type']).get_dielectrics(frequenc)
        cond_encap = cond_encap * d_encap['encap_scaling_cond']
        perm_encap = perm_encap * d_encap['encap_scaling_perm']

        conductivities = [cond_default, cond_GM, cond_WM, cond_CSF, cond_encap]
        rel_permittivities = [
            perm_default, perm_GM, perm_WM, perm_CSF, perm_encap
        ]

        # to get conductivity (and permittivity if EQS formulation) mapped accrodingly to the subdomains. k_val_r is just a list of conductivities (S/mm!) in a specific order to scale the cond. tensor
        from FEM_in_spectrum import get_dielectric_properties_from_subdomains
        kappa, k_val_r = get_dielectric_properties_from_subdomains(
            mesh_sol, subdomains, Laplace_mode, Domains.Float_contacts,
            conductivities, rel_permittivities, frequenc)
        file = File('Results_adaptive/Last_subdomains_map.pvd')
        file << subdomains
        file = File('Results_adaptive/Last_conductivity_map.pvd')
        file << kappa[0]
        if Laplace_mode == 'EQS':
            file = File('Results_adaptive/Last_permittivity_map.pvd')
            file << kappa[1]

    if anisotropy == 1:
        # order xx,xy,xz,yy,yz,zz
        c00 = MeshFunction("double", mesh_sol, 3, 0.0)
        c01 = MeshFunction("double", mesh_sol, 3, 0.0)
        c02 = MeshFunction("double", mesh_sol, 3, 0.0)
        c11 = MeshFunction("double", mesh_sol, 3, 0.0)
        c12 = MeshFunction("double", mesh_sol, 3, 0.0)
        c22 = MeshFunction("double", mesh_sol, 3, 0.0)

        if calc_with_MPI == True:  #load predefined Tensor
            Cond_tensor = load_scaled_cond_tensor(c00, c01, c02, c11, c12, c22,
                                                  mesh_sol)
        else:
            # load the unscaled diffusion tensor (should be normalized beforehand)
            hdf = HDF5File(
                mesh_sol.mpi_comm(),
                "Results_adaptive/Tensors_to_solve_num_el_" +
                str(mesh_sol.num_cells()) + ".h5", "r")
            hdf.read(c00, "/c00")
            hdf.read(c01, "/c01")
            hdf.read(c02, "/c02")
            hdf.read(c11, "/c11")
            hdf.read(c12, "/c12")
            hdf.read(c22, "/c22")
            hdf.close()

            unscaled_tensor = [c00, c01, c02, c11, c12, c22]

            # to get tensor scaled by the conductivity map (twice send frequenc to always get unscaled ellipsoid tensor for visualization)
            from FEM_in_spectrum import get_scaled_cond_tensor
            Cond_tensor = get_scaled_cond_tensor(mesh_sol,
                                                 subdomains,
                                                 frequenc,
                                                 frequenc,
                                                 unscaled_tensor,
                                                 k_val_r,
                                                 plot_tensors=True)
    else:
        Cond_tensor = False  #just to initialize

    from FEM_in_spectrum import get_solution_space_and_Dirichlet_BC
    V_space = get_solution_space_and_Dirichlet_BC(1,
                                                  mesh_sol,
                                                  boundaries_sol,
                                                  element_order,
                                                  Laplace_mode,
                                                  Domains.Contacts,
                                                  Phi_scaled,
                                                  only_space=True)

    Dirichlet_bc_scaled = []
    if calc_with_MPI == False or MPI.comm_world.rank == 1:
        print("Scaled complex potential on contacts: ", Phi_scaled[:])
    for bc_i in range(len(Domains.Contacts)):
        if Laplace_mode == 'EQS':
            Dirichlet_bc_scaled.append(
                DirichletBC(V_space.sub(0), np.real(Phi_scaled[bc_i]),
                            boundaries_sol, Domains.Contacts[bc_i]))
            Dirichlet_bc_scaled.append(
                DirichletBC(V_space.sub(1), np.imag(Phi_scaled[bc_i]),
                            boundaries_sol, Domains.Contacts[bc_i]))
        else:
            Dirichlet_bc_scaled.append(
                DirichletBC(V_space, Phi_scaled[bc_i], boundaries_sol,
                            Domains.Contacts[bc_i]))

        #facets.array()[boundaries_sol.array()==Domains.Contacts[bc_i]]=bc_i+1

    # to solve the Laplace equation div(kappa*grad(phi))=0   (variational form: a(u,v)=L(v))
    from FEM_in_spectrum import define_variational_form_and_solve
    phi_sol = define_variational_form_and_solve(V_space, Dirichlet_bc_scaled,
                                                kappa, Laplace_mode,
                                                Cond_tensor, Solver_type)

    if Laplace_mode == 'EQS':
        (phi_r_sol, phi_i_sol) = phi_sol.split(deepcopy=True)
    else:
        phi_r_sol = phi_sol
        phi_i_sol = Function(V_space)
        phi_i_sol.vector()[:] = 0.0

    # to get manual projections for the E-field
    from FEM_in_spectrum_multicontact import get_E_field
    E_field, E_field_im = get_E_field(mesh_sol, element_order, Laplace_mode,
                                      phi_r_sol, phi_i_sol)
    #if QS, E_field_im is a null function

    # to get current density function which is required for mesh refinement when checking current convergence
    from Math_module_hybrid import get_current_density
    j_dens_real, j_dens_im = get_current_density(mesh_sol, element_order,
                                                 Laplace_mode, kappa,
                                                 Cond_tensor, E_field,
                                                 E_field_im)
    # If QS, j_dens_im is null function

    # to project the E-field magnitude
    if element_order > 1:
        V_normE = FunctionSpace(mesh_sol, "CG", element_order - 1)
    else:
        V_normE = FunctionSpace(mesh_sol, "CG", element_order)

    # to get current on the active contacts (inlcuding the ground)
    from FEM_in_spectrum_multicontact import get_current_on_multiple_contacts
    J_r_contacts, J_im_contacts = get_current_on_multiple_contacts(
        mesh_sol, boundaries_sol, Laplace_mode, Domains.Contacts, Phi_scaled,
        E_field, E_field_im, kappa, Cond_tensor)
    # J_currents_imag is a zero array if 'QS' mode

    if calc_with_MPI == False:
        Vertices_get = read_csv(
            'Neuron_model_arrays/Vert_of_Neural_model_NEURON.csv',
            delimiter=' ',
            header=None)
        Vertices_array = Vertices_get.values

        Phi_ROI = np.zeros((Vertices_array.shape[0], 4), float)

        for inx in range(Vertices_array.shape[0]):
            pnt = Point(Vertices_array[inx, 0], Vertices_array[inx, 1],
                        Vertices_array[inx, 2])

            Phi_ROI[inx, 0] = Vertices_array[inx, 0]
            Phi_ROI[inx, 1] = Vertices_array[inx, 1]
            Phi_ROI[inx, 2] = Vertices_array[inx, 2]
            Phi_ROI[inx, 3] = np.sqrt(
                phi_r_sol(pnt) * phi_r_sol(pnt) +
                phi_i_sol(pnt) * phi_i_sol(pnt))

        np.savetxt('Results_adaptive/Phi_' + str(frequenc) + '.csv',
                   Phi_ROI,
                   delimiter=" ")  # this is amplitude, actually

    Quasi_imp_real = np.zeros(len(Domains.Contacts),
                              float)  #not really, but gives an idea
    Quasi_imp_im = np.zeros(len(Domains.Contacts),
                            float)  #not really, but gives an idea

    for bc_i in range(len(Domains.Contacts)):
        if calc_with_MPI == False or MPI.comm_world.rank == 1:
            print("J on contact ", Domains.Active_on_lead[bc_i], ": ",
                  J_r_contacts[bc_i] + 1j * J_im_contacts[bc_i], "A")

        Quasi_imp_real[bc_i] = np.real(
            Phi_scaled[bc_i] / (J_r_contacts[bc_i] + 1j * J_im_contacts[bc_i]))
        if Laplace_mode == 'EQS':
            Quasi_imp_im[bc_i] = np.imag(
                Phi_scaled[bc_i] /
                (J_r_contacts[bc_i] + 1j * J_im_contacts[bc_i]))

    J_r_max = J_r_contacts.max(
    )  # we need it to filter out contacts with very small currents (they have very high quasi-impedance)
    ind_high_current = []
    for bc_i in range(len(Domains.Contacts)):
        if J_r_contacts[bc_i] >= 0.1 * J_r_max:
            ind_high_current.append(bc_i)

    Quasi_imp_real_total = np.sum(abs(Quasi_imp_real[ind_high_current]))
    Quasi_imp_im_total = np.sum(abs(Quasi_imp_im[ind_high_current]))

    if calc_with_MPI == True:
        J_Vector = Vector(MPI.comm_self, 2)
        J_Vector.set_local(
            np.array([Quasi_imp_real_total, Quasi_imp_im_total],
                     dtype=np.float64))
        Hdf = HDF5File(
            mesh_sol.mpi_comm(),
            "Results_adaptive/Solution_" + str(np.round(frequenc, 6)) + ".h5",
            "w")
        Hdf.write(mesh_sol, "mesh_sol")
        Hdf.write(phi_sol, "solution_phi_full")
        Hdf.write(E_field, "solution_E_field")
        Hdf.write(E_field_im, "solution_E_field_im")
        Hdf.write(j_dens_real, "solution_j_real")
        Hdf.write(j_dens_im, "solution_j_im")
        Hdf.write(J_Vector, "/J_Vector")
        Hdf.close()

        return True
    else:
        print("Quasi_impedance (for current check):",
              sqrt(Quasi_imp_real_total**2 + Quasi_imp_im_total**2))
        E_norm = project(
            sqrt(inner(E_field, E_field) + inner(E_field_im, E_field_im)),
            V_normE,
            solver_type="cg",
            preconditioner_type="amg")
        max_E = E_norm.vector().max()
        if calc_with_MPI == False or MPI.comm_world.rank == 1:
            file = File('Results_adaptive/E_ampl_' + str(Laplace_mode) +
                        '.pvd')
            file << E_norm, mesh_sol
            file = File('Results_adaptive/Last_Phi_r_field_' +
                        str(Laplace_mode) + '.pvd')
            file << phi_r_sol, mesh_sol
            if Laplace_mode == 'EQS':
                file = File('Results_adaptive/Last_Phi_im_field_' +
                            str(Laplace_mode) + '.pvd')
                file << phi_i_sol, mesh_sol

        return (phi_r_sol, phi_i_sol, E_field, E_field_im, max_E,
                Quasi_imp_real_total, Quasi_imp_im_total, j_dens_real,
                j_dens_im)
def calculate_in_parallel(d, freq_list, Domains, MRI_param, DTI_param,
                          anisotropy, number_of_points, cc_multicontact):

    start_paral = tm.time()

    Field_on_VTA = 0  #temp solution
    if d["Full_Field_IFFT"] == 1:
        Field_on_VTA = 1
        d["Full_Field_IFFT"] = 0

    #load adapted mesh
    mesh = Mesh(os.environ['PATIENTDIR'] +
                '/Results_adaptive/mesh_adapt.xml.gz')
    boundaries = MeshFunction(
        'size_t', mesh,
        os.environ['PATIENTDIR'] + '/Results_adaptive/boundaries_adapt.xml')
    subdomains_assigned = MeshFunction(
        'size_t', mesh, os.environ['PATIENTDIR'] +
        '/Results_adaptive/subdomains_assigned_adapt.xml')

    #load the neuron array
    Vertices_get = read_csv(
        os.environ['PATIENTDIR'] +
        '/Neuron_model_arrays/Vert_of_Neural_model_NEURON.csv',
        delimiter=' ',
        header=None)
    Vertices = Vertices_get.values

    #load CPE parameters if necessary
    CPE_param = []  # just initialization
    if d["CPE_activ"] == 1:
        CPE_param = [d["K_A"], d["beta"], d["K_A_ground"], d["beta_ground"]]

    #load unscaled tensors if DTI data are provided
    if anisotropy == 1:

        from Tissue_marking_new import get_cellmap_tensors
        subdomains = get_cellmap_tensors(
            mesh, subdomains_assigned, Domains, MRI_param, DTI_param,
            d["default_material"])  #mapping of tissue onto the mesh

        #initiating with isotropic tensor
        c00 = MeshFunction("double", mesh, 3, 1.0)
        c01 = MeshFunction("double", mesh, 3, 0.0)
        c02 = MeshFunction("double", mesh, 3, 0.0)
        c11 = MeshFunction("double", mesh, 3, 1.0)
        c12 = MeshFunction("double", mesh, 3, 0.0)
        c22 = MeshFunction("double", mesh, 3, 1.0)

        hdf = HDF5File(
            mesh.mpi_comm(), os.environ['PATIENTDIR'] +
            "/Results_adaptive/Tensors_to_solve_num_el_" +
            str(mesh.num_cells()) + ".h5", "r")
        hdf.read(c00, "/c00")
        hdf.read(c01, "/c01")
        hdf.read(c02, "/c02")
        hdf.read(c11, "/c11")
        hdf.read(c12, "/c12")
        hdf.read(c22, "/c22")
        hdf.close()

        DTI_tensor = [c00, c01, c02, c11, c12, c22]
    else:
        from Tissue_marking_new import get_cellmap
        subdomains = get_cellmap(
            mesh, subdomains_assigned, Domains, MRI_param,
            d["default_material"])  #mapping of tissue onto the mesh
        DTI_tensor = [0, 0, 0, 0, 0, 0]  #initiating

    print(
        "Subdomains file for parallel is saved in Field_solutions/parallel_Subdomains.pvd"
    )
    file = File(os.environ['PATIENTDIR'] +
                '/Field_solutions/parallel_Subdomains.pvd')
    file << subdomains, mesh

    # choose solver
    if d['Solver_Type'] == 'Default':
        from Math_module_hybrid import choose_solver_for_me
        Solver_type = choose_solver_for_me(
            d["EQS_core"], Domains.Float_contacts
        )  #choses solver basing on the Laplace formulation and whether the floating conductors are used
    else:
        Solver_type = d['Solver_Type']  # just get the solver directly

    print("Solver: ", Solver_type)

    #with open(os.devnull, 'w') as FNULL: subprocess.call('python Paraview_adapted.py', shell=True, stdout=FNULL, stderr=subprocess.STDOUT)

    i = 0  #frequency index in the frequency list of the signal spectrum
    complete_solution = []

    # this snippet will check at which frequency the FFEM computations were interrupted
    if d["Parallel_comp_interrupted"] == 1:
        pack_to_start_after = np.genfromtxt(
            os.environ['PATIENTDIR'] +
            '/Field_solutions/last_completed_pack.csv',
            delimiter=' ')
        if pack_to_start_after.size == 1:
            rslt = np.where(freq_list == pack_to_start_after)
            i = rslt[0][0] + 1
        elif pack_to_start_after[-1] == freq_list[-1]:
            i = freq_list.shape[0]
            print(
                "All computations in frequency spectrum were already conducted"
            )
        else:
            rslt = np.where(freq_list == pack_to_start_after[-1])
            i = rslt[0][0] + 1

    #FFEM calculations are conducted in parallel
    while i < freq_list.shape[0]:
        proc = []
        j = 0  #counter for processes
        output = mp.Queue()
        freq_pack = []
        while j < d["number_of_processors"] and i < freq_list.shape[0]:

            sine_freq = freq_list[i]
            freq_pack.append(sine_freq)
            i = i + 1

            [cond_GM, perm_GM] = DielectricProperties(3).get_dielectrics(
                sine_freq)  #1 for grey matter and so on
            [cond_WM,
             perm_WM] = DielectricProperties(2).get_dielectrics(sine_freq)
            [cond_CSF,
             perm_CSF] = DielectricProperties(1).get_dielectrics(sine_freq)
            [cond_default, perm_default] = DielectricProperties(
                d["default_material"]).get_dielectrics(sine_freq)

            [cond_encap, perm_encap] = DielectricProperties(
                d["encap_tissue_type"]).get_dielectrics(sine_freq)
            cond_encap = cond_encap * d["encap_scaling_cond"]
            perm_encap = perm_encap * d["encap_scaling_perm"]

            cond_vector = [
                cond_default, cond_GM, cond_WM, cond_CSF, cond_encap
            ]
            perm_vector = [
                perm_default, perm_GM, perm_WM, perm_CSF, perm_encap
            ]

            Sim_setup = Simulation_setup(
                sine_freq, d["freq"], mesh, boundaries, subdomains,
                cond_vector, perm_vector, d["el_order"], anisotropy,
                d["current_control"], DTI_tensor, d["CPE_activ"], CPE_param,
                d["EQS_core"], d["external_grounding"])

            import Contact_ground_calc
            processes = mp.Process(
                target=Contact_ground_calc.compute_fields_from_unit_currents,
                args=(Sim_setup, Solver_type, Vertices, Domains, j,
                      Field_on_VTA, output))

            #            if cc_multicontact==True:
            #                import FEM_in_spectrum_multicontact
            #                processes=mp.Process(target=FEM_in_spectrum_multicontact.solve_Laplace_multicontact,args=(Sim_setup,Solver_type,Vertices,Domains,j,Field_on_VTA,output))
            #            else:
            #                import FEM_in_spectrum
            #                processes=mp.Process(target=FEM_in_spectrum.solve_Laplace,args=(Sim_setup,Solver_type,Vertices,Domains,j,Field_on_VTA,output))

            proc.append(processes)

            j = j + 1

        for p in proc:
            p.start()
        for p in proc:
            p.join()

        last_completed_pack = np.asarray(freq_pack)
        np.savetxt(os.environ['PATIENTDIR'] +
                   '/Field_solutions/last_completed_pack.csv',
                   last_completed_pack,
                   delimiter=" "
                   )  #to recover the last frequency of FFEM was interrupted
        if d["freq"] in freq_pack:
            print("Processed frequencies: ")
        print(freq_pack)
    if d["number_of_processors"] > freq_list.shape[0]:
        n_files = freq_list.shape[0]
    else:
        n_files = d["number_of_processors"]

    complete_impedance = np.zeros((freq_list.shape[0], 3), float)

    if d["Full_Field_IFFT"] == 1:  # for Full IFFT we have to re-sort only impedance results
        cnt_freq = 0
        for core in range(n_files):
            if (d["CPE_activ"] == 1
                    or d["current_control"] == 1) and cc_multicontact == False:
                impedance_get = read_csv(os.environ['PATIENTDIR'] +
                                         '/Field_solutions/Impedance' +
                                         str(core) + '.csv',
                                         delimiter=' ',
                                         header=None)
                impedance = impedance_get.values
                complete_impedance[cnt_freq:cnt_freq + impedance.shape[0], :]
                cnt_freq = cnt_freq + impedance.shape[0]

        if (
                d["CPE_activ"] == 1 or d["current_control"] == 1
        ) and cc_multicontact == False:  # we calculate impedance with FFEM only for these cases
            sorted_impedance = complete_impedance[
                complete_impedance[:, 2].argsort(axis=0)]  #sort by freq
            np.savetxt(os.environ['PATIENTDIR'] +
                       '/Field_solutions/sorted_impedance.csv',
                       sorted_impedance,
                       delimiter=" ")

        minutes = int((tm.time() - start_paral) / 60)
        secnds = int(tm.time() - start_paral) - minutes * 60
        print("----- parallel calculations took ", minutes, " min ", secnds,
              " s -----")

        return True
    else:
        inx_compl_sol = 0
        complete_solution = np.zeros(
            (freq_list.shape[0] * Vertices.shape[0], len(d["Phi_vector"]) + 1),
            float)
        cnt_freq = 0
        for core in range(n_files):
            hf = h5py.File(
                os.environ['PATIENTDIR'] +
                '/Field_solutions/sol_per_contact_cor' + str(core) + '.h5',
                'r')
            lst = list(hf.keys())
            result_total = []
            for i in lst:
                a = hf.get(i)
                a = np.array(a)
                result_total.append(a)
            result = np.concatenate(result_total)
            hf.close()

            complete_solution[inx_compl_sol:inx_compl_sol +
                              result.shape[0], :] = result
            inx_compl_sol = inx_compl_sol + result.shape[0]
            if (
                    d["CPE_activ"] == 1 or d["current_control"] == 1
            ) and cc_multicontact == False:  # we calculate impedance with FFEM only for these cases
                impedance_get = read_csv(os.environ['PATIENTDIR'] +
                                         '/Field_solutions/Impedance' +
                                         str(core) + '.csv',
                                         delimiter=' ',
                                         header=None)
                impedance = impedance_get.values
                complete_impedance[cnt_freq:cnt_freq +
                                   impedance.shape[0], :] = impedance
                cnt_freq = cnt_freq + impedance.shape[0]

        if (
                d["CPE_activ"] == 1 or d["current_control"] == 1
        ) and cc_multicontact == False:  # we calculate impedance with FFEM only for these cases
            sorted_impedance = complete_impedance[
                complete_impedance[:, 2].argsort(axis=0)]  #sort by freq
            np.savetxt(os.environ['PATIENTDIR'] +
                       '/Field_solutions/sorted_impedance.csv',
                       sorted_impedance,
                       delimiter=" ")
            plt.figure(101010)
            plt.plot(sorted_impedance[:, 0],
                     sorted_impedance[:, 1],
                     marker='o')
            #plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,ncol=2, mode="expand", borderaxespad=0.)
            ###           ncol=2, mode="expand", borderaxespad=0.)
            plt.xlabel(r'Re(Z), $\Omega$')
            plt.ylabel(r'Im(Z), $\Omega$')
            plt.grid(True)
            plt.savefig(os.environ['PATIENTDIR'] + '/Images/Imp_plot.eps',
                        format='eps',
                        dpi=1000)

            Ampl_imp = np.zeros(sorted_impedance.shape[0], dtype=float)
            for i_fr in range(sorted_impedance.shape[0]):
                Ampl_imp[i_fr] = np.sqrt(
                    sorted_impedance[i_fr, 0] * sorted_impedance[i_fr, 0] +
                    sorted_impedance[i_fr, 1] * sorted_impedance[i_fr, 1])
            plt.figure(2)
            plt.plot(sorted_impedance[:, 2], Ampl_imp[:], marker='o')
            plt.xscale("log")
            plt.xlabel('f, Hz')
            plt.ylabel(r'Ampl(Z), $\Omega$')
            plt.grid(True)
            plt.savefig(os.environ['PATIENTDIR'] + '/Images/Imp_Ampl_plot.eps',
                        format='eps',
                        dpi=1000)

        minutes = int((tm.time() - start_paral) / 60)
        secnds = int(tm.time() - start_paral) - minutes * 60
        print("----- Parallel calculations took ", minutes, " min ", secnds,
              " s -----\n")

        sort_full_solution(d, freq_list, complete_solution, number_of_points)
        del complete_solution

        if Field_on_VTA == 1:
            d["Full_Field_IFFT"] = 1

        return True
def get_field_with_floats(mesh_sol,
                          active_index,
                          Domains,
                          subdomains,
                          boundaries_sol,
                          default_material,
                          element_order,
                          anisotropy,
                          frequenc,
                          Laplace_mode,
                          Solver_type,
                          calc_with_MPI=False,
                          kappa=False):

    set_log_active(False)  #turns off debugging info
    parameters['linear_algebra_backend'] = 'PETSc'

    if Laplace_mode == 'EQS':
        Solver_type = 'MUMPS'  # always direct solver for EQS when multiple floats

    if calc_with_MPI == False:

        [cond_GM, perm_GM] = DielectricProperties(3).get_dielectrics(
            frequenc
        )  #3 for grey matter and so on (numeration as in voxel_data)
        [cond_WM, perm_WM] = DielectricProperties(2).get_dielectrics(frequenc)
        [cond_CSF,
         perm_CSF] = DielectricProperties(1).get_dielectrics(frequenc)

        [cond_default, perm_default
         ] = DielectricProperties(default_material).get_dielectrics(frequenc)

        from GUI_inp_dict import d as d_encap
        [cond_encap, perm_encap] = DielectricProperties(
            d_encap['encap_tissue_type']).get_dielectrics(frequenc)
        cond_encap = cond_encap * d_encap['encap_scaling_cond']
        perm_encap = perm_encap * d_encap['encap_scaling_perm']

        conductivities = [cond_default, cond_GM, cond_WM, cond_CSF, cond_encap]
        rel_permittivities = [
            perm_default, perm_GM, perm_WM, perm_CSF, perm_encap
        ]

        # to get conductivity (and permittivity if EQS formulation) mapped accrodingly to the subdomains. k_val_r is just a list of conductivities (S/mm!) in a specific order to scale the cond. tensor
        from FEM_in_spectrum import get_dielectric_properties_from_subdomains
        kappa, k_val_r = get_dielectric_properties_from_subdomains(
            mesh_sol, subdomains, Laplace_mode, Domains.Float_contacts,
            conductivities, rel_permittivities, frequenc)

    if anisotropy == 1:
        # order xx,xy,xz,yy,yz,zz
        c00 = MeshFunction("double", mesh_sol, 3, 0.0)
        c01 = MeshFunction("double", mesh_sol, 3, 0.0)
        c02 = MeshFunction("double", mesh_sol, 3, 0.0)
        c11 = MeshFunction("double", mesh_sol, 3, 0.0)
        c12 = MeshFunction("double", mesh_sol, 3, 0.0)
        c22 = MeshFunction("double", mesh_sol, 3, 0.0)

        if calc_with_MPI == True:  #load predefined Tensor
            Cond_tensor = load_scaled_cond_tensor(c00, c01, c02, c11, c12, c22,
                                                  mesh_sol)
        else:
            # load the unscaled diffusion tensor (should be normalized beforehand)
            hdf = HDF5File(
                mesh_sol.mpi_comm(),
                "Results_adaptive/Tensors_to_solve_num_el_" +
                str(mesh_sol.num_cells()) + ".h5", "r")
            hdf.read(c00, "/c00")
            hdf.read(c01, "/c01")
            hdf.read(c02, "/c02")
            hdf.read(c11, "/c11")
            hdf.read(c12, "/c12")
            hdf.read(c22, "/c22")
            hdf.close()

            unscaled_tensor = [c00, c01, c02, c11, c12, c22]

            # to get tensor scaled by the conductivity map (twice send frequenc to always get unscaled ellipsoid tensor for visualization)
            from FEM_in_spectrum import get_scaled_cond_tensor
            Cond_tensor = get_scaled_cond_tensor(mesh_sol, subdomains,
                                                 frequenc, frequenc,
                                                 unscaled_tensor, k_val_r)
    else:
        Cond_tensor = False  #just to initialize

    from FEM_in_spectrum import get_solution_space_and_Dirichlet_BC
    V_space = get_solution_space_and_Dirichlet_BC(1,
                                                  mesh_sol,
                                                  boundaries_sol,
                                                  element_order,
                                                  Laplace_mode,
                                                  Domains.Contacts,
                                                  Domains.fi,
                                                  only_space=True)

    facets = MeshFunction('size_t', mesh_sol, 2)
    facets.set_all(0)

    # here we have a custom way to assign Dirichlet BC
    dirichlet_bc = []
    float_surface = 2
    active_floats = 0

    # assign only the chosen active contact and the ground, other should be just marked on the mesh (starting from 2)
    #print("Contacts: ",Domains.Contacts)
    #print("fi: ",Domains.fi)
    #print("active_index: ",active_index)
    #print("ponteial: ", Domains.fi[active_index])

    for bc_i in range(len(Domains.Contacts)):
        if bc_i == active_index or Domains.fi[bc_i] == 0.0:
            #print("one")
            if Laplace_mode == 'EQS':
                dirichlet_bc.append(
                    DirichletBC(V_space.sub(0), Domains.fi[bc_i],
                                boundaries_sol, Domains.Contacts[bc_i]))
                dirichlet_bc.append(
                    DirichletBC(V_space.sub(1), Constant(0.0), boundaries_sol,
                                Domains.Contacts[bc_i]))
            else:
                dirichlet_bc.append(
                    DirichletBC(V_space, Domains.fi[bc_i], boundaries_sol,
                                Domains.Contacts[bc_i]))

            if bc_i == active_index:
                facets.array()[boundaries_sol.array() ==
                               Domains.Contacts[bc_i]] = 1
        else:
            facets.array()[boundaries_sol.array() == Domains.Contacts[
                bc_i]] = float_surface  #it will not be assigned to always floating contacts
            float_surface = float_surface + 1
            active_floats = active_floats + 1

    #definitions for integrators
    dx = Measure("dx", domain=mesh_sol)
    dsS = Measure("ds", domain=mesh_sol, subdomain_data=facets)
    dsS_int = Measure("dS", domain=mesh_sol, subdomain_data=facets)

    #An_surface_size=assemble(1.0*dsS_int(1))
    #Cat_surface_size=assemble(1.0*dsS_int(2))
    #print "Anode size: "
    #print An_surface_size

    # to solve the Laplace equation div(kappa*grad(phi))=0   (variational form: a(u,v)=L(v))

    from FEM_in_spectrum import define_variational_form_and_solve
    phi_sol = define_variational_form_and_solve(
        V_space, dirichlet_bc, kappa, Laplace_mode, Cond_tensor, Solver_type
    )  # with multiple floats MUMPS is the most stable though slow

    if Laplace_mode == 'EQS':
        (phi_r_sol, phi_i_sol) = phi_sol.split(deepcopy=True)
    else:
        phi_r_sol = phi_sol
        phi_i_sol = Function(V_space)
        phi_i_sol.vector()[:] = 0.0

    Float_potentials_real = np.zeros(active_floats, float)
    Float_potentials_imag = np.zeros(active_floats, float)

    float_surface = 2  #float indicies start from 2

    # assess the floating potential by integrating over the contact's surface
    for fl_in in range(active_floats):
        Float_surface_size = assemble(1.0 * dsS_int(float_surface))
        Float_potentials_real[float_surface - 2] = assemble(
            phi_r_sol * dsS_int(float_surface)) / Float_surface_size
        if Laplace_mode == 'EQS':
            Float_potentials_imag[float_surface - 2] = assemble(
                phi_i_sol * dsS_int(float_surface)) / Float_surface_size

        float_surface = float_surface + 1

    # to get manual projections for the E-field
    from FEM_in_spectrum_multicontact import get_E_field
    E_field, E_field_im = get_E_field(mesh_sol, element_order, Laplace_mode,
                                      phi_r_sol, phi_i_sol)
    #if QS, E_field_im is a null function

    n = FacetNormal(mesh_sol)
    if Laplace_mode == 'EQS':
        if Cond_tensor != False:
            j_dens_real_contact = dot(
                Cond_tensor * E_field, -1 * n)('-') * dsS_int(1) - dot(
                    kappa[1] * E_field_im, -1 * n)('-') * dsS_int(1)
            j_dens_im_contact = dot(
                Cond_tensor * E_field_im, -1 * n)('-') * dsS_int(1) + dot(
                    kappa[1] * E_field, -1 * n)('-') * dsS_int(1)
        else:
            j_dens_real_contact = dot(
                kappa[0] * E_field, -1 * n)('-') * dsS_int(1) - dot(
                    kappa[1] * E_field_im, -1 * n)('-') * dsS_int(1)
            j_dens_im_contact = dot(
                kappa[0] * E_field_im, -1 * n)('-') * dsS_int(1) + dot(
                    kappa[1] * E_field, -1 * n)('-') * dsS_int(1)

        J_real = assemble(j_dens_real_contact)
        J_im = assemble(j_dens_im_contact)
        return Float_potentials_real, Float_potentials_imag, J_real, J_im
    else:
        if Cond_tensor != False:
            j_dens_real_contact = dot(Cond_tensor * E_field,
                                      -1 * n)('-') * dsS_int(1)
        else:
            j_dens_real_contact = dot(kappa[0] * E_field,
                                      -1 * n)('-') * dsS_int(1)

    J_real = assemble(j_dens_real_contact)

    #print("Shape float potentials: ",Float_potentials_real.shape[0])

    return Float_potentials_real, 0.0, J_real, 0.0