Skip to content

Commit

Permalink
Merge pull request #302 from PauloCarvalhoRJ/next_release
Browse files Browse the repository at this point in the history
Contact analysis
  • Loading branch information
PauloCarvalhoRJ authored Apr 11, 2024
2 parents 6080836 + cf6ea63 commit 7e670d5
Show file tree
Hide file tree
Showing 37 changed files with 1,802 additions and 50 deletions.
17 changes: 16 additions & 1 deletion GammaRay.pro
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ win32 {

SOURCES += main.cpp\
dialogs/choosevariabledialog.cpp \
dialogs/contactanalysisdialog.cpp \
dialogs/faciestransitionmatrixoptionsdialog.cpp \
dialogs/gridrepositiondialog.cpp \
dialogs/listbuilderdialog.cpp \
Expand All @@ -49,7 +50,13 @@ SOURCES += main.cpp\
geometry/intersectionfinder.cpp \
geometry/quadrilateral.cpp \
geometry/triangle.cpp \
geostats/contactanalysis.cpp \
geostats/mcmcdataimputation.cpp \
geostats/searchannulus.cpp \
geostats/searchannulusstratigraphic.cpp \
geostats/searchsphericalshell.cpp \
geostats/searchverticaldumbbell.cpp \
geostats/searchwasher.cpp \
gslib/gslibparams/gslibpardir.cpp \
gslib/gslibparams/widgets/widgetgslibpardir.cpp \
mainwindow.cpp \
Expand Down Expand Up @@ -308,6 +315,7 @@ SOURCES += main.cpp\

HEADERS += mainwindow.h \
dialogs/choosevariabledialog.h \
dialogs/contactanalysisdialog.h \
dialogs/faciestransitionmatrixoptionsdialog.h \
dialogs/gridrepositiondialog.h \
dialogs/listbuilderdialog.h \
Expand All @@ -327,7 +335,13 @@ HEADERS += mainwindow.h \
geometry/intersectionfinder.h \
geometry/quadrilateral.h \
geometry/triangle.h \
geostats/contactanalysis.h \
geostats/mcmcdataimputation.h \
geostats/searchannulus.h \
geostats/searchannulusstratigraphic.h \
geostats/searchsphericalshell.h \
geostats/searchverticaldumbbell.h \
geostats/searchwasher.h \
gslib/gslibparams/gslibpardir.h \
gslib/gslibparams/widgets/widgetgslibpardir.h \
util.h \
Expand Down Expand Up @@ -589,6 +603,7 @@ HEADERS += mainwindow.h \

FORMS += mainwindow.ui \
dialogs/choosevariabledialog.ui \
dialogs/contactanalysisdialog.ui \
dialogs/faciestransitionmatrixoptionsdialog.ui \
dialogs/gridrepositiondialog.ui \
dialogs/listbuilderdialog.ui \
Expand Down Expand Up @@ -853,7 +868,7 @@ win32 {
# The application version
# Don't forget to update the Util::importSettingsFromPreviousVersion() method to
# enable the import of registry/user settings of previous versions.
VERSION = 6.18
VERSION = 6.20

# Define a preprocessor macro so we can get the application version in application code.
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ If you enjoyed this project, you might also enjoy GeostatsPy: https://github.com
Python script to convert Eclipse grids to Paraview-compatible VTU format: https://github.com/BinWang0213/PyGRDECL

VERSION HISTORY:<br>
&nbsp;&nbsp;&nbsp;Version 6.20 - Contact Analysis.<br>
&nbsp;&nbsp;&nbsp;Version 6.18 - MCRFSim execution in batch/unattended mode; dependencies upgrades (VTK, ITK, Boost, C++14, ...).<br>
&nbsp;&nbsp;&nbsp;Version 6.17 - Transiography and MCRFSim for Bayesian approach; some fixes and improvements.<br>
&nbsp;&nbsp;&nbsp;Version 6.16 - Upgrade of VTK to 9.1 and other years-old dependencies; some fixes.<br>
Expand Down
167 changes: 167 additions & 0 deletions dialogs/contactanalysisdialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#include "contactanalysisdialog.h"
#include "ui_contactanalysisdialog.h"

#include "domain/attribute.h"
#include "domain/datafile.h"
#include "domain/application.h"
#include "domain/categorydefinition.h"
#include "geostats/contactanalysis.h"
#include "widgets/categoryselector.h"
#include "widgets/linechartwidget.h"
#include "dialogs/emptydialog.h"

#include <QMessageBox>
#include <algorithm>

ContactAnalysisDialog::ContactAnalysisDialog(Attribute *attributeGrade,
Attribute *attributeDomains,
QWidget *parent) :
QDialog(parent),
ui(new Ui::ContactAnalysisDialog),
m_attributeGrade(attributeGrade),
m_attributeDomains(attributeDomains)
{
ui->setupUi(this);

//deletes dialog from memory upon user closing it
this->setAttribute(Qt::WA_DeleteOnClose);

//set dialog title
setWindowTitle( "Contact Analysis" );

//update the suffix of the lag size spin box with the length unit symbol.
onLengthUnitSymbolChanged( ui->txtLengthUnitSymbol->text() );

//get the pointer to the variables' parent data file and set caption of the dialog's label
m_dataFile = dynamic_cast<DataFile*>( attributeGrade->getContainingFile() );
DataFile* dataFileOfDomain = dynamic_cast<DataFile*>( attributeDomains->getContainingFile() );
if( ! m_dataFile || ! dataFileOfDomain || (dataFileOfDomain != m_dataFile ) ) { //sanity check
Application::instance()->logError( "ContactAnalysisDialog::ContactAnalysisDialog(): "
"Container file object of the grade and/or domains attributes is not a data file or "
"their parent files are different, which is not allowed for contact anaysis. ", true );
} else {
//enable/disable certain dialog widgets depending on whether the data set is 3D or is gridded.
ui->lblDataFile->setText( ui->lblDataFile->text() + "<b>" + m_dataFile->getName() + "</b>" );
if( m_dataFile->isGridded() || !m_dataFile->isTridimensional() ){
ui->lblZTolerance->setEnabled( false );
ui->dblSpinZTolerance->setEnabled( false );
}
if( ! m_dataFile->isTridimensional() ) {
ui->radioVertical->setEnabled( false );
ui->radioOmni3D->setEnabled( false );
}
}

//display the variables' names
ui->lblGradeAttribute->setText( ui->lblGradeAttribute->text() + "<b>" + attributeGrade->getName() + "</b>" );
ui->lblDomainsAttribute->setText( ui->lblDomainsAttribute->text() + "<b>" + attributeDomains->getName() + "</b>" );

//get the domains variable's category definition
CategoryDefinition* cd = m_dataFile->getCategoryDefinition( attributeDomains );
if( ! cd ){ //sanity check
Application::instance()->logError( "ContactAnalysisDialog::ContactAnalysisDialog(): "
"Category definition of domains variable is null. ", true );
}

//create the category selector widgets so the user can select both domains for the contact analysis
m_selectorDomain1 = new CategorySelector( cd );
m_selectorDomain2 = new CategorySelector( cd );
ui->frmDomain1->layout()->addWidget( m_selectorDomain1 ); //Qt takes ownership of the widget object with this
ui->frmDomain2->layout()->addWidget( m_selectorDomain2 ); //Qt takes ownership of the widget oject with this
}

ContactAnalysisDialog::~ContactAnalysisDialog()
{
delete ui;
}

void ContactAnalysisDialog::onLengthUnitSymbolChanged(QString lengthUnitSymbol)
{
ui->dblSpinLagSize->setSuffix( lengthUnitSymbol );
}

void ContactAnalysisDialog::onProceed()
{
ContactAnalysis contactAnalysis;
if( ui->radioLateral->isChecked() )
contactAnalysis.setMode( ContactAnalysisMode::LATERAL );
else
contactAnalysis.setMode( ContactAnalysisMode::VERTICAL );
contactAnalysis.setLagSize( ui->dblSpinLagSize->value() );
contactAnalysis.setZtolerance( ui->dblSpinZTolerance->value() );
contactAnalysis.setDomain1_code( static_cast<uint16_t>(m_selectorDomain1->getSelectedCategoryCode()) );
contactAnalysis.setDomain2_code( static_cast<uint16_t>(m_selectorDomain2->getSelectedCategoryCode()) );
contactAnalysis.setNumberOfLags( static_cast<uint16_t>(ui->spinNumberOfLags->value()) );
contactAnalysis.setInputDataFile( m_dataFile );
contactAnalysis.setAttributeGrade( m_attributeGrade );
contactAnalysis.setAttributeDomains( m_attributeDomains );
contactAnalysis.setMaxNumberOfSamples( static_cast<uint16_t>(ui->spinMaxNumberOfSamples->value()) );
contactAnalysis.setMinNumberOfSamples( static_cast<uint16_t>(ui->spinMinNumberOfSamples->value()) );

if( ! contactAnalysis.run() ) {

Application::instance()->logError("ContactAnalysisDialog::onProceed(): failed execution:");
Application::instance()->logError(" " + contactAnalysis.getLastError());
QMessageBox::critical( this, "Error", "Contact analysis failed. Further details in the message panel." );

} else { //if the contact analysis completed successfully

//shortcut for the STL's not-a-number value.
const double NaN = std::numeric_limits<double>::quiet_NaN();

//get the contact analysis results
std::vector<
std::pair<
ContactAnalysis::Lag,
ContactAnalysis::MeanGradesBothDomains
>
> results = contactAnalysis.getResults();

//prepare data points for chart plotting
//outer vector: the series of multivariate data
//inner vectors: each multivariate datum (each element is a X, Y1, Y2,... value).
std::vector< std::vector<double> > chartData;

//traverse the results to fill the chart data
//the desired effect is to have two different curves sharing a mirrored X-axis befitting a
//contact analysis chart (NaN causes the line chart widget to not render the curve at the given point).
for( const std::pair< ContactAnalysis::Lag, ContactAnalysis::MeanGradesBothDomains >& result : results ){
// lag values grades of domain 1 grades of domain 2
//indexes in the inner vectors: 0 1 2
chartData.push_back( { -result.first, result.second.first, NaN } );
}
std::reverse( chartData.begin(), chartData.end() );
for( const std::pair< ContactAnalysis::Lag, ContactAnalysis::MeanGradesBothDomains >& result : results ){
// lag values grades of domain 1 grades of domain 2
//indexes in the inner vectors: 0 1 2
chartData.push_back( { result.first, NaN, result.second.second } );
}

//get some properties of the domain categories relevant to make
//the chart informative
QColor colorDomain1, colorDomain2;
QString nameDomain1, nameDomain2;
{
CategoryDefinition* cd = m_dataFile->getCategoryDefinition( m_attributeDomains );
colorDomain1 = cd->getCustomColor( cd->getCategoryIndex( contactAnalysis.getDomain1_code() ));
colorDomain2 = cd->getCustomColor( cd->getCategoryIndex( contactAnalysis.getDomain2_code() ));
nameDomain1 = cd->getCategoryNameByCode( contactAnalysis.getDomain1_code() );
nameDomain2 = cd->getCategoryNameByCode( contactAnalysis.getDomain2_code() );
}

//display the results
LineChartWidget* lcw = new LineChartWidget(this);
lcw->setSharedYaxis( true );
lcw->setChartTitle( "Contact analysis of " + m_dataFile->getName() );
lcw->setData( chartData, 0,
{{1, nameDomain1 + " (Domain 1)"}, {2, nameDomain2 + " (Domain 2)"}},
{{2, "mean " + m_attributeGrade->getName() }}, // shared y-axis is enabled, set only the last one
{{1, colorDomain1} , {2, colorDomain2}} );
lcw->setXaxisCaption( "lag (" + ui->txtLengthUnitSymbol->text() + ")" );
EmptyDialog* ed = new EmptyDialog( this );
ed->addWidget( lcw );
ed->setWindowTitle( "Contact analysis results" );
ed->show();

}
}
39 changes: 39 additions & 0 deletions dialogs/contactanalysisdialog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef CONTACTANALYSISDIALOG_H
#define CONTACTANALYSISDIALOG_H

#include <QDialog>

namespace Ui {
class ContactAnalysisDialog;
}

class Attribute;
class DataFile;
class CategorySelector;

class ContactAnalysisDialog : public QDialog
{
Q_OBJECT

public:
explicit ContactAnalysisDialog(Attribute* attributeGrade,
Attribute* attributeDomains,
QWidget *parent = nullptr);
~ContactAnalysisDialog();

private:
Ui::ContactAnalysisDialog *ui;

private Q_SLOTS:
void onLengthUnitSymbolChanged( QString lengthUnitSymbol );
void onProceed();

private:
Attribute* m_attributeGrade;
Attribute* m_attributeDomains;
DataFile* m_dataFile;
CategorySelector* m_selectorDomain1;
CategorySelector* m_selectorDomain2;
};

#endif // CONTACTANALYSISDIALOG_H
Loading

0 comments on commit 7e670d5

Please sign in to comment.