Skip to content

Commit

Permalink
feat: sample conversion rate (%) in a reaction scheme (ComPlat#2159)
Browse files Browse the repository at this point in the history
-  add column conversion_rate (float) to reactions_samples table
- reaction scheme toggle to switch between yield or conversion rate
- reaction scheme fields calculation based on sample conversion rate
  • Loading branch information
adambasha0 authored Dec 19, 2024
1 parent 8b4e92d commit e751a92
Show file tree
Hide file tree
Showing 23 changed files with 292 additions and 131 deletions.
1 change: 1 addition & 0 deletions app/api/entities/reaction_material_entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ class ReactionMaterialEntity < ApplicationEntity
expose! :waste
expose! :gas_type
expose! :gas_phase_data
expose! :conversion_rate
end
end
2 changes: 2 additions & 0 deletions app/api/helpers/report_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ def build_sql_reaction_sample(columns, c_id, ids, checkedAll = false)
# reactions_sample:
equivalent: ['r_s.equivalent', '"r eq"', 10],
reference: ['r_s.reference', '"r ref"', 10],
conversion_rate: ['r_s.conversion_rate', '"r conversion rate"', 10],
},
analysis: {
name: ['anac."name"', '"name"', 10],
Expand Down Expand Up @@ -723,6 +724,7 @@ def force_molfile_selection
equivalent
reference
type
conversion_rate
],
sample: %i[
sample_svg_file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export default class NumeralInputWithUnitsCompo extends Component {

togglePrefix(currentUnit) {
const units = ['TON/h', 'TON/m', 'TON/s', '°C', '°F', 'K', 'h', 'm', 's'];
const excludedUnits = ['ppm', 'TON'];
const excludedUnits = ['ppm', 'TON', '%'];
const { onMetricsChange, unit } = this.props;
if (units.includes(currentUnit)) {
// eslint-disable-next-line no-unused-expressions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class Material extends Component {
this.gasFieldsUnitsChanged = this.gasFieldsUnitsChanged.bind(this);
this.handleCoefficientChange = this.handleCoefficientChange.bind(this);
this.debounceHandleAmountUnitChange = debounce(this.handleAmountUnitChange, 500);
this.yieldOrConversionRate = this.yieldOrConversionRate.bind(this);
}

handleMaterialClick(sample) {
Expand Down Expand Up @@ -242,34 +243,66 @@ class Material extends Component {
return result > 1 ? '100%' : `${(result * 100).toFixed(0)}%`;
}

equivalentOrYield(material) {
const { reaction, materialGroup } = this.props;
if (materialGroup === 'products') {
const refMaterial = reaction.getReferenceMaterial();
let calculateYield = material.equivalent;
if (material.gas_type === 'gas') {
calculateYield = this.recalculateYieldForGasProduct(material, reaction);
} else if (reaction.hasPolymers()) {
calculateYield = `${((material.equivalent || 0) * 100).toFixed(0)}%`;
} else if (refMaterial && (refMaterial.decoupled || material.decoupled)) {
calculateYield = 'n.a.';
} else if (material.purity < 1 && material.equivalent > 1) {
calculateYield = `${((material.purity / 100 * (material.amount_g * 1000)) * 100).toFixed(1)}%`;
} else {
calculateYield = `${((material.equivalent <= 1 ? material.equivalent || 0 : 1) * 100).toFixed(0)}%`;
}
calculateYield(material, reaction) {
const refMaterial = reaction.getReferenceMaterial();
let calculateYield = material.equivalent;
if (material.gas_type === 'gas') {
calculateYield = this.recalculateYieldForGasProduct(material, reaction);
} else if (reaction.hasPolymers()) {
calculateYield = `${((material.equivalent || 0) * 100).toFixed(0)}%`;
} else if (refMaterial && (refMaterial.decoupled || material.decoupled)) {
calculateYield = 'n.a.';
} else if (material.purity < 1 && material.equivalent > 1) {
calculateYield = `${((material.purity / 100 * (material.amount_g * 1000)) * 100).toFixed(1)}%`;
} else {
calculateYield = `${((material.equivalent <= 1 ? material.equivalent || 0 : 1) * 100).toFixed(0)}%`;
}
return calculateYield;
}

conversionRateField(material) {
const { reaction } = this.props;
const condition = material.conversion_rate / 100 > 1;
const allowedConversionRateValue = material.conversion_rate && condition
? 100 : material.conversion_rate;
return (
<div>
<NumeralInputWithUnitsCompo
precision={4}
value={allowedConversionRateValue || 'n.d.'}
unit="%"
disabled={!permitOn(reaction)}
onChange={(e) => this.handleConversionRateChange(e)}
size="sm"
/>
</div>
);
}

yieldOrConversionRate(material) {
const { reaction, displayYieldField } = this.props;
if (displayYieldField === true || displayYieldField === null) {
return (
<div>
<Form.Control
name="yield"
type="text"
bsClass="bs-form--compact form-control"
size="sm"
value={calculateYield || 'n.d.'}
value={this.calculateYield(material, reaction) || 'n.d.'}
disabled
/>
</div>
);
}
return this.conversionRateField(material);
}

equivalentOrYield(material) {
const { materialGroup } = this.props;
if (materialGroup === 'products') {
return this.yieldOrConversionRate(material);
}
return (
<NumeralInputWithUnitsCompo
size="sm"
Expand Down Expand Up @@ -522,6 +555,20 @@ class Material extends Component {
}
}

handleConversionRateChange(e) {
const { onChange, materialGroup } = this.props;
const conversionRate = e.value;
if (onChange && e) {
const event = {
type: 'conversionRateChanged',
materialGroup,
sampleID: this.materialId(),
conversionRate
};
onChange(event);
}
}

handleGasFieldsChange(field, e, currentValue) {
const { materialGroup, onChange } = this.props;
if (onChange && e.value !== undefined && e.unit !== undefined && e.value !== currentValue) {
Expand Down Expand Up @@ -1075,4 +1122,5 @@ Material.propTypes = {
canDrop: PropTypes.bool,
isOver: PropTypes.bool,
lockEquivColumn: PropTypes.bool.isRequired,
displayYieldField: PropTypes.bool,
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import { defaultMultiSolventsSmilesOptions } from 'src/components/staticDropdown
import { ionic_liquids } from 'src/components/staticDropdownOptions/ionic_liquids';
import { reagents_kombi } from 'src/components/staticDropdownOptions/reagents_kombi';
import { permitOn } from 'src/components/common/uis';
import ToggleButton from 'src/components/common/ToggleButton';

function MaterialGroup({
materials, materialGroup, deleteMaterial, onChange,
showLoadingColumn, reaction, addDefaultSolvent, headIndex,
dropMaterial, dropSample, switchEquiv, lockEquivColumn
dropMaterial, dropSample, switchEquiv, lockEquivColumn, displayYieldField,
switchYield
}) {
const contents = [];
let index = headIndex;
Expand All @@ -38,6 +40,7 @@ function MaterialGroup({
dropMaterial={dropMaterial}
dropSample={dropSample}
lockEquivColumn={lockEquivColumn}
displayYieldField={displayYieldField}
/>
));

Expand Down Expand Up @@ -76,6 +79,8 @@ function MaterialGroup({
addDefaultSolvent={addDefaultSolvent}
switchEquiv={switchEquiv}
lockEquivColumn={lockEquivColumn}
displayYieldField={displayYieldField}
switchYield={switchYield}
/>
);
}
Expand Down Expand Up @@ -106,7 +111,7 @@ function SwitchEquivButton(lockEquivColumn, switchEquiv) {

function GeneralMaterialGroup({
contents, materialGroup, showLoadingColumn, reaction, addDefaultSolvent,
switchEquiv, lockEquivColumn
switchEquiv, lockEquivColumn, displayYieldField, switchYield
}) {
const isReactants = materialGroup === 'reactants';
let headers = {
Expand Down Expand Up @@ -154,9 +159,35 @@ function GeneralMaterialGroup({
);
}

const yieldConversionRateFields = () => {
const conversionText = 'Click to switch to conversion field.'
+ ' The conversion will not be displayed as part of the reaction scheme';
const yieldText = 'Click to switch to yield field.'
+ ' The yield will be displayed as part of the reaction scheme';
let conversionOrYield = displayYieldField;
if (displayYieldField || displayYieldField === null) {
conversionOrYield = true;
}
return (
<div>
<ToggleButton
isToggledInitial={conversionOrYield}
onToggle={switchYield}
onLabel="Yield"
offLabel="Conv."
onColor="transparent"
offColor="transparent"
tooltipOn={conversionText}
tooltipOff={yieldText}
additionalClasses="fw-bold text-dark"
/>
</div>
);
};

if (materialGroup === 'products') {
headers.group = 'Products';
headers.eq = 'Yield';
headers.eq = yieldConversionRateFields();
}

const refTHead = (materialGroup !== 'products') ? headers.ref : null;
Expand Down Expand Up @@ -306,7 +337,9 @@ MaterialGroup.propTypes = {
dropMaterial: PropTypes.func.isRequired,
dropSample: PropTypes.func.isRequired,
switchEquiv: PropTypes.func.isRequired,
lockEquivColumn: PropTypes.bool
lockEquivColumn: PropTypes.bool,
displayYieldField: PropTypes.bool,
switchYield: PropTypes.func.isRequired
};

GeneralMaterialGroup.propTypes = {
Expand All @@ -316,7 +349,9 @@ GeneralMaterialGroup.propTypes = {
addDefaultSolvent: PropTypes.func.isRequired,
contents: PropTypes.arrayOf(PropTypes.shape).isRequired,
switchEquiv: PropTypes.func.isRequired,
lockEquivColumn: PropTypes.bool
lockEquivColumn: PropTypes.bool,
displayYieldField: PropTypes.bool,
switchYield: PropTypes.func.isRequired
};

SolventsMaterialGroup.propTypes = {
Expand All @@ -328,12 +363,14 @@ SolventsMaterialGroup.propTypes = {

MaterialGroup.defaultProps = {
showLoadingColumn: false,
lockEquivColumn: false
lockEquivColumn: false,
displayYieldField: null
};

GeneralMaterialGroup.defaultProps = {
showLoadingColumn: false,
lockEquivColumn: false
lockEquivColumn: false,
displayYieldField: null
};

export { MaterialGroup, GeneralMaterialGroup, SolventsMaterialGroup };
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class MaterialGroupContainer extends Component {
const {
materials, materialGroup, showLoadingColumn, headIndex,
isOver, canDrop, connectDropTarget,
deleteMaterial, onChange, reaction, dropSample, dropMaterial, switchEquiv, lockEquivColumn
deleteMaterial, onChange, reaction, dropSample, dropMaterial, switchEquiv, lockEquivColumn,
displayYieldField, switchYield,
} = this.props;
let className='';
if (canDrop) {
Expand All @@ -80,6 +81,8 @@ class MaterialGroupContainer extends Component {
headIndex={headIndex}
switchEquiv={switchEquiv}
lockEquivColumn={lockEquivColumn}
displayYieldField={displayYieldField}
switchYield={switchYield}
/>
</div>
);
Expand All @@ -106,7 +109,9 @@ MaterialGroupContainer.propTypes = {
canDrop: PropTypes.bool.isRequired,
connectDropTarget: PropTypes.func.isRequired,
switchEquiv: PropTypes.func,
lockEquivColumn: PropTypes.bool
lockEquivColumn: PropTypes.bool,
displayYieldField: PropTypes.bool.isRequired,
switchYield: PropTypes.func.isRequired,
};

MaterialGroupContainer.defaultProps = {
Expand Down
Loading

0 comments on commit e751a92

Please sign in to comment.