Skip to content

Commit dff5c30

Browse files
committed
Preparing for combining Modia with Modia3D (Modia3D: model_f1, model_f2 functions provided)
1 parent 0724cb6 commit dff5c30

File tree

3 files changed

+240
-14
lines changed

3 files changed

+240
-14
lines changed

src/Composition/_module.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ export initialize, initAnalysis!, performAnalysis!, closeAnalysis!, visualize!,
3636
export updatePosition!, update!, driveJoint!
3737
export Object3D, AssemblyInternal, initAssemblyInternal!, initAssemblyComponent!, Scene
3838
export Part
39-
export SimulationModel
39+
export SimulationModel, Model
4040
export BodyWithTwoFrames, ContactBox, ContactBox2, ContactBox3
4141
export printObject3DAndAllChildren, writeObject3DAndAllChildrenOnJsonFile
4242
export set_r!, set_q!, set_r_abs!
4343
export Fixed
4444
export Revolute, setAngle!, connect, addRevoluteTorqueObject, computeTorque
4545
export Prismatic, setDistance!
4646
export FreeMotion
47-
export getModelResidues!, getSimulationModelResidues!
47+
export getModelResidues!, model_f1!, model_f2!
4848
export distanceAndAngles, distance, planarRotationAngle
4949

5050
export Flange, RevoluteFlange

src/Composition/dynamics.jl

Lines changed: 237 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,126 @@ function get_WorldObject3D(assembly::Modia3D.AbstractAssembly)::Object3D
5858
end
5959

6060

61+
"""
62+
realScalar = getFlangeVariable(assembly::Modia3D.AbstractAssembly, name::String)
63+
64+
Return the reference of a Revolute or Prismatic flange variable, given the top-level `assembly`
65+
and the full path `name` of the flange variable. If one of the following flange variable names
66+
is provided, a reference to the respective RealScalar is returned:
67+
```
68+
flange_b.phi
69+
flange_b.s
70+
flange_b.tau
71+
flange_b.f
72+
der(<full-name>.flange_b.phi)
73+
der(<full-name>.flange_b.s)
74+
```
75+
76+
If one of the following flange names is provided, `nothing` is returned:
77+
```
78+
flange_a.phi
79+
flange_a.s
80+
flange_a.tau
81+
flange_a.f
82+
der(<full-name>.flange_a.phi)
83+
der(<full-name>.flange_a.s)
84+
```
85+
"""
86+
function getFlangeVariable(assembly::Modia3D.AbstractAssembly, name::String)::Union{ModiaMath.RealScalar,Nothing}
87+
# Handle der(..)
88+
lenName = length(name)
89+
if lenName >= 4 && SubString(name,1,4) == "der("
90+
if SubString(name,lenName,lenName) != ")" || lenName < 6
91+
error("Wrong name = \"", name, "\"")
92+
end
93+
name2 = SubString(name,5,lenName-1)
94+
der = true
95+
else
96+
name2 = name
97+
der = false
98+
end
99+
100+
field = assembly
101+
while true
102+
#println("... before. name2 = ", name2)
103+
i = findnext(".", name2, 1)
104+
#println("... after.")
105+
if i==nothing || length(name2) <= i[1] || i[1] <= 1
106+
error("Name not found: \"", name, "\"")
107+
end
108+
fieldName = Symbol(SubString(name2,1,i[1]-1))
109+
name2 = SubString(name2,i[1]+1)
110+
if !isdefined(field, fieldName)
111+
error("Name not found: \"", name, "\"")
112+
end
113+
field = getfield(field, fieldName)
114+
115+
# Handle the names "flange_a" and "flange_b"
116+
#println("... field name = ", fieldName, ", typeof(field) = ", typeof(field))
117+
if name2=="flange_a.phi"
118+
if typeof(field) == Modia3D.Composition.TreeJointRevolute
119+
return nothing
120+
else
121+
error("Name = \"", name, "\" is no flange variable of a Revolute joint")
122+
end
123+
elseif name2=="flange_a.tau"
124+
if typeof(field) == Modia3D.Composition.TreeJointRevolute
125+
return nothing
126+
else
127+
error("Name = \"", name, "\" is no flange variable of a Revolute joint")
128+
end
129+
elseif name2=="flange_a.s"
130+
if typeof(field) == Modia3D.Composition.TreeJointPrismatic
131+
return nothing
132+
else
133+
error("Name = \"", name, "\" is no flange variable of a Prismatic joint")
134+
end
135+
elseif name2=="flange_a.f"
136+
if typeof(field) == Modia3D.Composition.TreeJointPrismatic
137+
return nothing
138+
else
139+
error("Name = \"", name, "\" is no flange variable of a Prismatic joint")
140+
end
141+
elseif name2=="flange_b.phi"
142+
if typeof(field) == Modia3D.Composition.TreeJointRevolute
143+
return der ? getfield(field,:w) : getfield(field,:phi)
144+
else
145+
error("Name = \"", name, "\" is no flange variable of a Revolute joint")
146+
end
147+
elseif name2=="flange_b.tau"
148+
if typeof(field) == Modia3D.Composition.TreeJointRevolute
149+
if der
150+
error("Name = \"", name, "\" is no flange variable of a Revolute joint")
151+
end
152+
return getfield(field,:tau)
153+
else
154+
error("Name = \"", name, "\" is no flange variable of a Revolute joint")
155+
end
156+
elseif name2=="flange_b.s"
157+
if typeof(field) == Modia3D.Composition.TreeJointPrismatic
158+
return der ? getfield(field,:v) : getfield(field,:s)
159+
else
160+
error("Name = \"", name, "\" is no flange variable of a Prismatic joint")
161+
end
162+
elseif name2=="flange_b.f"
163+
if typeof(field) == Modia3D.Composition.TreeJointPrismatic
164+
if der
165+
error("Name = \"", name, "\" is no flange variable of a Prismatic joint")
166+
end
167+
return getfield(field,:f)
168+
else
169+
error("Name = \"", name, "\" is no flange variable of a Prismatic joint")
170+
end
171+
end
172+
end
173+
end
174+
61175

62176
"""
63177
model = Modia3D.Model(assembly::Modia3D.AbstractAssembly;
64-
analysis::ModiaMath.AnalysisType=ModiaMath.DynamicAnalysis)
178+
analysis::ModiaMath.AnalysisType=ModiaMath.DynamicAnalysis,
179+
potentialNames::Vector{String} = fill("",0),
180+
flowNames::Vector{String} = fill("",0))
65181
66182
Generate a `Modia3D.Model` from an `assembly` generated with macro [`Modia3D.@assembly`](@ref)
67183
and the type of `analysis` to be carried out on the `assembly`.
@@ -77,8 +193,14 @@ struct Model
77193
x_nominal::Vector{Float64}
78194
is_constraint::Vector{Bool}
79195

196+
# For connection with Modia
197+
potentials::Vector{Union{ModiaMath.RealScalar,Nothing}}
198+
flows::Vector{Union{ModiaMath.RealScalar,Nothing}}
199+
80200
function Model(assembly::Modia3D.AbstractAssembly;
81-
analysis::ModiaMath.AnalysisType=ModiaMath.DynamicAnalysis)
201+
analysis::ModiaMath.AnalysisType=ModiaMath.DynamicAnalysis,
202+
potentialNames::Vector{String} = fill("",0),
203+
flowNames::Vector{String} = fill("",0))
82204

83205
name = Modia3D.trailingPartOfName( string( typeof(assembly) ) )
84206
world = get_WorldObject3D(assembly)
@@ -147,17 +269,28 @@ struct Model
147269
build_SignalObject3DConnections!(assembly)
148270
scene.initAnalysis = true
149271

272+
# Generate potentials and flows
273+
potentials = Vector{Union{ModiaMath.RealScalar,Nothing}}(nothing, length(potentialNames))
274+
flows = Vector{Union{ModiaMath.RealScalar,Nothing}}(nothing, length(flowNames))
275+
for i = 1:length(potentialNames)
276+
potentials[i] = getFlangeVariable(assembly, potentialNames[i])
277+
#println("... potentials[", i, "] = ", potentials[i]==nothing ? "nothing" : ModiaMath.instanceName(potentials[i]))
278+
end
279+
for i = 1:length(flowNames)
280+
flows[i] = getFlangeVariable(assembly, flowNames[i])
281+
#println("... flows[", i, "] = ", flows[i]==nothing ? "nothing" : ModiaMath.instanceName(flows[i]))
282+
end
283+
150284
# Generate Model object
151-
new(name, nz, assembly, var, analysis, x_start, x_fixed, x_nominal, is_constraint)
285+
new(name, nz, assembly, var, analysis, x_start, x_fixed, x_nominal, is_constraint, potentials, flows)
152286
end
153287
end
154288

155289

156290

157-
158291
"""
159292
simModel = SimulationModel(assembly::Modia3D.AbstractAssembly;
160-
analysis::ModiaMath.AnalysisType=ModiaMath.DynamicAnalysis,
293+
analysis::ModiaMath.dAnalysisType=ModiaMath.DynamicAnalysis,
161294
startTime = 0.0, stopTime = 1.0, tolerance = 1e-4,
162295
interval = (stopTime-startTime)/500.0,
163296
maxStepSize = NaN, maxNumberOfSteps=missing)
@@ -186,7 +319,7 @@ struct SimulationModel <: ModiaMath.AbstractSimulationModel
186319
hev = 1e-8,
187320
scaleConstraintsAtEvents::Bool = true)
188321
model = Model(assembly; analysis=analysis)
189-
simulationState = ModiaMath.SimulationState(model.name, getSimulationModelResidues!, model.x_start, ModiaMath.Variables.getVariableName;
322+
simulationState = ModiaMath.SimulationState(model.name, getModelResidues!, model.x_start, ModiaMath.Variables.getVariableName;
190323
x_fixed = model.x_fixed,
191324
x_nominal = model.x_nominal,
192325
is_constraint = model.is_constraint,
@@ -239,6 +372,9 @@ struct SimulationModel <: ModiaMath.AbstractSimulationModel
239372
end
240373
end
241374

375+
ModiaMath.print_ModelVariables(model::Model) = ModiaMath.print_ModelVariables(model.var)
376+
print_ModelVariables( model::Model) = ModiaMath.print_ModelVariables(model.var)
377+
242378
ModiaMath.print_ModelVariables(simModel::SimulationModel) = ModiaMath.print_ModelVariables(simModel.model.var)
243379
print_ModelVariables( simModel::SimulationModel) = ModiaMath.print_ModelVariables(simModel.model.var)
244380

@@ -295,13 +431,91 @@ function ModiaMath.getVariableAndResidueValues(simModel::SimulationModel)
295431
end
296432

297433

434+
435+
436+
# Only temporarily here. Shall be moved to ModiaMath
437+
"""
438+
copy_x_to_variables!(x::Vector{Float64}, vars::ModelVariables)
439+
440+
Copy `x` of the integrator interface to the model variables `vars`.
441+
"""
442+
function copy_x_to_variables!(x::Vector{Float64}, m::ModiaMath.ModelVariables)::Nothing
443+
@assert(length(x) == m.nx)
444+
445+
for v in m.x_var
446+
#println("... typeof(", fullName(v), ") = ", typeof(v), ", isimmutable(v) = ", isimmutable(v))
447+
if ModiaMath.isScalar(v)
448+
v.value = x[ v.ivar ]
449+
elseif isimmutable(v.value)
450+
# v is an immutable array (e.g. SVector{3,Float64})
451+
v.value = x[ v.ivar:v.ivar + length(v.value) - 1 ]
452+
else
453+
vv = v.value
454+
for j in 1:length(vv)
455+
vv[j] = x[ v.ivar + j - 1 ]
456+
end
457+
end
458+
end
459+
return nothing
460+
end
461+
462+
463+
"""
464+
copy_derx_to_variables!(time::Float64, derx::Vector{Float64}, vars::ModelVariables)
465+
466+
Copy `time` and `derx` of the integrator interface to the model variables `vars`.
467+
"""
468+
function copy_derx_to_variables!(time::Float64, derx::Vector{Float64}, m::ModiaMath.ModelVariables)::Nothing
469+
@assert(length(derx) == m.nx)
470+
471+
m.var[1].value = time
472+
for v in m.derx_var
473+
if ModiaMath.isScalar(v)
474+
v.value = derx[ v.ivar ]
475+
elseif isimmutable(v.value)
476+
# v is an immutable array (e.g. SVector{3,Float64})
477+
v.value = derx[ v.ivar:v.ivar + length(v.value) - 1 ]
478+
else
479+
vv = v.value
480+
for j in 1:length(vv)
481+
vv[j] = derx[ v.ivar + j - 1 ]
482+
end
483+
end
484+
end
485+
486+
return nothing
487+
end
488+
489+
490+
491+
"""
492+
modelf1!(model, x, potentials)
493+
494+
Copy the potential variables defined for `model::Modia3D.Model` from `x` to vector `potentials`,
495+
"""
496+
function model_f1!(model::Model, x::Vector{Float64}, potentials::Vector{Float64})::Nothing
497+
@assert( length(model.potentials) == length(potentials) )
498+
499+
# Copy (time,x) to model variables
500+
copy_x_to_variables!(x, model.var)
501+
502+
# Copy selected potential variables from model to output argument potentials
503+
for i = 1:length(potentials)
504+
potentials[i] = model.potentials[i] == nothing ? 0.0 : model.potentials[i].value
505+
end
506+
return nothing
507+
end
508+
509+
298510
const str_DUMMY = "dummyDistance(nothing,nothing)"
511+
const zeroVector = Vector{Float64}()
299512

300-
getSimulationModelResidues!(simModel::SimulationModel, time::Float64, _x::Vector{Float64}, _derx::Vector{Float64}, _r::Vector{Float64}, _w::Vector{Float64}) =
301-
getModelResidues!(simModel.model, simModel.simulationState, time, _x, _derx, _r, _w)
513+
getModelResidues!(simModel::SimulationModel, time::Float64, _x::Vector{Float64}, _derx::Vector{Float64}, _r::Vector{Float64}, _w::Vector{Float64}) =
514+
model_f2!(simModel.model, simModel.simulationState, time, _x, _derx, zeroVector, _r, _w)
302515

303-
function getModelResidues!(m::Model, sim::ModiaMath.SimulationState,
304-
time::Float64, _x::Vector{Float64}, _derx::Vector{Float64}, _r::Vector{Float64}, _w::Vector{Float64})
516+
function model_f2!(m::Model, sim::ModiaMath.SimulationState,
517+
time::Float64, _x::Vector{Float64}, _derx::Vector{Float64}, _flows::Vector{Float64},
518+
_r::Vector{Float64}, _w::Vector{Float64})
305519
# println("... time = ", time, ", x = ", _x, ", derx = ", _derx)
306520
world = m.assembly._internal.referenceObject3D
307521
scene = m.assembly._internal.scene
@@ -351,6 +565,7 @@ function getModelResidues!(m::Model, sim::ModiaMath.SimulationState,
351565
@assert(length(_derx) == var.nx)
352566
@assert(length(_r) == var.nx)
353567
@assert(length(_w) == 0)
568+
@assert(length(_flows) == length(m.flows))
354569

355570
storeResults = ModiaMath.isStoreResult(sim) && (scene.visualize || var.nwr > 0 || var.nwc > 0 )
356571

@@ -360,14 +575,25 @@ function getModelResidues!(m::Model, sim::ModiaMath.SimulationState,
360575
end
361576

362577
# Copy x and derx to variables
363-
ModiaMath.copy_x_and_derx_to_variables!(time, _x, _derx, var)
578+
if length(m.potentials) == 0
579+
ModiaMath.copy_x_and_derx_to_variables!(time, _x, _derx, var)
580+
else
581+
copy_derx_to_variables!(time, _derx, var)
582+
end
364583

365584
# Compute signals
366585
initializeFlowVariables(scene)
367586
computationSignals(scene, sim)
368587
setPotentialVariables(scene)
369588
setFlowVariables(scene)
370589

590+
# Copy flows to model variables
591+
for i = 1:length(_flows)
592+
if m.flows[i] != nothing
593+
m.flows[i].value = _flows[i]
594+
end
595+
end
596+
371597
# Initialize force/torque of world-frame
372598
world.dynamics.f = ModiaMath.ZeroVector3D
373599
world.dynamics.t = ModiaMath.ZeroVector3D

src/Modia3D.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Modia3D
55

66
const path = dirname(dirname(@__FILE__)) # Absolute path of package directory
77
const Version = "0.4.1-dev"
8-
const Date = "2019-11-11"
8+
const Date = "2019-11-12"
99

1010
println("\nImporting Modia3D Version $Version ($Date)")
1111

0 commit comments

Comments
 (0)