def __setitem__(self, name, value): """ Set an option in the local dictionary. Parameters ---------- name : str name of the option. value : - value of the option to be value- and type-checked if declared. """ try: meta = self._dict[name] except KeyError: # The key must have been declared. msg = "Option '{}' cannot be set because it has not been declared." self._raise(msg.format(name), exc_type=KeyError) if meta['deprecation'] is not None and name not in self._deprecation_warning_issued: warn_deprecation(meta['deprecation']) self._deprecation_warning_issued.append(name) if self._read_only: self._raise("Tried to set read-only option '{}'.".format(name), exc_type=KeyError) self._assert_valid(name, value) meta['value'] = value meta['has_been_set'] = True
def __getitem__(self, name): """ Get an option from the dict or declared default. Parameters ---------- name : str name of the option. Returns ------- value : - value of the option. """ # If the option has been set in this system, return the set value try: meta = self._dict[name] if meta['deprecation'] is not None and name not in self._deprecation_warning_issued: warn_deprecation(meta['deprecation']) self._deprecation_warning_issued.append(name) if meta['has_been_set']: return meta['value'] else: self._raise( "Option '{}' is required but has not been set.".format( name)) except KeyError: self._raise("Option '{}' cannot be found".format(name), exc_type=KeyError)
def check_mpi_env(): """ Determine if the environment variable governing MPI usage is set. Returns ------- bool True if MPI is required, False if it's to be skipped, None if not set. """ if 'OPENMDAO_REQUIRE_MPI' in os.environ: warn_deprecation( "Set OPENMDAO_USE_MPI instead of OPENMDAO_REQUIRE_MPI.") mpi_selection = os.environ.get( 'OPENMDAO_USE_MPI', os.environ.get('OPENMDAO_REQUIRE_MPI', None)) # If OPENMDAO_USE_MPI is set to a postive value, the run will fail # immediately if the import fails if str(mpi_selection).lower() in ['always', '1', 'true', 'yes', 'y', 'on']: return True # If set to something else, no import is attempted. if mpi_selection is not None: return False # If unset, the import will be attempted but give no warning if it fails. return None
def factorial(*args): """ Raise a warning stating that the factorial function is deprecated. """ warn_deprecation( "The 'factorial' function is deprecated. " "It is no longer supported for SciPy versions >= 1.5.") return scipy.special.factorial(*args)
def record_system_options(problem): """ Record the system options for all systems in the model. Parameters ---------- problem : Problem The problem for which all its systems' options are to be recorded. """ warn_deprecation("The 'record_system_options' function is deprecated. " "Use 'record_model_options' instead.") record_model_options(problem)
def system_options(self): """ Provide '_system_options' property for backwards compatibility. Returns ------- dict reference to the _system_options attribute. """ warn_deprecation("The system_options attribute is deprecated. " "Use `list_model_options` instead.") return self._system_options
def record_metadata(self, recording_requester): """ Call record_metadata for all recorders. Parameters ---------- recording_requester : object The object that needs its metadata recorded. """ warn_deprecation( "The 'record_metadata' function is deprecated. " "All system and solver options are recorded automatically.")
def system_metadata(self): """ Provide 'system_metadata' property for backwards compatibility. Returns ------- dict reference to the '_system_options' attribute. """ warn_deprecation( "The BaseCaseReader.system_metadata attribute is deprecated. " "Use `list_model_options` instead.") return self._system_options
def get_conversion(old_units, new_units): """ Return conversion factor and offset between old and new units (deprecated). Parameters ---------- old_units : str original units as a string. new_units : str new units to return the value in. Returns ------- (float, float) Conversion factor and offset """ warn_deprecation("'get_conversion' has been deprecated. Use " "'unit_conversion' instead.") return unit_conversion(old_units, new_units)
def simple_warning(msg, category=UserWarning, stacklevel=2): """ Display a simple warning message without the annoying extra line showing the warning call. Parameters ---------- msg : str The warning message. category : class The warning class. stacklevel : int Number of levels up the stack to identify as the warning location. """ warn_deprecation( 'simple_warning is deprecated. Use openmdao.warnings.issue_warning instead.' ) old_format = warnings.formatwarning warnings.formatwarning = _warn_simple_format try: warnings.warn(msg, category, stacklevel) finally: warnings.formatwarning = old_format
def _n2_cmd(options, user_args): """ Process command line args and call n2 on the specified file. Parameters ---------- options : argparse Namespace Command line options. user_args : list of str Command line options after '--' (if any). Passed to user script. """ filename = _to_filename(options.file[0]) if filename.endswith('.py'): # the file is a python script, run as a post_setup hook def _noraise(prob): prob.model._raise_connection_errors = False if options.use_declare_partial_info: warn_deprecation("'--use_declare_partial_info' is now the" " default and the option is ignored.") def _viewmod(prob): n2(prob, outfile=options.outfile, show_browser=not options.no_browser, title=options.title, embeddable=options.embeddable) exit() # could make this command line selectable later hooks._register_hook('setup', 'Problem', pre=_noraise) hooks._register_hook('final_setup', 'Problem', post=_viewmod) ignore_errors(True) _load_and_exec(options.file[0], user_args) else: # assume the file is a recording, run standalone n2(filename, outfile=options.outfile, title=options.title, show_browser=not options.no_browser, embeddable=options.embeddable)
def add_output(self, name, val=1.0, shape=None, units=None, res_units=None, desc='', lower=None, upper=None, ref=None, ref0=None, res_ref=None, tags=None, shape_by_conn=False, copy_shape=None, distributed=None): """ Add an independent variable to this component. Parameters ---------- name : str name of the variable in this component's namespace. val : float or list or tuple or ndarray The initial value of the variable being added in user-defined units. Default is 1.0. shape : int or tuple or list or None Shape of this variable, only required if val is not an array. Default is None. units : str or None Units in which the output variables will be provided to the component during execution. Default is None, which means it has no units. res_units : None This argument is deprecated because it was unused. desc : str description of the variable lower : None This argument is deprecated because it was unused. upper : None This argument is deprecated because it was unused. ref : None This argument is deprecated because it was unused. ref0 : None This argument is deprecated because it was unused. res_ref : None This argument is deprecated because it was unused. tags : str or list of strs User defined tags that can be used to filter what gets listed when calling list_outputs. shape_by_conn : bool If True, shape this output to match its connected input(s). copy_shape : str or None If a str, that str is the name of a variable. Shape this output to match that of the named variable. distributed : bool If True, this variable is a distributed variable, so it can have different sizes/values across MPI processes. """ if res_units is not None: warn_deprecation( f"{self.msginfo}: The 'res_units' argument was used when adding " f"output '{name}'. This argument has been deprecated and will be " "removed in a future version.") if lower is not None: warn_deprecation( f"{self.msginfo}: The 'lower' argument was used when adding " f"output '{name}'. This argument has been deprecated and will be " "removed in a future version.") if upper is not None: warn_deprecation( f"{self.msginfo}: The 'upper' argument was used when adding " f"output '{name}'. This argument has been deprecated and will be " "removed in a future version.") if ref0 is not None: warn_deprecation( f"{self.msginfo}: The 'ref0' argument was used when adding " f"output '{name}'. This argument has been deprecated and will be " "removed in a future version.") if res_ref is not None: warn_deprecation( f"{self.msginfo}: The 'res_ref' argument was used when adding " f"output '{name}'. This argument has been deprecated and will be " "removed in a future version.") if ref is not None: warn_deprecation( f"{self.msginfo}: The 'ref' argument was used when adding " f"output '{name}'. This argument has been deprecated and will be " "removed in a future version.") ref = 1.0 ref0 = 0.0 if res_ref is None: res_ref = ref if tags is None: tags = {'indep_var'} else: tags = make_set(tags) | {'indep_var'} kwargs = { 'shape': shape, 'units': units, 'res_units': res_units, 'desc': desc, 'lower': lower, 'upper': upper, 'ref': ref, 'ref0': ref0, 'res_ref': res_ref, 'tags': tags, 'shape_by_conn': shape_by_conn, 'copy_shape': copy_shape, 'distributed': distributed, } super().add_output(name, val, **kwargs)
def n2(data_source, outfile='n2.html', case_id=None, show_browser=True, embeddable=False, title=None, use_declare_partial_info=False): """ Generate an HTML file containing a tree viewer. Optionally opens a web browser to view the file. Parameters ---------- data_source : <Problem> or str The Problem or case recorder database containing the model or model data. case_id : int, str, or None Case name or index of case in SQL file if data_source is a database. outfile : str, optional The name of the final output file show_browser : bool, optional If True, pop up the system default web browser to view the generated html file. Defaults to True. embeddable : bool, optional If True, gives a single HTML file that doesn't have the <html>, <DOCTYPE>, <body> and <head> tags. If False, gives a single, standalone HTML file for viewing. title : str, optional The title for the diagram. Used in the HTML title. use_declare_partial_info : ignored This option is no longer used because it is now always true. Still present for backwards compatibility. """ # grab the model viewer data model_data = _get_viewer_data(data_source, case_id=case_id) # if MPI is active only display one copy of the viewer if MPI and MPI.COMM_WORLD.rank != 0: return options = {} model_data['options'] = options if use_declare_partial_info: warn_deprecation("'use_declare_partial_info' is now the" " default and the option is ignored.") raw_data = json.dumps(model_data, default=default_noraise).encode('utf8') b64_data = str(base64.b64encode(zlib.compress(raw_data)).decode("ascii")) model_data = 'var compressedModel = "%s";' % b64_data import openmdao openmdao_dir = os.path.dirname(inspect.getfile(openmdao)) vis_dir = os.path.join(openmdao_dir, "visualization/n2_viewer") libs_dir = os.path.join(vis_dir, "libs") src_dir = os.path.join(vis_dir, "src") style_dir = os.path.join(vis_dir, "style") assets_dir = os.path.join(vis_dir, "assets") # grab the libraries, src and style lib_dct = { 'd3': 'd3.v5.min', 'awesomplete': 'awesomplete', 'vk_beautify': 'vkBeautify', 'pako_inflate': 'pako_inflate.min', 'json5': 'json5_2.2.0.min' } libs = read_files(lib_dct.values(), libs_dir, 'js') src_names = \ 'utils', \ 'SymbolType', \ 'N2TreeNode', \ 'ModelData', \ 'N2Style', \ 'N2Window', \ 'N2Layout', \ 'N2MatrixCell', \ 'N2Legend', \ 'N2Matrix', \ 'N2Arrow', \ 'N2Search', \ 'N2Toolbar', \ 'N2Diagram', \ 'NodeInfo', \ 'N2UserInterface', \ 'defaults', \ 'ptN2' srcs = read_files(src_names, src_dir, 'js') style_names = \ 'window', \ 'partition_tree', \ 'n2toolbar-icons', \ 'toolbar', \ 'legend', \ 'awesomplete' styles = read_files((style_names), style_dir, 'css') with open(os.path.join(style_dir, "n2toolbar-icons-font.woff"), "rb") as f: encoded_font = str(base64.b64encode(f.read()).decode("ascii")) with open(os.path.join(style_dir, "logo_png.b64"), "r") as f: logo_png = str(f.read()) with open(os.path.join(assets_dir, "spinner.png"), "rb") as f: waiting_icon = str(base64.b64encode(f.read()).decode("ascii")) with open(os.path.join(assets_dir, "n2toolbar_screenshot_png.b64"), "r") as f: n2toolbar_png = str(f.read()) if title: title = "OpenMDAO Model Hierarchy and N2 diagram: %s" % title else: title = "OpenMDAO Model Hierarchy and N2 diagram" src_names = ('N2ErrorHandling',) head_srcs = read_files(src_names, src_dir, 'js') h = DiagramWriter(filename=os.path.join(vis_dir, "index.html"), title=title, styles=styles, embeddable=embeddable, head_srcs=head_srcs) if (embeddable): h.insert("non-embedded-n2", "embedded-n2") # put all style and JS into index h.insert('{{n2toolbar-icons}}', encoded_font) h.insert('{{logo_png}}', logo_png) h.insert('{{waiting_icon}}', waiting_icon) h.insert('{{n2toolbar_png}}', n2toolbar_png) h.insert('{{om_version}}', openmdao_version) for k, v in lib_dct.items(): h.insert('{{{}_lib}}'.format(k), write_script(libs[v], indent=_IND)) for name, code in srcs.items(): h.insert('{{{}_lib}}'.format(name.lower()), write_script(code, indent=_IND)) h.insert('{{model_data}}', write_script(model_data, indent=_IND)) # Write output file h.write(outfile) if notebook: # display in Jupyter Notebook outfile = os.path.relpath(outfile) if not colab: display(IFrame(src=outfile, width="100%", height=700)) else: display(HTML(outfile)) elif show_browser: # open it up in the browser from openmdao.utils.webview import webview webview(outfile)
def assert_rel_error(test_case, actual, desired, tolerance=1e-15): """ Check relative error. Determine that the relative error between `actual` and `desired` is within `tolerance`. If `desired` is zero, then use absolute error. Parameters ---------- test_case : class:`unittest.TestCase` TestCase instance used for assertions. actual : float, array-like, dict The value from the test. desired : float, array-like, dict The value expected. tolerance : float Maximum relative error ``(actual - desired) / desired``. Returns ------- float The error. """ warn_deprecation("'assert_rel_error' has been deprecated. Use " "'assert_near_equal' instead.") if isinstance(actual, dict) and isinstance(desired, dict): actual_keys = set(actual.keys()) desired_keys = set(desired.keys()) if actual_keys.symmetric_difference(desired_keys): msg = 'Actual and desired keys differ. Actual extra keys: {}, Desired extra keys: {}' actual_extra = actual_keys.difference(desired_keys) desired_extra = desired_keys.difference(actual_keys) test_case.fail(msg.format(actual_extra, desired_extra)) error = 0. for key in actual_keys: try: new_error = assert_rel_error(test_case, actual[key], desired[key], tolerance) error = max(error, new_error) except test_case.failureException as exception: msg = '{}: '.format(key) + str(exception) raise test_case.failureException(msg) from None elif isinstance(actual, float) and isinstance(desired, float): if isnan(actual) and not isnan(desired): test_case.fail('actual nan, desired %s' % desired) if desired != 0: error = (actual - desired) / desired else: error = actual if abs(error) > tolerance: test_case.fail( 'actual %s, desired %s, rel error %s, tolerance %s' % (actual, desired, error, tolerance)) # array values else: actual = np.atleast_1d(actual) desired = np.atleast_1d(desired) if actual.shape != desired.shape: test_case.fail('actual and desired have differing shapes.' ' actual {}, desired {}'.format( actual.shape, desired.shape)) if not np.all(np.isnan(actual) == np.isnan(desired)): if actual.size == 1 and desired.size == 1: test_case.fail('actual %s, desired %s' % (actual, desired)) else: test_case.fail( 'actual and desired values have non-matching nan' ' values') if np.linalg.norm(desired) == 0: error = np.linalg.norm(actual) else: error = np.linalg.norm(actual - desired) / np.linalg.norm(desired) if abs(error) > tolerance: if actual.size < 10 and desired.size < 10: test_case.fail( 'actual %s, desired %s, rel error %s, tolerance %s' % (actual, desired, error, tolerance)) else: test_case.fail( 'arrays do not match, rel error %.3e > tol (%.3e)' % (error, tolerance)) return error