Created
February 27, 2020 10:12
-
-
Save jmarrec/e1294ba5be61a061b500337d96dd2417 to your computer and use it in GitHub Desktop.
Create_UniqueModelObject_Clone_tests.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "import re", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": "# Find UniqueModelObjects\n\nBecause UniqueModelObjects aren't a specific class, we first need to find which one are supposed to be Unique" | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": "## Grep on SWIG_UNIQUEMODELOBJECT" | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "s = !/bin/grep \"SWIG_UNIQUE\" *.i", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "re_swig = re.compile(r'.*.i:\\s*SWIG_UNIQUEMODELOBJECT\\((.*)\\);')", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "uniqueClasses = [m.groups()[0] for x in s if (m := re_swig.match(x))]", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "# 'Model_Common_Include.i:%define SWIG_UNIQUEMODELOBJECT(_name)', is throw-off\nlen(s), len(uniqueClasses)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": "## Using IDD property `\\unique-object` (using CLI)" | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "unique_objs1 = !$os_build_rel/Products/openstudio -e \"factory = OpenStudio::IddFileAndFactoryWrapper.new('OpenStudio'.to_IddFileType); factory.objects.select{|o| o.properties.unique}.each{|o| puts o.name.to_s}\"\n\n# Actually, there's alread a method to do that\nunique_objs = !$os_build_rel/Products/openstudio -e \"factory = OpenStudio::IddFileAndFactoryWrapper.new('OpenStudio'.to_IddFileType); factory.uniqueObjects.each{|o| puts o.name.to_s}\"", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "len(unique_objs1), len(unique_objs)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": "## Differences between the two methods" | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "cli_uniqueClasses = [x.replace('OS:', '').replace(':', '') for x in unique_objs]", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "set(cli_uniqueClasses) - set(uniqueClasses)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "set(uniqueClasses) - set(cli_uniqueClasses)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": "# Find their base class to see if we could implement a \"UniqueModelObject\" class" | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "re_base_class = re.compile(r'class\\s+(?:MODEL_API )?(?P<ClassName>.*?)\\s+:\\s+public\\s+(?P<BaseClass>.*?)\\s*{')", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "result = []\nfor obj in unique_objs:\n className = obj.replace('OS:', '').replace(':', '')\n try:\n with open(f\"{className}.hpp\", 'r') as f:\n content = f.read()\n re_base_class = re.compile(r'class\\s+(?:MODEL_API )?(?P<ClassName>' + className + ')\\s+:\\s+public\\s+(?P<BaseClass>.*?)\\s*{')\n if (m := re_base_class.search(content)):\n d = m.groupdict()\n d['IddObjectType'] = obj\n print(d)\n result.append(d)\n except FileNotFoundError:\n print(f\"File not found for {obj}\")\n \n# Sort it, for import in correct order\nresult.sort(key=lambda d: d['ClassName'])", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "from collections import Counter\nCounter([d['BaseClass'] for d in result])", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "list(filter(lambda d: d['BaseClass']=='ParentObject', result))", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "raw", | |
"source": "# With pandas: much nicer, including table representation, but not a STL package\nimport pandas as pd\ndf = pd.DataFrame(result).sort_values(by='BaseClass')\ndf['BaseClass'].value_counts()" | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "raw", | |
"source": "df[df['BaseClass'] == 'ParentObject']" | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": "# Generate a GTest for cloning Unique ModelObjects" | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": "**In the end I only care about the C++ GTest program, but I'm going to use the same program in ruby that I'll run with the CLI so I can test ahead of time whether the GTest would pass or not**" | |
}, | |
{ | |
"metadata": { | |
"scrolled": true, | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "# C++ Test program\ntest_program = \"\"\"\nTEST_F(ModelFixture, {className}_UniqueModelObject_Clone)\n{{\n // create a model to use\n Model model;\n\n // Get the Unique ModelObject\n EXPECT_FALSE(model.getOptionalUniqueModelObject<{className}>());\n {className} {camelClassName} = model.getUniqueModelObject<{className}>();\n EXPECT_TRUE(model.getOptionalUniqueModelObject<{className}>());\n // We use a comment to see if cloning to another model works\n {camelClassName}.setComment(\"Custom Object\");\n\n // clone it into the same model\n {className} {camelClassName}Clone = {camelClassName}.clone(model).cast<{className}>();\n // UniqueModelObject: should be the same as the original\n EXPECT_EQ({camelClassName}, {camelClassName}Clone);\n EXPECT_EQ(\"! Custom Object\", {camelClassName}Clone.comment());\n\n // clone it into a different model\n Model model2;\n EXPECT_FALSE(model2.getOptionalUniqueModelObject<{className}>());\n {className} {camelClassName}Clone2 = {camelClassName}.clone(model2).cast<{className}>();\n EXPECT_TRUE(model2.getOptionalUniqueModelObject<{className}>());\n EXPECT_EQ(\"! Custom Object\", {camelClassName}Clone2.comment());\n}}\n\"\"\"\n\n# Ruby Test program\nruby_test_program = \"\"\"include OpenStudio::Model\n\nmodel = Model.new\n{camelClassName} = model.get{className}\n{camelClassName}.setComment('Custom Object')\n\n{camelClassName}Clone = {camelClassName}.clone(model)\nraise if model.numObjectsOfType('{iddObjectType}'.to_IddObjectType) != 1\nraise if {camelClassName}Clone.comment() != '! Custom Object'\n\nmodel2 = Model.new\nraise if model2.numObjectsOfType('{iddObjectType}'.to_IddObjectType) != 0\n{camelClassName}Clone2 = {camelClassName}.clone(model2)\nraise if model2.numObjectsOfType('{iddObjectType}'.to_IddObjectType) != 1\nraise if {camelClassName}Clone2.comment() != '! Custom Object'\n\"\"\"", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "raw", | |
"source": "# Define variable if need to test\niddObjType = 'OS:ExternalInterface'\ncN = iddObjType.replace('OS:', '').replace(':', '')\nccN = cN[0].lower() + cN[1:]" | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "raw", | |
"source": "# test C++ program\nprint(test_program.format(className=cN, \n camelClassName=ccN))" | |
}, | |
{ | |
"metadata": {}, | |
"cell_type": "raw", | |
"source": "# test Ruby program\nruby_prog = ruby_test_program.format(className=cN,\n camelClassName=ccN,\n iddObjectType=iddObjType)\n\n \n# one_liner = \"; \".join(ruby_prog.splitlines())\n# print(one_liner)\n\n# Could not make that work, so I'll use a file\n# !$os_build_rel/Products/openstudio -e '\"{one_liner}\"'\n\nprint(ruby_prog)\nwith open('temp.rb', 'w') as f:\n f.write(ruby_prog)\n \ncmd_result = !$os_build_rel/Products/openstudio temp.rb\nprint(cmd_result)" | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "header_start = \"\"\"/***********************************************************************************************************************\n* OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the\n* following conditions are met:\n*\n* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following\n* disclaimer.\n*\n* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following\n* disclaimer in the documentation and/or other materials provided with the distribution.\n*\n* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products\n* derived from this software without specific prior written permission from the respective party.\n*\n* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works\n* may not use the \"OpenStudio\" trademark, \"OS\", \"os\", or any other confusingly similar designation without specific prior\n* written permission from Alliance for Sustainable Energy, LLC.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED\n* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n***********************************************************************************************************************/\n\n#include <gtest/gtest.h>\n#include \"ModelFixture.hpp\"\n\n#include \"../Model.hpp\"\n#include \"../Model_Impl.hpp\"\n\"\"\"\n\n\nheader_className = '''#include \"../{className}.hpp\"\n#include \"../{className}_Impl.hpp\"\n'''\n\nheader_end = \"\"\"\nusing namespace openstudio;\nusing namespace openstudio::model;\n\n\"\"\"", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "# I define it here, so that on subsequent runs of the below cell it's already populated to avoid re-rerunning ruby\nprint_at_end = []\nalreadyCheckedInRuby = False", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"metadata": { | |
"scrolled": false, | |
"trusted": false | |
}, | |
"cell_type": "code", | |
"source": "with open('test/UniqueModelObject_GTest.cpp', 'w') as gtest:\n gtest.write(header_start)\n\n for d in result:\n gtest.write(header_className.format(className = d['ClassName']))\n \n gtest.write(header_end)\n\n\n for d in result:\n className = d['ClassName']\n iddObjectType = d['IddObjectType']\n camelClassName = className[0].lower() + className[1:]\n\n # If the list is not already populated, we test via ruby\n if not alreadyCheckedInRuby:\n ruby_prog = ruby_test_program.format(className=className, \n camelClassName=camelClassName,\n iddObjectType=iddObjectType)\n with open('temp.rb', 'w') as f:\n f.write(ruby_prog)\n\n cmd_result = !$os_build_rel/Products/openstudio temp.rb\n # If ruby test failed, we'll print the C++ GTest at end\n if cmd_result:\n print(cmd_result)\n print_at_end.append(d)\n continue\n # If already populated, and found to not work, skip\n elif d in print_at_end:\n print(f\"Skipping {className}, already found to not work\")\n continue\n\n gtest_f = test_program.format(className=className, camelClassName=camelClassName)\n\n gtest.write(gtest_f)\n \n for d in print_at_end:\n className = d['ClassName']\n iddObjectType = d['IddObjectType']\n camelClassName = className[0].lower() + className[1:]\n \n gtest_f = test_program.format(className=className, camelClassName=camelClassName)\n \n gtest.write(\"\\n// TODO: Not working for {className}\".format(className=className))\n gtest.write(\"\\n// \".join(gtest_f.splitlines()))\n gtest.write(\"\\n\")\n \nalreadyCheckedInRuby = True", | |
"execution_count": null, | |
"outputs": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3", | |
"language": "python" | |
}, | |
"language_info": { | |
"name": "python", | |
"version": "3.8.0", | |
"mimetype": "text/x-python", | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"pygments_lexer": "ipython3", | |
"nbconvert_exporter": "python", | |
"file_extension": ".py" | |
}, | |
"toc": { | |
"nav_menu": {}, | |
"number_sections": true, | |
"sideBar": true, | |
"skip_h1_title": false, | |
"base_numbering": 1, | |
"title_cell": "Table of Contents", | |
"title_sidebar": "Contents", | |
"toc_cell": false, | |
"toc_position": {}, | |
"toc_section_display": true, | |
"toc_window_display": false | |
}, | |
"gist": { | |
"id": "", | |
"data": { | |
"description": "Create_UniqueModelObject_Clone_tests.ipynb", | |
"public": true | |
} | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To be placed in
OpenStudio/src/model/