From a52415bf037ae4985e427e0eead92eba5c3991ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 15:49:38 +0200 Subject: [PATCH 1/8] update optimization result even if result is not optimal --- src/optimization.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/optimization.jl b/src/optimization.jl index e154ff8..6a827a9 100644 --- a/src/optimization.jl +++ b/src/optimization.jl @@ -211,6 +211,7 @@ end function setjumpresult!(mop::MultiOperationProblem, jump_model) status = termination_status(jump_model) if status != TerminationStatusCode(1) + mop.opresult = OptimizationResult(string(status), NaN) @warn "Optimization did not find optimum! Ignoring result. Status: $status" return mop end @@ -220,7 +221,7 @@ function setjumpresult!(mop::MultiOperationProblem, jump_model) pz.position[j] = jump_result[i, j] end end - jump_status = string(termination_status(jump_model)) + jump_status = string(status) jump_minallowance = value(jump_model[:minAllowance]) or = OptimizationResult(jump_status, jump_minallowance) mop.opresult = or From d9bb9e63241aeda66e42d062c7888ebf17e2e0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 16:05:29 +0200 Subject: [PATCH 2/8] begin tests with partzeros --- Project.toml | 6 ++++-- test/partzeros.jl | 18 ++++++++++++++++++ test/runtests.jl | 9 ++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 test/partzeros.jl diff --git a/Project.toml b/Project.toml index 504a76e..6f0fada 100644 --- a/Project.toml +++ b/Project.toml @@ -18,11 +18,13 @@ DataFrames = "1" JuMP = "1.4" Meshes = "0.34,0.35" PrettyTables = "2" -julia = "1.9" Rotations = "1.5" +julia = "1.9" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" +Meshes = "eacbb407-ea5a-433e-ab97-5258b1ca43fa" [targets] -test = ["Test"] +test = ["Test", "Ipopt", "Meshes"] diff --git a/test/partzeros.jl b/test/partzeros.jl new file mode 100644 index 0000000..4b7b9e5 --- /dev/null +++ b/test/partzeros.jl @@ -0,0 +1,18 @@ +@testset "PartZero" begin + pz1 = PartZero("pz1", [0,0,0], hcat([0,1,0], [0,0,1], [1,0,0])) + pz2 = PartZero("pz", [0,0,0], hcat([0,1,0], [0,0,1], [1,0,0])) + + @test BLC.xaxis(pz1) == [0, 1, 0] + @test BLC.yaxis(pz1) == [0, 0, 1] + @test BLC.zaxis(pz1) == [1, 0, 0] + + M = BLC.getpartzeroHM(pz1) + Mt = [0 0 1 0; 1 0 0 0; 0 1 0 0; 0 0 0 1] + @test M == Mt + + @test inv(Mt) == BLC.getpartzeroinverseHM(pz1) + @test inv(Mt) == BLC.inverthomtr(Mt) + + pz = BLC.getpartzerobyname([pz1, pz2], "pz") + @test pz === pz2 +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 33787e3..1df97b0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,9 @@ using BlankLocalizationCore using Test -@testset "BlankLocalizationCore.jl" begin - # Write your tests here. -end +using Meshes +using Ipopt + +const BLC = BlankLocalizationCore + +include("partzeros.jl") \ No newline at end of file From 6157a66b3e977142975328aeaef6ef0ba3093514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 16:25:09 +0200 Subject: [PATCH 3/8] test part of geometries --- test/geometries.jl | 47 ++++++++++++++++++++++++++++++++++++++++++++++ test/partzeros.jl | 2 +- test/runtests.jl | 3 ++- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 test/geometries.jl diff --git a/test/geometries.jl b/test/geometries.jl new file mode 100644 index 0000000..e199ee7 --- /dev/null +++ b/test/geometries.jl @@ -0,0 +1,47 @@ +@testset "IsPrimitive geometries" begin + sh = SimpleHole([0, 0, 0], 29) + sp = SimplePlane([0, 0, 0]) + + @test featurepoint(sh) == [0, 0, 0] + @test featureradius(sh) == 29 + @test featurepoint(sp) == [0, 0, 0] + + @test_throws MethodError featureradius(sp) + @test_throws ErrorException surfacepoints(sp) + @test_throws ErrorException surfacepoints(sh) + @test_throws ErrorException filteredsurfacepoints(sp) + @test_throws ErrorException filteredsurfacepoints(sh) + + pz1 = PartZero("pz1", [0, 0, 0], hcat([0, 1, 0], [0, 0, 1], [1, 0, 0])) + sh_r = SimpleHole([82.5, 30, 40], 26) + sp_r = PlaneAndNormal([82.5, 30, 40], [1, 0, 0]) + fd_sh = FeatureDescriptor("simple-hole", pz1, true, true) + fd_sp = FeatureDescriptor("simple-plane", pz1, true, true) + + h1 = HoleLocalizationFeature(fd_sh, sh_r, sh) + p1 = PlaneLocalizationFeature(fd_sp, sp_r, sp) + + @test BLC.getfeaturename(h1) == "simple-hole" + @test BLC.getfeaturename(p1) == "simple-plane" + @test BLC.getpartzero(h1) === BLC.getpartzero(p1) === pz1 + @test BLC.getpartzeroname(h1) == "pz1" + @test BLC.hasrough(h1) + @test BLC.hasrough(p1) + @test BLC.hasmachined(h1) + @test BLC.hasmachined(p1) + + @test BLC.getroughfeaturepoint(h1) == [82.5, 30, 40] + @test BLC.getroughfeaturepoint(p1) == [82.5, 30, 40] + @test BLC.getmachinedfeaturepoint(h1) == [0, 0, 0] + @test BLC.getmachinedfeaturepoint(p1) == [0, 0, 0] + @test BLC.getmachinedradius(h1) == 29 + @test_throws MethodError BLC.getmachinedradius(p1) + @test BLC.getroughradius(h1) == 26 + @test_throws MethodError BLC.getroughradius(p1) + + @test_throws ErrorException BLC.getroughfilteredpoints(h1) + @test_throws ErrorException BLC.getroughfilteredpoints(p1) + + @test BLC.getmachinedfeaturepointindatum(h1) == [0, 0, 0] + @test BLC.getmachinedfeaturepointindatum(p1) == [0, 0, 0] +end diff --git a/test/partzeros.jl b/test/partzeros.jl index 4b7b9e5..3117b2a 100644 --- a/test/partzeros.jl +++ b/test/partzeros.jl @@ -15,4 +15,4 @@ pz = BLC.getpartzerobyname([pz1, pz2], "pz") @test pz === pz2 -end \ No newline at end of file +end diff --git a/test/runtests.jl b/test/runtests.jl index 1df97b0..21e5710 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,4 +6,5 @@ using Ipopt const BLC = BlankLocalizationCore -include("partzeros.jl") \ No newline at end of file +include("partzeros.jl") +include("geometries.jl") From 242a6a03105a5300ec4e9ffc7a6e844b1614f740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 16:37:27 +0200 Subject: [PATCH 4/8] allow local solutions as well closes #23 --- src/optimization.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/optimization.jl b/src/optimization.jl index 6a827a9..919c5b5 100644 --- a/src/optimization.jl +++ b/src/optimization.jl @@ -210,7 +210,7 @@ end function setjumpresult!(mop::MultiOperationProblem, jump_model) status = termination_status(jump_model) - if status != TerminationStatusCode(1) + if (status != OPTIMAL) & (status != LOCALLY_SOLVED) mop.opresult = OptimizationResult(string(status), NaN) @warn "Optimization did not find optimum! Ignoring result. Status: $status" return mop From 749d7986f3351be4ef6584e3d9e6df90fa51cb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 17:10:34 +0200 Subject: [PATCH 5/8] document mop --- src/geometries.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/geometries.jl b/src/geometries.jl index 3871dc7..a0a3c74 100644 --- a/src/geometries.jl +++ b/src/geometries.jl @@ -327,6 +327,12 @@ struct Tolerance note::String end +""" + MultiOperationProblem + +Collect all data for a multi operation problem, including: part zeros, holes, planes, +tolerances, parameters and optimization result. +""" mutable struct MultiOperationProblem partzeros::Vector{PartZero} holes::Vector{HoleLocalizationFeature} @@ -336,6 +342,23 @@ mutable struct MultiOperationProblem opresult::OptimizationResult end +""" + MultiOperationProblem(partzeros, holes, planes, tolerances, parameters) + +Construct a multi operation problem. +For usage, please see the example section in the documentation. +The parameters for the optimization are also described there with greater details. + +# Arguments + +- `partzeros::Vector{PartZero}`: array of part zeros. +- `holes::Vector{HoleLocalizationFeature}`: array of holes. +- `planes::Vector{PlaneLocalizationFeature}`: array of planes. +- `tolerances::Vector{Tolerance}`: array of tolerances. +- `parameters::Dict{String,Any}`: parameters in the form of a dictionary. Keys include: + `minAllowance`, `OptimizeForToleranceCenter`, `UseTolerances`, + `SetPartZeroPosition`, `maxPlaneZAllowance`. +""" function MultiOperationProblem(partzeros, holes, planes, tolerances, parameters) return MultiOperationProblem(partzeros, holes, planes, tolerances, parameters, emptyor()) end From e5fd0925f922f02f6bbd7dacc442e7a61d9a01dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 17:18:01 +0200 Subject: [PATCH 6/8] new parameter: maxPlaneZAllowance --- docs/src/example.md | 68 +++++++++++++++++++++++---------------------- src/optimization.jl | 10 +++++++ 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/docs/src/example.md b/docs/src/example.md index 7c9d57d..88aa206 100644 --- a/docs/src/example.md +++ b/docs/src/example.md @@ -257,6 +257,7 @@ These are: | OptimizeForToleranceCenter | The default method is to optimize for the middle (center) of the tolerance fields. For debugging, one can set it to `false`, then the minimum allowance will be maximised (ignoring the `minAllowance` value). | `true` | Required | | UseTolerances | Also a debugging feature. Tolerance lower-upper values are added as active constraints on the distance of the corresponding features. This can be turned off with this flag. | `true` | Required | | SetPartZeroPosition | The position of each part zero can be set with this option. A vector of 3 long vectors is expected, that is matched with the number of part zeros. Empty vectors can be passed, if not all part zero positions should be set. For example setting this option to `[[], [], []]` for three part zeros will have no effect. `NaN` elements are ignored, which means that specific axes of part zeros can be set. For example `[[NaN, 150, Nan], [], []]` would only set the value of the Y axis of the first part zero, all others are unaffected. | | Optional | +| maxPlaneZAllowance | The allowance has no upper bound by default. For planes, it is possible to set an upper bound to avoid the issue of "machining the whole part away". | | Optional | We need to load the JuMP package and also an optimizer. For the papers we used FICO Xpress, therefore here it will be used as well, thanks to the [Xpress.jl](https://github.com/jump-dev/Xpress.jl) package. @@ -266,7 +267,8 @@ The [Ipopt](https://github.com/jump-dev/Ipopt.jl) and [SCIP](https://github.com/ ```julia ## Constructing and solving the optimization problem -pard = Dict("minAllowance"=>0.5, "OptimizeForToleranceCenter"=>false, "UseTolerances"=>true); +pard = Dict("minAllowance"=>0.5, "OptimizeForToleranceCenter"=>true, + "UseTolerances"=>true, "maxPlaneZAllowance"=>1); mop = MultiOperationProblem(partzeros, holes, planes, tolerances, pard) @@ -293,41 +295,41 @@ julia> printallowancetable(mop) ┌────────────┬──────────────┬───────────┬───────────┬───────────┬────────┬────────┬────────┬───────────┬────────┬────────────┬───────────┬────────────┬─────────────┐ │ name │ partzeroname │ machinedx │ machinedy │ machinedz │ roughx │ roughy │ roughz │ machinedr │ roughr │ xydistance │ zdistance │ rallowance │ axallowance │ ├────────────┼──────────────┼───────────┼───────────┼───────────┼────────┼────────┼────────┼───────────┼────────┼────────────┼───────────┼────────────┼─────────────┤ -│ fronthole │ front │ 82.0 │ 29.4474 │ 39.9856 │ 82.5 │ 30.0 │ 40.0 │ 29.0 │ 26.0 │ 0.552773 │ │ 2.44723 │ │ -│ righthole1 │ right │ 66.0 │ 70.4474 │ 54.9856 │ 66.0 │ 71.5 │ 55.0 │ 7.5 │ 6.0 │ 0.0143979 │ │ 1.4856 │ │ -│ righthole2 │ right │ 57.0 │ 73.4474 │ 23.9856 │ 58.0 │ 74.5 │ 24.0 │ 9.0 │ 4.905 │ 1.0001 │ │ 3.0949 │ │ -│ righthole3 │ right │ 22.0 │ 67.4474 │ 39.9856 │ 21.5 │ 68.5 │ 40.0 │ 13.5 │ 8.0 │ 0.500207 │ │ 4.99979 │ │ -│ backhole1 │ back │ -2.5 │ 43.4474 │ 53.9856 │ -3.0 │ 44.0 │ 53.9 │ 9.0 │ 6.2 │ 0.559177 │ │ 2.24082 │ │ -│ backhole2 │ back │ -2.5 │ 15.4474 │ 53.9856 │ -3.0 │ 16.1 │ 54.0 │ 9.0 │ 6.25 │ 0.652744 │ │ 2.09726 │ │ -│ frontface │ front │ 82.0 │ 29.4474 │ 39.9856 │ 82.5 │ 30.0 │ 40.0 │ │ │ │ -0.5 │ │ 0.5 │ -│ rightface1 │ right │ 66.0 │ 70.4474 │ 54.9856 │ 66.0 │ 71.5 │ 55.0 │ │ │ │ -1.05259 │ │ 1.05259 │ -│ rightface2 │ right │ 57.0 │ 73.4474 │ 23.9856 │ 58.0 │ 74.5 │ 24.0 │ │ │ │ -1.05259 │ │ 1.05259 │ -│ rightface3 │ right │ 22.0 │ 67.4474 │ 39.9856 │ 21.5 │ 68.5 │ 40.0 │ │ │ │ -1.05259 │ │ 1.05259 │ -│ backface1 │ back │ -2.5 │ 43.4474 │ 53.9856 │ -3.0 │ 44.0 │ 54.0 │ │ │ │ -0.5 │ │ 0.5 │ -│ backface2 │ back │ -2.5 │ 15.4474 │ 53.9856 │ -3.0 │ 16.0 │ 54.0 │ │ │ │ -0.5 │ │ 0.5 │ +│ fronthole │ front │ 82.0 │ 29.7785 │ 39.986 │ 82.5 │ 30.0 │ 40.0 │ 29.0 │ 26.0 │ 0.221918 │ │ 2.77808 │ │ +│ righthole1 │ right │ 66.0 │ 70.7785 │ 54.986 │ 66.0 │ 71.5 │ 55.0 │ 7.5 │ 6.0 │ 0.014046 │ │ 1.48595 │ │ +│ righthole2 │ right │ 57.0 │ 73.7785 │ 23.986 │ 58.0 │ 74.5 │ 24.0 │ 9.0 │ 4.905 │ 1.0001 │ │ 3.0949 │ │ +│ righthole3 │ right │ 22.0 │ 67.7785 │ 39.986 │ 21.5 │ 68.5 │ 40.0 │ 13.5 │ 8.0 │ 0.500197 │ │ 4.9998 │ │ +│ backhole1 │ back │ -2.5 │ 43.7785 │ 53.986 │ -3.0 │ 44.0 │ 53.9 │ 9.0 │ 6.2 │ 0.237568 │ │ 2.56243 │ │ +│ backhole2 │ back │ -2.5 │ 15.7785 │ 53.986 │ -3.0 │ 16.1 │ 54.0 │ 9.0 │ 6.25 │ 0.32178 │ │ 2.42822 │ │ +│ frontface │ front │ 82.0 │ 29.7785 │ 39.986 │ 82.5 │ 30.0 │ 40.0 │ │ │ │ -0.5 │ │ 0.5 │ +│ rightface1 │ right │ 66.0 │ 70.7785 │ 54.986 │ 66.0 │ 71.5 │ 55.0 │ │ │ │ -0.721473 │ │ 0.721473 │ +│ rightface2 │ right │ 57.0 │ 73.7785 │ 23.986 │ 58.0 │ 74.5 │ 24.0 │ │ │ │ -0.721473 │ │ 0.721473 │ +│ rightface3 │ right │ 22.0 │ 67.7785 │ 39.986 │ 21.5 │ 68.5 │ 40.0 │ │ │ │ -0.721473 │ │ 0.721473 │ +│ backface1 │ back │ -2.5 │ 43.7785 │ 53.986 │ -3.0 │ 44.0 │ 54.0 │ │ │ │ -0.5 │ │ 0.5 │ +│ backface2 │ back │ -2.5 │ 15.7785 │ 53.986 │ -3.0 │ 16.0 │ 54.0 │ │ │ │ -0.5 │ │ 0.5 │ └────────────┴──────────────┴───────────┴───────────┴───────────┴────────┴────────┴────────┴───────────┴────────┴────────────┴───────────┴────────────┴─────────────┘ julia> printtolerancetable(mop) - Tolerance table avgabsreltolerror: 0.0% -┌───────┬──────────────┬───────────┬──────────────┬───────────┬──────────┬────────┬────────┬─────────────────────────────┬─────────────┬────────────────┐ -│ Tol # │ feature1 │ partzero1 │ feature2 │ partzero2 │ nominald │ lowerd │ upperd │ distance │ reald │ tolerancefield │ -├───────┼──────────────┼───────────┼──────────────┼───────────┼──────────┼────────┼────────┼─────────────────────────────┼─────────────┼────────────────┤ -│ 1 │ M rightface1 │ right │ M fronthole │ front │ 41.0 │ 40.7 │ 41.3 │ [-16.0, 41.0, 15.0] │ 41.0 │ -0.0 % │ -│ 2 │ M backhole1 │ back │ M fronthole │ front │ 14.0 │ 13.8 │ 14.2 │ [-84.5, 14.0, 14.0] │ 14.0 │ -0.0 % │ -│ 3 │ M fronthole │ front │ M backhole2 │ back │ 14.0 │ 13.8 │ 14.2 │ [84.5, 14.0, -14.0] │ 14.0 │ 0.0 % │ -│ 4 │ M backhole1 │ back │ M fronthole │ front │ 14.0 │ 13.8 │ 14.2 │ [-84.5, 14.0, 14.0] │ 14.0 │ -0.0 % │ -│ 5 │ M backhole2 │ back │ M fronthole │ front │ 14.0 │ 13.8 │ 14.2 │ [-84.5, -14.0, 14.0] │ 14.0 │ -0.0 % │ -│ 6 │ M rightface3 │ right │ M fronthole │ front │ 38.0 │ 37.7 │ 38.3 │ [-60.0, 38.0, 1.13687e-13] │ 38.0 │ -0.0 % │ -│ 7 │ M rightface2 │ right │ M fronthole │ front │ 44.0 │ 43.7 │ 44.3 │ [-25.0, 44.0, -16.0] │ 44.0 │ -0.0 % │ -│ 8 │ M frontface │ front │ M righthole3 │ right │ 60.0 │ 59.7 │ 60.3 │ [60.0, -38.0, -1.13687e-13] │ 60.0 │ 0.0 % │ -│ 9 │ M frontface │ front │ M righthole2 │ right │ 25.0 │ 24.8 │ 25.2 │ [25.0, -44.0, 16.0] │ 25.0 │ 0.0 % │ -│ 10 │ M frontface │ front │ M righthole1 │ right │ 16.0 │ 15.8 │ 16.2 │ [16.0, -41.0, -15.0] │ 16.0 │ 0.0 % │ -│ 11 │ M righthole1 │ right │ M fronthole │ front │ 15.0 │ 14.8 │ 15.2 │ [-16.0, 41.0, 15.0] │ 15.0 │ 0.0 % │ -│ 12 │ M fronthole │ front │ M righthole2 │ right │ 16.0 │ 15.8 │ 16.2 │ [25.0, -44.0, 16.0] │ 16.0 │ -0.0 % │ -│ 13 │ M frontface │ front │ R backface1 │ back │ 85.0 │ 84.6 │ 85.4 │ [85.0, -14.5526, -14.0144] │ 85.0 │ 0.0 % │ -│ 14 │ M frontface │ front │ R backface2 │ back │ 85.0 │ 84.6 │ 85.4 │ [85.0, 13.4474, -14.0144] │ 85.0 │ 0.0 % │ -│ 15 │ M righthole3 │ right │ M fronthole │ front │ 0.0 │ -0.2 │ 0.2 │ [-60.0, 38.0, 1.13687e-13] │ 1.13687e-13 │ 0.0 % │ -└───────┴──────────────┴───────────┴──────────────┴───────────┴──────────┴────────┴────────┴─────────────────────────────┴─────────────┴────────────────┘ + Tolerance table avgabsreltolerror: 0.0% +┌───────┬──────────────┬───────────┬──────────────┬───────────┬──────────┬────────┬────────┬────────────────────────────┬────────────┬────────────────┐ +│ Tol # │ feature1 │ partzero1 │ feature2 │ partzero2 │ nominald │ lowerd │ upperd │ distance │ reald │ tolerancefield │ +├───────┼──────────────┼───────────┼──────────────┼───────────┼──────────┼────────┼────────┼────────────────────────────┼────────────┼────────────────┤ +│ 1 │ M rightface1 │ right │ M fronthole │ front │ 41.0 │ 40.7 │ 41.3 │ [-16.0, 41.0, 15.0] │ 41.0 │ 0.0 % │ +│ 2 │ M backhole1 │ back │ M fronthole │ front │ 14.0 │ 13.8 │ 14.2 │ [-84.5, 14.0, 14.0] │ 14.0 │ 0.0 % │ +│ 3 │ M fronthole │ front │ M backhole2 │ back │ 14.0 │ 13.8 │ 14.2 │ [84.5, 14.0, -14.0] │ 14.0 │ -0.0 % │ +│ 4 │ M backhole1 │ back │ M fronthole │ front │ 14.0 │ 13.8 │ 14.2 │ [-84.5, 14.0, 14.0] │ 14.0 │ -0.0 % │ +│ 5 │ M backhole2 │ back │ M fronthole │ front │ 14.0 │ 13.8 │ 14.2 │ [-84.5, -14.0, 14.0] │ 14.0 │ -0.0 % │ +│ 6 │ M rightface3 │ right │ M fronthole │ front │ 38.0 │ 37.7 │ 38.3 │ [-60.0, 38.0, 9.9476e-14] │ 38.0 │ 0.0 % │ +│ 7 │ M rightface2 │ right │ M fronthole │ front │ 44.0 │ 43.7 │ 44.3 │ [-25.0, 44.0, -16.0] │ 44.0 │ 0.0 % │ +│ 8 │ M frontface │ front │ M righthole3 │ right │ 60.0 │ 59.7 │ 60.3 │ [60.0, -38.0, -9.9476e-14] │ 60.0 │ 0.0 % │ +│ 9 │ M frontface │ front │ M righthole2 │ right │ 25.0 │ 24.8 │ 25.2 │ [25.0, -44.0, 16.0] │ 25.0 │ 0.0 % │ +│ 10 │ M frontface │ front │ M righthole1 │ right │ 16.0 │ 15.8 │ 16.2 │ [16.0, -41.0, -15.0] │ 16.0 │ 0.0 % │ +│ 11 │ M righthole1 │ right │ M fronthole │ front │ 15.0 │ 14.8 │ 15.2 │ [-16.0, 41.0, 15.0] │ 15.0 │ 0.0 % │ +│ 12 │ M fronthole │ front │ M righthole2 │ right │ 16.0 │ 15.8 │ 16.2 │ [25.0, -44.0, 16.0] │ 16.0 │ -0.0 % │ +│ 13 │ M frontface │ front │ R backface1 │ back │ 85.0 │ 84.6 │ 85.4 │ [85.0, -14.2215, -14.014] │ 85.0 │ 0.0 % │ +│ 14 │ M frontface │ front │ R backface2 │ back │ 85.0 │ 84.6 │ 85.4 │ [85.0, 13.7785, -14.014] │ 85.0 │ 0.0 % │ +│ 15 │ M righthole3 │ right │ M fronthole │ front │ 0.0 │ -0.2 │ 0.2 │ [-60.0, 38.0, 9.9476e-14] │ 9.9476e-14 │ 0.0 % │ +└───────┴──────────────┴───────────┴──────────────┴───────────┴──────────┴────────┴────────┴────────────────────────────┴────────────┴────────────────┘ ``` ## Visualizing the result diff --git a/src/optimization.jl b/src/optimization.jl index 919c5b5..3d3a810 100644 --- a/src/optimization.jl +++ b/src/optimization.jl @@ -57,6 +57,7 @@ end function addplane2model!(::IsPrimitive, model, plane, ipzmatricedict) # access registered variables minAllowance = model[:minAllowance] + maxPlaneZAllowance = model[:maxPlaneZAllowance] # register distance variable: dz = @variable(model, base_name = string("d_z_", getfeaturename(plane))) @@ -69,12 +70,14 @@ function addplane2model!(::IsPrimitive, model, plane, ipzmatricedict) @constraint(model, dz == d_f[3]) # equation (7) @constraint(model, -1*dz >= minAllowance) + @constraint(model, -1*dz <= maxPlaneZAllowance) return model end function addplane2model!(::IsFreeForm, model, plane, ipzmatricedict) # access registered variables minAllowance = model[:minAllowance] + maxPlaneZAllowance = model[:maxPlaneZAllowance] # filtered surface points of a free form surface qs = getroughfilteredpoints(plane) @@ -92,6 +95,7 @@ function addplane2model!(::IsFreeForm, model, plane, ipzmatricedict) @constraint(model, dz[i] == d_f[3]) # equation (6) @constraint(model, -1*dz[i] >= minAllowance) + @constraint(model, -1*dz[i] <= maxPlaneZAllowance) end return model end @@ -163,6 +167,8 @@ function createjumpmodel(mop::MultiOperationProblem, optimizer; disable_string_n # variable for minimum allowance #@variable(model, minAllowance >= 0) @variable(model, minAllowance) + # variable for maximum allowance for planes + @variable(model, maxPlaneZAllowance) ## tolerances addtolerances2model!(model, mop, pzmatricedict) @@ -175,6 +181,10 @@ function createjumpmodel(mop::MultiOperationProblem, optimizer; disable_string_n for p in machinedplanes addplane2model!(model, p, ipzmatricedict) end + # if maximum allowance of planes is given, then set it + if haskey(mop.parameters, "maxPlaneZAllowance") + @constraint(model, maxPlaneZAllowance == mop.parameters["maxPlaneZAllowance"]) + end # optimization if mop.parameters["OptimizeForToleranceCenter"] From 78846b3db91562e17d4fb50c03cc4f963bb28824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 17:46:41 +0200 Subject: [PATCH 7/8] test an actual problem --- test/runtests.jl | 1 + test/testproblem.jl | 141 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 test/testproblem.jl diff --git a/test/runtests.jl b/test/runtests.jl index 21e5710..b34fd96 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,3 +8,4 @@ const BLC = BlankLocalizationCore include("partzeros.jl") include("geometries.jl") +include("testproblem.jl") diff --git a/test/testproblem.jl b/test/testproblem.jl new file mode 100644 index 0000000..831a485 --- /dev/null +++ b/test/testproblem.jl @@ -0,0 +1,141 @@ +@testset "simple mop" begin + # this is the problem from the documentation: + # https://csertegt3.github.io/BlankLocalizationCore.jl/stable/example/ + ## Part zero definitions + + pzf = PartZero("front", [0,0,0], hcat([0,1,0], [0,0,1], [1,0,0])) + pzr = PartZero("right", [0,0,0], hcat([-1, 0, 0], [0, 0, 1], [0, 1, 0])) + pzb = PartZero("back", [0,0,0], hcat([0, -1, 0], [0, 0, 1], [-1, 0, 0])) + + partzeros = [pzf, pzr, pzb] + + ## Machined geometry definitions + + fronthole_m = SimpleHole([0, 0, 0], 29) + frontface_m = SimplePlane([0, 0, 0]) + + righthole1_m = SimpleHole([16, 15, 0], 7.5) + righthole2_m = SimpleHole([25, -16, 3], 9) + righthole3_m = SimpleHole([60, 0, -3], 13.5) + rightface1_m = SimplePlane([16, 15, 0]) + rightface2_m = SimplePlane([25, -16, 3]) + rightface3_m = SimplePlane([60, 0, -3]) + + backhole1_m = SimpleHole([-14, 14, 0], 9) + backhole2_m = SimpleHole([14, 14, 0], 9) + backface1_m = SimplePlane([-14, 14, 0]) + backface2_m = SimplePlane([14, 14, 0]) + + ## Rough geometry definitions + + fronthole_r = SimpleHole([82.5, 30, 40], 26) + frontface_r = PlaneAndNormal([82.5, 30, 40], [1, 0, 0]) + + righthole1_r = SimpleHole([66, 71.5, 55], 6) + righthole2_r = SimpleHole([58, 74.5, 24], 4.905) + righthole3_r = SimpleHole([21.5, 68.5, 40], 8) + rightface1_r = PlaneAndNormal([66, 71.5, 55], [0, 1, 0]) + rightface2_r = PlaneAndNormal([58, 74.5, 24], [0, 1, 0]) + rightface3_r = PlaneAndNormal([21.5, 68.5, 40], [0, 1, 0]) + + backhole1_r = SimpleHole([-3, 44, 53.9], 6.2) + backhole2_r = SimpleHole([-3, 16.1, 54], 6.25) + backface1_r = PlaneAndNormal([-3, 44, 54], [-1, 0, 0]) + backface2_r = PlaneAndNormal([-3, 16, 54], [-1, 0, 0]) + + ## Geometry pairing and feature descriptors + + # Feature descriptors for each feature + + fd_fronthole = FeatureDescriptor("fronthole", pzf, true, true) + fd_frontface = FeatureDescriptor("frontface", pzf, true, true) + + fd_righthole1 = FeatureDescriptor("righthole1", pzr, true, true) + fd_righthole2 = FeatureDescriptor("righthole2", pzr, true, true) + fd_righthole3 = FeatureDescriptor("righthole3", pzr, true, true) + fd_rightface1 = FeatureDescriptor("rightface1", pzr, true, true) + fd_rightface2 = FeatureDescriptor("rightface2", pzr, true, true) + fd_rightface3 = FeatureDescriptor("rightface3", pzr, true, true) + + fd_backhole1 = FeatureDescriptor("backhole1", pzb, true, true) + fd_backhole2 = FeatureDescriptor("backhole2", pzb, true, true) + fd_backface1 = FeatureDescriptor("backface1", pzb, true, true) + fd_backface2 = FeatureDescriptor("backface2", pzb, true, true) + + # Hole features + + holes = [HoleLocalizationFeature(fd_fronthole, fronthole_r, fronthole_m), + HoleLocalizationFeature(fd_righthole1, righthole1_r, righthole1_m), + HoleLocalizationFeature(fd_righthole2, righthole2_r, righthole2_m), + HoleLocalizationFeature(fd_righthole3, righthole3_r, righthole3_m), + HoleLocalizationFeature(fd_backhole1, backhole1_r, backhole1_m), + HoleLocalizationFeature(fd_backhole2, backhole2_r, backhole2_m) + ] + + # Face features + planes = [PlaneLocalizationFeature(fd_frontface, frontface_r, frontface_m), + PlaneLocalizationFeature(fd_rightface1, rightface1_r, rightface1_m), + PlaneLocalizationFeature(fd_rightface2, rightface2_r, rightface2_m), + PlaneLocalizationFeature(fd_rightface3, rightface3_r, rightface3_m), + PlaneLocalizationFeature(fd_backface1, backface1_r, backface1_m), + PlaneLocalizationFeature(fd_backface2, backface2_r, backface2_m) + ] + + ## Tolerances + + xfunc(x) = x[1] + yfunc(x) = x[2] + zfunc(x) = x[3] + + tolerances = [Tolerance("rightface1", true, yfunc, "fronthole", true, 41, 40.7, 41.3, "1"), + Tolerance("backhole1", true, yfunc, "fronthole", true, 14, 13.8, 14.2, "2"), + Tolerance("fronthole", true, yfunc, "backhole2", true, 14, 13.8, 14.2, "3"), + Tolerance("backhole1", true, zfunc, "fronthole", true, 14, 13.8, 14.2, "4"), + Tolerance("backhole2", true, zfunc, "fronthole", true, 14, 13.8, 14.2, "5"), + Tolerance("rightface3", true, yfunc, "fronthole", true, 38, 37.7, 38.3, "6"), + Tolerance("rightface2", true, yfunc, "fronthole", true, 44, 43.7, 44.3, "7"), + Tolerance("frontface", true, xfunc, "righthole3", true, 60, 59.7, 60.3, "8"), + Tolerance("frontface", true, xfunc, "righthole2", true, 25, 24.8, 25.2, "9"), + Tolerance("frontface", true, xfunc, "righthole1", true, 16, 15.8, 16.2, "10"), + Tolerance("righthole1", true, zfunc, "fronthole", true, 15, 14.8, 15.2, "11"), + Tolerance("fronthole", true, zfunc, "righthole2", true, 16, 15.8, 16.2, "12"), + Tolerance("frontface", true, xfunc, "backface1", false, 85, 84.6, 85.4, "13"), + Tolerance("frontface", true, xfunc, "backface2", false, 85, 84.6, 85.4, "14"), + Tolerance("righthole3", true, zfunc, "fronthole", true, 0, -0.2, 0.2, "15")] + + ## Constructing and solving the optimization problem + ## Constructing and solving the optimization problem + pard = Dict("minAllowance"=>0.5, "OptimizeForToleranceCenter"=>true, + "UseTolerances"=>true, "maxPlaneZAllowance"=>1) + + mop = MultiOperationProblem(partzeros, holes, planes, tolerances, pard) + + import Ipopt + + @test mop.opresult.status == "empty" + @test BLC.getfeaturebyname(mop, "fronthole") === holes[1] + @test BLC.getfeaturebyname(mop, "frontface") === planes[1] + @test BLC.problemtype(mop) == :PrimitiveProblem + + optimizeproblem!(mop, Ipopt.Optimizer) + @test mop.opresult.status == "LOCALLY_SOLVED" + + resallowance = minimumallowance(mop) + tolerror = toleranceerror(mop) + + @test isapprox(resallowance.radial, 1.48846, atol=0.0001) + @test isapprox(resallowance.axial, 0.5) + # atol=0.01 -> toleranceerror returns in the 0-100% range + @test isapprox(tolerror, 0, atol=0.01) + + # infeasible problem + pard = Dict("minAllowance"=>0.5, "OptimizeForToleranceCenter"=>true, + "UseTolerances"=>true, "maxPlaneZAllowance"=>0.1) + + setparameters!(mop, pard) + optimizeproblem!(mop, Ipopt.Optimizer) + @test mop.opresult.status == "LOCALLY_INFEASIBLE" + @test mop.opresult.minallowance === NaN + + +end \ No newline at end of file From fbe2d0e5b5680913c5176924d2cfa94bb475eb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Cserteg?= Date: Thu, 14 Sep 2023 17:56:23 +0200 Subject: [PATCH 8/8] refine tolerances --- test/testproblem.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testproblem.jl b/test/testproblem.jl index 831a485..858a505 100644 --- a/test/testproblem.jl +++ b/test/testproblem.jl @@ -123,8 +123,8 @@ resallowance = minimumallowance(mop) tolerror = toleranceerror(mop) - @test isapprox(resallowance.radial, 1.48846, atol=0.0001) - @test isapprox(resallowance.axial, 0.5) + @test isapprox(resallowance.radial, 1.48846, atol=0.01) + @test isapprox(resallowance.axial, 0.5, atol=0.01) # atol=0.01 -> toleranceerror returns in the 0-100% range @test isapprox(tolerror, 0, atol=0.01)