```python
import gurobipy as gp
from gurobipy import GRB

# Create a new model
m = gp.Model("nutrition_optimization")

# Create variables
b2 = m.addVar(lb=0, vtype=GRB.CONTINUOUS, name="vitamin_B2")
b3 = m.addVar(lb=0, vtype=GRB.CONTINUOUS, name="vitamin_B3")
zinc = m.addVar(lb=0, vtype=GRB.CONTINUOUS, name="zinc")
fiber = m.addVar(lb=0, vtype=GRB.CONTINUOUS, name="fiber")

# Set objective function
m.setObjective(8*b2 + 4*b3 + 8*zinc + 9*fiber, GRB.MINIMIZE)

# Add resource constraints
resource_data = {
    'r0': {'description': 'kidney support index', 'upper_bound': 195, 'x0': 2, 'x1': 5, 'x2': 6, 'x3': 11},
    'r1': {'description': 'cognitive performance index', 'upper_bound': 270, 'x0': 13, 'x1': 10, 'x2': 12, 'x3': 2},
    'r2': {'description': 'digestive support index', 'upper_bound': 168, 'x0': 6, 'x1': 5, 'x2': 11, 'x3': 12},
    'r3': {'description': 'immune support index', 'upper_bound': 207, 'x0': 4, 'x1': 10, 'x2': 8, 'x3': 8}
}

for r_key, r_data in resource_data.items():
    m.addConstr(r_data['x0']*b2 + r_data['x1']*b3 + r_data['x2']*zinc + r_data['x3']*fiber <= r_data['upper_bound'], name=f"{r_data['description']}_upper_bound")


# Add other constraints as specified in the prompt
m.addConstr(5*b3 + 11*fiber >= 33)
m.addConstr(2*b2 + 6*zinc >= 37)
m.addConstr(6*zinc + 11*fiber >= 45)
m.addConstr(5*b3 + 6*zinc >= 39)
m.addConstr(2*b2 + 6*zinc + 11*fiber >= 39)
m.addConstr(2*b2 + 5*b3 + 11*fiber >= 39)
m.addConstr(2*b2 + 6*zinc + 11*fiber >= 40)
m.addConstr(2*b2 + 5*b3 + 11*fiber >= 40)
m.addConstr(2*b2 + 5*b3 + 6*zinc + 11*fiber >= 40)
m.addConstr(13*b2 + 2*fiber >= 52)
m.addConstr(10*b3 + 2*fiber >= 33)
m.addConstr(12*zinc + 2*fiber >= 45)
m.addConstr(13*b2 + 12*zinc >= 49)
m.addConstr(10*b3 + 12*zinc + 2*fiber >= 49)
m.addConstr(13*b2 + 10*b3 + 12*zinc + 2*fiber >= 49)
m.addConstr(11*zinc + 12*fiber >= 35)
m.addConstr(5*b3 + 11*zinc >= 27)
m.addConstr(6*b2 + 5*b3 + 11*zinc + 12*fiber >= 27)
m.addConstr(4*b2 + 8*zinc >= 37)
m.addConstr(4*b2 + 8*fiber >= 37)
m.addConstr(10*b3 + 8*zinc >= 29)
m.addConstr(8*zinc + 8*fiber >= 35)
m.addConstr(4*b2 + 10*b3 >= 43)
m.addConstr(10*b3 + 8*fiber >= 26)
m.addConstr(10*b3 + 8*zinc + 8*fiber >= 32)
m.addConstr(4*b2 + 10*b3 + 8*zinc >= 32)
m.addConstr(10*b3 + 8*zinc + 8*fiber >= 27)
m.addConstr(4*b2 + 10*b3 + 8*zinc >= 27)
m.addConstr(4*b2 + 10*b3 + 8*zinc + 8*fiber >= 27)
m.addConstr(-8*zinc + 10*fiber >= 0)
m.addConstr(5*b2 - 2*zinc >= 0)
m.addConstr(2*b2 + 5*b3 + 11*fiber <= 105)
m.addConstr(5*b3 + 6*zinc + 11*fiber <= 74)
m.addConstr(2*b2 + 6*zinc + 11*fiber <= 132)
m.addConstr(10*b3 + 2*fiber <= 70)
m.addConstr(10*b3 + 12*zinc <= 169)
m.addConstr(13*b2 + 12*zinc <= 186)
m.addConstr(13*b2 + 12*zinc + 2*fiber <= 238)
m.addConstr(5*b3 + 11*zinc + 12*fiber <= 85)
m.addConstr(6*b2 + 5*b3 + 12*fiber <= 157)


# Optimize model
m.optimize()

# Print solution
if m.status == GRB.OPTIMAL:
    print('Obj: %g' % m.objVal)
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))
elif m.status == GRB.INFEASIBLE:
    print('Model is infeasible')
else:
    print('Optimization ended with status %d' % m.status)
```