diff --git a/app/otbSARMetadataCorrection.cxx b/app/otbSARMetadataCorrection.cxx index cf6833c6085ca7c033525a461b7132a75aa216f2..f665f58451f20e3061361c63c7b51012333c1148 100644 --- a/app/otbSARMetadataCorrection.cxx +++ b/app/otbSARMetadataCorrection.cxx @@ -28,8 +28,12 @@ #include <fstream> #include <complex> #include <cmath> +#include <ctime> #include <iosfwd> +#include "otb_tinyxml.h" +#include "itksys/SystemTools.hxx" + // include ossim #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push @@ -47,11 +51,21 @@ #endif +enum +{ + Mode_UserDefined, + Mode_GCP, + Mode_Orbits +}; + + + // Time/Date ossim typedef ossimplugins::time::ModifiedJulianDate TimeType; typedef ossimplugins::time::Duration DurationType; // Keys for ImageKeywordlist +// Gcp keys const std::string keyAzimuthTime = "azimuthTime"; const std::string keySlantRangeTime = "slant_range_time"; const std::string keyImPtX = "im_pt.x"; @@ -62,6 +76,16 @@ const std::string keyWorldPtHgt = "world_pt.hgt"; const std::string GCP_PREFIX = "support_data.geom.gcp"; const std::string GCP_NUMBER_KEY = "support_data.geom.gcp.number"; const std::string SUPPORT_DATA_PREFIX = "support_data."; +// Orbit keys +const std::string ORBIT_PREFIX = "orbitList.orbit"; +const std::string ORBIT_NUMBER_KEY = "orbitList.nb_orbits"; +const std::string keyTime = "time"; +const std::string keyPosX = "x_pos"; +const std::string keyPosY = "y_pos"; +const std::string keyPosZ = "z_pos"; +const std::string keyVelX = "x_vel"; +const std::string keyVelY = "y_vel"; +const std::string keyVelZ = "z_vel"; ///// Functions to handle metadata ////// @@ -332,6 +356,130 @@ int updateGCPAndKWL(std::vector<double> * vector_hgt, unsigned int gcpcount, otb return 0; } +// Selection for fine orbits (choose only orbits that fit with the image) +int selectOrbits(std::vector<std::string> * vector_time, + const otb::ImageKeywordlist inKWL, int & ind_first, int & ind_last) +{ + // Initialize indexes + ind_first = 0; + ind_last = vector_time->size() - 1; + + // Get time for first and last original orbit states + int orbitCount = std::atoi(inKWL.GetMetadataByKey(ORBIT_NUMBER_KEY).c_str()); + + char prefix_first[1024]; + sprintf(prefix_first, "%s[%d].%s", ORBIT_PREFIX.c_str(), 0, keyTime.c_str()); + std::string UTC_first = inKWL.GetMetadataByKey(std::string (prefix_first)); + + char prefix_last[1024]; + sprintf(prefix_last, "%s[%d].%s", ORBIT_PREFIX.c_str(), (orbitCount-1), keyTime.c_str()); + std::string UTC_last = inKWL.GetMetadataByKey(std::string (prefix_last)); + + // Transform string to t_time (in seconds) + struct tm tm1; + struct tm tm2; + strptime(UTC_first.c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm1); + strptime(UTC_last.c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm2); + time_t t_first = mktime(&tm1); + time_t t_last = mktime(&tm2); + + // Selection of indexes into vector_time + // ind_first = last elt to be inferior to t_first + // ind_last = first elt to be superior to t_last + for (unsigned int i = 0; i < vector_time->size(); i++) + { + struct tm tm; + strptime(vector_time->at(i).c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm); + time_t t = mktime(&tm); + + if (difftime(t, t_first) > 0 && ind_first == 0) + { + if (i !=0) + { + ind_first = i - 1; + } + } + if (difftime(t_last, t) < 0) + { + ind_last = i; + + break; + } + } +} + + +// Create new Orbits and update outKWL // +int createOrbitsAndUpdateKWL(std::vector<double *>* vector_posvel, + std::vector<std::string> * vector_time, + int ind_first, int ind_last, + otb::ImageKeywordlist & outKWL) +{ + // Check size (same size for all vectors) + unsigned int vecSize = vector_posvel->size(); + if (vector_time->size() != vecSize) + { + // retrun 1 => Pb + return 1; + } + + int orbitCount = std::atoi(outKWL.GetMetadataByKey(ORBIT_NUMBER_KEY).c_str()); + + if (vecSize < orbitCount) + { + // Fine orbit are inferior to original => pb + return 1; + } + + std::string orbitFineCount = std::to_string(ind_last - ind_first + 1); + outKWL.AddKey(ORBIT_NUMBER_KEY, orbitFineCount); + + // Create or update each Orbit state + for (unsigned int i = 0; i < std::atoi(orbitFineCount.c_str()); i++) + { + // Add the orbit to kwl + char prefix[1024]; + + std::stringstream stream; + + // time + sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyTime.c_str()); + outKWL.AddKey(prefix, vector_time->at(ind_first + i)); + + // position + sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyPosX.c_str()); + stream.str(""); + stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[0]; + outKWL.AddKey(prefix, stream.str()); + + sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyPosY.c_str()); + stream.str(""); + stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[1]; + outKWL.AddKey(prefix, stream.str()); + + sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyPosZ.c_str()); + stream.str(""); + stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[2]; + outKWL.AddKey(prefix, stream.str()); + + // velocity + sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyVelX.c_str()); + stream.str(""); + stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[3]; + outKWL.AddKey(prefix, stream.str()); + + sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyVelY.c_str()); + stream.str(""); + stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[4]; + outKWL.AddKey(prefix, stream.str()); + + sprintf(prefix, "%s[%d].%s", ORBIT_PREFIX.c_str(), i, keyVelZ.c_str()); + stream.str(""); + stream << std::fixed << std::setprecision(6) << vector_posvel->at(ind_first + i)[5]; + outKWL.AddKey(prefix, stream.str()); + } + return 0; +} ///// OTB Application ////// namespace otb @@ -374,6 +522,22 @@ private: AddParameter(ParameterType_InputImage, "insar", "Input SAR image"); SetParameterDescription("insar", "SAR Image to extract initial metadata."); + AddParameter(ParameterType_InputFilename, "infineorbits", "Input file to get precise orbits"); + SetParameterDescription("infineorbits","Input file to get precise orbits."); + MandatoryOff("infineorbits"); + + // mode selection : gcp (auto) or fine orbits + AddParameter(ParameterType_Choice, "mode", "Parameters estimation modes"); + AddChoice("mode.auto", "User Defined"); + SetParameterDescription("mode.auto", "This mode allows you to fully modify default values : GCP corrections"); + AddChoice("mode.gcp", "GCP corrections"); + SetParameterDescription("mode.gcp", + "This mode allows you to automatically correct GCP into the output geom file"); + AddChoice("mode.orbits", "Fine orbits"); + SetParameterDescription("mode.orbits", + "This mode allows you to automatically retrieve the fine orbits and to save into a new geom file"); + + AddParameter(ParameterType_OutputFilename, "outkwl", "Write the OSSIM keywordlist to a geom file"); SetParameterDescription("outkwl", "This option allows extracting the OSSIM keywordlist of the image into a geom file."); MandatoryOff("outkwl"); @@ -386,145 +550,300 @@ private: void DoUpdateParameters() override { - // Nothing to do here : all parameters are independent + // Handle inputs following the mode + // chose by the user + switch (GetParameterInt("mode")) + { + case Mode_UserDefined: + { + EnableParameter("indem"); + EnableParameter("outkwl"); + DisableParameter("infineorbits"); + + MandatoryOn("indem"); + MandatoryOff("outkwl"); + MandatoryOff("infineorbits"); + } + break; + case Mode_GCP: + { + EnableParameter("indem"); + EnableParameter("outkwl"); + DisableParameter("infineorbits"); + + MandatoryOn("indem"); + MandatoryOff("outkwl"); + MandatoryOff("infineorbits"); + } + break; + case Mode_Orbits: + { + DisableParameter("indem"); + EnableParameter("outkwl"); + EnableParameter("infineorbits"); + + MandatoryOff("indem"); + MandatoryOn("outkwl"); + MandatoryOn("infineorbits"); + } + break; + } // switch (GetParameterInt("mode") ) } void DoExecute() override { std::ostringstream ossOutput; - // Get inputs + ////// Get inputs and keywordlist ///// ComplexFloatImageType::Pointer SARPtr = GetParameterComplexFloatImage("insar"); - FloatImageType::Pointer inputDEM = GetParameterFloatImage("indem"); - - // Get Sar keyWordList - otb::ImageKeywordlist sar_kwl = SARPtr->GetImageKeywordlist(); - + // Read information typedef otb::ImageMetadataInterfaceBase ImageMetadataInterfaceType; ImageMetadataInterfaceType::Pointer metadataInterface = ImageMetadataInterfaceFactory::CreateIMI(SARPtr->GetMetaDataDictionary()); - - // Change insar (???) - // SetParameterOutputImage("out", SARPtr); // Compilation error - // SARPtr->UpdateOutputInformation(); // Does not write (only for reader) - - ////////// KyWordList (geom) ////////////// SARPtr->UpdateOutputInformation(); ImageKeywordlist outputKWL = SARPtr->GetImageKeywordlist(); - - // Check with metadataInterface and keyword List - int gcpcount = metadataInterface->GetGCPCount(); - if (gcpcount == 0) + + // Get mode to adapt estimation according to user choice + bool doGcpCorrection = false; + bool doFineOrbits = false; + + switch (GetParameterInt("mode")) + { + case Mode_UserDefined: + { + doGcpCorrection = true; + } + break; + case Mode_GCP: + { + doGcpCorrection = true; + } + break; + case Mode_Orbits: + { + doFineOrbits = true; + } + break; + } // switch (GetParameterInt("mode") ) + + /////// GCP Correction /////// + if (doGcpCorrection) { - int gcpcount_kwl = std::atoi(outputKWL.GetMetadataByKey(GCP_NUMBER_KEY).c_str()); - if (gcpcount_kwl > 5) + FloatImageType::Pointer inputDEM = GetParameterFloatImage("indem"); + // Check with metadataInterface and keyword List + int gcpcount = metadataInterface->GetGCPCount(); + + if (gcpcount == 0) { - gcpcount = gcpcount_kwl; + int gcpcount_kwl = std::atoi(outputKWL.GetMetadataByKey(GCP_NUMBER_KEY).c_str()); + if (gcpcount_kwl > 5) + { + gcpcount = gcpcount_kwl; + } } - } - std::vector<double *> * vector_lonlat = new std::vector<double *>(); - std::vector<int *> * vector_colrow = new std::vector<int *>(); - std::vector<int> vector_ind; - std::vector<TimeType> vector_aziTime; - std::vector<double> vector_ranTime; + std::vector<double *> * vector_lonlat = new std::vector<double *>(); + std::vector<int *> * vector_colrow = new std::vector<int *>(); + std::vector<int> vector_ind; + std::vector<TimeType> vector_aziTime; + std::vector<double> vector_ranTime; - // Build the input (vector_lonlat) for GetClosestMNTHeight filter - if (gcpcount == 0) - { - // If no GCP => Retrieve Corners instead - // Get latitude and longitude for ur, ul, ll lr and center points - try + // Build the input (vector_lonlat) for GetClosestMNTHeight filter + if (gcpcount == 0) { - getCorners(metadataInterface->GetImageKeywordlist(), vector_lonlat, - vector_colrow, vector_ind, vector_aziTime, - vector_ranTime); + // If no GCP => Retrieve Corners instead + // Get latitude and longitude for ur, ul, ll lr and center points + try + { + getCorners(metadataInterface->GetImageKeywordlist(), vector_lonlat, + vector_colrow, vector_ind, vector_aziTime, + vector_ranTime); + } + catch (itk::ExceptionObject& /*err*/) + { + } } - catch (itk::ExceptionObject& /*err*/) - { + else + { + // If GCPs => Retrieve its + // Get latitude and longitude for each of its + getGCP(metadataInterface, gcpcount, outputKWL, vector_lonlat, vector_colrow, vector_ind); } - } - else - { - // If GCPs => Retrieve its - // Get latitude and longitude for each of its - getGCP(metadataInterface, gcpcount, outputKWL, vector_lonlat, vector_colrow, vector_ind); - } - ///// DEMClosestHgt filter to estimate accurate heights ///// - DEMClosestHgtFilterType::Pointer filterDEMClosestHgt = DEMClosestHgtFilterType::New(); - m_Ref.push_back(filterDEMClosestHgt.GetPointer()); + ///// DEMClosestHgt filter to estimate accurate heights ///// + DEMClosestHgtFilterType::Pointer filterDEMClosestHgt = DEMClosestHgtFilterType::New(); + m_Ref.push_back(filterDEMClosestHgt.GetPointer()); - // Set inputs : DEM and the vector_LonLat - filterDEMClosestHgt->SetInput(inputDEM); - filterDEMClosestHgt->SetVectorLonLat(vector_lonlat); + // Set inputs : DEM and the vector_LonLat + filterDEMClosestHgt->SetInput(inputDEM); + filterDEMClosestHgt->SetVectorLonLat(vector_lonlat); - // Init a vector for hgt - std::vector<double> * vector_hgt = new vector<double>(); - vector_hgt->resize(vector_lonlat->size()); // Same size than lon and lat + // Init a vector for hgt + std::vector<double> * vector_hgt = new vector<double>(); + vector_hgt->resize(vector_lonlat->size()); // Same size than lon and lat - for (unsigned int k = 0; k < vector_lonlat->size(); k++) - { - vector_hgt->at(k) = 0; - } + for (unsigned int k = 0; k < vector_lonlat->size(); k++) + { + vector_hgt->at(k) = 0; + } - // Launch our Persistent filter - filterDEMClosestHgt->Update(); - filterDEMClosestHgt->GetDEMHgt(vector_hgt); + // Launch our Persistent filter + filterDEMClosestHgt->Update(); + filterDEMClosestHgt->GetDEMHgt(vector_hgt); - // Add or update GCP into the output KWL (according to the sensor (GCPs already present or not)) - if (gcpcount == 0) - { - // Create GPCs with the four corners and center - createGCPAndUpdateKWL(vector_lonlat, vector_hgt, - vector_colrow, vector_ind, - vector_aziTime, - vector_ranTime, outputKWL); - } - else - { - // Just update heigths - updateGCPAndKWL(vector_hgt, gcpcount, outputKWL); - } + // Add or update GCP into the output KWL (according to the sensor (GCPs already present or not)) + if (gcpcount == 0) + { + // Create GPCs with the four corners and center + createGCPAndUpdateKWL(vector_lonlat, vector_hgt, + vector_colrow, vector_ind, + vector_aziTime, + vector_ranTime, outputKWL); + } + else + { + // Just update heigths + updateGCPAndKWL(vector_hgt, gcpcount, outputKWL); + } - // Display image information in the dedicated logger - otbAppLogINFO(<< ossOutput.str()); + // Display image information in the dedicated logger + otbAppLogINFO(<< ossOutput.str()); - // Free Memory - for (unsigned int itab = 0; itab < vector_lonlat->size(); itab++) - { - delete vector_lonlat->at(itab); - vector_lonlat->at(itab) = 0; - } - vector_lonlat->clear(); - delete vector_lonlat; - vector_lonlat = 0; + // Free Memory + for (unsigned int itab = 0; itab < vector_lonlat->size(); itab++) + { + delete vector_lonlat->at(itab); + vector_lonlat->at(itab) = 0; + } + vector_lonlat->clear(); + delete vector_lonlat; + vector_lonlat = 0; - vector_hgt->clear(); - delete vector_hgt; - vector_hgt = 0; + vector_hgt->clear(); + delete vector_hgt; + vector_hgt = 0; - for (unsigned int itab = 0; itab < vector_colrow->size(); itab++) - { - delete vector_colrow->at(itab); - vector_colrow->at(itab) = 0; + for (unsigned int itab = 0; itab < vector_colrow->size(); itab++) + { + delete vector_colrow->at(itab); + vector_colrow->at(itab) = 0; + } + vector_colrow->clear(); + delete vector_colrow; + vector_colrow = 0; + + vector_ind.clear(); + vector_aziTime.clear(); + vector_ranTime.clear(); } - vector_colrow->clear(); - delete vector_colrow; - vector_colrow = 0; - vector_ind.clear(); - vector_aziTime.clear(); - vector_ranTime.clear(); + /////// Fine orbits /////// + if (doFineOrbits) + { + double ullat = std::atof(outputKWL.GetMetadataByKey("ul_lat").c_str()); + + // Add into SAR Image keyword list, the precise metadata + std::string inFile = GetParameterString("infineorbits"); + + + // Check that the right extension is given : expected .EOF */ + std::string extension = itksys::SystemTools::GetFilenameLastExtension(inFile); + if (itksys::SystemTools::LowerCase(extension) != ".eof") + { + itkExceptionMacro(<< extension << " is a wrong Extension FileName : Expected .EOF"); + } + + // Open the xml file + TiXmlDocument doc(inFile.c_str()); + if (!doc.LoadFile()) + { + itkExceptionMacro(<< "Can't open file " << inFile); + } + + TiXmlHandle hDoc(&doc); + + // Get root node + TiXmlElement* root = hDoc.FirstChildElement("Earth_Explorer_File").ToElement(); + + if (root) + { + // Init vectors + std::vector<double *> * vector_posvel = new std::vector<double *>(); + std::vector<std::string> * vector_time = new std::vector<std::string>(); + + // Get Data_Block + TiXmlElement* dataBlock = root->FirstChildElement("Data_Block"); + + // Retrieve the number of orbits + int count = std::atoi(dataBlock->FirstChildElement("List_of_OSVs")->Attribute("count")); + + int count_loop = 0; + + // Iterate through the tree to get all the orbits + // Fill vectors with its + for (TiXmlElement* currentOrb = dataBlock->FirstChildElement("List_of_OSVs")->FirstChildElement(); + currentOrb != nullptr; currentOrb = currentOrb->NextSiblingElement()) + { + double * posvel = new double[6]; + + std::string UTCTime = std::string(currentOrb->FirstChildElement("UTC")->GetText()); + UTCTime = UTCTime.substr(UTCTime.find("=")+1, UTCTime.length()); + + posvel[0] = std::atof(currentOrb->FirstChildElement("X")->GetText()); + posvel[1] = std::atof(currentOrb->FirstChildElement("Y")->GetText()); + posvel[2] = std::atof(currentOrb->FirstChildElement("Z")->GetText()); + posvel[3] = std::atof(currentOrb->FirstChildElement("VX")->GetText()); + posvel[4] = std::atof(currentOrb->FirstChildElement("VY")->GetText()); + posvel[5] = std::atof(currentOrb->FirstChildElement("VZ")->GetText()); + + vector_posvel->push_back(posvel); + vector_time->push_back(std::string(UTCTime)); + + ++count_loop; + } + + int ind_first, ind_last; + selectOrbits(vector_time, outputKWL, ind_first, ind_last); + + // Check coherency between the number of orbits + if (count != count_loop) + { + itkExceptionMacro(<< "Problem of coherency into EOF file"); + } + + + int ret = createOrbitsAndUpdateKWL(vector_posvel, vector_time, ind_first, + ind_last, outputKWL); + + if (ret == 1) + { + itkExceptionMacro(<< "Problem during orbits update"); + } + + // Free Memory + for (unsigned int itab = 0; itab < vector_posvel->size(); itab++) + { + delete vector_posvel->at(itab); + vector_posvel->at(itab) = 0; + } + vector_posvel->clear(); + delete vector_posvel; + vector_posvel = 0; + + vector_time->clear(); + delete vector_time; + vector_time = 0; + } + } - // Write output keywordlist with correct gcp (correction on heigth) + /////// Write output keywordlist with correct gcp (correction on heigth) /////// if (IsParameterEnabled("outkwl") && HasValue("outkwl")) { WriteGeometry(outputKWL, GetParameterString("outkwl")); diff --git a/json_schemas/schema_MultiSlc.json b/json_schemas/schema_MultiSlc.json index 67d27d8a45306414419c4f22de3428fc5e2d881b..8138ec13041a7326e00f8e9083dbec9973d6fd5f 100644 --- a/json_schemas/schema_MultiSlc.json +++ b/json_schemas/schema_MultiSlc.json @@ -22,13 +22,14 @@ "End_Date", "Input_Path"], "additionalProperties": false, "properties": {"SRTM_Shapefile": {"type": "string"}, - "SRTM_Path": {"type": "string"}, - "Geoid": {"type": "string"}, - "Master_Image": {"type": "string"}, - "Start_Date": {"type": "string"}, - "End_Date": {"type": "string"}, - "Exclude": {"type": "string", "default": "-9999"}, - "Input_Path": {"type": "string"}} + "SRTM_Path": {"type": "string"}, + "EOF_Path": {"type": "string"}, + "Geoid": {"type": "string"}, + "Master_Image": {"type": "string"}, + "Start_Date": {"type": "string"}, + "End_Date": {"type": "string"}, + "Exclude": {"type": "string", "default": "-9999"}, + "Input_Path": {"type": "string"}} }, "out": { diff --git a/json_schemas/schema_MultiSlc_IW.json b/json_schemas/schema_MultiSlc_IW.json index cad9e7759b7f62cd1c2b401f685b4ec24a37b522..b74d7b7d03011fe24ffad14c2fde7f5187cc5513 100644 --- a/json_schemas/schema_MultiSlc_IW.json +++ b/json_schemas/schema_MultiSlc_IW.json @@ -21,13 +21,14 @@ "End_Date", "Input_Path"], "additionalProperties": false, "properties": {"SRTM_Shapefile": {"type": "string"}, - "SRTM_Path": {"type": "string"}, - "Geoid": {"type": "string"}, - "Master_Image": {"type": "string"}, - "Start_Date": {"type": "string"}, - "End_Date": {"type": "string"}, - "Exclude": {"type": "string", "default": "-9999"}, - "Input_Path": {"type": "string"}} + "SRTM_Path": {"type": "string"}, + "Geoid": {"type": "string"}, + "EOF_Path": {"type": "string"}, + "Master_Image": {"type": "string"}, + "Start_Date": {"type": "string"}, + "End_Date": {"type": "string"}, + "Exclude": {"type": "string", "default": "-9999"}, + "Input_Path": {"type": "string"}} }, "out": { diff --git a/json_schemas/schema_S1IW.json b/json_schemas/schema_S1IW.json index 137e8464d1ce473cb576edb57676936f2ac4f407..f8c9911633b55dd57fd265cb7f215c337b57ecab 100644 --- a/json_schemas/schema_S1IW.json +++ b/json_schemas/schema_S1IW.json @@ -21,7 +21,8 @@ "additionalProperties": false, "properties": {"Master_Image_Path": {"type": "string"}, "Slave_Image_Path": {"type": "string"}, - "DEM_Path": {"type": "string"}} + "DEM_Path": {"type": "string"}, + "EOF_Path": {"type": "string"}} }, "out": { diff --git a/json_schemas/schema_S1SM.json b/json_schemas/schema_S1SM.json index c18077fa860a20ad7c1ce91edd95c7ebec70575e..c69614c415fceb224b544bceb16f0b746a5cd17e 100644 --- a/json_schemas/schema_S1SM.json +++ b/json_schemas/schema_S1SM.json @@ -22,7 +22,8 @@ "additionalProperties": false, "properties": {"Master_Image_Path": {"type": "string"}, "Slave_Image_Path": {"type": "string"}, - "DEM_Path": {"type": "string"}} + "DEM_Path": {"type": "string"}, + "EOF_Path": {"type": "string"}} }, "out": { diff --git a/python_src/SAR_MultiSlc.py b/python_src/SAR_MultiSlc.py index e79d633f0d4c23b03e6620b08ad2d8db9e07b72e..a111fa0b0efe2ceedd114c636befd9034b7e76db 100644 --- a/python_src/SAR_MultiSlc.py +++ b/python_src/SAR_MultiSlc.py @@ -92,6 +92,10 @@ if __name__ == "__main__": hgts_path = dict_Global['in']['SRTM_Path'] geoid_path = dict_Global['in']['Geoid'] + eof_Path = None + if 'EOF_Path' in dict_Global['in']: + eof_Path = dict_Global['in']['EOF_Path'] + output_dir = dict_Global['out']['Output_Path'] if not os.path.exists(output_dir): @@ -234,6 +238,12 @@ if __name__ == "__main__": func_utils.check_ifExist(hgts_path) func_utils.check_ifExist(master_Image) + # Check eof path + if eof_Path : + if not os.path.exists(eof_Path) : + func_utils.log(logging.CRITICAL, "Error, {path} does not exist. Check its path.".format(path=eof_Path)) + quit() + # ====== Check roi format (if roi) if roi : func_utils.check_roiFormat(roi) @@ -408,6 +418,66 @@ if __name__ == "__main__": slave_Image = "HDF5:" + slave_Image + "://S01/SBI" + # Find eof files for each image if not cosmo + # Then, create the "fine" geom (with precise orbits) + # Eventually, assign an extended filename if EOF file correspond to the image + if satellite != "cosmo" : + if eof_Path : + list_ofEOF = func_utils.get_AllFilesWithExt(eof_Path, ".EOF") + + + # master + if counter <= 1 : + start_master = dictKWLMaster['support_data.first_line_time'] + end_master = dictKWLMaster['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_master, end_master, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(master_data_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=master_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_master.geom")) + + + # Assign new geom file with extended filename + master_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_master.geom") + + + # slave + dictKWLSlave = func_utils.getImageKWL(slave_Image) + start_slave = dictKWLSlave['support_data.first_line_time'] + end_slave = dictKWLSlave['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_slave, end_slave, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(output_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=slave_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_slave.geom")) + + # Assign new geom file with extended filename + slave_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_slave.geom") + + + func_utils.log(logging.INFO, "########### Input Images for the current execution ############## ") func_utils.log(logging.INFO, "Nb iteration : {param} with : ".format(param=counter)) func_utils.log(logging.INFO, "master_Image : {param}".format(param=master_Image)) diff --git a/python_src/SAR_MultiSlc_IW.py b/python_src/SAR_MultiSlc_IW.py index 03965645ef96069b1174219b180019ca66e4eeed..c5460fc3b040c32630cf53880351ed7167311c8c 100644 --- a/python_src/SAR_MultiSlc_IW.py +++ b/python_src/SAR_MultiSlc_IW.py @@ -95,6 +95,10 @@ if __name__ == "__main__": hgts_path = dict_Global['in']['SRTM_Path'] geoid_path = dict_Global['in']['Geoid'] + eof_Path = None + if 'EOF_Path' in dict_Global['in']: + eof_Path = dict_Global['in']['EOF_Path'] + output_dir = dict_Global['out']['Output_Path'] if not os.path.exists(output_dir): @@ -225,6 +229,12 @@ if __name__ == "__main__": func_utils.check_ifExist(hgts_path) func_utils.check_ifExist(master_Image) + # Check eof path + if eof_Path : + if not os.path.exists(eof_Path) : + func_utils.log(logging.CRITICAL, "Error, {path} does not exist. Check its path.".format(path=eof_Path)) + quit() + # ====== Check roi format (if roi) if roi : func_utils.check_roiFormat(roi) @@ -325,6 +335,72 @@ if __name__ == "__main__": os.makedirs(master_data_dir) + # ============================================== + # Retrieving informations about master and slave + # ============================================== + dictKWLMaster = func_utils.getImageKWL(master_Image) + dictKWLSlave = func_utils.getImageKWL(slave_Image) + + + # Find eof files for each image if not cosmo + # Then, create the "fine" geom (with precise orbits) + # Eventually, assign an extended filename if EOF file correspond to the image + if eof_Path : + list_ofEOF = func_utils.get_AllFilesWithExt(eof_Path, ".EOF") + + + # master + if counter <= 1 : + start_master = dictKWLMaster['support_data.first_line_time'] + end_master = dictKWLMaster['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_master, end_master, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(master_data_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=master_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_master.geom")) + + + # Assign new geom file with extended filename + master_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_master.geom") + + + # slave + start_slave = dictKWLSlave['support_data.first_line_time'] + end_slave = dictKWLSlave['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_slave, end_slave, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(output_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=slave_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_slave.geom")) + + # Assign new geom file with extended filename + slave_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_slave.geom") + + + + func_utils.log(logging.INFO, "########### Input Images for the current execution ############## ") func_utils.log(logging.INFO, "Nb iteration : {param} with : ".format(param=counter)) func_utils.log(logging.INFO, "master_Image : {param}".format(param=master_Image)) @@ -334,12 +410,6 @@ if __name__ == "__main__": func_utils.printOnStd("\n master_Image : {param} : \n".format(param=master_Image)) func_utils.printOnStd("\n slave_Image : {param} : \n".format(param=slave_Image)) - # ============================================== - # Retrieving informations about master and slave - # ============================================== - dictKWLMaster = func_utils.getImageKWL(master_Image) - dictKWLSlave = func_utils.getImageKWL(slave_Image) - # ===== Check header version if int(dictKWLMaster['header.version']) < 3 or int(dictKWLSlave['header.version']) < 3 : diff --git a/python_src/diapOTB.py b/python_src/diapOTB.py index cb207b18fe9d43cb670f6883f3049ec0c09f17b2..b97e8c36b87b0a27c0a2e3376274141a70861a69 100644 --- a/python_src/diapOTB.py +++ b/python_src/diapOTB.py @@ -47,6 +47,7 @@ from processings import DInSar from processings import Metadata_Correction from processings import Post_Processing +import utils.DiapOTB_applications as diapOTBApp from utils import func_utils # Main @@ -75,8 +76,12 @@ if __name__ == "__main__": master_Image = dict_Global['in']['Master_Image_Path'] slave_Image = dict_Global['in']['Slave_Image_Path'] dem = dict_Global['in']['DEM_Path'] - output_dir = dict_Global['out']['output_dir'] + eof_Path = None + if 'EOF_Path' in dict_Global['in']: + eof_Path = dict_Global['in']['EOF_Path'] + output_dir = dict_Global['out']['output_dir'] + satellite = "default" mode = "default" @@ -162,6 +167,13 @@ if __name__ == "__main__": print("The output directory exists. Some files can be overwritten") + # Check eof path + if eof_Path : + if not os.path.exists(eof_Path) : + func_utils.log(logging.CRITICAL, "Error, {path} does not exist. Check its path.".format(path=eof_Path)) + quit() + + # Init file handler (all normaly print on std is redirected into info.log) # To use previous print on std, use printOnStd func_utils.init_fileLog(output_dir) @@ -296,6 +308,67 @@ if __name__ == "__main__": func_utils.printOnStd("\n Beginning of DiapOTB processing (S1 SM or Cosmo mode) \n") func_utils.log(logging.INFO, "############ Beginning of DiapOTB processing (S1 SM or Cosmo mode) ##############") + + # Find eof files for each image if not cosmo + # Then, create the "fine" geom (with precise orbits) + # Eventually, assign an extended filename if EOF file correspond to the image + if satellite != "cosmo" : + if eof_Path : + list_ofEOF = func_utils.get_AllFilesWithExt(eof_Path, ".EOF") + + + # master + start_master = dictKWLMaster['support_data.first_line_time'] + end_master = dictKWLMaster['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_master, end_master, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(output_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=master_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_master.geom")) + + + # Assign new geom file with extended filename + master_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_master.geom") + + + # slave + dictKWLSlave = func_utils.getImageKWL(slave_Image) + start_slave = dictKWLSlave['support_data.first_line_time'] + end_slave = dictKWLSlave['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_slave, end_slave, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(output_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=slave_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_slave.geom")) + + # Assign new geom file with extended filename + slave_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_slave.geom") + + + + ####################### Pre Processing Chain ########################## # Master func_utils.printOnStd("\n Master Pre_Processing chain \n") diff --git a/python_src/diapOTB_S1IW.py b/python_src/diapOTB_S1IW.py index 29655d8413b84b8337afa8f25423bcef95db5d9d..b77c1b454681d6bee1cabfd64ced4680bd1d2965 100644 --- a/python_src/diapOTB_S1IW.py +++ b/python_src/diapOTB_S1IW.py @@ -46,6 +46,7 @@ from processings import Ground from processings import DInSar from processings import Post_Processing +import utils.DiapOTB_applications as diapOTBApp from utils import func_utils # Main @@ -74,6 +75,10 @@ if __name__ == "__main__": master_Image = dict_Global['in']['Master_Image_Path'] slave_Image = dict_Global['in']['Slave_Image_Path'] dem = dict_Global['in']['DEM_Path'] + eof_Path = None + if 'EOF_Path' in dict_Global['in']: + eof_Path = dict_Global['in']['EOF_Path'] + output_dir = dict_Global['out']['output_dir'] # Pre_Processing @@ -150,6 +155,12 @@ if __name__ == "__main__": else : print("The output directory exists. Some files can be overwritten") + # Check eof path + if eof_Path : + if not os.path.exists(eof_Path) : + func_utils.log(logging.CRITICAL, "Error, {path} does not exist. Check its path.".format(path=eof_Path)) + quit() + # Init file handler (all normaly print on std is redirected into info.log) # To use previous print on std, use printOnStd @@ -257,6 +268,65 @@ if __name__ == "__main__": func_utils.printOnStd("\n Beginning of DiapOTB processing (S1 IW mode) \n") func_utils.log(logging.INFO, "############ Beginning of DiapOTB processing (S1 IW mode) ##############") + + # Find eof files for each image if not cosmo + # Then, create the "fine" geom (with precise orbits) + # Eventually, assign an extended filename if EOF file correspond to the image + if eof_Path : + list_ofEOF = func_utils.get_AllFilesWithExt(eof_Path, ".EOF") + + + # master + start_master = dictKWLMaster['support_data.first_line_time'] + end_master = dictKWLMaster['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_master, end_master, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(output_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=master_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_master.geom")) + + + # Assign new geom file with extended filename + master_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_master.geom") + + + # slave + dictKWLSlave = func_utils.getImageKWL(slave_Image) + start_slave = dictKWLSlave['support_data.first_line_time'] + end_slave = dictKWLSlave['support_data.last_line_time'] + + # Get a eof file + eof_file = func_utils.select_EofWithDate(start_slave, end_slave, list_ofEOF) + + if (eof_file) : + # Create the new geom file into dedicated repository + extendedGeom_Path = os.path.join(output_dir, "extended_geom") + if not os.path.exists(extendedGeom_Path): + os.makedirs(extendedGeom_Path) + + # Call SARMetadataCorrection + diapOTBApp.metadataCorrection(mode="orbits", insar=slave_Image, indem=None, + infineorbits=os.path.join(eof_Path, eof_file), + outPath=os.path.join(extendedGeom_Path, + "extended_slave.geom")) + + # Assign new geom file with extended filename + slave_Image += "?geom=" + os.path.join(extendedGeom_Path, + "extended_slave.geom") + + + ####################### Pre Processing Chain ########################## # Master diff --git a/python_src/utils/DiapOTB_applications.py b/python_src/utils/DiapOTB_applications.py index 1cb94c504032511eafe7f569aaf8138a8ca0f9b5..ae7ab0c6400fe933dc1d028b2eb7f649b848c2a7 100644 --- a/python_src/utils/DiapOTB_applications.py +++ b/python_src/utils/DiapOTB_applications.py @@ -654,6 +654,52 @@ def topographicPhase(ingrid, insarslave, incartmeanmaster, gridsteprange, gridst appTopoPhase.ExecuteAndWriteOutput() +def metadataCorrection(mode, insar, indem, infineorbits, + outPath, ram="4000"): + """ + Launch SARMetadataCorrection application (from DiapOTB). + + This application correct some metadata such as gcp or orbit states. + Two kinds of uses are possible according to the input mode : + _ GCPs correction thanks to input DEM + _ Fine orbits correction (with input EOF file) + + + :param mode: String to indicate selected mode (gcp or orbits). + :param insar: Input SAR image. + :param indem: Input DEM to extract height data. + :param infineorbits: Input file to get precise orbits. + :param outPath: Output geom file. + + :type mode: string + :type insar: string + :type idem: string + :type infineorbits: string + :type outPath: string + + :return: None + """ + appMetatadataCorrection = otb.Registry.CreateApplication("SARMetadataCorrection") + + # Check mode (must be gcp or orbits) + if mode != "gcp" and mode != "orbits" : + print("Wrong selected modes for SARMetadataCorrection application") + return 1 + + + appMetatadataCorrection.SetParameterString("mode", mode) # Check if really string + appMetatadataCorrection.SetParameterString("insar", insar) + + if mode == "gcp" : + appMetatadataCorrection.SetParameterString("indem", indem) + else : + appMetatadataCorrection.SetParameterString("infineorbits", infineorbits) + + appMetatadataCorrection.SetParameterString("outkwl", outPath) + appMetatadataCorrection.SetParameterString("ram", ram) + appMetatadataCorrection.ExecuteAndWriteOutput() + + def phaseFiltering(withComplex, inForFiltering, mlran, mlazi, step, sizetiles, alpha, outPath, ram="4000"): """ diff --git a/python_src/utils/func_utils.py b/python_src/utils/func_utils.py index fa6d0e6e2237d9c34fd824300418d584f33ee939..c42e55272835ebb9a378ff36c9745ae2543806af 100644 --- a/python_src/utils/func_utils.py +++ b/python_src/utils/func_utils.py @@ -39,6 +39,7 @@ import argparse import re import xml.etree.ElementTree as ET import datetime +import time import gdal import ogr @@ -201,7 +202,7 @@ def getImageKWL(Img): keyword = ReadImageInfo.GetParameterString("keyword") keywordlist = ReadImageInfo.GetParameterString("keyword").split("\n") keywordlist = filter(None, keywordlist) - dictKWL = { i.split(':')[0] : re.sub(r"[\n\t\s]*", "", i.split(':')[1]) for i in keywordlist } + dictKWL = { i.split(':')[0] : re.sub(r"[\n\t\s]*", "", "".join(i.split(':')[1:])) for i in keywordlist } return dictKWL @@ -354,6 +355,42 @@ def get_Tiff_WithDates(start, end, exclude, TiffList, ext=""): date_list.append(i) return date_list +def select_EofWithDate(start, end, eofList) : + """ + Select into the input list, the file that correspond to dates + """ + time_start = time.mktime(time.strptime(start, + "%Y-%m-%dT%H%M%S.%f")) + + time_end = time.mktime(time.strptime(end, + "%Y-%m-%dT%H%M%S.%f")) + + + for i_eof in eofList: + # Without extension + i_eof = i_eof.split(".EOF")[0] + + start_eofDate = i_eof.split('_')[-2] + start_eofDate = start_eofDate.split("V")[1] + end_eofDate = i_eof.split('_')[-1] + + # Save date format + time_start_eofDate = time.mktime(time.strptime(start_eofDate, + "%Y%m%dT%H%M%S")) + + time_end_eofDate = time.mktime(time.strptime(end_eofDate, + "%Y%m%dT%H%M%S")) + + + # Compare dates and return eof file if eof file contains the current image dates + if time_start >= time_start_eofDate and time_end <= time_end_eofDate : + return i_eof + ".EOF" + + + # if none of files contains wanted dates : return None + return None + + def get_relative_orbit(manifest): """ Get from manifest file, the orbit number diff --git a/python_src/utils/getEOFFromESA.py b/python_src/utils/getEOFFromESA.py new file mode 100644 index 0000000000000000000000000000000000000000..4bd436e3cc8f489071e4749ebb143f4991e01595 --- /dev/null +++ b/python_src/utils/getEOFFromESA.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import re +import os +import time +import requests +import shutil +import argparse +import datetime +import xml.etree.ElementTree + +def searchForSafe(input_dir) : + """ + Search for Safe repository into input_dir + + :input_dir: (str) input directory + :returns: (iterable) list of SAFE repository + """ + list_SAFE = [] + for root, dirs, files in os.walk(input_dir): + for i in (i for i in dirs): + if i.endswith(".SAFE"): + list_SAFE.append(i) + + return list_SAFE + +# Get url for orbits files +def get_url_orbs(orbs_type, sensor, year, month, day, + url="https://aux.sentinel1.eo.esa.int/", + orb_list=None): + """ + Get the set of available orbs from url + + :orbs_type: (str) either POEROB or RESORB + :sensor: (str) seither S1A or S1B + :year: (str) year + :month: (str|int) month (as a 2 digit number) + :day: (str) day as a two digit number in the month + :url: (str) url where to gather the data + :returns: (iterable) list of urls of the EOF files + """ + url = url.strip('/') + month = "{:02d}".format(int(month)) + day = "{:02d}".format(int(day)) + + # Pattern to find EOF file into response + pattern = "".join(['"', sensor, '_.*?_', orbs_type, '_.*?.EOF"']) + + html_list = [] + orb_list_tmp = [] + + tacquisition0 = datetime.datetime(int(year), int(month), int(day)) + + list_of_days_tosearch = [] + # Fetch POEORB if orb_type is POEORB or None (ie, first try with Precises orbits) + # This kind of orbit is restitued around 21 days later + if orbs_type == 'POEORB' or orbs_type is None: + list_of_days_tosearch = [21, 20, 22, 19, 23] + # Fetch RESORB if orbs_type is RESORB + # This kind of orbit is restitued around 3 hours later (day before to day after safe name) + if orbs_type == "RESORB": + list_of_days_tosearch = [0, 1, 2] + + if url.startswith("https"): + for day in list_of_days_tosearch : + + tacquisition = tacquisition0 + datetime.timedelta(days=day) + + # Build the url wtih "ESA format" + url_orb = "{}/{}/{}/{}/{}/".format(url, orbs_type, tacquisition.year, + "{:02d}".format(tacquisition.month), + "{:02d}".format(tacquisition.day)) + + + try: + # Make the get request with verify = False to avoid ssl issues + response = requests.get(url_orb, verify=False) + + if response.status_code != 200 and response.status_code != 201: + print("problem with the url {} ".format(url_orb)) + continue + + orb_list_tmp += list(set([url_orb + "/" + x.strip().strip('"').strip() + for x in re.findall(pattern, response.text)])) + + + except Exception as e: + print("exception for url {} ".format(e)) + return [] + + else: + raise RuntimeError("malformed url or too recent date, should start by https://") + + + # Add result into orb_list or return orb_list_tmp + orb_list += orb_list_tmp + + + +# Get contents of orbit files on disk +def get_orb_content_ondisk(orb_list, output_dir) : + """ + Retrieve on disk the set of selected orbs + + :orb_list: (list) list or url (to get orbit files) + :output_dir: (str) output directory (on disk) to put orbit files + :returns: () + """ + for orb in orb_list: + try: + # Get the content of eof_file + response = requests.get(orb, verify=False, stream=True) + + if response.status_code != 200 and response.status_code != 201: + print("problem with the url {} ".format(orb)) + continue + + # Copy the content on disk + with open(os.path.join(output_dir, os.path.basename(orb)), 'wb') as out_file: + shutil.copyfileobj(response.raw, out_file) + + del response + except Exception as e: + print("exception for url {} ".format(e)) + + +################### +###### Main ####### +################### +if __name__ == "__main__": + + ###### Get the main argument : indir and outdir ###### + # Check arguments + parser = argparse.ArgumentParser() + parser.add_argument("indir", help="input directory to search SAFE repository") + parser.add_argument("outdir", help="output directory to store EOF files") + parser.add_argument("--type", "-t", type=str, choices=['POEORB', 'RESORB'], + default='POEORB', + help=("The type of data request. If set should be either POEORB or RESORB; " + "if not set test first POEORB and backoff to RESORB else")) + args = parser.parse_args() + + # Check input and output directory (if exist) + if not os.path.exists(args.indir): + print(args.indir + " does not exists") + quit() + + if not os.path.exists(args.outdir): + print(args.outdir + " does not exists") + quit() + + # Require a check of user for connexion parameters (proxy, ...) + response = input("Check all your parameters for internet connexion (proxy, ssl ...), before continuing. \ + \nReady to continue (yes/no) :") + + if response != "yes" : + print("Set all your parameters for internet connexion to relaunch this script") + quit() + + list_InSAFE = searchForSafe(args.indir) + + if len(list_InSAFE) == 0 : + print("None SAFE repository was found into {}".format(args.indir)) + quit() + + + # For each SAFE found, retrieve URLs of EOF files (with date correspondance) + orb_list = [] + + for safeDir in list_InSAFE: + + # Tmp lists + orb_list_firstSelect = [] + orb_list_secondSelect = [] + + # patterns for SAFE names + pattern_date = "".join(['\d{8}', "T", '\d{6}']) + pattern_sensor = "".join(["S1."]) + pattern_orbit = "".join(["_", '\d{6}', "_"]) + dates = "" + sensor = "" + orbit_number = "" + + try : + dates = re.findall(pattern_date, safeDir) + sensor = re.findall(pattern_sensor, safeDir) + orbit_number = int(re.findall(pattern_orbit, safeDir)[0][1:-1]) + except Exception as e: + print("Safe name does not match with usual pattern and causes an exception : \ + {}".format(e)) + # Next safe + continue + + if len(dates) == 2 and len(sensor) == 1 : + # First selection for S1A and S1B sensor at corresponding dates + get_url_orbs(args.type, sensor[0], dates[0][0:4], dates[0][4:6], + dates[0][6:8], orb_list=orb_list_firstSelect) + + + # Second selection with times + time_start = time.mktime(time.strptime(dates[0], + "%Y%m%dT%H%M%S")) + + time_end = time.mktime(time.strptime(dates[1], + "%Y%m%dT%H%M%S")) + + for orb in orb_list_firstSelect: + eof_file = orb.split('/')[-1] + + # Without extension + i_eof = eof_file.split(".EOF")[0] + + start_eofDate = i_eof.split('_')[-2] + start_eofDate = start_eofDate.split("V")[1] + end_eofDate = i_eof.split('_')[-1] + + # Save date format + time_start_eofDate = time.mktime(time.strptime(start_eofDate, + "%Y%m%dT%H%M%S")) + + time_end_eofDate = time.mktime(time.strptime(end_eofDate, + "%Y%m%dT%H%M%S")) + + # Compare dates and return eof file if eof file contains the current image dates + if time_end > time_start_eofDate and time_start <= time_end_eofDate : + orb_list_secondSelect.append(orb) + + + # Last selection/check with orbit (Keep ????) + for orb in orb_list_secondSelect: + try: + # Make the get request with verify = False to avoid ssl issues + response = requests.get(orb, verify=False) + + if response.status_code != 200 and response.status_code != 201: + print("problem with the url {} ".format(url_orb)) + continue + + tree = xml.etree.ElementTree.fromstring(response.text) + + Absolute_Orbit_Elt = tree.findall("Data_Block/List_of_OSVs/OSV/Absolute_Orbit") + + orbitNumbers = list(set([int(x.text) + for x in Absolute_Orbit_Elt])) + + if (orbit_number in orbitNumbers) : + orb_list.append(orb) + + + except Exception as e: + print("Exception {}".format(e)) + quit() + + else : + print("Wrong SAFE format for {}".format(args.indir)) + # Next Safe + continue + + + print("Selected orbit files (Ready to be retrieved on disk) : ") + print(orb_list) + + # Get selection into output_dir + get_orb_content_ondisk(orb_list, args.outdir) +