source: inundation/pyvolution/domain.py @ 2620

Last change on this file since 2620 was 2620, checked in by ole, 18 years ago

Worked on island.py example and it's gauges.
Renamed mesh_file to mesh_filename

File size: 27.3 KB
Line 
1"""Class Domain - 2D triangular domains for finite-volume computations of
2   the shallow water wave equation
3
4
5   Copyright 2004
6   Ole Nielsen, Stephen Roberts, Duncan Gray, Christopher Zoppou
7   Geoscience Australia
8"""
9
10from mesh import Mesh
11from generic_boundary_conditions import Boundary
12from generic_boundary_conditions import File_boundary
13from generic_boundary_conditions import Dirichlet_boundary
14from generic_boundary_conditions import Time_boundary
15from generic_boundary_conditions import Transmissive_boundary
16from pmesh2domain import pmesh_to_domain
17
18import types
19
20class Domain(Mesh):
21
22
23    #FIXME (Ole): I would like this interface to automatically work out
24    #whether input is mesh data or a filename (as in set_quantity).
25    #That way the user need not remember the keyword arguments.
26    def __init__(self, coordinates=None, vertices=None,
27                 boundary=None,
28                 conserved_quantities=None, other_quantities=None,
29                 tagged_elements=None, geo_reference=None,
30                 use_inscribed_circle=False,
31                 mesh_filename=None):
32
33        if mesh_filename is not None:
34            coordinates, vertices, boundary, vertex_quantity_dict \
35                                ,tagged_elements, geo_reference = \
36                                pmesh_to_domain(file_name=mesh_filename)
37            # FIXME(DSG-DSG) have to do something with vertex_quantity_dict
38
39        Mesh.__init__(self, coordinates, vertices, boundary,
40                      tagged_elements, geo_reference, use_inscribed_circle)
41
42        from Numeric import zeros, Float, Int
43        from quantity import Quantity, Conserved_quantity
44
45        #List of quantity names entering
46        #the conservation equations
47        #(Must be a subset of quantities)
48        if conserved_quantities is None:
49            self.conserved_quantities = []
50        else:
51            self.conserved_quantities = conserved_quantities
52
53        if other_quantities is None:
54            self.other_quantities = []
55        else:
56            self.other_quantities = other_quantities
57
58
59        #Build dictionary of Quantity instances keyed by quantity names
60        self.quantities = {}
61
62        #FIXME: remove later - maybe OK, though....
63        for name in self.conserved_quantities:
64            self.quantities[name] = Conserved_quantity(self)
65        for name in self.other_quantities:
66            self.quantities[name] = Quantity(self)
67
68        #Create an empty list for explicit forcing terms
69        self.forcing_terms = []
70
71
72        #Defaults
73        from config import max_smallsteps, beta_w, beta_h, epsilon, CFL
74        self.beta_w = beta_w
75        self.beta_h = beta_h
76        self.epsilon = epsilon
77
78        #FIXME: Maybe have separate orders for h-limiter and w-limiter?
79        #Or maybe get rid of order altogether and use beta_w and beta_h
80        self.set_default_order(1)       
81        #self.default_order = 1
82        #self.order = self.default_order
83
84        self.smallsteps = 0
85        self.max_smallsteps = max_smallsteps
86        self.number_of_steps = 0
87        self.number_of_first_order_steps = 0
88        self.CFL = CFL
89
90        #Model time
91        self.time = 0.0
92        self.finaltime = None
93        self.min_timestep = self.max_timestep = 0.0
94        self.starttime = 0 #Physical starttime if any (0 is 1 Jan 1970 00:00:00)
95
96        ######OBSOLETE
97        #Origin in UTM coordinates
98        #FIXME: This should be set if read by a msh file
99        #self.zone = zone
100        #self.xllcorner = xllcorner
101        #self.yllcorner = yllcorner
102
103
104        #Checkpointing and storage
105        from config import default_datadir
106        self.datadir = default_datadir
107        self.filename = 'domain'
108        self.checkpoint = False
109
110        #MH310505 To avoid calculating the flux across each edge twice, keep an integer (boolean) array,
111        #to be used during the flux calculation
112        N=self.number_of_elements
113        self.already_computed_flux = zeros((N, 3), Int)
114
115        if mesh_filename is not None:
116            # If the mesh file passed any quantity values
117            # , initialise with these values.
118            self.set_quantity_vertices_dict(vertex_quantity_dict)
119
120       
121
122    def set_default_order(self, n):
123        """Set default (spatial) order to either 1 or 2
124        """
125
126        msg = 'Default order must be either 1 or 2. I got %s' %n
127        assert n in [1,2], msg
128       
129        self.default_order = n
130        self.order = self.default_order
131
132
133    #Public interface to Domain
134    def get_conserved_quantities(self, vol_id, vertex=None, edge=None):
135        """Get conserved quantities at volume vol_id
136
137        If vertex is specified use it as index for vertex values
138        If edge is specified use it as index for edge values
139        If neither are specified use centroid values
140        If both are specified an exeception is raised
141
142        Return value: Vector of length == number_of_conserved quantities
143
144        """
145
146        from Numeric import zeros, Float
147
148        if not (vertex is None or edge is None):
149            msg = 'Values for both vertex and edge was specified.'
150            msg += 'Only one (or none) is allowed.'
151            raise msg
152
153        q = zeros( len(self.conserved_quantities), Float)
154
155        for i, name in enumerate(self.conserved_quantities):
156            Q = self.quantities[name]
157            if vertex is not None:
158                q[i] = Q.vertex_values[vol_id, vertex]
159            elif edge is not None:
160                q[i] = Q.edge_values[vol_id, edge]
161            else:
162                q[i] = Q.centroid_values[vol_id]
163
164        return q
165
166    def set_time(self, time=0.0):
167        """Set the time"""
168
169        self.time = time
170
171    def set_quantity_vertices_dict(self, quantity_dict):
172        """Set values for named quantities.
173        The index is the quantity
174
175        name: Name of quantity
176        X: Compatible list, Numeric array, const or function (see below)
177
178        The values will be stored in elements following their
179        internal ordering.
180
181        """
182        for key in quantity_dict.keys():
183            self.set_quantity(key, quantity_dict[key], location='vertices')
184
185
186    def set_quantity(self, name, *args, **kwargs):
187        """Set values for named quantity
188
189
190        One keyword argument is documented here:
191        expression = None, # Arbitrary expression
192
193        expression:
194          Arbitrary expression involving quantity names
195
196        See Quantity.set_values for further documentation.
197        """
198
199        #FIXME (Ole): Allow new quantities here
200        #from quantity import Quantity, Conserved_quantity
201        #Create appropriate quantity object
202        ##if name in self.conserved_quantities:
203        ##    self.quantities[name] = Conserved_quantity(self)
204        ##else:
205        ##    self.quantities[name] = Quantity(self)
206
207
208        #Do the expression stuff
209        if kwargs.has_key('expression'):
210            expression = kwargs['expression']
211            del kwargs['expression']
212
213            Q = self.create_quantity_from_expression(expression)
214            kwargs['quantity'] = Q
215
216
217        #Assign values
218        self.quantities[name].set_values(*args, **kwargs)
219
220
221    def get_quantity(self, name, location='vertices', indices = None):
222        """Get quantity object.
223
224        name: Name of quantity
225
226        See methods inside the quantity object for more options
227        """
228
229        return self.quantities[name] #.get_values( location, indices = indices)
230
231
232    def get_quantity_object(self, name):
233        """Get object for named quantity
234
235        name: Name of quantity
236
237        FIXME: Obsolete
238        """
239
240        print 'get_quantity_object has been deprecated. Please use get_quantity'
241        return self.quantities[name]
242
243
244    def create_quantity_from_expression(self, expression):
245        """Create new quantity from other quantities using arbitrary expression
246
247        Combine existing quantities in domain using expression and return
248        result as a new quantity.
249
250        Note, the new quantity could e.g. be used in set_quantity
251
252        Valid expressions are limited to operators defined in class Quantity
253
254        Example:
255
256
257        """
258
259        from util import apply_expression_to_dictionary
260        return apply_expression_to_dictionary(expression, self.quantities)
261
262
263
264
265    def set_boundary(self, boundary_map):
266        """Associate boundary objects with tagged boundary segments.
267
268        Input boundary_map is a dictionary of boundary objects keyed
269        by symbolic tags to matched against tags in the internal dictionary
270        self.boundary.
271
272        As result one pointer to a boundary object is stored for each vertex
273        in the list self.boundary_objects.
274        More entries may point to the same boundary object
275
276        Schematically the mapping is from two dictionaries to one list
277        where the index is used as pointer to the boundary_values arrays
278        within each quantity.
279
280        self.boundary:          (vol_id, edge_id): tag
281        boundary_map (input):   tag: boundary_object
282        ----------------------------------------------
283        self.boundary_objects:  ((vol_id, edge_id), boundary_object)
284
285
286        Pre-condition:
287          self.boundary has been built.
288
289        Post-condition:
290          self.boundary_objects is built
291
292        If a tag from the domain doesn't appear in the input dictionary an
293        exception is raised.
294        However, if a tag is not used to the domain, no error is thrown.
295        FIXME: This would lead to implementation of a
296        default boundary condition
297
298        Note: If a segment is listed in the boundary dictionary and if it is
299        not None, it *will* become a boundary -
300        even if there is a neighbouring triangle.
301        This would be the case for internal boundaries
302
303        Boundary objects that are None will be skipped.
304
305        FIXME: If set_boundary is called multiple times and if Boundary
306        object is changed into None, the neighbour structure will not be
307        restored!!!
308
309
310        """
311
312        self.boundary_objects = []
313        self.boundary_map = boundary_map  #Store for use with eg. boundary_stats.
314
315        #FIXME: Try to remove the sorting and fix test_mesh.py
316        x = self.boundary.keys()
317        x.sort()
318
319        #Loop through edges that lie on the boundary and associate them with
320        #callable boundary objects depending on their tags
321        for k, (vol_id, edge_id) in enumerate(x):
322            tag = self.boundary[ (vol_id, edge_id) ]
323
324            if boundary_map.has_key(tag):
325                B = boundary_map[tag]  #Get callable boundary object
326
327                if B is not None:
328                    self.boundary_objects.append( ((vol_id, edge_id), B) )
329                    self.neighbours[vol_id, edge_id] = -len(self.boundary_objects)
330                else:
331                    pass
332                    #FIXME: Check and perhaps fix neighbour structure
333
334
335            else:
336                msg = 'ERROR (domain.py): Tag "%s" has not been ' %tag
337                msg += 'bound to a boundary object.\n'
338                msg += 'All boundary tags defined in domain must appear '
339                msg += 'in the supplied dictionary.\n'
340                msg += 'The tags are: %s' %self.get_boundary_tags()
341                raise msg
342
343
344    def set_region(self, functions):
345        # The order of functions in the list is used.
346        if type(functions) not in [types.ListType,types.TupleType]:
347            functions = [functions]
348        for function in functions:
349            for tag in self.tagged_elements.keys():
350                function(tag, self.tagged_elements[tag], self)
351
352                #Do we need to do this sort of thing?
353                #self = function(tag, self.tagged_elements[tag], self)
354
355    #MISC
356    def check_integrity(self):
357        Mesh.check_integrity(self)
358
359        for quantity in self.conserved_quantities:
360            msg = 'Conserved quantities must be a subset of all quantities'
361            assert quantity in self.quantities, msg
362
363        ##assert hasattr(self, 'boundary_objects')
364
365    def write_time(self):
366        print self.timestepping_statistics()
367
368        #Old version
369        #if self.min_timestep == self.max_timestep:
370        #    print 'Time = %.4f, delta t = %.8f, steps=%d (%d)'\
371        #          %(self.time, self.min_timestep, self.number_of_steps,
372        #            self.number_of_first_order_steps)
373        #elif self.min_timestep > self.max_timestep:
374        #    print 'Time = %.4f, steps=%d (%d)'\
375        #          %(self.time, self.number_of_steps,
376        #            self.number_of_first_order_steps)
377        #else:
378        #    print 'Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
379        #          %(self.time, self.min_timestep,
380        #            self.max_timestep, self.number_of_steps,
381        #            self.number_of_first_order_steps)
382
383    def timestepping_statistics(self):
384        """Return string with time stepping statistics for printing or logging
385        """
386
387        msg = ''
388        if self.min_timestep == self.max_timestep:
389            msg += 'Time = %.4f, delta t = %.8f, steps=%d (%d)'\
390                   %(self.time, self.min_timestep, self.number_of_steps,
391                     self.number_of_first_order_steps)
392        elif self.min_timestep > self.max_timestep:
393            msg += 'Time = %.4f, steps=%d (%d)'\
394                   %(self.time, self.number_of_steps,
395                     self.number_of_first_order_steps)
396        else:
397            msg += 'Time = %.4f, delta t in [%.8f, %.8f], steps=%d (%d)'\
398                   %(self.time, self.min_timestep,
399                     self.max_timestep, self.number_of_steps,
400                     self.number_of_first_order_steps)
401
402        return msg
403
404
405    def write_boundary_statistics(self, quantities = None, tags = None):
406        print self.boundary_statistics(quantities, tags)
407
408    def boundary_statistics(self, quantities = None, tags = None):
409        """Output statistics about boundary forcing at each timestep
410
411
412        Input:
413          quantities: either None, a string or a list of strings naming the quantities to be reported
414          tags:       either None, a string or a list of strings naming the tags to be reported         
415
416
417        Example output:
418        Tag 'wall':
419            stage in [2, 5.5]
420            xmomentum in []
421            ymomentum in []
422        Tag 'ocean'
423
424
425        If quantities are specified only report on those. Otherwise take all conserved quantities.
426        If tags are specified only report on those, otherwise take all tags.
427
428        """
429
430        #Input checks
431        import types, string
432
433        if quantities is None:
434            quantities = self.conserved_quantities
435        elif type(quantities) == types.StringType:
436            quantities = [quantities] #Turn it into a list
437
438        msg = 'Keyword argument quantities must be either None, '
439        msg += 'string or list. I got %s' %str(quantities)
440        assert type(quantities) == types.ListType, msg
441
442
443        if tags is None:
444            tags = self.get_boundary_tags()
445        elif type(tags) == types.StringType:
446            tags = [tags] #Turn it into a list
447
448        msg = 'Keyword argument tags must be either None, '
449        msg += 'string or list. I got %s' %str(tags)
450        assert type(tags) == types.ListType, msg
451
452        #Determine width of longest quantity name (for cosmetic purposes)
453        maxwidth = 0
454        for name in quantities:
455            w = len(name)
456            if w > maxwidth:
457                maxwidth = w
458
459        #Output stats
460        msg = 'Boundary values at time %.4f:\n' %self.time
461        for tag in tags:
462            msg += '    %s:\n' %tag
463
464            for name in quantities:
465                q = self.quantities[name]
466
467                #Find range of boundary values for tag and q
468                maxval = minval = None
469                for i, ((vol_id, edge_id), B) in\
470                        enumerate(self.boundary_objects):
471                    if self.boundary[(vol_id, edge_id)] == tag:
472                        v = q.boundary_values[i]
473                        if minval is None or v < minval: minval = v
474                        if maxval is None or v > maxval: maxval = v
475
476                if minval is None or maxval is None:
477                    msg += '        Sorry no information available about' +\
478                           ' tag %s and quantity %s\n' %(tag, name)
479                else:
480                    msg += '        %s in [%12.8f, %12.8f]\n'\
481                           %(string.ljust(name, maxwidth), minval, maxval)
482
483
484        return msg
485
486
487    def get_name(self):
488        return self.filename
489
490    def set_name(self, name):
491        self.filename = name
492
493    def get_datadir(self):
494        return self.datadir
495
496    def set_datadir(self, name):
497        self.datadir = name
498
499
500
501    #def set_defaults(self):
502    #    """Set default values for uninitialised quantities.
503    #    Should be overridden or specialised by specific modules
504    #    """#
505    #
506    #    for name in self.conserved_quantities + self.other_quantities:
507    #        self.set_quantity(name, 0.0)
508
509
510    ###########################
511    #Main components of evolve
512
513    def evolve(self,
514               yieldstep = None,
515               finaltime = None,
516               duration = None,             
517               skip_initial_step = False):
518        """Evolve model through time starting from self.starttime.
519       
520       
521        yieldstep: Interval between yields where results are stored,
522                   statistics written and domain inspected or
523                   possibly modified. If omitted the internal predefined
524                   max timestep is used.
525                   Internally, smaller timesteps may be taken.               
526
527        duration: Duration of simulation
528
529        finaltime: Time where simulation should end
530
531        If both duration and finaltime are given an exception is thrown.
532
533
534        skip_initial_step: Boolean flag that decides whether the first
535        yield step is skipped or not. This is useful for example to avoid
536        duplicate steps when multiple evolve processes are dove tailed.
537
538
539        Evolve is implemented as a generator and is to be called as such, e.g.
540
541        for t in domain.evolve(yieldstep, finaltime):
542            <Do something with domain and t>
543
544
545        All times are given in seconds       
546
547        """
548
549        from config import min_timestep, max_timestep, epsilon
550
551        #FIXME: Maybe lump into a larger check prior to evolving
552        msg = 'Boundary tags must be bound to boundary objects before evolving system, '
553        msg += 'e.g. using the method set_boundary.\n'
554        msg += 'This system has the boundary tags %s '\
555               %self.get_boundary_tags()
556        assert hasattr(self, 'boundary_objects'), msg
557
558        ##self.set_defaults()
559
560        if yieldstep is None:
561            yieldstep = max_timestep
562        else:
563            yieldstep = float(yieldstep)
564
565        self.order = self.default_order
566
567
568        if finaltime is not None and duration is not None:
569            print 'F', finaltime, duration
570            msg = 'Only one of finaltime and duration may be specified'
571            raise msg
572        else:
573            if finaltime is not None:
574                self.finaltime = float(finaltime)
575            if duration is not None:
576                self.finaltime = self.starttime + float(duration)
577               
578
579       
580
581        self.yieldtime = 0.0 #Time between 'yields'
582
583        #Initialise interval of timestep sizes (for reporting only)
584        self.min_timestep = max_timestep
585        self.max_timestep = min_timestep
586        self.number_of_steps = 0
587        self.number_of_first_order_steps = 0
588
589        #update ghosts
590        self.update_ghosts()
591
592        #Initial update of vertex and edge values
593        self.distribute_to_vertices_and_edges()
594
595        #Initial update boundary values
596        self.update_boundary()
597
598        #Or maybe restore from latest checkpoint
599        if self.checkpoint is True:
600            self.goto_latest_checkpoint()
601
602        if skip_initial_step is False:
603            yield(self.time)  #Yield initial values
604
605        while True:
606
607            #Compute fluxes across each element edge
608            self.compute_fluxes()
609
610            #Update timestep to fit yieldstep and finaltime
611            self.update_timestep(yieldstep, finaltime)
612
613            #Update conserved quantities
614            self.update_conserved_quantities()
615
616            #update ghosts
617            self.update_ghosts()
618
619            #Update vertex and edge values
620            self.distribute_to_vertices_and_edges()
621
622            #Update boundary values
623            self.update_boundary()
624
625            #Update time
626            self.time += self.timestep
627            self.yieldtime += self.timestep
628            self.number_of_steps += 1
629            if self.order == 1:
630                self.number_of_first_order_steps += 1
631
632            #Yield results
633            if finaltime is not None and abs(self.time - finaltime) < epsilon:
634
635                #FIXME: There is a rare situation where the
636                #final time step is stored twice. Can we make a test?
637
638                # Yield final time and stop
639                yield(self.time)
640                break
641
642
643            if abs(self.yieldtime - yieldstep) < epsilon:
644                # Yield (intermediate) time and allow inspection of domain
645
646                if self.checkpoint is True:
647                    self.store_checkpoint()
648                    self.delete_old_checkpoints()
649
650                #Pass control on to outer loop for more specific actions
651                yield(self.time)
652
653                # Reinitialise
654                self.yieldtime = 0.0
655                self.min_timestep = max_timestep
656                self.max_timestep = min_timestep
657                self.number_of_steps = 0
658                self.number_of_first_order_steps = 0
659
660
661    def evolve_to_end(self, finaltime = 1.0):
662        """Iterate evolve all the way to the end
663        """
664
665        for _ in self.evolve(yieldstep=None, finaltime=finaltime):
666            pass
667
668
669
670    def update_boundary(self):
671        """Go through list of boundary objects and update boundary values
672        for all conserved quantities on boundary.
673        """
674
675        #FIXME: Update only those that change (if that can be worked out)
676        #FIXME: Boundary objects should not include ghost nodes.
677        for i, ((vol_id, edge_id), B) in enumerate(self.boundary_objects):
678            if B is None:
679                print 'WARNING: Ignored boundary segment %d (None)'
680            else:               
681                q = B.evaluate(vol_id, edge_id)
682
683                for j, name in enumerate(self.conserved_quantities):
684                    Q = self.quantities[name]
685                    Q.boundary_values[i] = q[j]
686
687
688    def compute_fluxes(self):
689        msg = 'Method compute_fluxes must be overridden by Domain subclass'
690        raise msg
691
692
693    def update_timestep(self, yieldstep, finaltime):
694
695        from config import min_timestep
696
697        # self.timestep is calculated from speed of characteristics
698        # Apply CFL condition here
699        timestep = self.CFL*self.timestep
700
701        #Record maximal and minimal values of timestep for reporting
702        self.max_timestep = max(timestep, self.max_timestep)
703        self.min_timestep = min(timestep, self.min_timestep)
704
705        #Protect against degenerate time steps
706        if timestep < min_timestep:
707
708            #Number of consecutive small steps taken b4 taking action
709            self.smallsteps += 1
710
711            if self.smallsteps > self.max_smallsteps:
712                self.smallsteps = 0 #Reset
713
714                if self.order == 1:
715                    msg = 'WARNING: Too small timestep %.16f reached '\
716                          %timestep
717                    msg += 'even after %d steps of 1 order scheme'\
718                           %self.max_smallsteps
719                    print msg
720                    timestep = min_timestep  #Try enforcing min_step
721
722                    #raise msg
723                else:
724                    #Try to overcome situation by switching to 1 order
725                    self.order = 1
726
727        else:
728            self.smallsteps = 0
729            if self.order == 1 and self.default_order == 2:
730                self.order = 2
731
732
733        #Ensure that final time is not exceeded
734        if finaltime is not None and self.time + timestep > finaltime:
735            timestep = finaltime-self.time
736
737        #Ensure that model time is aligned with yieldsteps
738        if self.yieldtime + timestep > yieldstep:
739            timestep = yieldstep-self.yieldtime
740
741        self.timestep = timestep
742
743
744
745    def compute_forcing_terms(self):
746        """If there are any forcing functions driving the system
747        they should be defined in Domain subclass and appended to
748        the list self.forcing_terms
749        """
750
751        for f in self.forcing_terms:
752            f(self)
753
754
755
756    def update_conserved_quantities(self):
757        """Update vectors of conserved quantities using previously
758        computed fluxes specified forcing functions.
759        """
760
761        from Numeric import ones, sum, equal, Float
762
763        N = self.number_of_elements
764        d = len(self.conserved_quantities)
765
766        timestep = self.timestep
767
768        #Compute forcing terms
769        self.compute_forcing_terms()
770
771        #Update conserved_quantities
772        for name in self.conserved_quantities:
773            Q = self.quantities[name]
774            Q.update(timestep)
775
776            #Clean up
777            #Note that Q.explicit_update is reset by compute_fluxes
778
779            #MH090605 commented out the following since semi_implicit_update is now re-initialized
780            #at the end of the _update function in quantity_ext.c (This is called by the
781            #preceeding Q.update(timestep) statement above).
782            #For run_profile.py with N=128, the time of update_conserved_quantities is cut from 14.00 secs
783            #to 8.35 secs
784
785            #Q.semi_implicit_update[:] = 0.0
786
787    def update_ghosts(self):
788        pass
789
790    def distribute_to_vertices_and_edges(self):
791        """Extrapolate conserved quantities from centroid to
792        vertices and edge-midpoints for each volume
793
794        Default implementation is straight first order,
795        i.e. constant values throughout each element and
796        no reference to non-conserved quantities.
797        """
798
799        for name in self.conserved_quantities:
800            Q = self.quantities[name]
801            if self.order == 1:
802                Q.extrapolate_first_order()
803            elif self.order == 2:
804                Q.extrapolate_second_order()
805                Q.limit()
806            else:
807                raise 'Unknown order'
808            Q.interpolate_from_vertices_to_edges()
809
810
811    def centroid_norm(self, quantity, normfunc):
812        """Calculate the norm of the centroid values
813        of a specific quantity, using normfunc.
814
815        normfunc should take a list to a float.
816
817        common normfuncs are provided in the module utilities.norms
818        """
819        return normfunc(self.quantities[quantity].centroid_values)
820
821
822
823##############################################
824#Initialise module
825
826#Optimisation with psyco
827from config import use_psyco
828if use_psyco:
829    try:
830        import psyco
831    except:
832        import os
833        if os.name == 'posix' and os.uname()[4] == 'x86_64':
834            pass
835            #Psyco isn't supported on 64 bit systems, but it doesn't matter
836        else:
837            msg = 'WARNING: psyco (speedup) could not import'+\
838                  ', you may want to consider installing it'
839            print msg
840    else:
841        psyco.bind(Domain.update_boundary)
842        #psyco.bind(Domain.update_timestep)     #Not worth it
843        psyco.bind(Domain.update_conserved_quantities)
844        psyco.bind(Domain.distribute_to_vertices_and_edges)
845
846
847if __name__ == "__main__":
848    pass
Note: See TracBrowser for help on using the repository browser.