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
20from .version import __version__
21
22__doc__ = """
23            PySCeS: the Python Simulator for Cellular Systems
24            -------------------------------------------------
25            PySCeS is developed by the Triple-J Group for Molecular Cell Physiology
26            in order to try model and understand the complex processes and systems
27            which make up the living cell. PySCeS features, amongst other things:
28
29            - A text based Model Description Language.
30            - A structural analysis module.
31            - Integrators for time simulation
32            - Non-linear solvers for steady-state analysis
33            - A module for performing Metabolic Control Analysis
34            - A bifurcation module for systems which exhibit multiple steady states
35            - A variety of extra utilites for parameter scans, data output and plotting.
36            - A dynamic module loading framework.
37            - SBML import and export capability.
38            """
39
40import os, time
41from pkg_resources import get_build_platform
42from . import PyscesConfig
43from . import PyscesParse
44from . import PyscesLink as link
45from . import codeutil
46from . import PyscesSED as SED
47
48from .PyscesUtils import str2bool
49from .PyscesModelMap import ModelMap
50
51#TODO get rid unused imports
52from .PyscesWeb import PyscesHTML
53html = PyscesHTML()
54
55DEBUG = False
56
57inipath = None
58lpath = None
59install_dir = None
60output_dir = None
61model_dir = None
62pitcon_switch = False
63nleq2_switch = False
64__USE_MATPLOTLIB__ = True
65__MATPLOTLIB_BACKEND__ = 'TkAgg'
66__USE_GNUPLOT__ = False
67__SILENT_START__ = False
68
69extra_dll_dir = os.path.join(os.path.dirname(__file__), '.libs')
70if os.sys.platform=='win32' and os.path.isdir(extra_dll_dir):
71    os.environ["PATH"] += os.pathsep + extra_dll_dir
72    if hasattr(os, 'add_dll_directory'):
73        os.add_dll_directory(extra_dll_dir)
74
75if os.sys.platform == 'win32':
76    __PyscesConfigDefault = PyscesConfig.__DefaultWin
77else:
78    __PyscesConfigDefault = PyscesConfig.__DefaultPosix
79
80if DEBUG: print(time.strftime('1-%H:%M:%S'))
81
82eggdir = 'pysces-%s-py%s.%s-%s.egg' %(__version__, os.sys.version_info[0],\
83os.sys.version_info[1], get_build_platform())
84for path in os.sys.path:
85    chkPath = path.split(os.path.sep)[-1]
86    if chkPath == 'pysces' and path != os.getcwd():
87        install_dir = path
88        inipath = os.path.join(install_dir, 'pyscfg.ini')
89        break
90    elif chkPath == eggdir:
91        install_dir = os.path.join(path, 'pysces')
92        inipath = os.path.join(install_dir, 'pyscfg.ini')
93        break
94if inipath == None:
95    for k in os.sys.path_importer_cache:
96        if k.split(os.path.sep)[-1] == 'pysces':
97            install_dir = k
98            inipath = os.path.join(install_dir, 'pyscfg.ini')
99            break
100        elif k.split(os.path.sep)[-1] == eggdir:
101            install_dir = os.path.join(k, 'pysces')
102            inipath = os.path.join(install_dir, 'pyscfg.ini')
103            break
104del eggdir
105if DEBUG: print(time.strftime('2-%H:%M:%S'))
106
107try:
108    __config_dict = PyscesConfig.ReadConfig(inipath, config=__PyscesConfigDefault)
109except Exception as ex:
110    print(ex)
111    print('Cwd', os.getcwd())
112    print('\nWARNING: Cannot read pyscfg.ini using default values\n')
113    __config_dict = __PyscesConfigDefault
114
115# Read config
116for key in __config_dict:
117    if key == 'pitcon':
118        pitcon_switch = str2bool(__config_dict[key])
119    elif key == 'nleq2':
120        nleq2_switch = str2bool(__config_dict[key])
121    elif key == 'matplotlib':
122        __USE_MATPLOTLIB__ = str2bool(__config_dict[key])
123    elif key == 'matplotlib_backend':
124        __MATPLOTLIB_BACKEND__ = __config_dict[key]
125    elif key == 'gnuplot':
126        __USE_GNUPLOT__ = str2bool(__config_dict[key])
127    elif key == 'gnuplot_dir':
128        GNUPLOT_DIR = __config_dict[key]
129        if GNUPLOT_DIR == 'None':
130            GNUPLOT_DIR = None
131    elif key == 'silentstart':
132        __SILENT_START__ = str2bool(__config_dict[key])
133assert inipath != None, '\nNo configuration file found'
134
135if DEBUG: print(time.strftime('3-%H:%M:%S'))
136
137__userdict = None
138if os.sys.platform != 'win32':
139    if os.path.exists(os.path.join(os.path.expanduser('~'),'Pysces','.pys_usercfg.ini')):
140        __userdict = PyscesConfig.ReadConfig(os.path.join(os.path.expanduser('~'),'Pysces','.pys_usercfg.ini'), PyscesConfig.__DefaultPosixUsr)
141    else:
142        if not os.path.exists(os.path.join(os.path.expanduser('~'),'Pysces')):
143            os.makedirs(os.path.join(os.path.expanduser('~'),'Pysces'))
144        PyscesConfig.WriteConfig(os.path.join(os.path.expanduser('~'),'Pysces','.pys_usercfg.ini'),config=PyscesConfig.__DefaultPosixUsr, section='Pysces')
145        __userdict = PyscesConfig.ReadConfig(os.path.join(os.path.expanduser('~'),'Pysces','.pys_usercfg.ini'), PyscesConfig.__DefaultPosixUsr)
146else:
147    if os.path.exists(os.path.join(os.getenv('HOMEDRIVE')+os.path.sep,'Pysces','.pys_usercfg.ini')):
148        __userdict = PyscesConfig.ReadConfig(os.path.join(os.getenv('HOMEDRIVE')+os.path.sep,'Pysces','.pys_usercfg.ini'), PyscesConfig.__DefaultWinUsr)
149    elif os.path.exists(os.path.join(os.getenv('USERPROFILE'),'Pysces','.pys_usercfg.ini')):
150        __userdict = PyscesConfig.ReadConfig(os.path.join(os.getenv('USERPROFILE'),'Pysces','.pys_usercfg.ini'), PyscesConfig.__DefaultWinUsr)
151    else:
152        if not os.path.exists(os.path.join(os.getenv('USERPROFILE'),'Pysces')):
153            os.makedirs(os.path.join(os.getenv('USERPROFILE'),'Pysces'))
154        PyscesConfig.WriteConfig(os.path.join(os.getenv('USERPROFILE'),'Pysces','.pys_usercfg.ini'), config=PyscesConfig.__DefaultWinUsr, section='Pysces')
155        __userdict = PyscesConfig.ReadConfig(os.path.join(os.getenv('USERPROFILE'),'Pysces','.pys_usercfg.ini'), PyscesConfig.__DefaultWinUsr)
156for key in __userdict:
157    if key == 'output_dir':
158        output_dir = __userdict[key]
159        if not os.path.exists(__userdict[key]):
160            os.makedirs(__userdict[key])
161    elif key == 'model_dir':
162        model_dir = __userdict[key]
163        if not os.path.exists(__userdict[key]):
164            os.makedirs(__userdict[key])
165    elif key == 'matplotlib':
166        __USE_MATPLOTLIB__ = str2bool(__userdict[key])
167    elif key == 'matplotlib_backend':
168        __MATPLOTLIB_BACKEND__ = __userdict[key]
169    elif key == 'gnuplot':
170        __USE_GNUPLOT__ = str2bool(__userdict[key])
171    elif key == 'gnuplot_dir':
172        GNUPLOT_DIR = __userdict[key]
173        if GNUPLOT_DIR == 'None':
174            GNUPLOT_DIR = None
175    elif key == 'silentstart':
176        __SILENT_START__ = str2bool(__userdict[key])
177assert output_dir != None, '\nNo output directory defined'
178assert model_dir != None, '\nNo output directory defined'
179
180# following is to get the full path when .pys_usercfg.ini specifies CWD as follows:
181# output_dir = ./
182backup_dir = os.getcwd()
183os.chdir(output_dir)
184output_dir = os.getcwd()
185os.chdir(backup_dir)
186os.chdir(model_dir)
187model_dir = os.getcwd()
188os.chdir(backup_dir)
189
190del PyscesConfig
191
192if DEBUG: print(time.strftime('4-%H:%M:%S'))
193
194# initialise pysces.interface.*
195try:
196    from . import PyscesInterfaces
197    interface = PyscesInterfaces.Core2interfaces()
198except Exception as ex:
199    print('INFO: pysces.interface.* not available')
200    print(ex)
201    interface = None
202
203# initialise pysces.plt.*
204from . import PyscesPlot2
205gplt = None
206mplt = None
207if __USE_MATPLOTLIB__:
208    try:
209        mplt = PyscesPlot2.MatplotlibUPI(work_dir=output_dir, backend=__MATPLOTLIB_BACKEND__)
210        if not __SILENT_START__:
211            print('Matplotlib interface loaded (pysces.plt.m)')
212    except Exception as ex:
213        print('Matplotlib interface not available')
214        if DEBUG: print(ex)
215        __USE_MATPLOTLIB__ = False
216if __USE_GNUPLOT__:
217    if GNUPLOT_DIR == None or not os.path.exists(GNUPLOT_DIR):
218        print('''GnuPlot has been enabled but the path to the executable has
219not been defined (or does not exist). Please set the "gnuplot_dir" key
220in your pyscfg.ini file.
221        ''')
222    else:
223        try:
224            if DEBUG: print(GNUPLOT_DIR)
225            gplt = PyscesPlot2.GnuPlotUPI(work_dir=output_dir, gnuplot_dir=GNUPLOT_DIR)
226            if not __SILENT_START__:
227                print('GnuPlot interface loaded (pysces.plt.g)')
228        except Exception as ex:
229            print('GnuPlot interface not available')
230            if DEBUG: print(ex)
231            __USE_GNUPLOT__ = False
232
233plt = None
234if __USE_MATPLOTLIB__ or __USE_GNUPLOT__:
235    plt = PyscesPlot2.PyscesUPI()
236if __USE_MATPLOTLIB__ and not __USE_GNUPLOT__:
237    plt.p_setInterface('matplotlib', mplt)
238elif __USE_GNUPLOT__ and not __USE_MATPLOTLIB__:
239    plt.p_setInterface('gnuplot', gplt)
240elif __USE_GNUPLOT__ and __USE_MATPLOTLIB__:
241    plt.p_setInterface('matplotlib', mplt)
242    plt.p_setInterface('gnuplot', gplt)
243    plt.p_deactivateInterface('gnuplot')
244
245if DEBUG: print(time.strftime('5-%H:%M:%S'))
246
247alt_import = False
248alt_import_pitcon = False
249alt_import_nleq2 = False
250if os.sys.platform == 'win32':
251    if pitcon_switch:
252        os.sys.path.append(os.path.join(install_dir,'pitcon'))
253        try:
254            from .pitcon import pitcon as pitcon
255            if not __SILENT_START__:
256                print('Continuation routines available')
257        except Exception as ex:
258            try:
259                os.environ['path'] = '%s;%s' % (os.path.join(install_dir,'win32'), os.environ['path'])
260                from .pitcon import pitcon as pitcon
261                if not __SILENT_START__:
262                    print('Continuation routines available')
263            except Exception as ex:
264                #print 'Attempting alternate pitcon import ...'
265                #alt_import = True
266                #alt_import_pitcon = True
267                print(ex)
268                print('INFO: Pitcon import failed: continuation not available')
269
270
271    if nleq2_switch:
272        os.sys.path.append(os.path.join(install_dir,'nleq2'))
273        try:
274            from .nleq2 import nleq2 as nleq2
275            if not __SILENT_START__:
276                print('NLEQ2 routines available')
277        except Exception as ex:
278            try:
279                os.environ['path'] = '%s;%s' % (os.path.join(install_dir,'win32'), os.environ['path'])
280                from .nleq2 import nleq2 as nleq2
281                if not __SILENT_START__:
282                    print('NLEQ2 routines available')
283            except Exception as ex:
284                #print 'Attempting alternate nleq2 import ...'
285                #alt_import = True
286                #alt_import_nleq2 = True
287                print(ex)
288                print('INFO: NLEQ2 import failed: option not available')
289else:
290    if pitcon_switch:
291        os.sys.path.append(os.path.join(install_dir,'pitcon'))
292        try:
293            from .pitcon import pitcon as pitcon
294            if not __SILENT_START__:
295                print('Pitcon routines available')
296        except Exception as ex:
297            #print ex
298            alt_import = True
299            alt_import_pitcon = True
300
301            print('Attempting alternate pitcon import ...')
302    if nleq2_switch:
303        os.sys.path.append(os.path.join(install_dir,'nleq2'))
304        try:
305            from .nleq2 import nleq2 as nleq2
306            if not __SILENT_START__:
307                print('NLEQ2 routines available')
308        except Exception as ex:
309            #print ex
310            alt_import = True
311            alt_import_nleq2 = True
312            print('Attempting alternate nleq2 import ...')
313
314if DEBUG: print(time.strftime('6-%H:%M:%S'))
315
316if alt_import:
317    savedir = os.getcwd()
318    for tpath in os.sys.path:
319        if alt_import_pitcon:
320            try:
321                if os.path.exists(os.path.join(tpath,'pysces','pitcon')) and tpath != '':
322                    os.chdir(os.path.join(tpath,'pysces','pitcon'))
323                    from . import pitcon
324                    if not __SILENT_START__:
325                        print('Continuation routines available (A)')
326            except Exception as ex:
327                print(ex)
328                print('INFO: Alternate pitcon import failed: continuation not available')
329        if alt_import_nleq2:
330            try:
331                if os.path.exists(os.path.join(tpath,'pysces','nleq2')) and tpath != '':
332                    os.chdir(os.path.join(tpath,'pysces','nleq2'))
333                    from . import nleq2
334                    if not __SILENT_START__:
335                        print('NLEQ2 routines available (A)')
336            except Exception as ex:
337                print(ex)
338                nleq2_switch = False
339                print('INFO: Alternate NLEQ2 import failed: option not available')
340    os.chdir(savedir)
341
342if DEBUG: print(time.strftime('7-%H:%M:%S'))
343
344# check for libsbml
345try:
346    import libsbml as SBML
347    if not __SILENT_START__:
348        print("SBML support available")
349except ImportError as ex:
350    SBML = None
351    print(ex)
352    print("INFO: No SBML library found, SBML support not available")
353
354
355# This has to come at the end
356from .PyscesModel import PysMod as model
357from .PyscesModel import ScanDataObj as ScanDataObj
358PyscesModel.interface = interface
359from .PyscesTest import PyscesTest as test
360write = None
361try:
362    from .PyscesUtils import WriteOutput
363    write = WriteOutput()
364    del WriteOutput
365except ImportError as ex:
366    pass
367
368from .PyscesScan import PITCONScanUtils, Scanner
369
370try:
371    from .RateChar import RateChar
372    if not __SILENT_START__:
373        print("RateChar is available")
374except Exception as ex:
375    RateChar = None
376    #print "RateChar not available"
377
378# ParScanner import
379try:
380    from .PyscesParScan import ParScanner
381    if not __SILENT_START__:
382        print("Parallel scanner is available")
383except ImportError as ex:
384    ParScanner = None
385    print(ex)
386    print("INFO: Parallel scanner not available")
387
388if DEBUG: print(time.strftime('9-%H:%M:%S'))
389
390if not __SILENT_START__:
391    print('\nPySCeS environment\n******************')
392    print('pysces.model_dir = ' + model_dir)
393    print('pysces.output_dir = ' + output_dir)
394
395    print('\n\n***********************************************************************')
396    print('* Welcome to PySCeS (' + __version__ + ') - Python Simulator for Cellular Systems   *')
397    print('*                http://pysces.sourceforge.net                        *')
398    ##  print '*                       Somewhere In Time                             *'
399    print('* Copyright(C) B.G. Olivier, J.M. Rohwer, J.-H.S. Hofmeyr, 2004-2020  *')
400    print('* Triple-J Group for Molecular Cell Physiology                        *')
401    print('* Stellenbosch University, ZA and VU University Amsterdam, NL         *')
402    print('* PySCeS is distributed under the PySCeS (BSD style) licence, see     *')
403    print('* LICENCE.txt (supplied with this release) for details                *')
404    ##  print '*                 ** Read about PySCeS **                             *'
405    print('* Please cite PySCeS with: doi:10.1093/bioinformatics/bti046          *')
406    print('***********************************************************************')
407
408try:
409    del os, key, gplt, mplt
410except Exception as ex:
411    print(ex)
412    print('\n\nOops I did it again error ...\n\n')
413if DEBUG: print(time.strftime('10-%H:%M:%S'))
414