// GetDP - Copyright (C) 1997-2022 P. Dular and C. Geuzaine, University of Liege
//
// See the LICENSE.txt file for license information. Please report all
// issues on https://gitlab.onelab.info/getdp/getdp/issues.
//
// Contributor(s):
//   Johan Gyselinck
//   Ruth Sabariego
//

#include <map>
#include <complex>
#include <string.h>
#include <math.h>
#include "GetDPVersion.h"
#include "ProData.h"
#include "DofData.h"
#include "GeoData.h"
#include "ExtendedGroup.h"
#include "ListUtils.h"
#include "TreeUtils.h"
#include "MallocUtils.h"
#include "Message.h"
#include "ProParser.h"
#include "OS.h"

#define TWO_PI 6.2831853071795865

extern struct Problem Problem_S;
extern struct CurrentData Current;

FILE *File_PRE = 0, *File_RES = 0, *File_TMP = 0;

struct DofData *CurrentDofData;

int fcmp_Dof(const void *a, const void *b)
{
  int Result;

  if((Result = ((struct Dof *)a)->NumType - ((struct Dof *)b)->NumType) != 0)
    return Result;
  if((Result = ((struct Dof *)a)->Entity - ((struct Dof *)b)->Entity) != 0)
    return Result;
  return ((struct Dof *)a)->Harmonic - ((struct Dof *)b)->Harmonic;
}

/* ------------------------------------------------------------------------ */
/*  D o f _ I n i t D o f D a t a                                           */
/* ------------------------------------------------------------------------ */

void Dof_InitDofData(struct DofData *DofData_P, int Num, int ResolutionIndex,
                     int SystemIndex, char *Name_SolverDataFile)
{
  int Index;

  DofData_P->Num = Num;

  DofData_P->ResolutionIndex = ResolutionIndex;
  DofData_P->SystemIndex = SystemIndex;

  DofData_P->FunctionSpaceIndex = NULL;
  DofData_P->TimeFunctionIndex = List_Create(10, 5, sizeof(int));
  Index = 0;
  List_Add(DofData_P->TimeFunctionIndex, &Index);
  DofData_P->Pulsation = NULL;
  DofData_P->Val_Pulsation = NULL;
  DofData_P->NbrHar = 1;

  DofData_P->NbrAnyDof = 0;
  DofData_P->NbrDof = 0;
  DofData_P->DofTree = Tree_Create(sizeof(struct Dof), fcmp_Dof);
  DofData_P->DofList = NULL;

  DofData_P->SolverDataFileName = Name_SolverDataFile;
  DofData_P->Flag_RHS = 0;
  DofData_P->Flag_ListOfRHS = 0;
  DofData_P->CounterOfRHS = 0;
  DofData_P->TotalNumberOfRHS = 0;

  DofData_P->Flag_Init[0] = 0;
  DofData_P->Flag_Init[1] = 0;
  DofData_P->Flag_Init[2] = 0;
  DofData_P->Flag_Init[3] = 0;
  DofData_P->Flag_Init[4] = 0;
  DofData_P->Flag_Init[5] = 0;
  DofData_P->Flag_Init[6] = 0;
  DofData_P->Flag_Init[7] = 0;

  DofData_P->Flag_Only = 0;
  DofData_P->Flag_InitOnly[0] = 0;
  DofData_P->Flag_InitOnly[1] = 0;
  DofData_P->Flag_InitOnly[2] = 0;

  DofData_P->OnlyTheseMatrices = NULL;

  DofData_P->Solutions = NULL;
  DofData_P->CurrentSolution = NULL;

  DofData_P->CorrectionSolutions.Flag = 0;
  DofData_P->CorrectionSolutions.AllSolutions = NULL;

  DofData_P->DummyDof = NULL;
}

/* ------------------------------------------------------------------------ */
/*  D o f _ F r e e D o f D a t a                                           */
/* ------------------------------------------------------------------------ */

void Dof_FreeDofData(struct DofData *DofData_P)
{
  Message::Debug("Freeing DofData %d", DofData_P->Num);

  List_Delete(DofData_P->FunctionSpaceIndex);
  List_Delete(DofData_P->TimeFunctionIndex);
  List_Delete(DofData_P->Pulsation);
  Tree_Delete(DofData_P->DofTree);
  List_Delete(DofData_P->DofList);
  Free(DofData_P->DummyDof);

  if(DofData_P->Solutions) {
    for(int i = 0; i < List_Nbr(DofData_P->Solutions); i++) {
      Solution *Solution_P =
        (struct Solution *)List_Pointer(DofData_P->Solutions, i);
      if(Solution_P->SolutionExist) {
        LinAlg_DestroyVector(&Solution_P->x);
        Free(Solution_P->TimeFunctionValues);
        Solution_P->TimeFunctionValues = NULL;
        Solution_P->SolutionExist = 0;
      }
    }
    List_Delete(DofData_P->Solutions);
  }

  List_Delete(DofData_P->OnlyTheseMatrices);

  if(DofData_P->Flag_Init[0] == 1 || DofData_P->Flag_Init[0] == 2) {
    LinAlg_DestroyMatrix(&DofData_P->A);
    LinAlg_DestroyVector(&DofData_P->b);
    LinAlg_DestroyVector(&DofData_P->res);
    LinAlg_DestroyVector(&DofData_P->dx);
    LinAlg_DestroySolver(&DofData_P->Solver);
  }

  if(DofData_P->Flag_Init[0] == 2) { LinAlg_DestroyMatrix(&DofData_P->Jac); }

  if(DofData_P->Flag_Init[1] == 1) {
    LinAlg_DestroyMatrix(&DofData_P->M1);
    LinAlg_DestroyVector(&DofData_P->m1);
    for(int i = 0; i < List_Nbr(DofData_P->m1s); i++)
      LinAlg_DestroyVector((gVector *)List_Pointer(DofData_P->m1s, i));
    List_Delete(DofData_P->m1s);
  }

  if(DofData_P->Flag_Init[2] == 1) {
    LinAlg_DestroyMatrix(&DofData_P->M2);
    LinAlg_DestroyVector(&DofData_P->m2);
    for(int i = 0; i < List_Nbr(DofData_P->m2s); i++)
      LinAlg_DestroyVector((gVector *)List_Pointer(DofData_P->m2s, i));
    List_Delete(DofData_P->m2s);
  }

  if(DofData_P->Flag_Init[3] == 1) {
    LinAlg_DestroyMatrix(&DofData_P->M3);
    LinAlg_DestroyVector(&DofData_P->m3);
    for(int i = 0; i < List_Nbr(DofData_P->m3s); i++)
      LinAlg_DestroyVector((gVector *)List_Pointer(DofData_P->m3s, i));
    List_Delete(DofData_P->m3s);
  }

  if(DofData_P->Flag_Init[4] == 1) {
    LinAlg_DestroyMatrix(&DofData_P->M4);
    LinAlg_DestroyVector(&DofData_P->m4);
    for(int i = 0; i < List_Nbr(DofData_P->m4s); i++)
      LinAlg_DestroyVector((gVector *)List_Pointer(DofData_P->m4s, i));
    List_Delete(DofData_P->m4s);
  }

  if(DofData_P->Flag_Init[5] == 1) {
    LinAlg_DestroyMatrix(&DofData_P->M5);
    LinAlg_DestroyVector(&DofData_P->m5);
    for(int i = 0; i < List_Nbr(DofData_P->m5s); i++)
      LinAlg_DestroyVector((gVector *)List_Pointer(DofData_P->m5s, i));
    List_Delete(DofData_P->m5s);
  }

  if(DofData_P->Flag_Init[6] == 1) {
    LinAlg_DestroyMatrix(&DofData_P->M6);
    LinAlg_DestroyVector(&DofData_P->m6);
    for(int i = 0; i < List_Nbr(DofData_P->m6s); i++)
      LinAlg_DestroyVector((gVector *)List_Pointer(DofData_P->m6s, i));
    List_Delete(DofData_P->m6s);
  }
  // nleigchange
  if(DofData_P->Flag_Init[7] == 1) {
    LinAlg_DestroyMatrix(&DofData_P->M7);
    LinAlg_DestroyVector(&DofData_P->m7);
    for(int i = 0; i < List_Nbr(DofData_P->m7s); i++)
      LinAlg_DestroyVector((gVector *)List_Pointer(DofData_P->m7s, i));
    List_Delete(DofData_P->m7s);
  }

  if(DofData_P->Flag_Only) {
    if(DofData_P->Flag_InitOnly[0] == 1) {
      LinAlg_DestroyMatrix(&DofData_P->A1);
      LinAlg_DestroyVector(&DofData_P->b1);
    }
    if(DofData_P->Flag_InitOnly[1] == 1) {
      LinAlg_DestroyMatrix(&DofData_P->A2);
      LinAlg_DestroyVector(&DofData_P->b2);
    }
    if(DofData_P->Flag_InitOnly[2] == 1) {
      LinAlg_DestroyMatrix(&DofData_P->A3);
      LinAlg_DestroyVector(&DofData_P->b3);
    }
  }

  // TODO: handle MH data and CorrectionSolutions
}

/* ------------------------------------------------------------------------ */
/*  D o f _ S e t C u r r e n t D o f D a t a                               */
/* ------------------------------------------------------------------------ */

void Dof_SetCurrentDofData(struct DofData *DofData_P)
{
  CurrentDofData = DofData_P;
}

/* ------------------------------------------------------------------------ */
/*  F i l e s   . . .                                                       */
/* ------------------------------------------------------------------------ */

/* ------------------------------------------------------------------------ */
/*  D o f _ O p e n F i l e                                                 */
/* ------------------------------------------------------------------------ */

void Dof_OpenFile(int Type, char *Name, const char *Mode)
{
  if((Message::GetIsCommWorld() && Message::GetCommRank()) &&
     (Mode[0] == 'w' || Mode[0] == 'a')) {
    switch(Type) {
    case DOF_PRE: File_PRE = 0; break;
    case DOF_RES: File_RES = 0; break;
    case DOF_TMP: File_RES = 0; break;
    default: break;
    }
    return;
  }

  const char *Extension;
  char FileName[256];
  FILE *File_X;

  switch(Type) {
  case DOF_PRE: Extension = ".pre"; break;
  case DOF_RES: Extension = ""; break;
  case DOF_TMP: Extension = ""; break;
  default: Extension = ".pre"; break;
  }

  strcpy(FileName, Name);
  strcat(FileName, Extension);

  if(!(File_X = FOpen(FileName, Mode)))
    Message::Error("Unable to open file '%s'", FileName);

  switch(Type) {
  case DOF_PRE: File_PRE = File_X; break;
  case DOF_RES: File_RES = File_X; break;
  case DOF_TMP:
    File_TMP = File_RES;
    File_RES = File_X;
    break;
  default: break;
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ C l o s e F i l e                                               */
/* ------------------------------------------------------------------------ */

void Dof_CloseFile(int Type)
{
  switch(Type) {
  case DOF_PRE:
    if(File_PRE) fclose(File_PRE);
    break;
  case DOF_RES:
    if(File_RES) fclose(File_RES);
    break;
  case DOF_TMP:
    if(File_RES) fclose(File_RES);
    File_RES = File_TMP;
    break;
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ F l u s h F i l e                                               */
/* ------------------------------------------------------------------------ */

void Dof_FlushFile(int Type)
{
  switch(Type) {
  case DOF_PRE: fflush(File_PRE); break;
  case DOF_RES: fflush(File_RES); break;
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ W r i t e F i l e P R E 0                                       */
/* ------------------------------------------------------------------------ */

void Dof_WriteFilePRE0(int Num_Resolution, char *Name_Resolution,
                       int Nbr_DofData)
{
  if(Message::GetIsCommWorld() && Message::GetCommRank()) return;

  fprintf(File_PRE, "$Resolution /* '%s' */\n", Name_Resolution);
  fprintf(File_PRE, "%d %d\n", Num_Resolution, Nbr_DofData);
  fprintf(File_PRE, "$EndResolution\n");
}

/* ------------------------------------------------------------------------ */
/*  D o f _ R e a d F i l e P R E 0                                         */
/* ------------------------------------------------------------------------ */

void Dof_ReadFilePRE0(int *Num_Resolution, int *Nbr_DofData)
{
  Message::Barrier();

  char String[256];

  do {
    if(!fgets(String, sizeof(String), File_PRE)) break;
    if(feof(File_PRE)) break;
  } while(String[0] != '$');

  if(feof(File_PRE)) {
    Message::Error("$Resolution field not found in file");
    return;
  }

  if(!strncmp(&String[1], "Resolution", 10)) {
    if(fscanf(File_PRE, "%d %d", Num_Resolution, Nbr_DofData) != 2) {
      Message::Error("Could not read resolution data");
      return;
    }
  }

  do {
    if(!fgets(String, sizeof(String), File_PRE) || feof(File_PRE)) {
      Message::Error("Premature end of file");
      break;
    }
  } while(String[0] != '$');
}

/* ------------------------------------------------------------------------ */
/*  D o f _ W r i t e F i l e P R E                                         */
/* ------------------------------------------------------------------------ */

void Dof_WriteFilePRE(struct DofData *DofData_P)
{
  if(Message::GetIsCommWorld() && Message::GetCommRank()) return;

  int i, Nbr_Index;
  struct Dof *Dof_P0;

  fprintf(File_PRE, "$DofData /* #%d */\n", DofData_P->Num);

  fprintf(File_PRE, "%d %d\n", DofData_P->ResolutionIndex,
          DofData_P->SystemIndex);

  Nbr_Index = List_Nbr(DofData_P->FunctionSpaceIndex);
  fprintf(File_PRE, "%d", Nbr_Index);
  for(i = 0; i < Nbr_Index; i++)
    fprintf(File_PRE, " %d",
            *((int *)List_Pointer(DofData_P->FunctionSpaceIndex, i)));
  fprintf(File_PRE, "\n");

  Nbr_Index = List_Nbr(DofData_P->TimeFunctionIndex);
  fprintf(File_PRE, "%d", Nbr_Index);
  for(i = 0; i < Nbr_Index; i++)
    fprintf(File_PRE, " %d",
            *((int *)List_Pointer(DofData_P->TimeFunctionIndex, i)));
  fprintf(File_PRE, "\n");

  fprintf(File_PRE, "%d", 1);
  for(i = 0; i < 1; i++) fprintf(File_PRE, " %d", 0);
  fprintf(File_PRE, "\n");

  fprintf(File_PRE, "%d %d\n",
          (DofData_P->DofTree) ? Tree_Nbr(DofData_P->DofTree) :
                                 DofData_P->NbrAnyDof,
          DofData_P->NbrDof);

  if(DofData_P->DofTree)
    Tree_Action(DofData_P->DofTree, Dof_WriteDofPRE);
  else {
    if(DofData_P->NbrAnyDof) {
      Dof_P0 = (struct Dof *)List_Pointer(DofData_P->DofList, 0);
      for(i = 0; i < DofData_P->NbrAnyDof; i++)
        Dof_WriteDofPRE(Dof_P0 + i, NULL);
    }
  }
  fprintf(File_PRE, "$EndDofData\n");
  fflush(File_PRE);
}

/* ------------------------------- */
/*  D o f _ W r i t e D o f P R E  */
/* ------------------------------- */

void Dof_WriteDofPRE(void *a, void *b)
{
  struct Dof *Dof_P;

  Dof_P = (struct Dof *)a;

  fprintf(File_PRE, "%d %d %d %d ", Dof_P->NumType, Dof_P->Entity,
          Dof_P->Harmonic, Dof_P->Type);

  switch(Dof_P->Type) {
  case DOF_UNKNOWN:
    fprintf(File_PRE, "%d %d\n", Dof_P->Case.Unknown.NumDof,
            Dof_P->Case.Unknown.NonLocal ? -1 : 1);
    break;
  case DOF_FIXEDWITHASSOCIATE:
    fprintf(File_PRE, "%d ", Dof_P->Case.FixedAssociate.NumDof);
    LinAlg_PrintScalar(File_PRE, &Dof_P->Val);
    fprintf(File_PRE, " %d\n", Dof_P->Case.FixedAssociate.TimeFunctionIndex);
    break;
  case DOF_FIXED:
    LinAlg_PrintScalar(File_PRE, &Dof_P->Val);
    fprintf(File_PRE, " %d\n", Dof_P->Case.FixedAssociate.TimeFunctionIndex);
    break;
  case DOF_FIXED_SOLVE:
    fprintf(File_PRE, "%d\n", Dof_P->Case.FixedAssociate.TimeFunctionIndex);
    break;
  case DOF_UNKNOWN_INIT:
    fprintf(File_PRE, "%d ", Dof_P->Case.Unknown.NumDof);
    LinAlg_PrintScalar(File_PRE, &Dof_P->Val);
    fprintf(File_PRE, " ");
    LinAlg_PrintScalar(File_PRE, &Dof_P->Val2);
    fprintf(File_PRE, " %d\n", Dof_P->Case.Unknown.NonLocal ? -1 : 1);
    break;
  case DOF_LINK:
    fprintf(File_PRE, "%.16g %d\n", Dof_P->Case.Link.Coef,
            Dof_P->Case.Link.EntityRef);
    break;
  case DOF_LINKCPLX:
    fprintf(File_PRE, "%.16g %.16g %d\n", Dof_P->Case.Link.Coef,
            Dof_P->Case.Link.Coef2, Dof_P->Case.Link.EntityRef);
    break;
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ R e a d F i l e P R E                                           */
/* ------------------------------------------------------------------------ */

void Dof_ReadFilePRE(struct DofData *DofData_P)
{
  Message::Barrier();

  int i, Nbr_Index, Int, Dummy;
  struct Dof Dof;
  char String[256];

  do {
    if(!fgets(String, sizeof(String), File_PRE)) break;
    if(feof(File_PRE)) break;
  } while(String[0] != '$');

  if(feof(File_PRE)) {
    Message::Error("$DofData field not found in file");
    return;
  }

  if(!strncmp(&String[1], "DofData", 7)) {
    if(fscanf(File_PRE, "%d %d", &DofData_P->ResolutionIndex,
              &DofData_P->SystemIndex) != 2) {
      Message::Error("Could not read Resolution and DofData indices");
      return;
    }

    if(fscanf(File_PRE, "%d", &Nbr_Index) != 1) {
      Message::Error("Could not read number of function spaces");
      return;
    }
    DofData_P->FunctionSpaceIndex = List_Create(Nbr_Index, 1, sizeof(int));
    for(i = 0; i < Nbr_Index; i++) {
      if(fscanf(File_PRE, "%d", &Int) != 1) {
        Message::Error("Could not read FunctionSpace index");
        return;
      }
      List_Add(DofData_P->FunctionSpaceIndex, &Int);
    }

    if(fscanf(File_PRE, "%d", &Nbr_Index) != 1) {
      Message::Error("Could not read number of time functions");
      return;
    }
    DofData_P->TimeFunctionIndex = List_Create(Nbr_Index, 1, sizeof(int));
    for(i = 0; i < Nbr_Index; i++) {
      if(fscanf(File_PRE, "%d", &Int) != 1) {
        Message::Error("Could not read TimeFunction index");
        return;
      }
      List_Add(DofData_P->TimeFunctionIndex, &Int);
    }

    if(fscanf(File_PRE, "%d", &Dummy) != 1) {
      Message::Error("Format error");
      return;
    }
    for(i = 0; i < 1; i++) {
      if(fscanf(File_PRE, "%d", &Dummy) != 1) {
        Message::Error("Format error");
        return;
      }
    }

    if(fscanf(File_PRE, "%d %d", &DofData_P->NbrAnyDof, &DofData_P->NbrDof) !=
       2) {
      Message::Error("Could not read number of dofs");
      return;
    }

    DofData_P->DofList =
      List_Create(DofData_P->NbrAnyDof, 1, sizeof(struct Dof));
    Tree_Delete(DofData_P->DofTree);
    DofData_P->DofTree = NULL;

    for(i = 0; i < DofData_P->NbrAnyDof; i++) {
      if(fscanf(File_PRE, "%d %d %d %d", &Dof.NumType, &Dof.Entity,
                &Dof.Harmonic, &Dof.Type) != 4) {
        Message::Error("Could not dof");
        return;
      }

      switch(Dof.Type) {
      case DOF_UNKNOWN:
        if(fscanf(File_PRE, "%d %d", &Dof.Case.Unknown.NumDof, &Dummy) != 2) {
          Message::Error("Could not read DOF_UNKNOWN");
          return;
        }
        Dof.Case.Unknown.NonLocal = (Dummy < 0) ? true : false;
        if(Dummy < 0)
          DofData_P->NonLocalEquations.push_back(Dof.Case.Unknown.NumDof);
        break;
      case DOF_FIXEDWITHASSOCIATE:
        if(fscanf(File_PRE, "%d", &Dof.Case.FixedAssociate.NumDof) != 1) {
          Message::Error("Could not read DOF_FIXEDWITHASSOCIATE");
          return;
        }
        LinAlg_ScanScalar(File_PRE, &Dof.Val);
        if(fscanf(File_PRE, "%d", &Dof.Case.FixedAssociate.TimeFunctionIndex) !=
           1) {
          Message::Error("Could not read DOF_FIXEDWITHASSOCIATE");
          return;
        }
        break;
      case DOF_FIXED:
        LinAlg_ScanScalar(File_PRE, &Dof.Val);
        if(fscanf(File_PRE, "%d", &Dof.Case.FixedAssociate.TimeFunctionIndex) !=
           1) {
          Message::Error("Could not read DOF_FIXED");
          return;
        }
        break;
      case DOF_FIXED_SOLVE:
        if(fscanf(File_PRE, "%d", &Dof.Case.FixedAssociate.TimeFunctionIndex) !=
           1) {
          Message::Error("Could not read DOF_FIXED_SOLVED");
          return;
        }
        break;
      case DOF_UNKNOWN_INIT:
        if(fscanf(File_PRE, "%d", &Dof.Case.Unknown.NumDof) != 1) {
          Message::Error("Could not read DOF_UNKNOWN_INIT");
          return;
        }
        LinAlg_ScanScalar(File_PRE, &Dof.Val);
        LinAlg_ScanScalar(File_PRE, &Dof.Val2);
        if(fscanf(File_PRE, "%d", &Dummy) != 1) {
          Message::Error("Could not read DOF_UNKNOWN_INIT");
          return;
        }
        Dof.Case.Unknown.NonLocal = (Dummy < 0) ? true : false;
        if(Dummy < 0)
          DofData_P->NonLocalEquations.push_back(Dof.Case.Unknown.NumDof);
        break;
      case DOF_LINK:
        if(fscanf(File_PRE, "%lf %d", &Dof.Case.Link.Coef,
                  &Dof.Case.Link.EntityRef) != 2) {
          Message::Error("Could not read DOF_LINK");
          return;
        }
        Dof.Case.Link.Dof = NULL;
        break;
      case DOF_LINKCPLX:
        if(fscanf(File_PRE, "%lf %lf %d", &Dof.Case.Link.Coef,
                  &Dof.Case.Link.Coef2, &Dof.Case.Link.EntityRef) != 3) {
          Message::Error("Could not read DOF_LINKCPLX");
          return;
        }
        Dof.Case.Link.Dof = NULL;
        break;
      }

      List_Add(DofData_P->DofList, &Dof);
    }
  }

  do {
    if(!fgets(String, sizeof(String), File_PRE) || feof(File_PRE)) {
      Message::Error("Premature end of file");
      break;
    }
  } while(String[0] != '$');

  Dof_InitDofType(DofData_P);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ W r i t e F i l e R E S 0                                       */
/* ------------------------------------------------------------------------ */

void Dof_WriteFileRES0(char *Name_File, int Format)
{
  if(Message::GetIsCommWorld() && Message::GetCommRank()) return;

  Dof_OpenFile(DOF_RES, Name_File, (char *)(Format ? "wb" : "w"));
  fprintf(File_RES, "$ResFormat /* GetDP %s, %s */\n", GETDP_VERSION,
          Format ? "binary" : "ascii");
  fprintf(File_RES, "1.1 %d\n", Format);
  fprintf(File_RES, "$EndResFormat\n");
  Dof_CloseFile(DOF_RES);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ W r i t e F i l e R E S _ E x t e n d M H                       */
/* ------------------------------------------------------------------------ */

void Dof_WriteFileRES_ExtendMH(char *Name_File, struct DofData *DofData_P,
                               int Format, int NbrH)
{
  if(Message::GetIsCommWorld() && Message::GetCommRank()) return;

  if(!DofData_P->CurrentSolution) {
    Message::Warning("No ExtendMH solution to save");
    return;
  }

  gVector x;
  double d;
  int i, inew;

  Dof_OpenFile(DOF_RES, Name_File, (char *)(Format ? "ab" : "a"));

  fprintf(File_RES, "$Solution  /* DofData #%d */\n", DofData_P->Num);
  fprintf(File_RES, "%d 0 0 0 \n", DofData_P->Num);

  LinAlg_CreateVector(&x, &DofData_P->Solver,
                      (DofData_P->NbrDof / Current.NbrHar) * NbrH);

  LinAlg_ZeroVector(&x);

  for(i = 0; i < DofData_P->NbrDof; i++) {
    LinAlg_GetDoubleInVector(&d, &DofData_P->CurrentSolution->x, i);
    inew = (i / Current.NbrHar) * NbrH + i % Current.NbrHar;
    LinAlg_SetDoubleInVector(d, &x, inew);
  }

  Format ? LinAlg_WriteVector(File_RES, &x) : LinAlg_PrintVector(File_RES, &x);

  fprintf(File_RES, "$EndSolution\n");

  Dof_CloseFile(DOF_RES);

  LinAlg_DestroyVector(&x);
}

void Dof_WriteFileRES_MHtoTime(char *Name_File, struct DofData *DofData_P,
                               int Format, List_T *Time_L)
{
  if(Message::GetIsCommWorld() && Message::GetCommRank()) return;

  if(!DofData_P->CurrentSolution) {
    Message::Warning("No solution to save");
    return;
  }

  gVector x;
  double Time, d1, d2, d, *Pulsation;
  int iT, i, j, k;

  Dof_OpenFile(DOF_RES, Name_File, (char *)(Format ? "ab" : "a"));

  for(iT = 0; iT < List_Nbr(Time_L); iT++) {
    List_Read(Time_L, iT, &Time);

    fprintf(File_RES, "$Solution  /* DofData #%d */\n", DofData_P->Num);
    fprintf(File_RES, "%d %e 0 %d \n", DofData_P->Num, Time, iT);

    Pulsation = DofData_P->Val_Pulsation;

    LinAlg_CreateVector(&x, &DofData_P->Solver,
                        DofData_P->NbrDof / Current.NbrHar);

    LinAlg_ZeroVector(&x);

    for(i = 0; i < DofData_P->NbrDof / Current.NbrHar; i++) {
      d = 0;
      for(k = 0; k < Current.NbrHar / 2; k++) {
        j = i * Current.NbrHar + 2 * k;
        LinAlg_GetDoubleInVector(&d1, &DofData_P->CurrentSolution->x, j);
        LinAlg_GetDoubleInVector(&d2, &DofData_P->CurrentSolution->x, j + 1);
        d += d1 * cos(Pulsation[k] * Time) - d2 * sin(Pulsation[k] * Time);
      }
      LinAlg_SetDoubleInVector(d, &x, i);
    }

    Format ? LinAlg_WriteVector(File_RES, &x) :
             LinAlg_PrintVector(File_RES, &x);

    fprintf(File_RES, "$EndSolution\n");
  }

  Dof_CloseFile(DOF_RES);

  LinAlg_DestroyVector(&x);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ W r i t e F i l e R E S                                         */
/* ------------------------------------------------------------------------ */

void Dof_WriteFileRES(char *Name_File, struct DofData *DofData_P, int Format,
                      double Val_Time, double Val_TimeImag, int Val_TimeStep)
{
  if(Message::GetIsCommWorld() && Message::GetCommRank()) return;

  if(!DofData_P->CurrentSolution) {
    Message::Warning("No solution to save");
    return;
  }

  Dof_OpenFile(DOF_RES, Name_File, (char *)(Format ? "ab" : "a"));

  fprintf(File_RES, "$Solution  /* DofData #%d */\n", DofData_P->Num);
  fprintf(File_RES, "%d %.16g %.16g %d\n", DofData_P->Num, Val_Time,
          Val_TimeImag, Val_TimeStep);

  Format ? LinAlg_WriteVector(File_RES, &DofData_P->CurrentSolution->x) :
           LinAlg_PrintVector(File_RES, &DofData_P->CurrentSolution->x);

  fprintf(File_RES, "$EndSolution\n");

  Dof_CloseFile(DOF_RES);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ W r i t e F i l e R E S _ W i t h E n t i t y N u m             */
/* ------------------------------------------------------------------------ */

void Dof_WriteFileRES_WithEntityNum(char *Name_File, struct DofData *DofData_P,
                                    struct GeoData *GeoData_P0,
                                    struct Group *Group_P, bool saveFixed)
{
  if(Message::GetIsCommWorld() && Message::GetCommRank()) return;

  if(!DofData_P->CurrentSolution) {
    Message::Warning("No solution to save");
    return;
  }

  std::map<int, std::map<int, std::complex<double> > > unknowns;

  List_T *l = !DofData_P->DofList ? Tree2List(DofData_P->DofTree) : 0;
  int N = l ? List_Nbr(l) : List_Nbr(DofData_P->DofList);
  for(int i = 0; i < N; i++) {
    struct Dof *dof;
    if(l)
      dof = (Dof *)List_Pointer(l, i);
    else
      dof = (Dof *)List_Pointer(DofData_P->DofList, i);
    if(dof->Type == DOF_UNKNOWN || dof->Type == DOF_UNKNOWN_INIT) {
      gScalar s;
      LinAlg_GetScalarInVector(&s, &DofData_P->CurrentSolution->x,
                               dof->Case.Unknown.NumDof - 1);
      unknowns[dof->NumType][dof->Entity] = s.s;
    }
    if(saveFixed && dof->Type == DOF_FIXED) {
      unknowns[dof->NumType][dof->Entity] = dof->Val.s;
    }
  }

  for(std::map<int, std::map<int, std::complex<double> > >::iterator it =
        unknowns.begin();
      it != unknowns.end(); it++) {
    // create files that can be interpreted by ListFromFile and
    // Value/VectorFromIndex
    char FileRe[256], FileIm[256];
    if(unknowns.size() > 1) {
      sprintf(FileRe, "%s_%d", Name_File, it->first);
      sprintf(FileIm, "%s_%d", Name_File, it->first);
    }
    else {
      strcpy(FileRe, Name_File);
      strcpy(FileIm, Name_File);
    }
    if(Current.NbrHar > 1) {
      strcat(FileRe, "_Re.txt");
      strcat(FileIm, "_Im.txt");
    }
    else {
      strcat(FileRe, ".txt");
      strcat(FileIm, ".txt");
    }
    FILE *fpRe = FOpen(FileRe, "w");
    if(!fpRe) {
      Message::Error("Unable to open file '%s'", FileRe);
      return;
    }
    FILE *fpIm = 0;
    if(Current.NbrHar > 1) {
      fpIm = FOpen(FileIm, "w");
      if(!fpIm) {
        Message::Error("Unable to open file '%s'", FileIm);
        return;
      }
    }

    // create vectors that can be shared as lists
    std::vector<double> exportRe, exportIm;

    if(!Group_P) {
      int n = (int)it->second.size();
      fprintf(fpRe, "%d\n", n);
      exportRe.push_back(n);
      if(fpIm) {
        fprintf(fpIm, "%d\n", n);
        exportIm.push_back(n);
      }
      for(std::map<int, std::complex<double> >::iterator it2 =
            it->second.begin();
          it2 != it->second.end(); it2++) {
        fprintf(fpRe, "%d %.16g\n", it2->first, it2->second.real());
        exportRe.push_back(it2->first);
        exportRe.push_back(it2->second.real());
        if(fpIm) {
          fprintf(fpIm, "%d %.16g\n", it2->first, it2->second.imag());
          exportIm.push_back(it2->first);
          exportIm.push_back(it2->second.imag());
        }
      }
    }
    else {
      Message::Info("Writing solution for all entities in group '%s'",
                    Group_P->Name);

      // force generation of extended list (necessary when using multiple
      // meshes)
      List_Delete(Group_P->ExtendedList);
      Generate_ExtendedGroup(Group_P);
      int n = List_Nbr(Group_P->ExtendedList);
      fprintf(fpRe, "%d\n", n);
      exportRe.push_back(n);
      if(fpIm) {
        fprintf(fpIm, "%d\n", n);
        exportIm.push_back(n);
      }
      for(int i = 0; i < List_Nbr(Group_P->ExtendedList); i++) {
        int num;
        List_Read(Group_P->ExtendedList, i, &num);
        if(!Group_P->InitialSuppList ||
           (!List_Search(Group_P->ExtendedSuppList, &num, fcmp_int))) {
          // SuppList assumed to be "Not"!
          if(it->second.count(num)) {
            std::complex<double> s = it->second[num];
            fprintf(fpRe, "%d %.16g\n", num, s.real());
            exportRe.push_back(num);
            exportRe.push_back(s.real());
            if(fpIm) {
              fprintf(fpIm, "%d %.16g\n", num, s.imag());
              exportIm.push_back(num);
              exportIm.push_back(s.imag());
            }
          }
          else {
            // yes, write zero: that's on purpose for the iterative schemes
            fprintf(fpRe, "%d 0\n", num);
            exportRe.push_back(num);
            exportRe.push_back(0);
            if(fpIm) {
              fprintf(fpIm, "%d 0\n", num);
              exportIm.push_back(num);
              exportIm.push_back(0);
            }
          }
        }
      }
    }
    fclose(fpRe);
    GetDPNumbers[FileRe] = exportRe;
    if(fpIm) {
      fclose(fpIm);
      GetDPNumbers[FileIm] = exportIm;
    }
  }

  List_Delete(l);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ R e a d F i l e R E S                                           */
/* ------------------------------------------------------------------------ */

void Dof_ReadFileRES(List_T *DofData_L, struct DofData *Read_DofData_P,
                     int Read_DofData, double *Time, double *TimeImag,
                     double *TimeStep)
{
  Message::Barrier();

  int Num_DofData, Val_TimeStep, Format = 0, Read;
  double Val_Time, Val_TimeImag = 0., Version = 0.;
  struct DofData *DofData_P = NULL;
  struct Solution Solution_S;
  char String[256];

  while(1) {
    do {
      if(!fgets(String, sizeof(String), File_RES)) break;
      if(feof(File_RES)) break;
    } while(String[0] != '$');

    if(feof(File_RES)) break;

    /*  F o r m a t  */

    if(!strncmp(&String[1], "ResFormat", 9)) {
      if(fscanf(File_RES, "%lf %d\n", &Version, &Format) != 2) {
        Message::Error("Could not read ResFormat");
        return;
      }
    }

    /*  S o l u t i o n  */

    if(!strncmp(&String[1], "Solution", 8)) {
      /* don't use fscanf directly on the stream here: the data that
     follows can be binary, and the first character could be
     e.g. 0x0d, which would cause fscanf to eat-up one character
     too much, leading to an offset in fread */
      if(!fgets(String, sizeof(String), File_RES)) {
        Message::Error("Could not read Solution");
        return;
      }
      if(Version <= 1.0)
        sscanf(String, "%d %lf %d", &Num_DofData, &Val_Time, &Val_TimeStep);
      else
        sscanf(String, "%d %lf %lf %d", &Num_DofData, &Val_Time, &Val_TimeImag,
               &Val_TimeStep);

      if(Read_DofData < 0) {
        Read = 1;
        DofData_P = (struct DofData *)List_Pointer(DofData_L, Num_DofData);
      }
      else if(Num_DofData == Read_DofData) {
        Read = 1;
        DofData_P = Read_DofData_P;
      }
      else {
        Read = 0;
      }

      if(Read) {
        Solution_S.Time = Val_Time;
        Solution_S.TimeImag = Val_TimeImag;
        Solution_S.TimeStep = Val_TimeStep;
        Solution_S.SolutionExist = 1;
        Solution_S.TimeFunctionValues = NULL;

        LinAlg_CreateVector(&Solution_S.x, &DofData_P->Solver,
                            DofData_P->NbrDof);
        Format ? LinAlg_ReadVector(File_RES, &Solution_S.x) :
                 LinAlg_ScanVector(File_RES, &Solution_S.x);

        if(DofData_P->Solutions == NULL)
          DofData_P->Solutions = List_Create(20, 20, sizeof(struct Solution));
        List_Add(DofData_P->Solutions, &Solution_S);
      }
    }

    do {
      if(!fgets(String, sizeof(String), File_RES) || feof(File_RES)) {
        Message::Warning("Premature end of file (Time Step %d)", Val_TimeStep);
        break;
      }
    } while(String[0] != '$');

  } /* while 1 ... */

  *Time = Val_Time;
  *TimeImag = Val_TimeImag;
  *TimeStep = (double)Val_TimeStep;
}

/* ------------------------------------------------------------------------ */
/*  D o f _ T r a n s f e r D o f T r e e T o L i s t                       */
/* ------------------------------------------------------------------------ */

void Dof_TransferDofTreeToList(struct DofData *DofData_P)
{
  if(DofData_P->DofTree) {
    DofData_P->DofList = Tree2List(DofData_P->DofTree);
    Tree_Delete(DofData_P->DofTree);
    DofData_P->DofTree = NULL;
    DofData_P->NbrAnyDof = List_Nbr(DofData_P->DofList);
  }

  Dof_InitDofType(DofData_P);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ I n i t D o f T y p e                                           */
/* ------------------------------------------------------------------------ */

void Dof_InitDofType(struct DofData *DofData_P)
{
  struct Dof *Dof_P, *Dof_P0;
  int i;

  if(!DofData_P->NbrAnyDof) { return; }

  Dof_P0 = (struct Dof *)List_Pointer(DofData_P->DofList, 0);

  for(i = 0; i < DofData_P->NbrAnyDof; i++) {
    Dof_P = Dof_P0 + i;

    switch(Dof_P->Type) {
    case DOF_LINK:
    case DOF_LINKCPLX:
      Dof_P->Case.Link.Dof = Dof_GetDofStruct(
        DofData_P, Dof_P->NumType, Dof_P->Case.Link.EntityRef, Dof_P->Harmonic);
      if(Dof_P->Case.Link.Dof == NULL ||
         Dof_P->Case.Link.Dof == Dof_GetDofStruct(DofData_P, Dof_P->NumType,
                                                  Dof_P->Entity,
                                                  Dof_P->Harmonic)) {
        Dof_P->Case.Link.Dof = /* Attention: bricolage ... */
          Dof_GetDofStruct(DofData_P, Dof_P->NumType - 1,
                           Dof_P->Case.Link.EntityRef, Dof_P->Harmonic);
        if(Dof_P->Case.Link.Dof == NULL)
          Message::Error(
            "Wrong Link Constraint: reference Dof (%d %d %d) does not exist",
            Dof_P->NumType, Dof_P->Case.Link.EntityRef, Dof_P->Harmonic);
      }
      /*
      if(Dof_P->Case.Link.Dof == NULL)
    Message::Error("Wrong Link Constraint: reference Dof (%d %d %d) does not
    exist", Dof_P->NumType, Dof_P->Case.Link.EntityRef, Dof_P->Harmonic);
      */
      break;
    default: break;
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  P R E P R O C E S S I N G   ( C o d e s   i n   T r e e )               */
/* ------------------------------------------------------------------------ */

/* ------------------------------------------------------------------------ */
/*  D o f _ A d d F u n c t i o n S p a c e I n d e x                       */
/* ------------------------------------------------------------------------ */

void Dof_AddFunctionSpaceIndex(int Index_FunctionSpace)
{
  if(CurrentDofData->FunctionSpaceIndex == NULL)
    CurrentDofData->FunctionSpaceIndex = List_Create(10, 5, sizeof(int));

  if(List_PQuery(CurrentDofData->FunctionSpaceIndex, &Index_FunctionSpace,
                 fcmp_int) == NULL) {
    List_Add(CurrentDofData->FunctionSpaceIndex, &Index_FunctionSpace);
    List_Sort(CurrentDofData->FunctionSpaceIndex, fcmp_int);
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ A d d T i m e F u n c t i o n I n d e x                         */
/* ------------------------------------------------------------------------ */

void Dof_AddTimeFunctionIndex(int Index_TimeFunction)
{
  if(List_PQuery(CurrentDofData->TimeFunctionIndex, &Index_TimeFunction,
                 fcmp_int) == NULL) {
    List_Add(CurrentDofData->TimeFunctionIndex, &Index_TimeFunction);
    List_Sort(CurrentDofData->TimeFunctionIndex, fcmp_int);
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ A d d P u l s a t i o n                                         */
/* ------------------------------------------------------------------------ */

void Dof_AddPulsation(struct DofData *DofData_P, double Val_Pulsation)
{
  if(DofData_P->Pulsation == NULL)
    DofData_P->Pulsation = List_Create(1, 2, sizeof(double));
  List_Add(DofData_P->Pulsation, &Val_Pulsation);
  /*
  if(List_PQuery
      (DofData_P->Pulsation, &Val_Pulsation, fcmp_double) == NULL) {
    List_Add(DofData_P->Pulsation, &Val_Pulsation) ;
    List_Sort(DofData_P->Pulsation, fcmp_double) ;
  }
  */
}

/* ------------------------------------------------------------------------ */
/*  D o f _ D e f i n e A s s i g n F i x e d D o f                         */
/* ------------------------------------------------------------------------ */

void Dof_DefineAssignFixedDof(int D1, int D2, int NbrHar, double *Val,
                              int Index_TimeFunction)
{
  struct Dof Dof, *Dof_P;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(!(Dof_P = (struct Dof *)Tree_PQuery(CurrentDofData->DofTree, &Dof))) {
      Dof.Type = DOF_FIXED;
      LinAlg_SetScalar(&Dof.Val, &Val[k]);
      Dof.Case.FixedAssociate.TimeFunctionIndex = Index_TimeFunction + 1;
      Dof_AddTimeFunctionIndex(Index_TimeFunction + 1);
      Tree_Add(CurrentDofData->DofTree, &Dof);
    }
    else if(Dof_P->Type == DOF_UNKNOWN) {
      if(Message::GetVerbosity() == 10)
        Message::Info("Overriding unknown Dof with fixed Dof");
      Dof_P->Type = DOF_FIXED;
      LinAlg_SetScalar(&Dof_P->Val, &Val[k]);
      Dof_P->Case.FixedAssociate.TimeFunctionIndex = Index_TimeFunction + 1;
      Dof_AddTimeFunctionIndex(Index_TimeFunction + 1);
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ D e f i n e A s s i g n S o l v e D o f                         */
/* ------------------------------------------------------------------------ */

void Dof_DefineAssignSolveDof(int D1, int D2, int NbrHar,
                              int Index_TimeFunction)
{
  struct Dof Dof;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
      Dof.Type = DOF_FIXED_SOLVE;
      Dof.Case.FixedAssociate.TimeFunctionIndex = Index_TimeFunction + 1;
      Dof_AddTimeFunctionIndex(Index_TimeFunction + 1);
      Tree_Add(CurrentDofData->DofTree, &Dof);
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ D e f i n e I n i t F i x e d D o f                             */
/* ------------------------------------------------------------------------ */

void Dof_DefineInitFixedDof(int D1, int D2, int NbrHar, double *Val,
                            double *Val2, bool NonLocal)
{
  struct Dof Dof;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
      Dof.Type = DOF_UNKNOWN_INIT;
      LinAlg_SetScalar(&Dof.Val, &Val[k]);
      LinAlg_SetScalar(&Dof.Val2, &Val2[k]);
      Dof.Case.Unknown.NumDof = ++(CurrentDofData->NbrDof);
      Dof.Case.Unknown.NonLocal = NonLocal;
      Tree_Add(CurrentDofData->DofTree, &Dof);
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ D e f i n e I n i t S o l v e D o f                             */
/* ------------------------------------------------------------------------ */

void Dof_DefineInitSolveDof(int D1, int D2, int NbrHar)
{
  struct Dof Dof;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
      Dof.Type = DOF_UNKNOWN_INIT;
      Dof.Case.Unknown.NumDof = ++(CurrentDofData->NbrDof);
      Dof.Case.Unknown.NonLocal = false;
      Tree_Add(CurrentDofData->DofTree, &Dof);
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ D e f i n e L i n k D o f                                       */
/* ------------------------------------------------------------------------ */

void Dof_DefineLinkDof(int D1, int D2, int NbrHar, double Value[], int D2_Link)
{
  struct Dof Dof;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
      Dof.Type = DOF_LINK;
      Dof.Case.Link.Coef = Value[0];
      Dof.Case.Link.EntityRef = D2_Link;
      Dof.Case.Link.Dof = NULL;
      Tree_Add(CurrentDofData->DofTree, &Dof);
    }
  }
}

void Dof_DefineLinkCplxDof(int D1, int D2, int NbrHar, double Value[],
                           int D2_Link)
{
  struct Dof Dof;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
      Dof.Type = DOF_LINKCPLX;
      Dof.Case.Link.Coef = Value[0];
      Dof.Case.Link.Coef2 = Value[1];
      Dof.Case.Link.EntityRef = D2_Link;
      Dof.Case.Link.Dof = NULL;
      Tree_Add(CurrentDofData->DofTree, &Dof);
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ D e f i n e U n k n o w n D o f                                 */
/* ------------------------------------------------------------------------ */

void Dof_DefineUnknownDof(int D1, int D2, int NbrHar, bool NonLocal)
{
  struct Dof Dof;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
      Dof.Type = DOF_UNKNOWN;
      /* Dof.Case.Unknown.NumDof = ++(CurrentDofData->NbrDof) ; */
      Dof.Case.Unknown.NumDof = -1;
      Dof.Case.Unknown.NonLocal = NonLocal;
      Tree_Add(CurrentDofData->DofTree, &Dof);
    }
  }
}

static void NumberUnknownDof(void *a, void *b)
{
  struct Dof *Dof_P;

  Dof_P = (struct Dof *)a;

  if(Dof_P->Type == DOF_UNKNOWN) {
    if(Dof_P->Case.Unknown.NumDof == -1)
      Dof_P->Case.Unknown.NumDof = ++(CurrentDofData->NbrDof);
    if(Dof_P->Case.Unknown.NonLocal)
      CurrentDofData->NonLocalEquations.push_back(Dof_P->Case.Unknown.NumDof);
  }
}

void Dof_NumberUnknownDof(void)
{
  if(CurrentDofData->DofTree)
    Tree_Action(CurrentDofData->DofTree, NumberUnknownDof);
  else
    List_Action(CurrentDofData->DofList, NumberUnknownDof);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ D e f i n e A s s o c i a t e D o f                             */
/* ------------------------------------------------------------------------ */

void Dof_DefineAssociateDof(int E1, int E2, int D1, int D2, int NbrHar,
                            int init, double *Val)
{
  struct Dof Dof, Equ, *Equ_P;
  int k;

  Equ.NumType = E1;
  Equ.Entity = E2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Equ.Harmonic = k;
    if((Equ_P = (struct Dof *)Tree_PQuery(CurrentDofData->DofTree, &Equ))) {
      switch(Equ_P->Type) {
      case DOF_FIXED:
        Equ_P->Type = DOF_FIXEDWITHASSOCIATE;
        Equ_P->Case.FixedAssociate.NumDof = ++(CurrentDofData->NbrDof);
        /* To be modified (Patrick): strange to define a new NumDof for Equ if
           associate-Dof already exists */
        Dof.NumType = D1;
        Dof.Entity = D2;
        Dof.Harmonic = k;
        if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
          if(!init) { Dof.Type = DOF_UNKNOWN; }
          else {
            Dof.Type = DOF_UNKNOWN_INIT;
            LinAlg_SetScalar(&Dof.Val, &Val[k]);
            LinAlg_ZeroScalar(&Dof.Val2);
          }
          Dof.Case.Unknown.NumDof = CurrentDofData->NbrDof;
          Dof.Case.Unknown.NonLocal = true;
          Tree_Add(CurrentDofData->DofTree, &Dof);
        }
        break;
      case DOF_FIXED_SOLVE:
        Equ_P->Type = DOF_FIXEDWITHASSOCIATE_SOLVE;
        Equ_P->Case.FixedAssociate.NumDof = ++(CurrentDofData->NbrDof);
        Dof.NumType = D1;
        Dof.Entity = D2;
        Dof.Harmonic = k;
        if(!Tree_PQuery(CurrentDofData->DofTree, &Dof)) {
          if(!init) { Dof.Type = DOF_UNKNOWN; }
          else {
            Dof.Type = DOF_UNKNOWN_INIT;
            LinAlg_SetScalar(&Dof.Val, &Val[k]);
            LinAlg_ZeroScalar(&Dof.Val2);
          }
          Dof.Case.Unknown.NumDof = CurrentDofData->NbrDof;
          Dof.Case.Unknown.NonLocal = true;
          Tree_Add(CurrentDofData->DofTree, &Dof);
        }
        break;
      case DOF_UNKNOWN:
      case DOF_UNKNOWN_INIT: Dof_DefineUnknownDof(D1, D2, NbrHar); break;
      }
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  P R O C E S S I N G   ( C o d e s   i n   L i s t )                     */
/* ------------------------------------------------------------------------ */

/* ------------------------------------------------------------------------ */
/*  D o f _ G e t D o f S t r u c t                                         */
/* ------------------------------------------------------------------------ */

struct Dof *Dof_GetDofStruct(struct DofData *DofData_P, int D1, int D2, int D3)
{
  struct Dof Dof;

  Dof.NumType = D1;
  Dof.Entity = D2;
  Dof.Harmonic = D3;

  return (struct Dof *)List_PQuery(DofData_P->DofList, &Dof, fcmp_Dof);
}

/* ------------------------------------------------------------------------ */
/*  D o f _ U p d a t e A s s i g n F i x e d D o f                         */
/* ------------------------------------------------------------------------ */

void Dof_UpdateAssignFixedDof(int D1, int D2, int NbrHar, double *Val,
                              double *Val2)
{
  struct Dof Dof, *Dof_P;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(CurrentDofData->DofTree)
      Dof_P = (struct Dof *)Tree_PQuery(CurrentDofData->DofTree, &Dof);
    else
      Dof_P =
        (struct Dof *)List_PQuery(CurrentDofData->DofList, &Dof, fcmp_Dof);
    LinAlg_SetScalar(&Dof_P->Val, &Val[Dof_P->Harmonic]);
    LinAlg_SetScalar(&Dof_P->Val2, &Val2[Dof_P->Harmonic]);
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ U p d a t e L i n k D o f                                       */
/* ------------------------------------------------------------------------ */

void Dof_UpdateLinkDof(int D1, int D2, int NbrHar, double Value[], int D2_Link)
{
  struct Dof Dof, *Dof_P;
  int k;

  Dof.NumType = D1;
  Dof.Entity = D2;

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    Dof.Harmonic = k;
    if(CurrentDofData->DofTree)
      Dof_P = (struct Dof *)Tree_PQuery(CurrentDofData->DofTree, &Dof);
    else
      Dof_P =
        (struct Dof *)List_PQuery(CurrentDofData->DofList, &Dof, fcmp_Dof);

    if(Dof_P->Type == DOF_LINK || Dof_P->Type == DOF_LINKCPLX) {
      /*
        fprintf(stderr,"===> %d %d %.16g\n", Dof_P->NumType, Dof_P->Entity,
        Value[0]) ;
      */
      Dof_P->Case.Link.Coef = Value[0];
      if(Dof_P->Type == DOF_LINKCPLX) Dof_P->Case.Link.Coef2 = Value[1];
      Dof_P->Case.Link.EntityRef = D2_Link;
      Dof_P->Case.Link.Dof = NULL;
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ A s s e m b l e I n M a t                                       */
/* ------------------------------------------------------------------------ */

void Dof_AssembleInMat(struct Dof *Equ_P, struct Dof *Dof_P, int NbrHar,
                       double *Val, gMatrix *Mat, gVector *Vec, List_T *Vecs)
{
  gScalar tmp, tmp2;
  double valtmp[2], d1, d2;

  switch(Equ_P->Type) {
  case DOF_UNKNOWN:
  case DOF_FIXEDWITHASSOCIATE:

    switch(Dof_P->Type) {
    case DOF_UNKNOWN:
      if(Current.DofData->Flag_RHS) break;
      if(NbrHar == 1) {
        LinAlg_AddDoubleInMatrix(Val[0], Mat, Equ_P->Case.Unknown.NumDof - 1,
                                 Dof_P->Case.Unknown.NumDof - 1);
      }
      else
        LinAlg_AddComplexInMatrix(
          Val[0], Val[1], Mat, Equ_P->Case.Unknown.NumDof - 1,
          Dof_P->Case.Unknown.NumDof - 1,
          (gSCALAR_SIZE == 1) ? ((Equ_P + 1)->Case.Unknown.NumDof - 1) : -1,
          (gSCALAR_SIZE == 1) ? ((Dof_P + 1)->Case.Unknown.NumDof - 1) : -1);
      break;

    case DOF_FIXED:
    case DOF_FIXEDWITHASSOCIATE:
      if(Vec) {
        if(NbrHar == 1) {
          if(Val[0]) {
            LinAlg_ProdScalarDouble(
              &Dof_P->Val,
              CurrentDofData->CurrentSolution->TimeFunctionValues
                [Dof_P->Case.FixedAssociate.TimeFunctionIndex],
              &tmp);
            LinAlg_ProdScalarDouble(&tmp, -Val[0], &tmp);
            LinAlg_AddScalarInVector(&tmp, Vec, Equ_P->Case.Unknown.NumDof - 1);
            if(Vecs) { // experimental
              int index = List_ISearchSeq(
                Current.DofData->TimeFunctionIndex,
                &Dof_P->Case.FixedAssociate.TimeFunctionIndex, fcmp_int);
              if(index >= 0 && index < List_Nbr(Vecs)) {
                gVector *v = (gVector *)List_Pointer(Vecs, index);
                LinAlg_AddScalarInVector(&tmp, v,
                                         Equ_P->Case.Unknown.NumDof - 1);
              }
              else {
                Message::Error("Something wrong in multi-vec assembly");
              }
            }
          }
        }
        else {
          LinAlg_ProdScalarDouble(
            &Dof_P->Val,
            CurrentDofData->CurrentSolution->TimeFunctionValues
              [Dof_P->Case.FixedAssociate.TimeFunctionIndex],
            &tmp);
          if(gSCALAR_SIZE == 2) {
            LinAlg_ProdScalarComplex(&tmp, -Val[0], -Val[1], &valtmp[0],
                                     &valtmp[1]);
          }
          else {
            LinAlg_GetDoubleInScalar(&d1, &tmp);
            LinAlg_ProdScalarDouble(
              &(Dof_P + 1)->Val,
              CurrentDofData->CurrentSolution->TimeFunctionValues
                [Dof_P->Case.FixedAssociate.TimeFunctionIndex],
              &tmp2);
            LinAlg_GetDoubleInScalar(&d2, &tmp2);
            valtmp[0] = -d1 * Val[0] + d2 * Val[1];
            valtmp[1] = -d1 * Val[1] - d2 * Val[0];
          }
          LinAlg_AddComplexInVector(
            valtmp[0], valtmp[1], Vec, Equ_P->Case.Unknown.NumDof - 1,
            (gSCALAR_SIZE == 1) ? ((Equ_P + 1)->Case.Unknown.NumDof - 1) : -1);
        }
      }
      break;

    case DOF_LINK:
      if(NbrHar == 1)
        valtmp[0] = Val[0] * Dof_P->Case.Link.Coef;
      else {
        valtmp[0] = Val[0] * Dof_P->Case.Link.Coef;
        valtmp[1] = Val[1] * Dof_P->Case.Link.Coef;
      }
      Dof_AssembleInMat(Equ_P, Dof_P->Case.Link.Dof, NbrHar, valtmp, Mat, Vec,
                        Vecs);
      break;

    case DOF_LINKCPLX:
      if(NbrHar == 1)
        Message::Error("LinkCplx only valid for Complex systems");
      else {
        valtmp[0] =
          Val[0] * Dof_P->Case.Link.Coef - Val[1] * Dof_P->Case.Link.Coef2;
        valtmp[1] =
          Val[1] * Dof_P->Case.Link.Coef + Val[0] * Dof_P->Case.Link.Coef2;
      }
      Dof_AssembleInMat(Equ_P, Dof_P->Case.Link.Dof, NbrHar, valtmp, Mat, Vec,
                        Vecs);
      break;

    case DOF_FIXED_SOLVE:
    case DOF_FIXEDWITHASSOCIATE_SOLVE:
      Message::Error("Wrong Constraints: "
                     "remaining Dof(s) waiting to be fixed by a Resolution");
      break;

    case DOF_UNKNOWN_INIT:
      Message::Error("Wrong Initial Constraints: "
                     "remaining Dof(s) with non-fixed initial conditions");
      break;
    }

    break;

  case DOF_LINK:
    if(NbrHar == 1)
      valtmp[0] = Val[0] * Equ_P->Case.Link.Coef;
    else {
      valtmp[0] = Val[0] * Equ_P->Case.Link.Coef;
      valtmp[1] = Val[1] * Equ_P->Case.Link.Coef;
    }
    Dof_AssembleInMat(Equ_P->Case.Link.Dof, Dof_P, NbrHar, valtmp, Mat, Vec,
                      Vecs);
    break;

  case DOF_LINKCPLX:
    if(NbrHar == 1)
      Message::Error("LinkCplx only valid for Complex systems");
    else { /* Warning: conjugate! */
      valtmp[0] =
        Val[0] * Equ_P->Case.Link.Coef + Val[1] * Equ_P->Case.Link.Coef2;
      valtmp[1] =
        Val[1] * Equ_P->Case.Link.Coef - Val[0] * Equ_P->Case.Link.Coef2;
    }
    Dof_AssembleInMat(Equ_P->Case.Link.Dof, Dof_P, NbrHar, valtmp, Mat, Vec,
                      Vecs);
    break;
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ A s s e m b l e I n V e c                                       */
/* ------------------------------------------------------------------------ */

void Dof_AssembleInVec(struct Dof *Equ_P, struct Dof *Dof_P, int NbrHar,
                       double *Val, struct Solution *OtherSolution,
                       gVector *Vec0, gVector *Vec)
{
  gScalar tmp;
  double valtmp[2];
  double a, b, c, d;

  switch(Equ_P->Type) {
  case DOF_UNKNOWN:
  case DOF_FIXEDWITHASSOCIATE:

    switch(Dof_P->Type) {
    case DOF_UNKNOWN:
      if(NbrHar == 1) {
        if(Val[0]) {
          LinAlg_GetDoubleInVector(&a, Vec0, Dof_P->Case.Unknown.NumDof - 1);
          a *= Val[0];
          LinAlg_AddDoubleInVector(a, Vec, Equ_P->Case.Unknown.NumDof - 1);
        }
      }
      else {
        LinAlg_GetComplexInVector(
          &a, &b, Vec0, Dof_P->Case.Unknown.NumDof - 1,
          (gSCALAR_SIZE == 1) ? ((Dof_P + 1)->Case.Unknown.NumDof - 1) : -1);
        c = a * Val[0] - b * Val[1];
        d = a * Val[1] + b * Val[0];
        LinAlg_AddComplexInVector(
          c, d, Vec, Equ_P->Case.Unknown.NumDof - 1,
          (gSCALAR_SIZE == 1) ? ((Equ_P + 1)->Case.Unknown.NumDof - 1) : -1);
      }
      break;

    case DOF_FIXED:
    case DOF_FIXEDWITHASSOCIATE:
      if(NbrHar == 1) {
        if(Val[0]) {
          LinAlg_ProdScalarDouble(
            &Dof_P->Val,
            Val[0] *
              OtherSolution->TimeFunctionValues[Dof_P->Case.FixedAssociate
                                                  .TimeFunctionIndex],
            &tmp);
          LinAlg_AddScalarInVector(&tmp, Vec, Equ_P->Case.Unknown.NumDof - 1);
        }
      }
      else {
        if(gSCALAR_SIZE == 2) {
          LinAlg_ProdScalarComplex(
            &Dof_P->Val,
            Val[0] *
              OtherSolution->TimeFunctionValues[Dof_P->Case.FixedAssociate
                                                  .TimeFunctionIndex],
            Val[1] *
              OtherSolution->TimeFunctionValues[Dof_P->Case.FixedAssociate
                                                  .TimeFunctionIndex],
            &a, &b);
          LinAlg_AddComplexInVector(
            a, b, Vec, Equ_P->Case.Unknown.NumDof - 1,
            (gSCALAR_SIZE == 1) ? ((Equ_P + 1)->Case.Unknown.NumDof - 1) : -1);
        }
        else {
          Message::Error("Assemby in vectors with more than one harmonic not "
                         "yet implemented");
        }
      }
      break;

    case DOF_LINK:
      if(NbrHar == 1)
        valtmp[0] = Val[0] * Dof_P->Case.Link.Coef;
      else {
        valtmp[0] = Val[0] * Dof_P->Case.Link.Coef;
        valtmp[1] = Val[1] * Dof_P->Case.Link.Coef;
      }
      Dof_AssembleInVec(Equ_P, Dof_P->Case.Link.Dof, NbrHar, valtmp,
                        OtherSolution, Vec0, Vec);
      break;

    case DOF_LINKCPLX:
      if(NbrHar == 1)
        Message::Error("LinkCplx only valid for Complex systems");
      else {
        valtmp[0] =
          Val[0] * Dof_P->Case.Link.Coef - Val[1] * Dof_P->Case.Link.Coef2;
        valtmp[1] =
          Val[1] * Dof_P->Case.Link.Coef + Val[0] * Dof_P->Case.Link.Coef2;
      }
      Dof_AssembleInVec(Equ_P, Dof_P->Case.Link.Dof, NbrHar, valtmp,
                        OtherSolution, Vec0, Vec);
      break;

    case DOF_FIXED_SOLVE:
    case DOF_FIXEDWITHASSOCIATE_SOLVE:
      Message::Error("Wrong Constraints: "
                     "remaining Dof(s) waiting to be fixed by a Resolution");
      break;

    case DOF_UNKNOWN_INIT:
      Message::Error("Wrong Initial Constraints: "
                     "remaining Dof(s) with non-fixed initial conditions");
      break;
    }
    break;

  case DOF_LINK:
    if(NbrHar == 1)
      valtmp[0] = Val[0] * Equ_P->Case.Link.Coef;
    else {
      valtmp[0] = Val[0] * Equ_P->Case.Link.Coef;
      valtmp[1] = Val[1] * Equ_P->Case.Link.Coef;
    }
    Dof_AssembleInVec(Equ_P->Case.Link.Dof, Dof_P, NbrHar, valtmp,
                      OtherSolution, Vec0, Vec);
    break;

  case DOF_LINKCPLX:
    if(NbrHar == 1)
      Message::Error("LinkCplx only valid for Complex systems");
    else { /* Warning: conjugate! */
      valtmp[0] =
        Val[0] * Equ_P->Case.Link.Coef + Val[1] * Equ_P->Case.Link.Coef2;
      valtmp[1] =
        Val[1] * Equ_P->Case.Link.Coef - Val[0] * Equ_P->Case.Link.Coef2;
    }
    Dof_AssembleInVec(Equ_P->Case.Link.Dof, Dof_P, NbrHar, valtmp,
                      OtherSolution, Vec0, Vec);
    break;
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ T r a n s f e r S o l u t i o n T o C o n s t r a i n t         */
/* ------------------------------------------------------------------------ */

void Dof_TransferSolutionToConstraint(struct DofData *DofData_P)
{
  struct Dof *Dof_P, *Dof_P0;
  int i;

  if(!DofData_P->NbrAnyDof) { return; }

  Dof_P0 = (struct Dof *)List_Pointer(DofData_P->DofList, 0);

  for(i = 0; i < DofData_P->NbrAnyDof; i++) {
    Dof_P = Dof_P0 + i;

    switch(Dof_P->Type) {
    case DOF_UNKNOWN:
      Dof_P->Type = DOF_FIXED;
      LinAlg_GetScalarInVector(&Dof_P->Val, &DofData_P->CurrentSolution->x,
                               Dof_P->Case.Unknown.NumDof - 1);
      Dof_P->Case.FixedAssociate.TimeFunctionIndex = 0;
      break;

    case DOF_FIXED:
    case DOF_FIXEDWITHASSOCIATE:
    case DOF_LINK:
    case DOF_LINKCPLX: break;

    default: break;
    }
  }

  DofData_P->NbrDof = 0;
}

/* ------------------------------------------------------------------------ */
/*  D o f _ G e t D o f V a l u e                                           */
/* ------------------------------------------------------------------------ */

gScalar Dof_GetDofValue(struct DofData *DofData_P, struct Dof *Dof_P)
{
  gScalar tmp;

  switch(Dof_P->Type) {
  case DOF_UNKNOWN:
    if(!DofData_P->CurrentSolution->SolutionExist)
      Message::Error("Empty solution in DofData %d", DofData_P->Num);
    else
      LinAlg_GetScalarInVector(&tmp, &DofData_P->CurrentSolution->x,
                               Dof_P->Case.Unknown.NumDof - 1);
    break;

  case DOF_FIXED:
  case DOF_FIXEDWITHASSOCIATE:
    LinAlg_ProdScalarDouble(
      &Dof_P->Val,
      ((Dof_P->Case.FixedAssociate.TimeFunctionIndex) ?
         DofData_P->CurrentSolution
           ->TimeFunctionValues[Dof_P->Case.FixedAssociate.TimeFunctionIndex] :
         1.),
      &tmp);
    break;

  case DOF_LINK:
    tmp = Dof_GetDofValue(DofData_P, Dof_P->Case.Link.Dof);
    LinAlg_ProdScalarDouble(&tmp, Dof_P->Case.Link.Coef, &tmp);
    break;

  case DOF_LINKCPLX:
    /* Too soon to treat LinkCplx: we need the real and imaginary parts */
    Message::Error("Cannot call Dof_GetDofValue for LinkCplx");
    break;

  default: LinAlg_ZeroScalar(&tmp); break;
  }

  return tmp;
}

void Dof_GetRealDofValue(struct DofData *DofData_P, struct Dof *Dof_P,
                         double *d)
{
  gScalar tmp;

  if(Dof_P->Type == DOF_LINKCPLX) {
    Message::Error("Cannot call Dof_GetRealDofValue for LinkCplx");
    return;
  }

  tmp = Dof_GetDofValue(DofData_P, Dof_P);
  LinAlg_GetDoubleInScalar(d, &tmp);
}

void Dof_GetComplexDofValue(struct DofData *DofData_P, struct Dof *Dof_P,
                            double *d1, double *d2)
{
  gScalar tmp1, tmp2;
  double valtmp[2];

  if(gSCALAR_SIZE == 1) {
    if(Dof_P->Type == DOF_LINKCPLX) { /* Can only be done here */
      if(Dof_P->Case.Link.Dof->Type == DOF_LINKCPLX) { /* recurse */
        Dof_GetComplexDofValue(DofData_P, Dof_P->Case.Link.Dof, d1, d2);
      }
      else {
        tmp1 = Dof_GetDofValue(DofData_P, Dof_P->Case.Link.Dof);
        tmp2 = Dof_GetDofValue(DofData_P, (Dof_P + 1)->Case.Link.Dof);
        LinAlg_GetDoubleInScalar(d1, &tmp1);
        LinAlg_GetDoubleInScalar(d2, &tmp2);
      }
    }
    else {
      tmp1 = Dof_GetDofValue(DofData_P, Dof_P);
      tmp2 = Dof_GetDofValue(DofData_P, Dof_P + 1);
      LinAlg_GetDoubleInScalar(d1, &tmp1);
      LinAlg_GetDoubleInScalar(d2, &tmp2);
    }
  }
  else {
    if(Dof_P->Type == DOF_LINKCPLX) { /* Can only be done here */
      if(Dof_P->Case.Link.Dof->Type == DOF_LINKCPLX) { /* recurse */
        Dof_GetComplexDofValue(DofData_P, Dof_P->Case.Link.Dof, d1, d2);
      }
      else {
        tmp1 = Dof_GetDofValue(DofData_P, Dof_P->Case.Link.Dof);
        LinAlg_GetComplexInScalar(d1, d2, &tmp1);
      }
    }
    else {
      tmp1 = Dof_GetDofValue(DofData_P, Dof_P);
      LinAlg_GetComplexInScalar(d1, d2, &tmp1);
    }
  }

  if(Dof_P->Type == DOF_LINKCPLX) {
    valtmp[0] = Dof_P->Case.Link.Coef * (*d1) - Dof_P->Case.Link.Coef2 * (*d2);
    valtmp[1] = Dof_P->Case.Link.Coef * (*d2) + Dof_P->Case.Link.Coef2 * (*d1);
    *d1 = valtmp[0];
    *d2 = valtmp[1];
  }
}

/* ------------------------------------------------------------------------- */
/*  D o f _ D e f i n e Unknown D o f F r o m Solve o r Init D o f           */
/* ------------------------------------------------------------------------- */

void Dof_DefineUnknownDofFromSolveOrInitDof(struct DofData **DofData_P)
{
  int i, Nbr_AnyDof;
  struct Dof *Dof_P;

  Nbr_AnyDof = List_Nbr((*DofData_P)->DofList);

  for(i = 0; i < Nbr_AnyDof; i++) {
    Dof_P = (struct Dof *)List_Pointer((*DofData_P)->DofList, i);

    switch(Dof_P->Type) {
    case DOF_FIXED_SOLVE:
    case DOF_FIXEDWITHASSOCIATE_SOLVE:
      Dof_P->Type = DOF_UNKNOWN;
      Dof_P->Case.Unknown.NumDof = ++((*DofData_P)->NbrDof);
      break;
    case DOF_UNKNOWN_INIT: Dof_P->Type = DOF_UNKNOWN; break;
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ T r a n s f e r D o f                                           */
/* ------------------------------------------------------------------------ */

void Dof_TransferDof(struct DofData *DofData_P1, struct DofData **DofData_P2)
{
  int i, Nbr_AnyDof;
  struct Dof Dof, *Dof_P;
  struct Solution *Solutions_P0;

  Nbr_AnyDof = List_Nbr(DofData_P1->DofList);
  Solutions_P0 = (struct Solution *)List_Pointer(DofData_P1->Solutions, 0);
  DofData_P1->CurrentSolution = Solutions_P0;

  for(i = 0; i < Nbr_AnyDof; i++) {
    Dof = *(struct Dof *)List_Pointer(DofData_P1->DofList, i);
    if((Dof_P = (struct Dof *)Tree_PQuery((*DofData_P2)->DofTree, &Dof))) {
      switch(Dof_P->Type) {
      case DOF_FIXED_SOLVE:
        Dof_P->Type = DOF_FIXED;
        Dof_P->Val = Dof_GetDofValue(DofData_P1, &Dof);
        break;
      case DOF_FIXEDWITHASSOCIATE_SOLVE:
        Dof_P->Type = DOF_FIXEDWITHASSOCIATE;
        Dof_P->Val = Dof_GetDofValue(DofData_P1, &Dof);
        break;
      case DOF_UNKNOWN_INIT:
        /* A DOF_UNKNOWN_INIT will always use the value obtained by
           pre-resolution even if a simple Init contraint is given; we should
           introduce DOF_UNKNOWN_INIT_SOLVE */
        Dof_P->Val = Dof_GetDofValue(DofData_P1, &Dof);
        if((DofData_P1->CurrentSolution - Solutions_P0) > 0) {
          DofData_P1->CurrentSolution -= 1;
          Dof_P->Val2 = Dof_GetDofValue(DofData_P1, &Dof);
          DofData_P1->CurrentSolution += 1;
        }
        else {
          LinAlg_ZeroScalar(&Dof_P->Val2);
        }
        break;
      }
    }
  }
}

/* ------------------------------------------------------------------------ */
/*  D o f _ I n i t D o f F o r N o D o f                                   */
/* ------------------------------------------------------------------------ */

void Dof_InitDofForNoDof(struct Dof *DofForNoDof, int NbrHar)
{
  int k;
  double Val[2] = {1., 0.};

  for(k = 0; k < NbrHar; k += gSCALAR_SIZE) {
    int incr = (gSCALAR_SIZE == 2) ? k / 2 : k;
    struct Dof *D = DofForNoDof + incr;
    D->Type = DOF_FIXED;
    LinAlg_SetScalar(&D->Val, &Val[k % 2]);
    D->Case.FixedAssociate.TimeFunctionIndex = 0;
  }
}

/* ------------------------------------------------------- */
/*  P r i n t _  D o f N u m b e r                         */
/* ------------------------------------------------------- */

void Print_DofNumber(struct Dof *Dof_P)
{
  switch(Dof_P->Type) {
  case DOF_UNKNOWN:
    printf("%d(%d) ", Dof_P->Case.Unknown.NumDof, Dof_P->Entity);
    break;
  case DOF_FIXED: printf("Fixed(%d) ", Dof_P->Entity); break;
  case DOF_FIXEDWITHASSOCIATE:
    printf("Assoc-%d ", Dof_P->Case.FixedAssociate.NumDof);
    break;
  case DOF_LINK:
    printf("Link-");
    Print_DofNumber(Dof_P->Case.Link.Dof);
    break;
  case DOF_LINKCPLX:
    printf("LinkCplx-");
    Print_DofNumber(Dof_P->Case.Link.Dof);
    break;
  default: printf(" ? "); break;
  }
}

/* ------------------------------------------------------- */
/*  D u m m y  D o f s                                     */
/* ------------------------------------------------------- */

void Dof_GetDummies(struct DefineSystem *DefineSystem_P,
                    struct DofData *DofData_P)
{
  struct Formulation *Formulation_P;
  struct DefineQuantity *DefineQuantity_P;
  struct FunctionSpace *FunctionSpace_P;
  struct BasisFunction *BasisFunction_P;
  struct GlobalQuantity *GlobalQuantity_P;
  struct Dof *Dof_P;

  int i, j, k, l, iDof, ii, iit, iNum, iHar;
  int Nbr_Formulation, Index_Formulation;
  int *DummyDof;
  double FrequencySpectrum, *Val_Pulsation;

  if(!(Val_Pulsation = Current.DofData->Val_Pulsation)) {
    Message::Error("Dof_GetDummies can only be used for harmonic problems");
    return;
  }

  DummyDof = DofData_P->DummyDof =
    (int *)Malloc(DofData_P->NbrDof * sizeof(int));
  for(iDof = 0; iDof < DofData_P->NbrDof; iDof++) DummyDof[iDof] = 0;

  Nbr_Formulation = List_Nbr(DefineSystem_P->FormulationIndex);

  for(i = 0; i < Nbr_Formulation; i++) {
    List_Read(DefineSystem_P->FormulationIndex, i, &Index_Formulation);
    Formulation_P = (struct Formulation *)List_Pointer(Problem_S.Formulation,
                                                       Index_Formulation);
    for(j = 0; j < List_Nbr(Formulation_P->DefineQuantity); j++) {
      DefineQuantity_P =
        (struct DefineQuantity *)List_Pointer(Formulation_P->DefineQuantity, j);
      for(l = 0; l < List_Nbr(DefineQuantity_P->FrequencySpectrum); l++) {
        FrequencySpectrum =
          *(double *)List_Pointer(DefineQuantity_P->FrequencySpectrum, l);

        iHar = -1;
        for(k = 0; k < Current.NbrHar / 2; k++)
          if(fabs(Val_Pulsation[k] - TWO_PI * FrequencySpectrum) <=
             1e-10 * Val_Pulsation[k]) {
            iHar = 2 * k;
            break;
          }
        if(iHar >= 0) {
          FunctionSpace_P = (struct FunctionSpace *)List_Pointer(
            Problem_S.FunctionSpace, DefineQuantity_P->FunctionSpaceIndex);

          for(k = 0; k < List_Nbr(FunctionSpace_P->BasisFunction); k++) {
            BasisFunction_P = (struct BasisFunction *)List_Pointer(
              FunctionSpace_P->BasisFunction, k);
            iNum = ((struct BasisFunction *)BasisFunction_P)->Num;
            ii = iit = 0;
            for(iDof = 0; iDof < List_Nbr(DofData_P->DofList); iDof++) {
              Dof_P = (struct Dof *)List_Pointer(DofData_P->DofList, iDof);
              if(Dof_P->Type == DOF_UNKNOWN && Dof_P->NumType == iNum) {
                iit++;
                if(Dof_P->Harmonic == iHar || Dof_P->Harmonic == iHar + 1) {
                  DummyDof[Dof_P->Case.Unknown.NumDof - 1] = 1;
                  ii++;
                }
              }
            }
            if(ii)
              Message::Info(
                "Freq %4lg (%d/%d) Formulation %s Quantity %s "
                "(BF %d)  #DofsNotInFreqSpectrum %d/%d",
                Val_Pulsation[iHar / 2] / TWO_PI, iHar / 2, Current.NbrHar / 2,
                Formulation_P->Name, DefineQuantity_P->Name,
                ((struct BasisFunction *)BasisFunction_P)->Num, ii, iit);
          }

          for(k = 0; k < List_Nbr(FunctionSpace_P->GlobalQuantity); k++) {
            GlobalQuantity_P = (struct GlobalQuantity *)List_Pointer(
              FunctionSpace_P->GlobalQuantity, k);
            iNum = ((struct GlobalQuantity *)GlobalQuantity_P)->Num;
            ii = iit = 0;
            for(iDof = 0; iDof < List_Nbr(DofData_P->DofList); iDof++) {
              Dof_P = (struct Dof *)List_Pointer(DofData_P->DofList, iDof);
              if(Dof_P->Type == DOF_UNKNOWN && Dof_P->NumType == iNum) {
                iit++;
                if(Dof_P->Harmonic == iHar || Dof_P->Harmonic == iHar + 1) {
                  DummyDof[Dof_P->Case.Unknown.NumDof - 1] = 1;
                  ii++;
                }
              }
            }
            if(ii)
              Message::Info(
                "Freq %4lg (%d/%d) Formulation %s  GlobalQuantity %s "
                "(BF %d)  #DofsNotInFrequencySpectrum %d/%d",
                Val_Pulsation[iHar / 2] / TWO_PI, iHar / 2, Current.NbrHar / 2,
                Formulation_P->Name, GlobalQuantity_P->Name,
                ((struct GlobalQuantity *)GlobalQuantity_P)->Num, ii, iit);
          }

        } /*  end FrequencySpectrum in DofData */
      } /* end FrequencySpectrum in Quantity */
    } /* end Quantity */
  } /* end Formulation */

  i = 0;
  for(iDof = 0; iDof < DofData_P->NbrDof; iDof++) {
    if(DummyDof[iDof]) i++;

    if(Message::GetVerbosity() == 99) {
      Dof_P = (struct Dof *)List_Pointer(DofData_P->DofList, iDof);
      Message::Debug("Dof Num iHar, Entity %d %d %d", iDof, Dof_P->NumType,
                     Dof_P->Harmonic, Dof_P->Entity);
    }
  }

  Message::Info("N: %d - N with FrequencySpectrum: %d", DofData_P->NbrDof, i);
}
