1"""
2PySCeS - Python Simulator for Cellular Systems (http://pysces.sourceforge.net)
3
4Copyright (C) 2004-2020 B.G. Olivier, J.M. Rohwer, J.-H.S Hofmeyr all rights reserved,
5
6Brett G. Olivier (bgoli@users.sourceforge.net)
7Triple-J Group for Molecular Cell Physiology
8Stellenbosch University, South Africa.
9
10Permission to use, modify, and distribute this software is given under the
11terms of the PySceS (BSD style) license. See LICENSE.txt that came with
12this distribution for specifics.
13
14NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
15Brett G. Olivier
16"""
17from __future__ import division, print_function
18from __future__ import absolute_import
19from __future__ import unicode_literals
20
21from pysces.version import __version__
22__doc__ = '''
23            PyscesUtils
24            -----------
25
26            The PyscesUtils module holds a collection of methods of general use such as timers and
27            array export fucntionality that can be accessed as **pysces.write.**
28
29            '''
30
31import fileinput
32import os,sys
33import time
34
35
36
37
38def VersionCheck(ver='0.1.5'):
39    print("dead")
40
41
42def str2bool(s):
43    """
44    Tries to convert a string to a Python boolean
45
46    - *s* True if 'True', 'true' or'1' else False
47
48    """
49    if s in ['True','true', '1']:
50        return True
51    else:
52        return False
53
54class TimerBox:
55    """
56    A timer "container" class that can be used to hold user defined timers
57
58    """
59    __go__ = 1
60
61    def __init__(self):
62        if os.sys.version_info[0] < 2 or os.sys.version_info[1] < 3:
63            print('Your version of Python (' + str(os.sys.version_info[:3]) + ') might be too old\
64            to use this class. Python 2.2 or newer is required')
65
66    def normal_timer(self,name):
67        """
68        normal_timer(name)
69
70        Creates a normal timer method with <name> in the TimerBox instance. Normal timers
71        print the elapsed time since creation when called.
72
73         - *name* the timer name
74
75        """
76        assert type(name) == str or type(name) == unicode
77        def timer(startTime=time.time()):
78            while self.__go__:
79                ms = divmod(time.time() - startTime,60)
80                nowTime = str(int(ms[0])) + ' min ' + str(int(ms[1])) + ' sec'
81                yield nowTime
82        setattr(self,name,timer())
83
84    def step_timer(self,name,maxsteps):
85        """
86        step_timer(name,maxsteps)
87
88        Creates a step timer method with <name> in the TimerBox instance. Step timers
89        print the elapsed time as well as the next step out of maxsteps when called.
90
91        - *name* the timer name
92        - *maxsteps* the maximum number of steps associated with this timer
93
94        """
95        assert type(name) == str, 'Name is a string representing the timer name'
96        assert type(maxsteps) == int or type(maxsteps) == float, 'int or float needed'
97
98        setattr(self,name+'_cstep',0)
99        def timer(startTime=time.time(),maxS=maxsteps):
100            while self.__go__:
101                ms = divmod(time.time() - startTime,60)
102                nowStep = 'step ' + str(getattr(self,name+'_cstep')) + ' of ' + str(maxS)+ ' ('+\
103                    str(int(ms[0])) + ' min ' + str(int(ms[1])) + ' sec)'
104                yield nowStep
105        setattr(self,name,timer())
106
107    def stop(self,name):
108        """
109        Delete the timer <name> from the TimerBox instance
110
111        - *name* the timer name to delete
112
113        """
114        delattr(self, name)
115        try:
116            getattr(self,name+'_cstep')
117            delattr(self,name+'_cstep')
118        except:
119            pass
120
121    def reset_step(self,name):
122        """
123        Reset the number of steps of timer <name> in the TimerBox to zero
124
125        - *name* the step timer whose steps should be reset
126
127        """
128        try:
129            getattr(self,name+'_cstep')
130            setattr(self,name+'_cstep',0)
131        except:
132            pass
133
134def CopyTestModels(*args, **kwargs):
135    print("moved to PyscesTest")
136
137def CopyModels(*args, **kwargs):
138    print("dead")
139
140
141def ConvertFileD2U(Filelist):
142    """
143    Converts a [Filename] from rn to n inplace no effect if the line termination is correct
144
145    - *Filelist* a file or list of files to convert
146
147    """
148    for line in fileinput.input(Filelist,inplace=1):
149        try:
150            if line[-2] == '\r':
151                print(line[:-2]+'\n', end=' ')
152            else:
153                print(line, end=' ')
154        except:
155            print(line, end=' ')
156
157def ConvertFileU2D(Filelist):
158    """
159    Converts a [Filename] from n to rn inplace no effect if the line termination is correct:
160
161    - *Filelist* a file or list of files to convert
162
163    """
164    for line in fileinput.input(Filelist,inplace=1):
165        try:
166            if line[-2] != '\r':
167                print(line[:-1]+'\n', end=' ')
168            else:
169                print(line, end=' ')
170        except:
171            print('\n', end=' ')
172
173class WriteOutput(object):
174    """
175    This code is adapted from:
176
177    CBMPy: CBTools module
178
179    Constraint Based Modelling in Python (http://cbmpy.sourceforge.net)
180    Copyright (C) 2009-2017 Brett G. Olivier, VU University Amsterdam, Amsterdam, The Netherlands
181
182    """
183
184    def exportLabelledArray(self, arr, names, fname, sep=',', format='%f'):
185        """
186        Write a 2D array type object to file
187
188         - *arr* the an array like object
189         - *names* the list of row names
190         - *fname* the output filename
191         - *sep* [default=','] the column separator
192         - *format* [default='%s'] the output number format
193
194        """
195        if names != None:
196            assert arr.shape[0] == len(names), '\n ...  rows must equal number of names!'
197        F = open(fname, 'w')
198        cntr = 0
199        for r in range(arr.shape[0]):
200            if names != None:
201                F.write(('%s'+sep) % names[r])
202            for c in range(arr.shape[1]):
203                if c < arr.shape[1]-1:
204                    F.write((format+sep) % arr[r,c])
205                else:
206                    F.write((format+'\n') % arr[r,c])
207            cntr += 1
208            if cntr >= 250:
209                F.flush()
210                cntr = 1
211        F.write('\n')
212        F.flush()
213        F.close()
214        print('exported to %s' % fname)
215
216    def exportLabelledArrayWithHeader(self, arr, names, header, fname, sep=',', format='%f'):
217        """
218        Export an array with row names and header
219
220         - *arr* the an array like object
221         - *names* the list of row names
222         - *header* the list of column names
223         - *fname* the output filename
224         - *sep* [default=','] the column separator
225         - *format* [default='%s'] the output number format
226         - *appendlist* [default=False] if True append the array to *fname* otherwise create a new file
227
228        """
229        if names != None:
230            assert arr.shape[0] == len(names), '\n ...  rows must equal number of names!'
231        if header != None:
232            assert arr.shape[1] == len(header), '\n ...  cols must equal number of header names!'
233        F = open(fname, 'w')
234        cntr = 0
235        if header != None:
236            if names != None:
237                hstr = ' '+sep
238            else:
239                hstr = ''
240            for h in header:
241                hstr += str(h)+sep
242            hstr = hstr[:-1]+'\n'
243            F.write(hstr)
244            del hstr
245        for r in range(arr.shape[0]):
246            if names != None:
247                F.write(('%s'+sep) % names[r])
248            for c in range(arr.shape[1]):
249                if c < arr.shape[1]-1:
250                    F.write((format+sep) % arr[r,c])
251                else:
252                    F.write((format+'\n') % arr[r,c])
253            cntr += 1
254            if cntr >= 250:
255                F.flush()
256                cntr = 1
257        F.write('\n')
258        F.flush()
259        F.close()
260        print('exported to %s' % fname)
261
262
263    def exportLabelledLinkedList(self, arr, fname, names=None, sep=',', format='%s', appendlist=False):
264        """
265        Write a 2D linked list [[...],[...],[...],[...]] and optionally a list of row labels to file:
266
267         - *arr* the linked list
268         - *fname* the output filename
269         - *names* the list of row names
270         - *sep* [default=','] the column separator
271         - *format* [default='%s'] the output number format
272         - *appendlist* [default=False] if True append the array to *fname* otherwise create a new file
273
274        """
275        if names != None:
276            assert len(arr) == len(names), '\n ...  rows must equal number of names!'
277        if not appendlist:
278            F = open(fname, 'w')
279        else:
280            F = open(fname, 'a')
281        cntr = 0
282        for r in range(len(arr)):
283            if names != None:
284                F.write(('%s'+sep) % names[r])
285            col_l = len(arr[0])
286            for c in range(col_l):
287                if c < col_l-1:
288                    if arr[r][c] == 0.0:
289                        F.write('0.0'+sep)
290                    else:
291                        try:
292                            F.write((format+sep) % arr[r][c])
293                        except UnicodeEncodeError:
294                            F.write((format+sep) % 'uError')
295                else:
296                    if arr[r][c] == 0.0:
297                        F.write('0.0\n')
298                    else:
299                        try:
300                            F.write((format+'\n') % arr[r][c])
301                        except UnicodeEncodeError:
302                            F.write((format+'\n') % 'uError')
303            cntr += 1
304            if cntr >= 250:
305                F.flush()
306                cntr = 1
307        ##  F.write('\n')
308        F.flush()
309        F.close()
310        del arr
311        if not appendlist:
312            print('exported to %s' % fname)
313
314    def exportLabelledArrayWithHeader2CSV(self, arr, names, header, fname):
315        """
316        Export an array with row names and header to fname.csv
317
318         - *arr* the an array like object
319         - *names* the list of row names
320         - *header* the list of column names
321         - *fname* the output filename
322
323        """
324        fname += '.csv'
325        self.exportLabelledArrayWithHeader(arr, names, header, fname, sep=',', format='%f')
326
327    def exportLabelledArray2CSV(self, arr, names, fname):
328        """
329        Export an array with row names to fname.csv
330
331         - *arr* the an array like object
332         - *names* the list of row names
333         - *fname* the output filename
334
335        """
336        fname += '.csv'
337        self.exportLabelledArray(arr, names, fname, sep=',', format='%f')
338
339    def exportArray2CSV(self, arr, fname):
340        """
341        Export an array to fname.csv
342
343         - *arr* the an array like object
344         - *fname* the output filename
345         - *sep* [default=','] the column separator
346
347        """
348        fname += '.csv'
349        self.exportLabelledArray(arr, None, fname, sep=',', format='%f')
350
351
352    def exportLabelledArrayWithHeader2TXT(self, arr, names, header, fname):
353        """
354        Export an array with row names and header to fname.txt
355
356         - *arr* the an array like object
357         - *names* the list of row names
358         - *header* the list of column names
359         - *fname* the output filename
360
361        """
362        fname += '.txt'
363        self.exportLabelledArrayWithHeader(arr, names, header, fname, sep='\t', format='%f')
364
365    def exportLabelledArray2TXT(self, arr, names, fname):
366        """
367        Export an array with row names to fname.txt
368
369         - *arr* the an array like object
370         - *names* the list of row names
371         - *fname* the output filename
372
373        """
374        fname += '.txt'
375        self.exportLabelledArray(arr, names, fname, sep='\t', format='%f')
376
377    def exportArray2TXT(self, arr, fname):
378        """
379        Export an array to fname.txt
380
381         - *arr* the an array like object
382         - *fname* the output filename
383         - *sep* [default=','] the column separator
384
385        """
386        fname += '.txt'
387        self.exportLabelledArray(arr, None, fname, sep='\t', format='%f')
388