PageRenderTime 62ms CodeModel.GetById 15ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/MultiPhysics/Poroelasticity/FiniteElasticityDarcy/IncompressibleElasticityDrivenMultiCompDarcyIO/input/iostuff.f90

http://github.com/xyan075/examples
FORTRAN Modern | 489 lines | 363 code | 42 blank | 84 comment | 17 complexity | 3d3d15062a5177cd3bf65aa5d0cc056d MD5 | raw file
  1MODULE IOSTUFF
  2  
  3  USE OPENCMISS
  4  IMPLICIT NONE
  5
  6  CONTAINS
  7
  8  ! --------------------------------------------------------------------------------------------------------------
  9  !>Reads in a mesh and returns a mesh object. Basically handles all Basis and Mesh creation calls (comment them out entirely)
 10  SUBROUTINE READ_MESH(Filename,MeshUserNumber,Region, Mesh,Bases,Nodes,Elements)
 11    character(len=*), intent(in) :: Filename
 12    INTEGER(CMISSIntg), intent(in) :: MeshUserNumber
 13    type(CMISSRegionType), intent(in) :: Region
 14    type(CMISSMeshType), intent(inout) :: Mesh
 15    type(CMISSBasisType), allocatable, intent(out) :: Bases(:)
 16    TYPE(CMISSMeshElementsType), allocatable, intent(out) :: Elements(:)
 17    TYPE(CMISSNodesType), intent(out) :: Nodes
 18    !Local variables
 19    INTEGER(CMISSIntg),parameter :: fid=77
 20    character*6, parameter :: MAXFMT='(A255)'
 21    character(len=255) :: word
 22    INTEGER(CMISSIntg) :: NumberOfMeshDimensions,NumberOfMeshComponents
 23    INTEGER(CMISSIntg) :: NumberOfNodes,NumberOfElements,NumberOfBases
 24    INTEGER(CMISSIntg) :: MeshComponentNumber,MyComputationalNode,i,Err
 25    INTEGER(CMISSIntg) :: InterpolationType
 26    INTEGER(CMISSIntg) :: compn,basisn,gaussn, basis_order,el(64),lnn
 27    
 28    CALL CMISSComputationalNodeNumberGet(MyComputationalNode,Err)
 29
 30    ! only if root process
 31    if (MyComputationalNode==0) then
 32      ! open file
 33      open(unit=fid, file=Filename, status='old', action='read', err=998)
 34      CALL CMISSMesh_Initialise(Mesh,Err)
 35
 36      compn=0; basisn=0
 37      ! read header info
 38      do
 39        read(fid,FMT=MAXFMT,end=776) word
 40        ! skip blanks/comments
 41        if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
 42        ! proper keywords start with a #
 43        if (trim(adjustl(word))=="#number_of_mesh_dimensions") then
 44          read(fid,*,end=777,err=999) NumberOfMeshDimensions
 45          CALL CMISSMesh_CreateStart(MeshUserNumber,Region,NumberOfMeshDimensions,Mesh,Err)
 46        elseif (trim(adjustl(word))=="#number_of_mesh_components") then
 47          read(fid,*,end=777,err=999) NumberOfMeshComponents
 48          CALL CMISSMesh_NumberOfComponentsSet(Mesh,NumberOfMeshComponents,Err)
 49          allocate(Elements(NumberOfMeshComponents))
 50        elseif (trim(adjustl(word))=="#number_of_nodes") then
 51          read(fid,*,end=777,err=999) NumberOfNodes
 52          !Define nodes for the mesh
 53          CALL CMISSNodes_Initialise(Nodes,Err)
 54          CALL CMISSNodes_CreateStart(Region,NumberOfNodes,Nodes,Err)
 55          CALL CMISSNodes_CreateFinish(Nodes,Err)  
 56        elseif (trim(adjustl(word))=="#number_of_elements") then
 57          read(fid,*,end=777,err=999) NumberOfElements
 58          CALL CMISSMesh_NumberOfElementsSet(Mesh,NumberOfElements,Err)  
 59        elseif (trim(adjustl(word))=="#number_of_bases") then
 60          read(fid,*,end=777,err=999) NumberOfBases
 61          allocate(Bases(NumberOfBases))
 62        elseif (trim(adjustl(word))=="#mesh_component") then
 63          ! start of a mesh component block
 64          compn=compn+1
 65          if (compn>NumberOfMeshComponents) then
 66            write(*,*) "READ_MESH: incorrect number of mesh components are defined"
 67            close(fid)
 68            return
 69          endif
 70          read(fid,*,end=777,err=999) MeshComponentNumber
 71          do
 72            read(fid,FMT=MAXFMT,end=777,err=999) word
 73            if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
 74            if (trim(adjustl(word))/="#basis_order") then
 75              write(*,*) "READ_MESH: #basis_order must follow the mesh_component definition"
 76              close(fid)
 77              return
 78            endif
 79            exit
 80          enddo
 81          read(fid,*,end=777,err=999) basis_order
 82          ! set up basis: hardcoded for lagrange basis type
 83          basisn=basisn+1
 84          CALL CMISSBasis_Initialise(Bases(basisn),Err)
 85          CALL CMISSBasis_CreateStart(basisn,Bases(basisn),Err) 
 86          CALL CMISSBasis_TypeSet(Bases(basisn),CMISS_BASIS_LAGRANGE_HERMITE_TP_TYPE,Err)
 87          CALL CMISSBasis_NumberOfXiSet(Bases(basisn),NumberOfMeshDimensions,Err)
 88          select case (basis_order)
 89          case (1)
 90            InterpolationType=CMISS_BASIS_LINEAR_LAGRANGE_INTERPOLATION
 91            gaussn=3; lnn=8
 92          case (2)
 93            InterpolationType=CMISS_BASIS_QUADRATIC_LAGRANGE_INTERPOLATION
 94            gaussn=3; lnn=27
 95          case (3)
 96            InterpolationType=CMISS_BASIS_CUBIC_LAGRANGE_INTERPOLATION
 97            gaussn=3; lnn=64
 98          end select
 99          CALL CMISSBasis_InterpolationXiSet(Bases(basisn),[InterpolationType,InterpolationType,InterpolationType],Err)
100          CALL CMISSBasis_QuadratureNumberOfGaussXiSet(Bases(basisn),[gaussn,gaussn,gaussn],Err)  
101          CALL CMISSBasis_QuadratureLocalFaceGaussEvaluateSet(Bases(basisn),.true.,Err)
102          CALL CMISSBasis_CreateFinish(Bases(basisn),Err)
103          ! element definition now
104          do
105            read(fid,FMT=MAXFMT,end=777,err=999) word
106            if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
107            if (trim(adjustl(word))/="#elements") then
108              write(*,*) "READ_MESH: #elements must follow the basis definition"
109              close(fid)
110              return
111            endif
112            exit
113          enddo
114          CALL CMISSMeshElements_Initialise(Elements(compn),Err)
115          CALL CMISSMeshElements_CreateStart(Mesh,compn,Bases(basisn),Elements(compn),Err)
116          do i=1,NumberOfElements
117            read(fid,*,end=777,err=999) el(1:lnn)
118            CALL CMISSMeshElements_NodesSet(Elements(compn),i,el(1:lnn),Err)
119          enddo
120          CALL CMISSMeshElements_CreateFinish(Elements(compn),Err)
121        elseif (trim(adjustl(word))=="#number_of_surfaces") then
122          write(*,*) "READ_MESH: not implemented yet"
123          close(fid)
124          return
125        endif
126      enddo
127    endif
128
129776 CALL CMISSMesh_CreateFinish(Mesh,Err)
130    close(fid)
131    return ! happy return
132777 write(*,*) "READ_MESH: unexpected end of file encountered"
133    close(fid)
134    return
135998 write(*,*) "READ_MESH: could not open file "//Filename
136    close(fid)
137    return
138999 write(*,*) "READ_MESH: error reading line"
139    close(fid)
140    return
141  END SUBROUTINE READ_MESH
142
143  ! --------------------------------------------------------------------------------------------------------------
144
145  SUBROUTINE READ_NODES(Filename,GeometricField)
146    character(len=*), intent(in) :: Filename
147    type(CMISSFieldType), intent(inout) :: GeometricField
148    !Local variables
149    INTEGER(CMISSIntg),parameter :: fid=79
150    character*6, parameter :: MAXFMT='(A255)'
151    character(len=255) :: word
152    INTEGER(CMISSIntg) :: NumberOfNodes,NumberOfCoordinateDimensions
153    INTEGER(CMISSIntg) :: MyComputationalNode,i,j,Err
154    REAL(CMISSDP) :: coord(3)
155
156    ! skipping all dimension, size or otherwise error checks
157
158    CALL CMISSComputationalNodeNumberGet(MyComputationalNode,Err)    
159
160    if (MyComputationalNode==0) then
161      ! open the file
162      open(unit=fid,file=Filename,status='old',action='read',err=998)
163
164      ! read some header info
165      do
166        read(fid,FMT=MAXFMT,end=776,err=999) word
167        ! skip blanks/comments
168        if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
169        if (trim(adjustl(word))=="#number_of_nodes") then
170          read(fid,*,end=777,err=999) NumberOfNodes
171        elseif (trim(adjustl(word))=="#number_of_coordinate_dimensions") then
172          read(fid,*,end=777,err=999) NumberOfCoordinateDimensions
173        elseif (trim(adjustl(word))=="#nodes") then
174          do i=1,NumberOfNodes
175            read(fid,*,err=999) coord(1:NumberOfCoordinateDimensions)
176            do j=1,NumberOfCoordinateDimensions
177            CALL CMISSField_ParameterSetUpdateNode(GeometricField,CMISS_FIELD_U_VARIABLE_TYPE,CMISS_FIELD_VALUES_SET_TYPE,1,1,i,j, &
178              & coord(j),Err)
179            enddo
180          enddo
181          exit
182        endif
183      enddo
184    endif
185
186776 close(fid)
187    return ! happy return
188777 write(*,*) "READ_NODES: unexpected end of file encountered"
189    close(fid)
190    return
191998 write(*,*) "READ_NODES: could not open file "//Filename
192    close(fid)
193    return
194999 write(*,*) "READ_NODES: error reading line"
195    close(fid)
196    return
197  END SUBROUTINE READ_NODES
198
199  ! --------------------------------------------------------------------------------------------------------------
200
201  !>Reads in a field. Only works for a material field currently, all components using same interpolation. handles full field definition code block.
202  SUBROUTINE READ_FIELD(Filename,FieldUserNumber,Region,GeometricField, Field)
203    character(len=*), intent(in) :: Filename
204    INTEGER(CMISSIntg), intent(in) :: FieldUserNumber
205    type(CMISSRegionType), intent(in) :: Region
206    type(CMISSFieldType), intent(in) :: GeometricField
207    type(CMISSFieldType), intent(out) :: Field
208    !Local variables
209    TYPE(CMISSDecompositionType) :: Decomposition
210    INTEGER(CMISSIntg), parameter :: fid=78
211    character*6, parameter :: MAXFMT='(A255)'
212    character(len=255) :: word,field_type,interpolation_type,data_type
213    INTEGER(CMISSIntg) :: NumberOfVariables,NumberOfComponents,num_var,var_idx,var_count
214    INTEGER(CMISSIntg) :: varn,mcompn,VariableType,InterpolationType,DataType
215    INTEGER(CMISSIntg) :: MyComputationalNode,i,ind,Err
216    INTEGER(CMISSIntg) :: data_int(100)
217    REAL(CMISSDP) :: data_dp(100)
218    INTEGER(CMISSIntg), ALLOCATABLE :: VariableTypes(:),DataTypes(:),MeshComponents(:),InterpolationTypes(:), &
219       & VariableNumComponents(:)
220    LOGICAL :: field_set
221
222    CALL CMISSComputationalNodeNumberGet(MyComputationalNode,Err)    
223
224    if (MyComputationalNode==0) then
225      ! Open the file see if everything is fine
226      open(unit=fid,file=Filename,status='old',action='read',err=998)
227
228      ! initial field setup
229!       CALL CMISSField_Initialise(Field,Err)
230!       CALL CMISSField_CreateStart(FieldUserNumber,Region,Field,Err)
231!       ! --- set material type here then do the below ---
232!       CALL CMISSDecomposition_Initialise(Decomposition,Err)
233!       CALL CMISSField_MeshDecompositionGet(GeometricField,Decomposition,Err)
234!       CALL CMISSField_MeshDecompositionSet(Field,Decomposition,Err)
235!       CALL CMISSField_GeometricFieldSet(Field,GeometricField,Err)
236     data_int = 0.0_CMISSIntg
237     data_dp = 0.0_CMISSDP
238     num_var=0_CMISSIntg
239     var_idx=0_CMISSIntg
240     var_count=0_CMISSIntg
241     field_set=.false.
242
243      do
244        read(fid,FMT=MAXFMT,end=776) word
245        write(*,*) word
246        ! skip blanks/comments
247        if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
248        ! proper keywords start with a #
249        if (trim(adjustl(word))=="#field_type") then
250          read(fid,FMT=MAXFMT,end=777) field_type
251          select case (trim(field_type))
252          case ("material")
253            CALL CMISSField_Initialise(Field,Err)
254            CALL CMISSField_CreateStart(FieldUserNumber,Region,Field,Err)
255            CALL CMISSField_TypeSet(Field,CMISS_FIELD_MATERIAL_TYPE,Err)
256            CALL CMISSDecomposition_Initialise(Decomposition,Err)
257            CALL CMISSField_MeshDecompositionGet(GeometricField,Decomposition,Err)
258            CALL CMISSField_MeshDecompositionSet(Field,Decomposition,Err)
259            CALL CMISSField_GeometricFieldSet(Field,GeometricField,Err)
260          case default
261            write(*,*) "READ_FIELD: field types other than material has not been implemented"
262            close(fid)
263            return
264          end select
265        elseif (trim(adjustl(word))=="#number_of_variables") then
266          read(fid,*,end=777) NumberOfVariables
267          CALL CMISSField_NumberOfVariablesSet(Field,NumberOfVariables,Err)
268          write(*,*) NumberOfVariables
269          ALLOCATE(VariableTypes(NumberOfVariables))
270          ALLOCATE(DataTypes(NumberOfVariables))
271          ALLOCATE(MeshComponents(NumberOfVariables))
272          ALLOCATE(InterpolationTypes(NumberOfVariables))
273          ALLOCATE(VariableNumComponents(NumberOfVariables))
274          do
275            read(fid,FMT=MAXFMT,end=776) word
276            write(*,*) word
277          ! skip blanks/comments
278            if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
279            if (trim(adjustl(word))=="#variable") then
280            read(fid,*,end=777) varn
281            num_var=num_var+1
282            select case (varn)
283            case (1)
284              VariableTypes(num_var)=CMISS_FIELD_U_VARIABLE_TYPE
285            case (2)
286              VariableTypes(num_var)=CMISS_FIELD_V_VARIABLE_TYPE
287            case (3)
288              VariableTypes(num_var)=CMISS_FIELD_U1_VARIABLE_TYPE
289            case (4)
290              VariableTypes(num_var)=CMISS_FIELD_U2_VARIABLE_TYPE
291            case default
292              write(*,*) "READ_FIELD: more than 4 variables, take care of it"
293            end select
294            elseif (trim(adjustl(word))=="#number_of_components") then
295              read(fid,*,end=777,err=999) NumberOfComponents
296              VariableNumComponents(num_var) = NumberOfComponents
297            elseif (trim(adjustl(word))=="#interpolation_type") then
298              read(fid,FMT=MAXFMT,end=777,err=999) interpolation_type
299              select case (trim(adjustl(interpolation_type)))
300              case ("constant")
301                InterpolationTypes(num_var)=CMISS_FIELD_CONSTANT_INTERPOLATION
302              case ("elemental")
303                InterpolationTypes(num_var)=CMISS_FIELD_ELEMENT_BASED_INTERPOLATION
304              case ("nodal")
305                InterpolationTypes(num_var)=CMISS_FIELD_NODE_BASED_INTERPOLATION
306              case default
307                write(*,*) "READ_FIELD: unsupported interpolation type encountered"
308                close(fid)
309                return
310              end select
311            elseif (trim(adjustl(word))=="#mesh_component") then
312              read(fid,*,end=777,err=999) mcompn
313              MeshComponents(num_var) = mcompn
314            elseif (trim(adjustl(word))=="#data_type") then
315              read(fid,*,end=777,err=999) data_type
316              select case (trim(data_type))
317              case ("dp")
318                DataTypes(num_var)=CMISS_FIELD_DP_TYPE
319              case ("intg")
320                DataTypes(num_var)=CMISS_FIELD_INTG_TYPE
321              case default
322                write(*,*) "READ_FIELD: unsupported data type encountered"
323                close(fid)
324                return
325              end select
326
327
328
329
330            ! start a variable block
331
332
333
334
335
336
337! !           do
338! !             read(fid,FMT=MAXFMT,end=777) word
339! !             ! skip blanks/comments
340! !             if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
341! !             if (trim(adjustl(word))=="#number_of_components") then
342! !               read(fid,*,end=777,err=999) NumberOfComponents
343! !               CALL CMISSField_NumberOfComponentsSet(Field,VariableType,NumberOfComponents,Err) 
344! !             elseif (trim(adjustl(word))=="#interpolation_type") then
345! !               read(fid,FMT=MAXFMT,end=777,err=999) interpolation_type
346! !               select case (trim(adjustl(interpolation_type)))
347! !               case ("constant")
348! !                 InterpolationType=CMISS_FIELD_CONSTANT_INTERPOLATION
349! !               case ("elemental")
350! !                 InterpolationType=CMISS_FIELD_ELEMENT_BASED_INTERPOLATION
351! !               case ("nodal")
352! !                 InterpolationType=CMISS_FIELD_NODE_BASED_INTERPOLATION
353! !               case default
354! !                 write(*,*) "READ_FIELD: unsupported interpolation type encountered"
355! !                 close(fid)
356! !                 return
357! !               end select
358! !               ! hardcoded: assume all components are interpolated the same way
359! !               do i=1,NumberOfComponents
360! !                 CALL CMISSField_ComponentInterpolationSet(Field,VariableType,i,InterpolationType,Err)
361! !               enddo
362! !             elseif (trim(adjustl(word))=="#mesh_component") then
363! !               read(fid,*,end=777,err=999) mcompn
364! ! !               if (InterpolationType==CMISS_FIELD_NODE_BASED_INTERPOLATION) then
365! !                 do i=1,NumberOfComponents
366! !                   write(*,*) mcompn
367! !                   CALL CMISSField_ComponentMeshComponentSet(Field,VariableType,i,mcompn,Err)
368! !                 enddo
369! ! !               endif
370! !             elseif (trim(adjustl(word))=="#data_type") then
371! !               read(fid,*,end=777,err=999) data_type
372! !               select case (trim(data_type))
373! !               case ("dp")
374! !                 DataType=CMISS_FIELD_DP_TYPE
375! !               case ("intg")
376! !                 DataType=CMISS_FIELD_INTG_TYPE
377! !               case default
378! !                 write(*,*) "READ_FIELD: unsupported data type encountered"
379! !                 close(fid)
380! !                 return
381! !               end select
382
383
384
385
386!              do 
387!               read(fid,FMT=MAXFMT,end=777) word
388
389              ! skip blanks/comments
390!               if (len_trim(word)==0 .or. index(adjustl(word),"!")==1) cycle
391             elseif (trim(adjustl(word))=="#data_variable_type") then
392             IF(field_set.eqv..false.)THEN
393             CALL CMISSField_VariableTypesSet(Field,VariableTypes,Err) 
394             DO var_idx=1,NumberOfVariables
395                  VariableType=VariableTypes(var_idx)
396                  CALL CMISSField_NumberOfComponentsSet(Field,VariableType,NumberOfComponents,Err) 
397                  do i=1,NumberOfComponents
398
399                    CALL CMISSField_ComponentInterpolationSet(Field,VariableType,i,InterpolationType,Err)
400                    CALL CMISSField_ComponentMeshComponentSet(Field,VariableType,i,mcompn,Err)
401                  enddo
402
403                CALL CMISSField_DataTypeSet(Field,VariableType,DataType,Err)
404             ENDDO
405
406             CALL CMISSField_CreateFinish(Field,Err)
407             field_set=.true.
408             ENDIF
409
410                 read(fid,*,end=777) varn
411                 VariableType=VariableTypes(varn)
412                  var_count=var_count+1
413              elseif (trim(adjustl(word))=="#data") then
414                ! don't know how many lines there will be - just go until blank line
415                do
416
417                  read(fid,FMT=MAXFMT,end=777,err=999) word
418                  if (len_trim(word)==0) exit ! exit if blank line
419                  select case (DataTypes(var_count))
420                  case (CMISS_FIELD_DP_TYPE)
421                    read(word,*,end=777,err=999) ind,data_dp(1:NumberOfComponents)
422                    do i=1,NumberOfComponents
423                      select case (InterpolationType)
424                      case (CMISS_FIELD_CONSTANT_INTERPOLATION)
425                        CALL CMISSField_ParameterSetUpdateConstant(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE,i,data_dp(i),Err)
426                      case (CMISS_FIELD_ELEMENT_BASED_INTERPOLATION)
427                        CALL CMISSField_ParameterSetUpdateElement(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE,ind,i,data_dp(i), &
428                          & Err)
429                      case (CMISS_FIELD_NODE_BASED_INTERPOLATION)
430                        CALL CMISSField_ParameterSetUpdateNode(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE,1,1,ind,i, &
431                          & data_dp(i), &
432                          & Err)
433                      end select
434                    enddo
435                  case (CMISS_FIELD_INTG_TYPE)
436                    read(word,*,end=777,err=999) ind,data_int(1:NumberOfComponents)
437                    do i=1,NumberOfComponents
438                      select case (InterpolationType)
439                      case (CMISS_FIELD_CONSTANT_INTERPOLATION)
440                        CALL CMISSField_ParameterSetUpdateConstant(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE,i,data_int(i),Err)
441                      case (CMISS_FIELD_ELEMENT_BASED_INTERPOLATION)
442                        CALL CMISSField_ParameterSetUpdateElement(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE,ind,i, &
443                          & data_int(i), &
444                          & Err)
445                      case (CMISS_FIELD_NODE_BASED_INTERPOLATION)
446                        CALL CMISSField_ParameterSetUpdateNode(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE,1,1,ind,i, &
447                          & data_int(i),Err)
448                      end select
449                    enddo
450                  end select
451                enddo
452              elseif (trim(adjustl(word))=="#data_all") then  ! debug-option to initialise all field values in one go, NO INDEX
453                read(fid,FMT=MAXFMT,end=777,err=999) word
454                select case (DataTypes(var_count))
455                case (CMISS_FIELD_DP_TYPE)
456                  read(word,*,end=777,err=999) data_dp(1:NumberOfComponents)
457                  do i=1,NumberOfComponents
458                    CALL CMISSField_ComponentValuesInitialise(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE, &
459                      & i,data_dp(i),Err)
460                  enddo
461                case (CMISS_FIELD_INTG_TYPE)
462                  read(word,*,end=777,err=999) data_int(1:NumberOfComponents)
463                  do i=1,NumberOfComponents
464                    CALL CMISSField_ComponentValuesInitialise(Field,VariableType,CMISS_FIELD_VALUES_SET_TYPE, &
465                      & i,data_int(i),Err)
466                  enddo
467                end select
468              endif
469            enddo
470            endif
471           enddo
472        endif
473      enddo
474    endif
475
476776 close(fid)
477    return ! happy return
478777 write(*,*) "READ_FIELD: unexpected end of file encountered"
479    close(fid)
480    return
481998 write(*,*) "READ_FIELD: could not open file "//Filename
482    close(fid)
483    return
484999 write(*,*) "READ_FIELD: error reading line"
485    close(fid)
486    return
487  END SUBROUTINE READ_FIELD
488
489END MODULE IOSTUFF