/* Simulation of a Lorenz attractor, a nonlinear CT system. Copyright (c) 1998-2005 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.domains.ct.demo.Lorenz; import ptolemy.actor.Manager; import ptolemy.actor.TypedCompositeActor; import ptolemy.actor.TypedIORelation; import ptolemy.actor.lib.AddSubtract; import ptolemy.actor.lib.Const; import ptolemy.actor.lib.MultiplyDivide; import ptolemy.actor.lib.Scale; import ptolemy.actor.lib.gui.XYPlotter; import ptolemy.data.DoubleToken; import ptolemy.data.expr.Parameter; import ptolemy.domains.ct.kernel.CTDirector; import ptolemy.domains.ct.kernel.CTMultiSolverDirector; import ptolemy.domains.ct.lib.Integrator; import ptolemy.kernel.util.Attribute; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.Workspace; import ptolemy.plot.Plot; ////////////////////////////////////////////////////////////////////////// //// Lorenz /** This is a model of a nonlinear feedback system that exhibits chaotic behavior. It is the well-known Lorenz attractor, and is given by a set of ordinary differential equations, <pre> dx1/dt = sigma*(x2-x1) dx2/dt = (lambda-x3)*x1 -x2 dx3/dt = x1*x2-b*x3 </pre> The plot created by the model shows the value of x2 vs. x1. <p> This class constructs a top-level Ptolemy model containing a CT director, which includes a sophisticated ODE numerical solver. @author Jie Liu @version $Id$ @since Ptolemy II 1.0 @Pt.ProposedRating Red (liuj) @Pt.AcceptedRating Red (cxh) */ public class Lorenz extends TypedCompositeActor { public Lorenz(Workspace workspace) throws IllegalActionException, NameDuplicationException { // Create the model. super(workspace); setName("LorenzSystem"); Manager manager = new Manager(workspace, "Manager"); setManager(manager); // Set up the top level composite actor, director and manager CTMultiSolverDirector director = new CTMultiSolverDirector(this, "CTMultiSolverDirector"); setDirector(director); director.stopTime.setToken(new DoubleToken(50.0)); // To get debug outputs, uncomment these: // director.addDebugListener(new StreamListener()); // manager.addDebugListener(new StreamListener()); // Parameters stopTime = new Parameter(this, "stopTime", new DoubleToken(50.0)); lambda = new Parameter(this, "lambda", new DoubleToken(25.0)); sigma = new Parameter(this, "sigma", new DoubleToken(10.0)); b = new Parameter(this, "b", new DoubleToken(2.0)); // Create the actors. Const LAMBDA = new Const(this, "LAMBDA"); LAMBDA.value.setExpression("lambda"); Scale SIGMA = new Scale(this, "SIGMA"); SIGMA.factor.setExpression("sigma"); Scale B = new Scale(this, "B"); B.factor.setExpression("b"); AddSubtract ADD1 = new AddSubtract(this, "Add1"); AddSubtract ADD2 = new AddSubtract(this, "Add2"); AddSubtract ADD3 = new AddSubtract(this, "Add3"); AddSubtract ADD4 = new AddSubtract(this, "Add4"); MultiplyDivide MULT1 = new MultiplyDivide(this, "MULT1"); MultiplyDivide MULT2 = new MultiplyDivide(this, "MULT2"); Integrator X1 = new Integrator(this, "IntegratorX1"); Integrator X2 = new Integrator(this, "IntegratorX2"); Integrator X3 = new Integrator(this, "IntegratorX3"); Scale MINUS1 = new Scale(this, "MINUS1"); Scale MINUS2 = new Scale(this, "MINUS2"); Scale MINUS3 = new Scale(this, "MINUS3"); XYPlotter myplot = new XYPlotter(this, "CTXYPlot"); myplot.plot = new Plot(); myplot.plot.setGrid(true); myplot.plot.setXRange(-25.0, 25.0); myplot.plot.setYRange(-25.0, 25.0); myplot.plot.setSize(400, 400); myplot.plot.addLegend(0, "(x1, x2)"); // CTConnections TypedIORelation x1 = new TypedIORelation(this, "X1"); TypedIORelation x2 = new TypedIORelation(this, "X2"); TypedIORelation x3 = new TypedIORelation(this, "X3"); X1.output.link(x1); X2.output.link(x2); X3.output.link(x3); MINUS1.input.link(x1); MINUS2.input.link(x2); MINUS3.input.link(x3); // dx1/dt = sigma*(x2-x1) connect(MINUS1.output, ADD1.plus); ADD1.plus.link(x2); connect(ADD1.output, SIGMA.input); connect(SIGMA.output, X1.input); // dx2/dt = (lambda-x3)*x1-x2 connect(LAMBDA.output, ADD2.plus); connect(MINUS3.output, ADD2.plus); connect(ADD2.output, MULT1.multiply); MULT1.multiply.link(x1); connect(MULT1.output, ADD3.plus); connect(MINUS2.output, ADD3.plus); connect(ADD3.output, X2.input); // dx3/dt = x1*x2-b*x3 MULT2.multiply.link(x1); MULT2.multiply.link(x2); B.input.link(x3); connect(MULT2.output, ADD4.plus); connect(B.output, ADD4.minus); connect(ADD4.output, X3.input); myplot.inputX.link(x1); myplot.inputY.link(x2); // CT Director parameters director.initStepSize.setToken(new DoubleToken(0.01)); director.minStepSize.setToken(new DoubleToken(1e-6)); // CTActorParameters X1.initialState.setToken(new DoubleToken(1.0)); X2.initialState.setToken(new DoubleToken(1.0)); X3.initialState.setToken(new DoubleToken(1.0)); MINUS1.factor.setToken(new DoubleToken(-1.0)); MINUS2.factor.setToken(new DoubleToken(-1.0)); MINUS3.factor.setToken(new DoubleToken(-1.0)); } /////////////////////////////////////////////////////////////////// //// parameters //// /** The stop time of the model. This is the top level facet for * the stopTime parameter of the director. */ Parameter stopTime; /** The lamda value in the equation. */ Parameter lambda; /** The sigma value in the equation. */ Parameter sigma; /** The b value in the equation. */ Parameter b; /////////////////////////////////////////////////////////////////// //// public methods //// /** If the parameter changed is the stopTime, then update the * stopTime parameter of the director. */ public void attributeChanged(Attribute attribute) throws IllegalActionException { CTDirector director = (CTDirector) getDirector(); if ((director != null) && (director.stopTime != null) && (stopTime != null)) { // This is a hack, we should really use controls=directorparamter // in the applet director.stopTime.setToken(stopTime.getToken()); } else { super.attributeChanged(attribute); } } }