FFDDM transfert scalar field from complex FE space to real one

Dear FreeFEM community,

I’m actually trying to solve a multiphysics problem in parallel using ffddm. I’m struggle to transfer some electromagnetic quantities (modulus) between two distributed finite element space : from a complex FE space to a real one on the same mesh. In order to do that, I’m trying to use prfe#transferfromVhi(us,Vht,Pkt,rest) as mentioned in the ffddm documentation but without success.
Otherwise, I’ve tried using PETCs interfaces without success too…and find some post Creating Mat from Mat but this is beyond my actual FreeFEM skills…

How can I perform this kind of interpolation ?
Otherwise, how can I save the global real part of the quantity of interest and load it in a new real distributed real finite element space (same mesh) ?

This is the pseudocode of my problem.


macro dimension 2// EOM           
include "ffddm.idp"
func Pk = P1;

// Domain decomposition
ffddmbuildDmesh( M ,Th , mpiCommWorld )
ffddmbuildDmesh( M2 ,Th , mpiCommWorld )

macro def(u)u// EOM                         // scalar field definition
macro init(u)u// EOM                        // scalar field initialization

ffddmbuildDfespace( FE , M , complex , def , init , Pk ) // FE complex space P1
ffddmbuildDfespace( FE2 , M2 , real , def , init , Pk ) // FE real space P1
FEVhi<complex> def(us) = ucomplex; // complex quantities of interest
FE2Vhi def(ut), def(ut2); // real space

FEtransferfromVhi(us,FE2Vhi,Pk,ut)
ut2 = real(ut); // take the real part
ffddmplot(FE,us,"u source");
ffddmplot(FE2,ut2,"u target"); // observe the real part on the new real Fespace 

Thanks in advance for your help !
Best
Damien

What’s your issue with the PETSc code?

If everything is happening on the same mesh you do not need any fancy transfer function, you can just take the real part of the local variables:

macro dimension 2// EOM           
include "ffddm.idp"
func Pk = P1;

// Domain decomposition
ffddmbuildDmesh( M ,Th , mpiCommWorld )

macro def(u)u// EOM                         // scalar field definition
macro init(u)u// EOM                        // scalar field initialization

ffddmbuildDfespace( FE , M , complex , def , init , Pk ) // FE complex space P1
ffddmbuildDfespace( FE2 , M , real , def , init , Pk ) // FE real space P1
FEVhi<complex> def(us) = ucomplex; // complex quantities of interest
FE2Vhi def(ut2); // real space

ut2 = real(us); // take the real part
// or:  ut2[] = us[].re;

ffddmplot(FE,abs(us),"u source");
ffddmplot(FE2,ut2,"u target"); // observe the real part on the new real Fespace 

Sorry for my delayed answer.

In fact, I have a problem which involve to first solve in a complex FEspace and after in a real one. So, I’m not able to mix “load PETSc-complex” with “load PETSc” which is apparently a known issue.

Thanks to phtournier answer, I’m able to solve my problem.

But now I have a new problem which is in the same topic. (maybe I have to open a new post).

Can I define a subdomain of my distributed global mesh and attached it to a new real FEspace ?
I have the following constraints :

  1. I will use a quantity computed previously in the complex global distributed domain as an input of my variational form in the subdomain.

I have been trying some attempts with the trunc function without success.

Please find some pseudocode for illustration of my problem

// ELECTROMAGNETIC PROBLEM 

ffddmbuildDmesh( M ,Th , mpiCommWorld )     // global distributed  mesh
macro def(u)u// EOM                         // scalar field definition
macro init(u)u// EOM                        // scalar field initialization

ffddmbuildDfespace( FE , M , complex , def , init , Pk1 ) // complex distributed FE space


ffddmsetupOperator(PB,FE,Varf )
complex[int] bi(0); 
ffddmbuildrhs( PB , Varf , bi )
complex[int] x0(bi.n);
x0 = 0;
// One-lvl preconditionner
ffddmsetupPrecond( PB , Varf ) 
// solve the problem
FEVhi<complex> def(u),def(err),def(E),def(J),def(Q);
u[] = PBfGMRES(x0, bi, 1.e-6, 200, "right"); // iterative

PBwritesummary
ffddmplot(FE,abs(u), "Global solution");

// Compute some quantities of interest inside the distributed domain
E = -iomega*u; // electric field
J = (Sigma*E) ;
ffddmplot(FE,abs(J), "Eddy current ");
func J2 = J*(region==CylinderRegion); // global quantities computed on a specific domain of the mesh
FEVhi<complex> Jr = J2;
ffddmplot(FE,abs(Jr), "Eddy current cylinder");
Q = ((abs(Jr^2))/(2*sigmaCylinder));  // joule losses inside the cylinder
FEVhi Qr = (abs(Q)); 


// THERMAL PROBLEM

// would like to create a subdomain of the global distributed mesh  wich i used Qr for solved a new problem
mesh Thbis = trunc(Th, x<=rCylinder);

// if a build a new distributed mesh i lost my actual decomposition... i don't want that
// ffddmbuildDmesh( M2 ,Thbis , mpiCommWorld ) 
ffddmbuildDfespace(FE2, M, real, def, init, P2)

ffddmplot(FE2,Qr, "Heat source restricted"); // doesn't plot on the restricted subdomain

// set up the thermal problem 
FE2Vhi u2, un2,Tp;
ffddmsetupOperator(PB2,FE2,Varf2 )
ffddmsetupPrecond(PB2, Varf2)

real[int] rhs(FE2Vhi.ndof);
un2 = 0; // initial guess

real t = 0; int iter=0; u2 = T0;
while (t <=tmax){    
    iter++; 
    t+=dt;
    Tp=u2;   // update temperature
    ffddmbuildrhs(PB2, Varf2, rhs)
    u2[] = PB2fGMRES(un2[], rhs, 1.e-6, 200, "right");
    un2[] = u2[];
    cout<<"Tmax: "<<u2[].max << "Tmin: "<<u2[].min <<endl; 
}

ffddmplot(FE2,u2, "Temperature");
PB2writesummary




Thanks for your help !
Best
Damien

Right, you need to stick with only one, e.g., load "PETSc-complex".
I don’t know how to deal with restricted global meshes in ffddm, FWIW, there is an exemple here using PETSc FreeFem-sources/restriction-2d-PETSc.edp at develop · FreeFem/FreeFem-sources · GitHub.

Thanks for the reference.
I will try the “PETSc way” to perform the subdomain restriction.

I keep you informed.

If you provide a full working example, I can help you out. In the current code you pasted, there are a bunch of macro (mostly for the varf) that are undefined, and I thus cannot run this on my end. The mesh is also not defined.