!
!     CalculiX - A 3-dimensional finite element program
!              Copyright (C) 1998-2005 Guido Dhondt
!
!     This program is free software; you can redistribute it and/or
!     modify it under the terms of the GNU General Public License as
!     published by the Free Software Foundation(version 2);
!     
!
!     This program is distributed in the hope that it will be useful,
!     but WITHOUT ANY WARRANTY; without even the implied warranty of 
!     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
!     GNU General Public License for more details.
!
!     You should have received a copy of the GNU General Public License
!     along with this program; if not, write to the Free Software
!     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
!
      subroutine gen3dnor(nk,nk_,co,iponoel,inoel,iponoelmax,kon,ipkon,
     &  lakon,ne,thicke,offset,iponor,xnor,knor,rig,iperturb,tinc,
     &  tper,tmin,tmax,ctrl,ipompc,nodempc,coefmpc,nmpc,nmpc_,mpcfree,
     &  ikmpc,ilmpc,labmpc,ikboun,ilboun,nboun,nboun_,nodeboun,ndirboun,
     &  xboun,iamboun,typeboun,nam,ntrans,inotr,trab,ikfree,ixfree,
     &  nmethod)
!
!     calculates normals on 1-D and 2-D elements
!
      implicit none
!
      character*1 type,typeboun(*)
      character*8 lakon(*)
      character*20 labmpc(*)
!
      integer nk,nk_,iponoel(*),inoel(3,*),iponoelmax,kon(*),ipkon(*),
     &  ne,iponor(2,*),knor(*),rig(*),iperturb,ipompc(*),nodempc(3,*),
     &  nmpc,nmpc_,mpcfree,ikmpc(*),ilmpc(*),ikboun(*),ilboun(*),nboun,
     &  nboun_,nodeboun(*),ndirboun(*),iamboun(*),nam,ntrans,inotr(2,*)
!
      integer i,ndepnodes,index,nexp,nnor,nel,ielem,indexe,j,iel(100),
     &  jl(100),ial(100),ifi(100),idepnodes(80),indexx,k,l,ifix,nemin,
     &  jact,ixfree,ikfree,node,nelshell,irefnode,idof,id,mpcfreeold,
     &  irotnode,imax,iamplitude,nmethod
!
      real*8 co(3,*),thicke(2,*),offset(2,*),xnor(*),tinc,tper,tmin,
     &  tmax,ctrl(26),coefmpc(*),xboun(*),trab(7,*) 
!
      real*8 xno(3,100),xta(3,100),xn1(3,100),thl1(100),thl2(100),
     &  off1(100),off2(100),xi,et,coloc6(2,6),coloc8(2,8),xl(3,8),
     &  dd,xnoref(3),dot,coloc3(3),dot1,dot2,dmax,val
!
      data coloc3 /-1.d0,0.d0,1.d0/
      data coloc6 /0.d0,0.d0,1.d0,0.d0,0.d0,1.d0,0.5d0,0.d0,
     &             0.5d0,0.5d0,0.d0,0.5d0/
      data coloc8 /-1.d0,-1.d0,1.d0,-1.d0,1.d0,1.d0,-1.d0,1.d0,
     &            0.d0,-1.d0,1.d0,0.d0,0.d0,1.d0,-1.d0,0.d0/
!
!     calculating the normals in nodes belonging to shells/beams
!
      do i=1,nk
c         if(i.eq.1015) then
c            ndepnodes=0
c         endif
         ndepnodes=0
         index=iponoel(i)
         if(index.eq.0) cycle
!
!           nexp indicates how many times the node was expanded
!
         nexp=0
!
!           nnor indicates whether the expanded nodes lie on a point
!           (nnor=0, only for plane stress, plane strain or axisymmetric
!           elements), on a line (nnor=1) or in a plane (nnor=2)
!
         nnor=0
!
!          locating the shell elements to which node i belongs
!
         nel=0
         do
            if(index.eq.0) exit
            ielem=inoel(1,index)
            if(lakon(ielem)(1:1).ne.'B') then
               if(lakon(ielem)(1:1).eq.'S') nnor=1
               indexe=ipkon(ielem)
               nel=nel+1
               if(nel.gt.100) then
                  write(*,*) '*ERROR in gen3dnor: more than 100'
                  write(*,*) '       shell elements share the'
                  write(*,*) '       same node'
                  stop
               endif
               j=inoel(2,index)
               jl(nel)=j
               iel(nel)=ielem
               thl1(nel)=thicke(1,indexe+j)
               off1(nel)=offset(1,ielem)
            endif
            index=inoel(3,index)
         enddo
!
         if(nel.gt.0) then
            do j=1,nel
               ial(j)=0
            enddo
!
!        estimate the normal
!
            do j=1,nel
               indexe=ipkon(iel(j))
               indexx=iponor(1,indexe+jl(j))
               if(indexx.ge.0) then
                  do k=1,3
                     xno(k,j)=xnor(indexx+k)
                  enddo
                  ifi(j)=1
                  cycle
               else
                  ifi(j)=0
               endif
               if((lakon(iel(j))(2:2).eq.'6').or.
     &              (lakon(iel(j))(4:4).eq.'6')) then
                  xi=coloc6(1,jl(j))
                  et=coloc6(2,jl(j))
                  do k=1,6
                     node=kon(indexe+k)
                     do l=1,3
                        xl(l,k)=co(l,node)
                     enddo
                  enddo
                  call norshell6(xi,et,xl,xno(1,j))
               else
                  xi=coloc8(1,jl(j))
                  et=coloc8(2,jl(j))
                  do k=1,8
                     node=kon(indexe+k)
                     do l=1,3
                        xl(l,k)=co(l,node)
                     enddo
                  enddo
                  call norshell8(xi,et,xl,xno(1,j))
               endif
               dd=dsqrt(xno(1,j)**2+xno(2,j)**2+xno(3,j)**2)
               if(dd.lt.1.d-10) then
                  write(*,*) '*ERROR in gen3dnor: size of estimated'
                  write(*,*)'    shell normal is smaller than 1.e-10'
                  stop
               endif
               do k=1,3
                  xno(k,j)=xno(k,j)/dd
               enddo
            enddo
!
            do
!
!           determining a fixed normal which was not treated yet,
!           or, if none is left, the minimum element number of all
!           elements containing node i and for which no normal was
!           determined yet
!
               ifix=0
               nemin=ne+1
               do j=1,nel
                  if(ial(j).ne.0) cycle
                  if(ifi(j).eq.1) then
                     jact=j
                     ifix=1
                     exit
                  endif
               enddo
               if(ifix.eq.0) then
                  do j=1,nel
                     if(ial(j).eq.0) then
                        if(iel(j).lt.nemin) then
                           nemin=iel(j)
                           jact=j
                        endif
                     endif
                  enddo
                  if(nemin.eq.ne+1) exit
               endif
!
               do j=1,3
                  xnoref(j)=xno(j,jact)
               enddo
!
!           determining all elements whose normal in node i makes an
!           angle smaller than 0.5 or 20 degrees with the reference normal,
!           depending whether the reference normal was given by the
!           user or is being calculated; the thickness and offset must
!           also fit.
!
               do j=1,nel
                  if(ial(j).eq.2) cycle
                  if(j.eq.jact) then
                     ial(jact)=1
                  else
                     dot=xno(1,j)*xnoref(1)+xno(2,j)*xnoref(2)+
     &                    xno(3,j)*xnoref(3)
                     if(ifix.eq.0) then
                        if(dot.gt.0.939693d0)then
                           if((dabs(thl1(j)-thl1(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(off1(j)-off1(jact)).lt.1.d-10)
     &                          .and.
     &                          (lakon(iel(j)).eq.lakon(iel(jact)))
     &                          .or.
     &                          ((lakon(iel(j))(1:1).eq.'S').and.
     &                           (lakon(iel(jact))(1:1).eq.'S')))
     &                          ial(j)=1
                        else
                           if((lakon(iel(j))(1:1).eq.'S').and.
     &                          (lakon(iel(jact))(1:1).eq.'S')) then
c                                 nnor=2
!
!                                if the normals have the opposite
!                                direction, the expanded nodes are on a
!                                straight line
!
                              if(dot.gt.-0.999962) then
                                 nnor=2
                              else
                                 write(*,*) '*INFO in gen3dnor: in some 
     & nodes opposite normals are defined'
                              endif
                           endif
                        endif
                     else
                        if(dot.gt.0.999962d0) then
                           if((dabs(thl1(j)-thl1(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(off1(j)-off1(jact)).lt.1.d-10)
     &                          .and.
     &                          (lakon(iel(j)).eq.lakon(iel(jact)))
     &                          .or.
     &                          ((lakon(iel(j))(1:1).eq.'S').and.
     &                           (lakon(iel(jact))(1:1).eq.'S')))
     &                          ial(j)=1
                        else
                           if((lakon(iel(j))(1:1).eq.'S').and.
     &                          (lakon(iel(jact))(1:1).eq.'S')) then
!
!                                if the normals have the opposite
!                                direction, the expanded nodes are on a
!                                straight line
!
                              if(dot.gt.-0.999962) then
                                 nnor=2
                              else
                                 write(*,*) '*INFO in gen3dnor: in some
     & nodes opposite normals are defined'
                              endif
                           endif
                        endif
                     endif
                  endif
               enddo
!
!           determining the mean normal for the selected elements
!
               if(ifix.eq.0) then
                  do j=1,3
                     xnoref(j)=0.d0
                  enddo
                  do j=1,nel
                     if(ial(j).eq.1) then
                        do k=1,3
                           xnoref(k)=xnoref(k)+xno(k,j)
                        enddo
                     endif
                  enddo
                  dd=dsqrt(xnoref(1)**2+xnoref(2)**2+xnoref(3)**2)
                  if(dd.lt.1.d-10) then
                     write(*,*) '*ERROR in gen3dnor: size of'
                     write(*,*) '        estimated shell normal is'
                     write(*,*) '       smaller than 1.e-10'
                     stop
                  endif
                  do j=1,3
                     xnoref(j)=xnoref(j)/dd
                  enddo
               endif
!
!           updating the pointers iponor
!            
               nexp=nexp+1
               do j=1,nel
                  if(ial(j).eq.1) then
                     ial(j)=2
                     if(ifix.eq.0) then
                        iponor(1,ipkon(iel(j))+jl(j))=ixfree
                     elseif(j.ne.jact) then
                        iponor(1,ipkon(iel(j))+jl(j))=
     &                       iponor(1,ipkon(iel(jact))+jl(jact)) 
                     endif
                     iponor(2,ipkon(iel(j))+jl(j))=ikfree
                  endif
               enddo
!
!           storing the normal in xnor and generating 3 nodes
!           for knor
!     
               if(ifix.eq.0) then
                  do j=1,3
                     xnor(ixfree+j)=xnoref(j)
                  enddo
                  ixfree=ixfree+3
               endif
!
               do k=1,3
                  nk=nk+1
                  if(nk.gt.nk_) then
                     write(*,*) '*ERROR in nodes: increase nk_'
                     stop
                  endif
                  knor(ikfree+k)=nk
!
!                    for plane stress, plane strain and axisymmetric
!                    elements only the middle node is included in the
!                    rigid body definition
! 
                  if((lakon(iel(jact))(2:2).ne.'P').and.
     &                 (lakon(iel(jact))(2:2).ne.'A')) then
                     idepnodes(ndepnodes+1)=nk
                     ndepnodes=ndepnodes+1
                  elseif(k.eq.2) then
c                        if(jl(jact).le.4) then
c                     write(*,*) 'depnode ',nk
                     idepnodes(ndepnodes+1)=nk
                     ndepnodes=ndepnodes+1
c                        endif
                  endif
               enddo
               ikfree=ikfree+3
            enddo
         endif
!
         nelshell=nel+1
!
!        locating the beam elements to which node i belongs
!
         index=iponoel(i)
         do
            if(index.eq.0) exit
            ielem=inoel(1,index)
            if(lakon(ielem)(1:1).eq.'B') then
               indexe=ipkon(ielem)
               nel=nel+1
               if(nel.gt.100) then
                  write(*,*) '*ERROR in gen3dnor: more than 100'
                  write(*,*) '        beam/shell elements share'
                  write(*,*) '        the same node'
                  stop
               endif
               j=inoel(2,index)
               jl(nel)=j
               iel(nel)=ielem
               thl1(nel)=thicke(1,indexe+j)
               thl2(nel)=thicke(2,indexe+j)
               off1(nel)=offset(1,ielem)
               off2(nel)=offset(2,ielem)
            endif
            index=inoel(3,index)
         enddo
!
         if(nel.ge.nelshell) then
            nnor=2
            do j=nelshell,nel
               ial(j)=0
            enddo
!
!           estimate the normal
!
            do j=nelshell,nel
               xi=coloc3(jl(j))
               indexe=ipkon(iel(j))
               do k=1,3
                  node=kon(indexe+k)
                  do l=1,3
                     xl(l,k)=co(l,node)
                  enddo
               enddo
!
!           determining the tangent vector xta
!
               do k=1,3
                  xta(k,j)=(xi-0.5d0)*xl(k,1)-2.d0*xi*xl(k,2)+
     &                 (xi+0.5d0)*xl(k,3)
               enddo
               dd=dsqrt(xta(1,j)**2+xta(2,j)**2+xta(3,j)**2)
               if(dd.lt.1.d-10) then
                  write(*,*) '*ERROR in gen3dnor: size of estimated'
                  write(*,*)'   shell tangent is smaller than 1.e-10'
                  stop
               endif
               do k=1,3
                  xta(k,j)=xta(k,j)/dd
               enddo
!
!           check whether normal was defined with *NORMAL and
!           determine vector n1
!
               if(iponor(1,indexe+jl(j)).ge.0) then
                  indexx=iponor(1,indexe+jl(j))
                  if(dabs(xnor(indexx+4)**2+xnor(indexx+5)**2+
     &                 xnor(indexx+6)**2-1.d0).lt.1.d-5) then
                     do k=1,3
                        xno(k,j)=xnor(indexx+3+k)
                     enddo
                     ifi(j)=1
                     cycle
                  endif
                  do k=1,3
                     xn1(k,j)=xnor(indexx+k)
                  enddo
               else
                  xn1(1,j)=0.d0
                  xn1(2,j)=0.d0
                  xn1(3,j)=-1.d0
               endif
!
!           normal (=n2) = xta x xn1
!
               xno(1,j)=xta(2,j)*xn1(3,j)-xta(3,j)*xn1(2,j)
               xno(2,j)=xta(3,j)*xn1(1,j)-xta(1,j)*xn1(3,j)
               xno(3,j)=xta(1,j)*xn1(2,j)-xta(2,j)*xn1(1,j)
               dd=dsqrt(xno(1,j)**2+xno(2,j)**2+xno(3,j)**2)
               if(dd.lt.1.d-10) then
                  write(*,*) '*ERROR in gen3dnor: size of estimated'
                  write(*,*)'    shell normal is smaller than 1.e-10'
                  stop
               endif
               do k=1,3
                  xno(k,j)=xno(k,j)/dd
               enddo
            enddo
!
            do
!
!           determining a fixed normal which was not treated yet,
!           or, if none is left, the minimum element number of all
!           elements containing node i and for which no normal was
!           determined yet
!
               ifix=0
               nemin=ne+1
               do j=nelshell,nel
                  if(ial(j).ne.0) cycle
                  if(ifi(j).eq.1) then
                     jact=j
                     ifix=1
                     exit
                  endif
               enddo
               if(ifix.eq.0) then
                  do j=nelshell,nel
                     if(ial(j).eq.0) then
                        if(iel(j).lt.nemin) then
                           nemin=iel(j)
                           jact=j
                        endif
                     endif
                  enddo
                  if(nemin.eq.ne+1) exit
               endif
!
!           the reference normal is the one on the element with the
!           smallest element number
!
               do j=1,3
                  xnoref(j)=xno(j,jact)
               enddo
!
!           determining all elements whose normal in node i makes an
!           angle smaller than 0.5 or 20 degrees with the reference normal,
!           depending whether the reference normal was given by the
!           user or is being calculated; the thickness and offset must
!           also fit.
!
               do j=nelshell,nel
                  if(j.eq.jact) then
                     ial(jact)=1
                  else
                     dot1=xno(1,j)*xnoref(1)+xno(2,j)*xnoref(2)+
     &                    xno(3,j)*xnoref(3)
                     dot2=xta(1,j)*xta(1,jact)+xta(2,j)*xta(2,jact)+
     &                    xta(3,j)*xta(3,jact)
                     if(ifix.eq.0) then
                        if((dot1.gt.0.939693d0).and.
     &                       (dot2.gt.0.939693d0)) then
                           if((dabs(thl1(j)-thl1(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(thl2(j)-thl2(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(off1(j)-off1(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(off2(j)-off2(jact)).lt.1.d-10)
     &                          .and.
     &                (lakon(iel(j))(8:8).eq.lakon(iel(jact))(8:8)))
     &                          ial(j)=1
                        endif
                     else
                        if((dot1.gt.0.999962d0).and.
     &                       (dot2.gt.0.999962d0)) then
                           if((dabs(thl1(j)-thl1(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(thl2(j)-thl2(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(off1(j)-off1(jact)).lt.1.d-10)
     &                          .and.
     &                          (dabs(off2(j)-off2(jact)).lt.1.d-10)
     &                          .and.
     &                (lakon(iel(j))(8:8).eq.lakon(iel(jact))(8:8)))
     &                          ial(j)=1
                        endif
                     endif
                  endif
               enddo
!
!           determining the mean normal for the selected elements
!
               if(ifix.eq.0) then
                  do j=1,3
                     xnoref(j)=0.d0
                  enddo
                  do j=nelshell,nel
                     if(ial(j).eq.1) then
                        do k=1,3
                           xnoref(k)=xnoref(k)+xno(k,j)
                        enddo
                     endif
                  enddo
               endif
!
!              calculating the mean tangent
!
               do j=nelshell,nel
                  if((ial(j).eq.1).and.(j.ne.jact)) then
                     do k=1,3
                        xta(k,jact)=xta(k,jact)+xta(k,j)
                     enddo
                  endif
               enddo
               dd=dsqrt(xta(1,jact)**2+xta(2,jact)**2+xta(3,jact)**2)
               if(dd.lt.1.d-10) then
                  write(*,*) '*ERROR in gen3dnor: size of mean'
                  write(*,*)'    beam tangent is smaller than 1.e-10'
                  stop
               endif
               do k=1,3
                  xta(k,jact)=xta(k,jact)/dd
               enddo
!
!              taking care that the mean normal is orthogonal towards
!              the mean tangent
!
               dd=xnoref(1)*xta(1,jact)+xnoref(2)*xta(2,jact)+
     &              xnoref(3)*xta(3,jact)
               do j=1,3
                  xnoref(j)=xnoref(j)-dd*xta(j,jact)
               enddo
               dd=dsqrt(xnoref(1)**2+xnoref(2)**2+xnoref(3)**2)
               if(dd.lt.1.d-10) then
                  write(*,*) '*ERROR in gen3dnor: size of'
                  write(*,*) '        estimated beam normal is'
                  write(*,*) '        smaller than 1.e-10'
                  stop
               endif
               do j=1,3
                  xnoref(j)=xnoref(j)/dd
               enddo
!
!              calculating xn1 = xn2  x tangent              
!
               xn1(1,jact)=xnoref(2)*xta(3,jact)-xnoref(3)*xta(2,jact)
               xn1(2,jact)=xnoref(3)*xta(1,jact)-xnoref(1)*xta(3,jact)
               xn1(3,jact)=xnoref(1)*xta(2,jact)-xnoref(2)*xta(1,jact)
!
!              storing the normals in xnor and generating 8 nodes
!              for knor
!
               nexp=nexp+1
               do j=nelshell,nel
                  if(ial(j).eq.1) then
                     ial(j)=2
                     if(ifix.eq.0) then
                        iponor(1,ipkon(iel(j))+jl(j))=ixfree
                     else
                        iponor(1,ipkon(iel(j))+jl(j))=
     &                       iponor(1,ipkon(iel(jact))+jl(jact))
                     endif
                     iponor(2,ipkon(iel(j))+jl(j))=ikfree
                  endif
               enddo
!
               do j=1,3
                  xnor(ixfree+j)=xn1(j,jact)
               enddo
               do j=1,3
                  xnor(ixfree+3+j)=xnoref(j)
               enddo
               ixfree=ixfree+6
               do k=1,8
                  nk=nk+1
                  if(nk.gt.nk_) then
                     write(*,*) '*ERROR in nodes: increase nk_'
                     stop
                  endif
                  knor(ikfree+k)=nk
                  idepnodes(ndepnodes+k)=nk
               enddo
               ikfree=ikfree+8
               ndepnodes=ndepnodes+8
            enddo
         endif
!
!           check whether the user has specified rotational degrees
!           of freedom; if so, a rigid MPC must be defined
!
         if(rig(i).ne.0) then
c            if(nnor.lt.1) then
               rig(i)=0
c            elseif(nexp.le.1) then
            if(nexp.le.1) then
               nexp=2
            endif
         endif
!
!        storing the expanded nodes
!
c         write(*,*) i,(idepnodes(k),k=1,ndepnodes)
!
!        generate rigid MPC's if necessary
!
         if(nexp.gt.1) then
c            write(*,*) i,'= KNOT !'
            if(iperturb.eq.0) then
               iperturb=2
               tinc=1.d0
               tper=1.d0
               tmin=1.d-5
               tmax=1.d+30
c               ctrl(19)=1.d+30
c               ctrl(20)=1.d+30
            elseif(iperturb.eq.1) then
               write(*,*) '*ERROR in gen3dnor: the expansion of'
               write(*,*) '       1D/2D elements has led to the'
               write(*,*) '       creation of rigid body MPCs.'
               write(*,*) '       This is not allowed in a'
               write(*,*) '       perturbation analysis. Please'
               write(*,*) '       generate a truely 3D structure'
               stop
            endif
            irefnode=i
            if(nnor.eq.0) then
!
!                 the node belongs to plane stress, plane strain
!                 or axisymmetric elements only. These are only linked
!                 through the node in the midplane: the nodes
!                 coincide; only DOF1 and DOF2 are linked.
!                 rig(i)=-1 to indicate that a knot has
!                 been generated without rotational node
!
               rig(i)=-1
!
               do k=1,ndepnodes
                  node=idepnodes(k)
                  do j=1,2
                     idof=7*(node-1)+j
                     call nident(ikmpc,idof,nmpc,id)
                     nmpc=nmpc+1
                     if(nmpc.gt.nmpc_) then
                        write(*,*) 
     &                       '*ERROR in rigidmpc: increase nmpc_'
                        stop
                     endif
!
                     ipompc(nmpc)=mpcfree
                     labmpc(nmpc)='                    '
!
                     do l=nmpc,id+2,-1
                        ikmpc(l)=ikmpc(l-1)
                        ilmpc(l)=ilmpc(l-1)
                     enddo
                     ikmpc(id+1)=idof
                     ilmpc(id+1)=nmpc
!
                     nodempc(1,mpcfree)=node
c                     write(*,*) 'dependent node: ',node
                     nodempc(2,mpcfree)=j
                     coefmpc(mpcfree)=1.d0
                     mpcfree=nodempc(3,mpcfree)
                     nodempc(1,mpcfree)=irefnode
                     nodempc(2,mpcfree)=j
                     coefmpc(mpcfree)=-1.d0
                     mpcfreeold=mpcfree
                     mpcfree=nodempc(3,mpcfree)
                     nodempc(3,mpcfreeold)=0
                  enddo
               enddo
            else
!
!              generate a rigid body knot; rig(i) contains the
!              rotational node of the knot
!
               nk=nk+1
               if(nk.gt.nk_) then
                  write(*,*) '*ERROR in rigidbodies: increase nk_'
                  stop
               endif
               irotnode=nk
               rig(i)=irotnode
               do k=1,ndepnodes
                  call rigidmpc(ipompc,nodempc,coefmpc,irefnode,
     &                 irotnode,
     &                 labmpc,nmpc,nmpc_,mpcfree,ikmpc,ilmpc,nk,nk_,
     &                 nodeboun,ndirboun,ikboun,ilboun,nboun,nboun_,
     &                 idepnodes(k),typeboun)
               enddo
            endif
!
!           MPC's for the temperature DOFs
!
            do k=1,ndepnodes
               node=idepnodes(k)
               idof=7*(node-1)
               call nident(ikmpc,idof,nmpc,id)
               nmpc=nmpc+1
               if(nmpc.gt.nmpc_) then
                  write(*,*) 
     &                 '*ERROR in rigidmpc: increase nmpc_'
                  stop
               endif
!
               ipompc(nmpc)=mpcfree
               labmpc(nmpc)='                    '
!
               do l=nmpc,id+2,-1
                  ikmpc(l)=ikmpc(l-1)
                  ilmpc(l)=ilmpc(l-1)
               enddo
               ikmpc(id+1)=idof
               ilmpc(id+1)=nmpc
!
               nodempc(1,mpcfree)=node
               nodempc(2,mpcfree)=0
               coefmpc(mpcfree)=1.d0
               mpcfree=nodempc(3,mpcfree)
               nodempc(1,mpcfree)=irefnode
               nodempc(2,mpcfree)=0
               coefmpc(mpcfree)=-1.d0
               mpcfreeold=mpcfree
               mpcfree=nodempc(3,mpcfree)
               nodempc(3,mpcfreeold)=0
            enddo
!
            if(nnor.eq.1) then
!
!                 generate an additional SPC or MPC for rigid body nodes
!                 lying on a line to prevent rotation about the
!                 line
!
               dmax=0.d0
               imax=0
               do j=1,3
                  if(dabs(xnoref(j)).gt.dmax) then
                     dmax=dabs(xnoref(j))
                     imax=j
                  endif
               enddo
!
!                 check whether a SPC suffices
!
c                  if(dabs(1.d0-dmax).lt.1.d-5) then
               if(dabs(1.d0-dmax).lt.1.d-3) then
                  write(*,*) 'additional SPC! ',i,irotnode,imax
                  val=0.d0
                  if(nam.gt.0) iamplitude=0
                  type='R'
                  call bounadd(irotnode,imax,imax,val,nodeboun,
     &                 ndirboun,xboun,nboun,nboun_,iamboun,
     &                 iamplitude,nam,ipompc,nodempc,coefmpc,
     &                 nmpc,nmpc_,mpcfree,inotr,trab,ntrans,
     &                 ikboun,ilboun,ikmpc,ilmpc,co,nk,nk_,labmpc,
     &                 type,typeboun,nmethod,iperturb)
               else
!
!                    check whether the rotational degree of freedom
!                    imax is fixed through a SPC
!
                  idof=7*(i-1)+3+imax
                  call nident(ikboun,idof,nboun,id)
                  if((id.gt.0).and.(ikboun(id).eq.idof)) then
!
!                       imax fixed: do not generate MPC
!                        
                  else
                     write(*,*) '*ERROR in gen3dnor: this branch'
                     write(*,*) '       does not work yet: contact'
                     write(*,*) '       the author'
                     idof=0
                     if(idof.eq.0) stop
c
                     idof=7*(irotnode-1)+imax
                     call nident(ikmpc,idof,nmpc,id)
                     nmpc=nmpc+1
                     if(nmpc.gt.nmpc_) then
                        write(*,*) 
     &                       '*ERROR in rigidmpc: increase nmpc_'
                        stop
                     endif
!     
                     ipompc(nmpc)=mpcfree
                     labmpc(nmpc)='                    '
!     
                     do l=nmpc,id+2,-1
                        ikmpc(l)=ikmpc(l-1)
                        ilmpc(l)=ilmpc(l-1)
                     enddo
                     ikmpc(id+1)=idof
                     ilmpc(id+1)=nmpc
!     
                     nodempc(1,mpcfree)=irotnode
                     nodempc(2,mpcfree)=imax
                     coefmpc(mpcfree)=xnoref(imax)
                     mpcfree=nodempc(3,mpcfree)
                     imax=imax+1
                     if(imax.gt.3) imax=imax-3
                     nodempc(1,mpcfree)=irotnode
                     nodempc(2,mpcfree)=imax
                     coefmpc(mpcfree)=xnoref(imax)
                     mpcfree=nodempc(3,mpcfree)
                     imax=imax+1
                     if(imax.gt.3) imax=imax-3
                     nodempc(1,mpcfree)=irotnode
                     nodempc(2,mpcfree)=imax
                     coefmpc(mpcfree)=xnoref(imax)
                     mpcfreeold=mpcfree
                     mpcfree=nodempc(3,mpcfree)
                     nodempc(3,mpcfreeold)=0
                  endif
               endif
            endif
         endif
      enddo
!
      return
      end


