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