From 0760af85159bc94407b8fef701beebb3c10e6278 Mon Sep 17 00:00:00 2001
From: Quentin Rodier <quentin.rodier@meteo.fr>
Date: Wed, 23 Jun 2021 11:10:19 +0200
Subject: [PATCH] T.Nagel 23/06/2021: IBM Object file reading to compute the
 Level Set function for any surface

---
 src/MNH/ibm_generls.f90 | 562 ++++++++++++++++++++++++++++++++++++++++
 src/MNH/ibm_prep_ls.f90 | 313 ++++++++++++++++++----
 2 files changed, 824 insertions(+), 51 deletions(-)
 create mode 100644 src/MNH/ibm_generls.f90

diff --git a/src/MNH/ibm_generls.f90 b/src/MNH/ibm_generls.f90
new file mode 100644
index 000000000..24592d216
--- /dev/null
+++ b/src/MNH/ibm_generls.f90
@@ -0,0 +1,562 @@
+!MNH_LIC Copyright 1994-2018 CNRS, Meteo-France and Universite Paul Sabatier
+!MNH_LIC This is part of the Meso-NH software governed by the CeCILL-C licence
+!MNH_LIC version 1. See LICENSE, CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt  
+!MNH_LIC for details. version 1.
+!
+!    #######################
+MODULE MODI_IBM_GENERLS  
+  !    ####################### 
+  !
+  INTERFACE
+     !
+     SUBROUTINE IBM_GENERLS(PIBM_FACES,PNORM_FACES,PV1,PV2,PV3,PX_MIN,PY_MIN,PX_MAX,PY_MAX,PPHI)
+       !
+       REAL, DIMENSION(:,:,:)   ,INTENT(IN)    :: PIBM_FACES  
+       REAL, DIMENSION(:,:)     ,INTENT(IN)    :: PNORM_FACES,PV1,PV2,PV3
+       REAL, DIMENSION(:,:,:,:) ,INTENT(INOUT) :: PPHI
+       REAL                     ,INTENT(IN)    :: PX_MIN,PY_MIN,PX_MAX,PY_MAX
+       !
+     END SUBROUTINE IBM_GENERLS
+     !
+  END INTERFACE
+  !
+END MODULE MODI_IBM_GENERLS
+!
+!     #####################################
+SUBROUTINE IBM_GENERLS(PIBM_FACES,PNORM_FACES,PV1,PV2,PV3,PX_MIN,PY_MIN,PX_MAX,PY_MAX,PPHI)
+  !     #####################################
+  !
+  !
+  !****  IBM_GENERLS computes the Level Set function for any surface       
+  !                
+  !    PURPOSE
+  !    -------
+  !****  The purpose of this routine is to estimate the level set
+  !      containing XYZ minimalisation interface locations
+
+  !    METHOD
+  !    ------
+  !****  Iterative system and minimization of the interface distance
+  !
+  !    EXTERNAL
+  !    --------
+  !      SUBROUTINE ?
+  !
+  !    IMPLICIT ARGUMENTS
+  !    ------------------
+  !       MODD_?   
+  !
+  !    REFERENCE
+  !    ---------
+  !    The method is based on '3D Distance from a Point to a Triangle'
+  !    a technical report from Mark W. Jones, University of Wales Swansea
+  !
+  !    AUTHORS
+  !    ------
+  !      Tim Nagel, Valéry Masson & Robert Schoetter 
+  !
+  !    MODIFICATIONS
+  !    -------------
+  !      Original         01/06/2021
+  !
+  !------------------------------------------------------------------------------
+  !       
+  !**** 0. DECLARATIONS
+  !     ---------------
+  !
+  ! module
+  USE MODE_POS
+  USE MODE_ll
+  USE MODE_IO
+  USE MODD_ARGSLIST_ll, ONLY : LIST_ll
+  !
+  ! declaration
+  USE MODD_IBM_PARAM_n
+  USE MODD_IBM_LSF
+  USE MODD_DIM_n, ONLY: NIMAX,NJMAX,NKMAX
+  USE MODD_PARAMETERS, ONLY: JPVEXT,JPHEXT,XUNDEF
+  USE MODD_GRID_n, ONLY: XXHAT,XYHAT,XZHAT,XZZ
+  USE MODD_METRICS_n, ONLY: XDXX,XDYY,XDZZ
+  USE MODD_VAR_ll, ONLY: IP
+  USE MODD_CST, ONLY: XMNH_EPSILON 
+  !
+  ! interface
+  USE MODI_SHUMAN
+  USE MODI_IBM_INTERPOS
+  USE MODI_IBM_DETECT
+  USE MODI_INI_CST
+  !
+  IMPLICIT NONE
+  !
+  !       0.1  declarations of arguments
+  !                                      
+  REAL, DIMENSION(:,:,:)   ,INTENT(IN)    :: PIBM_FACES     !faces coordinates
+  REAL, DIMENSION(:,:)     ,INTENT(IN)    :: PNORM_FACES    !normal
+  REAL, DIMENSION(:,:)     ,INTENT(IN)    :: PV1,PV2,PV3
+  REAL, DIMENSION(:,:,:,:) ,INTENT(INOUT) :: PPHI           ! LS functions
+  REAL                     ,INTENT(IN)    :: PX_MIN,PY_MIN,PX_MAX,PY_MAX           
+  !
+  !------------------------------------------------------------------------------
+  !
+  !       0.2  declaration of local variables
+  !
+  INTEGER :: JI,JJ,JK,JN,JM,JI2,JJ2,JK2                                       ! loop index
+  INTEGER :: JI_MIN,JI_MAX,JJ_MIN,JJ_MAX,JK_MIN,JK_MAX,IIU,IJU,IKU            ! loop boundaries
+  REAL                                :: Z_DIST_TEST1,Z_DIST_TEST2            ! saving distances  
+  REAL                                :: Z_DIST_TEST3,Z_DIST_TEST4,ZDIST_REF0
+  INTEGER                             :: INUMB_FACES                          ! number of faces 
+  REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZXHATM,ZYHATM,ZZHATM,ZDP0PP0PAST 
+  CHARACTER(LEN=1)                    :: YPOS
+  REAL, DIMENSION(3)                  :: ZP1P0,ZP1P2,ZP0PP0,ZP1PP0,ZP2PP0,ZP3PP0,ZPP0P1,ZPP0P2,ZPP0P3
+  REAL, DIMENSION(3)                  :: ZPP0PPP0,ZPPP0P1,ZPPP0P2,ZP2P1,ZP2P0,ZP2P3,ZP3P2,ZP3P1
+  REAL, DIMENSION(3)                  :: ZPP0,ZFT1,ZFT2,ZFT3,ZFT1B,ZFT2B,ZFT3B,ZR,ZPPP0,ZP3P0,ZP0P1
+  REAL, DIMENSION(3)                  :: ZPPP0P3,ZP1P3,ZPCP0,ZR0
+  REAL, DIMENSION(:), ALLOCATABLE     :: ZSTEMP,ZRDIR,ZVECTDISTPLUS,ZVECTDISTMOINS,ZVECTDIST!,ZFACE
+  REAL, DIMENSION(:,:), ALLOCATABLE   :: ZC
+  REAL                                :: ZF1,ZF2,ZF3,ZF1B,ZF2B,ZF3B,ZDPP0PPP0
+  REAL                                :: ZT,ZSIGN,ZS,ZDIST,ZDP0PP0,ZNNORM,ZRN,ZPHI_OLD
+  TYPE(LIST_ll), POINTER              :: TZFIELDS_ll   ! list of fields to exchange
+  INTEGER                             :: IINFO_ll,IMI  ! return code of parallel routine
+  INTEGER                             :: IIE,IIB,IJB,IJE,IKE,IKB,ZBPLUS
+  LOGICAL                             :: GABOVE_ROOF,LFACE,LDZ
+  LOGICAL, DIMENSION(:), ALLOCATABLE  :: ZFACE
+  INTEGER                             :: ZCOUNT,ZIDX,ZII,ZCHANGE,ZCHANGE1
+  REAL                                :: ZDIFF,ZMIN_DIFF,ZDX
+  !
+  !------------------------------------------------------------------------------
+  !   
+  !       0.3 allocation
+  !
+  NULLIFY(TZFIELDS_ll)
+  IIU = SIZE(PPHI,1)
+  IJU = SIZE(PPHI,2)
+  IKU = SIZE(PPHI,3)
+  IIB=1+JPHEXT
+  IIE=IIU-JPHEXT
+  IJB=1+JPHEXT
+  IJE=IJU-JPHEXT
+  IKB=1+JPVEXT
+  IKE=IKU-JPVEXT
+  !
+  JK_MIN = 1 + JPVEXT
+  JK_MAX = IKU - JPVEXT
+  !
+  CALL GET_INDICE_ll (JI_MIN,JJ_MIN,JI_MAX,JJ_MAX)
+  !
+  ALLOCATE(ZXHATM(IIU,IJU,IKU))
+  ALLOCATE(ZYHATM(IIU,IJU,IKU))
+  ALLOCATE(ZZHATM(IIU,IJU,IKU))
+  !
+  !-------------------------------------------------------------------------------
+  !
+  !**** 1. PRELIMINARIES
+  !     ----------------
+  !
+  INUMB_FACES = SIZE(PIBM_FACES,1)
+  ALLOCATE(ZC(INUMB_FACES,3))
+  ALLOCATE(ZSTEMP(1))
+  ALLOCATE(ZRDIR(1))  
+  PPHI = -XUNDEF
+  ALLOCATE(ZDP0PP0PAST(IIU,IJU,IKU))
+  ZDP0PP0PAST = 0.
+  ALLOCATE(ZVECTDIST(10000))
+  ALLOCATE(ZVECTDISTPLUS(10000))
+  ALLOCATE(ZVECTDISTMOINS(10000))
+  ALLOCATE(ZFACE(10000))
+  ZFACE=.FALSE.
+  !      
+  !-------------------------------------------------------------------------------
+  !
+  !**** 2. EXECUTIONS
+  !     -------------
+  !
+  JM=1
+  YPOS = 'P'
+  !
+  CALL IBM_INTERPOS(ZXHATM,ZYHATM,ZZHATM,YPOS)
+  ZDX = ZXHATM(JI_MIN+1,JJ_MIN,JK_MIN)-ZXHATM(JI_MIN,JJ_MIN,JK_MIN)
+  !
+  DO JK = JK_MIN,JK_MAX
+     DO JJ = JJ_MIN,JJ_MAX
+        DO JI = JI_MIN,JI_MAX
+           ZCOUNT = 1
+           ZVECTDIST = -999.
+           DO JN = 1,INUMB_FACES
+              LFACE=.FALSE.
+              !***Calcul of the face center
+              ZC(JN,1)=(PIBM_FACES(JN,1,1)+PIBM_FACES(JN,2,1)+PIBM_FACES(JN,3,1))/3.
+              ZC(JN,2)=(PIBM_FACES(JN,1,2)+PIBM_FACES(JN,2,2)+PIBM_FACES(JN,3,2))/3.
+              ZC(JN,3)=(PIBM_FACES(JN,1,3)+PIBM_FACES(JN,2,3)+PIBM_FACES(JN,3,3))/3.
+              !***Norm normalization
+              ZNNORM = SQRT(PNORM_FACES(JN,1)**2+PNORM_FACES(JN,2)**2+PNORM_FACES(JN,3)**2)
+              !***Vector between the face center and the current grid point
+              ZPCP0(1) = ZXHATM(JI,JJ,JK)-ZC(JN,1)
+              ZPCP0(2) = ZYHATM(JI,JJ,JK)-ZC(JN,2)
+              ZPCP0(3) = ZZHATM(JI,JJ,JK)-ZC(JN,3)
+              ZSIGN = ZPCP0(1)*PNORM_FACES(JN,1)+ &
+                      ZPCP0(2)*PNORM_FACES(JN,2)+ &
+                      ZPCP0(3)*PNORM_FACES(JN,3)
+              !***Various vectors
+              ZP1P0(1) = ZXHATM(JI,JJ,JK)-PIBM_FACES(JN,1,1)
+              ZP1P0(2) = ZYHATM(JI,JJ,JK)-PIBM_FACES(JN,1,2)
+              ZP1P0(3) = ZZHATM(JI,JJ,JK)-PIBM_FACES(JN,1,3)
+              ZP3P0(1) = ZXHATM(JI,JJ,JK)-PIBM_FACES(JN,3,1)
+              ZP3P0(2) = ZYHATM(JI,JJ,JK)-PIBM_FACES(JN,3,2)
+              ZP3P0(3) = ZZHATM(JI,JJ,JK)-PIBM_FACES(JN,3,3)
+              ZP0P1(1) = PIBM_FACES(JN,1,1)-ZXHATM(JI,JJ,JK)
+              ZP0P1(2) = PIBM_FACES(JN,1,2)-ZYHATM(JI,JJ,JK)
+              ZP0P1(3) = PIBM_FACES(JN,1,3)-ZZHATM(JI,JJ,JK)
+              ZP2P0(1) = ZXHATM(JI,JJ,JK)-PIBM_FACES(JN,2,1)
+              ZP2P0(2) = ZYHATM(JI,JJ,JK)-PIBM_FACES(JN,2,2)
+              ZP2P0(3) = ZZHATM(JI,JJ,JK)-PIBM_FACES(JN,2,3)
+              !***Equation (3) of Jones (1995)
+              IF(ZP1P0(1)==0.AND.ZP1P0(2)==0.AND.ZP1P0(3)==0) THEN
+                 WRITE(*,*) 'ZP1P0(1,2,3)',ZP1P0(1),ZP1P0(2),ZP1P0(3)
+                 ZDP0PP0 = 0.
+              ELSE
+                 ZDP0PP0 = SQRT(ZP0P1(1)**2+ZP0P1(2)**2+ZP0P1(3)**2)* &
+                        ((ZP1P0(1)*PNORM_FACES(JN,1)+ZP1P0(2)*PNORM_FACES(JN,2)+&
+                         ZP1P0(3)*PNORM_FACES(JN,3))/( &
+                        SQRT((ZP1P0(1))**2+(ZP1P0(2))**2+(ZP1P0(3))**2)*ZNNORM))
+              END IF
+              !***Equation (4) of Jones (1995)
+              ZP0PP0(1) = -ZDP0PP0*(PNORM_FACES(JN,1)/ZNNORM)
+              ZP0PP0(2) = -ZDP0PP0*(PNORM_FACES(JN,2)/ZNNORM)
+              ZP0PP0(3) = -ZDP0PP0*(PNORM_FACES(JN,3)/ZNNORM)
+              !***Equation (5) of Jones (1995)
+              ZPP0(1) = ZXHATM(JI,JJ,JK)+ZP0PP0(1)
+              ZPP0(2) = ZYHATM(JI,JJ,JK)+ZP0PP0(2)
+              ZPP0(3) = ZZHATM(JI,JJ,JK)+ZP0PP0(3)
+              !
+              ZP1PP0(1)=ZPP0(1)-PIBM_FACES(JN,1,1)
+              ZP1PP0(2)=ZPP0(2)-PIBM_FACES(JN,1,2)
+              ZP1PP0(3)=ZPP0(3)-PIBM_FACES(JN,1,3)
+              !
+              ZP2PP0(1)=ZPP0(1)-PIBM_FACES(JN,2,1)
+              ZP2PP0(2)=ZPP0(2)-PIBM_FACES(JN,2,2)
+              ZP2PP0(3)=ZPP0(3)-PIBM_FACES(JN,2,3)
+              !
+              ZP3PP0(1)=ZPP0(1)-PIBM_FACES(JN,3,1)
+              ZP3PP0(2)=ZPP0(2)-PIBM_FACES(JN,3,2)
+              ZP3PP0(3)=ZPP0(3)-PIBM_FACES(JN,3,3)
+              !
+              ZPP0P1(1)=PIBM_FACES(JN,1,1)-ZPP0(1)
+              ZPP0P1(2)=PIBM_FACES(JN,1,2)-ZPP0(2)
+              ZPP0P1(3)=PIBM_FACES(JN,1,3)-ZPP0(3)
+              !
+              ZPP0P2(1)=PIBM_FACES(JN,2,1)-ZPP0(1)
+              ZPP0P2(2)=PIBM_FACES(JN,2,2)-ZPP0(2)
+              ZPP0P2(3)=PIBM_FACES(JN,2,3)-ZPP0(3)
+              !
+              ZPP0P3(1)=PIBM_FACES(JN,3,1)-ZPP0(1)
+              ZPP0P3(2)=PIBM_FACES(JN,3,2)-ZPP0(2)
+              ZPP0P3(3)=PIBM_FACES(JN,3,3)-ZPP0(3)
+              !
+              !***Calculation of f1,f2,f3 (Jones (1995))
+              ZFT1= CROSSPRODUCT(PV1(JN,:),ZP1PP0)
+              ZFT2= CROSSPRODUCT(PV2(JN,:),ZP2PP0)
+              ZFT3= CROSSPRODUCT(PV3(JN,:),ZP3PP0)
+
+              ZF1 =ZFT1(1)*PNORM_FACES(JN,1)+ &
+                   ZFT1(2)*PNORM_FACES(JN,2)+ &
+                   ZFT1(3)*PNORM_FACES(JN,3)
+
+              ZF2 =ZFT2(1)*PNORM_FACES(JN,1)+ &
+                   ZFT2(2)*PNORM_FACES(JN,2)+ &
+                   ZFT2(3)*PNORM_FACES(JN,3)
+
+              ZF3 =ZFT3(1)*PNORM_FACES(JN,1)+ &
+                   ZFT3(2)*PNORM_FACES(JN,2)+ &
+                   ZFT3(3)*PNORM_FACES(JN,3)
+              !***Point anticlockwise of V1 and clockwise of V2
+              IF (ZF1.GE.0.AND.ZF2.LE.0) THEN
+                 ZFT1B = CROSSPRODUCT(ZPP0P1,ZPP0P2)
+                 ZF1B = ZFT1B(1)*PNORM_FACES(JN,1)+ &
+                      ZFT1B(2)*PNORM_FACES(JN,2)+ &
+                      ZFT1B(3)*PNORM_FACES(JN,3)
+                 IF (ZF1B<0) THEN
+                    ZP1P2(:) = PIBM_FACES(JN,2,:)-PIBM_FACES(JN,1,:)
+                    ZR = CROSSPRODUCT(CROSSPRODUCT(ZPP0P2,ZPP0P1),ZP1P2)
+                    ZRN = SQRT(ZR(1)**2+ZR(2)**2+ZR(3)**2)    
+                    !***Eq. (10) of Jones(1995)
+                    ZDPP0PPP0 = SQRT(ZPP0P1(1)**2+ZPP0P1(2)**2+ZPP0P1(3)**2)* &
+                                ((ZPP0P1(1)*ZR(1)+ZPP0P1(2)*ZR(2)+ZPP0P1(3)*ZR(3))/( &
+                                SQRT(ZPP0P1(1)**2+ZPP0P1(2)**2+ZPP0P1(3)**2)*ZRN))! &
+                    ZPP0PPP0 = ZDPP0PPP0*(ZR/ZRN)
+                    ZPPP0 = ZPP0+ZPP0PPP0
+                    ZPPP0P1 = PIBM_FACES(JN,1,:)-ZPPP0
+                    ZP2P1 = PIBM_FACES(JN,1,:)-PIBM_FACES(JN,2,:)
+                    ZRDIR = SIGN(1.,SCALPRODUCT(ZPPP0P1,ZP2P1))
+                    ZT = SQRT(ZPPP0P1(1)**2+ZPPP0P1(2)**2+ZPPP0P1(3)**2)/ &
+                         SQRT(ZP2P1(1)**2+ZP2P1(2)**2+ZP2P1(3)**2)*ZRDIR(1)
+                    IF (ZT.GE.0.AND.ZT.LE.1) THEN
+                       ZDIST =SQRT(ZDPP0PPP0**2+ZDP0PP0**2)
+                    ELSEIF (ZT<0.) THEN
+                       ZDIST = SQRT(ZP1P0(1)**2+ZP1P0(2)**2+ZP1P0(3)**2)
+                    ELSEIF (ZT>1.) THEN
+                       ZDIST = SQRT(ZP2P0(1)**2+ZP2P0(2)**2+ZP2P0(3)**2)
+                    ELSE                    
+                       WRITE(*,*) '*****************************'
+                       WRITE(*,*) '********ERROR in ZT **********'
+                       WRITE(*,*) '******* calculation **********'
+                       WRITE(*,*) '**** (stopped execution) ****'
+                       WRITE(*,*) '*****************************'
+                       call Print_msg( NVERB_FATAL, 'GEN', 'IBM_PREP_LS', 'Error in ZT calculation' )
+                    ENDIF
+                 ELSE
+                    ZDIST = ZDP0PP0 
+                    LFACE = .TRUE.                    
+                 ENDIF
+              !***Point anticlockwise of V2 and clockwise of V3
+              ELSEIF (ZF2.GE.0.AND.ZF3.LE.0) THEN
+                 ZFT2B = CROSSPRODUCT(ZPP0P2,ZPP0P3)
+                 ZF2B = ZFT2B(1)*PNORM_FACES(JN,1)+ &
+                      ZFT2B(2)*PNORM_FACES(JN,2)+ &
+                      ZFT2B(3)*PNORM_FACES(JN,3)
+                 IF (ZF2B<0) THEN
+                    ZP2P3(:) = PIBM_FACES(JN,3,:)-PIBM_FACES(JN,2,:)
+                    ZR = CROSSPRODUCT(CROSSPRODUCT(ZPP0P3,ZPP0P2),ZP2P3)
+                    ZRN = SQRT(ZR(1)**2+ZR(2)**2+ZR(3)**2)
+                    ZDPP0PPP0 = SQRT(ZPP0P2(1)**2+ZPP0P2(2)**2+ZPP0P2(3)**2)* &
+                         ((ZPP0P2(1)*ZR(1)+ZPP0P2(2)*ZR(2)+ZPP0P2(3)*ZR(3))/( &
+                         SQRT(ZPP0P2(1)**2+ZPP0P2(2)**2+ZPP0P2(3)**2)*ZRN))! &
+                    ZPP0PPP0 = ZDPP0PPP0*(ZR/ZRN)
+                    ZPPP0 = ZPP0+ZPP0PPP0
+                    ZPPP0P2 = PIBM_FACES(JN,2,:)-ZPPP0
+                    ZP3P2 = PIBM_FACES(JN,2,:)-PIBM_FACES(JN,3,:)
+                    ZRDIR = SIGN(1.,SCALPRODUCT(ZPPP0P2,ZP3P2))
+                    ZT = SQRT(ZPPP0P2(1)**2+ZPPP0P2(2)**2+ZPPP0P2(3)**2)/ &
+                         SQRT(ZP3P2(1)**2+ZP3P2(2)**2+ZP3P2(3)**2)*ZRDIR(1)
+                    IF (ZT.GE.0.AND.ZT.LE.1) THEN
+                       ZDIST = SQRT(ZDPP0PPP0**2+ZDP0PP0**2)
+                    ELSEIF (ZT<0.) THEN
+                       ZDIST = SQRT(ZP2P0(1)**2+ZP2P0(2)**2+ZP2P0(3)**2)
+                    ELSEIF (ZT>1.) THEN
+                       ZDIST = SQRT(ZP3P0(1)**2+ZP3P0(2)**2+ZP3P0(3)**2)
+                    ELSE
+                       WRITE(*,*) '*****************************'
+                       WRITE(*,*) '********ERROR in ZT **********'
+                       WRITE(*,*) '******* calculation **********'
+                       WRITE(*,*) '**** (stopped execution) ****'
+                       WRITE(*,*) '*****************************'
+                       call Print_msg( NVERB_FATAL, 'GEN', 'IBM_PREP_LS', 'Error in ZT calculation' )
+                    ENDIF
+                 ELSE
+                    ZDIST = ZDP0PP0
+                    LFACE = .TRUE.                    
+                 ENDIF
+              !***Point anticlockwise of V3 and clockwise of V1
+              ELSEIF (ZF3.GE.0.AND.ZF1.LE.0) THEN
+                 ZFT3B = CROSSPRODUCT(ZPP0P3,ZPP0P1)
+                 ZF3B = ZFT3B(1)*PNORM_FACES(JN,1)+ &
+                      ZFT3B(2)*PNORM_FACES(JN,2)+ &
+                      ZFT3B(3)*PNORM_FACES(JN,3)
+                 IF (ZF3B<0) THEN
+                    ZP3P1(:) = PIBM_FACES(JN,1,:)-PIBM_FACES(JN,3,:)
+                    ZR = CROSSPRODUCT(CROSSPRODUCT(ZPP0P1,ZPP0P3),ZP3P1)
+                    ZRN = SQRT(ZR(1)**2+ZR(2)**2+ZR(3)**2)
+                    ZDPP0PPP0 = SQRT(ZPP0P3(1)**2+ZPP0P3(2)**2+ZPP0P3(3)**2)* &
+                         ((ZPP0P3(1)*ZR(1)+ZPP0P3(2)*ZR(2)+ZPP0P3(3)*ZR(3))/( &
+                         SQRT((ZPP0P3(1))**2+(ZPP0P3(2))**2+(ZPP0P3(3))**2)*ZRN))! &
+                    ZPP0PPP0 = ZDPP0PPP0*(ZR/ZRN)
+                    ZPPP0 = ZPP0+ZPP0PPP0
+                    ZPPP0P3 = PIBM_FACES(JN,3,:)-ZPPP0
+                    ZP1P3 = PIBM_FACES(JN,3,:)-PIBM_FACES(JN,1,:)
+                    ZRDIR = SIGN(1.,SCALPRODUCT(ZPPP0P3,ZP1P3))
+                    ZT = SQRT(ZPPP0P3(1)**2+ZPPP0P3(2)**2+ZPPP0P3(3)**2)/ &
+                         SQRT(ZP1P3(1)**2+ZP1P3(2)**2+ZP1P3(3)**2)*ZRDIR(1)
+                    IF (ZT.GE.0.AND.ZT.LE.1) THEN
+                       ZDIST = SQRT(ZDPP0PPP0**2+ZDP0PP0**2)
+                    ELSEIF (ZT<0.) THEN
+                       ZDIST = SQRT(ZP3P0(1)**2+ZP3P0(2)**2+ZP3P0(3)**2)
+                    ELSEIF (ZT>1.) THEN
+                       ZDIST = SQRT(ZP1P0(1)**2+ZP1P0(2)**2+ZP1P0(3)**2)
+                    ELSE
+                       WRITE(*,*) '*****************************'
+                       WRITE(*,*) '********ERROR in ZT **********'
+                       WRITE(*,*) '******* calculation **********'
+                       WRITE(*,*) '**** (stopped execution) ****'
+                       WRITE(*,*) '*****************************'
+                       call Print_msg( NVERB_FATAL, 'GEN', 'IBM_PREP_LS', 'Error in ZT calculation' )
+                    ENDIF
+                 ELSE
+                    ZDIST = ZDP0PP0
+                    LFACE = .TRUE.
+                 ENDIF
+              ELSE
+                 WRITE(*,*) '*****************************'
+                 WRITE(*,*) '********ERROR in ZF **********'
+                 WRITE(*,*) '******* instruction **********'
+                 WRITE(*,*) '**** (stopped execution) ****'
+                 WRITE(*,*) '*****************************'
+                 call Print_msg( NVERB_FATAL, 'GEN', 'IBM_PREP_LS', 'Error in ZF instruction' )
+              ENDIF
+              ZDIST = SIGN(ZDIST,-ZSIGN)
+              ZDIST = ANINT(ZDIST*10.E5) / 10.E5
+              PPHI(JI,JJ,JK,JM) = ANINT(PPHI(JI,JJ,JK,JM)*10.E5) / 10.E5
+              IF (ABS(ZDIST).LE.ABS(PPHI(JI,JJ,JK,JM))) THEN
+                 ZPHI_OLD = PPHI(JI,JJ,JK,JM)
+                 IF (ABS(ZDIST)==ABS(PPHI(JI,JJ,JK,JM))) THEN
+                    IF (ABS(ZDP0PP0).GT.ABS(ZDP0PP0PAST(JI,JJ,JK))) THEN
+                       PPHI(JI,JJ,JK,JM) = ZDIST
+                       ZDP0PP0PAST(JI,JJ,JK) = ZDP0PP0
+                    ENDIF
+                 ELSE
+                    PPHI(JI,JJ,JK,JM) = ZDIST
+                 ENDIF
+                 IF (ABS(ZDIST).LT.ABS(ZPHI_OLD)) THEN        
+                    ZDP0PP0PAST(JI,JJ,JK) = ZDP0PP0
+                 ENDIF
+              ENDIF
+              IF (ABS(PPHI(JI,JJ,JK,JM)).GT.(SQRT(3.)*4.)) THEN
+                 PPHI(JI,JJ,JK,JM) = -999.
+              ENDIF
+              IF (ABS(ZDIST).LT.(SQRT(3.)*4.)) THEN
+                 ZVECTDIST(ZCOUNT)=ZDIST
+                 ZFACE(ZCOUNT)=LFACE
+                 ZCOUNT = ZCOUNT +1
+              ENDIF
+           ENDDO
+           ZVECTDISTPLUS=ZVECTDIST
+           ZVECTDISTMOINS=ZVECTDIST
+           WHERE (ZVECTDIST.GT.0)
+                 ZVECTDISTMOINS=-999. 
+           ENDWHERE
+           WHERE (ZVECTDIST.LT.0)
+                 ZVECTDISTPLUS=999.
+           ENDWHERE
+           IF (ANY(ZVECTDIST.GT.0.).AND.(ABS(ABS(MINVAL(ZVECTDISTPLUS))-ABS(MAXVAL(ZVECTDISTMOINS))).LT.10.E-6)) THEN
+              ZMIN_DIFF = 1.
+              ZIDX = 0
+              DO ZII = 1, SIZE(ZVECTDIST)
+                 ZDIFF = ABS(ZVECTDIST(ZII)-MINVAL(ZVECTDISTPLUS))
+                 IF ( ZDIFF < ZMIN_DIFF) THEN
+                    ZIDX = ZII
+                    ZMIN_DIFF = ZDIFF
+                 ENDIF
+               ENDDO
+               IF (ZFACE(ZIDX)) THEN
+                  PPHI(JI,JJ,JK,JM) = MINVAL(ZVECTDISTPLUS)
+               ENDIF   
+           ENDIF
+        ENDDO
+     ENDDO
+  ENDDO
+
+DO JJ=JJ_MIN,JJ_MAX
+DO JI=JI_MIN,JI_MAX
+GABOVE_ROOF=.FALSE.
+DO JK=IKB, IKE
+  ! check if point is flagged as not calculated
+  IF (PPHI(JI,JJ,JK,JM)==-999.) THEN
+     ! check if point is already above a point that encountered a point near the
+     ! surface (that can be outside or inside a building)
+     ! check if that point was inside (if outside, the value of the levelset
+     ! stays at -999.)
+     IF (GABOVE_ROOF .AND. PPHI(JI,JJ,JK-1,JM) > XIBM_EPSI) THEN
+       PPHI(JI,JJ,JK,JM) = 999.
+       CYCLE
+     END IF
+    ! check if the point of the column have not encoutered a near-building
+    ! surface point with a physical value of the level set
+    IF (.NOT. GABOVE_ROOF) THEN
+      ! if the point above has a physical value for the level set, then the
+      ! status inside (999) or outside (-999) is given to all points below,
+      ! depending if this point above (that needs not to be the point at the top
+      ! of the model!) is inside or outside
+      ! checks if the point above has a physical value for the levelset                   
+      IF (JK<IKE .AND. ABS (PPHI(JI,JJ,JK+1,JM)) < 900.) THEN
+         ! if the point above is inside, all points below are set inside
+         IF (PPHI(JI,JJ,JK+1,JM)>XIBM_EPSI) PPHI(JI,JJ,IKB:JK,JM) = 999.
+         ! indicate for further processing of points above the current point
+         ! that we have encountered a physical value of the level set, near the
+         ! surface building
+         GABOVE_ROOF = .TRUE.
+      END IF
+      CYCLE
+    ENDIF
+  END IF
+  ! if we have never encoutered a roof or point near a building form above,
+  ! then, we are outside, and nothing is changed (value -999 kept)
+  END DO
+  PPHI(JI,JJ,IKB-1,JM) = PPHI(JI,JJ,IKB,JM)
+  PPHI(JI,JJ,IKE+1,JM) = PPHI(JI,JJ,IKE,JM)
+END DO
+END DO
+
+
+JN=1
+PPHI(:,:,IKB-1,JN)=2*PPHI(:,:,IKB,JN)-PPHI(:,:,IKB+1,JN)
+PPHI(:,:,IKE+1,JN)=2*PPHI(:,:,IKE,JN)-PPHI(:,:,IKE-1,JN)
+PPHI(IIB-1,:,:,JN) = PPHI(    IIB  ,:,:,JN)
+PPHI(IIE+1,:,:,JN) = PPHI(    IIE  ,:,:,JN)
+PPHI(:,IJB-1,:,JN) = PPHI(:,    IJB  ,:,JN)
+PPHI(:,IJE+1,:,JN) = PPHI(:,    IJE  ,:,JN)
+
+PPHI(:,:,:,2)=MXM(PPHI(:,:,:,1))
+PPHI(:,:,:,3)=MYM(PPHI(:,:,:,1))
+PPHI(:,:,:,4)=MZM(PPHI(:,:,:,1))
+
+NULLIFY(TZFIELDS_ll)
+DO JN=2,4
+  PPHI(:,:,IKB-1,JN)=2*PPHI(:,:,IKB,JN)-PPHI(:,:,IKB+1,JN)
+  PPHI(:,:,IKE+1,JN)=2*PPHI(:,:,IKE,JN)-PPHI(:,:,IKE-1,JN)
+    PPHI(IIB-1,:,:,JN) = PPHI(    IIB  ,:,:,JN)
+    PPHI(IIE+1,:,:,JN) = PPHI(    IIE  ,:,:,JN)
+    PPHI(:,IJB-1,:,JN) = PPHI(:,    IJB  ,:,JN)
+    PPHI(:,IJE+1,:,JN) = PPHI(:,    IJE  ,:,JN)
+ENDDO
+
+PPHI(:,:,:,5)=MYM(PPHI(:,:,:,2))
+PPHI(:,:,:,6)=MXM(PPHI(:,:,:,4))
+PPHI(:,:,:,7)=MYM(PPHI(:,:,:,4))
+NULLIFY(TZFIELDS_ll)
+DO JN=5,7
+  PPHI(:,:,IKB-1,JN)=2*PPHI(:,:,IKB,JN)-PPHI(:,:,IKB+1,JN)
+  PPHI(:,:,IKE+1,JN)=2*PPHI(:,:,IKE,JN)-PPHI(:,:,IKE-1,JN)
+    PPHI(IIB-1,:,:,JN) = PPHI(    IIB  ,:,:,JN)
+    PPHI(IIE+1,:,:,JN) = PPHI(    IIE  ,:,:,JN)
+    PPHI(:,IJB-1,:,JN) = PPHI(:,    IJB  ,:,JN)
+    PPHI(:,IJE+1,:,JN) = PPHI(:,    IJE  ,:,JN)
+ENDDO
+WHERE (ABS(PPHI(:,:,:,:)).LT.XIBM_EPSI) PPHI(:,:,:,:)=2.*XIBM_EPSI
+
+
+  !COMPLETE PPHI ON THE HALO OF EACH SUBDOMAINS
+  DO JN=1,7
+     CALL ADD3DFIELD_ll(TZFIELDS_ll,PPHI(:,:,:,JN),'IBM_GENERLS::PPHI')
+  ENDDO
+  CALL UPDATE_HALO_ll(TZFIELDS_ll,IINFO_ll)
+  CALL CLEANLIST_ll(TZFIELDS_ll)
+
+  !
+  !-------------------------------------------------------------------------------
+  !
+  !**** X. DEALLOCATIONS/CLOSES
+  !     -----------------------
+  !  
+  !DEALLOCATE(ZDP0PP0,ZDIST,ZC,ZSTEMP)
+  DEALLOCATE(ZC,ZSTEMP)
+  DEALLOCATE(ZXHATM,ZYHATM,ZZHATM)              
+  !
+  RETURN
+  !
+CONTAINS
+  !
+  FUNCTION CROSSPRODUCT(PA,PB) RESULT(CROSS)
+    !
+    REAL, DIMENSION(3)             :: CROSS
+    REAL, DIMENSION(3), INTENT(IN) :: PA, PB
+    CROSS(1) = PA(2) * PB(3) - PA(3) * PB(2)
+    CROSS(2) = PA(3) * PB(1) - PA(1) * PB(3)
+    CROSS(3) = PA(1) * PB(2) - PA(2) * PB(1)
+  END FUNCTION CROSSPRODUCT
+
+  FUNCTION SCALPRODUCT(PA,PB) RESULT(SCAL)
+    !
+    REAL                           :: SCAL
+    REAL, DIMENSION(3), INTENT(IN) :: PA, PB
+    SCAL = PA(1)*PB(1)+PA(2)*PB(2)+PA(3)*PB(3)
+  END FUNCTION SCALPRODUCT
+
+END SUBROUTINE IBM_GENERLS
diff --git a/src/MNH/ibm_prep_ls.f90 b/src/MNH/ibm_prep_ls.f90
index 22ba92cc5..063269439 100644
--- a/src/MNH/ibm_prep_ls.f90
+++ b/src/MNH/ibm_prep_ls.f90
@@ -37,10 +37,27 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   !
   !    METHOD
   !    ------
-  !****  Three main steps
-  !      - read input ASCII files
-  !      - Types of topography:
-  !          IDEA : idealized obstacles (x,y coordinates)
+  !****  Types of topography:
+  !          1)GENE : generalized obstacles (x,y coordinates)
+  !          => read the informations (triangles constituting the
+  !          faces of obstacles) from an .obj file.
+  !          The .obj file must have a particular organization:
+  !              a) A line with 'usemtl' indicates the 2 materials 
+  !          of each side of the interface. Only the faces with 
+  !          their external face in contact with the outside air
+  !          are read (mat2=air)
+  !              b) A line starting with 'v' indicates the location
+  !          (x,y,z coordinates) of a face vortex.
+  !              c) A line starting with 'f' indicates the vortices
+  !          constituting the face.
+  !                   usemtl mat1:mat2
+  !                   v      xv1      yv1      zv1
+  !                   v      xv2      yv2      zv2
+  !                   v      xv3      yv3      zv3
+  !                   v      xv4      yv4      zv4
+  !                   f         1         2         3
+  !                   f         1         3         4
+  !          2)IDEA : idealized obstacles (x,y coordinates)
   !
   !    EXTERNAL
   !    --------
@@ -52,14 +69,17 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   !
   !    REFERENCE
   !    ---------
+  !    For the generalized case, the method is based on '3D Distance from a
+  !    Point to a Triangle' a technical report from Mark W. Jones, University 
+  !    of Wales Swansea [Jones (1995)].
   !
-  !    AUTHOR
+  !    AUTHORS
   !    ------
-  !      Franck Auguste (CERFACS-AE)
+  !      Franck Auguste (CERFACS-AE), Tim Nagel (Météo-France)
   !
   !    MODIFICATIONS
   !    -------------
-  !      Original         01/01/2019
+  !      Original         01/06/2021
   !
   !------------------------------------------------------------------------------
   !       
@@ -86,6 +106,7 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   ! interface
   USE MODI_SHUMAN
   USE MODI_GDIV
+  USE MODI_IBM_GENERLS
   USE MODI_IBM_IDEALRP
   USE MODI_IBM_IDEALEE
   !
@@ -93,6 +114,7 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   USE MODD_CST
   USE MODD_GRID_n
   USE MODE_GRIDPROJ
+  USE MODE_MSG
   !
   IMPLICIT NONE
   !
@@ -100,55 +122,30 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   !
   !       0.1  declarations of arguments
   !
-  LOGICAL                  ,INTENT(IN)    :: OIBM      ! flag for immersed boundary method
-  CHARACTER(LEN=4)         ,INTENT(IN)    :: HIBM_TYPE ! switch generalized/idealised object
-  REAL, DIMENSION(:,:,:,:) ,INTENT(INOUT) :: PPHI      ! LS functions
+  LOGICAL                  ,INTENT(IN)    :: OIBM                        ! flag for immersed boundary method
+  CHARACTER(LEN=4)         ,INTENT(IN)    :: HIBM_TYPE                   ! switch generalized/idealized object
+  REAL, DIMENSION(:,:,:,:) ,INTENT(INOUT) :: PPHI                        ! LS functions
   !
   !------------------------------------------------------------------------------
   !
   !       0.2  declaration of local variables
   !
-  INTEGER :: JN,JM,JNM,JL,JMM,JI,JJ,JK,JF,JV                           ! loop index
-  INTEGER :: IIU,IJU,KII,KJJ
+  INTEGER :: JN,JM,JNM,JL,JMM,JI,JJ,JK,JF,JV                             ! loop index
+  INTEGER :: IIU,IJU
   REAL    :: ZX_MIN,ZX_MAX,ZY_MIN,ZY_MAX,DX_LOW,DY_LOW,DX_HIGH,DY_HIGH
-  INTEGER :: JI2,JJ2,JK2,JI3,JJ3,JK3
-  INTEGER :: JIM1,JIP1,JIM2,JIP2,JIM4,JIP4
-  INTEGER :: JJM1,JJP1,JJM2,JJP2,JJM4,JJP4
-  INTEGER :: JI2_MIN,JI2_MAX,JJ2_MIN,JJ2_MAX
-  INTEGER :: IIB,IIE,IJB,IJE,IKB,IKE,ILOOP,JLOOP,KLOOP
-  INTEGER :: IGRIB,IIBM_LEVEL,KIBM_LEVEL,IIBM_MIDDLE,KIBM_LEVEL2
-  INTEGER :: KIII,KJJJ,KIIM1,KIIP1,KJJM1,KJJP1
-  INTEGER :: ILUIBMIDEA,IRESPIBMGENE,ILUIBMGENE,IRESPIBMIDEA ! integers for open/read files
-  INTEGER :: IIBM_NUMB_NODE_SURF ! number of surface points (generalized case) 
-  INTEGER :: IIBM_NUMB_TYPE_SURF ! number of surface type   (idealized case) 
-  INTEGER :: IIBM_TYPE_SURF      ! type of surfaces            
-  INTEGER :: IIBM_NUMB_SURF      ! number of surfaces in each type 
-  REAL    :: ZIBM_X1,ZIBM_X2,ZIBM_Y1,ZIBM_Y2,ZIBM_Z1,ZIBM_Z2 ! location of surface points for one object
+  INTEGER :: ILUIBMIDEA,IRESPIBMGENE,ILUIBMGENE,IRESPIBMIDEA             ! integers for open/read files
+  INTEGER :: IIBM_NUMB_NODE_SURF                                         ! number of surface points (generalized case) 
+  INTEGER :: IIBM_NUMB_TYPE_SURF                                         ! number of surface type   (idealized case) 
+  INTEGER :: IIBM_TYPE_SURF                                              ! type of surfaces            
+  INTEGER :: IIBM_NUMB_SURF                                              ! number of surfaces in each type 
+  REAL    :: ZIBM_X1,ZIBM_X2,ZIBM_Y1,ZIBM_Y2,ZIBM_Z1,ZIBM_Z2             ! location of surface points for one object
   REAL    :: ZIBM_TYPE_SURF
-  REAL, DIMENSION(:,:), ALLOCATABLE :: ZIBM_XYZ1,ZIBM_XYZ2  ! location of surface points for all object
-  REAL, DIMENSION(:,:), ALLOCATABLE :: ZV1,ZV1_2,ZV2,ZV2_2,ZV3,ZV3_2
-  REAL, DIMENSION(:,:), ALLOCATABLE :: NORM_FACES,NORM_FACES2
+  REAL, DIMENSION(:,:), ALLOCATABLE :: ZIBM_XYZ1,ZIBM_XYZ2               ! location of surface points for all object
+  REAL, DIMENSION(:,:), ALLOCATABLE :: ZV1,ZV1_2,ZV2,ZV2_2,ZV3,ZV3_2     ! face vectors
+  REAL, DIMENSION(:,:), ALLOCATABLE :: NORM_FACES,NORM_FACES2                 ! norm of the faces
   REAL, DIMENSION(:,:,:), ALLOCATABLE :: ZIBM_FACES,ZIBM_FACES2,ZIBM_FACES2b  ! extremities of triangle faces for all object
-  REAL                                  :: XXX,YYY,ZZZ
-  INTEGER                               :: IRESPIBMREAL,ILUIBMREAL ! reading/writing ASCII files
-  REAL, DIMENSION(:,:,:)  , ALLOCATABLE :: ZSURF,ZINDI,ZTMP2,ZTMP3 ! SSF and ISF functions + temporary arrays
-  REAL, DIMENSION(:,:,:,:), ALLOCATABLE :: ZTMP,ZPHI               ! temporary arrays
-  REAL                   :: ZLAT,ZLON,ZHEI,ZIBM_HEI                ! lat/lon/z coordinates
-  INTEGER                :: KNUM,KBOR,KIBM_BATMIN,KIBM_BATMAX      ! index of buildings (BATI, REAL)
-  CHARACTER(LEN=10)      :: YHCOUNT1                               ! reading/writing ASCII files
-  CHARACTER(LEN=24)      :: YHCOUNT2
-  LOGICAL                :: GHCOUNT3
-  REAL                   :: ZXX,ZYY,ZXM2,ZYM2,ZII,ZJJ              ! temporary values 
-  REAL                   :: ZMAX1,ZMAX2,ZMAX3
-  REAL                   :: IIMAX,IJMAX,IKMAX
-  REAL                   :: ZXX1,ZYY1,ZZZ1,ZXX2,ZYY2,ZZZ2
-  REAL                   :: ZTES1,ZTES2,ZTES3,ZTES4,ZDIS,ZHIGH,ZHORI
-  REAL                   :: ZLATMIN,ZLATMAX,ZLONMIN,ZLONMAX,ZXM2MIN,ZXM2MAX, ZYM2MIN, ZYM2MAX
-  REAL                   :: SIGN1,SIGN2,SIGN3,SIGN4,ZHEI2
-  REAL                   :: ZX1,ZY1,ZX2,ZY2,ZIND
   TYPE(LIST_ll), POINTER :: TZFIELDS_ll
   INTEGER                :: IINFO_ll
-  LOGICAL                :: LCAEP,LAZF
   CHARACTER(LEN=12)      :: HFILEGENE, HFILEIDEA
   CHARACTER(LEN=100)     :: YSTRING,YSTRING2
   INTEGER                :: NS1,NS2,NS3,NS4,NS5,NS6
@@ -158,12 +155,24 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   !------------------------------------------------------------------------------
   !
   !       0.3  Allocation
+  ILUIBMGENE = 42
   ILUIBMIDEA = 43
+  HFILEGENE = "ibm_gene.obj"
   HFILEIDEA = "ibm_idea.nam"
   !
   IIU = SIZE(XXHAT)
   IJU = SIZE(XYHAT)
   !
+  DX_LOW = XXHAT(2)-XXHAT(1)
+  DX_HIGH = XXHAT(IIU)-XXHAT(IIU-1)
+  DY_LOW = XYHAT(2)-XYHAT(1)
+  DY_HIGH = XYHAT(IJU)-XYHAT(IJU-1)
+  !
+  !Collect the face up to 10 gridsize out of the current processor
+  ZX_MIN = XXHAT(1)-10.*DX_LOW
+  ZX_MAX = XXHAT(IIU)+(11.)*DX_HIGH
+  ZY_MIN = XYHAT(1)-10.*DY_LOW
+  ZY_MAX = XYHAT(IJU)+(11.)*DY_HIGH
   !
   !------------------------------------------------------------------------------
   !
@@ -171,6 +180,9 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   !     ----------------
   !
   !  Read input files in order to compute interface location
+  !    - 'ibm_gene.obj' for generalized case 
+  !       => read the informations (triangles constituting the
+  !       faces of obstacles) from an .obj file
   !    - 'm_ideal.nam' for idealized case
   !       (NUMB_NODE_SURF is the number of objects) 
   !       (NUMB_TYPE_SURF is the number of surface types:  
@@ -179,7 +191,181 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   !       (     NUMB_SURF is the objects number in each type)
   !
   !
-  IF ((HIBM_TYPE=='IDEA')) THEN
+  !--------------------------------
+  !--------Generalized case--------
+  !--------------------------------
+  IF (HIBM_TYPE=='GENE') THEN
+     !
+     !Allocate the tables containing the vortices, the faces locations,
+     !the norms, which are needed to calculate the LSF
+     ALLOCATE(ZIBM_XYZ1(5400000,3))
+     ALLOCATE(ZIBM_FACES(3150000,3,3))
+     ALLOCATE(ZIBM_FACES2b(3150000,3,3))
+     ALLOCATE(NORM_FACES(3150000,3))
+     ALLOCATE(ZV1(3150000,3))
+     ALLOCATE(ZV2(3150000,3))
+     ALLOCATE(ZV3(3150000,3))
+     !
+     OPEN(ILUIBMGENE , FILE= HFILEGENE , IOSTAT=IRESPIBMGENE , STATUS='OLD')
+     !
+     JV=1
+     JF=0
+     JCOUNT=0
+     !
+     !Only the faces that are in contact with the air (external faces of
+     !the obstacles) are read.
+     DO
+        IF (IRESPIBMGENE/=0) EXIT
+        READ(UNIT=ILUIBMGENE,FMT='(A100)',IOSTAT=IRESPIBMGENE) YSTRING
+        NS1=LEN(TRIM(YSTRING))
+        IF (TRIM(YSTRING(1:7))=='usemtl') THEN
+           IF (TRIM(YSTRING(NS1-3:NS1))==':air') THEN
+              JN=1
+           ELSE
+              JN=0
+           ENDIF
+        ENDIF
+        IF (TRIM(YSTRING(1:2))=='v') THEN
+           NS2=INDEX(TRIM(YSTRING)," ",back=.true.) 
+           NS3=LEN(TRIM(YSTRING(:NS2)))
+           NS4=INDEX(TRIM(YSTRING(:NS3))," ",back=.true.)
+           NS5=LEN(TRIM(YSTRING(:NS4)))
+           NS6=INDEX(TRIM(YSTRING(:NS5))," ",back=.true.)
+           READ(YSTRING(NS6:NS5) , *) ZIBM_XYZ1(JV,1)
+           READ(YSTRING(NS4:NS3) , *) ZIBM_XYZ1(JV,2)
+           READ(YSTRING(NS2:NS1) , *) ZIBM_XYZ1(JV,3)
+           !FIXME temporary spatial modification
+           ZIBM_XYZ1(JV,1) = ZIBM_XYZ1(JV,1) +200.
+           ZIBM_XYZ1(JV,2) = ZIBM_XYZ1(JV,2) +200.
+           JV=JV+1
+        ENDIF
+        IF (JN==1.AND.TRIM(YSTRING(1:2))=='f') THEN
+           NS2=INDEX(TRIM(YSTRING)," ",back=.true.)
+           NS3=LEN(TRIM(YSTRING(:NS2)))
+           NS4=INDEX(TRIM(YSTRING(:NS3))," ",back=.true.)
+           NS5=LEN(TRIM(YSTRING(:NS4)))
+           NS6=INDEX(TRIM(YSTRING(:NS5))," ",back=.true.)
+           READ(YSTRING(NS6:NS5) , *) ZN1
+           READ(YSTRING(NS4:NS3) , *) ZN2
+           READ(YSTRING(NS2:NS1) , *) ZN3
+           ! If the face extremities are far outside of the processor they are not read
+           IF (ZIBM_XYZ1(ZN1,1)<ZX_MIN.AND.ZIBM_XYZ1(ZN2,1)<ZX_MIN.AND.ZIBM_XYZ1(ZN3,1)<ZX_MIN) CYCLE
+           IF (ZIBM_XYZ1(ZN1,1)>ZX_MAX.AND.ZIBM_XYZ1(ZN2,1)>ZX_MAX.AND.ZIBM_XYZ1(ZN3,1)>ZX_MAX) CYCLE
+           IF (ZIBM_XYZ1(ZN1,2)<ZY_MIN.AND.ZIBM_XYZ1(ZN2,2)<ZY_MIN.AND.ZIBM_XYZ1(ZN3,2)<ZY_MIN) CYCLE
+           IF (ZIBM_XYZ1(ZN1,2)>ZY_MAX.AND.ZIBM_XYZ1(ZN2,2)>ZY_MAX.AND.ZIBM_XYZ1(ZN3,2)>ZY_MAX) CYCLE
+           JF=JF+1
+           !
+           ZIBM_FACES(JF,1,1) = ZIBM_XYZ1(ZN1,1)
+           ZIBM_FACES(JF,1,2) = ZIBM_XYZ1(ZN1,2)
+           ZIBM_FACES(JF,1,3) = ZIBM_XYZ1(ZN1,3)
+           ZIBM_FACES(JF,2,1) = ZIBM_XYZ1(ZN2,1)
+           ZIBM_FACES(JF,2,2) = ZIBM_XYZ1(ZN2,2)
+           ZIBM_FACES(JF,2,3) = ZIBM_XYZ1(ZN2,3)
+           ZIBM_FACES(JF,3,1) = ZIBM_XYZ1(ZN3,1)
+           ZIBM_FACES(JF,3,2) = ZIBM_XYZ1(ZN3,2)
+           ZIBM_FACES(JF,3,3) = ZIBM_XYZ1(ZN3,3)
+           !
+           ZNA(1) = ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,2,1)
+           ZNA(2) = ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,2,2)
+           ZNA(3) = ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,2,3)
+           ZNB(1) = ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,3,1)
+           ZNB(2) = ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,3,2)
+           ZNB(3) = ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,3,3)
+           !Elimination of '1D' faces
+           IF (ZNA(1)==0..AND.ZNA(2)==0..AND.ZNA(3)==0.) CYCLE
+           IF (ZNB(1)==0..AND.ZNB(2)==0..AND.ZNB(3)==0.) CYCLE
+           IF (ZNA(2)==0..AND.ZNA(3)==0..AND.ZNB(2)==0..AND.ZNB(3)==0.) CYCLE
+           IF (ZNA(1)==ZNB(1).AND.ZNA(2)==ZNB(2).AND.ZNA(3)==ZNB(3)) CYCLE
+           JCOUNT=JCOUNT+1
+           NORM_FACES(JCOUNT,:)= CROSSPRODUCT(ZNA,ZNB)
+           ZIBM_FACES2b(JCOUNT,:,:)=ZIBM_FACES(JF,:,:)
+           !
+           !Equation (6) of Jones (1995)
+           ZV1(JCOUNT,1) = (ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,2,1))/ SQRT((ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,2,1))**2 + &
+                (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,2,2))**2 +(ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,2,3))**2)+ &
+                (ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,3,1))/ SQRT((ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,3,1))**2 + &
+                (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,3,2))**2 +(ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,3,3))**2)
+           !
+           ZV1(JCOUNT,2) = (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,2,2))/ SQRT((ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,2,1))**2 + &
+                (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,2,2))**2 +(ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,2,3))**2)+ &
+                (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,3,2))/ SQRT((ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,3,1))**2 + &
+                (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,3,2))**2 +(ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,3,3))**2)
+           !
+           ZV1(JCOUNT,3) = (ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,2,3))/ SQRT((ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,2,1))**2 + &
+                (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,2,2))**2 +(ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,2,3))**2)+ &
+                (ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,3,3))/ SQRT((ZIBM_FACES(JF,1,1)-ZIBM_FACES(JF,3,1))**2 + &
+                (ZIBM_FACES(JF,1,2)-ZIBM_FACES(JF,3,2))**2 +(ZIBM_FACES(JF,1,3)-ZIBM_FACES(JF,3,3))**2) 
+           !
+           ZV2(JCOUNT,1) = (ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,3,1))/ SQRT((ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,3,1))**2 + &
+                (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,3,2))**2 +(ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,3,3))**2)+ &
+                (ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,1,1))/ SQRT((ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,1,1))**2 + &
+                (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,1,2))**2 +(ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,1,3))**2)
+           !
+           ZV2(JCOUNT,2) = (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,3,2))/ SQRT((ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,3,1))**2 + &
+                (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,3,2))**2 +(ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,3,3))**2)+ &
+                (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,1,2))/ SQRT((ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,1,1))**2 + &
+                (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,1,2))**2 +(ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,1,3))**2)
+           !
+           ZV2(JCOUNT,3) = (ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,3,3))/ SQRT((ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,3,1))**2 + &
+                (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,3,2))**2 +(ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,3,3))**2)+ &
+                (ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,1,3))/ SQRT((ZIBM_FACES(JF,2,1)-ZIBM_FACES(JF,1,1))**2 + &
+                (ZIBM_FACES(JF,2,2)-ZIBM_FACES(JF,1,2))**2 +(ZIBM_FACES(JF,2,3)-ZIBM_FACES(JF,1,3))**2)
+           !
+           ZV3(JCOUNT,1) = (ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,1,1))/ SQRT((ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,1,1))**2 + &
+                (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,1,2))**2 +(ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,1,3))**2)+ &
+                (ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,2,1))/ SQRT((ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,2,1))**2 + &
+                (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,2,2))**2 +(ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,2,3))**2)
+           !
+           ZV3(JCOUNT,2) = (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,1,2))/ SQRT((ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,1,1))**2 + &
+                (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,1,2))**2 +(ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,1,3))**2)+ &
+                (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,2,2))/ SQRT((ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,2,1))**2 + &
+                (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,2,2))**2 +(ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,2,3))**2)
+           !
+           ZV3(JCOUNT,3) = (ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,1,3))/ SQRT((ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,1,1))**2 + &
+                (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,1,2))**2 +(ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,1,3))**2)+ &
+                (ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,2,3))/ SQRT((ZIBM_FACES(JF,3,1)-ZIBM_FACES(JF,2,1))**2 + &
+                (ZIBM_FACES(JF,3,2)-ZIBM_FACES(JF,2,2))**2 +(ZIBM_FACES(JF,3,3)-ZIBM_FACES(JF,2,3))**2)
+           !
+        ENDIF
+        !
+        IF (JN==1.AND.TRIM(YSTRING(1:2))=='vn') THEN
+           WRITE(*,*) '*****************************'
+           WRITE(*,*) '***** vn found in .obj ******'
+           WRITE(*,*) '***** Unable to read it *****'
+           WRITE(*,*) '**** (stopped execution) ****'
+           WRITE(*,*) '*****************************'
+           call Print_msg( NVERB_FATAL, 'GEN', 'IBM_PREP_LS', 'Unable to read vn found in .obj' )
+        ENDIF
+        !
+        IF (JN==1.AND.TRIM(YSTRING(1:2))=='vt') THEN
+           WRITE(*,*) '*****************************'
+           WRITE(*,*) '***** vt found in .obj ******'
+           WRITE(*,*) '***** Unable to read it *****'
+           WRITE(*,*) '**** (stopped execution) ****'
+           WRITE(*,*) '*****************************'
+           call Print_msg( NVERB_FATAL, 'GEN', 'IBM_PREP_LS', 'Unable to read vt found in .obj' )
+        ENDIF
+        !
+     END DO
+     !
+     ALLOCATE(ZIBM_FACES2(JCOUNT,3,3))
+     ALLOCATE(NORM_FACES2(JCOUNT,3))
+     ALLOCATE(ZV1_2(JCOUNT,3))
+     ALLOCATE(ZV2_2(JCOUNT,3))
+     ALLOCATE(ZV3_2(JCOUNT,3))
+     !
+     NORM_FACES2 = NORM_FACES(:JCOUNT,:)
+     ZV1_2 = ZV1(:JCOUNT,:)
+     ZV2_2 = ZV2(:JCOUNT,:)
+     ZV3_2 = ZV3(:JCOUNT,:)
+     ZIBM_FACES2 = ZIBM_FACES2b(:JCOUNT,:,:)
+     !
+  ENDIF
+  !
+  !----------------------------
+  !---------Idealized case-----
+  !----------------------------
+  IF (HIBM_TYPE=='IDEA') THEN
      !
      OPEN(ILUIBMIDEA , FILE= HFILEIDEA , IOSTAT=IRESPIBMIDEA , FORM='FORMATTED' , &
           STATUS='OLD', ACCESS='SEQUENTIAL', ACTION='READ')
@@ -216,16 +402,41 @@ SUBROUTINE IBM_PREP_LS(OIBM,HIBM_TYPE,PPHI)
   !     -------------
   ! 
   ! Computations of volumic fraction (VF) and Level Set function (LS) for all kinds of initialization
-  !        idealized shape  => construction of VF/LS function using analytical
+  !        generalized shape => construction of LS function (z<z_interface <=> phi>0)
+  !                             the method is based on '3D Distance from a Point to a Triangle' [Jones (1995)].
+  !                          => conversion of LS function to VF function (Sussman, JCP (1994)
+  !        idealized shape   => construction of VF/LS function using analytical
   !                            locations of interface (ellipsoidal/parallelepipedic shapes)
   !
-  IF ((HIBM_TYPE=='IDEA')) then
+  IF (HIBM_TYPE=='GENE') THEN
+     CALL IBM_GENERLS(ZIBM_FACES2,NORM_FACES2,ZV1_2,ZV2_2,ZV3_2,ZX_MIN,ZY_MIN,ZX_MAX,ZY_MAX,PPHI)
+  ENDIF
+  !
+  IF (HIBM_TYPE=='IDEA') then
      DO JN=1,JNM
-        !
         IF (abs(ZIBM_XYZ2(JN,7)-1.).lt.XIBM_EPSI) CALL IBM_IDEALRP(JN,ZIBM_XYZ2,PPHI)
         IF (abs(ZIBM_XYZ2(JN,7)-2.).lt.XIBM_EPSI) CALL IBM_IDEALEE(JN,ZIBM_XYZ2,PPHI)
      ENDDO
-     !
   ENDIF
   !
+CONTAINS
+  !
+  FUNCTION CROSSPRODUCT(PA,PB) RESULT(CROSS)
+    !
+    REAL, DIMENSION(3)             :: CROSS
+    REAL                           :: VAL
+    REAL, DIMENSION(3), INTENT(IN) :: PA, PB
+    !
+    CROSS(1) = PA(2) * PB(3) - PA(3) * PB(2)
+    CROSS(2) = PA(3) * PB(1) - PA(1) * PB(3)
+    CROSS(3) = PA(1) * PB(2) - PA(2) * PB(1)
+    !
+    VAL = (CROSS(1)**2+CROSS(2)**2+CROSS(3)**2)**(0.5)
+    !
+    CROSS(1) = CROSS(1)/VAL
+    CROSS(2) = CROSS(2)/VAL
+    CROSS(3) = CROSS(3)/VAL
+    !
+  END FUNCTION CROSSPRODUCT
+  !
 END SUBROUTINE IBM_PREP_LS
-- 
GitLab