Skip to content

Commit

Permalink
Merge pull request #46 from HybriD3-database/stoichiometry_enchanced_…
Browse files Browse the repository at this point in the history
…formula_parsing

Updated signals.py and add_data.html for parsing formulas with brackets.
  • Loading branch information
uthpalaherath authored Oct 1, 2024
2 parents 05a8fa4 + 1723975 commit da58829
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 71 deletions.
56 changes: 38 additions & 18 deletions materials/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,54 @@
from .models import System, System_Stoichiometry, Stoichiometry_Elements
import re

def parse_formula(formula):
tokens = re.findall(r'([A-Z][a-z]?|\(|\)|\d+)', formula)
stack = [{}]
i = 0
while i < len(tokens):
token = tokens[i]
if token == '(':
stack.append({})
i += 1
elif token == ')':
top = stack.pop()
i += 1
# Check if there is a multiplier
if i < len(tokens) and tokens[i].isdigit():
multiplier = int(tokens[i])
i += 1
else:
multiplier = 1
for element, count in top.items():
stack[-1][element] = stack[-1].get(element, 0) + count * multiplier
elif re.match(r'[A-Z][a-z]?$', token):
element = token
i += 1
if i < len(tokens) and tokens[i].isdigit():
count = int(tokens[i])
i += 1
else:
count = 1
stack[-1][element] = stack[-1].get(element, 0) + count
else:
i += 1
return stack[0]

@receiver(post_save, sender=System)
def create_stoichiometry_entries(sender, instance, created, **kwargs):
if created:
# Example: assuming the system's formula is provided in the form 'C6H12O6'
formula = (
instance.formula
) # Use the system's formula field for stoichiometry parsing

# Regular expression to extract elements and their counts (e.g., C6, H12, O6 from 'C6H12O6')
element_pattern = r"([A-Z][a-z]*)(\d*)"
elements = re.findall(element_pattern, formula)

# Create the stoichiometry string in the format "C:6,H:12,O:6"
stoichiometry_str = ",".join([f"{el}:{count or 1}" for el, count in elements])

# Create System_Stoichiometry entry
formula = instance.formula
elements_dict = parse_formula(formula)
stoichiometry_str = ",".join([f"{el}:{int(count)}" for el, count in elements_dict.items()])
stoichiometry = System_Stoichiometry.objects.create(
system=instance, stoichiometry=stoichiometry_str
)

# Create Stoichiometry_Elements entries
for el, count in elements:
for el, count in elements_dict.items():
Stoichiometry_Elements.objects.create(
system_stoichiometry=stoichiometry,
element=el,
string_value=count or "1",
float_value=float(count) if count else 1.0,
string_value=str(int(count)),
float_value=float(count),
)


Expand Down
114 changes: 61 additions & 53 deletions materials/templates/materials/add_data.html
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,12 @@ <h4>Add Data</h4>
{{"Stoichiometry extraction is case sensitive. For example, CsCl will read as Cs:1, Cl:1 as it needs to be distinguishable from CSCl, which will extract as C:1, S:1, Cl:1"|tooltip}}
</div>
<div id="stoichiometry-display"></div>
</div>
</div>
<div class="form-group col-md-6">
{% comment %} THE stoichiometry INPUT WILL BE HERE {% endcomment %}
{% input_field main_form.stoichiometry %}
{% comment %}<input type="text" class="form-control" id="id_stoichiometry" name="stoichiometry" placeholder="Please provide the stoichiometry value in the format: C:6,H:12,O:1">{% endcomment %}
</div>
</div>
<div class="form-group col-md-6">
{% input_field system_form.organic %}
</div>
Expand Down Expand Up @@ -165,7 +165,7 @@ <h5 class="modal-title" id="stoichiometryModalLabel">Is this the correct stoichi
</div>
</div>
</div>


<!-- ADD NEW PROPERTY -->
<div id="new-property-card" class="card mt-3 new-entry-card new-entry-card2" hidden="true">
Expand Down Expand Up @@ -287,7 +287,7 @@ <h5 class="modal-title" id="stoichiometryModalLabel">Is this the correct stoichi
</div>
<div class="form-check form-check-inline">
{% input_field main_form.two_axes %}
</div>
</div>
</div>
</div>

Expand Down Expand Up @@ -603,9 +603,9 @@ <h5 class="modal-title" id="stoichiometryModalLabel">Is this the correct stoichi
</div>
<!-- end template -->






<div class="card-body card-add-data">
{% input_field main_form.uploaded_files %}
{% endblock %}
Expand Down Expand Up @@ -669,54 +669,62 @@ <h5 class="modal-title" id="stoichiometryModalLabel">Is this the correct stoichi
</script>
<script>
var elementsData = {{ elements_json|safe }};
</script>
</script>
<script>
function parseFormula(formula) {
const tokens = formula.match(/([A-Z][a-z]?|\(|\)|\d+)/g);
if (!tokens) return {};
const stack = [{}];
let i = 0;
while (i < tokens.length) {
const token = tokens[i];
if (token === '(') {
stack.push({});
i++;
} else if (token === ')') {
const top = stack.pop();
i++;
let multiplier = 1;
if (i < tokens.length && /^\d+$/.test(tokens[i])) {
multiplier = parseInt(tokens[i], 10);
i++;
}
for (const [element, count] of Object.entries(top)) {
stack[stack.length - 1][element] = (stack[stack.length - 1][element] || 0) + count * multiplier;
}
} else if (/^[A-Z][a-z]?$/.test(token)) {
const element = token;
i++;
let count = 1;
if (i < tokens.length && /^\d+$/.test(tokens[i])) {
count = parseInt(tokens[i], 10);
i++;
}
stack[stack.length - 1][element] = (stack[stack.length - 1][element] || 0) + count;
} else {
i++;
}
}
return stack[0];
}

function extractStoichiometry() {
// Get the formula input value
const formulaInput = document.getElementById('id_formula');

// Check if the formulaInput is found
if (!formulaInput) {
const formulaInput = document.getElementById('id_formula');
if (!formulaInput) {
console.error("Formula input not found");
return;
}
const formula = formulaInput.value;
// Check if the formula is retrieved correctly
console.log("Formula:", formula);
console.log(newStoichiometryInput);
// Regular expression to match element and count
const regex = /([A-Z][a-z]*)(\d*)/g;
// Object to store element counts
const elementCounts = {};
// Match elements and counts in the formula
let match;
while ((match = regex.exec(formula)) !== null) {
const element = match[1];
const count = match[2] === '' ? 1 : parseInt(match[2], 10);

// Update or add the element count
if (elementCounts[element]) {
elementCounts[element] += count;
} else {
elementCounts[element] = count;
}
}

// Build the stoichiometry string
let stoichiometryString = '';
for (const element in elementCounts) {
}
const formula = formulaInput.value;
const elementCounts = parseFormula(formula);
let stoichiometryString = '';
for (const element in elementCounts) {
stoichiometryString += `${element}:${elementCounts[element]}, `;
}

// Remove the trailing comma and space
stoichiometryString = stoichiometryString.slice(0, -2);
console.log("Stoichiometry:", stoichiometryString);
// Display the stoichiometry in the modal
document.getElementById('stoichiometryOutput').innerText = `${stoichiometryString}`;
//Show as modal
$('#stoichiometryModal').modal('show');

}
stoichiometryString = stoichiometryString.slice(0, -2);
document.getElementById('stoichiometryOutput').innerText = `${stoichiometryString}`;
$('#stoichiometryModal').modal('show');
}

function handleStoichiometryConfirmation(answer){
const stoichiometryTextBox = document.getElementById('system-stoichiometry-input');
const newStoichiometrySection = document.getElementById('newStoichiometrySection');
Expand All @@ -736,7 +744,7 @@ <h5 class="modal-title" id="stoichiometryModalLabel">Is this the correct stoichi
document.getElementById('newStoichiometryInput').style.display = 'block';
document.getElementById('enterButton').style.display = 'block';
}

function handleNewStoichiometry() {
const newStoichiometryInput = document.getElementById('newStoichiometryInput');
const newStoichiometrySection = document.getElementById('newStoichiometrySection');
Expand All @@ -746,10 +754,10 @@ <h5 class="modal-title" id="stoichiometryModalLabel">Is this the correct stoichi

$('#stoichiometryModal').modal('hide');
}


</script>



{% endblock %}

0 comments on commit da58829

Please sign in to comment.