1# This file is part of QuTiP: Quantum Toolbox in Python.
2#
3#    Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson.
4#    All rights reserved.
5#
6#    Redistribution and use in source and binary forms, with or without
7#    modification, are permitted provided that the following conditions are
8#    met:
9#
10#    1. Redistributions of source code must retain the above copyright notice,
11#       this list of conditions and the following disclaimer.
12#
13#    2. Redistributions in binary form must reproduce the above copyright
14#       notice, this list of conditions and the following disclaimer in the
15#       documentation and/or other materials provided with the distribution.
16#
17#    3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names
18#       of its contributors may be used to endorse or promote products derived
19#       from this software without specific prior written permission.
20#
21#    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22#    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23#    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24#    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25#    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26#    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27#    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28#    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29#    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30#    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31#    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32###############################################################################
33"""
34This module contains settings for the QuTiP graphics, multiprocessing, and
35tidyup functionality, etc.
36"""
37from __future__ import absolute_import
38# use auto tidyup
39auto_tidyup = True
40# use auto tidyup dims on multiplication
41auto_tidyup_dims = True
42# detect hermiticity
43auto_herm = True
44# general absolute tolerance
45atol = 1e-12
46# use auto tidyup absolute tolerance
47auto_tidyup_atol = 1e-12
48# number of cpus (set at qutip import)
49num_cpus = 0
50# flag indicating if fortran module is installed
51# never used
52fortran = False
53# path to the MKL library
54mkl_lib = None
55# Flag if mkl_lib is found
56has_mkl = False
57# Has OPENMP
58has_openmp = False
59# debug mode for development
60debug = False
61# Running on mac with openblas make eigh unsafe
62eigh_unsafe = False
63# are we in IPython? Note that this cannot be
64# set by the RC file.
65ipython = False
66# define whether log handler should be
67#   - default: switch based on IPython detection
68#   - stream: set up non-propagating StreamHandler
69#   - basic: call basicConfig
70#   - null: leave logging to the user
71log_handler = 'default'
72# Allow for a colorblind mode that uses different colormaps
73# and plotting options by default.
74colorblind_safe = False
75# Sets the threshold for matrix NNZ where OPENMP
76# turns on. This is automatically calculated and
77# put in the qutiprc file.  This value is here in case
78# that failts
79openmp_thresh = 10000
80# Note that since logging depends on settings,
81# if we want to do any logging here, it must be manually
82# configured, rather than through _logging.get_logger().
83try:
84    import logging
85    _logger = logging.getLogger(__name__)
86    _logger.addHandler(logging.NullHandler())
87    del logging  # Don't leak names!
88except:
89    _logger = None
90
91
92def _valid_config(key):
93    if key == "absolute_import":
94        return False
95    if key.startswith("_"):
96        return False
97    val = __self[key]
98    if isinstance(val, (bool, int, float, complex, str)):
99        return True
100    return False
101
102
103_environment_keys = ["ipython", 'has_mkl', 'has_openmp',
104                     'mkl_lib', 'fortran', 'num_cpus']
105__self = locals().copy()  # Not ideal, making an object would be better
106__all_out = [key for key in __self if _valid_config(key)]
107__all = [key for key in __all_out if key not in _environment_keys]
108__default = {key: __self[key] for key in __all}
109__section = "qutip"
110del _valid_config
111__self = locals()
112
113
114def save(file='qutiprc', all_config=True):
115    """
116    Write the settings to a file.
117    Default file is 'qutiprc' which is loaded when importing qutip.
118    File are stored in .qutip directory in the user home.
119    The file can be a full path or relative to home to save elsewhere.
120    If 'all_config' is used, also load other available configs.
121    """
122    from qutip.configrc import write_rc_qset, write_rc_config
123    if all_config:
124        write_rc_config(file)
125    else:
126        write_rc_qset(file)
127
128
129def load(file='qutiprc', all_config=True):
130    """
131    Loads the settings from a file.
132    Default file is 'qutiprc' which is loaded when importing qutip.
133    File are stored in .qutip directory in the user home.
134    The file can be a full path or relative to home to save elsewhere.
135    If 'all_config' is used, also load other available configs.
136    """
137    from qutip.configrc import load_rc_qset, load_rc_config
138    if all_config:
139        load_rc_config(file)
140    else:
141        load_rc_qset(file)
142
143
144def reset():
145    """Hard reset of the qutip.settings values
146    Recompute the threshold for openmp, so it may be slow.
147    """
148    for key in __default:
149        __self[key] = __default[key]
150
151    import os
152    if 'QUTIP_NUM_PROCESSES' in os.environ:
153        num_cpus = int(os.environ['QUTIP_NUM_PROCESSES'])
154    elif 'cpus' in info:
155        import qutip.hardware_info
156        info = qutip.hardware_info.hardware_info()
157        num_cpus = info['cpus']
158    else:
159        try:
160            num_cpus = multiprocessing.cpu_count()
161        except:
162            num_cpus = 1
163    __self["num_cpus"] = num_cpus
164
165    try:
166        from qutip.cy.openmp.parfuncs import spmv_csr_openmp
167    except:
168        __self["has_openmp"] = False
169        __self["openmp_thresh"] = 10000
170    else:
171        __self["has_openmp"] = True
172        from qutip.cy.openmp.bench_openmp import calculate_openmp_thresh
173        thrsh = calculate_openmp_thresh()
174        __self["openmp_thresh"] = thrsh
175
176    try:
177        __IPYTHON__
178        __self["ipython"] = True
179    except:
180        __self["ipython"] = False
181
182    from qutip._mkl.utilities import _set_mkl
183    _set_mkl()
184
185
186def __repr__():
187    out = "qutip settings:\n"
188    longest = max(len(key) for key in __all_out)
189    for key in __all_out:
190        out += "{:{width}} : {}\n".format(key, __self[key], width=longest)
191    return out
192