diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 00000000..b1cdfded --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,19 @@ +[bumpversion] +current_version = 4.3.0 +commit = False +tag = False +parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? +serialize = + {major}.{minor}.{patch}-{release} + {major}.{minor}.{patch} + +[bumpversion:file:pycycle/__init__.py] +search = __version__ = '{current_version}' +replace = __version__ = '{new_version}' + +[bumpversion:part:release] +optional_value = rel +values = + dev + rel + diff --git a/example_cycles/high_bypass_turbofan.py b/example_cycles/high_bypass_turbofan.py index 2f86309c..802a25a2 100644 --- a/example_cycles/high_bypass_turbofan.py +++ b/example_cycles/high_bypass_turbofan.py @@ -18,29 +18,29 @@ def initialize(self): def setup(self): #Setup the problem by including all the relavant components here - comp, burner, turbine etc - + #Create any relavent short hands here: design = self.options['design'] - + USE_TABULAR = False - if USE_TABULAR: + if USE_TABULAR: self.options['thermo_method'] = 'TABULAR' self.options['thermo_data'] = pyc.AIR_JETA_TAB_SPEC FUEL_TYPE = 'FAR' - else: + else: self.options['thermo_method'] = 'CEA' self.options['thermo_data'] = pyc.species_data.janaf FUEL_TYPE = 'Jet-A(g)' - + #Add subsystems to build the engine deck: self.add_subsystem('fc', pyc.FlightConditions()) self.add_subsystem('inlet', pyc.Inlet()) - - # Note variable promotion for the fan -- + + # Note variable promotion for the fan -- # the LP spool speed and the fan speed are INPUTS that are promoted: # Note here that promotion aliases are used. Here Nmech is being aliased to LP_Nmech - # check out: http://openmdao.org/twodocs/versions/latest/features/core_features/grouping_components/add_subsystem.html?highlight=alias + # check out: https://openmdao.org/newdocs/versions/latest/features/core_features/working_with_groups/add_subsystem.html?highlight=alias self.add_subsystem('fan', pyc.Compressor(map_data=pyc.FanMap, bleed_names=[], map_extrap=True), promotes_inputs=[('Nmech','LP_Nmech')]) self.add_subsystem('splitter', pyc.Splitter()) @@ -63,14 +63,14 @@ def setup(self): self.add_subsystem('byp_bld', pyc.BleedOut(bleed_names=['bypBld'])) self.add_subsystem('duct15', pyc.Duct()) self.add_subsystem('byp_nozz', pyc.Nozzle(nozzType='CV', lossCoef='Cv')) - + #Create shaft instances. Note that LP shaft has 3 ports! => no gearbox self.add_subsystem('lp_shaft', pyc.Shaft(num_ports=3),promotes_inputs=[('Nmech','LP_Nmech')]) self.add_subsystem('hp_shaft', pyc.Shaft(num_ports=2),promotes_inputs=[('Nmech','HP_Nmech')]) self.add_subsystem('perf', pyc.Performance(num_nozzles=2, num_burners=1)) - + # Now use the explicit connect method to make connections -- connect(, ) - + #Connect the inputs to perf group self.connect('inlet.Fl_O:tot:P', 'perf.Pt2') self.connect('hpc.Fl_O:tot:P', 'perf.Pt3') @@ -78,7 +78,7 @@ def setup(self): self.connect('inlet.F_ram', 'perf.ram_drag') self.connect('core_nozz.Fg', 'perf.Fg_0') self.connect('byp_nozz.Fg', 'perf.Fg_1') - + #LP-shaft connections self.connect('fan.trq', 'lp_shaft.trq_0') self.connect('lpc.trq', 'lp_shaft.trq_1') @@ -89,7 +89,7 @@ def setup(self): #Ideally expanding flow by conneting flight condition static pressure to nozzle exhaust pressure self.connect('fc.Fl_O:stat:P', 'core_nozz.Ps_exhaust') self.connect('fc.Fl_O:stat:P', 'byp_nozz.Ps_exhaust') - + #Create a balance component # Balances can be a bit confusing, here's some explanation - # State Variables: @@ -102,7 +102,7 @@ def setup(self): # (lpt_PR) LPT press ratio to balance shaft power on the low spool # (hpt_PR) HPT press ratio to balance shaft power on the high spool # Ref: look at the XDSM diagrams in the pyCycle paper and this: - # http://openmdao.org/twodocs/versions/latest/features/building_blocks/components/balance_comp.html + # http://openmdao.org/newdocs/versions/latest/features/building_blocks/components/balance_comp.html balance = self.add_subsystem('balance', om.BalanceComp()) if design: @@ -116,7 +116,7 @@ def setup(self): self.connect('balance.FAR', 'burner.Fl_I:FAR') self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR') self.promotes('balance', inputs=[('rhs:FAR', 'T4_MAX')]) - + # Note that for the following two balances the mult val is set to -1 so that the NET torque is zero balance.add_balance('lpt_PR', val=1.5, lower=1.001, upper=8, eq_units='hp', use_mult=True, mult_val=-1) @@ -131,11 +131,11 @@ def setup(self): self.connect('hp_shaft.pwr_out_real', 'balance.rhs:hpt_PR') else: - + #In OFF-DESIGN mode we need to redefine the balances: # State Variables: # (W) Inlet mass flow rate to balance core flow area - # LHS: core_nozz.Throat:stat:area == Area from DESIGN calculation + # LHS: core_nozz.Throat:stat:area == Area from DESIGN calculation # # (FAR) Fuel-air ratio to balance Thrust req. # LHS: perf.Fn == RHS: Thrust requirement (set when TF is instantiated) @@ -146,13 +146,13 @@ def setup(self): # (lp_Nmech) LP spool speed to balance shaft power on the low spool # (hp_Nmech) HP spool speed to balance shaft power on the high spool - if self.options['throttle_mode'] == 'T4': + if self.options['throttle_mode'] == 'T4': balance.add_balance('FAR', val=0.017, lower=1e-4, eq_units='degR') self.connect('balance.FAR', 'burner.Fl_I:FAR') self.connect('burner.Fl_O:tot:T', 'balance.lhs:FAR') self.promotes('balance', inputs=[('rhs:FAR', 'T4_MAX')]) - elif self.options['throttle_mode'] == 'percent_thrust': + elif self.options['throttle_mode'] == 'percent_thrust': balance.add_balance('FAR', val=0.017, lower=1e-4, eq_units='lbf', use_mult=True) self.connect('balance.FAR', 'burner.Fl_I:FAR') self.connect('perf.Fn', 'balance.rhs:FAR') @@ -177,12 +177,12 @@ def setup(self): self.connect('balance.hp_Nmech', 'HP_Nmech') self.connect('hp_shaft.pwr_in_real', 'balance.lhs:hp_Nmech') self.connect('hp_shaft.pwr_out_real', 'balance.rhs:hp_Nmech') - + # Specify the order in which the subsystems are executed: - + # self.set_order(['balance', 'fc', 'inlet', 'fan', 'splitter', 'duct4', 'lpc', 'duct6', 'hpc', 'bld3', 'burner', 'hpt', 'duct11', # 'lpt', 'duct13', 'core_nozz', 'byp_bld', 'duct15', 'byp_nozz', 'lp_shaft', 'hp_shaft', 'perf']) - + # Set up all the flow connections: self.pyc_connect_flow('fc.Fl_O', 'inlet.Fl_I') self.pyc_connect_flow('inlet.Fl_O', 'fan.Fl_I') @@ -207,13 +207,13 @@ def setup(self): self.pyc_connect_flow('hpc.cool2', 'lpt.cool2', connect_stat=False) self.pyc_connect_flow('bld3.cool3', 'hpt.cool3', connect_stat=False) self.pyc_connect_flow('bld3.cool4', 'hpt.cool4', connect_stat=False) - + #Specify solver settings: newton = self.nonlinear_solver = om.NewtonSolver() newton.options['atol'] = 1e-8 # set this very small, so it never activates and we rely on atol - newton.options['rtol'] = 1e-99 + newton.options['rtol'] = 1e-99 newton.options['iprint'] = 2 newton.options['maxiter'] = 50 newton.options['solve_subsystems'] = True @@ -318,7 +318,7 @@ def setup(self): self.set_input_defaults('DESIGN.HP_Nmech', 14705.7, units='rpm') # --- Set up bleed values ----- - + self.pyc_add_cycle_param('inlet.ram_recovery', 0.9990) self.pyc_add_cycle_param('duct4.dPqP', 0.0048) self.pyc_add_cycle_param('duct6.dPqP', 0.0101) @@ -346,7 +346,7 @@ def setup(self): self.pyc_add_cycle_param('lpt.cool2:frac_P', 0.0) self.pyc_add_cycle_param('hp_shaft.HPX', 250.0, units='hp') - self.od_pts = ['OD_full_pwr', 'OD_part_pwr'] + self.od_pts = ['OD_full_pwr', 'OD_part_pwr'] self.od_MNs = [0.8, 0.8] self.od_alts = [35000.0, 35000.0] @@ -394,20 +394,20 @@ def setup(self): prob.set_val('DESIGN.hpc.PR', 9.369) prob.set_val('DESIGN.hpc.eff', 0.8707) - + prob.set_val('DESIGN.hpt.eff', 0.8888) prob.set_val('DESIGN.lpt.eff', 0.8996) - + prob.set_val('DESIGN.fc.alt', 35000., units='ft') prob.set_val('DESIGN.fc.MN', 0.8) - + prob.set_val('DESIGN.T4_MAX', 2857, units='degR') - prob.set_val('DESIGN.Fn_DES', 5900.0, units='lbf') + prob.set_val('DESIGN.Fn_DES', 5900.0, units='lbf') prob.set_val('OD_full_pwr.T4_MAX', 2857, units='degR') prob.set_val('OD_part_pwr.PC', 0.8) - + # Set initial guesses for balances prob['DESIGN.balance.FAR'] = 0.025 prob['DESIGN.balance.W'] = 100. @@ -416,15 +416,15 @@ def setup(self): prob['DESIGN.fc.balance.Pt'] = 5.2 prob['DESIGN.fc.balance.Tt'] = 440.0 - + for pt in ['OD_full_pwr', 'OD_part_pwr']: # initial guesses prob[pt+'.balance.FAR'] = 0.02467 prob[pt+'.balance.W'] = 300 prob[pt+'.balance.BPR'] = 5.105 - prob[pt+'.balance.lp_Nmech'] = 5000 - prob[pt+'.balance.hp_Nmech'] = 15000 + prob[pt+'.balance.lp_Nmech'] = 5000 + prob[pt+'.balance.hp_Nmech'] = 15000 prob[pt+'.hpt.PR'] = 3. prob[pt+'.lpt.PR'] = 4. prob[pt+'.fan.map.RlineMap'] = 2.0 @@ -437,16 +437,16 @@ def setup(self): prob.set_solver_print(level=2, depth=1) flight_env = [(0.8, 35000), (0.7, 35000), (0.55, 35000), (0.46, 35000), (0.4, 35000), - (0.4, 20000), (0.6, 20000), (0.8, 20000), + (0.4, 20000), (0.6, 20000), (0.8, 20000), (0.8, 10000), (0.6, 10000), (0.4, 10000), (0.2, 10000), (0.001, 10000), (.001, 1000), (0.2, 1000), (0.4, 1000), (0.6, 1000), (0.6, 0), (0.4, 0), (0.2, 0), (0.001, 0)] viewer_file = open('hbtf_view.out', 'w') first_pass = True - for MN, alt in flight_env: + for MN, alt in flight_env: - # NOTE: You never change the MN,alt for the + # NOTE: You never change the MN,alt for the # design point because that is a fixed reference condition. print('***'*10) @@ -454,26 +454,26 @@ def setup(self): print('***'*10) prob['OD_full_pwr.fc.MN'] = MN prob['OD_full_pwr.fc.alt'] = alt - + prob['OD_part_pwr.fc.MN'] = MN prob['OD_part_pwr.fc.alt'] = alt - for PC in [1, 0.9, 0.8, .7]: + for PC in [1, 0.9, 0.8, .7]: print(f'## PC = {PC}') prob['OD_part_pwr.PC'] = PC prob.run_model() - if first_pass: + if first_pass: viewer(prob, 'DESIGN', file=viewer_file) - first_pass = False + first_pass = False viewer(prob, 'OD_part_pwr', file=viewer_file) # run throttle back up to full power - for PC in [1, 0.85]: + for PC in [1, 0.85]: prob['OD_part_pwr.PC'] = PC prob.run_model() - + print() print("Run time", time.time() - st) diff --git a/pycycle/__init__.py b/pycycle/__init__.py index bc0e8d6f..e9655e52 100644 --- a/pycycle/__init__.py +++ b/pycycle/__init__.py @@ -1 +1 @@ -__version__ = '4.2.1' \ No newline at end of file +__version__ = '4.3.0' \ No newline at end of file diff --git a/pycycle/docs/index.rst b/pycycle/docs/index.rst index c6699faf..67489b46 100644 --- a/pycycle/docs/index.rst +++ b/pycycle/docs/index.rst @@ -9,11 +9,11 @@ pyCycle is a open-source thermodynamic cycle analysis tool designed integrating The pyCycle project implements 1D thermodynamic cycle analysis equations similar to the NPSS code and has been validated against this tool. While the thermodynamic equations are similar to NPSS and other available cycle analysis tools, pyCycle is focused on applying advanced methods for supporting gradient-based optimization through the implementation of analytic derivatives. This feature enables efficient exploration of large design spaces when pyCycle is coupled with other disciplinary analysis tools. -.. warning:: +.. warning:: - pyCycle is built on top of OpenMDAO and relies extensively its linear and nonlinear solver library. + pyCycle is built on top of OpenMDAO and relies extensively its linear and nonlinear solver library. pyCycle was also designed with a user interface that is very similar to the NPSS cycle modeling library. - If you're not comfortable with either OpenMDAO or NPSS, then you may find this library difficult to understand and use. + If you're not comfortable with either OpenMDAO or NPSS, then you may find this library difficult to understand and use. Installation ************ @@ -24,13 +24,13 @@ Installation of pyCycle requires two pieces of software. First, if you do not h pip install pycycle -.. _OpenMDAO Getting Started: http://openmdao.org/twodocs/versions/latest/getting_started/index.html +.. _OpenMDAO Getting Started: https://openmdao.org/newdocs/versions/latest/getting_started/getting_started.html Tutorials ********** -This section provides several tutorials showing how to build thermodynamic cycle models in pyCycle. -For users unfamiliar with OpenMDAO, a review of the OpenMDAO User Guide is highly recommended before completing the pyCycle tutorials. +This section provides several tutorials showing how to build thermodynamic cycle models in pyCycle. +For users unfamiliar with OpenMDAO, a review of the OpenMDAO User Guide is highly recommended before completing the pyCycle tutorials. The tutorials in this section will demonstrate how models are constructed and executed in pyCycle, starting with a simple turboject then moving to a more complicated turbofan model. Additional models showing more features available with pyCycle are provided in the Examples section. @@ -40,14 +40,14 @@ Additional models showing more features available with pyCycle are provided in t :name: tutorials tutorials/index.rst - + Reference Guide **************** The reference guide intended for users looking for explanation of a particular feature in detail or documentation of the arguments/options/settings for a specific cycle element, map or viewer. -.. toctree:: - :maxdepth: 1 +.. toctree:: + :maxdepth: 1 :name: reference_guide reference_guide/elements/index.rst @@ -56,21 +56,12 @@ The reference guide intended for users looking for explanation of a particular f -Examples +Examples ******** The examples in this section provide a more comprehensive demsonstration of the features of pyCycle and advanced modeling methods. -.. toctree:: - :maxdepth: 1 +.. toctree:: + :maxdepth: 1 :name: examples examples/index.rst - - - - - - - - - diff --git a/release_notes.md b/release_notes.md index 8b714a7f..a700e88e 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,32 +1,106 @@ -#3.9.9 + +*********************************** +# Release Notes for 4.3.0 + +Mar 27, 2025 + +* Clarified how to test example cycles & made fixes to some related test scripts [#83](https://github.com/OpenMDAO/pyCycle/pull/83) +* Fix for SolverWarning on high_bypass_turbofan.py [#80](https://github.com/OpenMDAO/pyCycle/pull/80) +* Remove cast conversion of an array with ndim > 0 to scalar [#77](https://github.com/OpenMDAO/pyCycle/pull/77) +* Added missing design off design area connection in burner [#62](https://github.com/OpenMDAO/pyCycle/pull/62) +* For tabular aero, use the 3d-slinear if possible. [#59](https://github.com/OpenMDAO/pyCycle/pull/59) +* changed several places where np.seterr was being called in order to keep the changes localized. [#58](https://github.com/OpenMDAO/pyCycle/pull/58) +* fix tests that used component as model [#57](https://github.com/OpenMDAO/pyCycle/pull/57) +* Add a GitHub Actions test workflow [#56](https://github.com/OpenMDAO/pyCycle/pull/56) +* replace deprecated 'value' keyword with 'val' [#55](https://github.com/OpenMDAO/pyCycle/pull/55) +* Fixed incorrect ordering in compressor viewer [#54](https://github.com/OpenMDAO/pyCycle/pull/54) + + + +*********************************** +# Release Notes for 4.2.1 + +Jan 25, 2022 + +* updated setup.py with description and dynamic version + +*********************************** +# Release Notes for 4.2.0 + +Jan 25, 2022 + +* changed the package name to om-pycycle for release on pypi by @swryan in https://github.com/OpenMDAO/pyCycle/pull/52 + +*********************************** +# Release Notes for 4.1.2 + +Jan 24, 2022 + +* updated setup.py with all modules/data and added optional test dependency by @swryan in https://github.com/OpenMDAO/pyCycle/pull/51 + +*********************************** +# Release Notes for 4.1.1 + +Jan 21, 2022 + +* Added variables to viewer, removed IVC from compressor and turbine map, and lowered hpt map speed bound by @jdgratz10 in https://github.com/OpenMDAO/pyCycle/pull/49 + +*********************************** +# Release Notes for 4.1.0 + +July 21, 2021 + +* Updating for API changes to OM 3.10 by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/45 + +*********************************** +# Release Notes for 4.0.0 + +July 21, 2021 + +* Code cleanup - removing `n` from flow stations by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/28 +* rename b0 to `composition` by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/29 +* Refactoring of FlowIn component to remove dependence on thermo specific stuff by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/30 +* fix for complex warnings. DO NOT merge this until the openmdao complex vector refactor is merged! by @naylor-b in https://github.com/OpenMDAO/pyCycle/pull/32 +* Mil Spec Option for Inlet by @caflack in https://github.com/OpenMDAO/pyCycle/pull/27 +* fixing n3ref exec-comp by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/33 +* Tabular Thermo!! by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/37 +* fixed the N3 benchmark by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/38 +* Added tabular package to setup by @lamkina in https://github.com/OpenMDAO/pyCycle/pull/39 +* fixing N+3 benchmark by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/40 +* change the way tabular data is loaded, so it only gets imported once by @JustinSGray in https://github.com/OpenMDAO/pyCycle/pull/43 +* updated compressor docstring by @anilyil in https://github.com/OpenMDAO/pyCycle/pull/44 + +*********************************** +# Release Notes for 3.9.9 ** Backwards incompatible API changes ** -The thermo refactorization continues. -A lot more internal modularization happened, -and though it mostly does not impact user facing APIs for model building, -it does affect strongly the way that Elements are coded. -The goal continues to be to change things to make it possible to add swappable thermo but we are not quite there yet. +The thermo refactorization continues. +A lot more internal modularization happened, +and though it mostly does not impact user facing APIs for model building, +it does affect strongly the way that Elements are coded. +The goal continues to be to change things to make it possible to add swappable thermo but we are not quite there yet. -* `Element` base class has been introduced and must be used for anything that contains fluid ports. +* `Element` base class has been introduced and must be used for anything that contains fluid ports. -* `Element` now have a `pyc_setup_output_ports` method that must be implemented to propagate -port setup data downstream. +* `Element` now have a `pyc_setup_output_ports` method that must be implemented to propagate +port setup data downstream. -* `pyc_add_element` has been deprecated. It was just added in V3.4.0, so it had a short but exciting life. -It is not needed any more because the presence of the `Element` class made it possible to handle all the details with the standard `add_subsystem` call. -It seems better to stick to stock OpenMDAO APIs where possible, so thats what we're going to do. +* `pyc_add_element` has been deprecated. It was just added in V3.4.0, so it had a short but exciting life. +It is not needed any more because the presence of the `Element` class made it possible to handle all the details with the standard `add_subsystem` call. +It seems better to stick to stock OpenMDAO APIs where possible, so thats what we're going to do. The old method is getting deprecated, and you'll get a noisy warning. Expect it to go away in V4.0 -#3.4.0 +*********************************** +# Release Notes for 3.4.0 -* new `MPCycle` (stands for MultiPoint Cycle) and `Cycle` classes that you can optionally use to simplify your models and reduce boiler plate code associated with connecting data between design and off-design instances. -* major refactor of the thermodynamics library that won't directly affect your models, but is a major cleanup of the core thermo implementation. Though it is fully backwards compatible with 3.2.0, you may notice some small numerical differences due to slightly different solver structure for the CEA solver. +* new `MPCycle` (stands for MultiPoint Cycle) and `Cycle` classes that you can optionally use to simplify your models and reduce boiler plate code associated with connecting data between design and off-design instances. +* major refactor of the thermodynamics library that won't directly affect your models, but is a major cleanup of the core thermo implementation. Though it is fully backwards compatible with 3.2.0, you may notice some small numerical differences due to slightly different solver structure for the CEA solver. -The thermo refactor has been specifically designed to make it easier to swap between multiple thermodynamics analyses -(i.e. simpler ones than CEA). -No other thermodynamic solvers are currently implemented, but they will be coming in future versions. +The thermo refactor has been specifically designed to make it easier to swap between multiple thermodynamics analyses +(i.e. simpler ones than CEA). +No other thermodynamic solvers are currently implemented, but they will be coming in future versions. -The features that will allow you to select from multiple thermodynamics libraries will be integrated in pyCycle 4.0.0. -This version will likely be slightly backwards incompatible, in terms of how you instantiate the elements. -If possible we'll provide a deprecations, but regardless it should be fairly simple to update to the new APIs. \ No newline at end of file +The features that will allow you to select from multiple thermodynamics libraries will be integrated in pyCycle 4.0.0. +This version will likely be slightly backwards incompatible, in terms of how you instantiate the elements. +If possible we'll provide a deprecations, but regardless it should be fairly simple to update to the new APIs. \ No newline at end of file