diff --git a/Project.toml b/Project.toml index bcf85341..f211f429 100644 --- a/Project.toml +++ b/Project.toml @@ -33,6 +33,7 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a" [sources] GetDP = {rev = "main", url = "https://github.com/Electa-Git/GetDP.jl"} @@ -65,6 +66,7 @@ Reexport = "1.2.2" Serialization = "1.11.0" SpecialFunctions = "2.5.0" Statistics = "1.11.1" +TestItemRunner = "1.1.0" [extras] Coverage = "a2441757-f6aa-5fb2-8edb-039e3f45d037" diff --git a/examples/18kV_1000mm2_equivalent_ZY.xml b/examples/18kV_1000mm2_equivalent_ZY.xml new file mode 100644 index 00000000..cdc25366 --- /dev/null +++ b/examples/18kV_1000mm2_equivalent_ZY.xml @@ -0,0 +1,24 @@ + + +1.3434279069898911E-05+1.7952866255503812E-08i,1.1017765633788020E-11+1.7081287857882299E-08i,1.1017764470276360E-11+1.7010534496485781E-08i,1.1015007112753420E-11+1.5576892169123991E-08i,1.1015007838539930E-11+1.5576896150241041E-08i,1.1015007832216130E-11+1.5576896296215632E-08i,1.1015008907855811E-11+1.5577067525585591E-08i,1.1015009786503661E-11+1.5577073892113442E-08i,1.1015009785051650E-11+1.5577073931078009E-08i +1.1017765633788020E-11+1.7081287857882319E-08i,4.8965847155552837E-04+1.7053209940201269E-08i,1.1017764436496461E-11+1.7010534018250459E-08i,1.1015007208492361E-11+1.5576891666096819E-08i,1.1015007934228091E-11+1.5576895647213502E-08i,1.1015007927904550E-11+1.5576895793192361E-08i,1.1015009647847549E-11+1.5577051592013609E-08i,1.1015010526527139E-11+1.5577057958287028E-08i,1.1015010525075190E-11+1.5577057997259709E-08i +1.1017764470276360E-11+1.7010534496485781E-08i,1.1017764436496449E-11+1.7010534018250469E-08i,7.1275338935888172E-04+1.7009694007398330E-08i,1.1015007212246959E-11+1.5576891511375961E-08i,1.1015007937982130E-11+1.5576895492488471E-08i,1.1015007931658590E-11+1.5576895638466728E-08i,1.1015009642246840E-11+1.5577051718596958E-08i,1.1015010520926270E-11+1.5577058084887011E-08i,1.1015010519474310E-11+1.5577058123859229E-08i +1.1015007112753420E-11+1.5576892169123991E-08i,1.1015007208492361E-11+1.5576891666096809E-08i,1.1015007212246959E-11+1.5576891511375971E-08i,1.3434279070081390E-05+1.7963938465725391E-08i,1.1017951241640630E-11+1.7092387891757259E-08i,1.1017950077073291E-11+1.7021634591932449E-08i,1.1015102403034780E-11+1.5582521805360730E-08i,1.1015102147403959E-11+1.5582506433544761E-08i,1.1015102152293051E-11+1.5582506338279011E-08i +1.1015007838539939E-11+1.5576896150241041E-08i,1.1015007934228091E-11+1.5576895647213502E-08i,1.1015007937982130E-11+1.5576895492488481E-08i,1.1017951241640630E-11+1.7092387891757259E-08i,4.8965847155570423E-04+1.7064310701644261E-08i,1.1017950119538740E-11+1.7021634707642821E-08i,1.1015103577693039E-11+1.5582521013060809E-08i,1.1015103322040260E-11+1.5582505641055911E-08i,1.1015103326929440E-11+1.5582505545791820E-08i +1.1015007832216121E-11+1.5576896296215632E-08i,1.1015007927904540E-11+1.5576895793192371E-08i,1.1015007931658590E-11+1.5576895638466718E-08i,1.1017950077073291E-11+1.7021634591932449E-08i,1.1017950119538730E-11+1.7021634707642821E-08i,7.1275338935904880E-04+1.7020794697957151E-08i,1.1015103571670630E-11+1.5582520929618101E-08i,1.1015103316018230E-11+1.5582505557622289E-08i,1.1015103320907400E-11+1.5582505462357939E-08i +1.1015008907855811E-11+1.5577067525585591E-08i,1.1015009647847549E-11+1.5577051592013619E-08i,1.1015009642246840E-11+1.5577051718596958E-08i,1.1015102403034780E-11+1.5582521805360720E-08i,1.1015103577693039E-11+1.5582521013060789E-08i,1.1015103571670630E-11+1.5582520929618091E-08i,1.3434279070090179E-05+1.7964450625337511E-08i,1.1017957744336239E-11+1.7092889322791409E-08i,1.1017956580156670E-11+1.7022135976960378E-08i +1.1015009786503649E-11+1.5577073892113442E-08i,1.1015010526527139E-11+1.5577057958287038E-08i,1.1015010520926270E-11+1.5577058084887011E-08i,1.1015102147403950E-11+1.5582506433544751E-08i,1.1015103322040270E-11+1.5582505641055891E-08i,1.1015103316018220E-11+1.5582505557622289E-08i,1.1017957744336239E-11+1.7092889322791409E-08i,4.8965847155571019E-04+1.7064811736840651E-08i,1.1017956552373579E-11+1.7022135740156459E-08i +1.1015009785051650E-11+1.5577073931077999E-08i,1.1015010525075190E-11+1.5577057997259699E-08i,1.1015010519474310E-11+1.5577058123859229E-08i,1.1015102152293051E-11+1.5582506338279002E-08i,1.1015103326929440E-11+1.5582505545791800E-08i,1.1015103320907391E-11+1.5582505462357910E-08i,1.1017956580156670E-11+1.7022135976960368E-08i,1.1017956552373579E-11+1.7022135740156459E-08i,7.1275338935905086E-04+1.7021295725736878E-08i + + +1.0235427486802910E-12+3.5876442374760141E-12i,-1.0235427486802910E-12-3.5876442374760120E-12i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i +-1.0235427486802910E-12-3.5876442374760108E-12i,1.6425015376953339E-01+1.5678614572597519E-09i,-1.6425015376850960E-01-1.5642738130222760E-09i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i +0.0000000000000000E+00+0.0000000000000000E+00i,-1.6425015376850960E-01-1.5642738130222760E-09i,1.6425015376906821E-01+1.5785181589513440E-09i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,7.1878404738314777E-20-5.7120222538543638E-21i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,7.1879257446717906E-20-5.7120900167636763E-21i +0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,1.0235261510765790E-12+3.5875860608171570E-12i,-1.0235261510765790E-12-3.5875860608171562E-12i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i +0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,-1.0235261510765790E-12-3.5875860608171562E-12i,1.6425015376954741E-01+1.5678613990832289E-09i,-1.6425015376852370E-01-1.5642738130224119E-09i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i +0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,7.1878404738314741E-20-5.7120222538543638E-21i,0.0000000000000000E+00+0.0000000000000000E+00i,-1.6425015376852370E-01-1.5642738130224119E-09i,1.6425015376908189E-01+1.5785181589523670E-09i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,7.1649474811640504E-20-5.6938296848403217E-21i +0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,1.0235189000849910E-12+3.5875606451926360E-12i,-1.0235189000849920E-12-3.5875606451926352E-12i,0.0000000000000000E+00+0.0000000000000000E+00i +0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,-1.0235189000849920E-12-3.5875606451926340E-12i,1.6425015376954749E-01+1.5678613736676110E-09i,-1.6425015376852389E-01-1.5642738130224179E-09i +0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,7.1879257446717858E-20-5.7120900167636763E-21i,0.0000000000000000E+00+0.0000000000000000E+00i,0.0000000000000000E+00+0.0000000000000000E+00i,7.1649474811640504E-20-5.6938296848403240E-21i,0.0000000000000000E+00+0.0000000000000000E+00i,-1.6425015376852389E-01-1.5642738130224179E-09i,1.6425015376908231E-01+1.5785181589523740E-09i + + diff --git a/examples/18kV_1000mm2_equivalent_export.xml b/examples/18kV_1000mm2_equivalent_export.xml new file mode 100644 index 00000000..6a7062b1 --- /dev/null +++ b/examples/18kV_1000mm2_equivalent_export.xml @@ -0,0 +1,39 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/18kV_1000mm2_trifoil_export.pscx b/examples/18kV_1000mm2_trifoil_export.pscx index 269f4d9d..d29c98fe 100644 --- a/examples/18kV_1000mm2_trifoil_export.pscx +++ b/examples/18kV_1000mm2_trifoil_export.pscx @@ -1,2 +1,2 @@ -
+ diff --git a/examples/525kV_1600mm2_bipole_export.pscx b/examples/525kV_1600mm2_bipole_export.pscx index 496a1c9e..d231cae2 100644 --- a/examples/525kV_1600mm2_bipole_export.pscx +++ b/examples/525kV_1600mm2_bipole_export.pscx @@ -1,2 +1,2 @@ - + diff --git a/examples/cables_library.json b/examples/cables_library.json index 60ec2b69..a4c41e5e 100644 --- a/examples/cables_library.json +++ b/examples/cables_library.json @@ -305,6 +305,314 @@ } } ] + }, + "525kV_1600mm2": { + "cable_id": "525kV_1600mm2", + "nominal_data": { + "U": 525, + "screen_cross_section": 1000, + "capacitance": null, + "__julia_type__": "LineCableModels.DataModel.NominalData", + "U0": 500, + "conductor_cross_section": 1600, + "armor_cross_section": null, + "resistance": null, + "inductance": null, + "designation_code": "(N)2XH(F)RK2Y" + }, + "__julia_type__": "LineCableModels.DataModel.CableDesign", + "components": [ + { + "insulator_group": { + "__julia_type__": "LineCableModels.DataModel.InsulatorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1000, + "mu_r": 1, + "rho": 1000 + }, + "radius_in": 0.02382185, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.02582185, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 2.3, + "mu_r": 1, + "rho": 197000000000000 + }, + "radius_in": 0.02582185, + "__julia_type__": "LineCableModels.DataModel.Insulator", + "radius_ext": 0.05182185, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1000, + "mu_r": 1, + "rho": 500 + }, + "radius_in": 0.05182185, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.053621850000000006, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 32.3, + "mu_r": 1, + "rho": 5300 + }, + "radius_in": 0.053621850000000006, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.05392185000000001, + "temperature": 20 + } + ] + }, + "__julia_type__": "LineCableModels.DataModel.CableComponent", + "id": "core", + "conductor_group": { + "__julia_type__": "LineCableModels.DataModel.ConductorGroup", + "layers": [ + { + "lay_ratio": 0, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00183245, + "num_wires": 1, + "temperature": 20 + }, + { + "lay_ratio": 11, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.00183245, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00183245, + "num_wires": 6, + "temperature": 20 + }, + { + "lay_ratio": 11, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.00549735, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00183245, + "num_wires": 12, + "temperature": 20 + }, + { + "lay_ratio": 11, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.00916225, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00183245, + "num_wires": 18, + "temperature": 20 + }, + { + "lay_ratio": 11, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.01282715, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00183245, + "num_wires": 24, + "temperature": 20 + }, + { + "lay_ratio": 11, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.01649205, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00183245, + "num_wires": 30, + "temperature": 20 + }, + { + "lay_ratio": 11, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.02015695, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00183245, + "num_wires": 36, + "temperature": 20 + } + ] + } + }, + { + "insulator_group": { + "__julia_type__": "LineCableModels.DataModel.InsulatorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 2.3, + "mu_r": 1, + "rho": 197000000000000 + }, + "radius_in": 0.057221850000000005, + "__julia_type__": "LineCableModels.DataModel.Insulator", + "radius_ext": 0.06022185000000001, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 2.8, + "mu_r": 1, + "rho": 1000000000000000 + }, + "radius_in": 0.06022185000000001, + "__julia_type__": "LineCableModels.DataModel.Insulator", + "radius_ext": 0.06322185000000001, + "temperature": 20 + } + ] + }, + "__julia_type__": "LineCableModels.DataModel.CableComponent", + "id": "sheath", + "conductor_group": { + "__julia_type__": "LineCableModels.DataModel.ConductorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0.004, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999983, + "rho": 2.14e-7 + }, + "radius_in": 0.05392185000000001, + "__julia_type__": "LineCableModels.DataModel.Tubular", + "radius_ext": 0.057221850000000005, + "temperature": 20 + } + ] + } + }, + { + "insulator_group": { + "__julia_type__": "LineCableModels.DataModel.InsulatorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 2.8, + "mu_r": 1, + "rho": 1000000000000000 + }, + "radius_in": 0.06904885000000001, + "__julia_type__": "LineCableModels.DataModel.Insulator", + "radius_ext": 0.07904885, + "temperature": 20 + } + ] + }, + "__julia_type__": "LineCableModels.DataModel.CableComponent", + "id": "armor", + "conductor_group": { + "__julia_type__": "LineCableModels.DataModel.ConductorGroup", + "layers": [ + { + "lay_ratio": 10, + "material_props": { + "T0": 20, + "alpha": 0.0045, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 300, + "rho": 1.38e-7 + }, + "lay_direction": 1, + "radius_in": 0.06322185000000001, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.0029135, + "num_wires": 68, + "temperature": 20 + } + ] + } + } + ] } } } \ No newline at end of file diff --git a/examples/materials_library.json b/examples/materials_library.json index dac01ffa..4a42a68f 100644 --- a/examples/materials_library.json +++ b/examples/materials_library.json @@ -15,14 +15,6 @@ "mu_r": 0.999994, "rho": 3.03e-8 }, - "carbon_pe": { - "T0": 20, - "alpha": 0, - "__julia_type__": "LineCableModels.Materials.Material", - "eps_r": 1000, - "mu_r": 1, - "rho": 0.06 - }, "bronze": { "T0": 20, "alpha": 0.003, @@ -31,22 +23,6 @@ "mu_r": 1, "rho": 3.5e-8 }, - "lead": { - "T0": 20, - "alpha": 0.004, - "__julia_type__": "LineCableModels.Materials.Material", - "eps_r": 1, - "mu_r": 0.999983, - "rho": 2.14e-7 - }, - "steel": { - "T0": 20, - "alpha": 0.0045, - "__julia_type__": "LineCableModels.Materials.Material", - "eps_r": 1, - "mu_r": 300, - "rho": 1.38e-7 - }, "copper": { "T0": 20, "alpha": 0.00393, @@ -55,14 +31,6 @@ "mu_r": 0.999994, "rho": 1.7241e-8 }, - "copper_corrected": { - "T0": 20, - "alpha": 0.00393, - "__julia_type__": "LineCableModels.Materials.Material", - "eps_r": 1, - "mu_r": 0.999994, - "rho": 1.835e-8 - }, "pec": { "T0": 20, "alpha": 0, @@ -79,17 +47,6 @@ "mu_r": 1, "rho": 18.5 }, - "air": { - "T0": 20, - "alpha": 0, - "__julia_type__": "LineCableModels.Materials.Material", - "eps_r": 1, - "mu_r": 1, - "rho": { - "value": "Inf", - "__type__": "SpecialFloat" - } - }, "laminated_paper": { "T0": 20, "alpha": 0, @@ -114,14 +71,6 @@ "mu_r": 1, "rho": 1000 }, - "epr": { - "T0": 20, - "alpha": 0.005, - "__julia_type__": "LineCableModels.Materials.Material", - "eps_r": 3, - "mu_r": 1, - "rho": 1000000000000000 - }, "xlpe": { "T0": 20, "alpha": 0, @@ -138,6 +87,57 @@ "mu_r": 1, "rho": 500 }, + "aluminum": { + "T0": 20, + "alpha": 0.00429, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1.000022, + "rho": 2.8264e-8 + }, + "carbon_pe": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1000, + "mu_r": 1, + "rho": 0.06 + }, + "lead": { + "T0": 20, + "alpha": 0.004, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999983, + "rho": 2.14e-7 + }, + "copper_corrected": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.835e-8 + }, + "air": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1, + "rho": { + "value": "Inf", + "__type__": "SpecialFloat" + } + }, + "epr": { + "T0": 20, + "alpha": 0.005, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 3, + "mu_r": 1, + "rho": 1000000000000000 + }, "pvc": { "T0": 20, "alpha": 0.1, @@ -154,12 +154,12 @@ "mu_r": 500, "rho": 7.0e-7 }, - "aluminum": { + "steel": { "T0": 20, - "alpha": 0.00429, + "alpha": 0.0045, "__julia_type__": "LineCableModels.Materials.Material", "eps_r": 1, - "mu_r": 1.000022, - "rho": 2.8264e-8 + "mu_r": 300, + "rho": 1.38e-7 } } \ No newline at end of file diff --git a/examples/tutorial3.jl b/examples/tutorial3.jl index dbc7a0a4..a4b1f497 100644 --- a/examples/tutorial3.jl +++ b/examples/tutorial3.jl @@ -368,3 +368,7 @@ if !opts.mesh_only println("L = $(@sprintf("%.6g", L)) mH/km") println("C = $(@sprintf("%.6g", C)) μF/km") end + + +output_file = fullfile("$(cable_system.system_id)_export.xml") +export_data(Val(:atp), line_params, cable_system, problem, file_name=output_file) \ No newline at end of file diff --git a/src/ImportExport.jl b/src/ImportExport.jl index a2058d89..8f60a71f 100644 --- a/src/ImportExport.jl +++ b/src/ImportExport.jl @@ -24,13 +24,23 @@ $(EXPORTS) """ module ImportExport +# Export public API +export export_data +export read_data +export save +export load! +export get +export delete! + # Load common dependencies using ..LineCableModels include("utils/commondeps.jl") # Module-specific dependencies using Measurements -using EzXML, Dates # For PSCAD export +using EzXML # For PSCAD export +using Dates # For PSCAD export +using Printf # For ATP export using JSON3 using Serialization # For .jls format using ..Utils @@ -44,6 +54,6 @@ include("importexport/deserialize.jl") include("importexport/cableslibrary.jl") include("importexport/materialslibrary.jl") include("importexport/pscad.jl") - +include("ImportExport/atp.jl") end # module ImportExport diff --git a/src/importexport/atp.jl b/src/importexport/atp.jl new file mode 100644 index 00000000..5d08a0a2 --- /dev/null +++ b/src/importexport/atp.jl @@ -0,0 +1,281 @@ + +""" +$(TYPEDSIGNATURES) + +Exports calculated [`LineParameters`](@ref) to an ATP-style XML file. + +This function takes all the system information, cables, ground parameters and frequency and assembles the XML to be used in ATPDraw + +# Arguments + +- `problem`: A [`LineParametersProblem`](@ref) object used to retrieve the frequency vector for the export. +- `file_name`: The path to the output XML file (default: "*_export.xml"). + +# Returns + +- The absolute path of the saved file. +""" +function export_data(::Val{:atp}, + cable_system::LineCableSystem, + earth_props::EarthModel; + base_freq=f₀, + file_name::String="$(cable_system.system_id)_export.xml" +)::Union{String,Nothing} + + function _set_attributes!(element::EzXML.Node, attrs::Dict) + for (k, v) in attrs + element[k] = string(v) + end + end + # --- 1. Setup Constants and Variables --- + file_name = isabspath(file_name) ? file_name : joinpath(@__DIR__, file_name) + num_phases = length(cable_system.cables) + + # Create XML Structure and LCC Component + doc = XMLDocument() + project = ElementNode("project") + setroot!(doc, project) + _set_attributes!(project, Dict("Application" => "ATPDraw", "Version" => "7.3", "VersionXML" => "1")) + header = addelement!(project, "header") + _set_attributes!(header, Dict("Timestep" => 1e-6, "Tmax" => 0.1, "XOPT" => 0, "COPT" => 0, "SysFreq" => base_freq, "TopLeftX" => 200, "TopLeftY" => 0)) + objects = addelement!(project, "objects") + variables = addelement!(project, "variables") + comp = addelement!(objects, "comp") + _set_attributes!(comp, Dict("Name" => "LCC", "Id" => "$(cable_system.system_id)_1", "Capangl" => 90, "CapPosX" => -10, "CapPosY" => -25, "Caption" => "")) + comp_content = addelement!(comp, "comp_content") + _set_attributes!(comp_content, Dict("PosX" => 280, "PosY" => 360, "NumPhases" => num_phases, "Icon" => "default", "SinglePhaseIcon" => "true")) + for side in ["IN", "OUT"]; y0 = -20; for k in 1:num_phases; y0 += 10; node = addelement!(comp_content, "node"); _set_attributes!(node, Dict("Name" => "$side$k", "Value" => "C$(k)$(side=="IN" ? "SND" : "RCV")", "UserNamed" => "true", "Kind" => k, "PosX" => side == "IN" ? -20 : 20, "PosY" => y0, "NamePosX" => 0, "NamePosY" => 0)); end; end + soil_rho = earth_props.layers[end].base_rho_g + for (name, value) in [("Length", cable_system.line_length), ("Freq", base_freq), ("Grnd resis", soil_rho)]; data_node = addelement!(comp_content, "data"); _set_attributes!(data_node, Dict("Name" => name, "Value" => value)); end + + # Populate the LCC Sub-structure with CORRECTLY Structured Cable Data + lcc_node = addelement!(comp, "LCC") + _set_attributes!(lcc_node, Dict("NumPhases" => num_phases, "IconLength" => "true", "LineCablePipe" => 2, "ModelType" => 1)) + cable_header = addelement!(lcc_node, "cable_header") + _set_attributes!(cable_header, Dict("InAirGrnd" => 1, "MatrixOutput" => "true", "ExtraCG"=>"$(num_phases)")) + + for (k, cable) in enumerate(cable_system.cables) + cable_node = addelement!(cable_header, "cable") + + num_components = length(cable.design_data.components) + outermost_radius = cable.design_data.components[end].insulator_group.radius_ext + + _set_attributes!(cable_node, Dict( + "NumCond" => num_components, + "Rout" => outermost_radius, + "PosX" => cable.horz, + "PosY" => cable.vert + )) + + for component in cable.design_data.components + conductor_node = addelement!(cable_node, "conductor") + + cond_group = component.conductor_group + ins_group = component.insulator_group + + rho_eq = calc_equivalent_rho(cond_group.resistance, cond_group.radius_ext, cond_group.radius_in) + mu_r_cond = calc_equivalent_mu(cond_group.gmr, cond_group.radius_ext, cond_group.radius_in) + mu_r_ins = ins_group.layers[1].material_props.mu_r + eps_eq = calc_equivalent_eps(ins_group.shunt_capacitance, ins_group.radius_in, ins_group.radius_ext) + + _set_attributes!(conductor_node, Dict( + "Rin" => cond_group.radius_in, + "Rout" => cond_group.radius_ext, + "rho" => rho_eq, + "muC" => mu_r_cond, + "muI" => mu_r_ins, + "epsI" => eps_eq, + "Cext" => ins_group.shunt_capacitance, + "Gext" => ins_group.shunt_conductance + )) + end + end + + # Finalize and Write to File + _set_attributes!(variables, Dict("NumSim" => 1, "IOPCVP" => 0, "UseParser" => "false")) + + try + open(file_name, "w") do fid + prettyprint(fid, doc) + end + @info "XML file saved to: $(_display_path(file_name))" + return file_name + catch e + @error "Failed to write XML file '$file_name'" exception=(e, catch_backtrace()) + return nothing + end +end + + +""" + read_atp_data(file_name::String, cable_system::LineCableSystem) + +Reads an ATP `.lis` output file, extracts the Ze and Zi matrices, and dynamically +reorders them to a grouped-by-phase format based on the provided `cable_system` +structure. It correctly handles systems with a variable number of components per cable. + +# Arguments +- `file_name`: The path to the `.lis` file. +- `cable_system`: The `LineCableSystem` object corresponding to the data in the file. + +# Returns +- `Array{T, 2}`: A 2D complex matrix representing the total reordered series + impedance `Z = Ze + Zi` for a single frequency. +- `nothing`: If the file cannot be found, parsed, or if the matrix dimensions in the + file do not match the provided `cable_system` structure. +""" +function read_data(::Val{:atp}, + cable_system::LineCableSystem, + freq::AbstractFloat; + file_name::String="$(cable_system.system_id)_1.lis" + )::Union{Array{COMPLEXSCALAR, 2}, Nothing} + # --- Inner helper function to parse a matrix block from text lines --- + function parse_block(block_lines::Vector{String}) + data_lines = filter(line -> !isempty(strip(line)), block_lines) + if isempty(data_lines) return Matrix{ComplexF64}(undef, 0, 0) end + matrix_size = length(split(data_lines[1])) + real_parts = zeros(Float64, matrix_size, matrix_size) + imag_parts = zeros(Float64, matrix_size, matrix_size) + row_counter = 1 + for i in 1:2:length(data_lines) + if i + 1 > length(data_lines) break end + real_line, imag_line = data_lines[i], data_lines[i+1] + try + real_parts[row_counter, :] = [parse(Float64, s) for s in split(real_line)[1:matrix_size]] + imag_parts[row_counter, :] = [parse(Float64, s) for s in split(imag_line)[1:matrix_size]] + catch e; @error "Parsing failed" exception=(e, catch_backtrace()); return nothing end + row_counter += 1 + if row_counter > matrix_size break end + end + return real_parts + im * imag_parts + end + + # --- Main Function Logic --- + if !isfile(file_name) @error "File not found: $file_name"; return nothing end + lines = readlines(file_name) + ze_start_idx = findfirst(occursin.("Earth impedance [Ze]", lines)) + zi_start_idx = findfirst(occursin.("Conductor internal impedance [Zi]", lines)) + if isnothing(ze_start_idx) || isnothing(zi_start_idx) @error "Could not find Ze/Zi headers."; return nothing end + + Ze = parse_block(lines[ze_start_idx + 1 : zi_start_idx - 1]) + Zi = parse_block(lines[zi_start_idx + 1 : end]) + if isnothing(Ze) || isnothing(Zi) return nothing end + + # --- DYNAMICALLY GENERATE PERMUTATION INDICES (Numerical Method) --- + component_counts = [length(c.design_data.components) for c in cable_system.cables] + total_conductors = sum(component_counts) + num_phases = length(component_counts) + max_components = isempty(component_counts) ? 0 : maximum(component_counts) + + if size(Ze, 1) != total_conductors + @error "Matrix size from file ($(size(Ze,1))x$(size(Ze,1))) does not match total components in cable_system ($total_conductors)." + return nothing + end + + num_conductors_per_type = [sum(c >= i for c in component_counts) for i in 1:max_components] + type_offsets = cumsum([0; num_conductors_per_type[1:end-1]]) + + permutation_indices = Int[] + sizehint!(permutation_indices, total_conductors) + instance_counters = ones(Int, max_components) + for phase_idx in 1:num_phases + for comp_type_idx in 1:component_counts[phase_idx] + instance = instance_counters[comp_type_idx] + original_idx = type_offsets[comp_type_idx] + instance + push!(permutation_indices, original_idx) + instance_counters[comp_type_idx] += 1 + end + end + + Ze_reordered = Ze[permutation_indices, permutation_indices] + Zi_reordered = Zi[permutation_indices, permutation_indices] + + return Ze_reordered+Zi_reordered +end + + +""" +$(TYPEDSIGNATURES) + +Exports calculated [`LineParameters`](@ref) to an ATP-style XML file. + +This function takes the results of a simulation (Z and Y matrices) and writes them +into a structured XML format for use in other programs. + +# Arguments + +- `line_params`: A [`LineParameters`](@ref) object containing the calculated Z and Y matrices to be exported. +- `cable_system`: A [`LineCableSystem`](@ref) object used for metadata (e.g., the default filename). +- `problem`: A [`LineParametersProblem`](@ref) object used to retrieve the frequency vector for the export. +- `file_name`: The path to the output XML file (default: "*_export.xml"). + +# Returns + +- The absolute path of the saved file. +""" +function export_data(::Val{:atp}, + line_params::LineParameters, + freq::Vector{BASE_FLOAT}; + file_name::String="ZY_export.xml", + cable_system::Union{LineCableSystem,Nothing}=nothing + )::Union{String,Nothing} + # Construct the file name with system_id if cable_system is provided + file_name = isnothing(cable_system) ? file_name : "$(cable_system.system_id)_ZY_export.xml" + + cable_length = 1.0 + atp_format = "G+Bi" + file_name = isabspath(file_name) ? file_name : joinpath(@__DIR__, file_name) + + open(file_name, "w") do fid + num_phases = size(line_params.Z, 1) + y_fmt = (atp_format == "C") ? "C" : "G+Bi" + + @printf(fid, "\n", num_phases, cable_length, y_fmt) + + # --- Z Matrix Printing --- + for (k, freq_val) in enumerate(freq) + @printf(fid, " \n", freq_val) + for i in 1:num_phases + row_str = join([@sprintf("%.16E%+.16Ei", real(line_params.Z[i, j, k]), imag(line_params.Z[i, j, k])) for j in 1:num_phases], ",") + println(fid, row_str) + end + @printf(fid, " \n") + end + + # --- Y Matrix Printing --- + if atp_format == "C" + freq1 = f[1] + @printf(fid, " \n", freq1) + for i in 1:num_phases + row_str = join([@sprintf("%.16E", imag(line_params.Y[i, j, 1]) / (2 * pi * freq1)) for j in 1:num_phases], ",") + println(fid, row_str) + end + @printf(fid, " \n") + else # Case for "G+Bi" + for (k, freq_val) in enumerate(freq) + @printf(fid, " \n", freq_val) + for i in 1:num_phases + row_str = join([@sprintf("%.16E%+.16Ei", real(line_params.Y[i, j, k]), imag(line_params.Y[i, j, k])) for j in 1:num_phases], ",") + println(fid, row_str) + end + @printf(fid, " \n") + end + end + + # --- Footer --- + println(fid, "") + end + try + # Use pretty print option for debugging comparisons if needed + # open(filename, "w") do io; prettyprint(io, doc); end + if isfile(file_name) + @info "XML file saved to: $(file_name)" + end + return file_name + catch e + @error "Failed to write XML file '$(file_name)': $(e)" + isa(e, SystemError) && println("SystemError details: ", e.extrainfo) + return nothing + rethrow(e) # Rethrow to indicate failure clearly + end +end \ No newline at end of file diff --git a/test/cable_test.json b/test/cable_test.json new file mode 100644 index 00000000..0a75ce9a --- /dev/null +++ b/test/cable_test.json @@ -0,0 +1,310 @@ +{ + "__julia_type__": "LineCableModels.DataModel.CablesLibrary", + "data": { + "test_cable": { + "cable_id": "test_cable", + "nominal_data": { + "U": 30, + "screen_cross_section": 35, + "capacitance": 0.39, + "__julia_type__": "LineCableModels.DataModel.NominalData", + "U0": 18, + "conductor_cross_section": 1000, + "armor_cross_section": null, + "resistance": 0.0291, + "inductance": 0.3, + "designation_code": "NA2XS(FL)2Y" + }, + "__julia_type__": "LineCableModels.DataModel.CableDesign", + "components": [ + { + "insulator_group": { + "__julia_type__": "LineCableModels.DataModel.InsulatorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 32.3, + "mu_r": 1, + "rho": 5300 + }, + "radius_in": 0.02115, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.02145, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1000, + "mu_r": 1, + "rho": 1000 + }, + "radius_in": 0.02145, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.02205, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 2.3, + "mu_r": 1, + "rho": 197000000000000 + }, + "radius_in": 0.02205, + "__julia_type__": "LineCableModels.DataModel.Insulator", + "radius_ext": 0.03005, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1000, + "mu_r": 1, + "rho": 500 + }, + "radius_in": 0.03005, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.030350000000000002, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 32.3, + "mu_r": 1, + "rho": 5300 + }, + "radius_in": 0.030350000000000002, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.030650000000000004, + "temperature": 20 + } + ] + }, + "__julia_type__": "LineCableModels.DataModel.CableComponent", + "id": "core", + "conductor_group": { + "__julia_type__": "LineCableModels.DataModel.ConductorGroup", + "layers": [ + { + "lay_ratio": 0, + "material_props": { + "T0": 20, + "alpha": 0.00429, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1.000022, + "rho": 2.8264e-8 + }, + "lay_direction": 1, + "radius_in": 0, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00235, + "num_wires": 1, + "temperature": 20 + }, + { + "lay_ratio": 15, + "material_props": { + "T0": 20, + "alpha": 0.00429, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1.000022, + "rho": 2.8264e-8 + }, + "lay_direction": 1, + "radius_in": 0.00235, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00235, + "num_wires": 6, + "temperature": 20 + }, + { + "lay_ratio": 13.5, + "material_props": { + "T0": 20, + "alpha": 0.00429, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1.000022, + "rho": 2.8264e-8 + }, + "lay_direction": 1, + "radius_in": 0.007050000000000001, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00235, + "num_wires": 12, + "temperature": 20 + }, + { + "lay_ratio": 12.5, + "material_props": { + "T0": 20, + "alpha": 0.00429, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1.000022, + "rho": 2.8264e-8 + }, + "lay_direction": 1, + "radius_in": 0.01175, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00235, + "num_wires": 18, + "temperature": 20 + }, + { + "lay_ratio": 11, + "material_props": { + "T0": 20, + "alpha": 0.00429, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1.000022, + "rho": 2.8264e-8 + }, + "lay_direction": 1, + "radius_in": 0.01645, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.00235, + "num_wires": 24, + "temperature": 20 + } + ] + } + }, + { + "insulator_group": { + "__julia_type__": "LineCableModels.DataModel.InsulatorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 32.3, + "mu_r": 1, + "rho": 5300 + }, + "radius_in": 0.031700000000000006, + "__julia_type__": "LineCableModels.DataModel.Semicon", + "radius_ext": 0.03200000000000001, + "temperature": 20 + } + ] + }, + "__julia_type__": "LineCableModels.DataModel.CableComponent", + "id": "sheath", + "conductor_group": { + "__julia_type__": "LineCableModels.DataModel.ConductorGroup", + "layers": [ + { + "lay_ratio": 10, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.030650000000000004, + "__julia_type__": "LineCableModels.DataModel.WireArray", + "radius_wire": 0.000475, + "num_wires": 49, + "temperature": 20 + }, + { + "lay_ratio": 10, + "material_props": { + "T0": 20, + "alpha": 0.00393, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 0.999994, + "rho": 1.7241e-8 + }, + "lay_direction": 1, + "radius_in": 0.0316, + "__julia_type__": "LineCableModels.DataModel.Strip", + "width": 0.01, + "radius_ext": 0.031700000000000006, + "temperature": 20 + } + ] + } + }, + { + "insulator_group": { + "__julia_type__": "LineCableModels.DataModel.InsulatorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 2.3, + "mu_r": 1, + "rho": 197000000000000 + }, + "radius_in": 0.032150000000000005, + "__julia_type__": "LineCableModels.DataModel.Insulator", + "radius_ext": 0.032200000000000006, + "temperature": 20 + }, + { + "material_props": { + "T0": 20, + "alpha": 0, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 2.3, + "mu_r": 1, + "rho": 197000000000000 + }, + "radius_in": 0.032200000000000006, + "__julia_type__": "LineCableModels.DataModel.Insulator", + "radius_ext": 0.034600000000000006, + "temperature": 20 + } + ] + }, + "__julia_type__": "LineCableModels.DataModel.CableComponent", + "id": "jacket", + "conductor_group": { + "__julia_type__": "LineCableModels.DataModel.ConductorGroup", + "layers": [ + { + "material_props": { + "T0": 20, + "alpha": 0.00429, + "__julia_type__": "LineCableModels.Materials.Material", + "eps_r": 1, + "mu_r": 1.000022, + "rho": 2.8264e-8 + }, + "radius_in": 0.03200000000000001, + "__julia_type__": "LineCableModels.DataModel.Tubular", + "radius_ext": 0.032150000000000005, + "temperature": 20 + } + ] + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/export_xml.jl b/test/export_xml.jl new file mode 100644 index 00000000..772c4091 --- /dev/null +++ b/test/export_xml.jl @@ -0,0 +1,165 @@ +# test/test_atp_export.jl + +using Test +using TestItemRunner +using LineCableModels + +# Add your setup snippets here if they are in this file +# @testsnippet defaults begin ... end +# @testsnippet cable_system_export begin ... end + +@testsnippet deps_export_atp begin + using EzXML +end + +@testitem "Export to ATPDraw LCC format" setup=[defaults, cable_system_export, deps_export_atp] begin + + # All variables from the setup snippets are available here (problem_atp, cable_system, etc.) + + # 1. ARRANGE & ACT: Run the export in a temporary directory + mktempdir() do tmpdir + output_file = joinpath(tmpdir, "atp_export_test.xml") + result_path = export_data(Val(:atp), cable_system, earth_props, file_name=output_file) + + # 2. ASSERT: Basic file checks (unchanged) + @test result_path == output_file + @test isfile(output_file) + @test filesize(output_file) > 500 + + # 3. ASSERT: General XML structure and LCC data + println(" Performing high-level XML structure checks...") + doc = readxml(output_file) + root_node = root(doc) + + @test nodename(root_node) == "project" + @test root_node["Application"] == "ATPDraw" + + # Find the main LCC component content node + comp_content_node = findfirst("/project/objects/comp/comp_content", root_node) + @test !isnothing(comp_content_node) + + # Verify general parameters like Length, Freq, and Ground Resistivity + println(" Verifying general LCC data (Length, Freq, Grnd resis)...") + @test parse(Float64, findfirst("data[@Name='Length']", comp_content_node)["Value"]) ≈ cable_system.line_length + @test parse(Float64, findfirst("data[@Name='Freq']", comp_content_node)["Value"]) ≈ problem_atp.frequencies[1] + @test parse(Float64, findfirst("data[@Name='Grnd resis']", comp_content_node)["Value"]) ≈ problem_atp.earth_props.layers[end].base_rho_g + + # 4. ASSERT: Detailed validation of ALL cables and conductors + println(" Verifying all cables and their conductors...") + lcc_node = findfirst("/project/objects/comp/LCC", root_node) + cable_header = findfirst("cable_header", lcc_node) + cable_nodes = findall("cable", cable_header) + + @test length(cable_nodes) == num_phases + + # Loop through each cable exported in the XML and compare it to the source + for (i, cable_node) in enumerate(cable_nodes) + println(" -> Checking Cable #$i...") + source_cable = cable_system.cables[i] + + # Verify position of EACH cable + @test parse(Float64, cable_node["PosX"]) ≈ source_cable.horz + @test parse(Float64, cable_node["PosY"]) ≈ source_cable.vert + + # Verify the number of conductor components inside this cable + num_components = length(source_cable.design_data.components) + @test parse(Int, cable_node["NumCond"]) == num_components + + conductor_nodes = findall("conductor", cable_node) + @test length(conductor_nodes) == num_components + + # Loop through each conductor component within the cable + for (j, conductor_node) in enumerate(conductor_nodes) + source_component = source_cable.design_data.components[j] + cond_group = source_component.conductor_group + ins_group = source_component.insulator_group + + # Pre-calculate the expected values using the same functions as the export + expected_rho = calc_equivalent_rho(cond_group.resistance, cond_group.radius_ext, cond_group.radius_in) + expected_muC = calc_equivalent_mu(cond_group.gmr, cond_group.radius_ext, cond_group.radius_in) + expected_epsI = calc_equivalent_eps(ins_group.shunt_capacitance, ins_group.radius_in, ins_group.radius_ext) + + # Assert that every attribute matches the expected value + @test parse(Float64, conductor_node["Rin"]) ≈ cond_group.radius_in + @test parse(Float64, conductor_node["Rout"]) ≈ cond_group.radius_ext + @test parse(Float64, conductor_node["rho"]) ≈ expected_rho + @test parse(Float64, conductor_node["muC"]) ≈ expected_muC + @test parse(Float64, conductor_node["muI"]) ≈ ins_group.layers[1].material_props.mu_r + @test parse(Float64, conductor_node["epsI"]) ≈ expected_epsI + @test parse(Float64, conductor_node["Cext"]) ≈ ins_group.shunt_capacitance + @test parse(Float64, conductor_node["Gext"]) ≈ ins_group.shunt_conductance + end + end + println(" All detailed checks passed!") + end +end + +# Run the test +# @run_package_tests filter = ti -> occursin("Export to ATPDraw LCC format", ti.name) + + +@testitem "Export to ATP format" setup=[defaults, cable_system_export, deps_export_atp] begin + + # The ACT and ASSERT parts of your test go here. + # All variables from the snippets are already defined. + + # 1. RUN THE TEST IN A TEMPORARY DIRECTORY + mktempdir() do tmpdir + output_file = joinpath(tmpdir, "atp_export_test.xml") + println(" Exporting ATP XML file to: ", output_file) + Z_matrix = randn(ComplexF64, num_phases, num_phases, length(freqs)) + Y_matrix = randn(ComplexF64, num_phases, num_phases, length(freqs)) + line_params = LineParameters(Z_matrix, Y_matrix) + + # Call the function we want to test + result_path = export_data(Val(:atp), line_params, freqs; file_name=output_file) + + # 2. BASIC FILE CHECKS + @test result_path == output_file + @test isfile(output_file) + @test filesize(output_file) > 100 + + xml_content = read(output_file, String) + @test occursin("", xml_content) + + # 3. XML STRUCTURE AND DATA VALIDATION + println(" Performing XML structure checks via XPath...") + xml_doc = readxml(output_file) + root_node = root(xml_doc) + + @test nodename(root_node) == "ZY" + @test parse(Int, root_node["NumPhases"]) == num_phases + + z_blocks = findall("//Z", root_node) + @test length(z_blocks) == length(freqs) + + # 4. DETAILED DATA VERIFICATION (for the first frequency) + println(" Verifying numerical data for first frequency...") + first_z_block = z_blocks[1] + @test parse(Float64, first_z_block["Freq"]) ≈ freqs[1] + + z_matrix_rows = split(strip(nodecontent(first_z_block)), '\n') + @test length(z_matrix_rows) == num_phases + + first_row_elements = split(z_matrix_rows[1], ',') + @test length(first_row_elements) == num_phases + number_pattern = r"(-?[\d\.]+E[+-]\d+)" + complex_pattern = Regex("$(number_pattern.pattern)([+-][\\d\\.]+E[+-]\\d+)i") + + match_result = match(complex_pattern, first_row_elements[1]) + + if !isnothing(match_result) + # The captures are now guaranteed to be valid Float64 strings + real_part = parse(Float64, match_result.captures[1]) + imag_part = parse(Float64, match_result.captures[2]) + parsed_z11 = complex(real_part, imag_part) + + expected_z11 = Z_matrix[1, 1, 1] + @test parsed_z11 ≈ expected_z11 rtol=1e-12 + end + end +end + + +@run_package_tests filter = ti -> occursin("Export to ATP format", ti.name) \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index c09ffefd..388868af 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,4 +17,39 @@ end semicon_props = Material(1000.0, 1000.0, 1.0, 20.0, 0.0) end -@run_package_tests verbose = true \ No newline at end of file +@testsnippet cable_system_export begin + + cables_library = CablesLibrary() + cables_library = load!(cables_library, file_name=joinpath(@__DIR__, "./cable_test.json")) + + # Retrieve the reloaded design + cable_design = collect(values(cables_library.data))[1] + x0, y0 = 0.0, -1.0 + xa, ya, xb, yb, xc, yc = trifoil_formation(x0, y0, 0.035); + + # Initialize the `LineCableSystem` with the first cable (phase A): + cablepos = CablePosition(cable_design, xa, ya, + Dict("core" => 1, "sheath" => 0, "jacket" => 0)) + cable_system = LineCableSystem("test_cable_sys", 1000.0, cablepos) + + # Add remaining cables (phases B and C): + add!(cable_system, cable_design, xb, yb, + Dict("core" => 2, "sheath" => 0, "jacket" => 0)) + add!(cable_system, cable_design, xc, yc, + Dict("core" => 3, "sheath" => 0, "jacket" => 0)) + + freqs = sort(abs.(randn(3))) + earth_params_atp = EarthModel(freqs, 100.0, 10.0, 1.0) + num_phases = cable_system.num_phases + + # Create minimal mock objects for the other required arguments + problem_atp = LineParametersProblem( + cable_system, + temperature=20.0, # Operating temperature + earth_props=earth_params_atp, + frequencies=freqs, # Frequency for the analysis + ); + +end + +@run_package_tests verbose = true