コード例 #1
0
def compute_field(mesh_sol,
                  Domains,
                  subdomains,
                  boundaries_sol,
                  kappa_r,
                  Field_calc_param,
                  kappa_i=False):

    set_log_active(False)  #turns off debugging info
    if MPI.comm_world.rank == 1:
        print("_________________________")
    parameters['linear_algebra_backend'] = 'PETSc'

    if Field_calc_param.EQS_mode == 'EQS':
        kappa = [kappa_r, kappa_i]
    else:
        kappa = [kappa_r]

    if Field_calc_param.anisotropy == 1:
        Cond_tensor = get_cond_tensor(
            mesh_sol
        )  # unlike get_scaled_cond_tensor, this function does not scale tensor with conductivity (as it was already scaled)
    else:
        Cond_tensor = False  #just to initialize

    from Math_module_hybrid import choose_solver_for_me
    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

    #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

    #facets = MeshFunction('size_t',mesh_sol,2)
    #facets.set_all(0)
    if Field_calc_param.external_grounding == False:
        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)
    if MPI.comm_world.rank == 1:
        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

    if MPI.comm_world.rank == 1:
        print("dofs on 2nd process: ", (max(V_space.dofmap().dofs()) + 1))

    # 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)
    # 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
    from Math_module_hybrid import get_current_density
    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)

    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

    ### Do not probe anything when inside MPI process!
    #    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]
    #        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+1j*J_im))
    #            phi_i_sol_scaled_on_point=V_across*np.imag((phi_r_sol(pnt)+1j*phi_i_sol(pnt))/(J_real+1j*J_im))
    #            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('Results_adaptive/Phi_'+str(Field_calc_param.frequenc)+'.csv',  Phi_ROI, delimiter=" ")

    #save the results
    if Field_calc_param.c_c != 1 and Field_calc_param.CPE != 1:
        #Just to save total currunt through the ground in FEniCS hdf5
        J_Vector = Vector(MPI.comm_self, 2)
        J_Vector.set_local(
            np.array([J_real_unscaled, J_im_unscaled], dtype=np.float64))
        Hdf = HDF5File(
            mesh_sol.mpi_comm(), "/opt/Patient/Results_adaptive/Solution_" +
            str(np.round(Field_calc_param.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_unscaled, "solution_j_real")
        Hdf.write(j_dens_im_unscaled, "solution_j_im")
        Hdf.write(J_Vector, "/J_Vector")
        Hdf.close()
        return True


### Do not probe anything when inside MPI process!
#    #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+1j*J_im))
#            phi_i_sol_scaled_on_point=V_across*np.imag((phi_r_sol(pnt)+1j*phi_i_sol(pnt))/(J_real+1j*J_im))
#            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
        if MPI.comm_world.rank == 1:
            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  #-1.0 to avoid printing
            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, -1.0, Domains.Contacts, Domains.fi,
                V_across, Z_tissue, V_space)
            if MPI.comm_world.rank == 1:
                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)
            if MPI.comm_world.rank == 1:
                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))

            #Just to save total currunt through the ground in FEniCS hdf5
            J_Vector = Vector(MPI.comm_self, 2)
            J_Vector.set_local(
                np.array([J_real_unscaled, J_im_unscaled], dtype=np.float64))
            Hdf = HDF5File(
                mesh_sol.mpi_comm(),
                "/opt/Patient/Results_adaptive/Solution_" +
                str(np.round(Field_calc_param.frequenc, 6)) + ".h5", "w")
            Hdf.write(mesh_sol, "mesh_sol")
            Hdf.write(phi_sol_CPE, "solution_phi_full")
            Hdf.write(E_field_CPE, "solution_E_field")
            Hdf.write(E_field_im_CPE, "solution_E_field_im")
            Hdf.write(j_dens_real_unscaled, "solution_j_real")
            Hdf.write(j_dens_im_unscaled, "solution_j_im")
            Hdf.write(J_Vector, "/J_Vector")
            Hdf.close()

            return True

        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 Sim_setup.Laplace_eq == '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_CPE,
                        phi_i_CPE,
                        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_r_sol_scaled = Function(V_space)
                phi_i_sol_scaled = Function(V_space)
                phi_i_sol_scaled.vector()[:] = 0.0
                phi_r_sol_scaled.vector(
                )[:] = V_across * phi_r_sol.vector()[:] / J_ground

                phi_sol_scaled = phi_r_sol_scaled

                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

            #Just to save total currunt through the ground in FEniCS hdf5 (we save unscaled currents!)
            J_Vector = Vector(MPI.comm_self, 2)
            J_Vector.set_local(
                np.array([J_real_unscaled, J_im_unscaled], dtype=np.float64))
            Hdf = HDF5File(
                mesh_sol.mpi_comm(),
                "/opt/Patient/Results_adaptive/Solution_" +
                str(np.round(Field_calc_param.frequenc, 6)) + ".h5", "w")
            Hdf.write(mesh_sol, "mesh_sol")
            Hdf.write(phi_sol_scaled, "solution_phi_full")
            Hdf.write(E_field_scaled, "solution_E_field")
            Hdf.write(E_field_im_scaled, "solution_E_field_im")
            Hdf.write(j_dens_real_unscaled, "solution_j_real")
            Hdf.write(j_dens_im_unscaled, "solution_j_im")
            Hdf.write(J_Vector, "/J_Vector")
            Hdf.close()
            return True

    return True
コード例 #2
0
def solve_Laplace_multicontact(Sim_setup, Solver_type, Vertices_array, Domains,
                               core, VTA_IFFT, output):

    Sim_setup.external_grounding = True

    set_log_active(False)  #turns off debugging info
    tol = 1e-14  #tolerance

    Sim_setup.mesh.coordinates()
    Sim_setup.mesh.init()

    #get scaled potentials on the contacts that provide the desired currents through the contacts
    Phi_scaled = scale_bc_potentials_with_superposition(
        Sim_setup, Domains, Solver_type)

    #Dirichlet_bc was scaled to match the desired current (using system's linearity).
    from FEM_in_spectrum import get_solution_space_and_Dirichlet_BC
    V_space, facets = get_solution_space_and_Dirichlet_BC(
        Sim_setup.external_grounding,
        Sim_setup.c_c,
        Sim_setup.mesh,
        Sim_setup.subdomains,
        Sim_setup.boundaries,
        Sim_setup.element_order,
        Sim_setup.Laplace_eq,
        Domains.Contacts,
        Phi_scaled,
        only_space=True)

    Dirichlet_bc_scaled = []
    for bc_i in range(len(Domains.Contacts)):
        if Sim_setup.Laplace_eq == 'EQS':
            Dirichlet_bc_scaled.append(
                DirichletBC(V_space.sub(0), np.real(Phi_scaled[bc_i]),
                            Sim_setup.boundaries, Domains.Contacts[bc_i]))
            Dirichlet_bc_scaled.append(
                DirichletBC(V_space.sub(1), np.imag(Phi_scaled[bc_i]),
                            Sim_setup.boundaries, Domains.Contacts[bc_i]))
        else:
            Dirichlet_bc_scaled.append(
                DirichletBC(V_space, Phi_scaled[bc_i], Sim_setup.boundaries,
                            Domains.Contacts[bc_i]))

    if Sim_setup.external_grounding == True:
        if Sim_setup.Laplace_eq == '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))

    # 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(
        Sim_setup.mesh, Sim_setup.subdomains, Sim_setup.Laplace_eq,
        Domains.Float_contacts, Sim_setup.conductivities,
        Sim_setup.rel_permittivities, Sim_setup.sine_freq)
    if int(Sim_setup.sine_freq) == int(Sim_setup.signal_freq):
        file = File('/opt/Patient/Field_solutions/Conductivity_map_' +
                    str(Sim_setup.signal_freq) + 'Hz.pvd')
        file << kappa[0]
        if Sim_setup.Laplace_eq == 'EQS':
            file = File('/opt/Patient/Field_solutions/Permittivity_map_' +
                        str(Sim_setup.signal_freq) + 'Hz.pvd')
            file << kappa[1]

    # to get tensor scaled by the conductivity map
    if Sim_setup.anisotropy == 1:
        from FEM_in_spectrum import get_scaled_cond_tensor
        Cond_tensor = get_scaled_cond_tensor(
            Sim_setup.mesh, Sim_setup.subdomains, Sim_setup.sine_freq,
            Sim_setup.signal_freq, Sim_setup.unscaled_tensor, k_val_r)
    else:
        Cond_tensor = False  #just to initialize

    # 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, Sim_setup.Laplace_eq,
                                                Cond_tensor, Solver_type)

    if Sim_setup.Laplace_eq == 'EQS':
        (phi_r, phi_i) = phi_sol.split(deepcopy=True)
    else:
        phi_r = phi_sol
        phi_i = Function(V_space)
        phi_i.vector()[:] = 0.0

    # the system was solved for already scaled potential, but to check the scaling accuracy, we will assess the currents through the contacts
    if int(Sim_setup.sine_freq) == int(Sim_setup.signal_freq):
        file = File('/opt/Patient/Field_solutions/Phi_real_scaled_' +
                    str(Sim_setup.signal_freq) + 'Hz.pvd')
        file << phi_r, Sim_setup.mesh
        print("DoFs on the mesh for " + Sim_setup.Laplace_eq + " : ",
              (max(V_space.dofmap().dofs()) + 1))

        # to get function space and manual projections for the E-field
        E_field, E_field_im = get_E_field(Sim_setup.mesh,
                                          Sim_setup.element_order,
                                          Sim_setup.Laplace_eq, phi_r, phi_i)
        #if QS, E_field_im is 0

        # to get current on the active contacts (inlcuding the ground)
        J_currents_real, J_currents_imag = get_current_on_multiple_contacts(
            Sim_setup.external_grounding, facets, Sim_setup.mesh,
            Sim_setup.boundaries, Sim_setup.Laplace_eq, Domains.Contacts,
            Phi_scaled, E_field, E_field_im, kappa, Cond_tensor)
        # J_currents_imag is a zero array if 'QS' mode

        print(
            "Complex currents on contacts at the base frequency (signal repetition rate): ",
            J_currents_real, J_currents_imag)
        file = File('/opt/Patient/Field_solutions/E_real_scaled_' +
                    str(Sim_setup.sine_freq) + 'Hz.pvd')
        file << E_field, Sim_setup.mesh

    #if Full_IFFT==1:
    #    Hdf=HDF5File(Sim_setup.mesh.mpi_comm(), "/opt/Patient/Field_solutions_functions/solution"+str(np.round(Sim_setup.sine_freq,6))+".h5", "w")
    #    Hdf.write(Sim_setup.mesh, "mesh")
    #    Hdf.write(phi_sol, "solution_full")
    #    Hdf.close()

    if VTA_IFFT == 1:
        Sim_type = 'Astrom'  #   fixed for now
        E_field_real, E_field_im = get_E_field(Sim_setup.mesh,
                                               Sim_setup.element_order,
                                               Sim_setup.Laplace_eq, phi_r,
                                               phi_i)
        if Sim_type == 'Astrom':
            W_amp = FunctionSpace(Sim_setup.mesh, 'DG',
                                  Sim_setup.element_order - 1)
            w_amp = TestFunction(W_amp)
            Pv_amp = TrialFunction(W_amp)
            E_amp_real = Function(W_amp)
            a_local = inner(w_amp, Pv_amp) * dx
            L_local = inner(w_amp, sqrt(dot(E_field_r, E_field_r))) * dx
            A_local, b_local = assemble_system(a_local, L_local, bcs=[])

            local_solver = PETScKrylovSolver('bicgstab')
            local_solver.solve(A_local, E_amp_real.vector(), b_local)

            #E_amp_real.vector()[:]=E_amp_real.vector()

            E_amp_imag = Function(W_amp)
            a_local = inner(w_amp, Pv_amp) * dx
            L_local = inner(w_amp, sqrt(dot(E_field_im, E_field_im))) * dx
            A_local, b_local = assemble_system(a_local, L_local, bcs=[])

            local_solver = PETScKrylovSolver('bicgstab')
            local_solver.solve(A_local, E_amp_imag.vector(), b_local)

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

        #VTA=0.0

        for inx in range(Vertices_array.shape[0]):
            pnt = Point(Vertices_array[inx, 0], Vertices_array[inx, 1],
                        Vertices_array[inx, 2])
            if Sim_setup.mesh.bounding_box_tree(
            ).compute_first_entity_collision(
                    pnt) < Sim_setup.mesh.num_cells() * 100:

                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 Sim_setup.c_c==1:
                if Sim_type == 'Butson':
                    Phi_ROI[inx, 3] = Second_deriv(pnt)  # already scaled
                    Phi_ROI[inx, 4] = Second_deriv_imag(pnt)  # already scaled
                elif Sim_type == 'Astrom':
                    Phi_ROI[inx, 3] = E_amp_real(pnt)  # already scaled
                    Phi_ROI[inx, 4] = E_amp_imag(pnt)  # already scaled

                #if Sim_setup.sine_freq==Sim_setup.signal_freq and abs(Phi_ROI[inx,3])>=0.3:
                #    VTA+=0.1**3

            else:  # we assign 0.0 here
                Phi_ROI[inx, 3] = 0.0
                Phi_ROI[inx, 4] = 0.0

                #print("Couldn't probe the potential at the point ",Vertices_array[inx,0],Vertices_array[inx,1],Vertices_array[inx,2])
                #print("check the neuron array, exiting....")
                #raise SystemExit

        fre_vector = [Sim_setup.sine_freq] * Phi_ROI.shape[0]
        comb = np.vstack((Phi_ROI[:, 0], Phi_ROI[:, 1], Phi_ROI[:, 2],
                          Phi_ROI[:, 3], Phi_ROI[:, 4], fre_vector)).T

        f = h5py.File(
            '/opt/Patient/Field_solutions/sol_cor' + str(core) + '.h5', 'a')
        f.create_dataset(str(Sim_setup.sine_freq), data=comb)
        f.close()

    else:
        Phi_ROI = np.zeros((Vertices_array.shape[0], 5), float)

        for inx in range(Vertices_array.shape[0]):
            pnt = Point(Vertices_array[inx, 0], Vertices_array[inx, 1],
                        Vertices_array[inx, 2])
            if Sim_setup.mesh.bounding_box_tree(
            ).compute_first_entity_collision(
                    pnt) < Sim_setup.mesh.num_cells() * 100:

                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] = phi_r(pnt)
                Phi_ROI[inx, 4] = phi_i(pnt)

            else:
                print("Couldn't probe the potential at the point ",
                      Vertices_array[inx, 0], Vertices_array[inx, 1],
                      Vertices_array[inx, 2])
                print("check the neuron array, exitting....")
                raise SystemExit

        fre_vector = [Sim_setup.sine_freq] * Phi_ROI.shape[0]
        ###    freq_vector=[frequenc]*coordinates.shape[0]
        #####    com=np.vstack((coordinat[0:10,0],coordinat[0:10,1],coordinat[0:10,2],real_par[0:10],image_par[0:10],fre_vector[0:10])).T
        comb = np.vstack((Phi_ROI[:, 0], Phi_ROI[:, 1], Phi_ROI[:, 2],
                          Phi_ROI[:, 3], Phi_ROI[:, 4], fre_vector)).T

        f = h5py.File(
            '/opt/Patient/Field_solutions/sol_cor' + str(core) + '.h5', 'a')
        f.create_dataset(str(Sim_setup.sine_freq), data=comb)
        f.close()

        output.put(1)
コード例 #3
0
def get_field_with_floats(Sim_setup, active_index, Domains, Solver_type):

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

    # 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(
        Sim_setup.mesh, Sim_setup.subdomains, Sim_setup.Laplace_eq,
        Domains.Float_contacts, Sim_setup.conductivities,
        Sim_setup.rel_permittivities, Sim_setup.sine_freq)

    # to get tensor scaled by the conductivity map
    if Sim_setup.anisotropy == 1:
        from FEM_in_spectrum import get_scaled_cond_tensor
        Cond_tensor = get_scaled_cond_tensor(
            Sim_setup.mesh, Sim_setup.subdomains, Sim_setup.sine_freq,
            Sim_setup.signal_freq, Sim_setup.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, facets = get_solution_space_and_Dirichlet_BC(
        Sim_setup.external_grounding,
        1,
        Sim_setup.mesh,
        Sim_setup.subdomains,
        Sim_setup.boundaries,
        Sim_setup.element_order,
        Sim_setup.Laplace_eq,
        Domains.Contacts,
        Domains.fi,
        only_space=True)

    facets_active = MeshFunction('size_t', Sim_setup.mesh, 2)
    facets_active.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)
    for bc_i in range(len(Domains.Contacts)):
        if bc_i == active_index or Domains.fi[bc_i] == 0.0:
            if Sim_setup.Laplace_eq == 'EQS':
                dirichlet_bc.append(
                    DirichletBC(V_space.sub(0), Domains.fi[bc_i],
                                Sim_setup.boundaries, Domains.Contacts[bc_i]))
                dirichlet_bc.append(
                    DirichletBC(V_space.sub(1), Constant(0.0),
                                Sim_setup.boundaries, Domains.Contacts[bc_i]))
            else:
                dirichlet_bc.append(
                    DirichletBC(V_space, Domains.fi[bc_i],
                                Sim_setup.boundaries, Domains.Contacts[bc_i]))

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

    if Sim_setup.external_grounding == True:
        if Sim_setup.Laplace_eq == 'EQS':
            dirichlet_bc.append(DirichletBC(V_space.sub(0), 0.0, facets, 1))
            dirichlet_bc.append(DirichletBC(V_space.sub(1), 0.0, facets, 1))
        else:
            dirichlet_bc.append(DirichletBC(V_space, 0.0, facets, 1))

    #definitions for integrators
    dx = Measure("dx", domain=Sim_setup.mesh)
    dsS = Measure("ds", domain=Sim_setup.mesh, subdomain_data=facets_active)
    dsS_int = Measure("dS",
                      domain=Sim_setup.mesh,
                      subdomain_data=facets_active)

    # 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
    if Sim_setup.Laplace_eq == 'EQS':
        phi_sol = define_variational_form_and_solve(
            V_space, dirichlet_bc, kappa, Sim_setup.Laplace_eq, Cond_tensor,
            'MUMPS')  #fixed to MUMPS here
    else:
        phi_sol = define_variational_form_and_solve(V_space, dirichlet_bc,
                                                    kappa,
                                                    Sim_setup.Laplace_eq,
                                                    Cond_tensor, Solver_type)

    if Sim_setup.Laplace_eq == 'EQS':
        (phi_r, phi_i) = phi_sol.split(deepcopy=True)
    else:
        phi_r = phi_sol
        phi_i = Function(V_space)
        phi_i.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(2))
        Float_potentials_real[float_surface - 2] = assemble(
            phi_r * dsS_int(float_surface)) / Float_surface_size
        if Sim_setup.Laplace_eq == 'EQS':
            Float_potentials_imag[float_surface - 2] = assemble(
                phi_i * dsS_int(float_surface)) / Float_surface_size

        float_surface += 1

    # to get manual projections for the E-field
    E_field, E_field_im = get_E_field(Sim_setup.mesh, Sim_setup.element_order,
                                      Sim_setup.Laplace_eq, phi_r, phi_i)
    #if QS, E_field_im is a null function

    n = FacetNormal(Sim_setup.mesh)
    if Sim_setup.Laplace_eq == '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)

        return Float_potentials_real, 0, J_real, 0
コード例 #4
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
コード例 #5
0
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)
コード例 #6
0
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