示例#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 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