Undefined function 'writeSegmentContent' for input arguments of type AemWriter

Hello, first of all thank you for the big work of the community and developers of Orekit ! I am new here and I use the version 12.1.2 within Matlab. I wrote a code to propagate an orbit and write the position and velocity in an OEM file, and the attitude in an AEM file in the order to visualize it on VTS. The OEM file was perfectly generated and the satellite orbit was visualized in VTS but I got the error message “Undefined function ‘writeSegmentContent’ for input arguments of type ‘org.orekit.files.ccsds.ndm.adm.aem.AemWriter’.” when I tried to generate the AEM file.

However, when I look into the orekit12.1.2 source, the writeSegmentContent() method is in the AEMWriter() class and the arguments required corresponds to the one I use.

Does anyone have a guess of where the error can come from and if I should use a different method instead of writeSegmentContent() or if I defined something in the wrong way ?

Below the code:


javaaddpath('S:\Documents\Matlab\orekit-12.1.2.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-core-3.1.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-fft-3.1.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-filtering-3.1.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-fitting-3.1.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-geometry-3.1.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-ode-3.1.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-optim-3.1.jar');
javaaddpath('S:\Documents\Matlab\hipparchus-stat-3.1.jar');
javaaddpath('S:\Documents\Matlab\handlerIllumination.jar');
javaaddpath('S:\Documents\Matlab\test.jar');

import org.illumination.*;

import org.orekit.data.*;
import org.orekit.attitudes.*
import org.orekit.orbits.*;
import org.orekit.time.*;
import org.orekit.bodies.*;
import org.orekit.frames.*;
import org.orekit.utils.*;
import org.orekit.propagation.*;
import org.orekit.propagation.semianalytical.*;
import org.orekit.propagation.numerical.*;
import org.orekit.forces.gravity.*;
import org.orekit.forces.drag.*;
import org.orekit.models.earth.atmosphere.*;
import org.orekit.models.radiation.*;
import org.orekit.forces.gravity.potential.*;
import org.orekit.forces.gravity.*;
import org.orekit.forces.radiation.*;

import org.hipparchus.ode.nonstiff.*;
import org.hipparchus.geometry.euclidean.threed.*;
import org.hipparchus.util.*;
import org.orekit.propagation.events.*;
import org.orekit.models.earth.atmosphere.data.*;
import org.orekit.models.earth.atmosphere.*;
import org.orekit.attitudes.*;

import org.orekit.files.ccsds.utils.*;
import org.orekit.files.ccsds.ndm.adm.*;
import org.orekit.files.ccsds.ndm.odm.oem.*;
import org.orekit.orbits.PositionAngleType.*;
import org.orekit.utils.Constants.*;
import org.orekit.data.DataContext.*;
import org.orekit.files.ccsds.definitions.*;
import java.io.File;
import java.io.FileWriter;
import org.orekit.files.ccsds.ndm.odm.*;
import org.orekit.files.ccsds.section.*;
import org.orekit.files.ccsds.ndm.*;
import org.orekit.files.ccsds.utils.generation.*;
import org.orekit.files.ccsds.ndm.adm.aem.*; 
import org.orekit.files.general.*;

dataProvider = org.orekit.data.DirectoryCrawler(java.io.File('S:\Documents\Matlab\orekit-data'));
dataContext = DataContext.getDefault();
conventions = IERSConventions.IERS_2010;
dataContext.getDataProvidersManager().addProvider(dataProvider);
DataContext.setDefault(dataContext);
% Ensure Orekit library is in the Java class path
% Define initial conditions

utc = TimeScalesFactory.getUTC();
initialDate = AbsoluteDate(2024, 7, 31, 0, 0, 0.000, utc);
finalDate = AbsoluteDate(2024, 8, 1, 0, 0, 0.000, utc);
mu = 3.986004418e14; % Earth's gravitational parameter

% Define initial orbit
a = 7000e3; % semi-major axis in meters
e = 0.001; % eccentricity
i = 98.5 * pi/180; % inclination in radians
omega = 0; % perigee argument in radians
raan = 0; % right ascension of ascending node in radians
lM = 0; % mean anomaly in radians

frame = FramesFactory.getGCRF();

initialOrbit = KeplerianOrbit(a, e, i, omega, raan, lM, PositionAngleType.TRUE, FramesFactory.getEME2000(), initialDate, mu);
mass = 1000.0;
initialState = SpacecraftState(initialOrbit, mass);

% Numerical propagator setup
% Define integrator parameters
minStep = 0.001; % Minimum step size in seconds
maxStep = 1000; % Maximum step size in seconds
initStep = 60.0;
positionTolerance = 0.8; % Position tolerance in meters
tolerances = NumericalPropagator.tolerances(positionTolerance, initialOrbit, OrbitType.CARTESIAN);
integrator = DormandPrince853Integrator(minStep, maxStep, tolerances(1), tolerances(2));
propagator = NumericalPropagator(integrator);
propagator.setOrbitType(OrbitType.KEPLERIAN);
propagator.setInitialState(initialState);

%Set the attitude law for yaw steering 
inertialFrame = FramesFactory.getCIRF(IERSConventions.IERS_2010, true);
earthShape = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, inertialFrame);
groundPointing = org.orekit.attitudes.NadirPointing(FramesFactory.getEME2000(), earthShape); % Define ground pointing attitude provider
sun = CelestialBodyFactory.getSun();
phasingAxis = Vector3D.MINUS_J; % Assuming the solar array rotation axis is X
yawSteeringAttitude = YawSteering(FramesFactory.getEME2000(), groundPointing, sun, phasingAxis);
propagator.setAttitudeProvider(yawSteeringAttitude);

% Define the total propagation duration
totalDuration = finalDate.durationFrom(initialDate);  % Duration from initial to final date in seconds

% Define the number of steps (10 steps in this case)
numSteps = 500;

% Calculate the time step for each propagation
timeStep = totalDuration / numSteps;

% Initialize an array or list to store the spacecraft states
states = java.util.ArrayList();

% Loop to propagate the orbit 10 times before the final date
currentState = initialState;
for i = 1:numSteps
    % Propagate the orbit for the current time step
    nextDate = currentState.getDate().shiftedBy(timeStep);
    currentState = propagator.propagate(nextDate);
    states.add(currentState);
end

% Format
format = FileFormat.KVN;

%%%%%%% OEM file%%%%%%%

% OEM Header
OemHeader = OdmHeader(); 

% OEM Metadata
OEMMetadata = OemMetadata(6);
OEMMetadata.setTimeSystem(TimeSystem.UTC);
OEMMetadata.setObjectID('M2B');
OEMMetadata.setObjectName('M2B');
OEMMetadata.setCenter(BodyFacade('EARTH', CelestialBodyFactory.getCelestialBodies().getEarth()));
OEMMetadata.setReferenceFrame(FrameFacade.map(FramesFactory.getGCRF()));
OEMMetadata.setStartTime(states.get(0).getDate());
OEMMetadata.setStopTime(states.get(states.size() - 1).getDate());

% OEM Data
OemData = OemData();

for i = 1:states.size()
    state = states.get(i-1);
    OemData.addData(state.getPVCoordinates(), false);
end

% OEM Segment
OemSegments = java.util.ArrayList();
OemSegments.add(OemSegment(OEMMetadata, OemData, states.get(0).getMu()));

% OEM object
oem = Oem(OemHeader, OemSegments, IERSConventions.IERS_2010, DataContext.getDefault(), mu);

% Create an OemWriter using a WriterBuilder
oemWriter = WriterBuilder().buildOemWriter();

% Prepare the output file for writing
file = java.io.File('OEMoutput.txt');
outputStream = java.io.FileOutputStream(file);
outputWriter = java.io.OutputStreamWriter(outputStream, java.nio.charset.StandardCharsets.UTF_8);

% Choose the correct generator based on the file format
if format == FileFormat.KVN
    generator = KvnGenerator(outputWriter, OemWriter.KVN_PADDING_WIDTH, 'output.oem', 0,0);
else
    generator = XmlGenerator(outputWriter, XmlGenerator.DEFAULT_INDENT, 'output.oem', false);
end

% Write the OEM data to the file
try
    oemWriter.writeMessage(generator, oem);
    outputWriter.close();
catch exception
    disp(exception.message);
end

bodyFrame = LocalOrbitalFrame(frame, LOFType.VNC, initialState.getOrbit(), 'Body Frame');

%%%%%%% AEM file%%%%%%%

% AEM Header
% header = org.orekit.files.ccsds.section.Header(3,3);
AemHeader = AdmHeader();
% AEM Metadata
AEMMetadata = AemMetadata(8);
AEMMetadata.setObjectID('M2B');
AEMMetadata.setObjectName('M2B');
% AemMetadata.setReferenceFrameA(FramesFactory.getEME2000());
% AemMetadata.setReferenceFrameB(FrameFacade.map(bodyFrame));
AEMMetadata.setTimeSystem(TimeSystem.UTC);
AEMMetadata.setAttitudeType(AttitudeType.QUATERNION);
AEMMetadata.setStartTime(states.get(0).getDate());
AEMMetadata.setStopTime(states.get(states.size() - 1).getDate());

frameA = FrameFacade(FramesFactory.getEME2000(), CelestialBodyFrame.EME2000, [], [], 'EME2000');
frameB = FrameFacade([], [], [], SpacecraftBodyFrame.parse('SC_BODY_1'), 'SC_BODY_1');

endpoints = AEMMetadata.getEndpoints();
endpoints.setFrameA(frameA); % Reference Frame A
endpoints.setFrameB(frameB); % Reference Frame B
endpoints.setA2b(true); % Attitude Direction

% AEM Data
AemData = AemData();

for i = 1:states.size()
    state = states.get(i-1);
    Attitude = state.getAttitude();
    TimeStampedAngles = TimeStampedAngularCoordinates(state.getDate(), Attitude.getRotation(), Attitude.getSpin(), Attitude.getRotationAcceleration());
    AEMData.addData(TimeStampedAngles);
end

% disp(AEMData.getAngularCoordinates());
% AEM Segment
AemSegments = java.util.ArrayList();
AemSegments.add(AemSegment(AEMMetadata, AemData));

% Create an OemWriter using a WriterBuilder
aemWriter = WriterBuilder().buildAemWriter();

% Prepare the output file for writing
file = java.io.File('AEMoutput2.txt');
outputStream = java.io.FileOutputStream(file);
outputWriter = java.io.OutputStreamWriter(outputStream, java.nio.charset.StandardCharsets.UTF_8);

% Choose the correct generator based on the file format
if format == FileFormat.KVN
    generator = KvnGenerator(outputWriter, aemWriter.KVN_PADDING_WIDTH, 'AEMoutput2.txt', 0,0);
else
    generator = XmlGenerator(outputWriter, XmlGenerator.DEFAULT_INDENT, 'AEMoutput2.txt', false);
end

% Write the AEM data to the file
try
    aemWriter.writeSegmentContent(generator,3.0, AemSegments.get(0));
    outputWriter.close();
catch exception
    disp(exception.message);
end

Hello @Victorjsn,

Thank you as well for opening a thread on this topic :slight_smile: , this wil be useful to other users as well !

Cause

You are getting this error because the “writeSegmentContent()” method is protected and hence, can’t be used explicitely as in your provided code. You can check the following documentation for more information.

Solution

First you should create an AEM message (as you did with the OEM) and then call the “writeMessage()” method of the AemWriter (again, the same way you did it with your OEM file) and it should work as expected :+1: !

Cheers,
Vincent

Hello Vincent,

I followed your advices then the AEM file was generated and I could visualize the attitude of the satellite on VTS. Thank you a lot for your help and you quick answer !

I just have another question, the line “ATTITUDE_DIR = A2B” is not generated in the AEM file even when I set “endpoints.setA2b(true)”, I tried with the Matlab syntax FOR booleans but it doesn’t change, do you have an idea of what I should change ?

Cheers,
Victor

Glad it worked !

Cause

I may be wrong but based on the you provided earlier, it seems that you tried to use format version = 3 when writing your AEM file. However, based on the ATTITUDE DATA
MESSAGES CCSDS Pink book from June 2022
, the format version for this book is 2. Finally, the “ATTITUDE_DIR” keyword is removed in this version and later.

That’s why we have the following lines in the AemWriter :

        if (formatVersion < 2.0) {
            generator.writeEntry(AemMetadataKey.ATTITUDE_DIR.name(), metadata.getEndpoints().isA2b() ? A_TO_B : B_TO_A, null, true);
        }

So any format version above 1 (initial ADM CCSDS blue book) will not have the “ATTITUDE_DIR” keyword inside.

Solution

Long story short, you need to use formatVersion = 1 for your AemWriter to write the “ATTITUDE_DIR” keyword inside your file :ok_hand:

Keep us updated :slight_smile: !

Cheers,
Vincent

Hi Vincent, thank you for your explanations and sorry for my late reply. I was looking for a way to change the formatVersion of the AemWritter but I havn’t found any methods or arguments allowing to do that in the classes AemWritter(), NdmWritter(), AdmHeader(), AemMetadata(), Aem() or in the method writeMessage() of the NdmWritter() class. Do you have an idea of how I can modify the format version ?

Cheers,

Victor

Hello @Victorjsn,

I believe this is done in the AdmHeader rather than in the AemWriter. You should find a “setFormatVersion” method.

Oh ok yes it is, thank you !

1 Like