Choral
feSpace_mod.F90
Go to the documentation of this file.
1 
56 !
59 
62  use real_type
63  use abstract_interfaces, only: r3tor3, r3tor
64  use algebra_set
65  use basic_tools
66  use graph_mod
67  use cell_mod
68  use quad_mod
69  use mesh_mod
70  use fe_mod
71  use geotsf_mod
72 
73  implicit none
74  private
75 
76 
77  ! %----------------------------------------%
78  ! | |
79  ! | PUBLIC DATA |
80  ! | |
81  ! %----------------------------------------%
82  public :: fespace
83 
84  public :: set, assemble !! TESTED
85  public :: clear
86  public :: interp_scal_func !! TESTED
87  public :: interp_vect_func !! TESTED
88  public :: interp_scal_fe !! TESTED
89  public :: eval_scal_fe_at_points !! TESTED
90  public :: print, valid, write, gmsh_addview
91  public :: flag_x_h_dof
92 
93 
94  ! %----------------------------------------%
95  ! | |
96  ! | DERIVED TYPE |
97  ! | |
98  ! %----------------------------------------%
103  type fespace
104 
105  !! DOF
106  integer :: nbdof=0
107 
108  !! feType = finite element method type per mesh cell
109  !! dofCoord = dof nodes coordinates
110  !! dofType(ii) = type of dof ii
111  real(RP), dimension(:,:), allocatable :: dofcoord
112  integer , dimension(:) , allocatable :: doftype
113  integer , dimension(:) , allocatable :: fetype
114 
115  !! associated mesh
116  type(mesh), pointer :: mesh=>null()
117 
118  !! cell dof local indexing --> dof global indexing
119  !! cell to dof connectivity
120  type(graph) :: cltodof
121 
122  !! dof_count(CELL_XXX) = number of dof
123  !! having CELL_XXX as geometry
124  !! fe_count(FE_XXX ) = number of cells
125  !! with the FE method FE_XXX
126  integer, dimension(CELL_TOT_NB) :: dof_count = 0
127  integer, dimension(0:FE_TOT_NB) :: fe_count = 0
128 
129  contains
130 
132  final :: fespace_clear
133 
134  end type fespace
135 
136 
137  ! %----------------------------------------%
138  ! | |
139  ! | GENERIc SUBROUTINES |
140  ! | |
141  ! %----------------------------------------%
142  interface clear
143  module procedure fespace_clear
144  end interface clear
145 
146  interface valid
147  module procedure fespace_valid
148  end interface valid
149 
150  interface fespace
151  module procedure fespace_create
152  end interface fespace
153 
154  interface set
155  module procedure fespace_set
156  end interface set
157 
159  interface print
160  module procedure fespace_print
161  end interface print
162 
164  interface write
165  module procedure fespace_write
166  end interface write
167 
168  interface assemble
169  module procedure fespace_assemble
170  end interface assemble
171 
173  module procedure fespace_interp_vect_func
174  end interface interp_vect_func
175 
176 contains
177 
179  subroutine fespace_clear(X_h)
180  type(fespace), intent(inout) :: X_h
181 
182  x_h%nbDof = 0
183  x_h%dof_count = 0
184  x_h%fe_count = 0
185 
186  x_h%mesh => null()
187 
188  call freemem(x_h%feType)
189  call freemem(x_h%dofType)
190  call freemem(x_h%dofCoord)
191  call clear(x_h%clToDof)
192 
193  end subroutine fespace_clear
194 
205  function fespace_create(m) result(X_h)
206  type(fespace) :: X_h
207  type(mesh) , target :: m
208 
209  if (choral_verb>0) write(*,*) 'feSpace_mod : create'
210  call clear(x_h)
211  if(.NOT.valid(m)) call quit( &
212  & "feSpace_mod: feSpace_create: mesh 'm' not valid" )
213  x_h%mesh => m
214  call allocmem( x_h%feType, m%nbCl )
215  x_h%feType = fe_none
216  if (choral_verb>1) write(*,*) &
217  & ' Number of cells =', x_h%mesh%nbCl
218 
219  end function fespace_create
220 
224  subroutine fespace_set(X_h, ft)
225  type(fespace), intent(inout) :: X_h
226  integer , intent(in) :: ft
227 
228  integer :: ii, jj, geo, cl_geo, cpt
229 
230  geo = fe_geo(ft)
231  cpt = 0
232 
233  do ii=1, x_h%mesh%nbCl
234 
235  jj = x_h%mesh%clType(ii)
236  cl_geo = cell_geo(jj)
237 
238  if (geo==cl_geo) then
239  x_h%feType(ii) = ft
240  cpt = cpt + 1
241  end if
242 
243  end do
244 
245  if (choral_verb>0) write(*,*) &
246  &'feSpace_mod : set =', &
247  & cpt, ' cells ', fe_name(ft)
248 
249  end subroutine fespace_set
250 
251 
252 
255  subroutine fespace_print(X_h)
256  type(fespace), intent(in) :: X_h
257 
258  integer :: ii
259 
260  write(*,*)"feSpace_mod : print"
261  write(*,*)" Number of DOF =", x_h%nbDof
262 
263  write(*,*) ' DOF per geometrical type'
264  do ii=1, cell_tot_nb
265  if ( x_h%dof_count(ii)>0) then
266  write(*,*) ' ', &
267  & cell_name(ii), ' DOF =', &
268  & x_h%dof_count(ii)
269  end if
270  end do
271  write(*,*) ' Number of cells per fe method'
272  do ii=0, fe_tot_nb
273  if ( x_h%fe_count(ii)>0) then
274  write(*,*) ' ', &
275  &fe_name(ii), ' =', &
276  & x_h%fe_count(ii)
277  end if
278  end do
279 
280  end subroutine fespace_print
281 
282 
285  function fespace_valid(X_h) result(b)
286  type(fespace), intent(in) :: x_h
287  logical :: b
288 
289  b = .false.
290  if(.NOT. ( associated(x_h%mesh) )) return
291  if(.NOT. ( valid(x_h%mesh) )) return
292  if( valid(x_h%clToDof) < 0 ) return
293  if(.NOT. ( allocated(x_h%dofCoord) )) return
294  if(.NOT. ( allocated(x_h%dofType) )) return
295  if(.NOT. ( allocated(x_h%feType) )) return
296 
297  b = x_h%nbdof>0
298  b = b .AND. ( all( shape(x_h%dofCoord) == (/3,x_h%nbdof/)) )
299  b = b .AND. ( size(x_h%dofType,1) == x_h%nbdof )
300  b = b .AND. ( size(x_h%feType,1) == x_h%mesh%nbCl )
301  b = b .AND. ( x_h%clToDof%nl == x_h%mesh%nbCl )
302 
303  end function fespace_valid
304 
305 
307  subroutine fespace_write (X_h, fileName, fileFormat)
308  type(fespace) , intent(in) :: X_h
309  character(len=*), intent(in) :: fileName, fileFormat
310 
311  if (choral_verb>1) write(*,*)&
312  & "feSpace_mod : write format = ",&
313  & trim(fileformat), " to ", trim(filename)
314 
315  select case(trim(fileformat))
316  case("gmsh")
317  call gmsh_write(x_h, filename)
318 
319  case default
320  call quit( "feSpace_mod: feSpace_write: uncorrect file format" )
321 
322  end select
323 
324  end subroutine fespace_write
325 
327  subroutine gmsh_write (X_h, fileName)
328  type(fespace) , intent(in) :: X_h
329  character(len=*), intent(in) :: fileName
330 
331  integer :: ii, cpt, ft, wdt, s1
332 
333  integer, dimension(:), allocatable :: p1
334 
335  open(unit = 999,file = filename)
336 
337  write(999,fmt="(A)") '$MeshFormat'
338  write(999,fmt="(A)") '2.2 0 8'
339  write(999,fmt="(A)") '$EndMeshFormat'
340  write(999,fmt="(A)") '$Nodes'
341  write(999,*) x_h%nbdof
342  do ii=1, x_h%nbdof
343  write(999,*) ii, x_h%dofCoord(:, ii)
344  end do
345  write(999,fmt="(A)") '$EndNodes'
346  write(999,fmt="(A)") '$Elements'
347 
348  !! count cells with non void fe method
349  !!
350  cpt = size(x_h%feType,1)
351  do ii=1, size(x_h%feType,1)
352  if (x_h%fetype(ii)==fe_none) cpt = cpt-1
353  end do
354  write(999,*) cpt
355 
356  !! write cells with non void fe method
357  !!
358  cpt = 0
359  wdt = x_h%clToDof%width
360  call allocmem(p1, wdt)
361  do ii=1, size(x_h%feType,1)
362 
363  ft = x_h%fetype(ii)
364 
365  if (ft==fe_none) cycle
366 
367  cpt = cpt + 1
368  call getrow(s1, p1, wdt, x_h%clToDof, ii)
369 
370  select case(ft)
371 
372  case(fe_p1_1d) ! line, order 1
373  write(999,*) cpt, 1, 0, p1(1:s1)
374 
375  case(fe_p2_1d) ! line, order 2
376  write(999,*) cpt, 8, 0, p1(1:s1)
377 
378  case(fe_p3_1d) ! line, order 3
379  write(999,*) cpt, 26, 0, p1(1:s1)
380 
382  & ) ! triangle, order 1
383  write(999,*) cpt, 2, 0, p1(1:s1)
384 
385  case(fe_p2_2d) ! triangle, order 2
386  write(999,*) cpt, 9, 0, p1(1:s1)
387 
388  case(fe_p3_2d) ! triangle, order 3
389  write(999,*) cpt, 21, 0, p1(1:s1)
390 
391  case(fe_p1_3d) ! tetra, order 1
392  write(999,*) cpt, 4, 0, p1(1:4)
393 
394  case(fe_p2_3d) ! tetra, order 1
395  write(999,*) cpt, 11, 0, p1(1:8), p1(10), p1(9)
396 
397  case default
398  call quit('feSpace_mod: gmsh_write: cell type not supported')
399 
400  end select
401 
402  end do
403  write(999,fmt="(A)") '$EndElements'
404 
405  close(999)
406 
407  end subroutine gmsh_write
408 
411  subroutine gmsh_addview(X_h, v, fileName, vname, time, idx)
412  type(fespace) , intent(in) :: X_h
413  real(RP), dimension(:), intent(in) :: v
414  character(len=*) , intent(in) :: fileName, vname
415  real(RP) , intent(in) :: time
416  integer , intent(in) :: idx
417 
418  integer :: ii
419 
420  if (choral_verb>1) write(*,*)&
421  &"feSpace_mod : gmsh_addView = "&
422  &//trim(filename)
423 
424  if (size(v,1)/=x_h%nbDof) call quit( &
425  & "feSpace_mod: gmsh_addView: fe function 'v' uncorrect" )
426 
427  open(unit = 999,file = filename, position='append', status='old')
428 
429  write(999,fmt="(A)") '$NodeData'
430  write(999,fmt="(A)") '1'
431  write(999,fmt="(A)") '"'//trim(vname)//'"'
432  write(999,fmt="(A)") '1'
433  write(999,*) time
434  write(999,fmt="(A)") '3'
435  write(999,*) idx
436  write(999,fmt="(A)") '1'
437  write(999,*) x_h%nbDof
438  do ii=1, x_h%nbDof
439  write(999,*) ii, v(ii)
440  end do
441  write(999,fmt="(A)") '$EndNodeData'
442  close(999)
443 
444  end subroutine gmsh_addview
445 
446 
447 
467  subroutine interp_scal_fe(u2, X_h2, u1, X_h1)
468  real(RP), dimension(:), intent(out) :: u2
469  type(fespace) , intent(in) :: X_h1, X_h2
470  real(RP), dimension(:), intent(in) :: u1
471 
472  integer, dimension(:), allocatable :: T
473  type(mesh), pointer :: m1 =>null()
474  type(graph) :: ndToNd
475  real(RP) :: dist
476  integer :: w1, nbDof, dim, ft
477 
478  if (choral_verb>0) write(*,*)&
479  & "feSpace_mod : interp_scal_fe"
480 
481  if(.NOT.valid(x_h1)) call quit( &
482  & "feSpace_mod: interp_scal_fe:&
483  & fe space 'X_h1' not valid" )
484 
485  if(.NOT.valid(x_h2)) call quit( &
486  & "feSpace_mod: interp_scal_fe:&
487  & fe space 'X_h2' not valid" )
488 
489  if (size(u1,1)/=x_h1%nbDof) call quit( &
490  & "feSpace_mod: interp_scal_fe:&
491  & fe function 'u1' uncorrect")
492 
493  if (size(u2,1)/=x_h2%nbDof) call quit( &
494  & "feSpace_mod: interp_scal_fe:&
495  & fe function 'u2' uncorrect")
496 
497  !! Srortcut to m1
498  !!
499  m1 => x_h1%mesh
500 
501  !! Node to node connectivity for m1
502  !!
503  call graph_prod(ndtond, x_h1%mesh%NdToCl, x_h1%mesh%clToNd)
504 
505  !! Search the closest node of m1
506  !! for all dof
507  !!
508  call closest_node(t, dist, x_h2%dofCoord, m1, ndtond)
509 
510 
511  !! Locate each dof of X_h2
512  !! inside a cell of m1
513  !!
514  call locate_nodes(t, x_h2%dofCoord, x_h1, ndtond)
515  call clear(ndtond)
516 
517  !! Conversion
518  !!
519  w1 = m1%clToNd%width
520  do ft=1, fe_tot_nb
521  if (x_h1%fe_count(ft)==0) cycle
522 
523  nbdof = fe_nbdof(ft)
524  dim = fe_dim(ft)
525 
526  call dof_loop()
527 
528  end do
529  m1 =>null()
530 
531  contains
532 
533  subroutine dof_loop()
535  integer , dimension(w1) :: p1
536  integer , dimension(nbDof) :: p2
537  real(RP), dimension(nbDof) :: u1_loc, val
538  real(RP), dimension(3,w1) :: Y
539  real(RP), dimension(3) :: x,z
540  integer :: ii, cl1, s1
541 
542  do ii=1, size(u2,1)
543 
544  !! dof is in cell cl1 of the mesh m1
545  cl1 = t(ii)
546  if ( x_h1%feType(cl1) /= ft ) cycle
547 
548  !! dof coordinates
549  x = x_h2%dofCoord(:,ii)
550 
551  !! p1(1:s1) = nodes of cell cl1
552  !!
553  call getrow(s1, p1, w1, m1%clToNd, cl1)
554 
555  !! Cell node coordinates
556  !!
557  call getndcoord(y, w1, p1(1:s1), s1, m1)
558 
559  !! Local coordinates
560  !!
561  call geotsf_t_inv(z, x, y(1:3,1:s1), s1, m1%clType(cl1) )
562 
563  !! values of u1 at the nodes in cl1
564  !!
565  call getrow(p2, nbdof, x_h1%clToDof, cl1)
566  u1_loc = u1(p2)
567 
568  select case(x_h2%dofType(ii))
569  case(fe_dof_lag)
570 
571  ! values of the base functions at z
572  call scal_fe(val, nbdof, z(1:dim), dim, ft)
573 
574  u2(ii) = sum( val*u1_loc )
575 
576  case default
577  call quit( "feSpace_mod: interp_scal_fe:&
578  & DOF type not supported")
579 
580  end select
581  end do
582 
583  end subroutine dof_loop
584 
585  end subroutine interp_scal_fe
586 
587 
588 
604  subroutine eval_scal_fe_at_points(val, P, u, X_h)
605  real(RP), dimension(:) , allocatable :: val
606  type(fespace) , intent(in) :: X_h
607  real(RP), dimension(:) , intent(in) :: u
608  real(RP), dimension(:,:), intent(in) :: P
609 
610  integer, dimension(:), allocatable :: T
611  type(mesh), pointer :: m =>null()
612  type(graph) :: ndToNd
613  real(RP) :: dist
614  integer :: w1, nbDof, dim, ft
615 
616  if (choral_verb>0) write(*,*)&
617  & "feSpace_mod : eval_scal_fe_at_points"
618 
619  if(.NOT.valid(x_h)) call quit( &
620  & "feSpace_mod: eval_scal_fe_at_points:&
621  & fe space 'X_h' not valid" )
622 
623  if (size(u,1)/=x_h%nbDof) call quit( &
624  & "feSpace_mod: eval_scal_fe_at_points:&
625  & fe function 'u' uncorrect")
626 
627  if (size(p,1)/=3 ) call quit( &
628  & "feSpace_mod: eval_scal_fe_at_points:&
629  & argument 'P' must have shape 3 x nb_points")
630 
631  !! allocation for val
632  !!
633  call allocmem(val, size(p,2))
634 
635  !! alias for X_h%mesh
636  !!
637  m => x_h%mesh
638 
639  !! Node to node connectivity for m
640  !!
641  call graph_prod(ndtond, m%NdToCl, m%clToNd)
642 
643  !! Search the cosest node of m
644  !! for all points P(:,i)
645  !!
646  call closest_node(t, dist, p, m, ndtond)
647 
648 
649  !! Locate each point P(:,i)
650  !! inside a cell of X_h%mesh with non void
651  !! feType
652  !!
653  call locate_nodes(t, p, x_h, ndtond)
654  call clear(ndtond)
655 
656  !! Conversion
657  !!
658  w1 = m%clToNd%width
659  do ft=1, fe_tot_nb
660  if (x_h%fe_count(ft)==0) cycle
661 
662  nbdof = fe_nbdof(ft)
663  dim = fe_dim(ft)
664 
665  call dof_loop()
666 
667  end do
668  m =>null()
669 
670  contains
671 
672  subroutine dof_loop()
673 
674  integer , dimension(w1) :: p1
675  integer , dimension(nbDof) :: p2
676  real(RP), dimension(nbDof) :: u_loc, u_base_val
677  real(RP), dimension(3,w1) :: Y
678  real(RP), dimension(3) :: x,z
679  integer :: ii, cl, s1
680 
681  do ii=1, size(val,1)
682 
683  !! point coordinates
684  x = p(:,ii)
685 
686  !! the point P(:,i) is in the cell cl of the mesh m
687  cl = t(ii)
688  if ( x_h%feType(cl) /= ft ) cycle
689 
690  !! p1(1:s1) = nodes of cell cl
691  !!
692  call getrow(s1, p1, w1, m%clToNd, cl)
693 
694  !! Cell node coordinates
695  !!
696  call getndcoord(y, w1, p1(1:s1), s1, m)
697 
698  !! z = local coordinates of P(:,i) in the ref. cell
699  !!
700  call geotsf_t_inv(z, x, y(1:3,1:s1), s1, m%clType(cl) )
701 
702  !! values of u at the finite element nodes
703  !! in the cell cl1
704  !!
705  call getrow(p2, nbdof, x_h%clToDof, cl)
706  u_loc = u(p2)
707 
708  ! values of the base functions at z
709  call scal_fe(u_base_val, nbdof, z(1:dim), dim, ft)
710 
711  val(ii) = sum( u_base_val*u_loc )
712  end do
713 
714  end subroutine dof_loop
715 
716  end subroutine eval_scal_fe_at_points
717 
718 
719 
731  subroutine locate_nodes(T, P, X_h, ndToNd)
732  integer , dimension(:) , intent(inout):: T
733  real(RP), dimension(:,:), intent(in) :: P
734  type(fespace) , intent(in) :: X_h
735  type(graph) , intent(in) :: ndToNd
736 
737  type(mesh), pointer :: m=>null()
738  integer :: nbPts, w1, w2, w3, w4, cpt1, cpt2, cpt3
739  real(RP) :: a
740 
741  if (choral_verb>0) write(*,*) &
742  & 'feSpace_mod : locate_nodes'
743 
744  if(.NOT.valid(x_h)) call quit( &
745  & "feSpace_mod: locate_nodes:&
746  & fe space 'X_h' not valid" )
747 
748  if (size(p,1)/= 3) call quit( &
749  & "feSpace_mod: locate_nodes:&
750  & array 'P' first dimension must be 3" )
751 
752  !! Number of points
753  !!
754  nbpts=size( p, 2)
755 
756  if (size(t,1)/=nbpts) call quit( &
757  & "feSpace_mod: locate_nodes:&
758  & node tab 'T' uncorrect" )
759 
760  m => x_h%mesh
761 
762  cpt1 = 0
763  cpt2 = 0
764  cpt3 = 0
765 
766  w1 = m%ndToCl%width
767  w2 = m%clToNd%width
768  w3 = ndtond%width
769  w4 = w1*w3
770 
771  call loop()
772 
773  a = re(cpt1, nbpts)*100._rp
774  if (choral_verb>1) write(*,*) &
775  & " locate_nodes, 1st search =",&
776  & real(a, SP), ' % '
777 
778  if (cpt2>0) then
779  a = re(cpt2, nbpts)*100._rp
780  if (choral_verb>1) write(*,*) &
781  &" locate_nodes, 2nd search =",&
782  & real(a, SP), ' % '
783  end if
784 
785  if (cpt3>0) then
786  a = re(cpt3, nbpts)*100._rp
787  if (choral_verb>1) write(*,*) &
788  & " locate_nodes, 3rd search =",&
789  & real(a, SP), ' % '
790  end if
791 
792  contains
793 
794  subroutine loop()
795  integer , dimension( w1) :: p1
796  integer , dimension( w2) :: p2
797  integer , dimension( w3) :: p3
798  integer , dimension( w4) :: p4, bf1
799  real(RP), dimension(3,w1) :: Y
800 
801  integer :: s1, s2, s3, s4
802 
803  integer :: ii, jj, cl
804  logical :: bool
805  real(RP), dimension(3) :: x
806 
807  do ii=1, nbpts
808  x = p(:,ii)
809  bool = .false.
810  !!
811  !! 1st search among the neighbour cells of node T(ii)
812  !!
813  !! p1(1:s1) = neighbour cells of the node T(ii)
814  !!
815  call getrow(s1, p1, w1, m%ndToCl, t(ii) )
816 
817  !! Loop on the neighbour cells
818  !!
819  do jj=1, s1
820  cl = p1(jj)
821  if (x_h%feType(cl) == fe_none) cycle
822 
823  !! p2(1:s2) = nodes of cell cl
824  !!
825  call getrow(s2, p2, w2, m%clToNd, cl )
826 
827  !! Cell node coordinates
828  !!
829  call getndcoord(y, w1, p2(1:s2), s2, m)
830 
831  bool = belongstocell(x, y(1:3, 1:s2), s2, m%clType(cl))
832 
833  if (bool) then
834  cpt1 = cpt1 + 1
835  exit
836  end if
837  end do
838 
839  if (.NOT.bool) then
840 
841  !!
842  !! 2nd search among the neighbour of the neighbour cells
843  !!
844  !! p3(1:s3) = nodes connected with the node T(ii)
845  !!
846  call getrow(s3, p3, w3, ndtond, t(ii) )
847  !!
848  !! p4(1:s4) = neighbour cells to nodes in p3(1:s3)
849  !!
850  call union(s4, p4, bf1, w4, p1, w1, &
851  & m%ndToCl, p3(1:s3), s3)
852 
853  !!
854  !! Loop on the neighbour cells
855  !!
856  do jj=1, s4
857  cl = p4(jj)
858  if (x_h%feType(cl) == fe_none) cycle
859 
860  !! p2(1:s2) = nodes of cell cl
861  !!
862  call getrow(s2, p2, w2, m%clToNd, cl )
863 
864  !! Cell node coordinates
865  !!
866  call getndcoord(y, w1, p2(1:s2), s2, m)
867 
868  bool = belongstocell(x, y(1:3, 1:s2), s2, m%clType(cl))
869 
870  if (bool) then
871  cpt2 = cpt2 + 1
872  exit
873  end if
874  end do
875 
876  end if
877 
878  if (.NOT.bool) then
879  cpt3 = cpt3 + 1
880  !!
881  !! 3rd search : choose a close cell
882  !!
883  cl = closest_cell(x, x_h)
884  end if
885 
886  t(ii) = cl
887 
888  end do
889 
890  end subroutine loop
891 
892  end subroutine locate_nodes
893 
894 
901  function closest_cell(x, X_h) result(cl)
902  real(RP), dimension(3), intent(in) :: x
903  type(fespace) , intent(in) :: X_h
904  integer :: cl
905 
906  integer , dimension( CELL_MAX_NBNODES) :: p1
907  real(RP), dimension(3,CELL_MAX_NBNODES) :: Y
908  integer :: ii, jj, nbVtx, s1
909  real(RP) :: a, dist
910  type(mesh), pointer :: m=>null()
911 
912  m => x_h%mesh
913  cl = 0
914  dist = 1e127_rp
915 
916 
917  do ii=1, m%nbCl
918 
919  if (x_h%feType(ii) == fe_none) cycle
920 
921  !! p1(1:s1) = nodes of cell cl1
922  !!
923  call getrow(s1, p1, cell_max_nbnodes, m%clToNd, ii)
924 
925  !! Cell node coordinates
926  !!
927  call getndcoord(y, cell_max_nbnodes, p1(1:s1), s1, m)
928 
929  a = 0._rp
930  jj = m%clType(ii)
931  nbvtx = cell_nbvtx(jj)
932  do jj=1, nbvtx
933  a = a + sum(abs( y(:,jj) - x ))
934  end do
935  a = a / re(nbvtx)
936  if (a<dist) then
937  dist = a
938  cl = ii
939  end if
940 
941  end do
942 
943  m=>null()
944 
945  end function closest_cell
946 
947 
948 
951  subroutine fespace_assemble(X_h)
952  type(fespace), intent(inout) :: X_h
953 
954  integer, dimension(:,:), allocatable :: dofTab
955  integer, dimension(X_h%mesh%nbCl) :: cl_row
956 
957  integer :: wdt
958 
959  if (choral_verb>0) write(*,*)&
960  & "feSpace_mod : assemble"
961 
962  if ( sum(x_h%feType(:))==0 ) call quit( &
963  'feSpace_mod: assemble: feType not defined' )
964 
965  call freemem(x_h%dofType)
966  call freemem(x_h%dofCoord)
967  x_h%dof_count = 0
968  x_h%fe_count = 0
969 
970  call initialise_doftab(doftab, cl_row, x_h)
971 
972  wdt = x_h%mesh%ndToCl%width
973  call scan_dof(doftab, x_h, wdt)
974 
975  call build_cltodof(doftab, cl_row, x_h)
976  call freemem( doftab )
977 
978  call x_h_dofcoord(x_h)
979 
980  if (choral_verb>1) write(*,*) &
981  & " Number of DOF =", x_h%nbDof
982 
983  if (.NOT.valid(x_h)) call quit(&
984  & 'feSpace_mod: feSpace_assemble: assembling not valid' )
985 
986  end subroutine fespace_assemble
987 
988 
989  subroutine x_h_dofcoord(X_h)
990  type(fespace), intent(inout) :: X_h
991 
992  type(mesh), pointer :: m=>null()
993  type(geotsf) :: g
994  integer , dimension(CELL_MAX_NBNODES) :: p_cl
995  integer , dimension(FE_MAX_NBDOF) :: p_dof
996  real(RP), dimension(3, CELL_MAX_NBNODES):: X
997  integer :: ft, fe_typ, cl, sz, ll, dof
998  integer :: dim, nbDof
999 
1000  call allocmem( x_h%dofCoord, 3, x_h%nbDof)
1001 
1002  m=>x_h%mesh
1003  do ft =1, fe_tot_nb
1004 
1005  if( x_h%fe_count(ft) == 0 ) cycle
1006 
1007  dim = fe_dim(ft)
1008  nbdof = fe_nbdof(ft)
1009  g = geotsf(dim, nbdof, fe_dof_coord(ft)%y )
1010 
1011  do cl=1, x_h%mesh%nbCl
1012  fe_typ = x_h%feType(cl)
1013 
1014  if (ft /= fe_typ) cycle
1015 
1016  ! cell node coordinates
1017  ! sz = nbNodes
1018  call getrow(sz, p_cl, cell_max_nbnodes, m%clToNd, cl)
1019  do ll=1, sz
1020  x(1:3,ll) = m%nd( 1:3, p_cl(ll) )
1021  end do
1022 
1023  ! dof coordinates
1024  call assemble(g, m%clType(cl), x(1:3, 1:sz), sz)
1025 
1026  ! dof indexes
1027  call getrow(sz, p_dof, fe_max_nbdof, x_h%clTodof, cl)
1028 
1029  do ll=1, sz
1030 
1031  dof = p_dof(ll)
1032  x_h%dofCoord(:,dof) = g%Ty(:,ll)
1033 
1034  end do
1035 
1036  end do
1037  end do
1038  m=>null()
1039 
1040  end subroutine x_h_dofcoord
1041 
1042 
1043  subroutine initialise_doftab(dofTab, cl_row, X_h)
1044  integer, dimension(:,:), allocatable, intent(inout) :: dofTab
1045  integer, dimension(:), intent(out) :: cl_row
1046  type(fespace), intent(inout) :: X_h
1047 
1048  integer, dimension(X_h%mesh%nbCl) :: nnz
1049  integer :: ii, cpt, fe_typ, nn
1050 
1051  !! The array dofTab contains all local dof
1052  !!
1053  !! jj = number of dof of cell ii
1054  !!
1055  !! nnz(ii) = jj
1056  !!
1057  !! the rows in dofTab associated with the cell ii
1058  !! are : cl_row(ii) + 1 ... cl_row(ii) + jj
1059  !!
1060  cpt = 0
1061  do ii = 1, x_h%mesh%nbCl
1062  fe_typ = x_h%feType(ii)
1063 
1064  x_h%fe_count(fe_typ) = x_h%fe_count(fe_typ) + 1
1065 
1066  if (fe_typ==0) then
1067  nnz( ii ) = 0
1068 
1069  else
1070  cl_row( ii ) = cpt
1071  nn = fe_nbdof(fe_typ)
1072  cpt = cpt + nn
1073  nnz( ii ) = nn
1074 
1075  end if
1076  end do
1077 
1078  x_h%clToDof = graph(nnz, size(nnz,1), 0)
1079  call allocmem(doftab, 3, cpt )
1080  doftab = 0
1081 
1082  end subroutine initialise_doftab
1083 
1084 
1090  subroutine scan_dof(dofTab, X_h, wdt)
1091  integer, dimension(:,:), intent(inout) :: dofTab
1092  type(fespace), intent(inout) :: X_h
1093  integer , intent(in) :: wdt
1094 
1095  type(mesh), pointer :: m=>null()
1096  integer , dimension(wdt, CELL_MAX_NBNODES):: vtx_toCl
1097  integer , dimension(wdt) :: dof1_cl, temp
1098  integer , dimension(CELL_MAX_NBNODES):: cl1_vtx, cl2_nd
1099  integer , dimension(CELL_MAX_NBNODES):: vtx_nbCl
1100  integer , dimension(CELL_MAX_NBVTX) :: dof1_vtx, dof2_vtx
1101  integer , dimension(CELL_MAX_NBVTX) :: dof1_vtx_g, dof2_vtx_g
1102  real(RP), dimension(CELL_MAX_NBVTX) :: dof1_bary, dof2_bary
1103  integer , dimension(CELL_MAX_NBVTX) :: sort1, sort2
1104  integer , dimension(2) :: p_3
1105  integer :: p_2
1106 
1107  integer :: dof_cpt, ii, jj, ll, nn, vtx
1108  integer :: cl1, cl1_nbVtx
1109  integer :: cl2, cl2_nbNd, cl2_ind
1110  integer :: dof1, dof1_type, dof1_geo
1111  integer :: dof1_nbCl
1112  integer :: dof2, dof2_type, dof2_geo
1113  integer :: geo1, ft1, ft2
1114  logical :: bool
1115 
1116  m=>x_h%mesh
1117  !!
1118  !! Loop on the mesh cells
1119  !!
1120  dof_cpt = 0
1121  do cl1 = 1, m%nbCl
1122  ft1 = x_h%feType( cl1 )
1123  if ( ft1 == fe_none ) cycle
1124 
1125  !! cell cl1 geometrical type
1126  geo1 = fe_geo( ft1 )
1127 
1128  !! cl1_nbVtx = number of vertexes of cell cl1
1129  !! cl1_vtx(:) = vertexes of cl1 (global indexzs)
1130  !!
1131  call getrow(cl1_nbvtx, cl1_vtx, cell_max_nbnodes, &
1132  & m%clToNd, cl1)
1133  !!
1134  !! We only consider the vertexes
1135  !!
1136  cl1_nbvtx = cell_nbvtx( geo1 )
1137 
1138 
1139  !! For the vertex ii of cell cl1 :
1140  !! vtx_nbCl(ii) = number of neighbour cells
1141  !! vtx_toCl(:,ii) = neighbour cells
1142  !!
1143  do ii=1, cl1_nbvtx
1144  call getrow(vtx_nbcl(ii), vtx_tocl(:,ii), wdt, &
1145  & m%ndToCl, cl1_vtx(ii))
1146  end do
1147 
1148  !! For the vertex ii of cell cl1 :
1149  !! Only consider the neighbour cells with index < cl1
1150  !!
1151  !! vtx_nbCl(ii) = number of neighbour cells
1152  !! with index < cl1
1153  !!
1154  !! IMPORTANT : the graph m%ndCl is sorted ! (see transpose)
1155  !!
1156  do ii=1, cl1_nbvtx
1157  inner_loop: do jj=1, vtx_nbcl(ii)
1158  ll = vtx_tocl(jj,ii)
1159  if ( ll == cl1 ) then
1160  vtx_nbcl(ii) = jj-1
1161  exit inner_loop
1162  end if
1163  end do inner_loop
1164  end do
1165 
1166  !! Loop on the dof of cell cl1
1167  !!
1168  dof_loop: do dof1=1, fe_nbdof(ft1)
1169  dof_cpt = dof_cpt + 1
1170  dof1_geo = fe_dof_geo(dof1, ft1)
1171  dof1_type = fe_dof_type(dof1, ft1)
1172 
1173 
1174  select case(dof1_geo)
1175 
1176  case(cell_tet)
1177  ! new dof
1178  x_h%dof_count(cell_tet) = x_h%dof_count(cell_tet) + 1
1179  doftab(3, dof_cpt) = dof1_type
1180 
1181  case(cell_vtx) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1182 
1183  !! vertex local index in cl1
1184  !!
1185  dof1_vtx(1) = fe_dof_vtx( 1, dof1, ft1)
1186 
1187  !! dof1_nbCl = number of cells associated with dof1
1188  !! dof1_cl(:) = cells associated with dof1
1189  !! with index < cl1
1190  !!
1191  vtx = dof1_vtx(1)
1192  dof1_nbcl = vtx_nbcl(vtx)
1193  if (dof1_nbcl==0) goto 10 ! new dof
1194  dof1_cl( 1: dof1_nbcl) = vtx_tocl( 1: dof1_nbcl, vtx)
1195 
1196  !! dof1_vtx_g(:) = vtx associated with dof1
1197  !! global indexes in the mesh
1198  !!
1199  dof1_vtx_g(1) = cl1_vtx( dof1_vtx(1) )
1200 
1201  !! Search if dof1 also is a dof of a cell
1202  !! in dof1_cl( 1: dof1_nbCl)
1203  !!
1204  ngb_cl_a: do cl2_ind=1, dof1_nbcl
1205 
1206  cl2 = dof1_cl(cl2_ind)
1207  ft2 = x_h%feType(cl2)
1208  if ( ft2 == fe_none ) cycle ngb_cl_a
1209 
1210  !! cl2_nbNd = number of nodes of cell cl2
1211  !! cl2_nd(:) = nodes of cell cl2 (global indexzs)
1212  !!
1213  call getrow(cl2_nbnd, cl2_nd, &
1214  & cell_max_nbnodes, m%clToNd, cl2)
1215 
1216  !! Loop on the dof of cl2
1217  !!
1218  dof2_a: do dof2=1, fe_nbdof(ft2)
1219 
1220  dof2_geo = fe_dof_geo(dof2, ft2)
1221  if ( dof2_geo /= dof1_geo) cycle dof2_a
1222 
1223  !! dof2_vtx(1) = vtx associated with dof2
1224  !! (local indexes in cl2)
1225  !!
1226  dof2_vtx( 1 ) = fe_dof_vtx( 1, dof2, ft2)
1227 
1228  !! dof2_vtx_g(1) = vtx associated with dof1
1229  !! global indexes in mesh
1230  dof2_vtx_g(1) = cl2_nd( dof2_vtx(1) )
1231 
1232  !! We verify if dof1 and dof2 are associated with
1233  !! the same vertex in the mesh
1234  !!
1235  bool = ( dof1_vtx_g(1) == dof2_vtx_g(1) )
1236  if ( .NOT. bool ) cycle dof2_a
1237 
1238  !! dof type comparison
1239  !!
1240  dof2_type = fe_dof_type(dof2, ft2)
1241  if ( dof2_type /= dof1_type) cycle dof2_a
1242 
1243  ! dof1 == dof2 : dof1 is not a new dof
1244  doftab(1:2, dof_cpt) = (/ cl2, dof2 /)
1245  cycle dof_loop
1246 
1247  end do dof2_a
1248 
1249  end do ngb_cl_a
1250 10 continue
1251  ! new dof
1252  x_h%dof_count(cell_vtx) = x_h%dof_count(cell_vtx) + 1
1253  doftab(3, dof_cpt) = dof1_type
1254 
1255  case(cell_edg) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1256 
1257  !! vertex local index in cl1
1258  !!
1259  dof1_vtx(1:2) = fe_dof_vtx( 1:2, dof1, ft1)
1260 
1261  !! barycentric coord
1262  !!
1263  dof1_bary(1:2) = fe_dof_bary(1:2, dof1, ft1)
1264 
1265  !! dof1_cl(:) = cells associated with dof1
1266  !! with index < cl1
1267  !!
1268  !! vtx 1
1269  ii = dof1_vtx(1)
1270  jj = dof1_vtx(2)
1271 
1272  ll = vtx_nbcl(ii)
1273  if (ll==0) goto 20 ! new dof
1274 
1275  nn = vtx_nbcl(jj)
1276  if (nn==0) goto 20 ! new dof
1277 
1278  call cap_sorted_set(dof1_nbcl, dof1_cl, wdt, &
1279  & vtx_tocl( 1: ll, ii), ll, &
1280  & vtx_tocl( 1: nn, jj), nn)
1281 
1282  if (dof1_nbcl==0) goto 20 ! new dof
1283 
1284 
1285  !! dof1_vtx_g(1:2) = vtx associated with dof1
1286  !! global indexes in the mesh
1287  !! these indexes are sorted
1288  !!
1289  dof1_vtx_g(1:2) = cl1_vtx( dof1_vtx(1:2) )
1290  sort1(1:2) = dof1_vtx_g(1:2)
1291  call order_2(sort1(1:2))
1292 
1293  !! Search if dof1 also is a dof of a cell
1294  !! in dof1_cl( 1: dof1_nbCl)
1295  !!
1296  dof1_type = fe_dof_type(dof1, ft1)
1297 
1298  ngb_cl_b: do cl2_ind=1, dof1_nbcl
1299 
1300  cl2 = dof1_cl(cl2_ind)
1301  ft2 = x_h%feType(cl2)
1302  if ( ft2 == fe_none ) cycle ngb_cl_b
1303 
1304  !! cl2_nbNd = number of nodes of cell cl2
1305  !! cl2_nd(:) = nodes of cell cl2 (global indexzs)
1306  !!
1307  call getrow(cl2_nbnd, cl2_nd, &
1308  & cell_max_nbnodes, m%clToNd, cl2)
1309 
1310  !! Loop on the dof of cl2
1311  !!
1312  dof2_b: do dof2=1, fe_nbdof(ft2)
1313 
1314  dof2_geo = fe_dof_geo(dof2, ft2)
1315  if ( dof2_geo /= dof1_geo) cycle dof2_b
1316 
1317  !! dof2_vtx(1:2) = vtx associated with dof2
1318  !! (local indexes in cl2)
1319  !!
1320  dof2_vtx(1:2) = fe_dof_vtx( 1:2, dof2, ft2)
1321 
1322  !! dof2_vtx_g(1) = vtx associated with dof1
1323  !! global indexes in mesh
1324  dof2_vtx_g(1:2) = cl2_nd( dof2_vtx(1:2) )
1325  sort2(1:2) = dof2_vtx_g(1:2)
1326  call order_2(sort2(1:2) )
1327 
1328  !! We verify if dof1 and dof2 are associated with
1329  !! the same vertexes in the mesh
1330  !!
1331  bool = all( sort1(1:2) == sort2(1:2) )
1332 
1333  if ( .NOT. bool ) cycle dof2_b
1334 
1335  !! Verify barycentric coordinates equality
1336  !!
1337  dof2_bary(1:2) = fe_dof_bary(1:2, dof2, ft2)
1338 
1339  !! permutation between the two vertex
1340  !! triplet
1341  !!
1342  call get_perm_2(p_2, dof1_vtx_g(1:2)&
1343  & , dof2_vtx_g(1:2) )
1344 
1345  !! barycentric coord. equality
1346  !!
1347  bool = equal( dof1_bary(1), dof2_bary( p_2 ) )
1348  if ( .NOT. bool ) cycle dof2_b
1349 
1350  !! dof type comparison
1351  !!
1352  dof2_type = fe_dof_type(dof2, ft2)
1353  if ( dof2_type /= dof1_type) cycle dof2_b
1354 
1355  ! dof1 == dof2 : dof1 is not a new dof
1356  doftab(1:2, dof_cpt) = (/ cl2, dof2 /)
1357  cycle dof_loop
1358 
1359  end do dof2_b
1360 
1361  end do ngb_cl_b
1362 
1363 20 continue
1364 
1365  ! new dof
1366  x_h%dof_count(cell_edg) = x_h%dof_count(cell_edg) + 1
1367  doftab(3, dof_cpt) = dof1_type
1368 
1369  case(cell_trg) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1370 
1371  !! vertex local index in cl1
1372  !!
1373  dof1_vtx(1:3) = fe_dof_vtx( 1:3, dof1, ft1)
1374 
1375  !! barycentric coord
1376  !!
1377  dof1_bary(1:3) = fe_dof_bary(1:3, dof1, ft1)
1378 
1379  !! dof1_cl(:) = cells associated with dof1
1380  !! with index < cl1
1381  !!
1382  !! vtx 1
1383  vtx = dof1_vtx(1)
1384  dof1_nbcl = vtx_nbcl(vtx)
1385  if (dof1_nbcl==0) goto 30 ! new dof
1386 
1387  dof1_cl( 1: dof1_nbcl) = vtx_tocl( 1: dof1_nbcl, vtx)
1388 
1389  !! vtx 2, 3
1390  do ii=2, 3
1391  vtx = dof1_vtx(ii)
1392  jj = vtx_nbcl(vtx)
1393  if (jj==0) goto 30 ! new dof
1394 
1395  call cap_sorted_set(ll, temp, wdt, &
1396  & dof1_cl( 1: dof1_nbcl), dof1_nbcl, &
1397  & vtx_tocl( 1: jj, vtx), jj)
1398 
1399  if (ll==0) goto 30 ! new dof
1400 
1401  dof1_nbcl = ll
1402  dof1_cl( 1: ll) = temp( 1: ll)
1403 
1404  end do
1405 
1406  !! dof1_vtx_g(1:3) = vtx associated with dof1
1407  !! global indexes in the mesh
1408  !! these indexes are sorted
1409  !!
1410  dof1_vtx_g(1:3) = cl1_vtx( dof1_vtx(1:3) )
1411  sort1(1:3) = dof1_vtx_g(1:3)
1412  call sort(sort1(1:3), 3)
1413 
1414  !! Search if dof1 also is a dof of a cell
1415  !! in dof1_cl( 1: dof1_nbCl)
1416  !!
1417  dof1_type = fe_dof_type(dof1, ft1)
1418 
1419  ngb_cl_c: do cl2_ind=1, dof1_nbcl
1420 
1421  cl2 = dof1_cl(cl2_ind)
1422  ft2 = x_h%feType(cl2)
1423  if ( ft2 == fe_none ) cycle ngb_cl_c
1424 
1425  !! cl2_nbNd = number of nodes of cell cl2
1426  !! cl2_nd(:) = nodes of cell cl2 (global indexzs)
1427  !!
1428  call getrow(cl2_nbnd, cl2_nd, &
1429  & cell_max_nbnodes, m%clToNd, cl2)
1430 
1431  !! Loop on the dof of cl2
1432  !!
1433  dof2_c: do dof2=1, fe_nbdof(ft2)
1434 
1435  dof2_geo = fe_dof_geo(dof2, ft2)
1436  if ( dof2_geo /= dof1_geo) cycle dof2_c
1437 
1438  !! dof2_vtx(1:3) = vtx associated with dof2
1439  !! (local indexes in cl2)
1440  !!
1441  dof2_vtx(1:3) = fe_dof_vtx( 1:3, dof2, ft2)
1442 
1443  !! dof2_vtx_g(1) = vtx associated with dof1
1444  !! global indexes in mesh
1445  !! these indexes are sorted
1446  dof2_vtx_g(1:3) = cl2_nd( dof2_vtx(1:3) )
1447  sort2(1:3) = dof2_vtx_g(1:3)
1448  call sort(sort2(1:3), 3)
1449 
1450  !! We verify if dof1 and dof2 are associated with
1451  !! the same vertexes in the mesh
1452  !!
1453  bool = all( sort1(1:3) == sort2(1:3) )
1454  if ( .NOT. bool ) cycle dof2_c
1455 
1456  !! Verify barycentric coordinates equality
1457  !!
1458  dof2_bary(1:3) = fe_dof_bary(1:3, dof2, ft2)
1459 
1460  !! permutation between the two vertex
1461  !! triplet
1462  !!
1463  call get_perm_3(p_3, dof1_vtx_g(1:3) &
1464  & , dof2_vtx_g(1:3) )
1465 
1466  !! barycentric coord. equality
1467  !!
1468  bool = equal( dof1_bary(1), dof2_bary( p_3(1) ) )
1469  bool = bool .AND. &
1470  & equal( dof1_bary(2), dof2_bary( p_3(2) ) )
1471 
1472  if ( .NOT. bool ) cycle dof2_c
1473 
1474  !! dof type comparison
1475  !!
1476  dof2_type = fe_dof_type(dof2, ft2)
1477  if ( dof2_type /= dof1_type) cycle dof2_c
1478 
1479  ! dof1 == dof2 : dof1 is not a new dof
1480  doftab(1:2, dof_cpt) = (/ cl2, dof2 /)
1481  cycle dof_loop
1482 
1483  end do dof2_c
1484 
1485  end do ngb_cl_c
1486 
1487 30 continue
1488  ! new dof
1489  x_h%dof_count(cell_trg) = x_h%dof_count(cell_trg) + 1
1490  doftab(3, dof_cpt) = dof1_type
1491 
1492  case default
1493 
1494  call quit( 'feSpace_mod: scan_dof:&
1495  & cell type not supported')
1496  end select
1497 
1498 
1499  end do dof_loop
1500 
1501  end do
1502  m=>null()
1503  end subroutine scan_dof
1504 
1505 
1506  subroutine build_cltodof(dofTab, cl_row, X_h)
1507  integer, dimension(:,:), intent(inout) :: dofTab
1508  integer, dimension(:) , intent(in) :: cl_row
1509  type(fespace) , intent(inout) :: X_h
1510 
1511  integer :: cpt, ii, jj, cl, dof, fe_typ, j1, j2
1512 
1513  !! counts all new dof
1514  !! give to all new dof an index
1515  !!
1516  cpt = 0
1517  do ii = 1, size( doftab, 2)
1518  if ( doftab(1, ii) == 0 ) then
1519  cpt = cpt + 1
1520  doftab(1, ii) = cpt
1521  end if
1522  end do
1523 
1524  !! Number of DOF
1525  if (cpt/=sum( x_h%dof_count)) call quit( &
1526  & 'feSpace_mod: build_clToDof: 1')
1527  if (cpt == 0 ) call quit( &
1528  & 'feSpace_mod: build_clToDof: 2')
1529  x_h%nbDof = cpt
1530  x_h%clToDof%nc = cpt
1531 
1532  !! DOF types
1533  call allocmem(x_h%dofType, x_h%nbDof)
1534  do ii = 1, size( doftab, 2)
1535  if ( doftab(2, ii) == 0 ) then
1536  dof = doftab(1, ii)
1537  x_h%dofType(dof) = doftab(3, ii)
1538  end if
1539  end do
1540 
1541  !! finds the new dof equal to a local dof
1542  !! when it is not a new dof
1543  !!
1544  do ii = 1, size( doftab, 2)
1545 
1546  if ( doftab(2, ii) == 0 ) cycle
1547 
1548  jj = ii
1549  do while( doftab(2, jj) /= 0 )
1550 
1551  cl = doftab(1, jj)
1552  dof = doftab(2, jj)
1553 
1554  jj = cl_row( cl ) + dof
1555 
1556  end do
1557  doftab(1, ii) = doftab(1, jj)
1558 
1559  end do
1560 
1561  !! Fills in the cell to dof graph
1562  !!
1563  do cl = 1, x_h%mesh%nbCl
1564  fe_typ = x_h%feType(cl)
1565 
1566  if (fe_typ==0) cycle
1567 
1568  jj = fe_nbdof( fe_typ )
1569 
1570  j1 = cl_row(cl) + 1
1571  j2 = cl_row(cl) + jj
1572 
1573  call setrow(x_h%clToDof, doftab(1, j1:j2), jj, cl)
1574 
1575  end do
1576 
1577  end subroutine build_cltodof
1578 
1585  subroutine get_perm_3(p, t1, t2)
1586  integer, dimension(2), intent(out) :: p
1587  integer, dimension(3), intent(in) :: t1, t2
1588 
1589  if (t1(1)==t2(1)) then
1590  p(1) = 1
1591  if (t1(2)==t2(2)) then
1592  p(2) = 2
1593  else
1594  p(2) = 3
1595  end if
1596 
1597  else if (t1(1)==t2(2)) then
1598  p(1) = 2
1599  if (t1(2)==t2(1)) then
1600  p(2) = 1
1601  else
1602  p(2) = 3
1603  end if
1604 
1605  else
1606  p(1) = 3
1607  if (t1(2)==t2(2)) then
1608  p(2) = 2
1609  else
1610  p(2) = 1
1611  end if
1612 
1613  end if
1614 
1615  end subroutine get_perm_3
1616 
1623  subroutine get_perm_2(p, t1, t2)
1624  integer, intent(out) :: p
1625  integer, dimension(2), intent(in) :: t1, t2
1626 
1627  if (t1(1)==t2(1)) then
1628  p = 1
1629 
1630  else
1631  p = 2
1632 
1633  end if
1634 
1635  end subroutine get_perm_2
1636 
1640  subroutine interp_scal_func(uh, u, X_h)
1641  real(RP), dimension(:), allocatable :: uh
1642  type(fespace) , intent(in) :: X_h
1643  procedure(r3tor) :: u
1644 
1645  integer :: ii
1646 
1647  if (choral_verb>1) write(*,*) &
1648  & "feSpace_mod : interp_scal_func"
1649 
1650  if (.NOT.valid(x_h)) call quit(&
1651  & "feSpace_mod: interp_scal_func:&
1652  & fe space 'X_h' not valid" )
1653 
1654  call allocmem(uh, x_h%nbDof)
1655 
1656  do ii=1, x_h%nbDof
1657  select case (x_h%dofType(ii))
1658  case(fe_dof_lag)
1659  uh(ii) = u(x_h%dofCoord(:,ii))
1660  case default
1661  call quit("feSpace_mod: interp_scal_func:&
1662  & DOF type not supported" )
1663  end select
1664  end do
1665 
1666  end subroutine interp_scal_func
1667 
1668 
1669 
1674  subroutine fespace_interp_vect_func(phi_h, phi, X_h)
1675  real(RP), dimension(:), allocatable :: phi_h
1676  type(fespace) , intent(in) :: X_h
1677  procedure(r3tor3) :: phi
1678 
1679  type(mesh), pointer :: m
1680  integer :: dim, nbDof, ft, nbItf
1681 
1682  if (choral_verb>1) write(*,*) &
1683  & "feSpace_mod : interp_vect_func"
1684 
1685  m=>x_h%mesh
1686 
1687  if (m%nbItf<=0) call quit("feSpace_mod:&
1688  & feSpace_interp_vect_func: mesh interfaces not defined" )
1689 
1690  call allocmem(phi_h, x_h%nbDof)
1691  phi_h = 0._rp
1692 
1693  do ft=1, fe_tot_nb
1694  if (x_h%fe_count(ft)==0) cycle
1695 
1696  dim = fe_dim(ft) ! dimension of K_ref
1697  nbdof = fe_nbdof(ft) ! fe number of DOF
1698  nbitf = cell_nbitf( fe_geo( ft) ) ! interface number
1699 
1700  call cell_loop()
1701 
1702  end do
1703 
1704  contains
1705 
1706  subroutine cell_loop()
1708  integer , dimension(nbDof) :: p
1709  integer , dimension(CELL_MAX_NBNODES) :: p_cl
1710  real(RP), dimension(3, CELL_MAX_NBNODES) :: X
1711  real(RP), dimension(nbDof) :: val
1712  integer , dimension(CELL_MAX_NBITF) :: eps
1713 
1714  real(RP), dimension(3) :: vec
1715  type(geotsf):: g
1716  integer :: cl, ii, jj, cl_nd, nb_itf
1717  real(RP) :: msK
1718 
1719  real(RP), dimension(3,nbItf) :: nf
1720  real(RP), dimension(nbItf) :: msf
1721 
1722 
1723  !! geometricat transformation K_ref --> K
1724  !
1725  g = geotsf(dim, nbdof, fe_dof_coord(ft)%y )
1726 
1727  !! CELL LOOP
1728  !!
1729  do cl=1, m%nbCl
1730 
1731  ii = x_h%feType(cl)
1732  if (ii/=ft) cycle
1733 
1734  ! cell node coordinates
1735  call getrow(cl_nd, p_cl, cell_max_nbnodes, m%clToNd, cl)
1736  do ii=1, cl_nd
1737  x(1:3,ii) = m%nd( 1:3, p_cl(ii) )
1738  end do
1739 
1740  ! transformation T : K_ref --> K = T(K_ref)
1741  call assemble(g, m%clType(cl), x(1:3, 1:cl_nd), cl_nd)
1742 
1743  ! unit normals and measures of the cell interfaces
1744  call cell_ms_itf_n(msk, nf, msf, nbitf, g)
1745 
1746 #if DBG>0
1747  !!
1748  !! checks the cell orientation
1749  if (.NOT.cell_orientation(m, cl)) call quit(&
1750  & "feSpace_mod: feSpace_interp_vect_func:&
1751  & cell orientation incorrect" )
1752 #endif
1753  !!
1754  !! orientation of the interfaces of cell cl
1755  call interface_orientation(nb_itf, &
1756  & eps, cell_max_nbitf, m, cl)
1757 
1758  select case(ft)
1759 
1760  case(fe_rt0_1d, fe_rt0_2d)
1761 
1762  ! local dof :
1763  do ii=1, nbdof
1764  val(ii) = sum( nf(:,ii) * phi(g%Ty(:,ii)) )
1765  val(ii) = val(ii) * msf(ii)
1766 
1767  if (eps(ii)==1) cycle
1768  val(ii) = - val(ii)
1769  end do
1770 
1771  case(fe_rt1_1d)
1772 
1773  ! local dof :
1774  do ii=1, 2
1775  val(ii) = sum( nf(:,ii) * phi(g%Ty(:,ii)) )
1776  val(ii) = val(ii) * msf(ii)
1777 
1778  if (eps(ii)==1) cycle
1779  val(ii) = - val(ii)
1780  end do
1781 
1782  vec = phi(g%Ty(:,3))
1783  val(3) = vec(1)
1784 
1785  case(fe_rt1_2d_2)
1786 
1787  ! local dof :
1788  do ii=1, 3
1789  jj = 2*ii - 1
1790 
1791  val(jj) = sum( nf(:,ii) * phi(g%Ty(:,jj)) )
1792  val(jj) = val(jj) * msf(ii)
1793 
1794  jj = jj + 1
1795  val(jj) = sum( nf(:,ii) * phi(g%Ty(:,jj)) )
1796  val(jj) = val(jj) * msf(ii)
1797 
1798  if ( eps(ii) == 1 ) cycle
1799  val(jj-1:jj) = -val(jj-1:jj)
1800 
1801  end do
1802 
1803  vec = phi(g%Ty(:,7)) * 2.0_rp * msk
1804  val(7) = sum( vec * nf(:,3) )
1805  val(8) = sum( vec * nf(:,1) )
1806 
1807  vec = x(:,2) - x(:,1) ! AB
1808  val(7) = val(7) / sum( vec * nf(:,3) )
1809 
1810  vec = x(:,3) - x(:,1) ! AC
1811  val(8) = val(8) / sum( vec * nf(:,1) )
1812 
1813  case default
1814  call quit("feSpace_mod: feSpace_interp_vect_func:&
1815  & fe type not supported")
1816 
1817  end select
1818 
1819  ! global dof indexes
1820  call getrow(p, nbdof, x_h%clTodof, cl)
1821  phi_h(p) = val
1822 
1823  end do
1824 
1825  end subroutine cell_loop
1826 
1827  end subroutine fespace_interp_vect_func
1828 
1829 
1839  subroutine flag_x_h_dof(dof_flag, X_h, dim, f)
1840  logical, dimension(:), allocatable :: dof_flag
1841  type(fespace) , intent(in) :: X_h
1842  integer , intent(in) :: dim
1843  procedure(r3tor) , optional :: f
1844 
1845  logical , dimension(:), allocatable :: flag
1846 
1847  integer, dimension(FE_MAX_NBDOF) :: dof_tab
1848  integer :: ii, jj, nb_dof
1849 
1850  if (choral_verb>1) write(*,*) &
1851  & "feSpace_mod : flag_X_h_dof"
1852 
1853  if (.NOT.valid(x_h)) call quit('feSpace_mod:&
1854  & flag_X_h_dof: X_h not valid')
1855 
1856  call flag_mesh_cells(flag, x_h%mesh, dim, f)
1857 
1858  call allocmem(dof_flag, x_h%nbDof)
1859  dof_flag = .false.
1860  do ii=1, x_h%mesh%nbCl
1861 
1862  !! cell ii is not a boundary cell so that f >=0
1863  if (.NOT.flag(ii)) cycle
1864 
1865  !! flag all finite element nodes linked to cell cl
1866  call getrow(nb_dof, dof_tab, fe_max_nbdof, x_h%clToDof, ii)
1867  do jj=1, nb_dof
1868  dof_flag( dof_tab(jj) ) = .true.
1869  end do
1870 
1871  end do
1872 
1873  end subroutine flag_x_h_dof
1874 
1875 end module fespace_mod
set a graph row
Definition: graph_mod.F90:144
DERIVED TYPE geoTsf: geometrical transformation of reference cells
Definition: geoTsf_mod.F90:92
integer, parameter fe_rt0_2d
integer, dimension(fe_tot_nb), public fe_dim
Reference cell dimension for each fe method.
Definition: fe_mod.F90:74
subroutine get_perm_3(p, t1, t2)
t2 is a permutation of t1
Derived type mesh.
Definition: mesh_mod.F90:92
subroutine fespace_clear(X_h)
Destructor for feSpace type.
subroutine scan_dof(dofTab, X_h, wdt)
Checks every local dof to say wether it is equal to dof &#39;dof2&#39; of cell &#39;cl2&#39; for cl2 < cell...
DEFINITION OF ABSTRACT_INTERFACES FOR THE LIBRARY CHORAL
type(r_2d), dimension(fe_tot_nb), public fe_dof_coord
DOF node coordinates.
Definition: fe_mod.F90:125
integer, dimension(fe_max_nbdof, fe_tot_nb), public fe_dof_geo
FE_DOF_GEO(i, j) = Geometric type of DOF i of the FE method j.
Definition: fe_mod.F90:78
DERIVED TYPE graph: sparse matrices of boolean in CSR format
Definition: graph_mod.F90:33
print a short description
subroutine loop()
integer, parameter cell_tot_nb
Number of CELL types.
integer, parameter cell_tet
Tetrahedron.
subroutine initialise_doftab(dofTab, cl_row, X_h)
BASIC TOOLS
Definition: basic_tools.F90:8
subroutine, public eval_scal_fe_at_points(val, P, u, X_h)
u is a finite element function on the finite element space X_h
deallocate memory for real(RP) arrays
Definition: real_type.F90:163
integer, dimension(cell_tot_nb), public cell_nbvtx
Number of vertexes for each cell type.
Definition: cell_mod.f90:118
subroutine fespace_write(X_h, fileName, fileFormat)
Write feSpace to file &#39;fileName&#39; with format &#39;fileFormat&#39;.
subroutine get_perm_2(p, t1, t2)
t2 is a permutation of t1
subroutine x_h_dofcoord(X_h)
integer, parameter fe_p2_2d
subroutine dof_loop()
subroutine, public interp_scal_fe(u2, X_h2, u1, X_h1)
Interpolate a scalar finite element function u1 on a second finite element space X_h2.
QUADRATURE RULES ON REFERENCE CELLS
Definition: quad_mod.f90:31
subroutine, public flag_x_h_dof(dof_flag, X_h, dim, f)
OUTPUT: flag(:) array of logical with size X_hnbDof.
DEFINITION OF FINITE ELEMENT METHODS
Definition: fe_mod.F90:19
logical function, public belongstocell(x, Y, n, ct)
Tests if the node x belongs to the cell with node coordinates Y and of type ct.
Definition: geoTsf_mod.F90:603
subroutine, public graph_prod(g, A, B)
Matrix product g = A*B.
Definition: graph_mod.F90:679
subroutine, public quit(message)
Stop program execution, display an error messahe.
integer, parameter fe_p1_2d_disc_ortho
integer, dimension(cell_tot_nb), public cell_geo
Associated reference cell for each cell type.
Definition: cell_mod.f90:133
subroutine, public flag_mesh_cells(flag, m, dim, f)
OUTPUT: flag(:) array of logical with size mnbCl.
Definition: mesh_mod.F90:622
Test real equality.
Definition: real_type.F90:146
integer, parameter fe_rt1_2d_2
integer, parameter cell_edg
Edge (line segment)
integer, parameter fe_tot_nb
Number of FE methods.
subroutine fespace_assemble(X_h)
sets cell dof local indexing –> global dof indexing connectivity
subroutine, public interface_orientation(nb_itf, eps, n, m, cl)
eps(ii) = +1 if the interface ii of the cell cl in mesh m is oriented outwards the cell cl = -1 other...
Definition: mesh_mod.F90:824
conversion integers or rational to real
Definition: real_type.F90:153
subroutine fespace_interp_vect_func(phi_h, phi, X_h)
Interp : vector function case.
integer, parameter fe_max_nbdof
Maximum number of dof for an element.
REAL NUMBERS PRECISION IN CHORAL: selects simple/double/quad
Definition: real_type.F90:33
integer, parameter fe_p2_3d
Geometrical transformation .
Definition: geoTsf_mod.F90:130
subroutine, public cell_ms_itf_n(ms, n, itf_ms, nbItf, g)
INPUT :: g = geoTsf, must have been set nbItf = number of interfaces OUTPUT : ms = measure of T(K_ref...
Definition: geoTsf_mod.F90:749
logical function fespace_valid(X_h)
Check if the structure content is correct.
integer function closest_cell(x, X_h)
finds the cell in X_h with non void feType the closest from node x
DERIVED TYPE feSpace: finite element spaces
Definition: feSpace_mod.F90:58
integer, parameter fe_p3_1d
integer, parameter cell_trg
Triangle.
integer, dimension(fe_tot_nb), public fe_nbdof
Number of DOF for each fe method.
Definition: fe_mod.F90:68
subroutine build_cltodof(dofTab, cl_row, X_h)
integer, dimension(cell_tot_nb), public cell_nbitf
Number of interfaces for each cell type.
Definition: cell_mod.f90:127
CHORAL CONSTANTS
type(fespace) function fespace_create(m)
Constructor for the type feSpace
ALGEBRAIC OPERATIONS ON SETS
Definition: algebra_set.F90:14
subroutine fespace_print(X_h)
Print a short description.
integer, parameter, public cell_max_nbitf
Cell maximal number of interfaces.
subroutine, public getndcoord(ndCoord, s, ndInd, n, m)
returns node coordinates of node indexes in ndInd
Definition: mesh_mod.F90:599
subroutine, public union(sz, tab, bf1, n, bf2, p, g, rows, m)
graph row union
Definition: graph_mod.F90:558
DERIVED TYPE mesh
Definition: mesh_mod.F90:57
integer, parameter fe_p1_2d
subroutine fespace_set(X_h, ft)
Apply the finite element method &#39;ft&#39; to all cells with comptible geometry.
allocate memory for real(RP) arrays
Definition: real_type.F90:158
Derived type feSpace: finite element space on a mesh.
subroutine, public geotsf_t_inv(z, X, Y, n, ct)
x = 3D node 3D cell of type ct with nodes = A, B, C, ... given by Y(:,1)=A, Y(:,2)=B, ..., Y(:,n)
Definition: geoTsf_mod.F90:683
subroutine, public order_2(t)
order an array of size 2
character(len=4), dimension(cell_tot_nb), public cell_name
CELL_ARRAY Arrays describing cells.
Definition: cell_mod.f90:112
integer choral_verb
Verbosity level.
integer, dimension(cell_max_nbvtx, fe_max_nbdof, fe_tot_nb), public fe_dof_vtx
FE_DOF_VTX(1:n,i,j) = for the DOF i of the FE method j :
Definition: fe_mod.F90:112
subroutine locate_nodes(T, P, X_h, ndToNd)
Locate each point P(:,i) inside a cell of X_hmesh associated to a non void finite element...
integer, parameter fe_dof_lag
Nodal value (Lagrangian DOF, scalar finite element)
subroutine, public interp_scal_func(uh, u, X_h)
Interpolation of a scalar function to a scalar finite element function.
integer, dimension(fe_tot_nb), public fe_geo
Reference cell geometry for each fe method.
Definition: fe_mod.F90:71
character(len=16), dimension(0:fe_tot_nb), public fe_name
Name for each fe method.
Definition: fe_mod.F90:65
integer, parameter fe_rt1_1d
subroutine, public sort(t, n)
Sorts the array t of length N in ascending order by the straight insertion method.
subroutine, public closest_node(V, dist, pt, m, nDToNd, start)
For each point X=pt(:,ii), determines a node V in the mesh m that minimises |X-V|.
Definition: mesh_mod.F90:698
DEFINITION OF GLOBAL VARIABLES FOR THE LIBRARY CHORAL
integer, parameter fe_none
subroutine cell_loop()
Definition: diffusion.F90:232
integer, parameter cell_vtx
Vertex.
real(rp), dimension(cell_max_nbvtx, fe_max_nbdof, fe_tot_nb), public fe_dof_bary
FE_DOF_BARY(1:n,i,j) = for the DOF i of the FE method j :
Definition: fe_mod.F90:121
subroutine, public cap_sorted_set(cpt, t, n, t1, n1, t2, n2)
t(1:cpt) = t1(1:n1) \cap t2(1:n2)
integer, parameter fe_p3_2d
integer, dimension(fe_max_nbdof, fe_tot_nb), public fe_dof_type
FE_DOF_TYPE(i,j) = dof type of the DOF i of the FE method j (Lagrange, ...)
Definition: fe_mod.F90:82
subroutine gmsh_write(X_h, fileName)
Write feSpace m to file &#39;fileName&#39; gmsh ASCII format.
integer, parameter fe_p1_3d
integer, parameter fe_p1_1d
logical function, public cell_orientation(m, cl)
has cell &#39;cl&#39; the direct orientation ?
Definition: mesh_mod.F90:777
The type graph stores sparse matrices of boolean in CSR format.
Definition: graph_mod.F90:78
DEFINITION OF GEOMETRICAL CELLS (for meshes)
Definition: cell_mod.f90:82
integer, parameter fe_rt0_1d
integer, parameter fe_p2_1d
subroutine, public scal_fe(val, nbDof, x, dim, ft)
Evaluate FE basis functions at point x.
Definition: fe_mod.F90:136
write a finite element space to a file
extract a graph row
Definition: graph_mod.F90:149
subroutine, public gmsh_addview(X_h, v, fileName, vname, time, idx)
add a view to X_h output file gmesh file format
integer, parameter, public cell_max_nbnodes
Cell maximal number of nodes.