Skip to content

Commit

Permalink
Merge pull request OSGeo#8518 from rouault/SetDerivedDatasetName
Browse files Browse the repository at this point in the history
Add a GDALPamDataset::SetDerivedDatasetName() method, …
  • Loading branch information
rouault authored Oct 10, 2023
2 parents 4288c3d + e239d4e commit 6a3584b
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 24 deletions.
70 changes: 70 additions & 0 deletions autotest/gdrivers/netcdf_multidim.py
Original file line number Diff line number Diff line change
Expand Up @@ -3740,3 +3740,73 @@ def test_netcdf_multidim_getresampled_with_geoloc_EMIT():
)[0]
== -10
)


###############################################################################


@gdaltest.enable_exceptions()
def test_netcdf_multidim_serialize_statistics_asclassicdataset(tmp_path):

filename = str(
tmp_path / "test_netcdf_multidim_serialize_statistics_asclassicdataset.nc"
)
shutil.copy("data/netcdf/byte_no_cf.nc", filename)

def test():
ds = gdal.OpenEx(filename, gdal.OF_MULTIDIM_RASTER | gdal.OF_UPDATE)
rg = ds.GetRootGroup()
ar = rg.OpenMDArray("Band1")

view = ar.GetView("[0:10,...]")
classic_ds = view.AsClassicDataset(1, 0)
assert classic_ds.GetRasterBand(1).GetStatistics(False, False) == [
0.0,
0.0,
0.0,
-1.0,
]
classic_ds.GetRasterBand(1).ComputeStatistics(False)

view = ar.GetView("[10:20,...]")
classic_ds = view.AsClassicDataset(1, 0)
classic_ds.GetRasterBand(1).ComputeStatistics(False)

def reopen():

aux_xml = open(filename + ".aux.xml", "rb").read().decode("UTF-8")
assert (
'<DerivedDataset name="AsClassicDataset(1,0) view of Sliced view of /Band1 ([0:10,...])">'
in aux_xml
)
assert (
'<DerivedDataset name="AsClassicDataset(1,0) view of Sliced view of /Band1 ([0:10,...])">'
in aux_xml
)

ds = gdal.OpenEx(filename, gdal.OF_MULTIDIM_RASTER)
rg = ds.GetRootGroup()
ar = rg.OpenMDArray("Band1")

view = ar.GetView("[0:10,...]")
classic_ds = view.AsClassicDataset(1, 0)
assert classic_ds.GetRasterBand(1).GetStatistics(False, False) == pytest.approx(
[74.0, 255.0, 126.82, 26.729713803182]
)

view = ar.GetView("[10:20,...]")
classic_ds = view.AsClassicDataset(1, 0)
assert classic_ds.GetRasterBand(1).GetStatistics(False, False) == pytest.approx(
[99.0, 206.0, 126.71, 18.356086184152]
)

classic_ds = ar.AsClassicDataset(1, 0)
assert classic_ds.GetRasterBand(1).GetStatistics(False, False) == [
0.0,
0.0,
0.0,
-1.0,
]

test()
reopen()
2 changes: 2 additions & 0 deletions gcore/gdal_pam.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class GDALDatasetPamInfo

CPLString osPhysicalFilename{};
CPLString osSubdatasetName{};
CPLString osDerivedDatasetName{};
CPLString osAuxFilename{};

int bHasMetadata = false;
Expand Down Expand Up @@ -145,6 +146,7 @@ class CPL_DLL GDALPamDataset : public GDALDataset
const char *GetPhysicalFilename();
void SetSubdatasetName(const char *);
const char *GetSubdatasetName();
void SetDerivedDatasetName(const char *);
//! @endcond

public:
Expand Down
16 changes: 13 additions & 3 deletions gcore/gdalmultidim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8250,7 +8250,7 @@ struct MetadataItem
};
} // namespace

class GDALRasterBandFromArray final : public GDALRasterBand
class GDALRasterBandFromArray final : public GDALPamRasterBand
{
std::vector<GUInt64> m_anOffset{};
std::vector<size_t> m_anCount{};
Expand Down Expand Up @@ -8282,7 +8282,7 @@ class GDALRasterBandFromArray final : public GDALRasterBand
GDALColorInterp GetColorInterpretation() override;
};

class GDALDatasetFromArray final : public GDALDataset
class GDALDatasetFromArray final : public GDALPamDataset
{
friend class GDALRasterBandFromArray;

Expand Down Expand Up @@ -8316,7 +8316,8 @@ class GDALDatasetFromArray final : public GDALDataset
CPLErr eErr = CE_None;
if (nOpenFlags != OPEN_FLAGS_CLOSED)
{
if (GDALDatasetFromArray::FlushCache() != CE_None)
if (GDALDatasetFromArray::FlushCache(/*bAtClosing=*/true) !=
CE_None)
eErr = CE_Failure;
m_poArray.reset();
}
Expand Down Expand Up @@ -9139,6 +9140,15 @@ GDALDatasetFromArray *GDALDatasetFromArray::Create(
if (iDim > 0)
goto lbl_return_to_caller;

if (!array->GetFilename().empty())
{
poDS->SetPhysicalFilename(array->GetFilename().c_str());
poDS->SetDerivedDatasetName(
CPLSPrintf("AsClassicDataset(%d,%d) view of %s", int(iXDim),
int(iYDim), array->GetFullName().c_str()));
poDS->TryLoadXML();
}

return poDS.release();
}

Expand Down
97 changes: 76 additions & 21 deletions gcore/gdalpamdataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@
*
* poDS->TryLoadXML();
* \endcode
*
* In some situations where a derived dataset (e.g. used by
* GDALMDArray::AsClassicDataset()) is linked to a physical file, the name of
* the derived dataset is set with the SetDerivedSubdatasetName() method.
*
* \code
* poDS->SetDescription( poOpenInfo->pszFilename );
* poDS->SetPhysicalFilename( poDS->pszFilename );
* poDS->SetDerivedDatasetName( osDerivedDatasetName );
*
* poDS->TryLoadXML();
* \endcode
*/
class GDALPamDataset;

Expand Down Expand Up @@ -761,6 +773,7 @@ const char *GDALPamDataset::GetPhysicalFilename()
/* SetSubdatasetName() */
/************************************************************************/

/* Mutually exclusive with SetDerivedDatasetName() */
void GDALPamDataset::SetSubdatasetName(const char *pszSubdataset)

{
Expand All @@ -770,6 +783,20 @@ void GDALPamDataset::SetSubdatasetName(const char *pszSubdataset)
psPam->osSubdatasetName = pszSubdataset;
}

/************************************************************************/
/* SetDerivedDatasetName() */
/************************************************************************/

/* Mutually exclusive with SetSubdatasetName() */
void GDALPamDataset::SetDerivedDatasetName(const char *pszDerivedDataset)

{
PamInitialize();

if (psPam)
psPam->osDerivedDatasetName = pszDerivedDataset;
}

/************************************************************************/
/* GetSubdatasetName() */
/************************************************************************/
Expand Down Expand Up @@ -916,29 +943,44 @@ CPLErr GDALPamDataset::TryLoadXML(char **papszSiblingFiles)
/* -------------------------------------------------------------------- */
/* If we are looking for a subdataset, search for its subtree now. */
/* -------------------------------------------------------------------- */
if (psTree && !psPam->osSubdatasetName.empty())
if (psTree)
{
CPLXMLNode *psSubTree = psTree->psChild;

for (; psSubTree != nullptr; psSubTree = psSubTree->psNext)
std::string osSubNode;
std::string osSubNodeValue;
if (!psPam->osSubdatasetName.empty())
{
if (psSubTree->eType != CXT_Element ||
!EQUAL(psSubTree->pszValue, "Subdataset"))
continue;
osSubNode = "Subdataset";
osSubNodeValue = psPam->osSubdatasetName;
}
else if (!psPam->osDerivedDatasetName.empty())
{
osSubNode = "DerivedDataset";
osSubNodeValue = psPam->osDerivedDatasetName;
}
if (!osSubNode.empty())
{
CPLXMLNode *psSubTree = psTree->psChild;

if (!EQUAL(CPLGetXMLValue(psSubTree, "name", ""),
psPam->osSubdatasetName))
continue;
for (; psSubTree != nullptr; psSubTree = psSubTree->psNext)
{
if (psSubTree->eType != CXT_Element ||
!EQUAL(psSubTree->pszValue, osSubNode.c_str()))
continue;

psSubTree = CPLGetXMLNode(psSubTree, "PAMDataset");
break;
}
if (!EQUAL(CPLGetXMLValue(psSubTree, "name", ""),
osSubNodeValue.c_str()))
continue;

if (psSubTree != nullptr)
psSubTree = CPLCloneXMLTree(psSubTree);
psSubTree = CPLGetXMLNode(psSubTree, "PAMDataset");
break;
}

CPLDestroyXMLNode(psTree);
psTree = psSubTree;
if (psSubTree != nullptr)
psSubTree = CPLCloneXMLTree(psSubTree);

CPLDestroyXMLNode(psTree);
psTree = psSubTree;
}
}

/* -------------------------------------------------------------------- */
Expand Down Expand Up @@ -1000,7 +1042,19 @@ CPLErr GDALPamDataset::TrySaveXML()
/* the subdataset tree within the whole existing pam tree, */
/* after removing any old version of the same subdataset. */
/* -------------------------------------------------------------------- */
std::string osSubNode;
std::string osSubNodeValue;
if (!psPam->osSubdatasetName.empty())
{
osSubNode = "Subdataset";
osSubNodeValue = psPam->osSubdatasetName;
}
else if (!psPam->osDerivedDatasetName.empty())
{
osSubNode = "DerivedDataset";
osSubNodeValue = psPam->osDerivedDatasetName;
}
if (!osSubNode.empty())
{
CPLXMLNode *psOldTree = nullptr;

Expand All @@ -1022,21 +1076,22 @@ CPLErr GDALPamDataset::TrySaveXML()
psSubTree = psSubTree->psNext)
{
if (psSubTree->eType != CXT_Element ||
!EQUAL(psSubTree->pszValue, "Subdataset"))
!EQUAL(psSubTree->pszValue, osSubNode.c_str()))
continue;

if (!EQUAL(CPLGetXMLValue(psSubTree, "name", ""),
psPam->osSubdatasetName))
osSubNodeValue.c_str()))
continue;

break;
}

if (psSubTree == nullptr)
{
psSubTree = CPLCreateXMLNode(psOldTree, CXT_Element, "Subdataset");
psSubTree =
CPLCreateXMLNode(psOldTree, CXT_Element, osSubNode.c_str());
CPLCreateXMLNode(CPLCreateXMLNode(psSubTree, CXT_Attribute, "name"),
CXT_Text, psPam->osSubdatasetName);
CXT_Text, osSubNodeValue.c_str());
}

CPLXMLNode *psOldPamDataset = CPLGetXMLNode(psSubTree, "PAMDataset");
Expand Down

0 comments on commit 6a3584b

Please sign in to comment.