source: trunk/anuga_core/anuga/load_mesh/loadASCII.py @ 9679

Last change on this file since 9679 was 9570, checked in by steve, 10 years ago

Removed another test_all from subpackage (use nosetests or py.test instead)

File size: 37.9 KB
Line 
1"""
2The format for a Points dictionary is:
3
4  ['pointlist'] a 2 column array describing points. 1st column x, 2nd column y.
5  ['attributelist'], a dictionary of 1D arrays, representing attribute values
6  at the point.  The dictionary key is the attribute header.
7  ['geo_reference'] a Geo_refernece object. Use if the point information
8        is relative. This is optional.
9    eg
10    dic['pointlist'] = [[1.0,2.0],[3.0,5.0]]
11    dic['attributelist']['elevation'] = [[7.0,5.0]
12
13
14    The dict format for IO with mesh files is;
15    (the triangulation)
16    vertices: [[x1,y1],[x2,y2],...] (lists of doubles)
17    vertex_attributes: [[a11,a12,...],[a21,a22],...] (lists of doubles)
18    vertex_attribute_titles:[A1Title, A2Title ...] (A list of strings)
19    segments: [[v1,v2],[v3,v4],...] (lists of integers)
20    segment_tags : [tag,tag,...] list of strings
21    triangles : [(v1,v2,v3), (v4,v5,v6),....] lists of points
22    triangle_tags: [s1,s2,...] A list of strings
23    triangle_neighbors: [[t1,t2,t3], [t4,t5,t6],..] lists of triangles
24
25    (the outline)
26    points: [[x1,y1],[x2,y2],...] (lists of doubles)
27    point_attributes: [[a11,a12,...],[a21,a22],...] (lists of doubles)
28    outline_segments: [[point1,point2],[p3,p4],...] (lists of integers)
29    outline_segment_tags : [tag1,tag2,...] list of strings
30    holes : [[x1,y1],...](List of doubles, one inside each hole region)
31    regions : [ [x1,y1],...] (List of 4 doubles)
32    region_tags : [tag1,tag2,...] (list of strings)
33    region_max_areas: [ma1,ma2,...] (A list of doubles)
34    {Convension: A -ve max area means no max area}
35    geo_reference: a Geo_refernece object. Use if the point information
36        is relative. This is optional.
37
38    Points files are .csv for ascii and .pts for NetCDF
39    Mesh files are .tsh for ascii and .msh for NetCDF
40
41    Note: point att's have no titles - that's currently ok, since least
42    squares adds the point info to vertices, and they have titles
43
44    The format for a .tsh file is (FIXME update this)
45
46    First line:  <# of vertices> <# of attributes>
47    Following lines:  <vertex #> <x> <y> [attributes]
48    One line:  <# of triangles>
49    Following lines: <triangle #> <vertex #>  <vertex #> <vertex #>
50                         <neigbouring triangle #> <neigbouring triangle #>
51                         <neigbouring triangle #> [attribute of region]
52    One line:  <# of segments>
53    Following lines:  <segment #> <vertex #>  <vertex #> [boundary tag]
54"""
55
56##FIXME (DSG-DSG) Is the dict format mentioned above a list of a numeric array?
57#  Needs to be defined
58
59
60from string import  find, rfind
61from os.path import splitext
62import exceptions
63
64from anuga.coordinate_transforms.geo_reference import Geo_reference, TITLE, \
65                                                      TitleError
66from anuga.config import netcdf_mode_r, netcdf_mode_w, netcdf_mode_a
67from anuga.config import netcdf_float, netcdf_char, netcdf_int
68from anuga.utilities.system_tools import *
69import anuga.utilities.log as log
70
71from anuga.file.netcdf import NetCDFFile
72from anuga.utilities.numerical_tools import ensure_numeric
73
74import numpy as num
75
76
77class TitleAmountError(exceptions.Exception): pass
78
79
80NOMAXAREA=-999
81
82
83def import_mesh_file(ofile):
84    """Read a mesh file, either .tsh or .msh
85
86    Note: will throw an IOError if it can't load the file.
87    """
88
89    try:
90        if ofile[-4:] == ".tsh":
91            dict = _read_tsh_file(ofile)
92        elif ofile[-4:] == ".msh":
93            dict = _read_msh_file(ofile)
94        else:
95            msg = 'Extension .%s is unknown' % ofile[-4:]
96            raise IOError, msg
97    #FIXME No test for ValueError
98    except (TitleError, SyntaxError, IndexError, ValueError):
99        msg = 'File %s could not be opened' % ofile
100        raise IOError, msg
101   
102    return dict
103
104
105def export_mesh_file(ofile, mesh_dict):
106    """Write a mesh file given a dictionary.
107
108    First line:       <# of vertices> <# of attributes>
109    Following lines:  <vertex #> <x> <y> [attributes]
110    One line:         <# of triangles>
111    Following lines:  <triangle #> <vertex #>  <vertex #> <vertex #>
112                          <neigbouring triangle #> <neigbouring triangle #>
113                          <neigbouring triangle #> [attribute of region]
114    One line:         <# of segments>
115    Following lines:  <segment #> <vertex #>  <vertex #> [boundary tag]
116    """
117
118    # Ensure that if required key isn't present, we add it with [] value.
119    # .setdefault() for dictionaries was added in python 2.0.
120    # The only other neat way to do this is to override the dictionary
121    # .__getitem__() method to return [] if key not found.
122    reqd_keys = ['points', 'point_attributes', 'outline_segments',
123                 'outline_segment_tags', 'holes', 'regions', 'region_tags',
124                 'region_max_areas', 'vertices', 'vertex_attributes',
125                 'vertex_attribute_titles', 'segments', 'segment_tags',
126                 'triangles', 'triangle_tags', 'triangle_neighbors']
127
128    for k in reqd_keys:
129        mesh_dict.setdefault(k, [])
130
131    # hand-off to appropriate function
132    if (ofile[-4:] == ".tsh"):
133        _write_tsh_file(ofile, mesh_dict)
134    elif (ofile[-4:] == ".msh"):
135        _write_msh_file(ofile, mesh_dict)
136    else:
137        msg = 'Unknown file type %s ' % ofile
138        raise IOError, msg
139
140
141def _read_tsh_file(ofile):
142    """Read the text file format for meshes"""
143
144    fd = open(ofile, 'r')
145    dict = _read_triangulation(fd)
146    dict_mesh = _read_outline(fd)
147    for element in dict_mesh.keys():
148        dict[element] = dict_mesh[element]
149    fd.close()
150
151    return dict
152
153
154def _read_triangulation(fd):
155    """Read the generated triangulation, NOT the outline."""
156
157    delimiter = " "
158
159    # loading the point info
160    line = fd.readline()
161    fragments = line.split()
162    if fragments == []:
163        NumOfVertices = 0
164        NumOfVertAttributes = 0
165    else:
166        NumOfVertices = fragments[0]
167        NumOfVertAttributes = fragments[1]
168    points = []
169    pointattributes = []
170    for index in range(int(NumOfVertices)):
171        fragments = fd.readline().split()
172        fragments.pop(0)        # pop off the index
173
174        # pop the x & y off so we're left with a list of attributes
175        vert = [float(fragments.pop(0)), float(fragments.pop(0))]
176        points.append(vert)
177        apointattributes  = []
178        for fragment in fragments:
179            apointattributes.append(float(fragment))
180        if apointattributes != []:
181            pointattributes.append(apointattributes)
182
183    # loading the point title info
184    line = fd.readline()
185    vertTitle = []
186    for index in range(int(NumOfVertAttributes)):
187        fragments = fd.readline().strip()
188        vertTitle.append(fragments)
189
190    # loading the triangle info
191    line = fd.readline()
192    fragments = line.split()
193    NumOfTriangles = fragments[0]
194    triangles = []
195    triangleattributes = []
196    triangleneighbors = []
197    for index in range(int(NumOfTriangles)):
198        line = fd.readline()
199        line.strip()            # so we can get the region string
200        fragments = line.split()
201        fragments.pop(0)        # pop off the index
202
203        tri = [int(fragments[0]), int(fragments[1]), int(fragments[2])]
204        triangles.append(tri)
205        neighbors = [int(fragments[3]), int(fragments[4]), int(fragments[5])]
206        triangleneighbors.append(neighbors)
207        for x in range(7):  # remove index [<vertex #>] [<neigbouring tri #>]
208            line = line[find(line, delimiter):]     # remove index
209            line = line.lstrip()
210        stringtag = line.strip()
211        triangleattributes.append(stringtag)
212
213    # loading the segment info
214    line = fd.readline()
215    fragments = line.split()
216    NumOfSegments = fragments[0]
217    segments = []
218    segmenttags = []
219    for index in range(int(NumOfSegments)):
220        line = fd.readline()
221        line.strip()            # to get the segment string
222        fragments = line.split()
223        fragments.pop(0)        #pop off the index
224        seg = [int(fragments[0]), int(fragments[1])]
225        segments.append(seg)
226        line = line[find(line, delimiter):] # remove index
227        line = line.lstrip()
228        line = line[find(line, delimiter):] # remove x
229        line = line.lstrip()
230        line = line[find(line, delimiter):] # remove y
231        stringtag = line.strip()
232        segmenttags.append(stringtag)
233
234    meshDict = {}
235    meshDict['vertices'] = points
236    if pointattributes == []:
237        meshDict['vertex_attributes'] = None
238    else:
239        meshDict['vertex_attributes'] = pointattributes
240    meshDict['triangles'] = triangles
241    meshDict['triangle_tags'] = triangleattributes
242    meshDict['triangle_neighbors'] = triangleneighbors
243    meshDict['segments'] = segments
244    meshDict['segment_tags'] = segmenttags
245    meshDict['vertex_attribute_titles'] = vertTitle
246
247    return meshDict
248
249
250def _read_outline(fd):
251    """Read a mesh file outline.
252
253    Note, if a file has no mesh info, it can still be read -
254    the meshdic returned will be 'empty'.
255    """
256
257    delimiter = " "     # warning: split() calls are using default whitespace
258
259    # loading the point info
260    line = fd.readline()
261    fragments = line.split()
262    if fragments == []:
263        NumOfVertices = 0
264        NumOfVertAttributes = 0
265    else:
266        NumOfVertices = fragments[0]
267        NumOfVertAttributes = fragments[1]
268    points = []
269    pointattributes = []
270    for index in range(int(NumOfVertices)):
271        fragments = fd.readline().split()
272        fragments.pop(0)                # pop off the index
273        # pop the x & y off so we're left with a list of attributes
274        vert = [float(fragments.pop(0)), float(fragments.pop(0))]
275        points.append(vert)
276        apointattributes = []
277        for fragment in fragments:
278            apointattributes.append(float(fragment))
279        pointattributes.append(apointattributes)
280
281    # loading the segment info
282    line = fd.readline()
283    fragments = line.split()
284    if fragments == []:
285        NumOfSegments = 0
286    else:
287        NumOfSegments = fragments[0]
288    segments = []
289    segmenttags = []
290    for index in range(int(NumOfSegments)):
291        line = fd.readline()
292        fragments = line.split()
293        fragments.pop(0)                    # pop off the index
294        seg = [int(fragments[0]), int(fragments[1])]
295        segments.append(seg)
296        line = line[find(line, delimiter):] # remove index
297        line = line.lstrip()
298        line = line[find(line, delimiter):] # remove x
299        line = line.lstrip()
300        line = line[find(line, delimiter):] # remove y
301        stringtag = line.strip()
302        segmenttags.append(stringtag)
303
304    # loading the hole info
305    line = fd.readline()
306    fragments = line.split()
307    if fragments == []:
308        numOfHoles = 0
309    else:
310        numOfHoles = fragments[0]
311    holes = []
312    for index in range(int(numOfHoles)):
313        fragments = fd.readline().split()
314        fragments.pop(0) #pop off the index
315        hole = [float(fragments[0]), float(fragments[1])]
316        holes.append(hole)
317
318    # loading the region info
319    line = fd.readline()
320    fragments = line.split()
321    if fragments == []:
322        numOfRegions = 0
323    else:
324        numOfRegions = fragments[0]
325    regions = []
326    regionattributes = []
327    for index in range(int(numOfRegions)):
328        line = fd.readline()
329        fragments = line.split()
330        fragments.pop(0)                    # pop off the index
331        region = [float(fragments[0]), float(fragments[1])]
332        regions.append(region)
333
334        line = line[find(line, delimiter):] # remove index
335        line = line.lstrip()
336        line = line[find(line, delimiter):] # remove x
337        line = line.lstrip()
338        line = line[find(line, delimiter):] # remove y
339        stringtag = line.strip()
340        regionattributes.append(stringtag)
341
342    regionmaxareas = []
343    line = fd.readline()
344    for index in range(int(numOfRegions)):  # Read in the Max area info
345        line = fd.readline()
346        fragments = line.split()
347        # The try is here for format compatibility
348        try:
349            fragments.pop(0)                # pop off the index
350            if len(fragments) == 0:         # no max area
351                regionmaxareas.append(None)
352            else:
353                regionmaxareas.append(float(fragments[0]))
354        except (ValueError, IndexError), e:
355            regionmaxareas.append(None)
356
357    try:
358        geo_reference = Geo_reference(ASCIIFile=fd)
359    except:
360        #geo_ref not compulsory
361        geo_reference = None
362
363    meshDict = {}
364    meshDict['points'] = points
365    meshDict['point_attributes'] = pointattributes
366    meshDict['outline_segments'] = segments
367    meshDict['outline_segment_tags'] = segmenttags
368    meshDict['holes'] = holes
369    meshDict['regions'] = regions
370    meshDict['region_tags'] = regionattributes
371    meshDict['region_max_areas'] = regionmaxareas
372    meshDict['geo_reference'] = geo_reference
373
374    return meshDict
375
376
377def _write_ASCII_triangulation(fd, gen_dict):
378    vertices = gen_dict['vertices']
379    vertices_attributes = gen_dict['vertex_attributes']
380
381    try:
382        vertices_attribute_titles = gen_dict['vertex_attribute_titles']
383    except KeyError, e:
384        #FIXME is this the best way?
385        if vertices_attributes == [] or vertices_attributes[0] == []:
386            vertices_attribute_titles = []
387        else:
388            raise KeyError, e
389       
390
391    triangles = gen_dict['triangles']
392    triangles_attributes = gen_dict['triangle_tags']
393    triangle_neighbors = gen_dict['triangle_neighbors']
394
395    segments = gen_dict['segments']
396    segment_tags = gen_dict['segment_tags']
397
398    numVert = str(len(vertices))
399    # Don't understand why we have to do vertices_attributes[0] is None,
400    # but it doesn't work otherwise...
401    if (vertices_attributes == None or
402        numVert == "0" or
403        len(vertices_attributes) == 0):
404        numVertAttrib = "0"
405    else:
406        #numVertAttrib = str(len(vertices_attributes[0]))
407        try:
408            numVertAttrib = str(len(vertices_attributes[0]))
409        except TypeError:
410            vertices_attributes = [ [entry] for entry in vertices_attributes]
411            numVertAttrib = str(len(vertices_attributes[0]))
412       
413
414
415    fd.write(numVert + " " + numVertAttrib + 
416             " # <# of verts> <# of vert attributes>, next lines <vertex #> "
417             "<x> <y> [attributes] ...Triangulation Vertices...\n")
418
419    #<vertex #> <x> <y> [attributes]
420    index = 0
421    for vert in vertices:
422        attlist = ""
423
424        if vertices_attributes == None or vertices_attributes == []:
425            attlist = ""
426        else:
427            for att in vertices_attributes[index]:
428                attlist = attlist + str(att) + " "
429        attlist.strip()
430        fd.write(str(index) + " " + str(vert[0]) + " " + str(vert[1])
431                 + " " + attlist + "\n")
432        index += 1
433
434    # write comments for title
435    fd.write("# attribute column titles ...Triangulation Vertex Titles...\n")
436    for title in vertices_attribute_titles:
437        fd.write(title + "\n")
438
439    # <# of triangles>
440    n = len(triangles)
441    fd.write(str(n)
442             + " # <# of triangles>, next lines <triangle #> [<vertex #>] "
443               "[<neigbouring triangle #>] [attribute of region] ..."
444               "Triangulation Triangles...\n")
445
446    # <triangle #> <vertex #>  <vertex #> <vertex #> <neigbouring triangle #>
447    #    <neigbouring triangle #> <neigbouring triangle #> [attribute of region]
448    for index in range(n):
449        neighbors = ""
450        tri = triangles[index]
451        if len(triangle_neighbors) == 0:
452            neighbors = "-1 -1 -1 "
453        else:
454            for neighbor in triangle_neighbors[index]:
455                if neighbor:
456                    neighbors += str(neighbor) + " "
457                else:
458                    if neighbor == 0:
459                        neighbors +=  "0 "
460                    else:
461                        neighbors +=  "-1 "
462        # Warning even though a list is passed, only the first value
463        # is written.  There's an assumption that the list only
464        # contains one item. This assumption is made since the
465        # dict that's being passed around is also be used to communicate
466        # with triangle, and it seems to have the option of returning
467        # more than one value for triangle attributex
468        if (triangles_attributes == None or
469            triangles_attributes == [] or
470            triangles_attributes[index] == ['']):
471            att = ""
472        else:
473            att = str(triangles_attributes[index])
474        fd.write(str(index) + " "
475                 + str(tri[0]) + " "
476                 + str(tri[1]) + " "
477                 + str(tri[2]) + " "
478                 + neighbors + " "
479                 + att + "\n")
480
481    # One line:  <# of segments>
482    fd.write(str(len(segments)) +
483             " # <# of segments>, next lines <segment #> <vertex #>  "
484             "<vertex #> [boundary tag] ...Triangulation Segments...\n")
485
486    # Following lines:  <segment #> <vertex #>  <vertex #> [boundary tag]
487    for i in range(len(segments)):
488        seg = segments[i]
489        fd.write(str(i) + " "
490                 + str(seg[0]) + " "
491                 + str(seg[1]) + " "
492                 + str(segment_tags[i]) + "\n")
493
494
495def _write_tsh_file(ofile, mesh_dict):
496    fd = open(ofile, 'w')
497    _write_ASCII_triangulation(fd, mesh_dict)
498    _write_ASCII_outline(fd, mesh_dict)
499    fd.close()
500
501
502def _write_ASCII_outline(fd, dict):
503    points = dict['points']
504    point_attributes = dict['point_attributes']
505    segments = dict['outline_segments']
506    segment_tags = dict['outline_segment_tags']
507    holes = dict['holes']
508    regions = dict['regions']
509    region_tags = dict['region_tags']
510    region_max_areas = dict['region_max_areas']
511
512    num_points = str(len(points))
513    if (num_points == '0'):
514        num_point_atts = '0'
515    else:
516        num_point_atts = str(len(point_attributes[0]))
517
518    fd.write(num_points + ' ' + num_point_atts +
519             ' # <# of verts> <# of vert attributes>, next lines <vertex #> '
520             '<x> <y> [attributes] ...Mesh Vertices...\n')
521
522    # <x> <y> [attributes]
523    for i, point in enumerate(points):
524        attlist = ''
525        for att in point_attributes[i]:
526            attlist = attlist + str(att) + ' '
527        attlist.strip()
528        fd.write(str(i) + ' ' + str(point[0]) + ' ' + str(point[1]) + ' ' +
529                 attlist + '\n')
530
531    # One line:  <# of segments>
532    fd.write(str(len(segments)) +
533             ' # <# of segments>, next lines <segment #> <vertex #>  '
534             '<vertex #> [boundary tag] ...Mesh Segments...\n')
535
536    # Following lines:  <vertex #>  <vertex #> [boundary tag]
537    for i,seg in enumerate(segments):
538        fd.write(str(i) + ' ' + str(seg[0]) + ' ' + str(seg[1]) + ' ' +
539                 str(segment_tags[i]) + '\n')
540
541    # One line:  <# of holes>
542    fd.write(str(len(holes)) +
543             ' # <# of holes>, next lines <Hole #> <x> <y> ...Mesh Holes...\n')
544    # <x> <y>
545    for i,h in enumerate(holes):
546        fd.write(str(i) + ' ' + str(h[0]) + ' ' + str(h[1]) + '\n')
547
548    # One line:  <# of regions>
549    fd.write(str(len(regions)) +
550             ' # <# of regions>, next lines <Region #> <x> <y> <tag>'
551             '...Mesh Regions...\n')
552
553    # <index> <x> <y> <tag>
554    for i,r in enumerate(regions):
555        fd.write(str(i) + ' ' + str(r[0]) + ' ' + str(r[1])+ ' ' +
556                 str(region_tags[i]) + '\n')
557
558    # <index> [<MaxArea>|'']
559
560    # One line:  <# of regions>
561    fd.write(str(len(regions)) +
562             ' # <# of regions>, next lines <Region #> [Max Area] '
563             '...Mesh Regions...\n')
564    for i,r in enumerate(regions):
565        area = str(region_max_areas[i])
566
567        fd.write(str(i) + ' ' + area + '\n')
568
569    # geo_reference info
570    if dict.has_key('geo_reference') and not dict['geo_reference'] is None:
571        dict['geo_reference'].write_ASCII(fd)
572
573
574def _write_msh_file(file_name, mesh):
575    """Write .msh NetCDF file
576
577    WARNING: This function mangles the mesh data structure
578    """
579
580    # FIXME(Ole and John): We ran into a problem on Bogong (64 bit)
581    # where integers appeared as arrays.  This may be similar to
582    # problem seen by Steve in changeset:2778 where he had to wrap
583    # them in int.  Now we are trying with the native Integer format
584    # (Int == 'l' == Int64). However, that caused casting errors, when
585    # 64bit arrays are to be assigned to their NetCDF counterparts. It
586    # seems that the NetCDF arrays are 32bit even though they are
587    # created with the type Int64. Need to look at the NetCDF library
588    # in more detail.
589
590    IntType = num.int32
591    #IntType = Int
592
593    #print 'mesh vertices',mesh['vertices'].shape
594
595
596    #the triangulation
597    mesh['vertices'] = num.array(mesh['vertices'], num.float)
598    mesh['vertex_attribute_titles'] = \
599        num.array(string_to_char(mesh['vertex_attribute_titles']), num.character)
600
601    num_attributes = len(mesh['vertex_attribute_titles'])
602    num_vertices = mesh['vertices'].shape[0]
603    #print 'num_attrib ',num_attributes
604    if mesh['vertex_attributes'] != None:
605        mesh['vertex_attributes'] = \
606            num.array(mesh['vertex_attributes'], num.float)
607
608    if num_attributes > 0 :
609        mesh['vertex_attributes'] = \
610            num.reshape(mesh['vertex_attributes'],(num_vertices,-1))
611
612
613
614    mesh['segments'] = num.array(mesh['segments'], IntType)
615    mesh['segment_tags'] = num.array(string_to_char(mesh['segment_tags']),
616                                     num.character)
617    mesh['triangles'] = num.array(mesh['triangles'], IntType)
618    mesh['triangle_tags'] = num.array(string_to_char(mesh['triangle_tags']),
619                                      num.character)
620    mesh['triangle_neighbors'] = \
621        num.array(mesh['triangle_neighbors'], IntType)
622
623    #the outline
624    mesh['points'] = num.array(mesh['points'], num.float)
625    mesh['point_attributes'] = num.array(mesh['point_attributes'], num.float)
626    mesh['outline_segments'] = num.array(mesh['outline_segments'], IntType)
627    mesh['outline_segment_tags'] = \
628        num.array(string_to_char(mesh['outline_segment_tags']), num.character)
629    mesh['holes'] = num.array(mesh['holes'], num.float)
630    mesh['regions'] = num.array(mesh['regions'], num.float)
631    mesh['region_tags'] = num.array(string_to_char(mesh['region_tags']), num.character)
632    mesh['region_max_areas'] = num.array(mesh['region_max_areas'], num.float)
633
634    # NetCDF file definition
635    try:
636        outfile = NetCDFFile(file_name, netcdf_mode_w)
637    except IOError:
638        msg = 'File %s could not be created' % file_name
639        raise Exception, msg
640
641    #Create new file
642    outfile.institution = 'Geoscience Australia'
643    outfile.description = 'NetCDF format for compact and portable storage ' + \
644                          'of spatial point data'
645
646    # dimension definitions - fixed
647    outfile.createDimension('num_of_dimensions', 2)     # This is 2d data
648    outfile.createDimension('num_of_segment_ends', 2)   # Segs have two points
649    outfile.createDimension('num_of_triangle_vertices', 3)
650    outfile.createDimension('num_of_triangle_faces', 3)
651    outfile.createDimension('num_of_region_max_area', 1)
652
653    # Create dimensions, variables and set the variables
654
655    # trianglulation
656    # vertices
657    if (mesh['vertices'].shape[0] > 0):
658        outfile.createDimension('num_of_vertices', mesh['vertices'].shape[0])
659        outfile.createVariable('vertices', netcdf_float, ('num_of_vertices',
660                                                          'num_of_dimensions'))
661        outfile.variables['vertices'][:] = mesh['vertices']
662
663        #print 'mesh vertex attributes', mesh['vertex_attributes'].shape
664       
665        if (mesh['vertex_attributes'] is not None and
666            (mesh['vertex_attributes'].shape[0] > 0 and
667             mesh['vertex_attributes'].shape[1] > 0)):
668            outfile.createDimension('num_of_vertex_attributes',
669                                    mesh['vertex_attributes'].shape[1])
670            outfile.createDimension('num_of_vertex_attribute_title_chars',
671                                    mesh['vertex_attribute_titles'].shape[1])
672            outfile.createVariable('vertex_attributes',
673                                   netcdf_float,
674                                   ('num_of_vertices',
675                                    'num_of_vertex_attributes'))
676            outfile.createVariable('vertex_attribute_titles',
677                                   netcdf_char,
678                                   ('num_of_vertex_attributes',
679                                    'num_of_vertex_attribute_title_chars'))
680            outfile.variables['vertex_attributes'][:] = \
681                                     mesh['vertex_attributes']
682            outfile.variables['vertex_attribute_titles'][:] = \
683                                     mesh['vertex_attribute_titles']
684
685    # segments
686    if (mesh['segments'].shape[0] > 0):
687        outfile.createDimension('num_of_segments', mesh['segments'].shape[0])
688        outfile.createVariable('segments', netcdf_int,
689                               ('num_of_segments', 'num_of_segment_ends'))
690        outfile.variables['segments'][:] = mesh['segments']
691        if (mesh['segment_tags'].shape[1] > 0):
692            outfile.createDimension('num_of_segment_tag_chars',
693                                    mesh['segment_tags'].shape[1])
694            outfile.createVariable('segment_tags',
695                                   netcdf_char,
696                                   ('num_of_segments',
697                                    'num_of_segment_tag_chars'))
698            outfile.variables['segment_tags'][:] = mesh['segment_tags']
699
700    # triangles
701    if (mesh['triangles'].shape[0] > 0):
702        outfile.createDimension('num_of_triangles', mesh['triangles'].shape[0])
703        outfile.createVariable('triangles', netcdf_int,
704                               ('num_of_triangles', 'num_of_triangle_vertices'))
705        outfile.createVariable('triangle_neighbors', netcdf_int,
706                               ('num_of_triangles', 'num_of_triangle_faces'))
707        outfile.variables['triangles'][:] = mesh['triangles']
708        outfile.variables['triangle_neighbors'][:] = mesh['triangle_neighbors']
709        if (mesh['triangle_tags'] is not None and
710            (mesh['triangle_tags'].shape[1] > 0)):
711            outfile.createDimension('num_of_triangle_tag_chars',
712                                    mesh['triangle_tags'].shape[1])
713            outfile.createVariable('triangle_tags', netcdf_char,
714                                   ('num_of_triangles',
715                                    'num_of_triangle_tag_chars'))
716            outfile.variables['triangle_tags'][:] = mesh['triangle_tags']
717
718    # outline
719    # points
720    if (mesh['points'].shape[0] > 0):
721        outfile.createDimension('num_of_points', mesh['points'].shape[0])
722        outfile.createVariable('points', netcdf_float,
723                               ('num_of_points', 'num_of_dimensions'))
724        outfile.variables['points'][:] = mesh['points']
725        if mesh['point_attributes'].shape[0] > 0  \
726           and mesh['point_attributes'].shape[1] > 0:
727            outfile.createDimension('num_of_point_attributes',
728                                    mesh['point_attributes'].shape[1])
729            outfile.createVariable('point_attributes', netcdf_float,
730                                   ('num_of_points', 'num_of_point_attributes'))
731            outfile.variables['point_attributes'][:] = mesh['point_attributes']
732
733    # outline_segments
734    if mesh['outline_segments'].shape[0] > 0:
735        outfile.createDimension('num_of_outline_segments',
736                                mesh['outline_segments'].shape[0])
737        outfile.createVariable('outline_segments', netcdf_int,
738                               ('num_of_outline_segments',
739                                'num_of_segment_ends'))
740        outfile.variables['outline_segments'][:] = mesh['outline_segments']
741        if mesh['outline_segment_tags'].shape[1] > 0:
742            outfile.createDimension('num_of_outline_segment_tag_chars',
743                                    mesh['outline_segment_tags'].shape[1])
744            outfile.createVariable('outline_segment_tags', netcdf_char,
745                                   ('num_of_outline_segments',
746                                    'num_of_outline_segment_tag_chars'))
747            outfile.variables['outline_segment_tags'][:] = \
748                mesh['outline_segment_tags']
749
750    # holes
751    if (mesh['holes'].shape[0] > 0):
752        outfile.createDimension('num_of_holes', mesh['holes'].shape[0])
753        outfile.createVariable('holes', netcdf_float,
754                               ('num_of_holes', 'num_of_dimensions'))
755        outfile.variables['holes'][:] = mesh['holes']
756
757    # regions
758    if (mesh['regions'].shape[0] > 0):
759        outfile.createDimension('num_of_regions', mesh['regions'].shape[0])
760        outfile.createVariable('regions', netcdf_float,
761                               ('num_of_regions', 'num_of_dimensions'))
762        outfile.createVariable('region_max_areas', netcdf_float,
763                               ('num_of_regions',))
764        outfile.variables['regions'][:] = mesh['regions']
765        outfile.variables['region_max_areas'][:] = mesh['region_max_areas']
766        if (mesh['region_tags'].shape[1] > 0):
767            outfile.createDimension('num_of_region_tag_chars',
768                                    mesh['region_tags'].shape[1])
769            outfile.createVariable('region_tags', netcdf_char,
770                                   ('num_of_regions',
771                                    'num_of_region_tag_chars'))
772            outfile.variables['region_tags'][:] = mesh['region_tags']
773
774    # geo_reference info
775    if mesh.has_key('geo_reference') and not mesh['geo_reference'] == None:
776        mesh['geo_reference'].write_NetCDF(outfile)
777
778    outfile.close()
779
780
781def _read_msh_file(file_name):
782    """ Read in an msh file."""
783
784    #Check contents.  Get NetCDF
785    fd = open(file_name, 'r')
786    fd.close()
787
788    # throws prints to screen if file not present
789    fid = NetCDFFile(file_name, netcdf_mode_r)
790    mesh = {}
791
792    # Get the variables - the triangulation
793    try:
794        mesh['vertices'] = fid.variables['vertices'][:]
795    except KeyError:
796        mesh['vertices'] = num.array([], num.int)      #array default#
797
798    try:
799        mesh['vertex_attributes'] = fid.variables['vertex_attributes'][:]
800    except KeyError:
801        mesh['vertex_attributes'] = None
802
803    mesh['vertex_attribute_titles'] = []
804    try:
805        titles = fid.variables['vertex_attribute_titles'][:]
806        mesh['vertex_attribute_titles'] = [x.tostring().strip() for x in titles]
807    except KeyError:
808        pass
809
810    try:
811        mesh['segments'] = fid.variables['segments'][:]
812    except KeyError:
813        mesh['segments'] = num.array([], num.int)      #array default#
814
815    mesh['segment_tags'] = []
816    try:
817        tags = fid.variables['segment_tags'][:]
818        mesh['segment_tags'] = [x.tostring().strip() for x in tags]
819    except KeyError:
820        for ob in mesh['segments']:
821            mesh['segment_tags'].append('')
822
823    try:
824        mesh['triangles'] = fid.variables['triangles'][:]
825        mesh['triangle_neighbors'] = fid.variables['triangle_neighbors'][:]
826    except KeyError:
827        mesh['triangles'] = num.array([], num.int)              #array default#
828        mesh['triangle_neighbors'] = num.array([], num.int)     #array default#
829
830    mesh['triangle_tags'] = []
831    try:
832        tags = fid.variables['triangle_tags'][:]
833        mesh['triangle_tags'] = [x.tostring().strip() for x in tags]
834    except KeyError:
835        for ob in mesh['triangles']:
836            mesh['triangle_tags'].append('')
837
838    #the outline
839    try:
840        mesh['points'] = fid.variables['points'][:]
841    except KeyError:
842        mesh['points'] = []
843
844    try:
845        mesh['point_attributes'] = fid.variables['point_attributes'][:]
846    except KeyError:
847        mesh['point_attributes'] = []
848        for point in mesh['points']:
849            mesh['point_attributes'].append([])
850
851    try:
852        mesh['outline_segments'] = fid.variables['outline_segments'][:]
853    except KeyError:
854        mesh['outline_segments'] = num.array([], num.int)      #array default#
855
856    mesh['outline_segment_tags'] =[]
857    try:
858        tags = fid.variables['outline_segment_tags'][:]
859        for i, tag in enumerate(tags):
860            mesh['outline_segment_tags'].append(tags[i].tostring().strip())
861    except KeyError:
862        for ob in mesh['outline_segments']:
863            mesh['outline_segment_tags'].append('')
864
865    try:
866        mesh['holes'] = fid.variables['holes'][:]
867    except KeyError:
868        mesh['holes'] = num.array([], num.int)          #array default#
869
870    try:
871        mesh['regions'] = fid.variables['regions'][:]
872    except KeyError:
873        mesh['regions'] = num.array([], num.int)        #array default#
874
875    mesh['region_tags'] =[]
876    try:
877        tags = fid.variables['region_tags'][:]
878        for i, tag in enumerate(tags):
879            mesh['region_tags'].append(tags[i].tostring().strip())
880    except KeyError:
881        for ob in mesh['regions']:
882            mesh['region_tags'].append('')
883
884    try:
885        mesh['region_max_areas'] = fid.variables['region_max_areas'][:]
886    except KeyError:
887        mesh['region_max_areas'] = num.array([], num.int)      #array default#
888
889    try:
890        geo_reference = Geo_reference(NetCDFObject=fid)
891        mesh['geo_reference'] = geo_reference
892    except AttributeError, e:
893        #geo_ref not compulsory
894        mesh['geo_reference'] = None
895
896    fid.close()
897
898    return mesh
899
900
901def export_boundary_file(file_name, points, title, delimiter=','):
902    """Export a boundary file.
903
904    Format:
905    First line: Title variable
906    Following lines:  [point index][delimiter][point index]
907
908    file_name - the name of the new file
909    points - List of point index pairs [[p1, p2],[p3, p4]..]
910    title - info to write in the first line
911    """
912
913    fd = open(file_name, 'w')
914
915    fd.write(title + '\n')
916
917    # [point index][delimiter][point index]
918    for point in points:
919        fd.write(str(point[0]) + delimiter + str(point[1]) + '\n')
920
921    fd.close()
922
923################################################################################
924#  IMPORT/EXPORT POINTS FILES
925################################################################################
926
927def extent_point_atts(point_atts):
928    """Returns 4 points representing the extent
929    This loses attribute info.
930    """
931
932    point_atts['pointlist'] = extent(point_atts['pointlist'])
933    point_atts['attributelist'] = {}
934
935    return point_atts
936
937
938def extent(points):
939    points = num.array(points, num.float)
940
941    max_x = min_x = points[0][0]
942    max_y = min_y = points[0][1]
943
944    for point in points[1:]:
945        x = point[0]
946        if x > max_x:
947            max_x = x
948        if x < min_x:
949            min_x = x
950
951        y = point[1]
952        if y > max_y:
953            max_y = y
954        if y < min_y:
955            min_y = y
956
957    extent = num.array([[min_x, min_y],
958                        [max_x, min_y],
959                        [max_x, max_y],
960                        [min_x, max_y]])
961
962    return extent
963
964
965def reduce_pts(infile, outfile, max_points, verbose = False):
966    """Reduce a points file until less than given size.
967
968    Reduces a points file by removing every second point until the # of points
969    is less than max_points.
970    """
971
972    # check out pts2rectangular in least squares, and the use of reduction.
973    # Maybe it does the same sort of thing?
974    point_atts = _read_pts_file(infile)
975
976    while point_atts['pointlist'].shape[0] > max_points:
977        if verbose: log.critical("point_atts['pointlist'].shape[0]")
978        point_atts = half_pts(point_atts)
979
980    export_points_file(outfile, point_atts)
981
982
983def produce_half_point_files(infile, max_points, delimiter, verbose=False):
984    point_atts = _read_pts_file(infile)
985    root, ext = splitext(infile)
986    outfiles = []
987
988    if verbose: log.critical("# of points", point_atts['pointlist'].shape[0])
989
990    while point_atts['pointlist'].shape[0] > max_points:
991        point_atts = half_pts(point_atts)
992
993        if verbose: log.critical("# of points = %s"
994                                 % str(point_atts['pointlist'].shape[0]))
995
996        outfile = root + delimiter + str(point_atts['pointlist'].shape[0]) + ext
997        outfiles.append(outfile)
998        export_points_file(outfile, point_atts)
999
1000    return outfiles
1001
1002
1003def point_atts2array(point_atts):
1004    # convert attribute list to array of floats
1005    point_atts['pointlist'] = num.array(point_atts['pointlist'], num.float)
1006
1007    for key in point_atts['attributelist'].keys():
1008        point_atts['attributelist'][key] = \
1009            num.array(point_atts['attributelist'][key], num.float)
1010
1011    return point_atts
1012
1013
1014def half_pts(point_atts):
1015    point_atts2array(point_atts)
1016    point_atts['pointlist'] = point_atts['pointlist'][::2]
1017
1018    for key in point_atts['attributelist'].keys():
1019        point_atts['attributelist'][key] = point_atts['attributelist'][key][::2]
1020
1021    return point_atts
1022
1023def concatinate_attributelist(dic):
1024    """
1025    giving a dic[attribute title] = attribute
1026    return list of attribute titles, array of attributes
1027    """
1028
1029    point_attributes = num.array([], num.float)
1030    keys = dic.keys()
1031    key = keys.pop(0)
1032    point_attributes = num.reshape(dic[key], (dic[key].shape[0], 1))
1033    for key in keys:
1034        reshaped = num.reshape(dic[key], (dic[key].shape[0], 1))
1035        point_attributes = num.concatenate([point_attributes, reshaped], axis=1)
1036
1037    return dic.keys(), point_attributes
1038
1039
1040def take_points(dict, indices_to_keep):
1041    dict = point_atts2array(dict)
1042    # FIXME maybe the points data structure should become a class?
1043    dict['pointlist'] = num.take(dict['pointlist'], indices_to_keep, axis=0)
1044
1045    for key in dict['attributelist'].keys():
1046        dict['attributelist'][key] = num.take(dict['attributelist'][key],
1047                                              indices_to_keep, axis=0)
1048
1049    return dict
1050
1051def add_point_dictionaries(dict1, dict2):
1052    """
1053    """
1054
1055    dict1 = point_atts2array(dict1)
1056    dict2 = point_atts2array(dict2)
1057
1058    combined = {}
1059    combined['pointlist'] = num.concatenate((dict2['pointlist'],
1060                                             dict1['pointlist']), axis=0)
1061
1062    atts = {}
1063    for key in dict2['attributelist'].keys():
1064        atts[key]= num.concatenate((dict2['attributelist'][key],
1065                                    dict1['attributelist'][key]), axis=0)
1066    combined['attributelist'] = atts
1067    combined['geo_reference'] = dict1['geo_reference']
1068
1069    return combined
1070
1071
1072if __name__ == "__main__":
1073    pass
Note: See TracBrowser for help on using the repository browser.