Scripting Using Product Builder
The Product Builder provides the capability to generate and export reports and graphs as well as save and load product lists for later use. Use the ScriptingTool "Props" function to explore the Ansys Orbit Determination Tool Kit (ODTK®) application ProductBuilder's interface in more detail.
For descriptions of the methods FindByName, FindProduct, GenerateAllProducts, GenerateProduct, LoadDataProductList, and SaveDataProductList and their arguments, see Product Builder Scope Functions.
When creating reports and graphs from a script, there are two common approaches. The first is to manually build a data product list. The script then loads the data product list and edits the properties of each data product as needed. The other approach is to use a new data product list and build a complete data product on the fly. The advantage of the former approach is that the script is using the same data product list that an analyst would use.
Below are descriptions and code samples for both approaches.
Using an existing data product list
The script example below processes measurements for the TDRS constellation and some of its user satellites. It performs a series of 10 one-day filter runs. After each run, it generates various data products using an existing data product list called TDRS6 and dumps them to disk. The analyst built the data product list manually ahead of time.
COM
option explicit
dim unused, odApp, ODTK, sc, f, s, i, diffile
dim product, topdir, outputdir, rundir
dim fso, sat
' Define how long each run should be in hours
dim durHours
durHours = 24
' Define how many runs to perform
dim numRuns
numRuns = 10
topdir = "C:\Temp\TDRS\"
' Define where the outputs will go
outputdir = topdir & "Outputs\"
Set FSO = CreateObject("Scripting.FileSystemObject")
'-----------------------------------------------------------------
' Grab ODTK COM object
'-----------------------------------------------------------------
set odApp = GetObject(, "ODTK.Application")
If Err.Number <> 0 Then
MsgBox("ODTK not running")
End If
set ODTK = odApp.Personality
set sc = ODTK.Scenario(0)
set f = sc.Filter(0)
set s = sc.Smoother(0)
f.ProcessControl.StopMode = "TimeSpan"
set unused = f.ProcessControl.TimeSpan.Set(durHours, "hr")
for i = 1 to numRuns
runDir = outputdir & "run " & i & "\"
if not fso.FolderExists(rundir) then
fso.createfolder(rundir)
end if
'-----------------------------------------------------------------
' Run the filter. If it's not the first run, then we will be in
' restart mode.
'-----------------------------------------------------------------
if (i = 1) then
f.ProcessControl.StartMode = "Initial"
else
f.ProcessControl.StartMode = "AutoRestart"
end if
f.Output.STKEphemeris.OutputDirectory = runDir
f.Go
'-----------------------------------------------------------------
' Run the smoother
'-----------------------------------------------------------------
s.Output.STKEphemeris.OutputDirectory = runDir
s.Go
'-----------------------------------------------------------------
' Difference the runs
'-----------------------------------------------------------------
diffile = f.Output.DataArchive.Filename
diffile = replace(diffile, "filrun", "difrun")
' Using empty dates as the start and stop implies that all available
' information should be used.
ODTK.CreateDifference diffile, s.Output.DataArchive.Filename, f.Output.DataArchive.Filename, true, "", "", false
'-----------------------------------------------------------------
' Generate reports and graphs
'-----------------------------------------------------------------
ODTK.ProductBuilder.LoadDataProductList(topdir & "\TDRS6.dpl")
' Loop through each of the satellites that the filter processed.
for each sat in f.SatelliteList
' Create TDRS specific products
if left(sat, 4) = "TDRS" then
GenSatProduct sat, "Range Residuals"
GenSatProduct sat, "BRTS Range Residuals"
GenSatProduct sat, "SRP estimate"
else
' Create non TDRS products
GenSatProduct sat, "Doppler Residuals"
GenSatProduct sat, "4L Range Residuals"
end if
GenSatProduct sat, "Filter Position Uncertainty"
GenSatProduct sat, "Smoother Position Uncertainty"
GenSatProduct sat, "Position Consistency"
next
GenSatProduct "", "Impulsive Mnvr Summary"
GenSatProduct "", "BRTS Transponder Bias"
GenSatProduct "", "Relay Transponder Bias"
' Reload the data product list to reset all the settings we used earlier.
' don't want to confuse the user if they want to create some products manually.
ODTK.ProductBuilder.LoadDataProductList(topdir & "\TDRS6.dpl")
' Close any report or graph windows that are up
closeOutputWindows
next
'-----------------------------------------------------------------
' Routine for generating specific products with optional
' satellite filter. Sat is the name of a specific satellite and
' prod_name is the name of the product in the data product list.
'-----------------------------------------------------------------
sub GenSatProduct(sat, prod_name)
dim extension, product
' Go find the requested product
for each product in ODTK.ProductBuilder.DataProducts
if (product.Name = prod_name) then
' Set the input filters. This is where we limit
' by the specific satellite
product.Inputs.SatelliteList.clear()
if (sat <> "") then
product.Inputs.SatelliteList.push_back(sat)
end if
' Configure where the product will go.
product.Outputs.Display = false
product.Outputs.Export.Enabled = true
product.Outputs.Export.DestinationType = "File"
if (product.Type = "Graph") then
product.Outputs.Export.Format = "PNG"
extension = "png"
else
product.Outputs.Export.Format = "TXT"
extension = "txt"
end if
' Build an output file path
if sat <> "" then
product.Outputs.Export.FileName = rundir & sat & "_" & prod_name & "." & extension
else
product.Outputs.Export.FileName = rundir & prod_name & "." & extension
end if
' Create product and save it to disk.
set unused = ODTK.ProductBuilder.GenerateProduct(prod_name)
set unused = nothing
exit for
end if
next
end sub
sub closeOutputWindows
dim w
for each w in odapp.windows
if left(w.Caption,12) = "Graph Viewer" or left(w.Caption,13) = "Report Viewer" then
w.Close
end if
next
end sub
var unused, odApp, ODTK, sc, f, s, i, diffile;
var product, topdir, outputdir, rundir;
var fso, sat;
// Define how long each run should be in hours
var durHours;
durHours = 24;
// Define how many runs to perform
var numRuns;
numRuns = 10;
topdir = "C:\\Temp\\TDRS\\";
// Define where the outputs will go
outputdir = topdir + "Outputs\\";
fso = new ActiveXObject("Scripting.FileSystemObject");
//-----------------------------------------------------------------
// Grab ODTK COM object
//-----------------------------------------------------------------
odApp = GetObject("", "ODTK.Application");
ODTK = odApp.Personality;
sc = ODTK.Scenario(0);
f = sc.Filter(0);
s = sc.Smoother(0);
f.ProcessControl.StopMode = "TimeSpan";
unused = f.ProcessControl.TimeSpan.Set(durHours, "hr");
for(var i = 1; i < numRuns; i++)
{
runDir = new String(outputdir + "run " + i + "\\");
if(fso.FolderExists(runDir) == false)
{
fso.CreateFolder(runDir);
}
//-----------------------------------------------------------------
// Run the filter. If it's not the first run, then we will be in
// restart mode.
//-----------------------------------------------------------------
if(i == 1)
{
f.ProcessControl.StartMode = "Initial";
}
else
{
f.ProcessControl.StartMode = "AutoRestart";
}
f.Output.STKEphemeris.OutputDirectory = runDir.toString();
f.Go();
//-----------------------------------------------------------------
// Run the smoother
//-----------------------------------------------------------------
s.Output.STKEphemeris.OutputDirectory = runDir.toString();
s.Go();
//-----------------------------------------------------------------
//Difference the runs
//-----------------------------------------------------------------
diffile = new String(f.Output.DataArchive.Filename);
diffile = diffile.replace(/filrun/gi, "difrun");
// Using empty dates as the start and stop implies that all available
// information should be used.
ODTK.CreateDifference(diffile, s.Output.DataArchive.Filename, f.Output.DataArchive.Filename, true, "", "", false);
//-----------------------------------------------------------------
// Generate reports and graphs
//-----------------------------------------------------------------
ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl");
// Loop through each of the satellites that the filter processed.
for (var k = 0; k < f.SatelliteList.Count; k++)
{
// Create TDRS specific products
if (SatelliteList(k).substr(0,4) == "TDRS" )
{
GenSatProduct(SatelliteList(k), "Range Residuals");
GenSatProduct(SatelliteList(k), "BRTS Range Residuals");
GenSatProduc(SatelliteList(k), "SRP estimate");
}
else
{
// Create non TDRS products
GenSatProduct(SatelliteList(k), "Doppler Residuals");
GenSatProduct(SatelliteList(k), "4L Range Residuals");
}
GenSatProduct(SatelliteList(k), "Filter Position Uncertainty");
GenSatProduct(SatelliteList(k), "Smoother Position Uncertainty");
GenSatProduct(SatelliteList(k), "Position Consistency");
}
GenSatProduct("", "Impulsive Mnvr Summary");
GenSatProduct("", "BRTS Transponder Bias");
GenSatProduct("", "Relay Transponder Bias");
// Reload the data product list to reset all the settings we used earlier.
// don't want to confuse the user if they want to create some products manually.
ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl");
// Close any report or graph windows that are up
closeOutputWindows();
}
//-----------------------------------------------------------------
// Routine for generating specific products with optional
// satellite filter. Sat is the name of a specific satellite and
// prod_name is the name of the product in the data product list.
//-----------------------------------------------------------------
function GenSatProduct(sat, prod_name)
{
var extension;
// Go find the requested product
for(var i = 0; i < ODTK.ProductBuilder.DataProducts.Count; i++)
{
if (ODTK.ProductBuilder.DataProducts(i).Name == prod_name)
{
// Set the input filters. This is where we limit
// by the specific satellite
ODTK.ProductBuilder.DataProducts(i).Inputs.SatelliteList.clear();
if (sat != "")
{
ODTK.ProductBuilder.DataProducts(i).Inputs.SatelliteList.push_back(sat);
}
// Configure where the product will go.
ODTK.ProductBuilder.DataProducts(i).Outputs.Display = false;
ODTK.ProductBuilder.DataProducts(i).Outputs.Export.Enabled = true;
ODTK.ProductBuilder.DataProducts(i).Outputs.Export.DestinationType = "File";
if (ODTK.ProductBuilder.DataProducts(i).Type == "Graph")
{
ODTK.ProductBuilder.DataProducts(i).Outputs.Export.Format = "PNG";
extension = "png";
}
else
{
ODTK.ProductBuilder.DataProducts(i).Outputs.Export.Format = "TXT";
extension = "txt";
}
// Build an output file path
if (sat != "")
{
ODTK.ProductBuilder.DataProducts(i).Outputs.Export.FileName = rundir + sat + "_" + prod_name + "." + extension;
}
else
{
ODTK.ProductBuilder.DataProducts(i).Outputs.Export.FileName = rundir + prod_name + "." + extension;
}
// Create product and save it to disk.
var unused = ODTK.ProductBuilder.GenerateProduct(prod_name);
unused = nothing;
}
}
}
function closeOutputWindows()
{
for(var i = 0; i < odApp.windows.Count; i++)
{
if ( odApp.windows(i).Caption.substr(0,12) == "Graph Viewer" || odApp.windows(i).Caption.substr(0,13) == "Report Viewer")
{
w.Close();
}
}
}
# from pathlib import Path
#-----------------------------------------------------------------
# Routine for generating specific products with optional
# satellite filter. Sat is the name of a specific satellite and
# prod_name is the name of the product in the data product list.
#-----------------------------------------------------------------
def GenSatProduct(sat, prod_name):
# Go find the requested product
for product in ODTK.ProductBuilder.DataProducts:
if (product.Name == prod_name):
# Set the input filters. This is where we limit
# by the specific satellite
product.Inputs.SatelliteList.clear()
if sat != "":
product.Inputs.SatelliteList.push_back(sat)
# Configure where the product will go.
product.Outputs.Display = False
product.Outputs.Export.Enabled = True
product.Outputs.Export.DestinationType = "File"
if product.Type == "Graph":
product.Outputs.Export.Format = "PNG"
extension = "png"
else:
product.Outputs.Export.Format = "TXT"
extension = "txt"
# Build an output file path
if sat != "":
product.Outputs.Export.FileName = rundir + sat + "_" + prod_name + "." + extension
else:
product.Outputs.Export.FileName = rundir + prod_name + "." + extension
# Create product and save it to disk.
ODTK.ProductBuilder.GenerateProduct(prod_name)
# Grabs amount of characters from left side of string
def left(string, amount):
return string[:amount]
def closeOutputWindows():
for w in odApp.windows:
if left(w.Caption,12) == "Graph Viewer" or left(w.Caption,13) == "Report Viewer":
w.Close()
# Define how long each run should be in hours
durHours = 24
# Define how many runs to perform
numRuns = 10
topdir = "C:\\Temp\\TDRS\\"
# Define where the outputs will go
outputdir = topdir + "Outputs\\"
fso = w32c.Dispatch("Scripting.FileSystemObject")
#-----------------------------------------------------------------
# Grab ODTK COM object
#-----------------------------------------------------------------
odApp = w32c.GetActiveObject("ODTK.Application")
ODTK = odApp.Personality
sc = ODTK.Scenario(0)
f = sc.Filter(0)
s = sc.Smoother(0)
f.ProcessControl.StopMode = "TimeSpan"
f.ProcessControl.TimeSpan.Set(durHours, "hr")
for i in range(1,numRuns):
runDir = outputdir + "run " + str(i) + "\\"
if not Path.exists(runDir):
Path.mkdir(runDir)
#-----------------------------------------------------------------
# Run the filter. If it's not the first run, then we will be in
# restart mode.
#-----------------------------------------------------------------
if i == 1:
f.ProcessControl.StartMode = "Initial"
else:
f.ProcessControl.StartMode = "AutoRestart"
f.Output.STKEphemeris.OutputDirectory = runDir
f.Go()
#-----------------------------------------------------------------
# Run the smoother
#-----------------------------------------------------------------
s.Output.STKEphemeris.OutputDirectory = runDir
s.Go()
#-----------------------------------------------------------------
# Difference the runs
#-----------------------------------------------------------------
diffile = str(f.Output.DataArchive.Filename)
diffile = diffile.replace("filrun", "difrun")
# Using empty dates as the start and stop implies that all available
# information should be used.
ODTK.CreateDifference(diffile, s.Output.DataArchive.Filename, f.Output.DataArchive.Filename, True, "", "", False)
#-----------------------------------------------------------------
# Generate reports and graphs
#-----------------------------------------------------------------
ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl")
# Loop through each of the satellites that the filter processed.
for sat in f.SatelliteList:
# Create TDRS specific products
if left(sat, 4) == "TDRS":
GenSatProduct(sat, "Range Residuals")
GenSatProduct(sat, "BRTS Range Residuals")
GenSatProduct(sat, "SRP estimate")
else:
# Create non TDRS products
GenSatProduct(sat, "Doppler Residuals")
GenSatProduct(sat, "4L Range Residuals")
GenSatProduct(sat, "Filter Position Uncertainty")
GenSatProduct(sat, "Smoother Position Uncertainty")
GenSatProduct(sat, "Position Consistency")
GenSatProduct("", "Impulsive Mnvr Summary")
GenSatProduct("", "BRTS Transponder Bias")
GenSatProduct("", "Relay Transponder Bias")
# Reload the data product list to reset all the settings we used earlier.
# don't want to confuse the user if they want to create some products manually.
ODTK.ProductBuilder.LoadDataProductList(topdir + "\\TDRS6.dpl")
# Close any report or graph windows that are up
closeOutputWindows()
Cross-Platform API
# Using an Existing Data Product List
# The script example below was used to process measurements for the TDRS constellation and some of its user
# satellites. It performs a series of 10 1-day filter runs. After each run it generates various data products using
# an existing data product list called TDRS6 and dumps them to disk. The data product list was built manually ahead
# of time by the analyst.
# -----------------------------------------------------------------
# Routine for generating specific products with optional
# satellite filter. Sat is the name of a specific satellite and
# prod_name is the name of the product in the data product list.
# -----------------------------------------------------------------
def gen_sat_product(sat_name, prod_name, run_dir_path):
# Go find the requested product
for product in odtk.ProductBuilder.DataProducts:
if product.Name.eval() == prod_name:
# Set the input filters. This is where we limit
# by the specific satellite
product.Inputs.SatelliteList.clear()
if sat_name != "":
product.Inputs.SatelliteList.push_back(sat_name)
# Configure where the product will go.
product.Outputs.Display = False
product.Outputs.Export.Enabled = True
product.Outputs.Export.DestinationType = 'File'
if product.Type.eval() == 'Graph':
product.Outputs.Export.Format = 'PNG'
extension = 'png'
else:
product.Outputs.Export.Format = 'TXT'
extension = 'txt'
# Build an output file path
if sat_name != '':
product.Outputs.Export.FileName = f'{run_dir_path}{sat_name}_{prod_name}.{extension}'
else:
product.Outputs.Export.FileName = f'{run_dir_path}{prod_name}.{extension}'
# Create product and save it to disk.
odtk.ProductBuilder.GenerateProduct(prod_name)
print(f'Generated {prod_name} for {sat_name}.')
break
# Load the scenario
if odtk.children.count > 0:
# close scenario
odtk.application.deleteObject('', odtk.scenario[0])
print('Scenario closed.')
scenario_file_path = Path(this_dir_path) / '..' / 'test_resources' / 'FDF_TDRS 6.1'/ 'FDF-OPS.sco'
odtk.LoadObject('', str(scenario_file_path))
scenario = odtk.scenario[0]
# Define how long each run should be in hours
duration_hours = 24
# Define how many runs to perform
num_runs = 2
# Define where the outputs will go
output_dir = Path(this_dir_path) / 'Outputs'
f = scenario.Filter[0]
s = scenario.Smoother[0]
f.ProcessControl.StopMode = 'TimeSpan'
f.ProcessControl.TimeSpan.Set(duration_hours, 'hr')
data_product_list_path = Path(this_dir_path) / '..' / 'test_resources' / 'FDF_TDRS 6.1' / 'FDF-OPS.dpl'
for i in range(1, num_runs+1):
run_dir = output_dir / f'run {i}'
if not Path.exists(run_dir):
Path.mkdir(run_dir)
# -----------------------------------------------------------------
# Run the filter. If it's not the first run, then we will be in
# restart mode.
# -----------------------------------------------------------------
if i == 1:
f.ProcessControl.StartMode = 'Initial'
else:
f.ProcessControl.StartMode = 'AutoRestart'
f.Output.STKEphemeris.OutputDirectory = str(run_dir)
if not f.Go():
print(f'Filter run {i} failed.')
exit()
# -----------------------------------------------------------------
# Run the smoother
# -----------------------------------------------------------------
s.Output.STKEphemeris.OutputDirectory = str(run_dir)
if not s.Go():
print(f'Simulator run {i} failed.')
exit()
# -----------------------------------------------------------------
# Difference the runs
# -----------------------------------------------------------------
diff_file = f.Output.DataArchive.Filename.value.eval()
diff_file = diff_file.replace('filrun', 'difrun')
# Using empty dates as the start and stop implies that all available
# information should be used.
if not odtk.CreateDifference(diff_file, s.Output.DataArchive.Filename.value.eval(),
f.Output.DataArchive.Filename.value.eval(), True, '', '', False):
print(f'CreateDifference run {i} failed.')
exit()
# -----------------------------------------------------------------
# Generate reports and graphs
# -----------------------------------------------------------------
odtk.ProductBuilder.LoadDataProductList(data_product_list_path)
# Loop through each of the satellites that the filter processed.
for sat in f.SatelliteList:
sat_name = sat.name.eval()
print(f'Generating products for {sat_name}...')
# Create TDRS specific products
if sat_name[:4] == 'TDRS':
gen_sat_product(sat_name, 'Range Residuals', run_dir)
gen_sat_product(sat_name, 'BRTS Range Residuals', run_dir)
gen_sat_product(sat_name, 'SRP estimate', run_dir)
else:
# Create non TDRS products
gen_sat_product(sat_name, 'Doppler Residuals', run_dir)
gen_sat_product(sat_name, '4L Range Residuals', run_dir)
gen_sat_product(sat_name, 'Filter Position Uncertainty', run_dir)
gen_sat_product(sat_name, 'Smoother Position Uncertainty', run_dir)
gen_sat_product(sat_name, 'Position Consistency', run_dir)
print(f'Products have been generated for {sat_name}.')
gen_sat_product('', 'Impulsive Mnvr Summary', run_dir)
gen_sat_product('', 'BRTS Transponder Bias', run_dir)
gen_sat_product('', 'Relay Transponder Bias', run_dir)
# Reload the data product list to reset all the settings we used earlier.
# don't want to confuse the user if they want to create some products manually.
odtk.ProductBuilder.LoadDataProductList(data_product_list_path)
% Using an Existing Data Product List
% The script example below was used to process measurements for the TDRS constellation and some of its user
% satellites. It performs a series of 10 1-day filter runs. After each run it generates various data products using
% an existing data product list called TDRS6 and dumps them to disk. The data product list was built manually ahead
% of time by the analyst.
% Load the scenario
if odtk.children.count > 0
% close scenario
odtk.application.deleteObject("", odtk.scenario{0});
fprintf("Scenario closed.\n");
end
scenarioFilePath = [thisFolderPath, filesep, '..', filesep, 'test_resources', filesep, 'FDF_TDRS 6.1', filesep, 'FDF-OPS.sco'];
odtk.LoadObject("", scenarioFilePath);
scenario = odtk.scenario{0};
% Define how long each run should be in hours
durationHours = 24;
% Define how many runs to perform
numRuns = 2;
% Define where the outputs will go
outputDir = [thisFolderPath, filesep, 'Outputs'];
f = scenario.Filter{0};
s = scenario.Smoother{0};
f.ProcessControl.StopMode = "TimeSpan";
f.ProcessControl.TimeSpan.Set(durationHours, "hr");
dataProductListPath = [thisFolderPath, filesep, '..', filesep, 'test_resources', filesep, 'FDF_TDRS 6.1', filesep, 'FDF-OPS.dpl'];
for i = 1: numRuns
runDir = [outputDir, filesep, 'run ', int2str(i), filesep];
if exist(runDir, "dir") ~= 7 % 7 = directory
mkdir(runDir);
end
% -----------------------------------------------------------------
% Run the filter. If it's not the first run, then we will be in
% restart mode.
% -----------------------------------------------------------------
if i == 1
f.ProcessControl.StartMode = "Initial";
else
f.ProcessControl.StartMode = "AutoRestart";
end
f.Output.STKEphemeris.OutputDirectory = runDir;
if ~f.Go()
fprintf("Filter run %i failed.\n", i);
exit();
end
% -----------------------------------------------------------------
% Run the smoother
% -----------------------------------------------------------------
s.Output.STKEphemeris.OutputDirectory = runDir;
if ~s.Go()
fprintf("Simulator run %i failed.\n", i);
exit();
end
% -----------------------------------------------------------------
% Difference the runs
% -----------------------------------------------------------------
filterOutputFile = f.Output.DataArchive.Filename.value;
diffFile = replace(filterOutputFile, "filrun", "difrun");
% Using empty dates as the start and stop implies that all available
% information should be used.
if ~odtk.CreateDifference(diffFile, s.Output.DataArchive.Filename.value, ...
filterOutputFile, true, "", "", false)
fprintf("CreateDifference run % failed.\n", i);
exit();
end
% -----------------------------------------------------------------
% Generate reports and graphs
% -----------------------------------------------------------------
odtk.ProductBuilder.LoadDataProductList(dataProductListPath);
% Loop through each of the satellites that the filter processed.
for j = 0: f.SatelliteList.Count-1
satelliteName = f.SatelliteList{j}.name;
fprintf("Generating products for %s...\n", satelliteName);
% Create TDRS specific products
if startsWith(satelliteName, "TDRS")
genSatProduct(odtk, satelliteName, "Range Residuals", runDir);
genSatProduct(odtk, satelliteName, "BRTS Range Residuals", runDir);
genSatProduct(odtk, satelliteName, "SRP estimate", runDir);
else
% Create non TDRS products
genSatProduct(odtk, satelliteName, "Doppler Residuals", runDir);
genSatProduct(odtk, satelliteName, "4L Range Residuals", runDir);
end
genSatProduct(odtk, satelliteName, "Filter Position Uncertainty", runDir);
genSatProduct(odtk, satelliteName, "Smoother Position Uncertainty", runDir);
genSatProduct(odtk, satelliteName, "Position Consistency", runDir);
fprintf("Products have been generated for %s.\n", satelliteName);
end
genSatProduct(odtk, "", "Impulsive Mnvr Summary", runDir);
genSatProduct(odtk, "", "BRTS Transponder Bias", runDir);
genSatProduct(odtk, "", "Relay Transponder Bias", runDir);
% Reload the data product list to reset all the settings we used earlier.
% don't want to confuse the user if they want to create some products manually.
odtk.ProductBuilder.LoadDataProductList(dataProductListPath);
end
% -----------------------------------------------------------------
% Routine for generating specific products with optional
% satellite filter. Sat is the name of a specific satellite and
% prod_name is the name of the product in the data product list.
% -----------------------------------------------------------------
function genSatProduct(odtk, satName, prodName, runDirPath)
% Go find the requested product
products = odtk.ProductBuilder.DataProducts;
for i = 0: products.Count-1
product = products{i};
if product.Name == prodName
% Set the input filters. This is where we limit
% by the specific satellite
product.Inputs.SatelliteList.clear();
if satName ~= ""
product.Inputs.SatelliteList.push_back(satName);
end
% Configure where the product will go.
product.Outputs.Display = false;
product.Outputs.Export.Enabled = true;
product.Outputs.Export.DestinationType = "File";
if product.Type == "Graph"
product.Outputs.Export.Format = "PNG";
extension = "png";
else
product.Outputs.Export.Format = "TXT";
extension = "txt";
end
% Build an output file path
if satName ~= ""
product.Outputs.Export.FileName = runDirPath + satName + " " + prodName + "." + extension;
else
product.Outputs.Export.FileName = runDirPath + prodName + "." + extension;
end
% Create product and save it to disk.
odtk.ProductBuilder.GenerateProduct(prodName);
fprintf("Generated %s for %s.\n", prodName, satName);
break;
end
end
end
// Using an Existing Data Product List
// The script example below was used to process measurements for the TDRS constellation and some of its user
// satellites.It performs a series of 10 1 - day filter runs.After each run it generates various data products using
// an existing data product list called TDRS6 and dumps them to disk.The data product list was built manually ahead
// of time by the analyst.
// Load the scenario
if (odtk("Children")("Count").AsInt() > 0)
{
// close scenario
odtk("application")("deleteObject").Invoke("", odtk("scenario")[0]);
std::cout << "Scenario closed.\n";
}
const auto scenario_file_path = resourcesFolderPath + s_pathSeparator + "FDF_TDRS 6.1" + s_pathSeparator + "FDF-OPS.sco";
odtk("LoadObject").Invoke("", scenario_file_path);
// Define how long each run should be in hours
const auto durationHours = 24;
// Define how many runs to perform
const auto numRuns = 2;
//Define where the outputs will go
const auto outputDir = thisFolderPath + s_pathSeparator + "Outputs";
if (!EnsureDirExists(outputDir))
{
return;
}
const agi::odtk::AttrProxy scenario = odtk("scenario")[0];
const auto f = scenario("Filter")[0].AsAttrProxy();
const auto s = scenario("Smoother")[0].AsAttrProxy();
f("ProcessControl")("StopMode").Assign("TimeSpan");
f("ProcessControl")("TimeSpan")("Set").Invoke(durationHours, "hr");
const auto dataProductListPath = resourcesFolderPath + s_pathSeparator + "FDF_TDRS 6.1" + s_pathSeparator +
"FDF-OPS.dpl";
for (int i = 1; i <= numRuns; i++)
{
const auto runDirPath = outputDir + s_pathSeparator + "run " + std::to_string(i) + s_pathSeparator;
if (!EnsureDirExists(runDirPath))
{
return;
}
// Run the filter.If it's not the first run, then we will be in restart mode.
if (i == 1)
{
f("ProcessControl")("StartMode").Assign("Initial");
}
else
{
f("ProcessControl")("StartMode").Assign("AutoRestart");
}
f("Output")("STKEphemeris")("OutputDirectory").Assign(runDirPath);
if (!f("Go").InvokeBool())
{
std::cout << "Filter run " << i << " failed.\n";
return;
}
// Run the smoother
s("Output")("STKEphemeris")("OutputDirectory").Assign(runDirPath);
if (!s("Go").InvokeBool())
{
std::cout << "Simulator run " << i << " failed.\n";
return;
}
// Difference the runs
std::string diffFile = f("Output")("DataArchive")("Filename")("value").AsString();
const std::string filRunString = "filrun";
diffFile = diffFile.replace(diffFile.find(filRunString), filRunString.length(), "difrun");
// Using empty dates as the start and stop implies that all available
// information should be used.
if (!odtk("CreateDifference").InvokeBool(
diffFile, s("Output")("DataArchive")("Filename")("value").AsString(),
f("Output")("DataArchive")("Filename")("value").AsString(), true, "", "", false))
{
std::cout << "CreateDifference run " << i << " failed.\n";
return;
}
// Generate reports and graphs
odtk("ProductBuilder")("LoadDataProductList").Invoke(dataProductListPath);
// Loop through each of the satellites that the filter processed.
for (int j = 0; j < f("SatelliteList")("Count").AsInt(); j++)
{
const auto satName = f("SatelliteList")[j]("Name").AsString();
std::cout << "Generating products for " << satName << "...\n";
// Create TDRS specific products
if (satName.substr(0, 4) == "TDRS")
{
GetSatProduct(odtk, satName, "Range Residuals", runDirPath);
GetSatProduct(odtk, satName, "BRTS Range Residuals", runDirPath);
GetSatProduct(odtk, satName, "SRP estimate", runDirPath);
}
else
{
// Create non TDRS products
GetSatProduct(odtk, satName, "Doppler Residuals", runDirPath);
GetSatProduct(odtk, satName, "4L Range Residuals", runDirPath);
}
GetSatProduct(odtk, satName, "Filter Position Uncertainty", runDirPath);
GetSatProduct(odtk, satName, "Smoother Position Uncertainty", runDirPath);
GetSatProduct(odtk, satName, "Position Consistency", runDirPath);
std::cout << "Products have been generated for " << satName << ".\n";
}
GetSatProduct(odtk, "", "Impulsive Mnvr Summary", runDirPath);
GetSatProduct(odtk, "", "BRTS Transponder Bias", runDirPath);
GetSatProduct(odtk, "", "Relay Transponder Bias", runDirPath);
// Reload the data product list to reset all the settings we used earlier.
// don't want to confuse the user if they want to create some products manually.
odtk("ProductBuilder")("LoadDataProductList").Invoke(dataProductListPath);
}
}
std::string InternalScriptingGuide::GetCurrentWorkingDir()
{
#ifdef _WIN32
char filePath[MAX_PATH];
char* currentPath = _getcwd(filePath, sizeof filePath);
#else
char filePath[PATH_MAX];
char* currentPath = getcwd(filePath, sizeof filePath);
#endif
return std::string(currentPath);
}
void InternalScriptingGuide::GetSatProduct(const agi::odtk::AttrProxy& odtk, const std::string& satName,
const std::string& prodName, const std::string& runDirPath)
{
// Routine for generating specific products with optional
// satellite filter. satName is the name of a specific satellite and
// prodName is the name of the product in the data product list.
// Go find the requested product
const agi::odtk::AttrProxy products = odtk("ProductBuilder")("DataProducts");
for (int i = 0; i < products("Count").AsInt(); i++)
{
const auto product = products[i].AsAttrProxy();
if (product("Name").AsString() == prodName)
{
// Set the input filters.This is where we limit
// by the specific satellite
product("Inputs")("SatelliteList")("Clear").Invoke();
if (satName != "")
{
product("Inputs")("SatelliteList")("push_back").Invoke(satName);
}
// Configure where the product will go.
product("Outputs")("Display").Assign(false);
product("Outputs")("Export")("Enabled").Assign(true);
product("Outputs")("Export")("DestinationType").Assign("File");
std::string extension;
if (product("Type").AsString() == "Graph")
{
product("Outputs")("Export")("Format").Assign("PNG");
extension = "png";
}
else
{
product("Outputs")("Export")("Format").Assign("TXT");
extension = "txt";
}
// Build an output file path
if (satName != "")
{
product("Outputs")("Export")("FileName").Assign(runDirPath + satName + "_" + prodName + "." + extension);
}
else
{
product("Outputs")("Export")("FileName").Assign(runDirPath + prodName + "." + extension);
}
// Create product and save it to disk.
odtk("ProductBuilder")("GenerateProduct").Invoke(prodName);
std::cout << "Generated " << prodName << " for " << satName << "\n";
break;
}
}
}
bool InternalScriptingGuide::EnsureDirExists(const std::string& dirPath)
{
int errorCode = 0;
#ifdef _WIN32
errorCode = _mkdir(dirPath.c_str());
if (errorCode != 0 && errno == EEXIST)
{
return true;
}
#else
mode_t mode = 0733;
errorCode = mkdir(dirPath.c_str(), mode);
#endif
if (errorCode != 0)
{
std::cout << "An error occurred while creating directory " << dirPath << ". Error code: " << errorCode << "\n";
}
return errorCode == 0;
}
const char InternalScriptingGuide::s_pathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif
// Using an Existing Data Product List
// The script example below was used to process measurements for the TDRS constellation and some of its user
// satellites.It performs a series of 10 1 - day filter runs.After each run it generates various data products using
// an existing data product list called TDRS6 and dumps them to disk.The data product list was built manually ahead
// of time by the analyst.
// Load the scenario
String resourcesFolderPath = "";
String thisFolderPath = System.getProperty("user.dir");
AttrProxy odtk = client.getRoot();
// Load the scenario
if (odtk.get("children.count").asInt() > 0) {
// close scenario
odtk.get("application.deleteObject").invoke("",odtk.get("scenario[0]"));
System.out.println("Scenario closed.");
}
String scenarioFilePath = resourcesFolderPath + Client.PATH_SEPARATOR + "FDF_TDRS 6.1" + Client.PATH_SEPARATOR + "FDF-OPS.sco";
odtk.get("LoadObject").invoke("", scenarioFilePath);
// Define how long each run should be in hours
int durationHours = 24;
// Define how many runs to perform
int numRuns = 2;
// Define where the outputs will go
String outputDir = thisFolderPath + Client.PATH_SEPARATOR + "Outputs";
if(!EnsureDirExists(outputDir)) {
return;
}
AttrProxy scenario = odtk.get("scenario[0]");
AttrProxy f = scenario.get("Filter[0]");
AttrProxy s = scenario.get("Smoother[0]");
f.get("ProcessControl.StopMode").assign("TimeSpan");
f.get("ProcessControl.TimeSpan.Set").invoke(durationHours, "hr");
String dataProductListPath = resourcesFolderPath + Client.PATH_SEPARATOR + "FDF_TDRS 6.1" + Client.PATH_SEPARATOR + "FDF-OPS.dpl";
for (int i = 1; i <= numRuns; i++) {
String runDirPath = outputDir + Client.PATH_SEPARATOR + "run " + i + Client.PATH_SEPARATOR;
if (!EnsureDirExists(runDirPath)) {
return;
}
// Run the filter.If it's not the first run, then we will be in restart mode.
if (i == 1) {
f.get("ProcessControl.StartMode").assign("Initial");
} else {
f.get("ProcessControl.StartMode").assign("AutoRestart");
}
f.get("Output.STKEphemeris.OutputDirectory").assign(runDirPath);
if (!f.get("Go").invokeBool()) {
System.out.println("Filter run " + i + " failed.");
return;
}
// Run the smoother
s.get("Output.STKEphemeris.OutputDirectory").assign(runDirPath);
if (!s.get("Go").invokeBool()) {
System.out.println("Simulator run " + i + " failed.");
return;
}
// Difference the runs
String diffFile = f.get("Output.DataArchive.Filename.value").asString();
String filRunString = "filrun";
diffFile = diffFile.replace(filRunString, "difrun");
// Using empty dates as the start and stop implies that all available
// information should be used.
if (!odtk.get("CreateDifference").invokeBool(diffFile, s.get("Output.DataArchive.Filename.value").asString(),f.get("Output.DataArchive.Filename.value").asString(), true, "", "", false))
{
System.out.println("CreateDifference run " + i + " failed.");
return;
}
// Generate reports and graphs
odtk.get("ProductBuilder.LoadDataProductList").invoke(dataProductListPath);
// Loop through each of the satellites that the filter processed.
for (int j = 0; j < f.get("SatelliteList.Count").asInt(); j++) {
String satName = f.get("SatelliteList[" + j + "].Name").asString();
System.out.println("Generating products for " + satName + "...");
// Create TDRS specific products
if (satName.substring(0, 4) == "TDRS") {
GetSatProduct(odtk, satName, "Range Residuals", runDirPath);
GetSatProduct(odtk, satName, "BRTS Range Residuals", runDirPath);
GetSatProduct(odtk, satName, "SRP estimate", runDirPath);
} else {
// Create non TDRS products
GetSatProduct(odtk, satName, "Doppler Residuals", runDirPath);
GetSatProduct(odtk, satName, "4L Range Residuals", runDirPath);
}
GetSatProduct(odtk, satName, "Filter Position Uncertainty", runDirPath);
GetSatProduct(odtk, satName, "Smoother Position Uncertainty", runDirPath);
GetSatProduct(odtk, satName, "Position Consistency", runDirPath);
System.out.println("Products have been generated for " + satName);
}
GetSatProduct(odtk, "", "Instant Mnvr Summary", runDirPath);
GetSatProduct(odtk, "", "BRTS Transponder Bias", runDirPath);
GetSatProduct(odtk, "", "Relay Transponder Bias", runDirPath);
// Reload the data product list to reset all the settings we used earlier.
// don't want to confuse the user if they want to create some products manually.
odtk.get("ProductBuilder.LoadDataProductList").invoke(dataProductListPath);
}
public static void GetSatProduct(AttrProxy odtk, String satName, String prodName, String runDirPath) throws ClientException, IOException {
// Routine for generating specific products with optional
// satellite filter. satName is the name of a specific satellite and
// prodName is the name of the product in the data product list.
// Go find the requested product
IterProxy products = odtk.get("ProductBuilder.DataProducts").asIterProxy();
while (products.hasNext()) {
AttrProxy product = products.next();
if (product.get("Name").asString() == prodName) {
// Set the input filters.This is where we limit
// by the specific satellite
product.get("Inputs.SatelliteList.Clear").invoke();
if (satName != "") {
product.get("Inputs.SatelliteList.push_back").invoke(satName);
}
// Configure where the product will go.
product.get("Outputs.Display").assign(false);
product.get("Outputs.Export.Enabled").assign(true);
product.get("Outputs.Export.DestinationType").assign("File");
String extension;
if (product.get("Type").asString() == "Graph") {
product.get("Outputs.Export.Format").assign("PNG");
extension = "png";
} else {
product.get("Outputs.Export.Format").assign("TXT");
extension = "txt";
}
// Build an output file path
if (satName != "") {
product.get("Outputs.Export.FileName").assign(runDirPath + satName + "_" + prodName + "." + extension);
} else {
product.get("Outputs.Export.FileName").assign(runDirPath + prodName + "." + extension);
}
// Create product and save it to disk.
odtk.get("ProductBuilder.GenerateProduct").invoke(prodName);
System.out.println("Generated " + prodName + " for " + satName);
break;
}
}
}
public static boolean EnsureDirExists(String dirPath) {
File file = new File(dirPath);
if(file.isDirectory()) {
return true;
}
return false;
}
Building and using a data product list
The script examples below assume there is no existing data product list. Therefore, the Product Builder builds a data product each time the script calls it to produce the desired output.
COM
set scen = ODTK.Scenario(0)
set unused = ODTK.ProductBuilder.DataProducts.Clear()
ArchiveFile = ODTK.Scenario(0).Filter(0).Output.DataArchive.Filename
RunReport ArchiveFile, "Residuals.gph", ""
RunReport ArchiveFile, "Residual Summary.rpt", "TXT"
' Generic function to build and create a product.
Function RunReport(ArchiveFile, ReportName, ExportFormat)
' Find the requested style
style = ODTK.InstallHome & "/ODTK/AppData/Styles/Static/" & ReportName
' Create a new data product at the end of the list
set newElm = ODTK.ProductBuilder.DataProducts.NewElem()
set unused = ODTK.ProductBuilder.DataProducts.push_back(newElm)
index = ODTK.ProductBuilder.DataProducts.size - 1
set Product = ODTK.ProductBuilder.DataProducts(index)
' Configure the the data product
set newSrc = Product.Inputs.DataSources.NewElem()
set unused = Product.Inputs.DataSources.push_back(newSrc)
Product.Name = "Satellite 1 " & ReportName
Product.Inputs.DataSources(0).Filename = CStr(ArchiveFile)
Product.Outputs.Style = Style
Product.Outputs.Display = true
' Configure the export if requested
if ExportFormat <> "" then
ExpFile = ODTK.UserHome & "\" & Product.Name & "." & ExportFormat
msgbox ExpFile
Product.Outputs.Export.Enabled = true
Product.Outputs.Export.Format = ExportFormat
Product.Outputs.Export.FileName = CStr(ExpFile)
end if
' Create the product
ODTK.ProductBuilder.GenerateProduct(Product.Name)
End Function
var Shell = new ActiveXObject("WScript.Shell");
var scen = ODTK.Scenario(0);
var unused = ODTK.ProductBuilder.DataProducts.Clear();
var ArchiveFile = ODTK.Scenario(0).Filter(0).Output.DataArchive.Filename;
RunReport(ArchiveFile, "Residuals.gph", "");
RunReport(ArchiveFile, "Residual Summary.rpt", "TXT");
// Generic function to build and create a product.
function RunReport(ArchiveFile, ReportName, ExportFormat)
{
// Find the requested style
var Style = ODTK.InstallHome + "\\ODTK\\AppData\\Styles\\Static\\" + ReportName;
// Create a new data product at the end of the list
var newElm = ODTK.ProductBuilder.DataProducts.NewElem();
var unused = ODTK.ProductBuilder.DataProducts.push_back(newElm);
var index = ODTK.ProductBuilder.DataProducts.size - 1;
var Product = ODTK.ProductBuilder.DataProducts(index);
// Configure the the data product
var newSrc = Product.Inputs.DataSources.NewElem();
unused = Product.Inputs.DataSources.push_back(newSrc);
Product.Name = "Satellite 1 " + ReportName;
Product.Inputs.DataSources(0).Filename = String(ArchiveFile);
Product.Outputs.Style = Style;
Product.Outputs.Display = true;
// Configure the export if requested
if (ExportFormat != "")
{
ExpFile = ODTK.UserHome + "\\" + Product.Name + "." + ExportFormat;
Shell.Popup(ExpFile);
Product.Outputs.Export.Enabled = true;
Product.Outputs.Export.Format = ExportFormat;
Product.Outputs.Export.FileName = String(ExpFile);
}
// Create the product
ODTK.ProductBuilder.GenerateProduct(Product.Name);
}
# Generic function to build and create a product.
def RunReport(ArchiveFile, ReportName, ExportFormat):
# Find the requested style
style = str(ODTK.InstallHome) + "\\ODTK\\AppData\\Styles\\Static\\" + ReportName
# Create a new data product at the end of the list
newElm = ODTK.ProductBuilder.DataProducts.NewElem()
unused = ODTK.ProductBuilder.DataProducts.push_back(newElm)
index = int(ODTK.ProductBuilder.DataProducts.size) - 1
Product = ODTK.ProductBuilder.DataProducts(index)
# Configure the the data product
newSrc = Product.Inputs.DataSources.NewElem()
unused = Product.Inputs.DataSources.push_back(newSrc)
Product.Name = "Satellite 1 " + ReportName
Product.Inputs.DataSources(0).Filename = str(ArchiveFile)
Product.Outputs.Style = style
Product.Outputs.Display = True
# Configure the export if requested
if ExportFormat != "":
ExpFile = str(ODTK.UserHome) + "\\" + str(Product.Name) + "." + ExportFormat
print(ExpFile)
Product.Outputs.Export.Enabled = True
Product.Outputs.Export.Format = ExportFormat
Product.Outputs.Export.FileName = str(ExpFile)
# Create the product
ODTK.ProductBuilder.GenerateProduct(Product.Name)
scen = ODTK.Scenario(0)
unused = ODTK.ProductBuilder.DataProducts.Clear()
ArchiveFile = ODTK.Scenario(0).Filter(0).Output.DataArchive.Filename
RunReport(ArchiveFile, "Residuals.gph", "")
RunReport(ArchiveFile, "Residual Summary.rpt", "TXT")
Cross-Platform API
# Generic function to build and create a product.
def run_report(input_file_name, style_path, product_name, export_file_path):
# Create a new data product at the end of the list
new_elem = odtk.ProductBuilder.DataProducts.NewElem()
odtk.ProductBuilder.DataProducts.push_back(new_elem)
index = odtk.ProductBuilder.DataProducts.size.eval() - 1
product = odtk.ProductBuilder.DataProducts[index]
# Configure the the data product
new_src = product.Inputs.DataSources.NewElem()
product.Inputs.DataSources.push_back(new_src)
product.Name.Assign(product_name)
product.Inputs.DataSources[0].Filename = input_file_name
product.Outputs.Style = style_path
product.Outputs.Display = True
product.Outputs.Export.Enabled = True
product.Outputs.Export.Format = "CommaSeparated"
product.Outputs.Export.FileName = export_file_path
# Create the product
if not odtk.ProductBuilder.GenerateProduct(product_name):
raise Exception('GenerateProduct failed. Please check the log for more details.')
print(f'{input_file_name} exported to {export_file_path}')
odtk.ProductBuilder.DataProducts.Clear()
archive_file_name = scenario.Filter[0].Output.DataArchive.Filename.value.eval()
print(f'Archive file: {archive_file_name}')
style_file_path = Path(this_dir_path) / ".." / "SharedResources" / "measHist.exp"
output_file_path = Path(this_dir_path) / "measHist.txt"
run_report(archive_file_name, str(style_file_path), "measHist", str(output_file_path))
% The script example below assumes there is no existing data product list. So it builds a data product each time it
% is called to produce the desired output.
odtk.ProductBuilder.DataProducts.Clear();
archiveFileName = scenario.Filter{0}.Output.DataArchive.Filename.value;
fprintf("Archive file: %s\n", archiveFileName);
styleFilePath = [thisFolderPath, filesep, '..', filesep, 'SharedResources', filesep, 'measHist.exp'];
outputFilePath = [thisFolderPath, filesep, 'measHist.txt'];
runReport(odtk, archiveFileName, styleFilePath, "measHist", outputFilePath);
% Setting a custom location for the ODTK log file
% By default ODTK will create its log in a user temp directory and delete it upon application exit.
% However, you may override this by using the following commands:
appendMode = true;
logfilePath = [thisFolderPath, filesep, 'log.txt'];
odtk.Application.SetLogFile(logfilePath, appendMode);
logLevelDebug = 0;
logLevelInfo = 1;
logLevelForceInfo = 2;
logLevelWarning = 3;
logLevelError = 4;
odtk.Application.LogMsg(logLevelInfo, "LogFile = " + odtk.Application.LogFile);
odtk.Application.LogMsg(logLevelWarning, "This is a warning message.");
odtk.Application.LogMsg(logLevelError, "This is an error message.");
% functions
function printKeplerianOrbitState(os)
fprintf("Epoch : %s UTCG, Eccentricity: %f, " + ...
"TrueArgOfLatitude: %f deg, Inclination: %f deg, " + ...
"RAAN: %f deg, ArgOfPerigee: %f deg rad\n", ...
os.Epoch.Format("UTCG"), ...
os.Eccentricity, ...
os.TrueArgOfLatitude.GetIn("deg"), ...
os.Inclination.GetIn("deg"), ...
os.RAAN.GetIn("deg"), ...
os.ArgOfPerigee.GetIn("rad"));
end
function printGeodeticPos(p)
fprintf("Lat : %f deg, Lon: %f deg, Alt: %f m\n", ...
p.Lat.GetIn("deg"), ...
p.Lon.GetIn("deg"), ...
p.Alt.GetIn("m"));
end
% Generic function to build and create a product.
function runReport(odtk, inputFileName, stylePath, productName, exportFilePath)
% Create a new data product at the end of the list
newElem = odtk.ProductBuilder.DataProducts.NewElem();
odtk.ProductBuilder.DataProducts.push_back(newElem);
index = odtk.ProductBuilder.DataProducts.size - 1;
product = odtk.ProductBuilder.DataProducts{index};
% Configure the the data product
newSrc = product.Inputs.DataSources.NewElem();
product.Inputs.DataSources.push_back(newSrc);
product.Name.Assign(productName);
product.Inputs.DataSources{0}.Filename = inputFileName;
product.Outputs.Style = stylePath;
product.Outputs.Display = true;
product.Outputs.Export.Enabled = true;
product.Outputs.Export.Format = "CommaSeparated";
product.Outputs.Export.FileName = exportFilePath;
% Create the product
if ~odtk.ProductBuilder.GenerateProduct(productName)
throw(MException('ScriptingGuide:unexpectedError', 'GenerateProduct failed. Please check the log for more details.'));
end
fprintf("%s exported to %s\n", inputFileName, exportFilePath);
end
// The script example below assumes there is no existing data product list.So it builds a data product each time it
// is called to produce the desired output.
odtk("ProductBuilder")("DataProducts")("Clear").Invoke();
const auto archiveFileName = scenario("Filter")[0]("Output")("DataArchive")("Filename")("value").AsString();
std::cout << "Archive file: " << archiveFileName << "\n";
const std::string styleFilePath = thisFolderPath + s_pathSeparator + ".." + s_pathSeparator + "SharedResources"
+ s_pathSeparator + "measHist.exp";
const std::string outputFilePath = thisFolderPath + s_pathSeparator + "measHist.txt";
RunReport(odtk, archiveFileName, styleFilePath, "measHist", outputFilePath);
std::string ScriptingGuide::GetThisFolderPath()
{
#ifdef _WIN32
char filePath[MAX_PATH];
char* currentPath = _getcwd(filePath, sizeof filePath);
#else
char filePath[PATH_MAX];
char* currentPath = getcwd(filePath, sizeof filePath);
#endif
return std::string(currentPath);
}
const char* ScriptingGuide::BoolToString(const bool deleted)
{
return (deleted ? "true" : "false");
}
void ScriptingGuide::PrintGeodeticPos(const agi::odtk::AttrProxy& pos)
{
std::cout << "Lat : " << pos("Lat")("GetIn").InvokeDouble("deg")
<< " deg, Lon: " << pos("Lon")("GetIn").InvokeDouble("deg")
<< " deg, Alt: " << pos("Alt")("GetIn").InvokeDouble("m") << " m\n";
}
void ScriptingGuide::PrintKeplerianOrbitState(const agi::odtk::AttrProxy& kep)
{
std::cout << "Epoch : " << kep("Epoch")("Format").InvokeString("UTCG")
<< " UTCG, Eccentricity: " << kep("Eccentricity").AsDouble()
<< ", TrueArgOfLatitude: " << kep("TrueArgOfLatitude")("GetIn").InvokeDouble("deg")
<< " deg, Inclination: " << kep("Inclination")("GetIn").InvokeDouble("deg")
<< " deg, RAAN: " << kep("RAAN")("GetIn").InvokeDouble("deg")
<< " deg, ArgOfPerigee: " << kep("ArgOfPerigee")("GetIn").InvokeDouble("rad") << " deg rad\n";
}
void ScriptingGuide::RunReport(const agi::odtk::AttrProxy& odtk, const std::string& inputFileName, const std::string& stylePath,
const std::string& productName, const std::string& exportFilePath)
{
// Create a new data product at the end of the list
const agi::odtk::AttrProxy newElem = odtk("ProductBuilder")("DataProducts")("NewElem").InvokeAttrProxy();
odtk("ProductBuilder")("DataProducts")("push_back").Invoke(newElem);
const auto index = odtk("ProductBuilder")("DataProducts")("size").AsInt() - 1;
const auto product = odtk("ProductBuilder")("DataProducts")[index].AsAttrProxy();
// Configure the the data product
const agi::odtk::AttrProxy newSrc = product("Inputs")("DataSources")("NewElem").InvokeAttrProxy();
product("Inputs")("DataSources")("push_back").Invoke(newSrc);
product("Name")("Assign").Invoke(productName);
product("Inputs")("DataSources")[0]("Filename").Assign(inputFileName);
product("Outputs")("Style").Assign(stylePath);
product("Outputs")("Display").Assign(true);
product("Outputs")("Export")("Enabled").Assign(true);
product("Outputs")("Export")("Format").Assign("CommaSeparated");
product("Outputs")("Export")("FileName").Assign(exportFilePath);
//Create the product
if (!odtk("ProductBuilder")("GenerateProduct").InvokeBool(productName))
{
throw std::runtime_error("GenerateProduct failed. Please check the log for more details.");
}
std::cout << inputFileName << " exported to " << exportFilePath << "\n";
}
const char ScriptingGuide::s_pathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif
// The script example below assumes there is no existing data product list.So it builds a data product each time it
// is called to produce the desired output.
odtk.get("ProductBuilder.DataProducts.Clear").invoke();
String archiveFileName = scenario.get("Filter[0].Output.DataArchive.Filename.value").asString();
System.out.println("Archive file: " + archiveFileName);
String styleFilePath = thisFolderPath + Client.PATH_SEPARATOR + ".." + Client.PATH_SEPARATOR + ".."
+ Client.PATH_SEPARATOR + "SharedResources" + Client.PATH_SEPARATOR + "measHist.exp";
String outputFilePath = thisFolderPath + Client.PATH_SEPARATOR + "measHist.txt";
runReport(archiveFileName, styleFilePath, "measHist", outputFilePath);
private void printGeodeticPos(AttrProxy pos) throws ClientException, IOException {
System.out.printf("Lat : %s deg, Lon: %s deg, Alt: %s m\n", pos.get("Lat.GetIn").invokeDouble("deg"), pos.get("Lon.GetIn").invokeDouble("deg"), pos.get("Alt.GetIn").invokeDouble("m"));
}
private void printKeplerianOrbitState(AttrProxy orbitState) throws ClientException, IOException {
System.out.printf("Epoch : %s UTCG, Eccentricity: %s deg, TrueArgOfLaatitude: %s deg, Inclination: %s deg, RAAN: %s deg, ArgOfPerigee %s rad\n", orbitState.get("Epoch.Format").invokeString("UTCG"), orbitState.get("Eccentricity").asDouble(), orbitState.get("TrueArgOfLatitude.GetIn").invokeDouble("deg"), orbitState.get("Inclination.GetIn").invokeDouble("deg"), orbitState.get("RAAN.GetIn").invokeDouble("deg"), orbitState.get("ArgOfPerigee.GetIn").invokeDouble("rad"));
}
private void runReport(String inputFileName, String stylePath, String productName, String exportFilePath) throws Exception {
// Create a new data product at the end of the list
AttrProxy newElem = odtk.get("ProductBuilder.DataProducts.NewElem").invokeAttr();
odtk.get("ProductBuilder.DataProducts.push_Back").invoke(newElem);
int index = odtk.get("ProductBuilder.DataProducts.size").asInt() - 1;
AttrProxy product = odtk.get("ProductBuilder.DataProducts(" + index + ")");
// Configure the the data product
AttrProxy newSrc = product.get("Inputs.DataSources.NewElem").invokeAttr();
product.get("Inputs.DataSources.push_back").invoke(newSrc);
product.get("Name.assign").invoke(productName);
product.get("Inputs.DataSources[0].Filename").assign(inputFileName);
product.get("Outputs.Style").assign(stylePath);
product.get("Outputs.Display").assign(true);
product.get("Outputs.Export.Enabled").assign(true);
product.get("Outputs.Export.Format").assign("CommaSeparated");
product.get("Outputs.Export.FileName").assign(exportFilePath);
// Create the product
if(!odtk.get("ProductBuilder.GenerateProduct").invokeBool(productName)){
throw new Exception("GenerateProduct failed. Please check the log for more details.");
}
System.out.println(inputFileName + " exported to " + exportFilePath);
}