1 //#**************************************************************
2 //#
3 //# filename: control.cpp
4 //#
5 //# author: Gerstmayr Johannes, Rafael Ludwig
6 //#
7 //# generated: 17.October 2004
8 //# description: Driver and model for timeintegration
9 //# Model of a rigid arm and a hydraulic zylinder
10 //# remarks:
11 //#
12 //# Copyright (c) 2003-2013 Johannes Gerstmayr, Linz Center of Mechatronics GmbH, Austrian
13 //# Center of Competence in Mechatronics GmbH, Institute of Technical Mechanics at the
14 //# Johannes Kepler Universitaet Linz, Austria. All rights reserved.
15 //#
16 //# This file is part of HotInt.
17 //# HotInt is free software: you can redistribute it and/or modify it under the terms of
18 //# the HOTINT license. See folder 'licenses' for more details.
19 //#
20 //# bug reports are welcome!!!
21 //# WWW: www.hotint.org
22 //# email: bug_reports@hotint.org or support@hotint.org
23 //#***************************************************************************************
24
25 #include "element.h"
26 #include "constraint.h"
27 #include "sensors.h"
28 #include "control.h"
29 #include "elementdataaccess.h"
30 #include "graphicsconstants.h"
31 #include "rendercontext.h"
32
33 const double DEFAULT_IOE_SIZE = 20;
34
35 //! AD: these strings are the default SYMBOL TEXTs, used as label in the 2D IO Blocks Window
36 //! AD: shortened names to fit nicer into the element rectangle
37 const char* CSText_InputOutputElement = "IOElement";
38 const char* CSText_LinearTransformation = "y=Ax+b"; //"IOLinearTransformation";
39 const char* CSText_STransferFunction = "S-Fcn"; //"IOContinuousTransferFunction";
40 const char* CSText_LinearODE = "lin ODE"; //"IOLinearODE";
41 const char* CSText_IOTime = "Time"; //"IOTime";
42 const char* CSText_IODisplay = "..."; //"IODisplay";
43 const char* CSText_IOResponseElement = "Response";
44 const char* CSText_IOKeyResponseElement = "Key";
45 const char* CSText_IOMouseResponseElement = "Mouse";
46 const char* CSText_InputOutputElementDiscrete = "Discr."; //"IODiscrElement";
47 const char* CSText_ZTransferFunction = "Z-Fcn"; //"IODiscreteTransferFunction";
48 const char* CSText_RandomSource = "Random"; //"IORandomSource";
49 const char* CSText_Quantizer = "Quant."; //"IOQuantizer";
50 const char* CSText_SDActor = "SDActor";
51 const char* CSText_ControllerInterface = "Contr."; //"ControllerInterface"; //$ RL 2010-04
52 const char* CSText_IOSaturate = "Saturate"; //"IOSaturate"; //$ RL 2011-01
53 const char* CSText_IODeadZone = "DeadZone"; //"IODeadZone"; //$ RL 2011-01
54 const char* CSText_IOProduct = "X"; //"IOProduct"; //$ RL 2011-05
55 const char* CSText_IOPulseGenerator = "Pulse"; //"IOPulseGenerator"; //$ RL 2011-07
56 const char* CSText_IOStopComputation = "Stop"; //"IOStopComputation";//$ RL 2012-2-1: //$ MS 2012-2-1:
57 const char* CSText_IOElementDataModifier = "Modify";
58 const char* CSText_IOTimeWindow = "TWindow"; //"IOTimeWindow";
59 const char* CSText_IOMathFunction = "f(x)";
60 const char* CSText_IOMinMax = "MinMax";
61 const char* CSText_IOTCPIPBlock = "TCPIP";
62
SymbolText() const63 const char* Quantizer::SymbolText() const
64 {
65 return CSText_Quantizer;
66 }
67
68 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
69 // DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS
70
SymbolText() const71 const char* InputOutputElementDiscrete::SymbolText() const
72 {
73 return CSText_InputOutputElementDiscrete;
74 }
75
Roundval(double x) const76 double InputOutputElementDiscrete::Roundval(double x) const
77 {
78 double d = 0.;
79 if (modf(x,&d)>=.5)
80 return x>=0?ceil(x):floor(x);
81 else
82 return x<0?ceil(x):floor(x);
83 }
84
GetDiscreteTime() const85 double InputOutputElementDiscrete::GetDiscreteTime() const
86 {
87 double tol = discrete_time_tol_inv;
88 double val = (double)GetK()*deltaT + toff;
89 val = Roundval(val*tol)/tol;
90 return val;
91 }
GetNextDiscreteTime() const92 double InputOutputElementDiscrete::GetNextDiscreteTime() const
93 {
94 double tol = discrete_time_tol_inv;
95 double val = (double)(GetK()+1.)*deltaT + toff;
96 val = Roundval(val*tol)/tol;
97 return val;
98 }
99
StartTimeStep()100 void InputOutputElementDiscrete::StartTimeStep()
101 {
102 double time_to_next_event = GetNextDiscreteTime() - GetMBS()->GetTime();
103 if(GetMBS()->GetStepSizeNew() >= time_to_next_event)
104 {
105 if (time_to_next_event < GetMBS()->GetStepRecommendation())
106 {
107 GetMBS()->SetStepRecommendation(time_to_next_event);
108 }
109 }
110 }
EndTimeStep()111 void InputOutputElementDiscrete::EndTimeStep()
112 {
113 // call this function after TItime += TIstep and before the sensor data is written!
114 if(isDiscreteEvent(GetNextDiscreteTime())) //t == (k+1)* deltaT?
115 {
116 UpdateDiscreteElementState(); // update state variables xk
117 SetK(GetK()+1); // k --> k+1
118 UpdateDiscreteElementInput(GetDiscreteTime()); // update uk
119 }
120 }
121
isDiscreteEvent(double discrete_time) const122 int InputOutputElementDiscrete::isDiscreteEvent(double discrete_time) const
123 {
124 //if(GetMBS()->GetStepEndTime() >= (discrete_time-discrete_time_tol))return 1; // values of end of time step are computed --> update of discrete element
125 if(GetMBS()->GetTime() >= (discrete_time-discrete_time_tol))return 1; // values of actual time step must be computed --> update of discrete element
126 else return 0; // solver endtime point before than next disctrete time point --> no update of discrete element
127 };
128
GetElementData(ElementDataContainer & edc)129 void InputOutputElementDiscrete::GetElementData(ElementDataContainer& edc) //fill in all element data
130 {
131 InputOutputElement::GetElementData(edc);
132 ElementData ed;
133 ed.SetDouble(deltaT, "discrete_time_step"); ed.SetToolTipText("Sample time \"dT\""); /*edc.Add(ed);*/ edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
134 ed.SetDouble(toff, "discrete_time_offset"); ed.SetToolTipText("Sample offset \"off\": Tk = k*dT + off"); /*edc.Add(ed);*/ edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
135 }
136
SetElementData(ElementDataContainer & edc)137 int InputOutputElementDiscrete::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
138 {
139 int rv = InputOutputElement::SetElementData(edc);
140 GetElemDataDouble(mbs, edc, "IOBlock.discrete_time_step", deltaT, 0);
141 GetElemDataDouble(mbs, edc, "IOBlock.discrete_time_offset", toff, 0);
142 return rv;
143 }
144
DrawBlockSymbol()145 void InputOutputElementDiscrete::DrawBlockSymbol()
146 {
147 // TODO: add specific symbol
148 }
149
150
151 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const152 const char* ZTransferFunction::SymbolText() const
153 {
154 return CSText_ZTransferFunction;
155 }
156
CheckConsistency(mystr & errorstr)157 int ZTransferFunction::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
158 {
159 int rv = InputOutputElementDiscrete::CheckConsistency(errorstr);
160 if(rv){ return rv;}
161
162 return rv;
163 }
164
GetElementData(ElementDataContainer & edc)165 void ZTransferFunction::GetElementData(ElementDataContainer& edc) //fill in all element data
166 {
167 InputOutputElementDiscrete::GetElementData(edc);
168
169 ElementData ed;
170 ed.SetVector(num.GetVecPtr(), num.Length(), "num_coeffs"); ed.SetVariableLength(); ed.SetToolTipText("Coefficients of numerator polynomial of z-function"); /*, b0+b1*z+b2*z\\^2+...+bn*z\\^n*/ edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
171 ed.SetVector(den.GetVecPtr(), den.Length(), "den_coeffs"); ed.SetVariableLength(); ed.SetToolTipText("Coefficients of denominator polynomial of z-function"); /*, a0+a1*z+a2*z\\^2+...+am*z\\^m*/ edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
172
173 //ed.SetVector(init_vec.GetVecPtr(), init_vec.Length(), "init_vec"); ed.SetVariableLength(); ed.SetToolTipText("Initial state vector."); edc.TreeAdd("IOBlock",ed); // added: MSax 28-02-2013
174
175 //SetElemDataVector(edc, num, "Num_coeffs"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Coefficients of numerator polynomial of z-function, b0+b1*z+b2*z^2+...+bn*z^n");
176 //SetElemDataVector(edc, den, "Den_coeffs"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Coefficients of denominator polynomial of z-function, a0+a1*z+a2*z^2+...+am*z^m");
177
178 //XXX: ElementData ed;
179 //XXX: ed.SetDouble(yk, "Initial_output"); ed.SetToolTipText("Initial output value."); edc.Add(ed);
180 }
181
SetElementData(ElementDataContainer & edc)182 int ZTransferFunction::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
183 {
184 int rv = InputOutputElementDiscrete::SetElementData(edc);
185
186 Vector numI, denI;
187 //double y0;
188 //GetElemDataVector(mbs, edc, "Num_coeffs", numI, 1);
189 //GetElemDataVector(mbs, edc, "Den_coeffs", denI, 1);
190
191 GetElemDataVector(mbs,edc,"IOBlock.num_coeffs",numI,1);
192 GetElemDataVector(mbs,edc,"IOBlock.den_coeffs",denI,1);
193 //XXX: GetElemDataDouble(mbs, edc, "Initial_output", y0, 1);
194 //GetElemDataVector(mbs,edc,"IOBlock.init_vec",init_vec,1); // $MSax 2013-03-01: added
195
196 if (num.Length() != den.Length())
197 {
198 rv = 0; //not successful
199 }
200 else
201 {
202 SetZTransferFunction(numI, denI); //, init_vec); // $MSax 2013-03-01: changed --> added 3rd. input argument init_vec
203 //XXX: SetZTransferFunction(numI, denI, y0); // not implemented yet!
204 }
205
206 return rv;
207 }
208
DrawBlockSymbol()209 void ZTransferFunction::DrawBlockSymbol()
210 {
211 return InputOutputElement::DrawBlockSymbol(); // $ MSax 2013-03-01: added
212 }
213
214 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SetRandomSource(double amplitudeI,double offsetI,TRandomType methodI,double seedI,double init_val,int Nbits)215 void RandomSource::SetRandomSource(double amplitudeI, double offsetI, TRandomType methodI, double seedI, double init_val, int Nbits)
216 {
217 InitRandomSource(amplitudeI, offsetI, methodI, seedI, init_val, Roundval(pow(2., Nbits)-1.));
218 }
219 // rand_max_i ... 2^N-1
InitRandomSource(double amplitudeI,double offsetI,TRandomType methodI,double seedI,double init_val,int rand_maxi)220 void RandomSource::InitRandomSource(double amplitudeI, double offsetI, TRandomType methodI, double seedI, double init_val, int rand_maxi)
221 {
222 amplitude = amplitudeI;
223 offset = offsetI;
224 seed = seedI;
225 method = methodI;
226
227 SetNOutputs(1);
228 SetNStates(0);
229 int dimIODiscrete = DataS(); // dimension of root element
230
231 if(seed > 1.0)
232 {
233 seed = 1.0; // max. value of seed
234 GetMBS()->UO(UO_LVL_warn) << "WARNING: InitRandomSource: \"seed\" bigger than 1.0 --> automatically set to 1.0\n";
235 }
236 if(seed < 0.0)
237 {
238 seed = 0.0; // min. value of seed
239 GetMBS()->UO(UO_LVL_warn) << "WARNING: InitRandomSource: \"seed\" negative --> automatically set to 0.0\n";
240 }
241
242
243 Vector init;
244 init.SetLen(0); // new init vector inclusive base element variables
245 init = init.Append(GetDataInit());
246 init = init.Append(init_val); // x(t=0) = y(t=0)
247
248 // initialize random signal generator
249 if(method == (TRandomType)Trand)
250 {
251 if(seed)srand((int)seed); //initialize random generator
252 SetNDiscreteStates(1); // yk = xk
253 }
254 else //if(method == (TRandomType)TLFSR
255 {
256 SetRandMax(rand_maxi);
257 int random_value = (int)(seed * rand_maxi);
258 if(!random_value)
259 {
260 random_value++; // intialize state with value unequal 0
261 }
262 init = init.Append((double)random_value); // internal state of LSFR random generator, unequal 0.
263 SetNDiscreteStates(2); // yk = xk, state
264 }
265 SetDataInit(init);
266 }
267
268 // random integer number � [0, RAND_MAX]; method TLFSR returns numbers unequal zero
GetRandomInt()269 int RandomSource::GetRandomInt()
270 {
271 if(method == (TRandomType)Trand)
272 {
273 return rand();
274 }
275 else //if method == (TRandomType)TLFSR
276 {
277 int shift_left = (int)(log10((double)abs(~GetRandMax()))/log10(2.)); // NOT(7FFF) = 32768 = 2^15 = 1000 0000 0000 0000 ==> 16 = log2(2^15)+1 = log10(2^15)/log10(2) + 1
278 unsigned int rand_val = (unsigned int)XDiscrete(2); // get current internal state
279 unsigned int newBit = 0;
280
281 switch(GetRandMax())
282 {
283 case 1: newBit = rand_val&1; break;//Fibonacci LFSR, Bit1 ... 1 Bits
284 case 3: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) ... 2 Bits
285 case 7: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) ... 3 Bits
286 case 15: newBit = rand_val & (rand_val&1)^((rand_val&2)>> 1); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) ... 4 Bits
287 case 31: newBit = rand_val & (rand_val&1)^((rand_val&4) >> 2); break; //Fibonacci LFSR, (Bit1) XOR (Bit3) ... 5 Bits
288 case 63: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) ... 6 Bits
289 case 127: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) ... 7 Bits
290 case 255: newBit = rand_val & (rand_val&1)^((rand_val&4) >> 2)^((rand_val&8) >> 3)^((rand_val&16) >> 4); break; //Fibonacci LFSR, (Bit1) XOR (Bit3) XOR (Bit4) XOR (Bit5)... 8 Bits
291 case 511: newBit = rand_val & (rand_val&1)^((rand_val&16) >> 4); break; //Fibonacci LFSR, (Bit1) XOR (Bit5) ... 9 Bits
292 case 1023: newBit = rand_val & (rand_val&1)^((rand_val&8) >> 3); break; //Fibonacci LFSR, (Bit1) XOR (Bit4) ... 10 Bits
293 case 2047: newBit = rand_val & (rand_val&1)^((rand_val&4) >> 2); break; //Fibonacci LFSR, (Bit1) XOR (Bit3) ... 11 Bits
294 case 4095: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1)^((rand_val&16) >> 4)^((rand_val&64) >> 6); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) XOR (Bit5) XOR (Bit7) ... 12 Bits
295 case 8191: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1)^((rand_val&8) >> 3)^((rand_val&128) >> 7); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) XOR (Bit4) XOR (Bit8) ... 13 Bits
296 case 16383: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1)^((rand_val&8) >> 3)^((rand_val&32) >> 5); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) XOR (Bit4) XOR (Bit6) ... 14 Bits
297 case 32767: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) ... 15 Bits
298 case 65535: newBit = rand_val & (rand_val&1)^((rand_val&4) >> 2)^((rand_val&8) >> 3)^((rand_val&32) >> 5); break; //Fibonacci LFSR, (Bit1) XOR (Bit3) XOR (Bit4) XOR (Bit6) ... 16 Bits
299 case 131071: newBit = rand_val & (rand_val&1)^((rand_val&8) >> 3); break; //Fibonacci LFSR, (Bit1) XOR (Bit4) ... 17 Bits
300 case 262143: newBit = rand_val & (rand_val&1)^((rand_val&128) >> 7); break; //Fibonacci LFSR, (Bit1) XOR (Bit8) ... 18 Bits
301 case 524287: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1)^((rand_val&4) >> 2)^((rand_val&32) >> 5); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) XOR (Bit3) XOR (Bit6) ... 19 Bits
302 case 1048575: newBit = rand_val & (rand_val&1)^((rand_val&8) >> 3); break; //Fibonacci LFSR, (Bit1) XOR (Bit4) ... 20 Bits
303 case 2097151: newBit = rand_val & (rand_val&1)^((rand_val&4) >> 2); break; //Fibonacci LFSR, (Bit1) XOR (Bit3) ... 21 Bits
304 case 4194303: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) ... 22 Bits
305 case 8388607: newBit = rand_val & (rand_val&1)^((rand_val&32) >> 5); break; //Fibonacci LFSR, (Bit1) XOR (Bit6) ... 23 Bits
306 case 16777215: newBit = rand_val & (rand_val&1)^((rand_val&2) >> 1)^((rand_val&8) >> 3)^((rand_val&16) >> 4); break; //Fibonacci LFSR, (Bit1) XOR (Bit2) XOR (Bit4) XOR (Bit5) ... 24 Bits
307 default: mbs->UO(UO_LVL_err) << "XOR-operation only implemented for maximal 24 Bits.";
308 }
309
310 newBit = newBit << shift_left; // newBit � {1000 0000 0000 0000, 0000 0000 0000 0000}
311 rand_val = (rand_val + newBit) >> 1; // one shift left (doesn't work with rand_val = 0)
312 XDiscrete(2) = (double)rand_val; // store new internal state
313 return rand_val;
314 }
315 }
316
317 //function is called every discrete event
318 // xk+1 = f(xk,uk)
UpdateDiscreteElementState()319 void RandomSource::UpdateDiscreteElementState()
320 {
321 int randval = GetRandomInt();
322 assert(randval >= 0 && randval <= GetRandMax());
323 XDiscrete(1) = amplitude*((double)randval/(double)GetRandMax() - 0.5) + offset;
324 }
325
SymbolText() const326 const char* RandomSource::SymbolText() const
327 {
328 return CSText_RandomSource;
329 }
330
CheckConsistency(mystr & errorstr)331 int RandomSource::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
332 {
333 int rv = InputOutputElementDiscrete::CheckConsistency(errorstr);
334 if(rv){ return rv;}
335
336 return rv;
337 }
338
GetElementData(ElementDataContainer & edc)339 void RandomSource::GetElementData(ElementDataContainer& edc) //fill in all element data
340 {
341 InputOutputElementDiscrete::GetElementData(edc);
342
343 ElementData ed;
344 ed.SetDouble(amplitude, "max_amplitude"); ed.SetToolTipText("Max. amplitude of random value."); edc.TreeAdd("IOBlock",ed);
345 ed.SetDouble(offset, "mean_value"); ed.SetToolTipText("Offset of random signal."); edc.TreeAdd("IOBlock",ed);
346
347 ed.SetBool((TRandomType)method, "method"); ed.SetToolTipText("Random generator method."); edc.TreeAdd("IOBlock",ed);
348
349 int bits = (int)Roundval(log10(rand_max+1.)/log10(2.)); // Bits = log2(max_rand+1)
350 ed.SetInt(bits, "bits"); ed.SetToolTipText("Number of bits for random signal."); edc.TreeAdd("IOBlock",ed);
351
352 ed.SetBool(isConstAmplitude, "constant_amplitude"); ed.SetToolTipText("Output values are +amplitude or -amplitude if flag is activate."); edc.TreeAdd("IOBlock",ed);
353
354 ed.SetDouble(seed, "seed"); ed.SetToolTipText("seed � [0.,1.]... initialization of random generator"); edc.TreeAdd("IOBlock",ed); //$ MSax 2013-02-28: added
355
356 ed.SetDouble(init_val, "init_val"); ed.SetToolTipText("initial value of the generator x(t=0) = y(t=0)"); edc.TreeAdd("IOBlock",ed); //$ MSax 2013-02-28: added
357 }
358
SetElementData(ElementDataContainer & edc)359 int RandomSource::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
360 {
361 int rv = InputOutputElementDiscrete::SetElementData(edc);
362
363
364 GetElemDataDouble(mbs, edc, "IOBlock.max_amplitude", amplitude, 1);
365 GetElemDataDouble(mbs, edc, "IOBlock.mean_value", offset, 1);
366
367 int methodI;
368 GetElemDataBool(mbs, edc, "IOBlock.method", methodI, 1);
369
370 int bits;
371 GetElemDataInt(mbs, edc, "IOBlock.bits", bits, 1);
372
373 GetElemDataBool(mbs, edc, "IOBlock.constant_amplitude", isConstAmplitude, 1);
374
375 GetElemDataDouble(mbs, edc, "IOBlock.seed", seed, 1); //$ MSax 2013-02-28: added
376
377 GetElemDataDouble(mbs, edc, "IOBlock.init_val", init_val, 1); //$ MSax 2013-02-28: added
378
379
380 // TODO: add init_data
381
382 SetRandomSource(amplitude, offset, (TRandomType)methodI, seed, init_val, bits);
383 SetConstantAmplitude(isConstAmplitude);
384
385 inputs.SetLen(0); //$ MSax 2013-04-03: added
386 input_types.SetLen(0); //$ MSax 2013-04-03: added
387 input_localnum.SetLen(0); //$ MSax 2013-04-03: added
388
389 return rv;
390 }
391
DrawBlockSymbol()392 void RandomSource::DrawBlockSymbol()
393 {
394 return InputOutputElement::DrawBlockSymbol();
395 }
396
397
398 // DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS DISCRETE SYSTEMS
399 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
400
CopyFrom(const Element & e)401 void InputOutputElement::CopyFrom(const Element& e)
402 {
403 Constraint::CopyFrom(e);
404 const InputOutputElement& ce = (const InputOutputElement&)e;
405
406 inputs = ce.inputs;
407 input_types = ce.input_types;
408 input_localnum = ce.input_localnum;
409
410 n_output = ce.n_output;
411 n_state = ce.n_state;
412 ref_pos=ce.ref_pos;
413 draw_dim=ce.draw_dim;
414
415 rotation = ce.rotation;
416 input_nodes.SetLen(ce.input_nodes.Length());
417 input_nodes_num.SetLen(ce.input_nodes_num.Length());
418 for (int i=1; i <= ce.input_nodes.Length(); i++)
419 {
420 input_nodes(i) = ce.input_nodes(i);
421 input_nodes_num(i) = ce.input_nodes_num(i);
422 }
423 colbackground = ce.colbackground;
424 colforeground = ce.colforeground;
425 }
426
InitConstructor()427 void InputOutputElement::InitConstructor()
428 {
429 draw_element = 1;
430 type = TMBSElement(TController+TConstraint);
431 elementname = GetElementSpec();
432 elements.SetLen(0);
433
434 inputs.SetLen(0);
435 input_localnum.SetLen(0);
436 input_types.SetLen(0);
437 n_output = 0;
438 n_state = 0;
439
440 x_init = Vector(SS());
441 rotation = 0;
442 input_nodes.SetLen(0);
443 input_nodes_num.SetLen(0);
444
445 //AddInput(1, 1); // $ MSax 2013-02-28: added
446
447 //drawing properties:
448 ref_pos = Vector2D(0.,0.);
449 // default size for elements made much larger to represent pixels in 2D View
450 draw_dim = Vector3D(DEFAULT_IOE_SIZE,DEFAULT_IOE_SIZE,0.);
451 // draw_dim = Vector3D(1.,1.,0.);
452 rotation = 0;
453
454 colbackground = Vector3D(-1.,-1.,-1.); //-1. ... no background color
455 colforeground = colblack;
456 }
457
458
GetElementData(ElementDataContainer & edc)459 void InputOutputElement::GetElementData(ElementDataContainer& edc) //fill in all element data
460 {
461 //if(1)
462 //{
463 Constraint::GetElementData(edc);
464 //}
465 //else
466 //{
467 // old:
468 // Constraint::GetElementData(edc);
469
470 // ElementData ed;
471
472 // ed.SetInt(GetNInputs(), "Number_of_inputs"); ed.SetLocked(1); edc.Add(ed);
473 // ed.SetInt(GetNOutputs(), "Number_of_outputs"); ed.SetLocked(1); edc.Add(ed);
474 // ed.SetInt(GetNStates(), "Number_of_states"); ed.SetLocked(1); edc.Add(ed);
475 //
476 // ed.SetVector2D(ref_pos.X(), ref_pos.Y(), "Drawing_ref_pos"); ed.SetToolTipText("reference position for drawing"); edc.Add(ed);
477 // ed.SetVector3D(draw_dim.X(), draw_dim.Y(), draw_dim.Z(), "Draw_size"); ed.SetToolTipText("drawing parameters: x=width, y=height, z=unused"); edc.Add(ed);
478
479 // SetElemDataIVector(edc, inputs, "Input_element_numbers"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Only valid element numbers permitted!");
480 // SetElemDataIVector(edc, input_types, "Input_element_types"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("1=InputOutputElement, 2=Sensor");
481 // SetElemDataIVector(edc, input_localnum, "Input_local_number"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Local number i = output number i of referred element");
482 //}
483
484 Matrix mat;
485 mat.SetMatrix2n(input_nodes);
486
487 ElementData ed;
488 ed.SetVector2DList(mat.GetMatPtr(), input_nodes.Length(), "input_nodes");
489 edc.TreeAdd("Graphics",ed);
490 }
491
SetElementData(ElementDataContainer & edc)492 int InputOutputElement::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
493 {
494 //InitConstructor();
495 int rv = Constraint::SetElementData(edc);
496 //int old = 0;
497 //if(old)
498 //{
499 // GetElemDataVector2D(mbs, edc, "Drawing_ref_pos", ref_pos, 0);
500 // GetElemDataVector3D(mbs, edc, "Draw_size", draw_dim, 0);
501
502 // GetElemDataIVector(mbs, edc, "Input_element_numbers", inputs, 1);
503 // GetElemDataIVector(mbs, edc, "Input_element_types", input_types, 1);
504 // GetElemDataIVector(mbs, edc, "Input_local_number", input_localnum, 1);
505 //}
506
507 double *mp;
508 int n;
509 edc.TreeGetVector2DList("Graphics.input_nodes",&mp,n);
510 Matrix mat(n,2,mp);
511 mat.GetVector2DList(input_nodes);
512
513 return rv;
514 }
515
GetAvailableSpecialValues(TArrayDynamic<ReadWriteElementDataVariableType> & available_variables)516 int InputOutputElement::GetAvailableSpecialValues(TArrayDynamic<ReadWriteElementDataVariableType>& available_variables)
517 {
518 // call base class routines
519 Constraint::GetAvailableSpecialValues(available_variables);
520
521 // Automatic entries for this class
522 InputOutputElement::GetAvailableSpecialValuesAuto(available_variables);
523
524 // Manual entries for this class
525 for(int i=1; i<=GetNOutputs();i++)
526 {
527 available_variables.Add(ReadWriteElementDataVariableType("IOBlock.output",i,0,0.,mystr("IOBlock.output[i] ... measures the i-th output of this IOBlock"))) ;
528 }
529 for(int i=1; i<=GetNInputs();i++)
530 {
531 available_variables.Add(ReadWriteElementDataVariableType("IOBlock.input",i,0,0.,mystr("IOBlock.input[i] ... measures the i-th input of this IOBlock"))) ;
532 }
533 return 0;
534 }
535
ReadSingleElementData(ReadWriteElementDataVariableType & RWdata)536 int InputOutputElement::ReadSingleElementData(ReadWriteElementDataVariableType& RWdata)
537 {
538 // call base class routine
539 int rv = Constraint::ReadSingleElementData(RWdata);
540 if (rv == 1) return 1;
541
542 // manual things to read
543 if( RWdata.variable_name == mystr("IOBlock.output") )
544 {
545 if (RWdata.comp1 > 0 && RWdata.comp1 <= GetNOutputs()) //range check
546 {
547 RWdata.value = GetOutput(RWdata.time, RWdata.comp1);
548 return 1;
549 }
550 else return -2;
551 }
552 else if(RWdata.variable_name == mystr("IOBlock.input"))
553 {
554 if (RWdata.comp1 > 0 && RWdata.comp1 <= GetNInputs()) //range check
555 {
556 RWdata.value = GetInput(RWdata.time, RWdata.comp1);
557 return 1;
558 }
559 else return -2;
560 }
561
562 return ReadSingleElementDataAuto(RWdata);
563 }
564
SymbolText() const565 const char* InputOutputElement::SymbolText() const
566 {
567 return CSText_InputOutputElement;
568 }
569
CheckConsistency(mystr & errorstr)570 int InputOutputElement::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
571 {
572 int rv = Constraint::CheckConsistency(errorstr);
573 if(rv==2){ return rv;}
574
575 if ((GetNInputs() != input_types.Length()) || (inputs.Length() != input_localnum.Length()))
576 {
577 errorstr = "Inconsistent system: lengths of vectors for definition of input don't match in element " + elementname + ". ";
578 return 2;
579 }
580 if(GetExpectedNumberOfInputs()!= -1 && GetNInputs() != GetExpectedNumberOfInputs())
581 {
582 errorstr = "Inconsistent system: please connect " + mystr(GetExpectedNumberOfInputs()) + " inputs to element " + elementname + ". ";
583 return 2;
584 }
585
586 for(int i=1; i<=input_types.Length();i++)
587 {
588 if(input_types(i)!=IOInputTypeSensor && input_types(i)!=IOInputTypeElement)
589 {
590 errorstr = "Inconsistent system: unexpected type of " + mystr(i) + "-th input. ";
591 return 2;
592 }
593 else if(input_types(i)==IOInputTypeSensor)
594 {
595 if(inputs(i) < 1 /*||inputs(i) > NSensors()*/)
596 {
597 errorstr = "Inconsistent system: invalid sensor number found in element " + elementname + ". ";
598 return 2;
599 }
600 }
601 else if(input_types(i)==IOInputTypeElement)
602 {
603 if(inputs(i)>mbs->GetNElements())
604 {
605 errorstr = "Inconsistent system: input element number not well-defined in element " + elementname + ". ";
606 return 2;
607 }
608 else if(!mbs->GetElement(inputs(i)).IsType(TController))
609 {
610 errorstr = "Inconsistent system: can't connect the element with number " + mystr(inputs(i)) + " to element " + elementname + "(no output found). ";
611 return 2;
612 }
613 else if(input_localnum(i) < 1 || mbs->GetElement(inputs(i)).IsType(TController) && ((InputOutputElement*)mbs->GetElementPtr(inputs(i)))->GetNOutputs() < input_localnum(i))
614 {
615 errorstr = "Inconsistent system: can't connect the element with number " + mystr(inputs(i)) + " to element " + elementname + "(unexpected output number " + mystr(input_localnum(i)) + "). ";
616 return 2;
617 }
618 }
619 }
620 return rv;
621 }
622
GetInputPosD(int i) const623 Vector2D InputOutputElement::GetInputPosD(int i) const //return absolute position of input #i
624 {
625 double phi = rotation*MY_PI*0.5;
626 Matrix3D rot; rot.Set22(cos(phi), -sin(phi),sin(phi), cos(phi));
627
628 double y = 0;
629 if (GetNInputs() > 1)
630 {
631 // y = draw_dim.Y() - (draw_dim.Y()/((double)GetNInputs()+0.5)) * (double)i;
632 y = draw_dim.Y()/2. - (draw_dim.Y()/((double)GetNInputs())) * ((double)i - 0.5);
633
634 }
635 double x =draw_dim.X()*0.5;
636 Vector2D dpos(-x,y);
637 if(rotation == 1)//rotation, 1==90�, 2==180�, 3==270�, 4=360�)
638 {
639 dpos = Vector2D(-y,-x);
640 }
641 else if(rotation == 2)
642 {
643 dpos = Vector2D(x,y);
644 }
645 else if(rotation == 3)
646 {
647 dpos = Vector2D(-y,x);
648 }
649 return GetRefPos2DD() + dpos; //rot * Vector2D(-draw_dim.X()*0.5,y);
650 }
651
GetOutputPosD(int i) const652 Vector2D InputOutputElement::GetOutputPosD(int i) const //return absolute position of input #i
653 {
654 double phi = rotation*MY_PI*0.5;
655 Matrix3D rot; rot.Set22(cos(phi), -sin(phi),sin(phi), cos(phi));
656
657 double y = 0;
658 if (GetNOutputs() > 1)
659 {
660 y = draw_dim.Y()/2. - (draw_dim.Y()/((double)GetNOutputs())) * ((double)i - 0.5);
661 }
662 return GetRefPos2DD() + rot * Vector2D(draw_dim.X()*0.5,y);
663 }
664
DrawElement()665 void InputOutputElement::DrawElement()
666 {
667 //DrawElement2D();
668 if (!GetMBS()->GetIOption(144)) return; //do not draw control object
669
670 //draw text in center of symbol:
671 double phi = rotation*MY_PI*0.5;
672 Matrix3D rot = RotMatrix3(phi);
673 //Matrix rot(cos(phi), -sin(phi), sin(phi), cos(phi));
674
675 //draw rectangle:
676 double b = draw_dim.X();
677 double h = draw_dim.Y();
678 Vector2D rp = GetRefPos2DD();
679 Vector3D rp3 = ToP3D(rp);
680
681 Vector3D p1(-0.5*b,-0.5*h,0.); //ll 2
682 Vector3D p2( 0.5*b,-0.5*h,0.); //lr 3
683 Vector3D p3( 0.5*b, 0.5*h,0.); //ur 4
684 Vector3D p4(-0.5*b, 0.5*h,0.); //ul 1
685
686 if(colbackground(1) < 0)
687 {
688 GetMBS()->MyDrawRectangle(rp3+rot*p4, rp3+rot*p1, rp3+rot*p2, rp3+rot*p3, 1, &colforeground); //$ RL 2011-11-17: draw only lines
689 }
690 else
691 {
692 GetMBS()->MyDrawRectangle(rp3+rot*p4, rp3+rot*p1, rp3+rot*p2, rp3+rot*p3, 1, &colforeground, &colbackground); //$ RL 2011-11-17: draw color rectangle
693 }
694 Vector2D tp = rp - Vector2D(draw_dim.X()*0.3,-draw_dim.Y()*0.3);
695 GetMBS()->GetRC()->PrintText3D((float)tp.X(), (float)tp.Y(), 0., GetElementName().c_str());
696
697 if (GetMBS()->GetIOption(123))
698 {
699 char text[40];
700 sprintf(text,"element %d", GetOwnNum());
701
702 GetMBS()->GetRC()->PrintText3D((float)tp.X(),(float)(tp.Y()-draw_dim.Y()*0.3),0.,text);
703 }
704
705 //draw inputs and outputs:
706 Vector3D v1=rot*Vector3D(-0.1*b, 0.1*h, 0.);
707 Vector3D v2=rot*Vector3D(-0.1*b,-0.1*h, 0.);
708
709 if(GetNInputs() == input_types.Length())
710 {
711 for (int i=1; i <= GetNInputs(); i++)
712 {
713 //GetMBS()->MyDrawCircleXY(ToP3D(GetInputPosD(i)), draw_dim.Y()*0.1, color);
714 Vector3D pi(0.);
715 if(Dim() == 2)
716 {
717 pi = ToP3D(GetInputPosD(i));
718 }
719 else
720 {
721 pi = GetInputPos3DD(i);
722 }
723
724 GetMBS()->MyDrawLine(pi + v1, pi, 2., colforeground);
725 GetMBS()->MyDrawLine(pi + v2, pi, 2., colforeground);
726
727 Vector3D po(0.,0.,0.);
728 int show = 0;
729 if (GetInputType(i) == 1) //if InputOutputElement, draw line to last IO-Element
730 {
731 Element *elp = GetMBS()->GetElementPtr(inputs(i));
732 if(! elp->IsType(TController)) //$ DR 2013-03-28 added this check
733 {
734 GetMBS()->UO(UO_LVL_warn) << "WARNING: input " << i << " of element " << elp->GetOwnNum() << " should be an other IO-Element, but is not. Drawing of controll elements stopped!\n";
735 return;
736 }
737 InputOutputElement* ioe = (InputOutputElement*)GetMBS()->GetElementPtr(inputs(i));
738 if (ioe->Dim()==2)
739 {
740 po = ToP3D(ioe->GetOutputPosD(GetInputLocalNum(i)));
741 }
742 else
743 {
744 po = ioe->GetOutputPos3DD(GetInputLocalNum(i));
745 }
746 show = 1;
747 }
748 else if (GetMBS()->GetIOption(127) && GetInputType(i) == 2)
749 {
750 // sensor als eingang
751 if(GetMBS()->GetSensor(inputs(i)).GetNumberOfDrawingPositions() > 0)
752 {
753 po = GetMBS()->GetSensor(inputs(i)).GetDrawPosition(1);
754 show = 1;
755 }
756 }
757 if (show)
758 { // zwischenpunkte
759 Vector3D last = pi;
760 for (int j=1; j <= input_nodes.Length(); j++)
761 {
762 if (input_nodes_num(j) == i)
763 {
764 GetMBS()->MyDrawLine(ToP3D(input_nodes(j)), last, 1., colforeground);
765 last = ToP3D(input_nodes(j));
766 }
767 }
768 GetMBS()->MyDrawLine(last, po, 1., colforeground);
769 }
770 }
771 }
772
773 for (int i=1; i <= GetNOutputs(); i++)
774 {
775 Vector2D v2d = GetOutputPosD(i);
776 Vector3D po = ToP3D(GetOutputPosD(i));
777
778 GetMBS()->MyDrawLine(po + Vector3D(v1(1),2.0/GetNOutputs()*v1(2),v1(3)), po, 1., colforeground);
779 GetMBS()->MyDrawLine(po + Vector3D(v2(1),2.0/GetNOutputs()*v2(2),v2(3)), po, 1., colforeground);
780 }
781 };
782
783
784
SetOutputName(int output_nr,mystr & name)785 void InputOutputElement::SetOutputName(int output_nr, mystr& name)
786 {
787 if(output_names.Length() != GetNOutputs()) // conditional reset ( is called when a name is added for the first time )
788 {
789 output_names.Reset();
790 for (int i=1; i<=GetNOutputs(); i++)
791 {
792 output_names.Add("");
793 }
794 }
795 if (name.Length()>=80)
796 {
797 name.Left(77);
798 name += "...";
799 }
800 output_names.Set(output_nr, name);
801 }
802
GetOutputName(int output_nr)803 char* InputOutputElement::GetOutputName(int output_nr)
804 {
805 if( output_names.Length() > 0 && output_nr <= output_names.Length() )
806 return output_names.Get(output_nr);
807 else
808 return NULL;
809 }
810
DrawElement2D()811 void InputOutputElement::DrawElement2D()
812 {
813 // ASSUMPTION: the default element size is 24x24 (const double DEFAULT_IOE_SIZE = 24;)
814 const int textboxheight = 8;
815 const int nodediameter = 1;
816
817
818 // Basic Size, rotation
819 Vector3D refpos = GetRefPosD();
820 double phi = rotation*MY_PI*0.5;
821 Matrix2D rot; rot.SetSkew(phi);
822
823 Vector2D center, size; // used for frame, labels
824 Vector2D nodecenter, nodesize; // individual nodes / lines
825
826
827 // Drawing order for nice pictures
828 // 1: connection lines
829 // 2: Element Frame
830 // 3: Nodes
831 // 4: Text
832
833 // ****************
834 // (1) CONNECTIONS
835 // ****************
836 // loop over Input Nodes
837 center = Vector2D(refpos.X(),refpos.Y());
838 size = Vector2D(draw_dim.X(), draw_dim.Y());
839
840 int last_array_pos_to_insert = 1; // array pos to insert the node at
841
842 for (int i=1; i <= GetNInputs(); i++)
843 {
844 nodecenter = Vector2D(-0.5*draw_dim.X(), 0.5*draw_dim.Y() - (draw_dim.Y()/((double)GetNInputs())) * ((double)i - 0.5)); // relative position
845 nodecenter = rot * nodecenter + center;
846 nodesize = Vector2D(nodediameter,nodediameter);
847 // nodesize = Vector2D(nodediameter/2.,nodediameter/2.); // construction nodes smaller then IO Nodes
848
849 if (GetInputType(i) == 1) // connected to an other IO-Element
850 {
851 //InputOutputElement* ioe = (InputOutputElement*)GetMBS()->GetElementPtr(inputs(i));
852 //$ DR 2013-03-28 added the following check
853 Element *elp = GetMBS()->GetElementPtr(inputs(i));
854 if(! elp->IsType(TController))
855 {
856 GetMBS()->UO(UO_LVL_warn) << "WARNING: input " << i << " of element " << elp->GetOwnNum() << " should be an other IO-Element, but is not.";
857 }
858 else
859 {
860 InputOutputElement* ioe = (InputOutputElement*)elp;
861
862 Vector2D final = ioe->GetOutputPosD(GetInputLocalNum(i));
863 Vector2D start = nodecenter;
864 Vector2D end;
865
866 for (int j=1; j <= input_nodes.Length(); j++)
867 {
868 if (input_nodes_num(j) == i)
869 {
870 end = input_nodes(j);
871
872 last_array_pos_to_insert = j;
873 int identifier_subelnr = i * 65536 + last_array_pos_to_insert; // combines Input Number and Array Position to insert a split node
874
875 // AD: NOTE - I dont want to change the data struct and access functions right now, but to identify the connection line unambiguous there are two integer numbers required.
876 // As these integers are short I store them both in the variable sub_elnr.
877
878 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
879 identifier_subelnr, TConnectionLine, // DRAW identifier
880 start, end, // extent
881 Vector3D(0.,0.,0.)); // color
882
883 GetMBS()->AddDrawComponent_Ellipse( GetOwnNum(), TIOBlock, // MBS identifier
884 identifier_subelnr, TConstructionNode, // DRAW identifier
885 end, nodesize, // extent
886 Vector3D(0.,0.,0.), Vector3D(0.,0.,0.)); // color
887 start = end;
888
889 last_array_pos_to_insert++; // after a node is found increase the array position to insert new nodes
890 }
891 }
892
893 int identifier_subelnr = i * 65536 + last_array_pos_to_insert; // combines Input Number and Array Position to insert a split node
894 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
895 identifier_subelnr, TConnectionLine, // DRAW identifier
896 start, final, // extent
897 Vector3D(0.,0.,0.)); // color
898 }
899 }
900 }
901
902 // ******************
903 // (2) ELEMENT FRAME
904 // ******************
905 center = Vector2D(refpos.X(),refpos.Y());
906 size = Vector2D(draw_dim.X(), draw_dim.Y());
907 GetMBS()->AddDrawComponent_Rect( GetOwnNum(), TIOBlock, // MBS identifier
908 1, TElementFrame, // DRAW identifier
909 center, size, // extent
910 Vector3D(0.,0.,0.), colbackground); // colors : border always black, area as set ...
911 // specific Symbol
912 if(size.X() > 2)
913 DrawBlockSymbol();
914
915 // ***************************
916 // (3) INPUT AND OUTPUT NODES
917 // ***************************
918 center = Vector2D(refpos.X(),refpos.Y());
919 size = Vector2D(draw_dim.X(), draw_dim.Y());
920 nodesize = Vector2D(nodediameter,nodediameter);
921 // Input Nodes
922 for (int i=1; i <= GetNInputs(); i++)
923 {
924 nodecenter = Vector2D(-0.5*draw_dim.X(), 0.5*draw_dim.Y() - (draw_dim.Y()/((double)GetNInputs())) * ((double)i - 0.5)); // relative position
925 nodecenter = rot * nodecenter + center;
926
927 if (GetInputType(i) == 1) // connected to an other IO-Element
928 {
929 GetMBS()->AddDrawComponent_Ellipse( GetOwnNum(), TIOBlock, // MBS identifier
930 i, TInputNode, // DRAW identifier
931 nodecenter, nodesize, // extent
932 Vector3D(0.,0.,0.), Vector3D(0.,0.,0.)); // color
933 }
934 else if (GetInputType(i) == 2) // connected to a sensor
935 {
936 GetMBS()->AddDrawComponent_Ellipse( GetOwnNum(), TIOBlock, // MBS identifier
937 i, TInputNode, // DRAW identifier
938 nodecenter, nodesize, // extent
939 Vector3D(0.,0.,0.), Vector3D(0.,0.,0.)); // color
940 }
941 else
942 {
943 GetMBS()->AddDrawComponent_Ellipse( GetOwnNum(), TIOBlock, // MBS identifier
944 i, TInputNode, // DRAW identifier
945 nodecenter, nodesize, // extent
946 Vector3D(0.,0.,0.), Vector3D(1.,0.,0.)); // color
947 }
948 }
949 // Output Nodes
950 for (int i=1; i <= GetNOutputs(); i++)
951 {
952 nodecenter = Vector2D( 0.5*draw_dim.X(), 0.5*draw_dim.Y() - (draw_dim.Y()/((double)GetNOutputs())) * ((double)i - 0.5)); // relative position
953 nodecenter = rot * nodecenter + center;
954
955 GetMBS()->AddDrawComponent_Ellipse( GetOwnNum(), TIOBlock, // MBS identifier
956 i, TOutputNode, // DRAW identifier
957 nodecenter, nodesize, // extent
958 Vector3D(0.,0.,0.), Vector3D(0.,0.,0.)); // color
959 }
960
961 // ***********
962 // (4) LABELS
963 // ***********
964 // Element Name below the element // "about a 3rd to 4th of the default height"
965 center = Vector2D(refpos.X(),refpos.Y()-0.5*draw_dim.Y() - textboxheight/2);
966 size = Vector2D(draw_dim.X(), textboxheight);
967 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
968 1, TElementName, // DRAW identifier
969 center, size, // extent
970 Vector3D(0.,0.,0.), // color of this label is alway black
971 GetElementName(), // label element with element name
972 TTextAllign (HCenter+VTop) ); // other properties
973 // MBS-element number
974 //b 123 PostProcOptions.Bodies.show_element_numbers 0 "1|(0) ... (Don't) show element body numbers."
975 //b 124 PostProcOptions.Connectors.show_constraint_numbers 0 "1|(0) ... (Don't) show constraint number."
976 if (GetMBS()->GetIOption(124))
977 {
978 size = Vector2D( 6, 5); // rectangle of constant absolute size in top right corner ( "for about 4 digits" )
979 center = Vector2D( refpos.X()+0.5*draw_dim.X()-0.5*size.X(), refpos.Y()+0.5*draw_dim.Y()-0.5*size.Y());
980 if(draw_dim.X() > 5)
981 {
982 GetMBS()->AddDrawComponent_Rect( GetOwnNum(), TIOBlock, // MBS identifier
983 2, TElementName, // DRAW identifier
984 center, size, // extent
985 colforeground, colbackground); // colors : border always black, area as set ...
986 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
987 2, TElementName, // DRAW identifier
988 center, size, // extent
989 colforeground, // color of this label is alway black
990 mystr(GetOwnNum()), // label element with element name
991 TTextAllign (HCenter+VTop) ); // other properties
992 }
993 }
994
995 center = Vector2D(refpos.X(),refpos.Y());
996 size = Vector2D(draw_dim.X(), draw_dim.Y());
997 // Input Nodes
998 for (int i=1; i <= GetNInputs(); i++)
999 {
1000 nodecenter = Vector2D(-0.5*draw_dim.X(), 0.5*draw_dim.Y() - (draw_dim.Y()/((double)GetNInputs())) * ((double)i - 0.5)); // relative position
1001 nodecenter = rot * nodecenter + center;
1002 Vector2D shift(-DEFAULT_IOE_SIZE/2-nodediameter , textboxheight/2 + nodediameter);
1003 Vector2D textbox(DEFAULT_IOE_SIZE, textboxheight);
1004
1005 if (GetInputType(i) == 2) // connected to a sensor
1006 {
1007 if (inputs(i) > 0 && inputs(i) <= GetMBS()->NSensors())
1008 {
1009 mystr name = GetMBS()->GetSensor(inputs(i)).GetSensorName();
1010 mystr label = mystr("S")+mystr(inputs(i))+mystr(":")+name;
1011 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
1012 i, TInputNode, // DRAW identifier
1013 nodecenter+shift, textbox, // extent
1014 Vector3D(0.,0.,0.), // color of this label is alway black
1015 label, // label input node with sensor name
1016 TTextAllign (HRight+VBottom) ); // other properties
1017 }
1018 }
1019 }
1020 // Output Nodes
1021 for (int i=1; i <= GetNOutputs(); i++)
1022 {
1023 nodecenter = Vector2D( 0.5*draw_dim.X(), 0.5*draw_dim.Y() - (draw_dim.Y()/((double)GetNOutputs())) * ((double)i - 0.5)); // relative position
1024 nodecenter = rot * nodecenter + center;
1025 Vector2D shift(+DEFAULT_IOE_SIZE/2+nodediameter , textboxheight/2 + nodediameter);
1026 Vector2D textbox(DEFAULT_IOE_SIZE, textboxheight);
1027 if (GetOutputName(i) != NULL)
1028 {
1029 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
1030 i, TOutputNode, // DRAW identifier
1031 nodecenter+shift, textbox, // extent
1032 Vector3D(0.,0.,0.), // color of this label is alway black
1033 mystr(GetOutputName(i)), // label output with load identifier
1034 TTextAllign (HLeft+VBottom) ); // other properties
1035 }
1036 }
1037
1038 return;
1039 };
1040
DrawBlockSymbol()1041 void InputOutputElement::DrawBlockSymbol()
1042 {
1043 Vector3D refpos = GetRefPosD();
1044 Vector2D center(refpos.X(),refpos.Y());
1045 Vector2D size(draw_dim.X(), draw_dim.Y());
1046
1047 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
1048 1, TSymbol, // DRAW identifier
1049 center, size, // extent
1050 colforeground, // color
1051 mystr(SymbolText()), // label element with element name
1052 TTextAllign (HCenter+VCenter) ); // other properties
1053 }
1054
GetDirectFeedThroughElements(TArray<int> & elnums) const1055 void InputOutputElement::GetDirectFeedThroughElements(TArray<int>& elnums) const //return all elements which are depending on this element by direct feed through
1056 {
1057 if (IsDirectFeedThrough())
1058 {
1059 for (int i=1; i <= GetNInputs(); i++)
1060 {
1061 if (GetInputType(i) == IOInputTypeElement)
1062 {
1063 elnums.Add(GetInputNum(i));
1064 GetMBS()->GetElement(GetInputNum(i)).GetDirectFeedThroughElements(elnums);
1065 }
1066 }
1067 }
1068 }
1069
1070
1071 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1072 const char* LinearTransformation::SymbolText() const
1073 {
1074 return CSText_LinearTransformation;
1075 }
1076
SetLinearTransformation(const Matrix & A,const Vector & b)1077 void LinearTransformation::SetLinearTransformation(const Matrix& A, const Vector& b)
1078 {
1079 //inputs must be added separately
1080 A_coeff.Resize(A.Getrows(), A.Getcols(),1);
1081 A_coeff = A;
1082 b_coeff = b;
1083 SetNOutputs(b.Length());
1084
1085 //check if sizes are consistent!
1086 //if (A.Getrows()*A.Getcols() != 0) assert(A.Getrows() == b.Length()); //-->moved to CheckConsistency
1087 }
1088
SetConstant(double val)1089 void LinearTransformation::SetConstant(double val)
1090 {
1091 //inputs must be added separately
1092 A_coeff = Matrix(1,0); b_coeff = Vector(val);
1093 SetNOutputs(1);
1094 }
1095
SetGain(double val)1096 void LinearTransformation::SetGain(double val)
1097 {
1098 //inputs must be added separately
1099 A_coeff = Matrix(val);
1100 b_coeff = Vector(1);
1101 b_coeff(1) = 0;
1102 SetNOutputs(1);
1103 }
1104
SetAdder(const Vector & signs)1105 void LinearTransformation::SetAdder(const Vector& signs)
1106 {
1107 //inputs must be added separately
1108 A_coeff = Matrix(1,signs.Length());
1109 for (int i=1; i <= signs.Length(); i++) {A_coeff(1,i) = signs(i);}
1110 b_coeff = Vector(1);
1111 b_coeff(1) = 0.;
1112 SetNOutputs(1);
1113 }
1114
1115
1116 //To be overwritten in derived class:
CopyFrom(const Element & e)1117 void LinearTransformation::CopyFrom(const Element& e)
1118 {
1119 InputOutputElement::CopyFrom(e);
1120 const LinearTransformation& ce = (const LinearTransformation&)e;
1121
1122 A_coeff.Resize(ce.A_coeff.Getrows(), ce.A_coeff.Getcols(),1);
1123 A_coeff = ce.A_coeff;
1124 b_coeff = ce.b_coeff;
1125 }
1126
InitConstructor()1127 void LinearTransformation::InitConstructor()
1128 {
1129 InputOutputElement::InitConstructor();
1130 elementname = GetElementSpec();
1131 SetNStates(0);
1132 Matrix A_init(4,4);
1133 SetLinearTransformation(A_init,Vector(4));
1134 }
1135
CheckConsistency(mystr & errorstr)1136 int LinearTransformation::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
1137 {
1138 int rv = InputOutputElement::CheckConsistency(errorstr);
1139 if(rv==2){return rv;}
1140 if(A_coeff.Getrows()*A_coeff.Getcols() != 0)
1141 {
1142 if(A_coeff.Getcols() != GetNInputs())
1143 {
1144 errorstr = "Inconsistent system: columns of A_matrix and number of inputs do not match " + mystr("(check element with number ") + mystr(GetOwnNum()) + mystr(")");
1145 return 2;
1146 }
1147 else if(A_coeff.Getrows() != b_coeff.Length())
1148 {
1149 errorstr = "Inconsistent system: rows of A_matrix and b_vector do not match " + mystr("(check element with number ") + mystr(GetOwnNum()) + mystr(")");
1150 return 2;
1151 }
1152 else if(A_coeff.Getrows() != GetNOutputs())
1153 {
1154 errorstr = "Inconsistent system: rows of A_matrix and number of output do not match " + mystr("(check element with number ") + mystr(GetOwnNum()) + mystr(")");
1155 return 2;
1156 }
1157 }
1158 else if(A_coeff.Getrows()*A_coeff.Getcols() == 0 && GetNInputs() != 0)
1159 {
1160 errorstr = "Inconsistent system: no rows or columns of A_matrix defined, but number of inputs is not zero " + mystr("(check element with number ") + mystr(GetOwnNum()) + mystr(")");
1161 return 2;
1162 }
1163 return rv;
1164 }
1165
GetElementData(ElementDataContainer & edc)1166 void LinearTransformation::GetElementData(ElementDataContainer& edc) //fill in all element data
1167 {
1168 InputOutputElement::GetElementData(edc);
1169
1170 ElementData ed;
1171 }
1172
SetElementData(ElementDataContainer & edc)1173 int LinearTransformation::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1174 {
1175 //TODO: resize matrix, if user change the size!!!
1176 int rv = InputOutputElement::SetElementData(edc);
1177
1178 //// possible extensions e.g. with radio buttons
1179 //SetConstant(val);
1180 //SetGain(val);
1181 //SetAdder(signs);
1182
1183
1184 //if(A_coeff.Getrows() == 1 && A_coeff.Getcols() == 1)
1185 //{
1186 // if( A_coeff(1,1) == 0.0)
1187 // {
1188 // SetConstant(b_coeff(1));
1189 // }
1190 // else if(b_coeff.Length()==1 && b_coeff(1) == 0.0)
1191 // {
1192 // SetGain(A_coeff(1,1));
1193 // }
1194 //}
1195 //else
1196 //{
1197 SetLinearTransformation(A_coeff, b_coeff);
1198 //}
1199 return rv;
1200 }
1201
GetOutput(double t,int i) const1202 double LinearTransformation::GetOutput(double t, int i) const
1203 {
1204 //to be overwritten in specific class!
1205 int elnum = GetOwnNum();
1206 double yi = b_coeff(i);
1207 for (int j=1; j <= GetNInputs(); j++)
1208 {
1209 //y_i = sum_j=1..nI {A_ij*u_j} + b_i
1210 yi += A_coeff(i, j)*GetInput(t, j);
1211 }
1212
1213 /*if (GetOwnNum() == 25 && GetMBS()->GetTime()>0.005)
1214 {
1215 GetMBS()->UO() << "Gain: t=" << GetMBS()->GetTime() << "\n";
1216 GetMBS()->UO() << "u=" << GetInput(t, 1) << "\n";
1217 GetMBS()->UO() << "y=" << yi << "\n";
1218 }*/
1219
1220 return yi;
1221 }
1222
DrawBlockSymbol()1223 void LinearTransformation::DrawBlockSymbol()
1224 {
1225 return InputOutputElement::DrawBlockSymbol();
1226
1227 Vector3D refpos = GetRefPosD();
1228 Vector2D center(refpos.X(),refpos.Y());
1229 Vector2D size(draw_dim.X(), draw_dim.Y());
1230
1231 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1232 1, TSymbol, // DRAW identifier
1233 center + Vector2D( -0.35*size.X(), -0.4*size.Y() ), center + Vector2D( -0.35*size.X(), 0.4*size.Y() ), // extent
1234 Vector3D(0.,0.,0.) ); // other properties
1235
1236 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1237 1, TSymbol, // DRAW identifier
1238 center + Vector2D( -0.4*size.X(), -0.35*size.Y() ), center + Vector2D( 0.4*size.X(), -0.35*size.Y() ), // extent
1239 Vector3D(0.,0.,0.) ); // other properties
1240
1241 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1242 1, TSymbol, // DRAW identifier
1243 center + Vector2D( -0.4*size.X(), -0.2*size.Y() ), center + Vector2D( 0.4*size.X(), 0.2*size.Y() ), // extent
1244 Vector3D(1.,0.,0.) ); // other properties
1245 }
1246
1247 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1248
GetElementData(ElementDataContainer & edc)1249 void Quantizer::GetElementData(ElementDataContainer& edc) //fill in all element data
1250 {
1251 InputOutputElement::GetElementData(edc);
1252
1253 ElementData ed;
1254 ed.SetDouble(roundval, "rounding_value"); ed.SetToolTipText("Max. amplitude of random value."); edc.TreeAdd("IOBlock",ed);
1255 //edc.Add(ed);
1256 }
1257
SetElementData(ElementDataContainer & edc)1258 int Quantizer::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1259 {
1260 int rv = InputOutputElement::SetElementData(edc);
1261
1262 GetElemDataDouble(mbs, edc, "IOBlock.rounding_value", roundval, 1);
1263
1264 SetNOutputs(1);
1265 SetNStates(0);
1266
1267 return rv;
1268 }
1269
DrawBlockSymbol()1270 void Quantizer::DrawBlockSymbol()
1271 {
1272 InputOutputElement::DrawBlockSymbol();
1273 }
1274
1275 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1276 const char* STransferFunction::SymbolText() const
1277 {
1278 return CSText_STransferFunction;
1279 }
1280
CheckConsistency(mystr & errorstr)1281 int STransferFunction::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
1282 {
1283 int rv = InputOutputElement::CheckConsistency(errorstr);
1284 if(rv){ return rv;}
1285
1286 if(num.Length() != den.Length())
1287 {
1288 errorstr = "Error: Numerator and denominator vectors must have same size. Transfer function is set automatically to \"1/s\".";
1289 SetSTransferFunction(Vector(1.,0.), Vector(0.,1.)); // set to valid value
1290 return 1;
1291 }
1292
1293 if(den(den.Length()) == 0)
1294 {
1295 errorstr = "Error: Denominator coefficient corresponding to Laplace variable with highest exponent is zero. Transfer function is set automatically to \"1/s\".\n";
1296 SetSTransferFunction(Vector(1.,0.), Vector(0.,1.)); // set to valid value
1297 return 1;
1298 }
1299
1300 if (GetNStates() == 0)
1301 {
1302 errorstr = "Error: Transfer function is fully algebraic. Transfer function is set automatically to \"1/s\".";
1303 SetSTransferFunction(Vector(1.,0.), Vector(0.,1.)); // set to valid value
1304 return 1;
1305 }
1306
1307 //check if sizes are consistent!
1308 if(GetNStates() != x_init.Length())
1309 {
1310 errorstr = "Error: Wrong size of intitialization vector. Transfer function is set automatically to \"1/s\".";
1311 SetSTransferFunction(Vector(1.,0.), Vector(0.,1.)); // set to valid value
1312 return 1;
1313 }
1314
1315 return rv;
1316 }
1317
GetElementData(ElementDataContainer & edc)1318 void STransferFunction::GetElementData(ElementDataContainer& edc) //fill in all element data
1319 {
1320 InputOutputElement::GetElementData(edc);
1321
1322 ElementData ed;
1323 //SetElemDataVector(edc, x_init, "Initial_vector"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Initial values of time-domain variables");
1324 }
1325
SetElementData(ElementDataContainer & edc)1326 int STransferFunction::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1327 {
1328 int rv = InputOutputElement::SetElementData(edc);
1329 SetSTransferFunction(num, den);
1330 // alternative with inital state "initVector"
1331 //GetElemDataVector(mbs, edc, "Initial_vector", initVector, 1);
1332 //SetSTransferFunction(numI, denI, initVector);
1333 return rv;
1334 }
1335
EvalF(Vector & f,double t)1336 void STransferFunction::EvalF(Vector& f, double t)
1337 {
1338 //compute f(i) = sum_j (A_ij * XG(j)) + b_i
1339 /*if (GetOwnNum() == 26 && GetMBS()->GetTime()>0.005)
1340 {
1341 int test=1;
1342 }*/
1343 if(GetNInputs() >=1) //$ RL 2011-01
1344 {
1345 int n = ES();
1346 double u = GetInput(t, 1);
1347
1348 //f = A*x+u*b;
1349 //A=[0 ..... 0 -den1 ]
1350 // [1 0 ... 0 -den2 ]
1351 // [0 0 ... 1 -den(n)]
1352 //bb(i) = num(i) - num(n+1)*den(i)
1353
1354 f(1) += -den(1)*XG(n) + (num(1)-num(n+1)*den(1))*u;
1355
1356 /*if (GetOwnNum() == 26 && GetMBS()->GetTime()>0.005)
1357 {
1358 GetMBS()->UO() << "integrator: t=" << GetMBS()->GetTime() << "\n";
1359 GetMBS()->UO() << "u=" << u << "\n";
1360 GetMBS()->UO() << "xg=" << XG(1) << "\n";
1361 GetMBS()->UO() << "f=" << f(1) << "\n";
1362 }*/
1363
1364 for(int i = 2; i<=n; i++ )
1365 {
1366 f(i) += XG(i-1) - den(i)*XG(n) + (num(i)-num(n+1)*den(i))*u; //A(i,i-1) * x(i-1) + b(i)*u; // ones in A-matrix
1367 }
1368 }
1369 };
1370
GetOutput(double t,int i) const1371 double STransferFunction::GetOutput(double t, int i) const
1372 {
1373 //to be overwritten in specific class!
1374 if (i != 1)
1375 {
1376 assert(0);
1377 return 0;
1378 }
1379
1380 //y = [0 0 .... 1][x_1 x_2 ... x_n] + b_n*u;
1381 int n = ES();
1382 double u = 0;
1383 if (num(n+1) != 0.) u = GetInput(t, 1);
1384
1385 if (n==0) return num(n+1)*u;
1386 else return XG(n) + num(n+1)*u;
1387 }
1388
DrawBlockSymbol()1389 void STransferFunction::DrawBlockSymbol()
1390 {
1391 InputOutputElement::DrawBlockSymbol();
1392 }
1393
1394 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1395 const char* LinearODE::SymbolText() const
1396 {
1397 return CSText_LinearODE;
1398 }
1399
CheckConsistency(mystr & errorstr)1400 int LinearODE::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
1401 {
1402 int rv = InputOutputElement::CheckConsistency(errorstr);
1403 if(rv){ return rv;}
1404
1405 return rv;
1406 }
1407
GetElementData(ElementDataContainer & edc)1408 void LinearODE::GetElementData(ElementDataContainer& edc) //fill in all element data
1409 {
1410 InputOutputElement::GetElementData(edc);
1411
1412 ElementData ed;
1413 ed.SetMatrix(A_coeff.GetMatPtr(),A_coeff.Getrows(),A_coeff.Getcols(),"A_coeffs"); ed.SetVariableLength(); ed.SetToolTipText("Coefficients of state matrix A, x_dot = A*x + B*u"); edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
1414 ed.SetMatrix(B_coeff.GetMatPtr(),B_coeff.Getrows(),B_coeff.Getcols(),"B_coeffs"); ed.SetVariableLength(); ed.SetToolTipText("Coefficients of input matrix B, x_dot = A*x + B*u"); edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
1415 ed.SetMatrix(C_coeff.GetMatPtr(),C_coeff.Getrows(),C_coeff.Getcols(),"C_coeffs"); ed.SetVariableLength(); ed.SetToolTipText("Coefficients of output matrix C, y = C*x + D*u"); edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
1416 ed.SetMatrix(D_coeff.GetMatPtr(),D_coeff.Getrows(),D_coeff.Getcols(),"D_coeffs"); ed.SetVariableLength(); ed.SetToolTipText("Coefficients of output matrix D, y = C*x + D*u"); edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
1417
1418 ed.SetVector(x_init.GetVecPtr(),x_init.GetLen(),"initital_vector"); ed.SetVariableLength(); ed.SetToolTipText("Initial values of time-domain variables"); edc.TreeAdd("IOBlock",ed); // change: MSax 28-02-2013
1419
1420 //ElementData ed;
1421
1422 //SetElemDataMatrix(edc, A_coeff, "A_coeffs"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Coefficients of state matrix A, x_dot = A*x + B*u");
1423 //SetElemDataMatrix(edc, B_coeff, "B_coeffs"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Coefficients of input matrix B, x_dot = A*x + B*u");
1424 //SetElemDataMatrix(edc, C_coeff, "C_coeffs"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Coefficients of output matrix C, y = C*x + D*u");
1425 //SetElemDataMatrix(edc, D_coeff, "D_coeffs"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Coefficients of output matrix D, y = C*x + D*u");
1426
1427 //SetElemDataVector(edc, x_init, "initital_vector"); edc.Last().SetVariableLength(); edc.Last().SetToolTipText("Initial values of time-domain variables");
1428 }
1429
SetElementData(ElementDataContainer & edc)1430 int LinearODE::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1431 {
1432 int rv = InputOutputElement::SetElementData(edc);
1433
1434 Vector numI, denI, initVector;
1435 GetElemDataMatrix(mbs, edc, "IOBlock.A_coeffs", A_coeff, 1); // change: MSax 28-02-2013
1436 GetElemDataMatrix(mbs, edc, "IOBlock.B_coeffs", B_coeff, 1); // change: MSax 28-02-2013
1437 GetElemDataMatrix(mbs, edc, "IOBlock.C_coeffs", C_coeff, 1); // change: MSax 28-02-2013
1438 GetElemDataMatrix(mbs, edc, "IOBlock.D_coeffs", D_coeff, 1); // change: MSax 28-02-2013
1439
1440 GetElemDataVector(mbs, edc, "IOBlock.initital_vector", initVector, 1); // change: MSax 28-02-2013
1441
1442 int ni = B_coeff.Getcols(); //number of inputs
1443 int ns = A_coeff.Getcols(); //number of states
1444 int no = C_coeff.Getrows(); //number of outputs
1445
1446 if (!(A_coeff.Getrows() == ns) || !(B_coeff.Getrows() == ns) ||
1447 !(C_coeff.Getcols() == ns) || !(D_coeff.Getrows() == no) ||
1448 !(D_coeff.Getcols() == ni) || !(initVector.Length() == ns)) rv = 0;
1449
1450
1451 if (rv) SetLinearODE(A_coeff, B_coeff, C_coeff, D_coeff, initVector);
1452
1453 return rv;
1454 }
1455
DrawBlockSymbol()1456 void LinearODE::DrawBlockSymbol()
1457 {
1458 InputOutputElement::DrawBlockSymbol();
1459 }
1460
1461
1462 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1463 const char* IOMathFunction::SymbolText() const
1464 {
1465 return mathfunc.GetTypeName();
1466 }
1467
SetIOMathFunction(const MathFunction & mathfuncI)1468 void IOMathFunction::SetIOMathFunction(const MathFunction& mathfuncI)
1469 {
1470 mathfunc = mathfuncI;
1471
1472 //elementspec = mystr("IOMathFunction");// + mystr(mathfunc.GetTypeName());
1473
1474 //SetNOutputs(1);
1475 //SetNStates(0);
1476 }
1477
GetCopy()1478 Element* IOMathFunction::GetCopy()
1479 {
1480 Element* ec = new IOMathFunction(mbs);
1481 ec->CopyFrom(*this);
1482
1483 return ec;
1484 }
1485 //To be overwritten in derived class:
CopyFrom(const Element & e)1486 void IOMathFunction::CopyFrom(const Element& e)
1487 {
1488 InputOutputElement::CopyFrom(e);
1489 const IOMathFunction& ce = (const IOMathFunction&)e;
1490
1491 mathfunc = ce.mathfunc;
1492 pieceWiseSwitchOnlyInPostNewton = ce.pieceWiseSwitchOnlyInPostNewton;
1493 //pieceWiseIndex = ce.pieceWiseIndex;
1494 pieceWiseIteration = ce.pieceWiseIteration;
1495 }
1496
InitConstructor()1497 void IOMathFunction::InitConstructor()
1498 {
1499 InputOutputElement::InitConstructor();
1500 elementname = GetElementSpec();
1501
1502 //Vector datainit(DataS());
1503 //datainit.SetAll(-1);
1504 //SetDataInit(datainit);
1505 pieceWiseSwitchOnlyInPostNewton = 0;
1506 pieceWiseIndex = -1;
1507 pieceWiseIteration = 0;
1508 SetNOutputs(1);
1509 SetNStates(0);
1510 }
1511
CheckConsistency(mystr & errorstr)1512 int IOMathFunction::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
1513 {
1514 int rv = InputOutputElement::CheckConsistency(errorstr);
1515 if(rv){ return rv;}
1516
1517 return rv;
1518 }
1519
GetElementData(ElementDataContainer & edc)1520 void IOMathFunction::GetElementData(ElementDataContainer& edc) //fill in all element data
1521 {
1522 InputOutputElement::GetElementData(edc);
1523 //mathfunc.GetElementData(edc); //fill in all element data
1524
1525 ElementDataContainer edc_mf;
1526 mathfunc.GetElementData(edc_mf);
1527 ElementData ed;
1528 ed.SetEDC(&edc_mf,"MathFunction"); ed.SetToolTipText("mathematical function"); edc.TreeAdd("IOBlock",ed);
1529 //ElementData ed;
1530 //SetElemDataMathFunc(edc, mathfunc, "Math_function"); edc.Last().SetToolTipText("Set coefficients of math function");
1531 }
1532
SetElementData(ElementDataContainer & edc)1533 int IOMathFunction::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1534 {
1535
1536 int rv = InputOutputElement::SetElementData(edc);
1537
1538 //const ElementData* ed = edc.TreeFind("IOBlock.MathFunction");
1539 ElementData* ed = edc.TreeFind("IOBlock.MathFunction");
1540 if(ed && ed->IsEDC())
1541 {
1542 //mathfunc.SetElementData(mbs, *ed->GetEDC());
1543 mathfunc.SetElementData(mbs,*ed->GetEDC()); //$ DR 2012-12-12
1544 SetIOMathFunction(mathfunc);
1545 }
1546 return rv;
1547 }
1548
DrawBlockSymbol()1549 void IOMathFunction::DrawBlockSymbol()
1550 {
1551 return InputOutputElement::DrawBlockSymbol();
1552 }
1553
GetOutput(double t,int i) const1554 double IOMathFunction::GetOutput(double t, int i) const
1555 {
1556 //to be overwritten in specific class!
1557 double u = GetInput(t, i);
1558
1559 //------------------------------------
1560 //begin: special case: input is IOTime
1561 if(mathfunc.GetFuncMode() == TMFpiecewiseconst && u == GetMBS()->GetStepEndTime() && u > 0.0)
1562 {
1563 if(GetInputType(i) == IOInputTypeElement)
1564 {
1565 mystr inputname(((const InputOutputElement&)(GetMBS()->GetElement(GetInputNum(i)))).SymbolText());
1566 if(inputname.Compare(mystr(CSText_IOTime)))
1567 {
1568 // use time tolerance ONLY if input element is IOTime and time is equal to solver - StepEndTime and piecewise constant Mathfunction is used!!!
1569 u = u - discrete_time_tol; // if solver needs value at next time point for integration; value changes AFTERWARDS integration of time step is finished (then TItime is increased by FinishStep).
1570 }
1571 }
1572 }
1573 //end: special case: input is IOTime
1574 //----------------------------------
1575 if(pieceWiseSwitchOnlyInPostNewton && pieceWiseIndex>0)
1576 {
1577 return mathfunc.InterpolatePiecewise(u, pieceWiseIndex);
1578 }
1579 else
1580 {
1581 return mathfunc.Evaluate(u);
1582 }
1583 }
1584 //$ RL 2012-7-25:[
PostNewtonStep(double t)1585 double IOMathFunction::PostNewtonStep(double t)
1586 {
1587 double error=0.;
1588 if(pieceWiseSwitchOnlyInPostNewton && mathfunc.GetFuncMode() == TMFpiecewiselinear && !pieceWiseIteration == 1 )
1589 {
1590 double u = GetInput(t, 1);
1591 int pieceWiseIndexOld = pieceWiseIndex;
1592 pieceWiseIndex = mathfunc.FindIndexPiecewise(u);
1593 if(pieceWiseIndexOld != -1 && pieceWiseIndex != pieceWiseIndexOld)
1594 {
1595 mbs->ForceJacobianRecomputation();
1596
1597 pieceWiseIteration++;
1598 double fnew = mathfunc.InterpolatePiecewise(u, pieceWiseIndex);
1599 double fold = mathfunc.InterpolatePiecewise(u, pieceWiseIndexOld);
1600
1601 //error = fabs(fnew-fold); // difference of new and old value
1602 double f_nominal = mathfunc.GetXVector().MaxNorm();
1603 if(!f_nominal){ f_nominal = 1;} // in case of zero - vector: use 1.0 as nominal value to omit division by zero
1604 error = fabs((fnew-fold)/f_nominal); // difference of new and old value
1605 }
1606 else
1607 {
1608 pieceWiseIteration = 0;
1609 }
1610 }
1611 return error;
1612 }
1613
PostprocessingStep()1614 void IOMathFunction::PostprocessingStep()
1615 {
1616 pieceWiseIteration = 0;
1617 };
1618 //$ RL 2012-7-25:]
1619 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1620
GetElementData(ElementDataContainer & edc)1621 void IOSaturate::GetElementData(ElementDataContainer& edc)
1622 {
1623 InputOutputElement::GetElementData(edc);
1624 ElementData ed;
1625 ed.SetDouble(upperLimit, "upper_limit"); ed.SetToolTipText("Upper limit of saturate."); edc.TreeAdd("IOBlock",ed);
1626 ed.SetDouble(lowerLimit, "lower_limit"); ed.SetToolTipText("Lower limit of saturate."); edc.TreeAdd("IOBlock",ed);
1627
1628 }
SetElementData(ElementDataContainer & edc)1629 int IOSaturate::SetElementData(ElementDataContainer& edc)
1630 {
1631 int rv = InputOutputElement::SetElementData(edc);
1632 GetElemDataDouble(mbs, edc, "IOBlock.upper_limit", upperLimit, 0);
1633 GetElemDataDouble(mbs, edc, "IOBlock.lower_limit", lowerLimit, 0);
1634
1635 SetNOutputs(1);
1636 SetNStates(0);
1637 return rv;
1638 }
1639
1640
SymbolText() const1641 const char* IOSaturate::SymbolText() const
1642 {
1643 return CSText_IOSaturate;
1644 }
1645
DrawBlockSymbol()1646 void IOSaturate::DrawBlockSymbol()
1647 {
1648 InputOutputElement::DrawBlockSymbol();
1649 }
1650
1651
1652 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1653 const char* IODeadZone::SymbolText() const
1654 {
1655 return CSText_IODeadZone;
1656 }
1657
GetElementData(ElementDataContainer & edc)1658 void IODeadZone::GetElementData(ElementDataContainer& edc) //fill in all element data
1659 {
1660 InputOutputElement::GetElementData(edc);
1661 ElementData ed;
1662 ed.SetDouble(start_deadzone, "start_deadzone"); ed.SetToolTipText("Start of dead zone."); edc.TreeAdd("IOBlock",ed);
1663 ed.SetDouble(end_deadzone, "end_deadzone"); ed.SetToolTipText("End of dead zone."); edc.TreeAdd("IOBlock",ed);
1664 }
1665
SetElementData(ElementDataContainer & edc)1666 int IODeadZone::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1667 {
1668 int rv = InputOutputElement::SetElementData(edc);
1669 GetElemDataDouble(mbs, edc, "IOBlock.start_deadzone", start_deadzone, 0); // lower limit of deadzone
1670 GetElemDataDouble(mbs, edc, "IOBlock.end_deadzone", end_deadzone, 0); // upper limit of deadzone
1671 return rv;
1672 }
1673
DrawBlockSymbol()1674 void IODeadZone::DrawBlockSymbol()
1675 {
1676 InputOutputElement::DrawBlockSymbol();
1677 }
1678
1679 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1680 const char* IOTime::SymbolText() const
1681 {
1682 return CSText_IOTime;
1683 }
1684
GetElementData(ElementDataContainer & edc)1685 void IOTime::GetElementData(ElementDataContainer& edc) //fill in all element data
1686 {
1687 InputOutputElement::GetElementData(edc);
1688 ElementData ed;
1689 }
1690
SetElementData(ElementDataContainer & edc)1691 int IOTime::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1692 {
1693 int rv = InputOutputElement::SetElementData(edc);
1694
1695 inputs.SetLen(0); //$ MSax 2013-08-28: added
1696 input_types.SetLen(0); //$ MSax 2013-08-28: added
1697 input_localnum.SetLen(0); //$ MSax 2013-08-28: added
1698
1699 return rv;
1700 }
1701
DrawBlockSymbol()1702 void IOTime::DrawBlockSymbol()
1703 {
1704 Vector3D refpos = GetRefPosD();
1705 Vector2D center(refpos.X(),refpos.Y());
1706 Vector2D size(draw_dim.X(), draw_dim.Y());
1707
1708 GetMBS()->AddDrawComponent_Ellipse( GetOwnNum(), TIOBlock, // MBS identifier
1709 1, TSymbol, // DRAW identifier
1710 center, 0.7* size, // extent
1711 colforeground, colbackground ); // color
1712 //#define animate_clock
1713 #ifdef animate_clock
1714 double angle = GetMBS()->GetDrawTime()*2.*MY_PI; // 1 full revelation per second
1715 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1716 1, TSymbol, // DRAW identifier
1717 center, center + Vector2D(0.30*size.Y()*sin(angle),0.30*size.Y()*cos(angle)), // extent
1718 colforeground ); // color
1719 #else
1720 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1721 1, TSymbol, // DRAW identifier
1722 center, center + Vector2D(0.,0.30*size.Y()), // extent
1723 colforeground ); // color
1724
1725 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1726 1, TSymbol, // DRAW identifier
1727 center, center + Vector2D(0.20*size.X(),0.), // extent
1728 colforeground ); // color
1729 #endif
1730 }
1731 //
1732 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1733 const char* IOPulseGenerator::SymbolText() const
1734 {
1735 return CSText_IOPulseGenerator;
1736 }
1737
GetElementData(ElementDataContainer & edc)1738 void IOPulseGenerator::GetElementData(ElementDataContainer& edc) //fill in all element data
1739 {
1740 InputOutputElement::GetElementData(edc);
1741
1742 ElementData ed;
1743 ed.SetDouble(amplitude, "amplitude"); ed.SetToolTipText("Amplitude of rectangle pulse generator."); edc.TreeAdd("IOBlock",ed);
1744 ed.SetDouble(toffs, "offset"); ed.SetToolTipText("Time offset (s)."); edc.TreeAdd("IOBlock",ed);
1745 ed.SetDouble(period, "period"); ed.SetToolTipText("Period of signal (s)."); edc.TreeAdd("IOBlock",ed);
1746 ed.SetDouble(pulseWidth, "pulse_width"); ed.SetToolTipText("Pulse width (s)."); edc.TreeAdd("IOBlock",ed);
1747 ed.SetInt(useExternalTime, "use_external_time_source"); ed.SetLocked(1); ed.SetToolTipText("1|(0) ... (Don't) use external input as time source."); edc.TreeAdd("IOBlock",ed);
1748
1749 }
1750
SetElementData(ElementDataContainer & edc)1751 int IOPulseGenerator::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1752 {
1753 int rv = InputOutputElement::SetElementData(edc);
1754
1755 GetElemDataDouble(mbs, edc, "IOBlock.amplitude", amplitude, 0);
1756 GetElemDataDouble(mbs, edc, "IOBlock.offset", toffs, 0);
1757 GetElemDataDouble(mbs, edc, "IOBlock.period", period, 0);
1758 GetElemDataDouble(mbs, edc, "IOBlock.pulse_width", pulseWidth, 0);
1759 GetElemDataInt(mbs, edc, "IOBlock.use_external_time_source", useExternalTime, 0);
1760
1761 assert(period > 0. && pulseWidth >= 0.); // $ MSax 2013-02-28: added from set function
1762
1763 inputs.SetLen(0); //$ MSax 2013-04-03: added
1764 input_types.SetLen(0); //$ MSax 2013-04-03: added
1765 input_localnum.SetLen(0); //$ MSax 2013-04-03: added
1766
1767 return rv;
1768 }
1769
DrawBlockSymbol()1770 void IOPulseGenerator::DrawBlockSymbol()
1771 {
1772 return InputOutputElement::DrawBlockSymbol();
1773
1774 Vector3D refpos = GetRefPosD();
1775 Vector2D center(refpos.X(),refpos.Y());
1776 Vector2D size(draw_dim.X(), draw_dim.Y());
1777
1778 Vector2D p1, p2;
1779 size *= 0.16; // scale overall size of the symbol
1780 for (int i=1; i<=7; i++)
1781 {
1782 switch (i)
1783 {
1784 case 1: p1 = center + Vector2D(-2.*size.X(),-2.*size.Y()); p2 = center + Vector2D( -size.X(),-2.*size.Y()); break;
1785 case 2: p1 = center + Vector2D( -size.X(),-2.*size.Y()); p2 = center + Vector2D( -size.X(), 2.*size.Y()); break;
1786 case 3: p1 = center + Vector2D( -size.X(), 2.*size.Y()); p2 = center + Vector2D( 0.0, 2.*size.Y()); break;
1787 case 4: p1 = center + Vector2D( 0.0, 2.*size.Y()); p2 = center + Vector2D( 0.0,-2.*size.Y()); break;
1788 case 5: p1 = center + Vector2D( 0.0,-2.*size.Y()); p2 = center + Vector2D( size.X(),-2.*size.Y()); break;
1789 case 6: p1 = center + Vector2D( size.X(),-2.*size.Y()); p2 = center + Vector2D( size.X(), 2.*size.Y()); break;
1790 case 7: p1 = center + Vector2D( size.X(), 2.*size.Y()); p2 = center + Vector2D( 2.*size.X(), 2.*size.Y()); break;
1791 default: break;
1792 }
1793 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1794 1, TSymbol, // DRAW identifier
1795 p1, p2, // extent
1796 colforeground ); // color
1797 }
1798 }
1799
1800 //
1801 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const1802 const char* IOProduct::SymbolText() const
1803 {
1804 return CSText_IOProduct;
1805 }
1806
GetElementData(ElementDataContainer & edc)1807 void IOProduct::GetElementData(ElementDataContainer& edc) //fill in all element data
1808 {
1809 InputOutputElement::GetElementData(edc);
1810 ElementData ed;
1811 ed.SetVector(exp.GetVecPtr(), exp.Length(), "exponents"); ed.SetVariableLength(); ed.SetToolTipText("Exponent of inputs. y=u1\\^exp1*u2\\^exp2*...*un\\^expn+offset."); edc.TreeAdd("IOBlock",ed); //$ MSax2013-02-28
1812 ed.SetDouble(offset, "offset"); ed.SetToolTipText("Output offset."); edc.TreeAdd("IOBlock",ed);
1813 }
1814
SetElementData(ElementDataContainer & edc)1815 int IOProduct::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1816 {
1817 int rv = InputOutputElement::SetElementData(edc);
1818 GetElemDataVector(mbs, edc, "IOBlock.exponents", exp, 0);
1819 GetElemDataDouble(mbs, edc, "IOBlock.offset", offset, 0);
1820
1821 if(exp.Length() <= 0) //$ MSax 2013-02-28 added from set function
1822 {
1823 exp = Vector(1.,1.);
1824 mbs->UO(UO_LVL_err).InstantMessageText("Error in SetIOProduct: exponent vector is empty.");
1825 }
1826 return rv;
1827 }
1828
GetOutput(double t,int i) const1829 double IOProduct::GetOutput(double t, int i) const
1830 {
1831 assert(GetNInputs() == exp.Length());
1832
1833 double outval = 1.;
1834 for(int i = 1; i<=GetNInputs(); i++)
1835 {
1836 // multiplication
1837 double u = GetInput(t, i);
1838 if(exp(i)<0)
1839 {
1840 assert(u != 0.);
1841 }
1842 ////TODO: if necessary, add strategy if input is zero (e.g. like code below)
1843 //if(u == 0.)
1844 //{
1845 // // division
1846 // u = divide_by_zero_tol; // omit division by zero
1847 // mbs->UO(UO_LVL_warn) << "Warning in IOProduct: Division by zero. Divisor is set to tolerance\n";
1848 //}
1849 //else if(fabs(u) < divide_by_zero_tol)
1850 //{
1851 // u = u/fabs(u)*divide_by_zero_tol; // omit division by zero
1852 // mbs->UO(UO_LVL_warn) << "Warning in IOProduct: Division by value close to zero. Divisor is set to tolerance\n";
1853 //}
1854 outval *= pow(u, exp(i));
1855 // just for debugging
1856 //if(1)
1857 //{
1858 // mbs->UO() << "Product: u = " << u << ", exp = " << exp(i) << "\n";
1859 // if(i == GetNInputs())
1860 // {
1861 // mbs->UO() << "Product: y = " << outval << "\n\n";
1862 // }
1863 //}
1864 }
1865 outval += offset;
1866
1867 return outval;
1868 }
1869
DrawBlockSymbol()1870 void IOProduct::DrawBlockSymbol()
1871 {
1872 return InputOutputElement::DrawBlockSymbol();
1873
1874 Vector3D refpos = GetRefPosD();
1875 Vector2D center(refpos.X(),refpos.Y());
1876 Vector2D size(draw_dim.X(), draw_dim.Y());
1877
1878
1879 size *= 0.16; // scale overall size of the symbol
1880
1881 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1882 1, TSymbol, // DRAW identifier
1883 center + Vector2D( size.X(), size.Y() ), center + Vector2D( -size.X(), -size.Y() ), // extent
1884 colforeground ); // color
1885 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
1886 1, TSymbol, // DRAW identifier
1887 center + Vector2D( -size.X(), size.Y() ), center + Vector2D( size.X(), -size.Y() ), // extent
1888 colforeground ); // color
1889 }
1890 //
1891 //+++++++Interface Data element: ControllerInterfaceData ++++++++++++++++++++++++++++++++++++++++
GetElementData(ElementDataContainer & edc)1892 void ControllerInterfaceData::GetElementData(ElementDataContainer& edc)
1893 {
1894 ElementData ed;
1895 //adresses to functions are not in user menu.
1896 //void (*Reg_Init)(); // pointer on initialize function, not necessary to show these pointer in data container
1897 //void (*Reg_Update)(); // pointer on update function, not necessary to show these pointer in data container
1898 //ed.SetDouble(deltaT, "discrete_update_time"); edc.Add(ed); // already defined in InputOutputElementDiscrete::GetElementData(edc);
1899 //ed.SetInt(nOut, "number_of_outputs"); edc.Add(ed); // not necessary, already written into menu dialog from InputOutputElement::GetElementData(edc);
1900 //ed.SetInt(nInp, "number_of_inputs"); edc.Add(ed);// not necessary, already written into menu dialog from InputOutputElement::GetElementData(edc);
1901 }
1902
SetElementData(ElementDataContainer & edc)1903 int ControllerInterfaceData::SetElementData(ElementDataContainer& edc)
1904 {
1905 int rv = 0;
1906 //adresses to functions are not in user menu.
1907 //void (*Reg_Init)(); // pointer on initialize function
1908 //void (*Reg_Update)(); // pointer on update function
1909 //GetElemDataDouble(mbs, edc, "discrete_update_time", deltaT, 0); // already defined in InputOutputElementDiscrete::SetElementData(edc)
1910 //GetElemDataInt(mbs, edc, "number_of_outputs", nOut, 0); // not necessary, already written into menu dialog from InputOutputElement::GetElementData(edc);
1911 //GetElemDataInt(mbs, edc, "number_of_outputs", nInp, 0); // not necessary, already written into menu dialog from InputOutputElement::GetElementData(edc);
1912 return rv;
1913 }
1914
1915 //extern char* CSText_ControllerInterface;
1916 extern const char* CSText_ControllerInterface;
SymbolText() const1917 const char* ControllerInterface::SymbolText() const
1918 {
1919 return CSText_ControllerInterface;
1920 }
1921
CheckConsistency(mystr & errorstr)1922 int ControllerInterface::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
1923 {
1924 int rv = InputOutputElementDiscrete::CheckConsistency(errorstr);
1925 if(rv){ return rv;}
1926
1927 return rv;
1928 }
1929
GetElementData(ElementDataContainer & edc)1930 void ControllerInterface::GetElementData(ElementDataContainer& edc) //fill in all element data
1931 {
1932 InputOutputElementDiscrete::GetElementData(edc);
1933 data.GetElementData(edc);
1934 }
1935
SetElementData(ElementDataContainer & edc)1936 int ControllerInterface::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1937 {
1938 int rv = InputOutputElementDiscrete::SetElementData(edc);
1939 rv += data.SetElementData(edc);
1940 return rv;
1941 }
1942
DrawBlockSymbol()1943 void ControllerInterface::DrawBlockSymbol()
1944 {
1945 InputOutputElement::DrawBlockSymbol();
1946 }
1947
1948 // INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE INTERFACE
1949 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1950
1951 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1952 // IOTimeWindow
1953 //$ DR 2011-12:[ IOTimeWindow added
1954 //const char* CSText_IOTimeWindow = "Window"; //"IOTimeWindow"; // AD: moved to top of file ...
1955
SymbolText() const1956 const char* IOTimeWindow::SymbolText() const
1957 {
1958 return CSText_IOTimeWindow;
1959 }
1960
CheckConsistency(mystr & errorstr)1961 int IOTimeWindow::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
1962 {
1963 int rv = InputOutputElement::CheckConsistency(errorstr);
1964 if(rv){ return rv;}
1965
1966 return rv;
1967 }
1968
GetElementData(ElementDataContainer & edc)1969 void IOTimeWindow::GetElementData(ElementDataContainer& edc) //fill in all element data
1970 {
1971 InputOutputElement::GetElementData(edc);
1972 ElementData ed;
1973 ed.SetDouble(t_start, "t_start"); ed.SetToolTipText("Start time (s)."); edc.TreeAdd("IOBlock",ed);
1974 ed.SetDouble(t_end, "t_end"); ed.SetToolTipText("End time (s)."); edc.TreeAdd("IOBlock",ed);
1975 }
1976
SetElementData(ElementDataContainer & edc)1977 int IOTimeWindow::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
1978 {
1979 int rv = InputOutputElement::SetElementData(edc);
1980
1981 GetElemDataDouble(mbs, edc, "IOBlock.t_start", t_start, 0);
1982 GetElemDataDouble(mbs, edc, "IOBlock.t_end", t_end, 0);
1983
1984 if (t_end > t_start)
1985 {
1986 SetIOTimeWindow(t_start, t_end);
1987 }
1988 else
1989 {
1990 SetIOTimeWindow(t_start);
1991 }
1992
1993 return rv;
1994 }
1995
GetOutput(double t,int i) const1996 double IOTimeWindow::GetOutput(double t, int i) const
1997 {
1998 // y = u(2) if t_start <= u(1) <= t_start + delta_t
1999 // y = u(2) if t_start <= u(1) and delta_t < 0
2000 // y = 0 else
2001
2002 if(reached_end)
2003 {
2004 return 0;
2005 }
2006 else
2007 {
2008 if (GetInput(t, 1) < t_start )
2009 {
2010 return 0;
2011 }
2012 else
2013 {
2014 if(delta_t < 0.)
2015 {
2016 return GetInput(t, 2);
2017 }
2018 else if (t_start + delta_t < GetInput(t, 1))
2019 {
2020 reached_end = 1;
2021 return 0;
2022 }
2023 else
2024 {
2025 return GetInput(t, 2);
2026 }
2027 }
2028 }
2029 }
2030
DrawBlockSymbol()2031 void IOTimeWindow::DrawBlockSymbol()
2032 {
2033 InputOutputElement::DrawBlockSymbol();
2034 }
2035
2036 //$ DR 2011-12:] IOTimeWindow added
2037 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const2038 const char* IOStopComputation::SymbolText() const
2039 {
2040 return CSText_IOStopComputation;
2041 }
2042
GetElementData(ElementDataContainer & edc)2043 void IOStopComputation::GetElementData(ElementDataContainer& edc) //fill in all element data
2044 {
2045 InputOutputElement::GetElementData(edc);
2046
2047 ElementData ed;
2048 }
2049
SetElementData(ElementDataContainer & edc)2050 int IOStopComputation::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
2051 {
2052 int rv = InputOutputElement::SetElementData(edc);
2053
2054 return rv;
2055 }
2056
DrawBlockSymbol()2057 void IOStopComputation::DrawBlockSymbol()
2058 {
2059 InputOutputElement::DrawBlockSymbol();
2060 }
2061
2062 //
2063 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2064
2065
2066 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2067 // functions for class IOElementDataModifier
2068
GetCopy()2069 Element* IOElementDataModifier::GetCopy()
2070 {
2071 Element* ec = new IOElementDataModifier(mbs);
2072 ec->CopyFrom(*this);
2073
2074 return ec;
2075 }
2076
CopyFrom(const Element & e)2077 void IOElementDataModifier::CopyFrom(const Element& e)
2078 {
2079 InputOutputElement::CopyFrom(e);
2080 const IOElementDataModifier& ce = (const IOElementDataModifier&)e;
2081
2082 RWdata = ce.RWdata;
2083 element_number = ce.element_number;
2084 variable_name = ce.variable_name;
2085 modify_at_start_time_step_only = ce.modify_at_start_time_step_only;
2086 }
2087
InitConstructor()2088 void IOElementDataModifier::InitConstructor()
2089 {
2090 InputOutputElement::InitConstructor();
2091
2092 type = TMBSElement(type + TIOElementDataModifier);
2093
2094 elementname = GetElementSpec();
2095
2096 RWdata.comp1 = 0;
2097 RWdata.comp2 = 0;
2098 RWdata.value = 0.;
2099
2100 RWdata.RWaccess = TRWElementDataNoAccess;
2101 element_number = 1;
2102 variable_name = mystr("");
2103
2104 modify_at_start_time_step_only = 0;
2105 }
2106
SymbolText() const2107 const char* IOElementDataModifier::SymbolText() const
2108 {
2109 return CSText_IOElementDataModifier;
2110 }
2111
GetElementData(ElementDataContainer & edc)2112 void IOElementDataModifier::GetElementData(ElementDataContainer& edc) //fill in all element data
2113 {
2114 InputOutputElement::GetElementData(edc);
2115 ElementData ed;
2116 ed.SetText(variable_name.c_str(),"mod_variable_name"); ed.SetToolTipText("variable name of the modified element data"); edc.TreeAdd("IOBlock",ed);
2117 ed.SetInt(element_number,"mod_element_number"); ed.SetToolTipText("element number of the modified element or constraint"); edc.TreeAdd("IOBlock",ed);
2118
2119 //ElementData ed;
2120 }
2121
SetElementData(ElementDataContainer & edc)2122 int IOElementDataModifier::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
2123 {
2124 //TODO: resize matrix, if user change the size!!!
2125 int rv = InputOutputElement::SetElementData(edc);
2126
2127 ElementData ed;
2128 GetElemDataText(GetMBS(), edc, "IOBlock.mod_variable_name",variable_name, 1);
2129 GetElemDataInt(GetMBS(), edc, "IOBlock.mod_element_number",element_number, 1);
2130
2131 SetIOElementDataModifier(element_number, variable_name.c_str());
2132
2133 return rv;
2134 }
2135
DrawBlockSymbol()2136 void IOElementDataModifier::DrawBlockSymbol()
2137 {
2138 return InputOutputElement::DrawBlockSymbol();
2139
2140 Vector3D refpos = GetRefPosD();
2141 Vector2D center(refpos.X(),refpos.Y());
2142 Vector2D size(draw_dim.X(), draw_dim.Y());
2143
2144
2145 //dial
2146 Vector2D dial = center + Vector2D( 0., -0.1*draw_dim.Y());
2147 GetMBS()->AddDrawComponent_Ellipse( GetOwnNum(), TIOBlock, // MBS identifier
2148 1, TSymbol, // DRAW identifier
2149 dial , 0.5*size, // extent
2150 Vector3D(0.,0.,0.), Vector3D(.5,.5,.5)); // color
2151
2152 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
2153 1, TSymbol, // DRAW identifier
2154 dial+Vector2D(0., 0.15*size.Y()) , dial+Vector2D(0., 0.25*size.Y()), // extent
2155 Vector3D(0.,0.,0.) ); // color
2156
2157 int nr_of_ticks = 7;
2158 double angle_first=0.;
2159 double angle_last=180.;
2160 for (int i=1; i<=7; i++)
2161 {
2162 double angle = (MY_PI / 180.) * ((angle_last-angle_first) / (double) (nr_of_ticks-1) ) * (i-1.);
2163 Vector2D dir( size.X()*cos(angle), size.Y()*sin(angle) );
2164
2165 GetMBS()->AddDrawComponent_Line( GetOwnNum(), TIOBlock, // MBS identifier
2166 1, TConnectionLine, // DRAW identifier
2167 dial + 0.3*dir , dial + 0.4*dir, // extent
2168 Vector3D(0.,0.,0.) ); // color
2169
2170 }
2171 }
2172
2173
2174 // SM: 10012013
2175 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2176
2177
2178
2179 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const2180 const char* IODisplay::SymbolText() const
2181 {
2182 return CSText_IODisplay;
2183 }
2184
GetElementData(ElementDataContainer & edc)2185 void IODisplay::GetElementData(ElementDataContainer& edc) //fill in all element data
2186 {
2187 InputOutputElement::GetElementData(edc);
2188 ElementData ed;
2189 }
2190
SetElementData(ElementDataContainer & edc)2191 int IODisplay::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
2192 {
2193 int rv = InputOutputElement::SetElementData(edc);
2194 return rv;
2195 }
2196
DrawBlockSymbol()2197 void IODisplay::DrawBlockSymbol()
2198 {
2199 Vector3D refpos = GetRefPosD();
2200 Vector2D center(refpos.X(),refpos.Y());
2201 Vector2D size(draw_dim.X(), draw_dim.Y());
2202
2203 double t = GetMBS()->GetDrawTime();
2204 double value = XDataD(1); // $ MSax 2013-03-01: added
2205 mystr text(value,ndigits);
2206
2207 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
2208 1, TSymbol, // DRAW identifier
2209 center, 0.8 * size, // extent
2210 Vector3D(0.,0.,0.), // color of this label is alway black
2211 text, // display value
2212 TTextAllign (HCenter+VCenter) ); // other properties
2213 };
2214
2215
2216 // ELEMENTS for Response to input Key or Mouse during computation
2217 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const2218 const char* IOResponseElement::SymbolText() const
2219 {
2220 return CSText_IOResponseElement;
2221 }
2222
GetElementData(ElementDataContainer & edc)2223 void IOResponseElement::GetElementData(ElementDataContainer& edc) //fill in all element data
2224 {
2225 InputOutputElement::GetElementData(edc);
2226 ElementData ed;
2227 }
2228
SetElementData(ElementDataContainer & edc)2229 int IOResponseElement::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
2230 {
2231 int rv = InputOutputElement::SetElementData(edc);
2232 return rv;
2233 }
2234
DrawBlockSymbol()2235 void IOResponseElement::DrawBlockSymbol()
2236 {
2237 Vector3D refpos = GetRefPosD();
2238 Vector2D center(refpos.X(), refpos.Y());
2239 Vector2D size(draw_dim.X(), draw_dim.Y());
2240
2241 int drawn_value = XData(1);
2242
2243 // display current value
2244 if (IsToggle())
2245 {
2246 Vector3D color_onoff;
2247 if (drawn_value == 0) color_onoff = Vector3D(1.,0.,0.);
2248 if (drawn_value == 1) color_onoff = Vector3D(0.,1.,0.);
2249
2250 GetMBS()->AddDrawComponent_Rect( GetOwnNum(), TIOBlock, // MBS identifier
2251 1, TSymbol, // DRAW identifier
2252 center, 0.5*size, // extent
2253 Vector3D(0.,0.,0.), color_onoff ); // colors
2254 }
2255 else
2256 {
2257 mystr text_curr(drawn_value);
2258 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
2259 1, TSymbol, // DRAW identifier
2260 center, 0.8 * size, // extent
2261 Vector3D(0.,0.,0.), // color of this label is alway black
2262 text_curr, // display value
2263 TTextAllign (HCenter+VCenter) ); // other properties
2264 }
2265
2266 // marker mode in upper left corner
2267 mystr text_mode;
2268 Vector2D mode_m(refpos.X()-0.4*draw_dim.X(), refpos.Y()+0.4*draw_dim.Y());
2269 Vector2D mode_s(0.2*draw_dim.X(), 0.2*draw_dim.Y());
2270 if (GetInputMode() == TMouseResponse) text_mode = mystr("M");
2271 if (GetInputMode() == TKeyResponse) text_mode = mystr("K");
2272 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
2273 2, TSymbol, // DRAW identifier
2274 mode_m, mode_s, // extent
2275 Vector3D(0.,0.,0.), // color of this label is alway black
2276 text_mode, // display value
2277 TTextAllign (HCenter+VTop) ); // other properties
2278 // marker range at bottom
2279 mystr text_range;
2280 Vector2D range_c(refpos.X(), refpos.Y()-0.35*draw_dim.Y());
2281 Vector2D range_s(draw_dim.X(), 0.2*draw_dim.Y());
2282 if (IsToggle()) text_range = mystr("[on/off]");
2283 else text_range = mystr("[") + mystr(lower_bound) + mystr(",") + mystr(upper_bound) + mystr("]");
2284 GetMBS()->AddDrawComponent_Text( GetOwnNum(), TIOBlock, // MBS identifier
2285 3, TSymbol, // DRAW identifier
2286 range_c, range_s, // extent
2287 Vector3D(0.,0.,0.), // color of this label is alway black
2288 text_range, // display value
2289 TTextAllign (HCenter+VCenter) ); // other properties
2290 }
2291
2292 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SymbolText() const2293 const char* IOMinMax::SymbolText() const
2294 {
2295 return CSText_IOMinMax;
2296 }
2297
CheckConsistency(mystr & errorstr)2298 int IOMinMax::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
2299 {
2300 int rv = InputOutputElement::CheckConsistency(errorstr);
2301 if(rv){ return rv;}
2302
2303 return rv;
2304 }
2305
StartTimeStep()2306 void IOMinMax::StartTimeStep()
2307 {
2308 double t = mbs->GetTime();
2309 double u = GetInput(t, 1);
2310
2311 if(t<start_time)
2312 {
2313 current_value = u;
2314 }
2315 else
2316 {
2317 if(first_time_step)
2318 {
2319 current_value = u;
2320 if(mode >= 4) {current_value = fabs(current_value);}
2321 first_time_step = 0;
2322 WriteToXData();
2323 }
2324 else
2325 {
2326 switch(mode)
2327 {
2328 case 1: {current_value = min(XData(1),u); break;}
2329 case 2: {current_value = max(XData(1),u); break;}
2330 case 3: {current_value = XData(1)+u; break;}
2331 case 4: {current_value = min(XData(1),fabs(u)); break;}
2332 case 5: {current_value = max(XData(1),fabs(u)); break;}
2333 case 6: {current_value = XData(1)+fabs(u); break;}
2334 }
2335 WriteToXData();
2336 }
2337 }
2338 }
2339
2340 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2341 // functions for class IOTCPIPBlock
2342
GetCopy()2343 Element* IOTCPIPBlock::GetCopy()
2344 {
2345 Element* ec = new IOTCPIPBlock(mbs);
2346 ec->CopyFrom(*this);
2347
2348 return ec;
2349 }
2350
CopyFrom(const Element & e)2351 void IOTCPIPBlock::CopyFrom(const Element& e)
2352 {
2353 InputOutputElement::CopyFrom(e);
2354 const IOTCPIPBlock& ce = (const IOTCPIPBlock&)e;
2355
2356 port_number = ce.port_number;
2357 ip_address = ce.ip_address;
2358 timeout = ce.timeout;
2359 serversocket = ce.serversocket;
2360 tcpdata = ce.tcpdata;
2361 addtcpdata = ce.addtcpdata;
2362 use_default_protocol = ce.use_default_protocol;
2363 use_additional_communication = ce.use_additional_communication;
2364 separate_additional_communication = ce.separate_additional_communication;
2365 additional_communication_length = ce.additional_communication_length;
2366 additional_communication_unit_size = ce.additional_communication_unit_size;
2367 isinitialized = ce.isinitialized;
2368
2369 }
2370
InitConstructor()2371 void IOTCPIPBlock::InitConstructor()
2372 {
2373 InputOutputElement::InitConstructor();
2374
2375 //type = TMBSElement(type + TIOTCPIPBlock);
2376
2377 elementname = GetElementSpec();
2378 port_number = 50000;
2379 ip_address = mystr("127.0.0.1");
2380 use_default_protocol = 1;
2381 use_additional_communication = 1;
2382 separate_additional_communication = 0;
2383 additional_communication_length = 1;
2384 additional_communication_unit_size = 8;
2385 timeout = 10000;
2386 isinitialized = 0;
2387 }
2388
SymbolText() const2389 const char* IOTCPIPBlock::SymbolText() const
2390 {
2391 return CSText_IOTCPIPBlock;
2392 }
2393
SetElementData(ElementDataContainer & edc)2394 int IOTCPIPBlock::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
2395 {
2396 int rv = InputOutputElement::SetElementData(edc);
2397
2398 Vector datainit(DataS());
2399 datainit.SetAll(0.);
2400 SetDataInit(datainit);
2401
2402 return rv;
2403 }
2404
Initialize()2405 void IOTCPIPBlock::Initialize() // allocate memory and initialize TCP/IP connection
2406 {
2407 double tnew;
2408 static double told;
2409 if(!isinitialized)
2410 {
2411 told=-1;
2412 //ensure consistency
2413 if(use_default_protocol)
2414 {
2415 use_additional_communication = 1;
2416 separate_additional_communication = 0;
2417 additional_communication_length = 1;
2418 additional_communication_unit_size = 8;
2419 }
2420 else if(!use_additional_communication)
2421 {
2422 separate_additional_communication = 0;
2423 additional_communication_length = 0;
2424 additional_communication_unit_size = 8;
2425 }
2426 if(additional_communication_unit_size!=1 && additional_communication_unit_size!=2 && additional_communication_unit_size!=4 && additional_communication_unit_size!=8)
2427 {
2428 additional_communication_unit_size = 8;
2429 mbs->UO(UO_LVL_warn) << "Warning in IOTCPIPBlock: additional_communication_unit_size was reset to default (8 bytes)\n";
2430 }
2431
2432 tcpdata = new double[(GetNInputs()>GetNOutputs() ? GetNInputs() : GetNOutputs()) + additional_communication_length + 1 ];
2433
2434 if(use_additional_communication)
2435 {
2436 addtcpdata = new char[additional_communication_length*additional_communication_unit_size];
2437 }
2438
2439 if(!serversocket)
2440 {
2441 serversocket = new TCPIPHotInt;
2442 serversocket->Set(mbs,SocketType::ST_server,ip_address.c_str(),port_number,1,1);
2443 serversocket->SetAutoReconnect(0);
2444 serversocket->SetAcceptTimeOut(timeout);
2445 serversocket->SetUpConnection();
2446 serversocket->SetRecvTimeOut(timeout);
2447 serversocket->SetSendTimeOut(timeout);
2448 }
2449
2450 isinitialized = 1;
2451 }
2452
2453 if(use_default_protocol)
2454 {
2455 //set reset-flag in additional communication per default
2456 SetCommunicationFlag(0,Freset,1);
2457 //communication of the reset flag and initial values
2458 tnew = mbs->GetTime(); //ensure that this is only done once per simulation run (single computation or one computation of a parameter variation)
2459 if(abs(tnew-told)>1E-14)
2460 {
2461 Communicate(tnew);
2462 told=tnew;
2463 }
2464 SetCommunicationFlag(0,Fneutral,1);
2465 }
2466 else
2467 {
2468 //to be implemented as required
2469 }
2470 }
2471
CloseAndCleanUp()2472 void IOTCPIPBlock::CloseAndCleanUp()
2473 {
2474 if(isinitialized && mbs->GetSimulationStatus().GetStatusFlag(TSimulationProcessFinished))
2475 {
2476 SetCommunicationFlag(0,Fclose,1);
2477 OutgoingDataCommunication(GetMBS()->GetTime());
2478 delete [] tcpdata;
2479 if(use_additional_communication)
2480 delete [] addtcpdata;
2481
2482 if(serversocket)
2483 {
2484 serversocket->CloseConnection();
2485 delete [] serversocket;
2486 serversocket = NULL;
2487 }
2488
2489 isinitialized = 0;
2490 }
2491 }
2492
~IOTCPIPBlock()2493 IOTCPIPBlock::~IOTCPIPBlock()
2494 {
2495 CloseAndCleanUp();
2496 }
2497
ComputationFinished()2498 void IOTCPIPBlock::ComputationFinished()
2499 {
2500 CloseAndCleanUp();
2501 //if(isinitialized)
2502 //{
2503 // if(GetMBS()->GetMBS_EDC_Options()->TreeGetInt("SolverOptions.ParameterVariation.activate"))
2504 // {
2505 // //without the following, when the parameter variation is finished, the client will just run into a recv timeout
2506
2507 // //if(parameter variation is finished)
2508 // //{
2509 // // SetCommunicationFlag(0,Fclose,1);
2510 // // OutgoingDataCommunication(GetMBS()->GetStepEndTime());
2511 // //}
2512 // }
2513 // else
2514 // {
2515 // //SetCommunicationFlag(0,Fclose,1);
2516 // //OutgoingDataCommunication(GetMBS()->GetStepEndTime());
2517 // //TSimulationStatus stat = mbs->GetSimulationStatus();
2518 // CloseAndCleanUp();
2519 // }
2520 //}
2521 }
2522
OutgoingDataCommunication(double t)2523 void IOTCPIPBlock::OutgoingDataCommunication(double t)
2524 {
2525 //outgoing data transfer
2526 *(tcpdata)=t;
2527 int nin = GetNInputs();
2528 for(int i=0; i<nin; ++i)
2529 *(tcpdata+i+1)=GetInput(t,i+1);
2530 if(use_additional_communication && !separate_additional_communication)
2531 {
2532 double* temp = (double*) addtcpdata;
2533 for(int i=0; i<additional_communication_length; ++i)
2534 *(tcpdata+nin+i+1) = *(temp+i);
2535 }
2536 serversocket->SendData((char*)tcpdata,(1+nin+additional_communication_length)*8);
2537 }
2538
IncomingDataCommunication()2539 void IOTCPIPBlock::IncomingDataCommunication()
2540 {
2541 //incoming data transfer
2542 int nout = GetNOutputs();
2543 serversocket->RecvData((char*)tcpdata,(nout+additional_communication_length)*8);
2544 for(int i=0; i<nout; ++i)
2545 SetOutput(*(tcpdata+i),i+1);
2546 if(use_additional_communication && !separate_additional_communication)
2547 {
2548 double* temp = (double*) addtcpdata;
2549 for(int i=0; i<additional_communication_length; ++i)
2550 *(temp+i) = *(tcpdata+nout+i);
2551 }
2552 }
2553
Communicate(double t)2554 void IOTCPIPBlock::Communicate(double t)
2555 {
2556 if(use_additional_communication && !separate_additional_communication)
2557 {
2558 OutgoingDataCommunication(t);
2559 IncomingDataCommunication();
2560 ReactToAdditionalCommunication(t);
2561 }
2562 else if(use_additional_communication && separate_additional_communication)
2563 {
2564 serversocket->SendData(addtcpdata,additional_communication_length*additional_communication_unit_size);
2565 serversocket->RecvData(addtcpdata,additional_communication_length*additional_communication_unit_size);
2566 int commdata = ReactToAdditionalCommunication(t);
2567 if(commdata)
2568 {
2569 OutgoingDataCommunication(t);
2570 IncomingDataCommunication();
2571 }
2572 }
2573 else
2574 {
2575 OutgoingDataCommunication(t);
2576 IncomingDataCommunication();
2577 }
2578 }
2579
SetCommunicationFlag(int pos,CommunicationFlag flag,int convertdouble)2580 void IOTCPIPBlock::SetCommunicationFlag(int pos, CommunicationFlag flag, int convertdouble)
2581 {
2582 if(convertdouble)
2583 {
2584 double temp = (double)(int)flag;
2585 *(double*)(addtcpdata+pos) = temp;
2586 }
2587 else
2588 *(int*)(addtcpdata+pos) = (int)flag;
2589 }
2590
GetCommunicationFlag(int pos,int convertdouble)2591 CommunicationFlag IOTCPIPBlock::GetCommunicationFlag(int pos, int convertdouble)
2592 {
2593 if(convertdouble)
2594 {
2595 return (CommunicationFlag)(int)*(double*)(addtcpdata+pos);
2596 }
2597 else
2598 return (CommunicationFlag)(*(int*)(addtcpdata+pos));
2599 }
2600
2601 //called by Communicate(double t)
2602 //read received data and respond somehow
2603 //possibly rewrite addtcpdata and call Communicate(t) recursively for complex communication schemes
ReactToAdditionalCommunication(double t)2604 int IOTCPIPBlock::ReactToAdditionalCommunication(double t)
2605 {
2606 //default
2607 if(use_default_protocol)
2608 {
2609 switch(GetCommunicationFlag(0,1))
2610 {
2611 case Fneutral:
2612 break;
2613 case Ferror:
2614 mbs->UO().InstantMessageText("An error occurred on the client side!\n");
2615 assert(0);
2616 exit(0);
2617 break;
2618 default:
2619 mbs->UO().InstantMessageText("Received an unknown command from the client!\n");
2620 assert(0);
2621 exit(0);
2622 break;
2623 }
2624 }
2625 else
2626 {
2627 //to be implemented as required
2628 }
2629
2630 return 1; //returns a flag deciding if DataCommunication(t) should be called afterwards in case of separate add�onal communication
2631 }
2632