History¶
0.12.3 (2022-09-21)¶
0.12.2 (2022-05-26)¶
New features & API changes¶
0.12.1 (2022-02-25)¶
New features & API changes¶
Simplification of driver
Optimizer:
Before:
from cosapp.drivers import Optimizer
s = SomeSystem('s')
optim = s.add_driver(Optimizer('optim'))
optim.runner.set_objective('cost')
optim.runner.add_unknown(['a', 'b', 'p_in.x'])
# Enter constraints as non-negative expressions:
optim.runner.add_constraints([
"b - a", # b >= a
"a", # a >= 0
"1 - a", # a <= 1
])
optim.runner.add_constraints(
"p_out.y",
inequality = False, # p_out.y == 0
)
s.run_drivers()
After:
optim.set_objective('cost')
optim.add_unknown(['a', 'b', 'p_in.x'])
optim.add_constraints(
"b >= a",
"0 <= a <= 1",
"p_out.y == 0",
)
New, convenient iterators and setters for ports (MR #137):
from cosapp.base import Port, System
class XyzPort(Port):
def setup(self):
self.add_variable('x')
self.add_variable('y')
self.add_variable('z')
class SomeSystem(System):
def setup(self):
self.add_input(XyzPort, 'p_in')
self.add_output(XyzPort, 'p_out')
def compute(self):
self.p_out.set_from(self.p_in) # assign values from `p_in`
self.p_out.z = 0.0
s = SomeSystem('s')
# Multi-variable setter `set_values`
s.p_in.set_values(x=1, y=-0.5, z=0.1)
s.run_once()
# Dict-like (key, value) iterator `items`:
for varname, value in s.p_out.items():
print(f"p_out.{varname} = {value})
Bug fixes and code quality¶
Fix bug in Jacobian computation for negative perturbations (MR #129).
Fix bug in
RunOnceandRunSingleCaserecorders withhold=False(MR #130).Resolve input aliasing in time driver scenarios (MR #135).
Discard empty connectors, and send a warning (MR #132).
Other code quality improvements (MRs #127, #131, #133, #134).
0.12.0 (2022-01-17)¶
New features¶
Implementation of multimode systems and hybrid continuous/discrete time solver (MRs #100, #103, #105-#108, #110-#121):
Possibility to declare events and mode variables in systems.
New method
System.transitiondescribing system transition upon the occurrence of events.Event detection in
ExplicitTimeDriver.
Possibility to specify a stop criterion in time simulation scenarios (MR #107).
Documentation¶
New tutorial on hybrid time simulations and multimode systems (MRs #116 and #120).
Updated build config file following up a bug fix in github.com/readthedocs (MR #109).
0.11.8 (2021-11-24)¶
New features & API evolutions¶
New module
cosapp.base(MR #96) containing base classes for user-defined classes (in particular,Port,SystemandDriver). Also containsBaseConnector, base class for custom connectors (see “User-defined and peer-to-peer connectors” below), as well as CoSApp-specific exceptionsScopeError,UnitErrorandConnectorError. Note:Port,SystemandDrivercan still be imported fromcosapp.ports,cosapp.systemsandcosapp.drivers, respectively.Public API
cosapp.base.SurrogateModelto define custom surrogate models used inSystem.make_surrogate(MR #97). Pre-defined models have been moved to modulecosapp.utils.surrogate_models.System-to-system connections (MR #94).
class LegacyPortToPort(System):
def setup(self):
a = self.add_child(ModelA('a'))
b = self.add_child(ModelB('b'))
# Explicit port-to-port connections
self.connect(a.p_in, b.p_out)
self.connect(a.outwards, b.inwards, {'y': 'x'})
class Alternative(System):
"""Same as `LegacyPortToPort`, with alternative connection syntax"""
def setup(self):
a = self.add_child(ModelA('a'))
b = self.add_child(ModelB('b'))
# Alternative syntax: connect systems, with port or variable mapping
self.connect(a, b, {'p_in': 'p_out', 'y': 'x'})
import numpy
from copy import deepcopy
from cosapp.base import Port, System, BaseConnector
class DeepCopyConnector(BaseConnector):
"""User-defined deep-copy connector"""
def transfer(self) -> None:
source, sink = self.source, self.sink
for target, origin in self.mapping.items():
value = getattr(source, origin)
setattr(sink, target, deepcopy(value))
class CustomPort(Port):
def setup(self):
self.add_variable('x', 0.0)
self.add_variable('y', 1.0)
class Connector(BaseConnector):
"""Connector for peer-to-peer connections"""
def transfer(self) -> None:
source, sink = self.source, self.sink
sink.x = source.y
sink.y = -source.x
class MyModel(System):
def setup(self):
self.add_input(CustomPort, 'p_in')
self.add_output(CustomPort, 'p_out')
self.add_inward('entry', numpy.identity(3))
self.add_outward('exit', numpy.zeros_like(self.entry))
class Assembly(System):
def setup(self):
a = self.add_child(MyModel('a'))
b = self.add_child(MyModel('b'))
self.connect(a, b, {'exit', 'entry'}, cls=DeepCopyConnector)
self.connect(a.p_in, b.p_out) # will use CustomPort.Connector
0.11.7 (2021-09-21)¶
New features¶
Possibility to define unknowns and equations at solver level (MR #65). Minor API evolution facilitating the definition of nonlinear problems and of multi-point design problems.
engine = Turbofan('engine')
solver = engine.add_driver(NonLinearSolver('solver'))
# Add design points:
takeoff = solver.add_child(RunSingleCase('takeoff'))
cruise = solver.add_child(RunSingleCase('cruise'))
# Unknowns defined at solver level regarded as *design* unknowns
solver.add_unknown(['fan.diameter', 'core.turbine.inlet.area'])
# Local off-design equations can be directly defined at case level
takeoff.add_equation('thrust == 1.2e5')
cruise.add_equation('Mach == 0.8')
New recursive iterator
tree()for systems and drivers, yielding all elements in a composite tree (MR #68).
head = CompositeSystem('head')
bottom_to_top = [s.name for s in head.tree()]
top_to_bottom = [s.name for s in head.tree(downwards=True)]
Visitor pattern for composite collections of systems, drivers and ports (MR #68).
from cosapp.patterns.visitor import Visitor, send as send_visitor
class DataCollector(Visitor):
def __init__(self):
self.data = {}
def visit_system(self, system):
key = system.full_name()
self.data.setdefault(key, {})
self.data[key]['children'] = [
child.name for child in system.children.values()
]
send_visitor(self, system.inputs.values())
def visit_port(self, port):
# specify what to do with a port
def visit_driver(self, driver):
# specify what to do with a driver
head = CompositeSystem('head')
collector = DataCollector()
send_visitor(collector, head.tree())
print(collector.data)
Bug fixes and code quality¶
Improved tests on clean/dirty status (MR #66).
Bug fix in tutorial notebook on validation (MR #67).
Code quality improvements (MR #69).
Make
System.exec_ordera view onSystem.childrendictionary keys, rather than an independent attribute (MR #70). Execution order can still be specified, via a dedicated setter forexec_order.Fix solver bugs occurring when system structure changes (MR #73).
0.11.6 (2021-06-25)¶
Bug fixes and code quality¶
0.11.5 (2021-05-07)¶
New features¶
**New binder container**, allowing anyone to run interactively the tutorials used in the online documentation (MR #30 and #36).
Deferred equations to set targets:
New method
add_target, defining a deferred equation on on a target variable (MR #48). In effect,add_targetcreates an equation whose right-hand side is evaluated dynamically prior to each execution of the nonlienar solver.In the example below, the feature is illustrated in design mode. Outward
zis a function of two independent variablesxandy. When design method'target_z'is activated, the actual value ofz, set interactively, is used as a target value, with unknowny:
class SystemWithTarget(System):
def setup(self):
self.add_inward('x', 1.0)
self.add_inward('y', 1.0)
self.add_outward('z', 1.0)
# Define design problem with a target on `z`
design = self.add_design_method('target_z')
design.add_unknown('y').add_target('z')
def compute(self):
self.z = self.x * self.y**2
s = SystemWithTarget('s')
solver = s.add_driver(NonLinearSolver('solver', tol=1e-9))
# Activate design method 'target_z': outward `z` becomes a target
solver.runner.design.extend(s.design_methods['target_z'])
s.x = 0.5
s.y = 0.5
s.z = 2.0 # set target
s.run_drivers()
assert s.y == pytest.approx(2) # solution of x * y**2 == 2
assert s.z == pytest.approx(2)
s.z = 4.0 # dynamically set new target
s.run_drivers()
assert s.y == pytest.approx(np.sqrt(8)) # solution of x * y**2 == 4
assert s.z == pytest.approx(4)
Targets can be also be declared in off-design mode, by calling ``self.add_target(...)`` in ``System.setup``.
Documentation¶
Bug fixes, minor improvements and code quality¶
Report variable name in unit-related Connector warning message (MR #32).
Automatically include field
timeinDataFramerecorders attached to a time driver (MR #34).Bug fix in
MonteCarlodriver (MR #37).Replace
condabymambain CI scripts (MR #39).Revamp markdown and JS rendering of systems and ports (MR #40 and #43, #47 and #51).
Fix bug in
ratetype inference (MR #44).Other code quality improvement (MR #35, #38, #42, #46, #50, #52, #53).
0.11.4 (2021-03-08)¶
New features¶
Recorders: It is now possible to add evaluable expressions in recorders (MR #27):
point = PointMass('point')
driver = point.add_driver(RungeKutta(order=3, time_interval=(0, 2), dt=0.01))
recorder = driver.add_recorder(recorders.DataFrameRecorder(
includes=['x', 'a', 'norm(v)']), # norm(v) will be recorded in DataFrame
period=0.1,
)
Bug fixes, minor improvements and code quality¶
Initialization bug in time simulations (MR #23).
Bug in nonlinearity estimation in
NumericalSolver(MR #22).Do not raise
ArithmeticErrorwhen an unknown is declared several time (MR #18).Suppress deprecation warnings raised by
numpy(MR #20 and #24).Suppress undue warning raised by
numpyinNonLinearSolver(MR #19).Fix incompatibility between
pandasandxlrd(MR #21).
0.11.3 (2020-12-16)¶
New features¶
Surrogate models: It is now possible to create a surrogate model at any system level with new method
System.make_surrogate(MR #3 and #12):
plane = Aeroplane('plane') # system with subsystems engine1 and engine2
# Say engine systems have one input parameter `fuel_rate`
# and possibly several outputs, and many sub-systems
# Create training schedule for input data
doe = pandas.DataFrame(
# loads of input data
columns=['fuel_rate', 'fan.diameter', ..] # input names
)
plane.engine1.make_surrogate(doe) # generates output data and train model
plane.run_once() # executes the surrogate model of `engine1` instead of original compute()
# dump model to file
plane.engine1.dump_surrogate('engine.bin')
# load model into `engine2`:
plane.engine2.load_surrogate('engine.bin')
# deactivate surrogate model on demand
plane.engine1.active_surrogate = plane.engine2.active_surrogate = False
Bug fixes, minor improvements and code quality¶
Add several US-common unit conversions (MR #2).
New method to export cosapp system structure into a dictionary (MR #5)
Make recorders capture port and system properties (MR #8).
Fix Module/System naming bug: ‘inwards’ and ‘outwards’ are allowed as Module/System names (MR #9).
Broad code quality improvement (MR #11).
Replace
typing.NoReturnbyNonewhen appropriate.Rewording pass, typo and error fixes in tutorial notebooks.
Suppress a
DeprecationWarningraised bynumpyin classVariable.Reformat many strings as Python f-strings, for clarity.
Symplify many occurrences of
str.join()for just two elements.
Global rewording of tutorial notebooks, including a few error fixes.
0.11.2 (2020-09-28)¶
First open-source version. No major code change; mostly updates of license files, URLs in docs, and CI scripts.
0.11.1 (2020-07-22)¶
Features¶
Add the possibility to set boundary condition of transient simulation from interpolate profile.
Add the possibility to prescribe a maximum step for transient variables.
Bugs and code quality¶
Bug fix in
RunOncedriver, preventing undue call torun_oncemethod.Bug fix in AssignString: force copy for numpy arrays.
New tutorial for advanced features of time simulations in CosApp.
0.11.0 (2020-05-12)¶
Features¶
Improve documentation at various places, add documentation about the cosapp packages structure and sequence diagram for transient simulation.
Add a advanced logger feature for CoSApp simulations.
Update FMU export to PythonFMU 0.6.0
New method
System.add_propertyallowing users to create read-only properties.
Bugs and code quality¶
Suppress deprecation warnings raised by external dependencies.
Fix bug in AssignString with arrays,
AssignStringof the kind'x = [0, 1, 2]'won’t change variablexinto an array of integers, ifxis declared as an array of floats.Fix
TimeStackUnknownnot able to stack transient variables defined on a children System or with partially pulled transient variable.Fix the bug related to the initialization of
rateattributes in systems.
0.10.2 (2020-04-21)¶
Features¶
[BETA] Export CoSApp System as FMU
Bugs and code quality¶
Apply Broyden correction on Jacobian matrix for iteration without Jacobian update
Support varying time step
Fix time not being set before
setup_runare called.Fix reference for residues in
IterativeConnector(it equals 1. now)Drop pyhamcrest for pytest
0.10.1 (2020-01-15)¶
Features¶
Time varying boundary conditions are now possible:
system = MySystem('something') # system with transient variables x and v
driver = system.add_driver(RungeKutta(time_interval=(0, 2), dt=0.01, order=3))
driver.set_scenario(
init = {'x': 0.5, 'v': 0}, # initial conditions
values =
{
'omega': 0.7,
'F_ext': '0.6 * cos(omega * t)' # explicit time-dependency
}
)
Bugs and code quality¶
Fix various bug on the transient simulation front
Correct implementation of step limitation in the Newton-Raphson solver
Using a logger at
DEBUGlevel will now display the call stack through the systems and driversRework of the Python evaluable string to be more efficient
0.10.0 (2019-10-23)¶
Introduce continuous time simulations with dedicated time drivers (see
TimeDrivernotebook in tutorials).Suppress notion of (un)freeze; all variables are considered as known, unless explicitly declared as unknowns.
Drivers no longer use ports.
Connectors are now stored by parent system.
Migrate to pytest.
API Changes¶
Ports:
add_variable("x", units="m", types=Number)=>add_variable("x", unit="m", dtype=Number)freeze=> removedunfreeze=> replaced byadd_unknownin Systems and Driversconnect_to=> replaced byconnectat system level
Systems:
time_refis no longer an argument of methodcompute:def compute(self, time_ref):=>def compute(self):Create a new connection between
a.in1andb.out:self.a.in1.connect_to(self.b.out)=>self.connect(self.a.in1, self.b.out)add_residues=>add_equationset_numerical_default=> Pass keyword toadd_unknownadd_inward("x", units="m", types=Number)=>add_inward("x", unit="m", dtype=Number)add_outward("x", units="m", types=Number)=>add_outward("x", unit="m", dtype=Number)
Drivers:
add_unknowns(maximal_absolute_step, maximal_relative_step, low_bound, high_bound)=>add_unknown(max_abs_step, max_rel_step, lower_bound, upper_bound)add_equations=>add_equationEquations are now represented by a unique string, instead of two strings (left-hand-side, right-hand-side):
add_equations("a", "b")=>add_equation("a == b")add_equations([("x", "2 * y + 1"), ("a", "b")])=>add_equation(["x == 2 * y + 1", "a == b"])For
NonLinearSolver:fatolandxtol=>tolmaxiter=>max_iterFor
Optimizer:ftol=>tolmaxiter=>max_iter
0.9.6 (2019-10-10)¶
More correction for VISjs viewer and System HTML representation
0.9.5 (2019-09-25)¶
Correct D3 & VISjs Viewers
0.9.4 (2019-09-25)¶
Introduce an optional environment variable
COSAPP_CONFIG_DIR
0.9.3 (2019-07-25)¶
API Changes¶
MonteCarlo:
Montecarlo=>MonteCarloMontecarlo.add_input_vars=>MonteCarlo.add_random_variableMontecarlo.add_response_vars=>MonteCarlo.add_response
MonteCarlo has been improved by using Sobol random generator
Viewers code on
Systemis moved in a subpackage ofcosapp.toolsResidue reference is now calculated only once
Various bug fix
0.9.2 (2019-07-01)¶
In nonlinear solver, store LU factorization of the Jacobian matrix, rather than its inverse.
Minor refactoring of the core source code, with no API changes
0.9.1 (2019-04-23)¶
Create
Variableclass to manage variable attributeswatchdogis now optionalConfiguration is now inside a folder
$HOME/.cosapp.dAPI changes:
get_latest_solution=>save_solutionload_solver_solution=>load_solution
Various bug fix
0.9.0 (2019-03-04)¶
This release introduces lots of API changes:
Core ports and unit are available in
cosapp.portsCore systems are available in
cosapp.systemsCore drivers are available in
cosapp.driversCore recorders are available in
cosapp.recordersCore tools are available in
cosapp.toolsCore notebook tools are available in
cosapp.notebook(! this is now a separated package)datahave been renamed ininwardsandadd_datainadd_inwardlocalshave been renamed inoutwardsandadd_localsinadd_outwardBaseRecorder.record_iterationrenamed inBaseRecorder.record_stateHuge code refractoring: cosapp is now a Python namespace.
cosapp.notebookhas been moved to an independent packagecosapp_notebook. But it is still accessible fromcosapp.notebook.Introduce Signal / Slot pattern to connect to internal event (implementation from signalslot, included in
cosapp.core.signal)Module.setup_ran: Signal emitted after thecall_setup_runexecutionModule.computed: Signal emitted after the full compute stack (i.e.:
_postcompute)Module.clean_ran: Signal emitted after thecall_clean_runexecutionBaseRecorder.state_recorded: Signale emitted after therecord_stateexecution
0.8.0 (2018-10-26)¶
Add Jacobian partial matrix update
Add numerical features to variables to ease convergence control
Add monitoring of solver residues
Add restoration of solver result for initialization
Rework residues and unknowns handling (remove virtual port and pulling port)
Rework optimizer to be more homogeneous with non-linear solver
Improve linear Monte Carlo computation time
Improve data viewer for non-linear solver
Create viewer for Monte Carlo
Add dropdown widget for enum variables
0.7.0 (2018-09-17)¶
Add helper functions to present solver evolutions
Add new d3 visualization of systems
0.6.0 (2018-08-14)¶
Implement clean-dirty policy
Restore compatibility with Python 3.4
Display influence matrix
0.5.0 (2018-07-20)¶
Simplify drivers structure, all actions for a case are supported by a single class
RunSingleCaseAdd support for vector variables; they can be partially (un)frozen and are handled correctly by the solver.
Add
MonteCarlodriverAdd recording data capability
0.4.0 (2018-06-15)¶
SystemandDriverhave now a common ancestorModule=>Drivervariables are now stored as data or localsAdd visualization of
Systemconnections based on N2 graph (syntax:cosapp.viewmodel(mySystem))
0.3.0 (2018-04-05)¶
API changes: System.add_driver and Driver.add_child take now an instance of Driver
Add external code caller System
Add validation range attributes on variables
Add variable visibility
Add metamodel training and DoE generator
Add helper function to list inputs and outputs variables of a
System
0.2.0 (2018-03-01)¶
Stabilization of the user API
0.1.0 (2018-01-02)¶
First release.